mirror of
https://git.dev.opencascade.org/repos/occt.git
synced 2025-08-14 13:30:48 +03:00
Data Exchange, DE_Wrapper - Implement Stream support (#663)
- Adds stream-based read/write methods to multiple data exchange providers - Refactors underlying APIs (VrmlAPI_Writer, StlAPI_Writer, RWStl) to support stream operations - Implements comprehensive test coverage for stream functionality - Adds validation utilities for improved error handling
This commit is contained in:
@@ -103,6 +103,13 @@ bool DE_ConfigurationNode::IsExportSupported() const
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
bool DE_ConfigurationNode::IsStreamSupported() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
bool DE_ConfigurationNode::CheckExtension(const TCollection_AsciiString& theExtension) const
|
||||
{
|
||||
TCollection_AsciiString anExtension(theExtension);
|
||||
|
@@ -92,14 +92,18 @@ public:
|
||||
const Standard_Boolean theToKeep);
|
||||
|
||||
public:
|
||||
//! Checks the import supporting
|
||||
//! @return Standard_True if import is support
|
||||
//! Checks for import support.
|
||||
//! @return Standard_True if import is supported
|
||||
Standard_EXPORT virtual bool IsImportSupported() const;
|
||||
|
||||
//! Checks the export supporting
|
||||
//! @return Standard_True if export is support
|
||||
//! Checks for export support.
|
||||
//! @return Standard_True if export is supported
|
||||
Standard_EXPORT virtual bool IsExportSupported() const;
|
||||
|
||||
//! Checks for stream support.
|
||||
//! @return Standard_True if streams are supported
|
||||
Standard_EXPORT virtual bool IsStreamSupported() const;
|
||||
|
||||
//! Gets CAD format name of associated provider
|
||||
//! @return provider CAD format
|
||||
Standard_EXPORT virtual TCollection_AsciiString GetFormat() const = 0;
|
||||
|
@@ -15,6 +15,7 @@
|
||||
|
||||
#include <DE_ConfigurationNode.hxx>
|
||||
#include <Message.hxx>
|
||||
#include <NCollection_IndexedDataMap.hxx>
|
||||
|
||||
IMPLEMENT_STANDARD_RTTIEXT(DE_Provider, Standard_Transient)
|
||||
|
||||
@@ -148,3 +149,123 @@ Standard_Boolean DE_Provider::Write(const TCollection_AsciiString& thePath,
|
||||
<< " doesn't support write operation";
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DE_Provider::Read(ReadStreamList& theStreams,
|
||||
const Handle(TDocStd_Document)& theDocument,
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
(void)theStreams;
|
||||
(void)theDocument;
|
||||
(void)theWS;
|
||||
(void)theProgress;
|
||||
Message::SendFail() << "Error: provider " << GetFormat() << " " << GetVendor()
|
||||
<< " doesn't support stream read operation";
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DE_Provider::Write(WriteStreamList& theStreams,
|
||||
const Handle(TDocStd_Document)& theDocument,
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
(void)theStreams;
|
||||
(void)theDocument;
|
||||
(void)theWS;
|
||||
(void)theProgress;
|
||||
Message::SendFail() << "Error: provider " << GetFormat() << " " << GetVendor()
|
||||
<< " doesn't support stream write operation";
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DE_Provider::Read(ReadStreamList& theStreams,
|
||||
TopoDS_Shape& theShape,
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
(void)theStreams;
|
||||
(void)theShape;
|
||||
(void)theWS;
|
||||
(void)theProgress;
|
||||
Message::SendFail() << "Error: provider " << GetFormat() << " " << GetVendor()
|
||||
<< " doesn't support stream read operation";
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DE_Provider::Write(WriteStreamList& theStreams,
|
||||
const TopoDS_Shape& theShape,
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
(void)theStreams;
|
||||
(void)theShape;
|
||||
(void)theWS;
|
||||
(void)theProgress;
|
||||
Message::SendFail() << "Error: provider " << GetFormat() << " " << GetVendor()
|
||||
<< " doesn't support stream write operation";
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DE_Provider::Read(ReadStreamList& theStreams,
|
||||
const Handle(TDocStd_Document)& theDocument,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
(void)theStreams;
|
||||
(void)theDocument;
|
||||
(void)theProgress;
|
||||
Message::SendFail() << "Error: provider " << GetFormat() << " " << GetVendor()
|
||||
<< " doesn't support stream read operation";
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DE_Provider::Write(WriteStreamList& theStreams,
|
||||
const Handle(TDocStd_Document)& theDocument,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
(void)theStreams;
|
||||
(void)theDocument;
|
||||
(void)theProgress;
|
||||
Message::SendFail() << "Error: provider " << GetFormat() << " " << GetVendor()
|
||||
<< " doesn't support stream write operation";
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DE_Provider::Read(ReadStreamList& theStreams,
|
||||
TopoDS_Shape& theShape,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
(void)theStreams;
|
||||
(void)theShape;
|
||||
(void)theProgress;
|
||||
Message::SendFail() << "Error: provider " << GetFormat() << " " << GetVendor()
|
||||
<< " doesn't support stream read operation";
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DE_Provider::Write(WriteStreamList& theStreams,
|
||||
const TopoDS_Shape& theShape,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
(void)theStreams;
|
||||
(void)theShape;
|
||||
(void)theProgress;
|
||||
Message::SendFail() << "Error: provider " << GetFormat() << " " << GetVendor()
|
||||
<< " doesn't support stream write operation";
|
||||
return Standard_False;
|
||||
}
|
||||
|
@@ -15,6 +15,9 @@
|
||||
#define _DE_Provider_HeaderFile
|
||||
|
||||
#include <Message_ProgressRange.hxx>
|
||||
#include <NCollection_List.hxx>
|
||||
#include <Standard_IStream.hxx>
|
||||
#include <Standard_OStream.hxx>
|
||||
|
||||
class DE_ConfigurationNode;
|
||||
class TopoDS_Shape;
|
||||
@@ -43,6 +46,45 @@ class DE_Provider : public Standard_Transient
|
||||
public:
|
||||
DEFINE_STANDARD_RTTIEXT(DE_Provider, Standard_Transient)
|
||||
|
||||
//! Node to store write stream information
|
||||
//! Contains relative path and reference to output stream
|
||||
struct WriteStreamNode
|
||||
{
|
||||
TCollection_AsciiString Path; //!< Relative path to the output file
|
||||
Standard_OStream& Stream; //!< Reference to output stream
|
||||
|
||||
//! Constructor
|
||||
WriteStreamNode(const TCollection_AsciiString& thePath, Standard_OStream& theStream)
|
||||
: Path(thePath),
|
||||
Stream(theStream)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
//! Node to store read stream information
|
||||
//! Contains relative path and reference to input stream
|
||||
struct ReadStreamNode
|
||||
{
|
||||
TCollection_AsciiString Path; //!< Relative path to the input file
|
||||
Standard_IStream& Stream; //!< Reference to input stream
|
||||
|
||||
//! Constructor
|
||||
ReadStreamNode(const TCollection_AsciiString& thePath, Standard_IStream& theStream)
|
||||
: Path(thePath),
|
||||
Stream(theStream)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
//! List to store write stream nodes
|
||||
//! First element is the main stream, others are for internal referencing
|
||||
using WriteStreamList = NCollection_List<WriteStreamNode>;
|
||||
|
||||
//! List to store read stream nodes
|
||||
//! First element is the main stream, others are for internal referencing
|
||||
using ReadStreamList = NCollection_List<ReadStreamNode>;
|
||||
|
||||
public:
|
||||
//! Default constructor
|
||||
//! Configure translation process with global configuration
|
||||
@@ -77,6 +119,30 @@ public:
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange());
|
||||
|
||||
//! Reads streams according to internal configuration
|
||||
//! @param[in] theStreams streams to read from
|
||||
//! @param[out] theDocument document to save result
|
||||
//! @param[in] theWS current work session
|
||||
//! @param[in] theProgress progress indicator
|
||||
//! @return True if Read was successful
|
||||
Standard_EXPORT virtual Standard_Boolean Read(
|
||||
ReadStreamList& theStreams,
|
||||
const Handle(TDocStd_Document)& theDocument,
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange());
|
||||
|
||||
//! Writes streams according to internal configuration
|
||||
//! @param[in] theStreams streams to write to
|
||||
//! @param[out] theDocument document to export
|
||||
//! @param[in] theWS current work session
|
||||
//! @param[in] theProgress progress indicator
|
||||
//! @return True if Write was successful
|
||||
Standard_EXPORT virtual Standard_Boolean Write(
|
||||
WriteStreamList& theStreams,
|
||||
const Handle(TDocStd_Document)& theDocument,
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange());
|
||||
|
||||
//! Reads a CAD file, according internal configuration
|
||||
//! @param[in] thePath path to the import CAD file
|
||||
//! @param[out] theDocument document to save result
|
||||
@@ -97,6 +163,26 @@ public:
|
||||
const Handle(TDocStd_Document)& theDocument,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange());
|
||||
|
||||
//! Reads streams according to internal configuration
|
||||
//! @param[in] theStreams streams to read from
|
||||
//! @param[out] theDocument document to save result
|
||||
//! @param[in] theProgress progress indicator
|
||||
//! @return True if Read was successful
|
||||
Standard_EXPORT virtual Standard_Boolean Read(
|
||||
ReadStreamList& theStreams,
|
||||
const Handle(TDocStd_Document)& theDocument,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange());
|
||||
|
||||
//! Writes streams according to internal configuration
|
||||
//! @param[in] theStreams streams to write to
|
||||
//! @param[out] theDocument document to export
|
||||
//! @param[in] theProgress progress indicator
|
||||
//! @return True if Write was successful
|
||||
Standard_EXPORT virtual Standard_Boolean Write(
|
||||
WriteStreamList& theStreams,
|
||||
const Handle(TDocStd_Document)& theDocument,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange());
|
||||
|
||||
//! Reads a CAD file, according internal configuration
|
||||
//! @param[in] thePath path to the import CAD file
|
||||
//! @param[out] theShape shape to save result
|
||||
@@ -121,6 +207,30 @@ public:
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange());
|
||||
|
||||
//! Reads streams according to internal configuration
|
||||
//! @param[in] theStreams streams to read from
|
||||
//! @param[out] theShape shape to save result
|
||||
//! @param[in] theWS current work session
|
||||
//! @param[in] theProgress progress indicator
|
||||
//! @return True if Read was successful
|
||||
Standard_EXPORT virtual Standard_Boolean Read(
|
||||
ReadStreamList& theStreams,
|
||||
TopoDS_Shape& theShape,
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange());
|
||||
|
||||
//! Writes streams according to internal configuration
|
||||
//! @param[in] theStreams streams to write to
|
||||
//! @param[out] theShape shape to export
|
||||
//! @param[in] theWS current work session
|
||||
//! @param[in] theProgress progress indicator
|
||||
//! @return True if Write was successful
|
||||
Standard_EXPORT virtual Standard_Boolean Write(
|
||||
WriteStreamList& theStreams,
|
||||
const TopoDS_Shape& theShape,
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange());
|
||||
|
||||
//! Reads a CAD file, according internal configuration
|
||||
//! @param[in] thePath path to the import CAD file
|
||||
//! @param[out] theShape shape to save result
|
||||
@@ -141,6 +251,26 @@ public:
|
||||
const TopoDS_Shape& theShape,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange());
|
||||
|
||||
//! Reads streams according to internal configuration
|
||||
//! @param[in] theStreams streams to read from
|
||||
//! @param[out] theShape shape to save result
|
||||
//! @param[in] theProgress progress indicator
|
||||
//! @return True if Read was successful
|
||||
Standard_EXPORT virtual Standard_Boolean Read(
|
||||
ReadStreamList& theStreams,
|
||||
TopoDS_Shape& theShape,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange());
|
||||
|
||||
//! Writes streams according to internal configuration
|
||||
//! @param[in] theStreams streams to write to
|
||||
//! @param[out] theShape shape to export
|
||||
//! @param[in] theProgress progress indicator
|
||||
//! @return True if Write was successful
|
||||
Standard_EXPORT virtual Standard_Boolean Write(
|
||||
WriteStreamList& theStreams,
|
||||
const TopoDS_Shape& theShape,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange());
|
||||
|
||||
public:
|
||||
//! Gets CAD format name of associated provider
|
||||
//! @return provider CAD format
|
||||
|
345
src/DataExchange/TKDE/DE/DE_ValidationUtils.cxx
Normal file
345
src/DataExchange/TKDE/DE/DE_ValidationUtils.cxx
Normal file
@@ -0,0 +1,345 @@
|
||||
// Copyright (c) 2025 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 <DE_ValidationUtils.hxx>
|
||||
|
||||
#include <Message.hxx>
|
||||
#include <NCollection_Buffer.hxx>
|
||||
#include <NCollection_BaseAllocator.hxx>
|
||||
#include <OSD_FileSystem.hxx>
|
||||
#include <OSD_Path.hxx>
|
||||
#include <OSD_File.hxx>
|
||||
#include <OSD_Protection.hxx>
|
||||
#include <fstream>
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DE_ValidationUtils::ValidateConfigurationNode(
|
||||
const Handle(DE_ConfigurationNode)& theNode,
|
||||
const Handle(Standard_Type)& theExpectedType,
|
||||
const TCollection_AsciiString& theContext,
|
||||
const Standard_Boolean theIsVerbose)
|
||||
{
|
||||
if (theNode.IsNull())
|
||||
{
|
||||
if (theIsVerbose)
|
||||
{
|
||||
Message::SendFail() << "Error during " << theContext << ": Configuration Node is null";
|
||||
}
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
if (!theNode->IsKind(theExpectedType))
|
||||
{
|
||||
if (theIsVerbose)
|
||||
{
|
||||
Message::SendFail() << "Error during " << theContext
|
||||
<< ": Configuration Node is not of expected type. Expected: "
|
||||
<< theExpectedType->Name() << ", got: " << theNode->DynamicType()->Name();
|
||||
}
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
return Standard_True;
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DE_ValidationUtils::ValidateFileForReading(
|
||||
const TCollection_AsciiString& thePath,
|
||||
const TCollection_AsciiString& theContext,
|
||||
const Standard_Boolean theIsVerbose)
|
||||
{
|
||||
if (thePath.IsEmpty())
|
||||
{
|
||||
if (theIsVerbose)
|
||||
{
|
||||
Message::SendFail() << "Error during " << theContext << ": File path is empty";
|
||||
}
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
OSD_Path aOSDPath(thePath);
|
||||
OSD_File aFile(aOSDPath);
|
||||
|
||||
// Check if file exists
|
||||
if (!aFile.Exists())
|
||||
{
|
||||
if (theIsVerbose)
|
||||
{
|
||||
Message::SendFail() << "Error during " << theContext << ": File '" << thePath
|
||||
<< "' does not exist";
|
||||
}
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
// Try to open for reading to verify permissions
|
||||
std::ifstream aTestFile(thePath.ToCString());
|
||||
if (!aTestFile.is_open() || !aTestFile.good())
|
||||
{
|
||||
if (theIsVerbose)
|
||||
{
|
||||
Message::SendFail() << "Error during " << theContext << ": Cannot open file '" << thePath
|
||||
<< "' for reading";
|
||||
}
|
||||
return Standard_False;
|
||||
}
|
||||
}
|
||||
catch (const std::exception& anException)
|
||||
{
|
||||
if (theIsVerbose)
|
||||
{
|
||||
Message::SendFail() << "Error during " << theContext << ": Cannot access file '" << thePath
|
||||
<< "': " << anException.what();
|
||||
}
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
return Standard_True;
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DE_ValidationUtils::ValidateFileForWriting(
|
||||
const TCollection_AsciiString& thePath,
|
||||
const TCollection_AsciiString& theContext,
|
||||
const Standard_Boolean theIsVerbose)
|
||||
{
|
||||
if (thePath.IsEmpty())
|
||||
{
|
||||
if (theIsVerbose)
|
||||
{
|
||||
Message::SendFail() << "Error during " << theContext << ": File path is empty";
|
||||
}
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// Try to open for writing to verify permissions
|
||||
std::ofstream aTestFile(thePath.ToCString(), std::ios::out | std::ios::app);
|
||||
if (!aTestFile.is_open() || !aTestFile.good())
|
||||
{
|
||||
if (theIsVerbose)
|
||||
{
|
||||
Message::SendFail() << "Error during " << theContext << ": Cannot open file '" << thePath
|
||||
<< "' for writing";
|
||||
}
|
||||
return Standard_False;
|
||||
}
|
||||
// File will be closed automatically when aTestFile goes out of scope
|
||||
}
|
||||
catch (const std::exception& anException)
|
||||
{
|
||||
if (theIsVerbose)
|
||||
{
|
||||
Message::SendFail() << "Error during " << theContext << ": Cannot access file '" << thePath
|
||||
<< "': " << anException.what();
|
||||
}
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
return Standard_True;
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DE_ValidationUtils::ValidateReadStreamList(
|
||||
const DE_Provider::ReadStreamList& theStreams,
|
||||
const TCollection_AsciiString& theContext,
|
||||
const Standard_Boolean theIsVerbose)
|
||||
{
|
||||
if (theStreams.IsEmpty())
|
||||
{
|
||||
if (theIsVerbose)
|
||||
{
|
||||
Message::SendFail() << "Error during " << theContext << ": Stream list is empty";
|
||||
}
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
if (theStreams.Size() > 1)
|
||||
{
|
||||
if (theIsVerbose)
|
||||
{
|
||||
Message::SendWarning() << "Warning during " << theContext << ": Received "
|
||||
<< theStreams.Size() << " streams, using only the first one";
|
||||
}
|
||||
}
|
||||
|
||||
// Additional validation for input streams
|
||||
try
|
||||
{
|
||||
const DE_Provider::ReadStreamNode& aNode = theStreams.First();
|
||||
if (aNode.Stream.fail())
|
||||
{
|
||||
if (theIsVerbose)
|
||||
{
|
||||
TCollection_AsciiString aKeyInfo = aNode.Path.IsEmpty() ? "<empty path>" : aNode.Path;
|
||||
Message::SendFail() << "Error during " << theContext << ": Input stream '" << aKeyInfo
|
||||
<< "' is in invalid state";
|
||||
}
|
||||
return Standard_False;
|
||||
}
|
||||
}
|
||||
catch (const std::exception&)
|
||||
{
|
||||
if (theIsVerbose)
|
||||
{
|
||||
const DE_Provider::ReadStreamNode& aNode = theStreams.First();
|
||||
TCollection_AsciiString aKeyInfo = aNode.Path.IsEmpty() ? "<empty path>" : aNode.Path;
|
||||
Message::SendFail() << "Error during " << theContext << ": Cannot access input stream '"
|
||||
<< aKeyInfo << "'";
|
||||
}
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
return Standard_True;
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DE_ValidationUtils::ValidateWriteStreamList(
|
||||
DE_Provider::WriteStreamList& theStreams,
|
||||
const TCollection_AsciiString& theContext,
|
||||
const Standard_Boolean theIsVerbose)
|
||||
{
|
||||
if (theStreams.IsEmpty())
|
||||
{
|
||||
if (theIsVerbose)
|
||||
{
|
||||
Message::SendFail() << "Error during " << theContext << ": Stream list is empty";
|
||||
}
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
if (theStreams.Size() > 1)
|
||||
{
|
||||
if (theIsVerbose)
|
||||
{
|
||||
Message::SendWarning() << "Warning during " << theContext << ": Received "
|
||||
<< theStreams.Size() << " streams, using only the first one";
|
||||
}
|
||||
}
|
||||
|
||||
// Additional validation for output streams
|
||||
try
|
||||
{
|
||||
const DE_Provider::WriteStreamNode& aNode = theStreams.First();
|
||||
if (aNode.Stream.fail())
|
||||
{
|
||||
if (theIsVerbose)
|
||||
{
|
||||
TCollection_AsciiString aKeyInfo = aNode.Path.IsEmpty() ? "<empty path>" : aNode.Path;
|
||||
Message::SendFail() << "Error during " << theContext << ": Output stream '" << aKeyInfo
|
||||
<< "' is in invalid state";
|
||||
}
|
||||
return Standard_False;
|
||||
}
|
||||
}
|
||||
catch (const std::exception&)
|
||||
{
|
||||
if (theIsVerbose)
|
||||
{
|
||||
const DE_Provider::WriteStreamNode& aNode = theStreams.First();
|
||||
TCollection_AsciiString aKeyInfo = aNode.Path.IsEmpty() ? "<empty path>" : aNode.Path;
|
||||
Message::SendFail() << "Error during " << theContext << ": Cannot access output stream '"
|
||||
<< aKeyInfo << "'";
|
||||
}
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
return Standard_True;
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DE_ValidationUtils::ValidateDocument(const Handle(TDocStd_Document)& theDocument,
|
||||
const TCollection_AsciiString& theContext,
|
||||
const Standard_Boolean theIsVerbose)
|
||||
{
|
||||
if (theDocument.IsNull())
|
||||
{
|
||||
if (theIsVerbose)
|
||||
{
|
||||
Message::SendFail() << "Error during " << theContext << ": Document handle is null";
|
||||
}
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
return Standard_True;
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DE_ValidationUtils::WarnLengthUnitNotSupported(
|
||||
const Standard_Real theLengthUnit,
|
||||
const TCollection_AsciiString& theContext,
|
||||
const Standard_Boolean theIsVerbose)
|
||||
{
|
||||
if (theIsVerbose && theLengthUnit != 1.0)
|
||||
{
|
||||
Message::SendWarning() << "Warning during " << theContext
|
||||
<< ": Format doesn't support custom length unit scaling (unit: "
|
||||
<< theLengthUnit << ")";
|
||||
}
|
||||
|
||||
return Standard_True;
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DE_ValidationUtils::CreateContentBuffer(const TCollection_AsciiString& thePath,
|
||||
Handle(NCollection_Buffer)& theBuffer)
|
||||
{
|
||||
const Handle(OSD_FileSystem)& aFileSystem = OSD_FileSystem::DefaultFileSystem();
|
||||
std::shared_ptr<std::istream> aStream =
|
||||
aFileSystem->OpenIStream(thePath, std::ios::in | std::ios::binary);
|
||||
|
||||
if (aStream.get() == nullptr)
|
||||
{
|
||||
theBuffer.Nullify();
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
return CreateContentBuffer(*aStream, theBuffer);
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DE_ValidationUtils::CreateContentBuffer(std::istream& theStream,
|
||||
Handle(NCollection_Buffer)& theBuffer)
|
||||
{
|
||||
constexpr std::streamsize aBufferLength = 2048;
|
||||
|
||||
theBuffer =
|
||||
new NCollection_Buffer(NCollection_BaseAllocator::CommonBaseAllocator(), aBufferLength);
|
||||
|
||||
// Save current stream position
|
||||
std::streampos aOriginalPos = theStream.tellg();
|
||||
|
||||
theStream.read(reinterpret_cast<char*>(theBuffer->ChangeData()), aBufferLength);
|
||||
const std::streamsize aBytesRead = theStream.gcount();
|
||||
theBuffer->ChangeData()[aBytesRead < aBufferLength ? aBytesRead : aBufferLength - 1] = '\0';
|
||||
|
||||
// Clear any error flags (including EOF) BEFORE attempting to reset position
|
||||
// This is essential because seekg() fails when EOF flag is set
|
||||
theStream.clear();
|
||||
|
||||
// Reset stream to original position for subsequent reads
|
||||
theStream.seekg(aOriginalPos);
|
||||
|
||||
return Standard_True;
|
||||
}
|
118
src/DataExchange/TKDE/DE/DE_ValidationUtils.hxx
Normal file
118
src/DataExchange/TKDE/DE/DE_ValidationUtils.hxx
Normal file
@@ -0,0 +1,118 @@
|
||||
// Copyright (c) 2025 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 _DE_ValidationUtils_HeaderFile
|
||||
#define _DE_ValidationUtils_HeaderFile
|
||||
|
||||
#include <TCollection_AsciiString.hxx>
|
||||
#include <DE_ConfigurationNode.hxx>
|
||||
#include <DE_Provider.hxx>
|
||||
|
||||
class TDocStd_Document;
|
||||
|
||||
//! Utility class providing static methods for common validation operations
|
||||
//! used across DataExchange providers. Includes validation for configuration nodes,
|
||||
//! file paths, streams, and other common scenarios with optional verbose error reporting.
|
||||
class DE_ValidationUtils
|
||||
{
|
||||
public:
|
||||
//! Validates that configuration node is not null and matches expected type
|
||||
//! @param[in] theNode configuration node to validate
|
||||
//! @param[in] theExpectedType expected RTTI type
|
||||
//! @param[in] theContext context string for error messages
|
||||
//! @param[in] theIsVerbose if true, sends detailed error messages via Message::SendFail
|
||||
//! @return Standard_True if node is valid, Standard_False otherwise
|
||||
Standard_EXPORT static Standard_Boolean ValidateConfigurationNode(
|
||||
const Handle(DE_ConfigurationNode)& theNode,
|
||||
const Handle(Standard_Type)& theExpectedType,
|
||||
const TCollection_AsciiString& theContext,
|
||||
const Standard_Boolean theIsVerbose = Standard_True);
|
||||
|
||||
//! Checks if file exists and is readable
|
||||
//! @param[in] thePath file path to check
|
||||
//! @param[in] theContext context string for error messages
|
||||
//! @param[in] theIsVerbose if true, sends detailed error messages via Message::SendFail
|
||||
//! @return Standard_True if file exists and is readable, Standard_False otherwise
|
||||
Standard_EXPORT static Standard_Boolean ValidateFileForReading(
|
||||
const TCollection_AsciiString& thePath,
|
||||
const TCollection_AsciiString& theContext,
|
||||
const Standard_Boolean theIsVerbose = Standard_True);
|
||||
|
||||
//! Checks if file location is writable (file may or may not exist)
|
||||
//! @param[in] thePath file path to check
|
||||
//! @param[in] theContext context string for error messages
|
||||
//! @param[in] theIsVerbose if true, sends detailed error messages via Message::SendFail
|
||||
//! @return Standard_True if location is writable, Standard_False otherwise
|
||||
Standard_EXPORT static Standard_Boolean ValidateFileForWriting(
|
||||
const TCollection_AsciiString& thePath,
|
||||
const TCollection_AsciiString& theContext,
|
||||
const Standard_Boolean theIsVerbose = Standard_True);
|
||||
|
||||
//! Validates read stream list, warns if multiple streams
|
||||
//! @param[in] theStreams read stream list to validate
|
||||
//! @param[in] theContext context string for error messages
|
||||
//! @param[in] theIsVerbose if true, sends detailed error/warning messages
|
||||
//! @return Standard_True if stream list is valid, Standard_False otherwise
|
||||
Standard_EXPORT static Standard_Boolean ValidateReadStreamList(
|
||||
const DE_Provider::ReadStreamList& theStreams,
|
||||
const TCollection_AsciiString& theContext,
|
||||
const Standard_Boolean theIsVerbose = Standard_True);
|
||||
|
||||
//! Validates write stream list, warns if multiple streams
|
||||
//! @param[in] theStreams write stream list to validate
|
||||
//! @param[in] theContext context string for error messages
|
||||
//! @param[in] theIsVerbose if true, sends detailed error/warning messages
|
||||
//! @return Standard_True if stream list is valid, Standard_False otherwise
|
||||
Standard_EXPORT static Standard_Boolean ValidateWriteStreamList(
|
||||
DE_Provider::WriteStreamList& theStreams,
|
||||
const TCollection_AsciiString& theContext,
|
||||
const Standard_Boolean theIsVerbose = Standard_True);
|
||||
|
||||
//! Validates that TDocStd_Document handle is not null
|
||||
//! @param[in] theDocument document to validate
|
||||
//! @param[in] theContext context string for error messages
|
||||
//! @param[in] theIsVerbose if true, sends detailed error messages via Message::SendFail
|
||||
//! @return Standard_True if document is not null, Standard_False otherwise
|
||||
Standard_EXPORT static Standard_Boolean ValidateDocument(
|
||||
const Handle(TDocStd_Document)& theDocument,
|
||||
const TCollection_AsciiString& theContext,
|
||||
const Standard_Boolean theIsVerbose = Standard_True);
|
||||
|
||||
//! Sends warning when format doesn't support length unit scaling
|
||||
//! @param[in] theLengthUnit length unit value to check
|
||||
//! @param[in] theContext context string for warning messages
|
||||
//! @param[in] theIsVerbose if true, sends warning messages via Message::SendWarning
|
||||
//! @return Standard_True always (this is just a warning)
|
||||
Standard_EXPORT static Standard_Boolean WarnLengthUnitNotSupported(
|
||||
const Standard_Real theLengthUnit,
|
||||
const TCollection_AsciiString& theContext,
|
||||
const Standard_Boolean theIsVerbose = Standard_True);
|
||||
|
||||
//! Creates buffer by reading from file stream for content checking
|
||||
//! @param[in] thePath file path for reading
|
||||
//! @param[out] theBuffer output buffer with file content
|
||||
//! @return Standard_True if successful, Standard_False otherwise
|
||||
Standard_EXPORT static Standard_Boolean CreateContentBuffer(
|
||||
const TCollection_AsciiString& thePath,
|
||||
Handle(NCollection_Buffer)& theBuffer);
|
||||
|
||||
//! Creates buffer by reading from input stream for content checking
|
||||
//! @param[in,out] theStream input stream to read from (position will be restored)
|
||||
//! @param[out] theBuffer output buffer with stream content
|
||||
//! @return Standard_True if successful, Standard_False otherwise
|
||||
Standard_EXPORT static Standard_Boolean CreateContentBuffer(
|
||||
std::istream& theStream,
|
||||
Handle(NCollection_Buffer)& theBuffer);
|
||||
};
|
||||
|
||||
#endif // _DE_ValidationUtils_HeaderFile
|
@@ -16,6 +16,7 @@
|
||||
#include <DE_ConfigurationContext.hxx>
|
||||
#include <DE_ConfigurationNode.hxx>
|
||||
#include <DE_Provider.hxx>
|
||||
#include <DE_ValidationUtils.hxx>
|
||||
#include <Message_ProgressRange.hxx>
|
||||
#include <NCollection_Buffer.hxx>
|
||||
#include <OSD_File.hxx>
|
||||
@@ -499,18 +500,26 @@ Standard_Boolean DE_Wrapper::FindProvider(const TCollection_AsciiString& thePath
|
||||
const Standard_Boolean theToImport,
|
||||
Handle(DE_Provider)& theProvider) const
|
||||
{
|
||||
Handle(NCollection_Buffer) aBuffer;
|
||||
if (theToImport)
|
||||
{
|
||||
const Handle(OSD_FileSystem)& aFileSystem = OSD_FileSystem::DefaultFileSystem();
|
||||
std::shared_ptr<std::istream> aStream =
|
||||
aFileSystem->OpenIStream(thePath, std::ios::in | std::ios::binary);
|
||||
if (aStream.get() != nullptr)
|
||||
{
|
||||
aBuffer = new NCollection_Buffer(NCollection_BaseAllocator::CommonBaseAllocator(), 2048);
|
||||
aStream->read((char*)aBuffer->ChangeData(), 2048);
|
||||
aBuffer->ChangeData()[2047] = '\0';
|
||||
}
|
||||
return FindReadProvider(thePath, Standard_True, theProvider);
|
||||
}
|
||||
else
|
||||
{
|
||||
return FindWriteProvider(thePath, theProvider);
|
||||
}
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DE_Wrapper::FindReadProvider(const TCollection_AsciiString& thePath,
|
||||
const Standard_Boolean theCheckContent,
|
||||
Handle(DE_Provider)& theProvider) const
|
||||
{
|
||||
Handle(NCollection_Buffer) aBuffer;
|
||||
if (theCheckContent && !DE_ValidationUtils::CreateContentBuffer(thePath, aBuffer))
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
OSD_Path aPath(thePath);
|
||||
const TCollection_AsciiString anExtr = aPath.Extension();
|
||||
@@ -521,11 +530,69 @@ Standard_Boolean DE_Wrapper::FindProvider(const TCollection_AsciiString& thePath
|
||||
aVendorIter.Next())
|
||||
{
|
||||
const Handle(DE_ConfigurationNode)& aNode = aVendorIter.Value();
|
||||
if (aNode->IsEnabled()
|
||||
&& ((theToImport && aNode->IsImportSupported())
|
||||
|| (!theToImport && aNode->IsExportSupported()))
|
||||
&& (aNode->CheckExtension(anExtr) || (theToImport && aNode->CheckContent(aBuffer)))
|
||||
&& aNode->UpdateLoad(theToImport, myKeepUpdates))
|
||||
if (aNode->IsEnabled() && aNode->IsImportSupported()
|
||||
&& (aNode->CheckExtension(anExtr) || (theCheckContent && aNode->CheckContent(aBuffer)))
|
||||
&& aNode->UpdateLoad(Standard_True, myKeepUpdates))
|
||||
{
|
||||
theProvider = aNode->BuildProvider();
|
||||
aNode->GlobalParameters = GlobalParameters;
|
||||
return Standard_True;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DE_Wrapper::FindReadProvider(const TCollection_AsciiString& thePath,
|
||||
std::istream& theStream,
|
||||
Handle(DE_Provider)& theProvider) const
|
||||
{
|
||||
Handle(NCollection_Buffer) aBuffer;
|
||||
if (!DE_ValidationUtils::CreateContentBuffer(theStream, aBuffer))
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
OSD_Path aPath(thePath);
|
||||
const TCollection_AsciiString anExtr = aPath.Extension();
|
||||
for (DE_ConfigurationFormatMap::Iterator aFormatIter(myConfiguration); aFormatIter.More();
|
||||
aFormatIter.Next())
|
||||
{
|
||||
for (DE_ConfigurationVendorMap::Iterator aVendorIter(aFormatIter.Value()); aVendorIter.More();
|
||||
aVendorIter.Next())
|
||||
{
|
||||
const Handle(DE_ConfigurationNode)& aNode = aVendorIter.Value();
|
||||
if (aNode->IsEnabled() && aNode->IsImportSupported()
|
||||
&& (aNode->CheckExtension(anExtr) || aNode->CheckContent(aBuffer))
|
||||
&& aNode->UpdateLoad(Standard_True, myKeepUpdates))
|
||||
{
|
||||
theProvider = aNode->BuildProvider();
|
||||
aNode->GlobalParameters = GlobalParameters;
|
||||
return Standard_True;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DE_Wrapper::FindWriteProvider(const TCollection_AsciiString& thePath,
|
||||
Handle(DE_Provider)& theProvider) const
|
||||
{
|
||||
OSD_Path aPath(thePath);
|
||||
const TCollection_AsciiString anExtr = aPath.Extension();
|
||||
for (DE_ConfigurationFormatMap::Iterator aFormatIter(myConfiguration); aFormatIter.More();
|
||||
aFormatIter.Next())
|
||||
{
|
||||
for (DE_ConfigurationVendorMap::Iterator aVendorIter(aFormatIter.Value()); aVendorIter.More();
|
||||
aVendorIter.Next())
|
||||
{
|
||||
const Handle(DE_ConfigurationNode)& aNode = aVendorIter.Value();
|
||||
if (aNode->IsEnabled() && aNode->IsExportSupported() && aNode->CheckExtension(anExtr)
|
||||
&& aNode->UpdateLoad(Standard_False, myKeepUpdates))
|
||||
{
|
||||
theProvider = aNode->BuildProvider();
|
||||
aNode->GlobalParameters = GlobalParameters;
|
||||
@@ -572,3 +639,251 @@ void DE_Wrapper::sort(const Handle(DE_ConfigurationContext)& theResource)
|
||||
ChangePriority(aFormatIter.Key(), aVendorPriority, Standard_True);
|
||||
}
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DE_Wrapper::Read(DE_Provider::ReadStreamList& theStreams,
|
||||
const Handle(TDocStd_Document)& theDocument,
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
if (!DE_ValidationUtils::ValidateReadStreamList(theStreams, "DE_Wrapper Read"))
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
const TCollection_AsciiString& aFirstKey = theStreams.First().Path;
|
||||
|
||||
Handle(DE_Provider) aProvider;
|
||||
Standard_IStream& aFirstStream = theStreams.First().Stream;
|
||||
if (!FindReadProvider(aFirstKey, aFirstStream, aProvider))
|
||||
{
|
||||
Message::SendFail() << "Error: DE_Wrapper cannot find provider for stream " << aFirstKey;
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
if (!aProvider->GetNode()->IsStreamSupported())
|
||||
{
|
||||
Message::SendFail() << "Error: Provider " << aProvider->GetFormat() << " "
|
||||
<< aProvider->GetVendor() << " doesn't support stream operations";
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
return aProvider->Read(theStreams, theDocument, theWS, theProgress);
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DE_Wrapper::Write(DE_Provider::WriteStreamList& theStreams,
|
||||
const Handle(TDocStd_Document)& theDocument,
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
if (!DE_ValidationUtils::ValidateWriteStreamList(theStreams, "DE_Wrapper Write"))
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
const TCollection_AsciiString& aFirstKey = theStreams.First().Path;
|
||||
|
||||
Handle(DE_Provider) aProvider;
|
||||
if (!FindWriteProvider(aFirstKey, aProvider))
|
||||
{
|
||||
Message::SendFail() << "Error: DE_Wrapper cannot find provider for stream " << aFirstKey;
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
if (!aProvider->GetNode()->IsStreamSupported())
|
||||
{
|
||||
Message::SendFail() << "Error: Provider " << aProvider->GetFormat() << " "
|
||||
<< aProvider->GetVendor() << " doesn't support stream operations";
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
return aProvider->Write(theStreams, theDocument, theWS, theProgress);
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DE_Wrapper::Read(DE_Provider::ReadStreamList& theStreams,
|
||||
const Handle(TDocStd_Document)& theDocument,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
if (!DE_ValidationUtils::ValidateReadStreamList(theStreams, "DE_Wrapper Read"))
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
const TCollection_AsciiString& aFirstKey = theStreams.First().Path;
|
||||
|
||||
Handle(DE_Provider) aProvider;
|
||||
Standard_IStream& aFirstStream = theStreams.First().Stream;
|
||||
if (!FindReadProvider(aFirstKey, aFirstStream, aProvider))
|
||||
{
|
||||
Message::SendFail() << "Error: DE_Wrapper cannot find provider for stream " << aFirstKey;
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
if (!aProvider->GetNode()->IsStreamSupported())
|
||||
{
|
||||
Message::SendFail() << "Error: Provider " << aProvider->GetFormat() << " "
|
||||
<< aProvider->GetVendor() << " doesn't support stream operations";
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
return aProvider->Read(theStreams, theDocument, theProgress);
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DE_Wrapper::Write(DE_Provider::WriteStreamList& theStreams,
|
||||
const Handle(TDocStd_Document)& theDocument,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
if (!DE_ValidationUtils::ValidateWriteStreamList(theStreams, "DE_Wrapper Write"))
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
const TCollection_AsciiString& aFirstKey = theStreams.First().Path;
|
||||
|
||||
Handle(DE_Provider) aProvider;
|
||||
if (!FindWriteProvider(aFirstKey, aProvider))
|
||||
{
|
||||
Message::SendFail() << "Error: DE_Wrapper cannot find provider for stream " << aFirstKey;
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
if (!aProvider->GetNode()->IsStreamSupported())
|
||||
{
|
||||
Message::SendFail() << "Error: Provider " << aProvider->GetFormat() << " "
|
||||
<< aProvider->GetVendor() << " doesn't support stream operations";
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
return aProvider->Write(theStreams, theDocument, theProgress);
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DE_Wrapper::Read(DE_Provider::ReadStreamList& theStreams,
|
||||
TopoDS_Shape& theShape,
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
if (!DE_ValidationUtils::ValidateReadStreamList(theStreams, "DE_Wrapper Read"))
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
const TCollection_AsciiString& aFirstKey = theStreams.First().Path;
|
||||
|
||||
Handle(DE_Provider) aProvider;
|
||||
Standard_IStream& aFirstStream = theStreams.First().Stream;
|
||||
if (!FindReadProvider(aFirstKey, aFirstStream, aProvider))
|
||||
{
|
||||
Message::SendFail() << "Error: DE_Wrapper cannot find provider for stream " << aFirstKey;
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
if (!aProvider->GetNode()->IsStreamSupported())
|
||||
{
|
||||
Message::SendFail() << "Error: Provider " << aProvider->GetFormat() << " "
|
||||
<< aProvider->GetVendor() << " doesn't support stream operations";
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
return aProvider->Read(theStreams, theShape, theWS, theProgress);
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DE_Wrapper::Write(DE_Provider::WriteStreamList& theStreams,
|
||||
const TopoDS_Shape& theShape,
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
if (!DE_ValidationUtils::ValidateWriteStreamList(theStreams, "DE_Wrapper Write"))
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
const TCollection_AsciiString& aFirstKey = theStreams.First().Path;
|
||||
|
||||
Handle(DE_Provider) aProvider;
|
||||
if (!FindWriteProvider(aFirstKey, aProvider))
|
||||
{
|
||||
Message::SendFail() << "Error: DE_Wrapper cannot find provider for stream " << aFirstKey;
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
if (!aProvider->GetNode()->IsStreamSupported())
|
||||
{
|
||||
Message::SendFail() << "Error: Provider " << aProvider->GetFormat() << " "
|
||||
<< aProvider->GetVendor() << " doesn't support stream operations";
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
return aProvider->Write(theStreams, theShape, theWS, theProgress);
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DE_Wrapper::Read(DE_Provider::ReadStreamList& theStreams,
|
||||
TopoDS_Shape& theShape,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
if (!DE_ValidationUtils::ValidateReadStreamList(theStreams, "DE_Wrapper Read"))
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
const TCollection_AsciiString& aFirstKey = theStreams.First().Path;
|
||||
|
||||
Handle(DE_Provider) aProvider;
|
||||
Standard_IStream& aFirstStream = theStreams.First().Stream;
|
||||
if (!FindReadProvider(aFirstKey, aFirstStream, aProvider))
|
||||
{
|
||||
Message::SendFail() << "Error: DE_Wrapper cannot find provider for stream " << aFirstKey;
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
if (!aProvider->GetNode()->IsStreamSupported())
|
||||
{
|
||||
Message::SendFail() << "Error: Provider " << aProvider->GetFormat() << " "
|
||||
<< aProvider->GetVendor() << " doesn't support stream operations";
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
return aProvider->Read(theStreams, theShape, theProgress);
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DE_Wrapper::Write(DE_Provider::WriteStreamList& theStreams,
|
||||
const TopoDS_Shape& theShape,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
if (!DE_ValidationUtils::ValidateWriteStreamList(theStreams, "DE_Wrapper Write"))
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
const TCollection_AsciiString& aFirstKey = theStreams.First().Path;
|
||||
|
||||
Handle(DE_Provider) aProvider;
|
||||
if (!FindWriteProvider(aFirstKey, aProvider))
|
||||
{
|
||||
Message::SendFail() << "Error: DE_Wrapper cannot find provider for stream " << aFirstKey;
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
if (!aProvider->GetNode()->IsStreamSupported())
|
||||
{
|
||||
Message::SendFail() << "Error: Provider " << aProvider->GetFormat() << " "
|
||||
<< aProvider->GetVendor() << " doesn't support stream operations";
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
return aProvider->Write(theStreams, theShape, theProgress);
|
||||
}
|
||||
|
@@ -15,6 +15,7 @@
|
||||
#define _DE_Wrapper_HeaderFile
|
||||
|
||||
#include <DE_ConfigurationNode.hxx>
|
||||
#include <DE_Provider.hxx>
|
||||
#include <Message_ProgressRange.hxx>
|
||||
#include <NCollection_DataMap.hxx>
|
||||
#include <NCollection_IndexedDataMap.hxx>
|
||||
@@ -163,6 +164,94 @@ public:
|
||||
const TopoDS_Shape& theShape,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange());
|
||||
|
||||
//! Reads streams according to internal configuration
|
||||
//! @param[in] theStreams streams to read from
|
||||
//! @param[out] theDocument document to save result
|
||||
//! @param[in] theWS current work session
|
||||
//! @param[in] theProgress progress indicator
|
||||
//! @return true if Read operation has ended correctly
|
||||
Standard_EXPORT Standard_Boolean
|
||||
Read(DE_Provider::ReadStreamList& theStreams,
|
||||
const Handle(TDocStd_Document)& theDocument,
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange());
|
||||
|
||||
//! Writes streams according to internal configuration
|
||||
//! @param[in] theStreams streams to write to
|
||||
//! @param[out] theDocument document to export
|
||||
//! @param[in] theWS current work session
|
||||
//! @param[in] theProgress progress indicator
|
||||
//! @return true if Write operation has ended correctly
|
||||
Standard_EXPORT Standard_Boolean
|
||||
Write(DE_Provider::WriteStreamList& theStreams,
|
||||
const Handle(TDocStd_Document)& theDocument,
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange());
|
||||
|
||||
//! Reads streams according to internal configuration
|
||||
//! @param[in] theStreams streams to read from
|
||||
//! @param[out] theDocument document to save result
|
||||
//! @param[in] theProgress progress indicator
|
||||
//! @return true if Read operation has ended correctly
|
||||
Standard_EXPORT Standard_Boolean
|
||||
Read(DE_Provider::ReadStreamList& theStreams,
|
||||
const Handle(TDocStd_Document)& theDocument,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange());
|
||||
|
||||
//! Writes streams according to internal configuration
|
||||
//! @param[in] theStreams streams to write to
|
||||
//! @param[out] theDocument document to export
|
||||
//! @param[in] theProgress progress indicator
|
||||
//! @return true if Write operation has ended correctly
|
||||
Standard_EXPORT Standard_Boolean
|
||||
Write(DE_Provider::WriteStreamList& theStreams,
|
||||
const Handle(TDocStd_Document)& theDocument,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange());
|
||||
|
||||
//! Reads streams according to internal configuration
|
||||
//! @param[in] theStreams streams to read from
|
||||
//! @param[out] theShape shape to save result
|
||||
//! @param[in] theWS current work session
|
||||
//! @param[in] theProgress progress indicator
|
||||
//! @return true if Read operation has ended correctly
|
||||
Standard_EXPORT Standard_Boolean
|
||||
Read(DE_Provider::ReadStreamList& theStreams,
|
||||
TopoDS_Shape& theShape,
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange());
|
||||
|
||||
//! Writes streams according to internal configuration
|
||||
//! @param[in] theStreams streams to write to
|
||||
//! @param[out] theShape shape to export
|
||||
//! @param[in] theWS current work session
|
||||
//! @param[in] theProgress progress indicator
|
||||
//! @return true if Write operation has ended correctly
|
||||
Standard_EXPORT Standard_Boolean
|
||||
Write(DE_Provider::WriteStreamList& theStreams,
|
||||
const TopoDS_Shape& theShape,
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange());
|
||||
|
||||
//! Reads streams according to internal configuration
|
||||
//! @param[in] theStreams streams to read from
|
||||
//! @param[out] theShape shape to save result
|
||||
//! @param[in] theProgress progress indicator
|
||||
//! @return true if Read operation has ended correctly
|
||||
Standard_EXPORT Standard_Boolean
|
||||
Read(DE_Provider::ReadStreamList& theStreams,
|
||||
TopoDS_Shape& theShape,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange());
|
||||
|
||||
//! Writes streams according to internal configuration
|
||||
//! @param[in] theStreams streams to write to
|
||||
//! @param[out] theShape shape to export
|
||||
//! @param[in] theProgress progress indicator
|
||||
//! @return true if Write operation has ended correctly
|
||||
Standard_EXPORT Standard_Boolean
|
||||
Write(DE_Provider::WriteStreamList& theStreams,
|
||||
const TopoDS_Shape& theShape,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange());
|
||||
|
||||
public:
|
||||
//! Updates values according the resource file
|
||||
//! @param[in] theResource file path to resource or resource value
|
||||
@@ -243,6 +332,35 @@ public:
|
||||
const Standard_Boolean theToImport,
|
||||
Handle(DE_Provider)& theProvider) const;
|
||||
|
||||
//! Find available read provider from the configuration for file-based operations.
|
||||
//! If there are several providers, choose the one with the highest priority.
|
||||
//! @param[in] thePath path to the CAD file (for extension and content checking)
|
||||
//! @param[in] theCheckContent flag to enable content checking via file reading
|
||||
//! @param[out] theProvider created new provider
|
||||
//! @return Standard_True if provider found and created
|
||||
Standard_EXPORT virtual Standard_Boolean FindReadProvider(const TCollection_AsciiString& thePath,
|
||||
const Standard_Boolean theCheckContent,
|
||||
Handle(DE_Provider)& theProvider) const;
|
||||
|
||||
//! Find available read provider from the configuration for stream-based operations.
|
||||
//! If there are several providers, choose the one with the highest priority.
|
||||
//! @param[in] thePath path to the CAD file (for extension extraction)
|
||||
//! @param[in] theStream input stream for content checking
|
||||
//! @param[out] theProvider created new provider
|
||||
//! @return Standard_True if provider found and created
|
||||
Standard_EXPORT virtual Standard_Boolean FindReadProvider(const TCollection_AsciiString& thePath,
|
||||
std::istream& theStream,
|
||||
Handle(DE_Provider)& theProvider) const;
|
||||
|
||||
//! Find available write provider from the configuration.
|
||||
//! If there are several providers, choose the one with the highest priority.
|
||||
//! @param[in] thePath path to the CAD file (for extension checking only)
|
||||
//! @param[out] theProvider created new provider
|
||||
//! @return Standard_True if provider found and created
|
||||
Standard_EXPORT virtual Standard_Boolean FindWriteProvider(
|
||||
const TCollection_AsciiString& thePath,
|
||||
Handle(DE_Provider)& theProvider) const;
|
||||
|
||||
//! Updates all registered nodes, all changes will be saved in nodes
|
||||
//! @param[in] theToForceUpdate flag that turns on/of nodes, according to updated ability to
|
||||
//! import/export
|
||||
|
@@ -12,6 +12,8 @@ set(OCCT_DE_FILES
|
||||
DE_ShapeFixConfigurationNode.cxx
|
||||
DE_ShapeFixConfigurationNode.hxx
|
||||
DE_ShapeFixParameters.hxx
|
||||
DE_ValidationUtils.cxx
|
||||
DE_ValidationUtils.hxx
|
||||
DE_Wrapper.cxx
|
||||
DE_Wrapper.hxx
|
||||
)
|
||||
|
@@ -13,6 +13,7 @@
|
||||
|
||||
#include <DEGLTF_Provider.hxx>
|
||||
|
||||
#include <DE_ValidationUtils.hxx>
|
||||
#include <Message.hxx>
|
||||
#include <RWGltf_CafWriter.hxx>
|
||||
#include <TDocStd_Document.hxx>
|
||||
@@ -86,17 +87,15 @@ bool DEGLTF_Provider::Read(const TCollection_AsciiString& thePath,
|
||||
const Handle(TDocStd_Document)& theDocument,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
if (theDocument.IsNull())
|
||||
TCollection_AsciiString aContext = TCollection_AsciiString("reading the file ") + thePath;
|
||||
if (!DE_ValidationUtils::ValidateDocument(theDocument, aContext))
|
||||
{
|
||||
Message::SendFail() << "Error in the DEGLTF_Provider during reading the file " << thePath
|
||||
<< "\t: theDocument shouldn't be null";
|
||||
return false;
|
||||
}
|
||||
if (GetNode().IsNull()
|
||||
|| (!GetNode().IsNull() && !GetNode()->IsKind(STANDARD_TYPE(DEGLTF_ConfigurationNode))))
|
||||
if (!DE_ValidationUtils::ValidateConfigurationNode(GetNode(),
|
||||
STANDARD_TYPE(DEGLTF_ConfigurationNode),
|
||||
aContext))
|
||||
{
|
||||
Message::SendFail() << "Error in the DEGLTF_Provider during reading the file " << thePath
|
||||
<< "\t: Incorrect or empty Configuration Node";
|
||||
return false;
|
||||
}
|
||||
Handle(DEGLTF_ConfigurationNode) aNode = Handle(DEGLTF_ConfigurationNode)::DownCast(GetNode());
|
||||
@@ -121,10 +120,11 @@ bool DEGLTF_Provider::Write(const TCollection_AsciiString& thePath,
|
||||
const Handle(TDocStd_Document)& theDocument,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
if (GetNode().IsNull() || !GetNode()->IsKind(STANDARD_TYPE(DEGLTF_ConfigurationNode)))
|
||||
TCollection_AsciiString aContext = TCollection_AsciiString("writing the file ") + thePath;
|
||||
if (!DE_ValidationUtils::ValidateConfigurationNode(GetNode(),
|
||||
STANDARD_TYPE(DEGLTF_ConfigurationNode),
|
||||
aContext))
|
||||
{
|
||||
Message::SendFail() << "Error in the DEGLTF_Provider during writing the file " << thePath
|
||||
<< "\t: Incorrect or empty Configuration Node";
|
||||
return false;
|
||||
}
|
||||
Handle(DEGLTF_ConfigurationNode) aNode = Handle(DEGLTF_ConfigurationNode)::DownCast(GetNode());
|
||||
@@ -141,9 +141,11 @@ bool DEGLTF_Provider::Write(const TCollection_AsciiString& thePath,
|
||||
aConverter.SetInputCoordinateSystem(aNode->InternalParameters.SystemCS);
|
||||
if (aNode->GlobalParameters.LengthUnit != 1000.)
|
||||
{
|
||||
TCollection_AsciiString aContext = TCollection_AsciiString("writing the file ") + thePath;
|
||||
Message::SendWarning()
|
||||
<< "Warning in the DEGLTF_Provider during writing the file " << thePath
|
||||
<< "\t: Target format doesn't support custom units. Model will be scaled to Meters";
|
||||
<< "Warning during " << aContext
|
||||
<< ": Target format doesn't support custom units. Model will be scaled to Meters (unit: "
|
||||
<< aNode->GlobalParameters.LengthUnit << ")";
|
||||
}
|
||||
aConverter.SetOutputLengthUnit(1.); // gltf units always Meters
|
||||
aConverter.SetOutputCoordinateSystem(aNode->InternalParameters.FileCS);
|
||||
|
@@ -13,6 +13,7 @@
|
||||
|
||||
#include <DEIGES_Provider.hxx>
|
||||
|
||||
#include <DE_ValidationUtils.hxx>
|
||||
#include <DEIGES_ConfigurationNode.hxx>
|
||||
#include <IGESCAFControl_Reader.hxx>
|
||||
#include <IGESCAFControl_Writer.hxx>
|
||||
@@ -27,6 +28,128 @@
|
||||
|
||||
IMPLEMENT_STANDARD_RTTIEXT(DEIGES_Provider, DE_Provider)
|
||||
|
||||
namespace
|
||||
{
|
||||
// Helper function to validate configuration node
|
||||
Standard_Boolean validateConfigurationNode(const Handle(DE_ConfigurationNode)& theNode,
|
||||
const TCollection_AsciiString& theContext)
|
||||
{
|
||||
return DE_ValidationUtils::ValidateConfigurationNode(theNode,
|
||||
STANDARD_TYPE(DEIGES_ConfigurationNode),
|
||||
theContext);
|
||||
}
|
||||
|
||||
// Helper function to configure IGES CAF reader parameters
|
||||
void configureIGESCAFReader(IGESCAFControl_Reader& theReader,
|
||||
const Handle(DEIGES_ConfigurationNode)& theNode)
|
||||
{
|
||||
theReader.SetReadVisible(theNode->InternalParameters.ReadOnlyVisible);
|
||||
theReader.SetColorMode(theNode->InternalParameters.ReadColor);
|
||||
theReader.SetNameMode(theNode->InternalParameters.ReadName);
|
||||
theReader.SetLayerMode(theNode->InternalParameters.ReadLayer);
|
||||
theReader.SetShapeFixParameters(theNode->ShapeFixParameters);
|
||||
}
|
||||
|
||||
// Helper function to configure IGES control reader parameters
|
||||
void configureIGESControlReader(IGESControl_Reader& theReader,
|
||||
const Handle(DEIGES_ConfigurationNode)& theNode)
|
||||
{
|
||||
theReader.SetReadVisible(theNode->InternalParameters.ReadOnlyVisible);
|
||||
theReader.SetShapeFixParameters(theNode->ShapeFixParameters);
|
||||
}
|
||||
|
||||
// Helper function to setup IGES unit configuration
|
||||
void setupIGESUnits(IGESData_GlobalSection& theGS,
|
||||
const Handle(DEIGES_ConfigurationNode)& theNode,
|
||||
const Handle(TDocStd_Document)& theDocument,
|
||||
const TCollection_AsciiString& thePath,
|
||||
Standard_Boolean theUseDocumentUnits)
|
||||
{
|
||||
Standard_Integer aFlag =
|
||||
IGESData_BasicEditor::GetFlagByValue(theNode->GlobalParameters.LengthUnit);
|
||||
|
||||
if (theUseDocumentUnits && !theDocument.IsNull())
|
||||
{
|
||||
Standard_Real aScaleFactorMM = 1.;
|
||||
Standard_Boolean aHasUnits =
|
||||
XCAFDoc_DocumentTool::GetLengthUnit(theDocument,
|
||||
aScaleFactorMM,
|
||||
UnitsMethods_LengthUnit_Millimeter);
|
||||
if (aHasUnits)
|
||||
{
|
||||
theGS.SetCascadeUnit(aScaleFactorMM);
|
||||
}
|
||||
else
|
||||
{
|
||||
theGS.SetCascadeUnit(theNode->GlobalParameters.SystemUnit);
|
||||
Message::SendWarning()
|
||||
<< "Warning in the DEIGES_Provider during writing the file " << thePath
|
||||
<< "\t: The document has no information on Units. Using global parameter as initial Unit.";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
theGS.SetCascadeUnit(theNode->GlobalParameters.SystemUnit);
|
||||
}
|
||||
|
||||
if (aFlag == 0)
|
||||
{
|
||||
theGS.SetScale(theNode->GlobalParameters.LengthUnit);
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to configure IGES CAF writer parameters
|
||||
void configureIGESCAFWriter(IGESCAFControl_Writer& theWriter,
|
||||
const Handle(DEIGES_ConfigurationNode)& theNode,
|
||||
const Handle(TDocStd_Document)& theDocument,
|
||||
const TCollection_AsciiString& thePath)
|
||||
{
|
||||
IGESData_GlobalSection aGS = theWriter.Model()->GlobalSection();
|
||||
setupIGESUnits(aGS, theNode, theDocument, thePath, Standard_True);
|
||||
|
||||
theWriter.Model()->SetGlobalSection(aGS);
|
||||
theWriter.SetColorMode(theNode->InternalParameters.WriteColor);
|
||||
theWriter.SetNameMode(theNode->InternalParameters.WriteName);
|
||||
theWriter.SetLayerMode(theNode->InternalParameters.WriteLayer);
|
||||
theWriter.SetShapeFixParameters(theNode->ShapeFixParameters);
|
||||
}
|
||||
|
||||
// Helper function to configure IGES control writer for shapes
|
||||
void configureIGESControlWriter(IGESControl_Writer& theWriter,
|
||||
const Handle(DEIGES_ConfigurationNode)& theNode)
|
||||
{
|
||||
IGESData_GlobalSection aGS = theWriter.Model()->GlobalSection();
|
||||
Handle(TDocStd_Document) aNullDoc;
|
||||
setupIGESUnits(aGS, theNode, aNullDoc, "", Standard_False);
|
||||
|
||||
theWriter.Model()->SetGlobalSection(aGS);
|
||||
theWriter.SetShapeFixParameters(theNode->ShapeFixParameters);
|
||||
}
|
||||
|
||||
// Helper function to setup IGES writer unit flags
|
||||
TCollection_AsciiString getIGESUnitString(const Handle(DEIGES_ConfigurationNode)& theNode)
|
||||
{
|
||||
Standard_Integer aFlag =
|
||||
IGESData_BasicEditor::GetFlagByValue(theNode->GlobalParameters.LengthUnit);
|
||||
return (aFlag > 0) ? IGESData_BasicEditor::UnitFlagName(aFlag) : "MM";
|
||||
}
|
||||
|
||||
// Helper function to process read file operation
|
||||
Standard_Boolean processReadFile(IGESControl_Reader& theReader,
|
||||
const TCollection_AsciiString& thePath)
|
||||
{
|
||||
IFSelect_ReturnStatus aReadStat = theReader.ReadFile(thePath.ToCString());
|
||||
if (aReadStat != IFSelect_RetDone)
|
||||
{
|
||||
Message::SendFail() << "Error in the DEIGES_Provider during reading the file " << thePath
|
||||
<< "\t: abandon, no model loaded";
|
||||
return Standard_False;
|
||||
}
|
||||
return Standard_True;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
DEIGES_Provider::DEIGES_Provider() {}
|
||||
@@ -160,35 +283,26 @@ bool DEIGES_Provider::Read(const TCollection_AsciiString& thePath,
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
if (theDocument.IsNull())
|
||||
TCollection_AsciiString aContext = TCollection_AsciiString("reading the file ") + thePath;
|
||||
if (!DE_ValidationUtils::ValidateDocument(theDocument, aContext)
|
||||
|| !validateConfigurationNode(GetNode(), aContext))
|
||||
{
|
||||
Message::SendFail() << "Error in the DEIGES_Provider during reading the file " << thePath
|
||||
<< "\t: theDocument shouldn't be null";
|
||||
return false;
|
||||
}
|
||||
if (!GetNode()->IsKind(STANDARD_TYPE(DEIGES_ConfigurationNode)))
|
||||
{
|
||||
Message::SendFail() << "Error in the DEIGES_Provider during reading the file " << thePath
|
||||
<< "\t: Incorrect or empty Configuration Node";
|
||||
return false;
|
||||
}
|
||||
|
||||
Handle(DEIGES_ConfigurationNode) aNode = Handle(DEIGES_ConfigurationNode)::DownCast(GetNode());
|
||||
personizeWS(theWS);
|
||||
initStatic(aNode);
|
||||
|
||||
XCAFDoc_DocumentTool::SetLengthUnit(theDocument,
|
||||
aNode->GlobalParameters.LengthUnit,
|
||||
UnitsMethods_LengthUnit_Millimeter);
|
||||
|
||||
IGESCAFControl_Reader aReader;
|
||||
aReader.SetWS(theWS);
|
||||
configureIGESCAFReader(aReader, aNode);
|
||||
|
||||
aReader.SetReadVisible(aNode->InternalParameters.ReadOnlyVisible);
|
||||
|
||||
aReader.SetColorMode(aNode->InternalParameters.ReadColor);
|
||||
aReader.SetNameMode(aNode->InternalParameters.ReadName);
|
||||
aReader.SetLayerMode(aNode->InternalParameters.ReadLayer);
|
||||
aReader.SetShapeFixParameters(aNode->ShapeFixParameters);
|
||||
IFSelect_ReturnStatus aReadStat = IFSelect_RetVoid;
|
||||
aReadStat = aReader.ReadFile(thePath.ToCString());
|
||||
IFSelect_ReturnStatus aReadStat = aReader.ReadFile(thePath.ToCString());
|
||||
if (aReadStat != IFSelect_RetDone)
|
||||
{
|
||||
Message::SendFail() << "Error in the DEIGES_Provider during reading the file " << thePath
|
||||
@@ -215,54 +329,30 @@ bool DEIGES_Provider::Write(const TCollection_AsciiString& thePath,
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
if (!GetNode()->IsKind(STANDARD_TYPE(DEIGES_ConfigurationNode)))
|
||||
TCollection_AsciiString aContext = TCollection_AsciiString("writing the file ") + thePath;
|
||||
if (!DE_ValidationUtils::ValidateDocument(theDocument, aContext)
|
||||
|| !validateConfigurationNode(GetNode(), aContext))
|
||||
{
|
||||
Message::SendFail() << "Error in the DEIGES_Provider during reading the file " << thePath
|
||||
<< "\t: Incorrect or empty Configuration Node";
|
||||
return false;
|
||||
}
|
||||
|
||||
Handle(DEIGES_ConfigurationNode) aNode = Handle(DEIGES_ConfigurationNode)::DownCast(GetNode());
|
||||
personizeWS(theWS);
|
||||
initStatic(aNode);
|
||||
Standard_Integer aFlag = IGESData_BasicEditor::GetFlagByValue(aNode->GlobalParameters.LengthUnit);
|
||||
IGESCAFControl_Writer aWriter(theWS,
|
||||
(aFlag > 0) ? IGESData_BasicEditor::UnitFlagName(aFlag) : "MM");
|
||||
IGESData_GlobalSection aGS = aWriter.Model()->GlobalSection();
|
||||
Standard_Real aScaleFactorMM = 1.;
|
||||
Standard_Boolean aHasUnits =
|
||||
XCAFDoc_DocumentTool::GetLengthUnit(theDocument,
|
||||
aScaleFactorMM,
|
||||
UnitsMethods_LengthUnit_Millimeter);
|
||||
if (aHasUnits)
|
||||
{
|
||||
aGS.SetCascadeUnit(aScaleFactorMM);
|
||||
}
|
||||
else
|
||||
{
|
||||
aGS.SetCascadeUnit(aNode->GlobalParameters.SystemUnit);
|
||||
Message::SendWarning()
|
||||
<< "Warning in the DEIGES_Provider during writing the file " << thePath
|
||||
<< "\t: The document has no information on Units. Using global parameter as initial Unit.";
|
||||
}
|
||||
if (aFlag == 0)
|
||||
{
|
||||
aGS.SetScale(aNode->GlobalParameters.LengthUnit);
|
||||
}
|
||||
aWriter.Model()->SetGlobalSection(aGS);
|
||||
aWriter.SetColorMode(aNode->InternalParameters.WriteColor);
|
||||
aWriter.SetNameMode(aNode->InternalParameters.WriteName);
|
||||
aWriter.SetLayerMode(aNode->InternalParameters.WriteLayer);
|
||||
aWriter.SetShapeFixParameters(aNode->ShapeFixParameters);
|
||||
|
||||
IGESCAFControl_Writer aWriter(theWS, Standard_False);
|
||||
configureIGESCAFWriter(aWriter, aNode, theDocument, thePath);
|
||||
|
||||
if (!aWriter.Transfer(theDocument, theProgress))
|
||||
{
|
||||
Message::SendFail() << "Error in the DEIGES_Provider during reading the file " << thePath
|
||||
Message::SendFail() << "Error in the DEIGES_Provider during writing the file " << thePath
|
||||
<< "\t: The document cannot be translated or gives no result";
|
||||
resetStatic();
|
||||
return false;
|
||||
}
|
||||
if (!aWriter.Write(thePath.ToCString()))
|
||||
{
|
||||
Message::SendFail() << "Error in the DEIGES_Provider during reading the file " << thePath
|
||||
Message::SendFail() << "Error in the DEIGES_Provider during writing the file " << thePath
|
||||
<< "\t: Write failed";
|
||||
resetStatic();
|
||||
return false;
|
||||
@@ -298,31 +388,26 @@ bool DEIGES_Provider::Read(const TCollection_AsciiString& thePath,
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
(void)theProgress;
|
||||
if (!GetNode()->IsKind(STANDARD_TYPE(DEIGES_ConfigurationNode)))
|
||||
if (!validateConfigurationNode(GetNode(), TCollection_AsciiString("reading the file ") + thePath))
|
||||
{
|
||||
Message::SendFail() << "Error in the DEIGES_Provider during reading the file " << thePath
|
||||
<< "\t: Incorrect or empty Configuration Node";
|
||||
return false;
|
||||
}
|
||||
|
||||
Handle(DEIGES_ConfigurationNode) aNode = Handle(DEIGES_ConfigurationNode)::DownCast(GetNode());
|
||||
initStatic(aNode);
|
||||
personizeWS(theWS);
|
||||
|
||||
IGESControl_Reader aReader;
|
||||
aReader.SetWS(theWS);
|
||||
aReader.SetReadVisible(aNode->InternalParameters.ReadOnlyVisible);
|
||||
aReader.SetShapeFixParameters(aNode->ShapeFixParameters);
|
||||
configureIGESControlReader(aReader, aNode);
|
||||
|
||||
IFSelect_ReturnStatus aReadStat = IFSelect_RetVoid;
|
||||
aReadStat = aReader.ReadFile(thePath.ToCString());
|
||||
if (aReadStat != IFSelect_RetDone)
|
||||
if (!processReadFile(aReader, thePath))
|
||||
{
|
||||
Message::SendFail() << "Error in the DEIGES_Provider during reading the file " << thePath
|
||||
<< "\t: Could not read file, no model loaded";
|
||||
resetStatic();
|
||||
return false;
|
||||
}
|
||||
if (aReader.TransferRoots() <= 0)
|
||||
|
||||
if (aReader.TransferRoots(theProgress) <= 0)
|
||||
{
|
||||
Message::SendFail() << "Error in the DEIGES_Provider during reading the file " << thePath
|
||||
<< "\t: Cannot read any relevant data from the IGES file";
|
||||
@@ -341,28 +426,21 @@ bool DEIGES_Provider::Write(const TCollection_AsciiString& thePath,
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
(void)theWS;
|
||||
(void)theProgress;
|
||||
if (!GetNode()->IsKind(STANDARD_TYPE(DEIGES_ConfigurationNode)))
|
||||
TCollection_AsciiString aContext = TCollection_AsciiString("writing the file ") + thePath;
|
||||
if (!validateConfigurationNode(GetNode(), aContext))
|
||||
{
|
||||
Message::SendFail() << "Error in the DEIGES_Provider during reading the file " << thePath
|
||||
<< "\t: Incorrect or empty Configuration Node";
|
||||
return false;
|
||||
}
|
||||
|
||||
Handle(DEIGES_ConfigurationNode) aNode = Handle(DEIGES_ConfigurationNode)::DownCast(GetNode());
|
||||
initStatic(aNode);
|
||||
Standard_Integer aFlag = IGESData_BasicEditor::GetFlagByValue(aNode->GlobalParameters.LengthUnit);
|
||||
IGESControl_Writer aWriter((aFlag > 0) ? IGESData_BasicEditor::UnitFlagName(aFlag) : "MM",
|
||||
personizeWS(theWS);
|
||||
|
||||
IGESControl_Writer aWriter(getIGESUnitString(aNode).ToCString(),
|
||||
aNode->InternalParameters.WriteBRepMode);
|
||||
IGESData_GlobalSection aGS = aWriter.Model()->GlobalSection();
|
||||
aGS.SetCascadeUnit(aNode->GlobalParameters.SystemUnit);
|
||||
if (!aFlag)
|
||||
{
|
||||
aGS.SetScale(aNode->GlobalParameters.LengthUnit);
|
||||
}
|
||||
aWriter.Model()->SetGlobalSection(aGS);
|
||||
aWriter.SetShapeFixParameters(aNode->ShapeFixParameters);
|
||||
Standard_Boolean aIsOk = aWriter.AddShape(theShape);
|
||||
configureIGESControlWriter(aWriter, aNode);
|
||||
|
||||
Standard_Boolean aIsOk = aWriter.AddShape(theShape, theProgress);
|
||||
if (!aIsOk)
|
||||
{
|
||||
Message::SendFail() << "DEIGES_Provider: Shape not written";
|
||||
@@ -370,7 +448,7 @@ bool DEIGES_Provider::Write(const TCollection_AsciiString& thePath,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(aWriter.Write(thePath.ToCString())))
|
||||
if (!aWriter.Write(thePath.ToCString()))
|
||||
{
|
||||
Message::SendFail() << "DEIGES_Provider: Error on writing file " << thePath;
|
||||
resetStatic();
|
||||
@@ -413,3 +491,253 @@ TCollection_AsciiString DEIGES_Provider::GetVendor() const
|
||||
{
|
||||
return TCollection_AsciiString("OCC");
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
// TODO: Implement IGES stream support
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DEIGES_Provider::Read(ReadStreamList& theStreams,
|
||||
const Handle(TDocStd_Document)& theDocument,
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
TCollection_AsciiString aContext = "reading stream";
|
||||
if (!DE_ValidationUtils::ValidateReadStreamList(theStreams, aContext))
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
const TCollection_AsciiString& aFirstKey = theStreams.First().Path;
|
||||
TCollection_AsciiString aFullContext = aContext + " " + aFirstKey;
|
||||
Standard_IStream& aStream = theStreams.First().Stream;
|
||||
|
||||
if (!DE_ValidationUtils::ValidateDocument(theDocument, aFullContext)
|
||||
|| !validateConfigurationNode(GetNode(), aFullContext))
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
Handle(DEIGES_ConfigurationNode) aNode = Handle(DEIGES_ConfigurationNode)::DownCast(GetNode());
|
||||
initStatic(aNode);
|
||||
personizeWS(theWS);
|
||||
|
||||
XCAFDoc_DocumentTool::SetLengthUnit(theDocument,
|
||||
aNode->GlobalParameters.LengthUnit,
|
||||
UnitsMethods_LengthUnit_Millimeter);
|
||||
|
||||
IGESCAFControl_Reader aReader;
|
||||
aReader.SetWS(theWS);
|
||||
configureIGESCAFReader(aReader, aNode);
|
||||
|
||||
IFSelect_ReturnStatus aReadStat = aReader.ReadStream(aFirstKey.ToCString(), aStream);
|
||||
if (aReadStat != IFSelect_RetDone)
|
||||
{
|
||||
Message::SendFail() << "Error in the DEIGES_Provider during reading stream " << aFirstKey
|
||||
<< "\t: abandon, no model loaded";
|
||||
resetStatic();
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
if (!aReader.Transfer(theDocument, theProgress))
|
||||
{
|
||||
Message::SendFail() << "Error in the DEIGES_Provider during reading stream " << aFirstKey
|
||||
<< "\t: Cannot read any relevant data from the IGES stream";
|
||||
resetStatic();
|
||||
return Standard_False;
|
||||
}
|
||||
resetStatic();
|
||||
return Standard_True;
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DEIGES_Provider::Write(WriteStreamList& theStreams,
|
||||
const Handle(TDocStd_Document)& theDocument,
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
TCollection_AsciiString aContext = "writing stream";
|
||||
if (!DE_ValidationUtils::ValidateWriteStreamList(theStreams, aContext))
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
const TCollection_AsciiString& aFirstKey = theStreams.First().Path;
|
||||
Standard_OStream& aStream = theStreams.First().Stream;
|
||||
|
||||
TCollection_AsciiString aFullContext = aContext + " " + aFirstKey;
|
||||
if (!DE_ValidationUtils::ValidateDocument(theDocument, aFullContext)
|
||||
|| !validateConfigurationNode(GetNode(), aFullContext))
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
Handle(DEIGES_ConfigurationNode) aNode = Handle(DEIGES_ConfigurationNode)::DownCast(GetNode());
|
||||
initStatic(aNode);
|
||||
personizeWS(theWS);
|
||||
|
||||
IGESCAFControl_Writer aWriter(theWS, Standard_False);
|
||||
configureIGESCAFWriter(aWriter, aNode, theDocument, aFirstKey);
|
||||
|
||||
if (!aWriter.Transfer(theDocument, theProgress))
|
||||
{
|
||||
Message::SendFail() << "Error in the DEIGES_Provider during writing stream " << aFirstKey
|
||||
<< "\t: The document cannot be translated or gives no result";
|
||||
resetStatic();
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
if (!aWriter.Write(aStream))
|
||||
{
|
||||
Message::SendFail() << "Error in the DEIGES_Provider during writing stream " << aFirstKey
|
||||
<< "\t: Write failed";
|
||||
resetStatic();
|
||||
return Standard_False;
|
||||
}
|
||||
resetStatic();
|
||||
return Standard_True;
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DEIGES_Provider::Read(ReadStreamList& theStreams,
|
||||
TopoDS_Shape& theShape,
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
TCollection_AsciiString aContext = "reading stream";
|
||||
if (!DE_ValidationUtils::ValidateReadStreamList(theStreams, aContext))
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
const TCollection_AsciiString& aFirstKey = theStreams.First().Path;
|
||||
Standard_IStream& aStream = theStreams.First().Stream;
|
||||
|
||||
TCollection_AsciiString aFullContext = aContext + " " + aFirstKey;
|
||||
if (!validateConfigurationNode(GetNode(), aFullContext))
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
Handle(DEIGES_ConfigurationNode) aNode = Handle(DEIGES_ConfigurationNode)::DownCast(GetNode());
|
||||
initStatic(aNode);
|
||||
personizeWS(theWS);
|
||||
|
||||
IGESControl_Reader aReader;
|
||||
aReader.SetWS(theWS);
|
||||
configureIGESControlReader(aReader, aNode);
|
||||
|
||||
IFSelect_ReturnStatus aReadStat = aReader.ReadStream(aFirstKey.ToCString(), aStream);
|
||||
if (aReadStat != IFSelect_RetDone)
|
||||
{
|
||||
Message::SendFail() << "Error in the DEIGES_Provider during reading stream " << aFirstKey
|
||||
<< "\t: Could not read stream, no model loaded";
|
||||
resetStatic();
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
if (aReader.TransferRoots(theProgress) <= 0)
|
||||
{
|
||||
Message::SendFail() << "Error in the DEIGES_Provider during reading stream " << aFirstKey
|
||||
<< "\t: Cannot read any relevant data from the IGES stream";
|
||||
resetStatic();
|
||||
return Standard_False;
|
||||
}
|
||||
theShape = aReader.OneShape();
|
||||
resetStatic();
|
||||
return Standard_True;
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DEIGES_Provider::Write(WriteStreamList& theStreams,
|
||||
const TopoDS_Shape& theShape,
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
TCollection_AsciiString aContext = "writing stream";
|
||||
if (!DE_ValidationUtils::ValidateWriteStreamList(theStreams, aContext))
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
const TCollection_AsciiString& aFirstKey = theStreams.First().Path;
|
||||
Standard_OStream& aStream = theStreams.First().Stream;
|
||||
|
||||
TCollection_AsciiString aFullContext = aContext + " " + aFirstKey;
|
||||
if (!validateConfigurationNode(GetNode(), aFullContext))
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
Handle(DEIGES_ConfigurationNode) aNode = Handle(DEIGES_ConfigurationNode)::DownCast(GetNode());
|
||||
initStatic(aNode);
|
||||
personizeWS(theWS);
|
||||
|
||||
IGESControl_Writer aWriter(getIGESUnitString(aNode).ToCString(),
|
||||
aNode->InternalParameters.WriteBRepMode);
|
||||
configureIGESControlWriter(aWriter, aNode);
|
||||
|
||||
Standard_Boolean isOk = aWriter.AddShape(theShape, theProgress);
|
||||
if (!isOk)
|
||||
{
|
||||
Message::SendFail() << "Error: DEIGES_Provider failed to transfer shape for stream "
|
||||
<< aFirstKey;
|
||||
resetStatic();
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
if (!aWriter.Write(aStream))
|
||||
{
|
||||
Message::SendFail() << "Error: DEIGES_Provider failed to write shape to stream " << aFirstKey;
|
||||
resetStatic();
|
||||
return Standard_False;
|
||||
}
|
||||
resetStatic();
|
||||
return Standard_True;
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DEIGES_Provider::Read(ReadStreamList& theStreams,
|
||||
const Handle(TDocStd_Document)& theDocument,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
Handle(XSControl_WorkSession) aWS = new XSControl_WorkSession();
|
||||
return Read(theStreams, theDocument, aWS, theProgress);
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DEIGES_Provider::Write(WriteStreamList& theStreams,
|
||||
const Handle(TDocStd_Document)& theDocument,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
Handle(XSControl_WorkSession) aWS = new XSControl_WorkSession();
|
||||
return Write(theStreams, theDocument, aWS, theProgress);
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DEIGES_Provider::Read(ReadStreamList& theStreams,
|
||||
TopoDS_Shape& theShape,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
Handle(XSControl_WorkSession) aWS = new XSControl_WorkSession();
|
||||
return Read(theStreams, theShape, aWS, theProgress);
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DEIGES_Provider::Write(WriteStreamList& theStreams,
|
||||
const TopoDS_Shape& theShape,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
Handle(XSControl_WorkSession) aWS = new XSControl_WorkSession();
|
||||
return Write(theStreams, theShape, aWS, theProgress);
|
||||
}
|
||||
|
||||
*/
|
||||
|
@@ -14,6 +14,7 @@
|
||||
#include <DEOBJ_Provider.hxx>
|
||||
|
||||
#include <BRep_Builder.hxx>
|
||||
#include <DE_ValidationUtils.hxx>
|
||||
#include <DEOBJ_ConfigurationNode.hxx>
|
||||
#include <RWObj_CafReader.hxx>
|
||||
#include <RWObj_CafWriter.hxx>
|
||||
@@ -62,16 +63,15 @@ bool DEOBJ_Provider::Read(const TCollection_AsciiString& thePath,
|
||||
const Handle(TDocStd_Document)& theDocument,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
if (theDocument.IsNull())
|
||||
TCollection_AsciiString aContext = TCollection_AsciiString("reading the file ") + thePath;
|
||||
if (!DE_ValidationUtils::ValidateDocument(theDocument, aContext))
|
||||
{
|
||||
Message::SendFail() << "Error in the DEOBJ_Provider during reading the file " << thePath
|
||||
<< "\t: theDocument shouldn't be null";
|
||||
return false;
|
||||
}
|
||||
if (GetNode().IsNull() || !GetNode()->IsKind(STANDARD_TYPE(DEOBJ_ConfigurationNode)))
|
||||
if (!DE_ValidationUtils::ValidateConfigurationNode(GetNode(),
|
||||
STANDARD_TYPE(DEOBJ_ConfigurationNode),
|
||||
aContext))
|
||||
{
|
||||
Message::SendFail() << "Error in the DEOBJ_ConfigurationNode during reading the file "
|
||||
<< thePath << "\t: Incorrect or empty Configuration Node";
|
||||
return false;
|
||||
}
|
||||
Handle(DEOBJ_ConfigurationNode) aNode = Handle(DEOBJ_ConfigurationNode)::DownCast(GetNode());
|
||||
|
@@ -14,6 +14,7 @@
|
||||
#include <DEPLY_Provider.hxx>
|
||||
|
||||
#include <BRep_Builder.hxx>
|
||||
#include <DE_ValidationUtils.hxx>
|
||||
#include <DEPLY_ConfigurationNode.hxx>
|
||||
#include <DE_Wrapper.hxx>
|
||||
#include <Message.hxx>
|
||||
@@ -55,10 +56,11 @@ bool DEPLY_Provider::Write(const TCollection_AsciiString& thePath,
|
||||
const Handle(TDocStd_Document)& theDocument,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
if (GetNode().IsNull() || !GetNode()->IsKind(STANDARD_TYPE(DEPLY_ConfigurationNode)))
|
||||
TCollection_AsciiString aContext = TCollection_AsciiString("writing the file ") + thePath;
|
||||
if (!DE_ValidationUtils::ValidateConfigurationNode(GetNode(),
|
||||
STANDARD_TYPE(DEPLY_ConfigurationNode),
|
||||
aContext))
|
||||
{
|
||||
Message::SendFail() << "Error in the DEPLY_Provider during writing the file " << thePath
|
||||
<< "\t: Incorrect or empty Configuration Node";
|
||||
return false;
|
||||
}
|
||||
Handle(DEPLY_ConfigurationNode) aNode = Handle(DEPLY_ConfigurationNode)::DownCast(GetNode());
|
||||
|
@@ -635,6 +635,13 @@ bool DESTEP_ConfigurationNode::IsExportSupported() const
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
bool DESTEP_ConfigurationNode::IsStreamSupported() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
TCollection_AsciiString DESTEP_ConfigurationNode::GetFormat() const
|
||||
{
|
||||
return TCollection_AsciiString("STEP");
|
||||
|
@@ -68,6 +68,10 @@ public:
|
||||
//! @return true if export is supported
|
||||
Standard_EXPORT virtual bool IsExportSupported() const Standard_OVERRIDE;
|
||||
|
||||
//! Checks for stream support.
|
||||
//! @return Standard_True if streams are supported
|
||||
Standard_EXPORT virtual bool IsStreamSupported() const Standard_OVERRIDE;
|
||||
|
||||
//! Gets CAD format name of associated provider
|
||||
//! @return provider CAD format
|
||||
Standard_EXPORT virtual TCollection_AsciiString GetFormat() const Standard_OVERRIDE;
|
||||
|
@@ -13,6 +13,7 @@
|
||||
|
||||
#include <DESTEP_Provider.hxx>
|
||||
|
||||
#include <DE_ValidationUtils.hxx>
|
||||
#include <DESTEP_ConfigurationNode.hxx>
|
||||
#include <DESTEP_Parameters.hxx>
|
||||
#include <Interface_Static.hxx>
|
||||
@@ -20,13 +21,125 @@
|
||||
#include <STEPCAFControl_Controller.hxx>
|
||||
#include <STEPCAFControl_Reader.hxx>
|
||||
#include <STEPCAFControl_Writer.hxx>
|
||||
#include <STEPControl_Reader.hxx>
|
||||
#include <STEPControl_Writer.hxx>
|
||||
#include <StepData_StepModel.hxx>
|
||||
#include <UnitsMethods.hxx>
|
||||
#include <XCAFDoc_DocumentTool.hxx>
|
||||
#include <XSControl_WorkSession.hxx>
|
||||
#include <OSD_OpenFile.hxx>
|
||||
#include <fstream>
|
||||
|
||||
IMPLEMENT_STANDARD_RTTIEXT(DESTEP_Provider, DE_Provider)
|
||||
|
||||
namespace
|
||||
{
|
||||
//! Helper function to validate configuration node
|
||||
Standard_Boolean validateNode(const Handle(DE_ConfigurationNode)& theNode,
|
||||
const TCollection_AsciiString& theContext)
|
||||
{
|
||||
return DE_ValidationUtils::ValidateConfigurationNode(theNode,
|
||||
STANDARD_TYPE(DESTEP_ConfigurationNode),
|
||||
theContext);
|
||||
}
|
||||
|
||||
//! Configures STEPCAFControl_Reader with specified parameters and optional document setup.
|
||||
//! @param[in,out] theReader STEP CAF reader to configure
|
||||
//! @param[in] theParams Parameters containing read settings
|
||||
//! @param[in] theWS Work session to initialize reader with (optional, if provided reader will
|
||||
//! be initialized)
|
||||
//! @param[in] theDocument Target document for length unit setup (optional)
|
||||
//! @param[in] theLengthUnit Length unit for document setup (used only if theDocument is provided)
|
||||
//! @param[in] theShapeFixParams Shape fix parameters (optional, uses default if not provided)
|
||||
//! @note Sets up colors, names, layers, properties, metadata, and shape fix parameters
|
||||
void configureSTEPCAFReader(STEPCAFControl_Reader& theReader,
|
||||
const DESTEP_Parameters& theParams,
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Handle(TDocStd_Document)& theDocument,
|
||||
Standard_Real theLengthUnit,
|
||||
const DE_ShapeFixParameters& theShapeFixParams)
|
||||
{
|
||||
theReader.Init(theWS);
|
||||
|
||||
theReader.SetColorMode(theParams.ReadColor);
|
||||
theReader.SetNameMode(theParams.ReadName);
|
||||
theReader.SetLayerMode(theParams.ReadLayer);
|
||||
theReader.SetPropsMode(theParams.ReadProps);
|
||||
theReader.SetMetaMode(theParams.ReadMetadata);
|
||||
theReader.SetProductMetaMode(theParams.ReadProductMetadata);
|
||||
|
||||
theReader.SetShapeFixParameters(theShapeFixParams);
|
||||
|
||||
XCAFDoc_DocumentTool::SetLengthUnit(theDocument,
|
||||
theLengthUnit,
|
||||
UnitsMethods_LengthUnit_Millimeter);
|
||||
}
|
||||
|
||||
//! Configures STEPCAFControl_Writer with full setup.
|
||||
//! @param[in,out] theWriter STEP CAF writer to configure
|
||||
//! @param[in] theParams Parameters containing write settings
|
||||
//! @param[in,out] theWS Work session to initialize writer with
|
||||
//! @param[in] theDocument Source document for length unit extraction
|
||||
//! @param[in] theLengthUnit Length unit for document setup
|
||||
//! @param[in] theShapeFixParams Shape fix parameters
|
||||
//! @note Sets up all write parameters including colors, names, layers, props, materials
|
||||
void configureSTEPCAFWriter(STEPCAFControl_Writer& theWriter,
|
||||
const DESTEP_Parameters& theParams,
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Handle(TDocStd_Document)& theDocument,
|
||||
Standard_Real theLengthUnit,
|
||||
const DE_ShapeFixParameters& theShapeFixParams)
|
||||
{
|
||||
theWriter.Init(theWS);
|
||||
|
||||
theWriter.SetColorMode(theParams.WriteColor);
|
||||
theWriter.SetNameMode(theParams.WriteName);
|
||||
theWriter.SetLayerMode(theParams.WriteLayer);
|
||||
theWriter.SetPropsMode(theParams.WriteProps);
|
||||
theWriter.SetMaterialMode(theParams.WriteMaterial);
|
||||
theWriter.SetVisualMaterialMode(theParams.WriteVisMaterial);
|
||||
theWriter.SetCleanDuplicates(theParams.CleanDuplicates);
|
||||
|
||||
theWriter.SetShapeFixParameters(theShapeFixParams);
|
||||
|
||||
Handle(StepData_StepModel) aModel =
|
||||
Handle(StepData_StepModel)::DownCast(theWriter.Writer().WS()->Model());
|
||||
|
||||
Standard_Real aScaleFactorMM = 1.;
|
||||
if (XCAFDoc_DocumentTool::GetLengthUnit(theDocument,
|
||||
aScaleFactorMM,
|
||||
UnitsMethods_LengthUnit_Millimeter))
|
||||
{
|
||||
aModel->SetLocalLengthUnit(aScaleFactorMM);
|
||||
}
|
||||
else
|
||||
{
|
||||
aModel->SetLocalLengthUnit(theLengthUnit);
|
||||
Message::SendWarning()
|
||||
<< "Warning in the DESTEP_Provider during writing"
|
||||
<< "\t: The document has no information on Units. Using global parameter as initial Unit.";
|
||||
}
|
||||
}
|
||||
|
||||
//! Checks if output stream is in writable state.
|
||||
//! @param[in] theStream Output stream to check
|
||||
//! @param[in] theKey Stream identifier for error reporting
|
||||
//! @return Standard_True if stream is writable, Standard_False otherwise
|
||||
bool checkStreamWritability(Standard_OStream& theStream, const TCollection_AsciiString& theKey)
|
||||
{
|
||||
if (!theStream.good())
|
||||
{
|
||||
TCollection_AsciiString aKeyInfo = theKey.IsEmpty() ? "<empty key>" : theKey;
|
||||
Message::SendFail() << "Error: Output stream '" << aKeyInfo
|
||||
<< "' is not in good state for writing";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
DESTEP_Provider::DESTEP_Provider() {}
|
||||
@@ -45,35 +158,28 @@ bool DESTEP_Provider::Read(const TCollection_AsciiString& thePath,
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
if (theDocument.IsNull())
|
||||
TCollection_AsciiString aContext = TCollection_AsciiString("reading the file ") + thePath;
|
||||
if (!DE_ValidationUtils::ValidateDocument(theDocument, aContext)
|
||||
|| !validateNode(GetNode(), aContext))
|
||||
{
|
||||
Message::SendFail() << "Error in the DESTEP_Provider during reading the file " << thePath
|
||||
<< "\t: theDocument shouldn't be null";
|
||||
return false;
|
||||
}
|
||||
if (GetNode().IsNull() || !GetNode()->IsKind(STANDARD_TYPE(DESTEP_ConfigurationNode)))
|
||||
{
|
||||
Message::SendFail() << "Error in the DESTEP_Provider during reading the file " << thePath
|
||||
<< "\t: Incorrect or empty Configuration Node";
|
||||
return false;
|
||||
}
|
||||
|
||||
Handle(DESTEP_ConfigurationNode) aNode = Handle(DESTEP_ConfigurationNode)::DownCast(GetNode());
|
||||
personizeWS(theWS);
|
||||
XCAFDoc_DocumentTool::SetLengthUnit(theDocument,
|
||||
aNode->GlobalParameters.LengthUnit,
|
||||
UnitsMethods_LengthUnit_Millimeter);
|
||||
|
||||
STEPCAFControl_Reader aReader;
|
||||
aReader.Init(theWS);
|
||||
aReader.SetColorMode(aNode->InternalParameters.ReadColor);
|
||||
aReader.SetNameMode(aNode->InternalParameters.ReadName);
|
||||
aReader.SetLayerMode(aNode->InternalParameters.ReadLayer);
|
||||
aReader.SetPropsMode(aNode->InternalParameters.ReadProps);
|
||||
aReader.SetMetaMode(aNode->InternalParameters.ReadMetadata);
|
||||
aReader.SetProductMetaMode(aNode->InternalParameters.ReadProductMetadata);
|
||||
aReader.SetShapeFixParameters(aNode->ShapeFixParameters);
|
||||
configureSTEPCAFReader(aReader,
|
||||
aNode->InternalParameters,
|
||||
theWS,
|
||||
theDocument,
|
||||
aNode->GlobalParameters.LengthUnit,
|
||||
aNode->ShapeFixParameters);
|
||||
|
||||
IFSelect_ReturnStatus aReadStat = IFSelect_RetVoid;
|
||||
DESTEP_Parameters aParams = aNode->InternalParameters;
|
||||
aReadStat = aReader.ReadFile(thePath.ToCString(), aParams);
|
||||
|
||||
if (aReadStat != IFSelect_RetDone)
|
||||
{
|
||||
Message::SendFail() << "Error in the DESTEP_Provider during reading the file " << thePath
|
||||
@@ -97,43 +203,28 @@ bool DESTEP_Provider::Write(const TCollection_AsciiString& thePath,
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
if (GetNode().IsNull() || !GetNode()->IsKind(STANDARD_TYPE(DESTEP_ConfigurationNode)))
|
||||
TCollection_AsciiString aContext = TCollection_AsciiString("writing the file ") + thePath;
|
||||
if (!DE_ValidationUtils::ValidateDocument(theDocument, aContext)
|
||||
|| !validateNode(GetNode(), aContext))
|
||||
{
|
||||
Message::SendFail() << "Error in the DESTEP_Provider during writing the file " << thePath
|
||||
<< "\t: Incorrect or empty Configuration Node";
|
||||
return false;
|
||||
}
|
||||
Handle(DESTEP_ConfigurationNode) aNode = Handle(DESTEP_ConfigurationNode)::DownCast(GetNode());
|
||||
personizeWS(theWS);
|
||||
|
||||
STEPCAFControl_Writer aWriter;
|
||||
aWriter.Init(theWS);
|
||||
configureSTEPCAFWriter(aWriter,
|
||||
aNode->InternalParameters,
|
||||
theWS,
|
||||
theDocument,
|
||||
aNode->GlobalParameters.SystemUnit,
|
||||
aNode->ShapeFixParameters);
|
||||
|
||||
Handle(StepData_StepModel) aModel =
|
||||
Handle(StepData_StepModel)::DownCast(aWriter.Writer().WS()->Model());
|
||||
STEPControl_StepModelType aMode =
|
||||
static_cast<STEPControl_StepModelType>(aNode->InternalParameters.WriteModelType);
|
||||
aWriter.SetColorMode(aNode->InternalParameters.WriteColor);
|
||||
aWriter.SetNameMode(aNode->InternalParameters.WriteName);
|
||||
aWriter.SetLayerMode(aNode->InternalParameters.WriteLayer);
|
||||
aWriter.SetPropsMode(aNode->InternalParameters.WriteProps);
|
||||
aWriter.SetShapeFixParameters(aNode->ShapeFixParameters);
|
||||
aWriter.SetMaterialMode(aNode->InternalParameters.WriteMaterial);
|
||||
aWriter.SetVisualMaterialMode(aNode->InternalParameters.WriteVisMaterial);
|
||||
aWriter.SetCleanDuplicates(aNode->InternalParameters.CleanDuplicates);
|
||||
DESTEP_Parameters aParams = aNode->InternalParameters;
|
||||
Standard_Real aScaleFactorMM = 1.;
|
||||
if (XCAFDoc_DocumentTool::GetLengthUnit(theDocument,
|
||||
aScaleFactorMM,
|
||||
UnitsMethods_LengthUnit_Millimeter))
|
||||
{
|
||||
aModel->SetLocalLengthUnit(aScaleFactorMM);
|
||||
}
|
||||
else
|
||||
{
|
||||
aModel->SetLocalLengthUnit(aNode->GlobalParameters.SystemUnit);
|
||||
Message::SendWarning()
|
||||
<< "Warning in the DESTEP_Provider during writing the file " << thePath
|
||||
<< "\t: The document has no information on Units. Using global parameter as initial Unit.";
|
||||
}
|
||||
DESTEP_Parameters aParams = aNode->InternalParameters;
|
||||
UnitsMethods_LengthUnit aTargetUnit =
|
||||
UnitsMethods::GetLengthUnitByFactorValue(aNode->GlobalParameters.LengthUnit,
|
||||
UnitsMethods_LengthUnit_Millimeter);
|
||||
@@ -194,11 +285,9 @@ bool DESTEP_Provider::Read(const TCollection_AsciiString& thePath,
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
(void)theProgress;
|
||||
if (GetNode().IsNull() || !GetNode()->IsKind(STANDARD_TYPE(DESTEP_ConfigurationNode)))
|
||||
TCollection_AsciiString aContext = TCollection_AsciiString("reading the file ") + thePath;
|
||||
if (!validateNode(GetNode(), aContext))
|
||||
{
|
||||
Message::SendFail() << "Error in the DESTEP_Provider during reading the file " << thePath
|
||||
<< "\t: Incorrect or empty Configuration Node";
|
||||
return false;
|
||||
}
|
||||
Handle(DESTEP_ConfigurationNode) aNode = Handle(DESTEP_ConfigurationNode)::DownCast(GetNode());
|
||||
@@ -217,7 +306,7 @@ bool DESTEP_Provider::Read(const TCollection_AsciiString& thePath,
|
||||
return false;
|
||||
}
|
||||
aModel->SetLocalLengthUnit(aNode->GlobalParameters.LengthUnit);
|
||||
if (aReader.TransferRoots() <= 0)
|
||||
if (aReader.TransferRoots(theProgress) <= 0)
|
||||
{
|
||||
Message::SendFail() << "Error in the DESTEP_Provider during reading the file " << thePath
|
||||
<< "\t:Cannot read any relevant data from the STEP file";
|
||||
@@ -234,10 +323,9 @@ bool DESTEP_Provider::Write(const TCollection_AsciiString& thePath,
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
if (GetNode().IsNull() || !GetNode()->IsKind(STANDARD_TYPE(DESTEP_ConfigurationNode)))
|
||||
TCollection_AsciiString aContext = TCollection_AsciiString("writing the file ") + thePath;
|
||||
if (!validateNode(GetNode(), aContext))
|
||||
{
|
||||
Message::SendFail() << "Error in the DESTEP_Provider during reading the file " << thePath
|
||||
<< "\t: Incorrect or empty Configuration Node";
|
||||
return false;
|
||||
}
|
||||
Handle(DESTEP_ConfigurationNode) aNode = Handle(DESTEP_ConfigurationNode)::DownCast(GetNode());
|
||||
@@ -312,6 +400,281 @@ bool DESTEP_Provider::Write(const TCollection_AsciiString& thePath,
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DESTEP_Provider::Read(ReadStreamList& theStreams,
|
||||
const Handle(TDocStd_Document)& theDocument,
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
TCollection_AsciiString aContext = "reading stream";
|
||||
if (!DE_ValidationUtils::ValidateReadStreamList(theStreams, aContext))
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
TCollection_AsciiString aFirstKey = theStreams.First().Path;
|
||||
TCollection_AsciiString aFullContext = aContext + " " + aFirstKey;
|
||||
if (!DE_ValidationUtils::ValidateDocument(theDocument, aFullContext)
|
||||
|| !validateNode(GetNode(), aFullContext)
|
||||
|| !DE_ValidationUtils::ValidateReadStreamList(theStreams, aFullContext))
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
Standard_IStream& aStream = theStreams.First().Stream;
|
||||
|
||||
personizeWS(theWS);
|
||||
|
||||
Handle(DESTEP_ConfigurationNode) aNode = Handle(DESTEP_ConfigurationNode)::DownCast(GetNode());
|
||||
STEPCAFControl_Reader aReader(theWS, Standard_False);
|
||||
configureSTEPCAFReader(aReader,
|
||||
aNode->InternalParameters,
|
||||
theWS,
|
||||
theDocument,
|
||||
aNode->GlobalParameters.LengthUnit,
|
||||
aNode->ShapeFixParameters);
|
||||
|
||||
Standard_Boolean isOk = aReader.ReadStream(aFirstKey.ToCString(), aStream);
|
||||
if (!isOk)
|
||||
{
|
||||
Message::SendFail() << "Error: DESTEP_Provider failed to read stream " << aFirstKey;
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
return aReader.Transfer(theDocument, theProgress);
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DESTEP_Provider::Write(WriteStreamList& theStreams,
|
||||
const Handle(TDocStd_Document)& theDocument,
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
TCollection_AsciiString aContext = "writing stream";
|
||||
if (!DE_ValidationUtils::ValidateWriteStreamList(theStreams, aContext))
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
TCollection_AsciiString aFirstKey = theStreams.First().Path;
|
||||
TCollection_AsciiString aFullContext = aContext + " " + aFirstKey;
|
||||
if (!DE_ValidationUtils::ValidateDocument(theDocument, aFullContext)
|
||||
|| !validateNode(GetNode(), aFullContext))
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
Standard_OStream& aStream = theStreams.First().Stream;
|
||||
if (!checkStreamWritability(aStream, aFirstKey))
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
personizeWS(theWS);
|
||||
|
||||
Handle(DESTEP_ConfigurationNode) aNode = Handle(DESTEP_ConfigurationNode)::DownCast(GetNode());
|
||||
|
||||
STEPCAFControl_Writer aWriter(theWS, Standard_False);
|
||||
configureSTEPCAFWriter(aWriter,
|
||||
aNode->InternalParameters,
|
||||
theWS,
|
||||
theDocument,
|
||||
aNode->GlobalParameters.LengthUnit,
|
||||
aNode->ShapeFixParameters);
|
||||
|
||||
Handle(StepData_StepModel) aModel =
|
||||
Handle(StepData_StepModel)::DownCast(aWriter.Writer().WS()->Model());
|
||||
DESTEP_Parameters aParams = aNode->InternalParameters;
|
||||
UnitsMethods_LengthUnit aTargetUnit =
|
||||
UnitsMethods::GetLengthUnitByFactorValue(aNode->GlobalParameters.LengthUnit,
|
||||
UnitsMethods_LengthUnit_Millimeter);
|
||||
aParams.WriteUnit = aTargetUnit;
|
||||
aModel->SetWriteLengthUnit(aNode->GlobalParameters.LengthUnit);
|
||||
STEPControl_StepModelType aMode =
|
||||
static_cast<STEPControl_StepModelType>(aNode->InternalParameters.WriteModelType);
|
||||
Standard_Boolean isOk = aWriter.Transfer(theDocument, aParams, aMode, 0, theProgress);
|
||||
if (!isOk)
|
||||
{
|
||||
Message::SendFail() << "Error: DESTEP_Provider failed to transfer document for stream "
|
||||
<< aFirstKey;
|
||||
return Standard_False;
|
||||
}
|
||||
return aWriter.WriteStream(aStream);
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DESTEP_Provider::Read(ReadStreamList& theStreams,
|
||||
const Handle(TDocStd_Document)& theDocument,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
Handle(XSControl_WorkSession) aWS = new XSControl_WorkSession();
|
||||
return Read(theStreams, theDocument, aWS, theProgress);
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DESTEP_Provider::Write(WriteStreamList& theStreams,
|
||||
const Handle(TDocStd_Document)& theDocument,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
Handle(XSControl_WorkSession) aWS = new XSControl_WorkSession();
|
||||
return Write(theStreams, theDocument, aWS, theProgress);
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DESTEP_Provider::Read(ReadStreamList& theStreams,
|
||||
TopoDS_Shape& theShape,
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
TCollection_AsciiString aContext = "reading stream";
|
||||
if (!DE_ValidationUtils::ValidateReadStreamList(theStreams, aContext))
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
TCollection_AsciiString aFirstKey = theStreams.First().Path;
|
||||
TCollection_AsciiString aFullContext = aContext + " " + aFirstKey;
|
||||
if (!validateNode(GetNode(), aFullContext))
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
Standard_IStream& aStream = theStreams.First().Stream;
|
||||
personizeWS(theWS);
|
||||
|
||||
Handle(DESTEP_ConfigurationNode) aNode = Handle(DESTEP_ConfigurationNode)::DownCast(GetNode());
|
||||
|
||||
// Use STEPControl_Reader for shape operations from streams
|
||||
STEPControl_Reader aReader;
|
||||
aReader.SetWS(theWS);
|
||||
aReader.SetShapeFixParameters(aNode->ShapeFixParameters);
|
||||
|
||||
// Read from stream using the reader's internal model
|
||||
IFSelect_ReturnStatus aReadStat = aReader.ReadStream(aFirstKey.ToCString(), aStream);
|
||||
if (aReadStat != IFSelect_RetDone)
|
||||
{
|
||||
Message::SendFail() << "Error: DESTEP_Provider failed to read from stream " << aFirstKey;
|
||||
return Standard_False;
|
||||
}
|
||||
Handle(StepData_StepModel) aModel = aReader.StepModel();
|
||||
aModel->SetLocalLengthUnit(aNode->GlobalParameters.LengthUnit);
|
||||
|
||||
// Transfer the first root to get the shape
|
||||
if (aReader.TransferRoots(theProgress) <= 0)
|
||||
{
|
||||
Message::SendFail() << "Error: DESTEP_Provider found no transferable roots in stream "
|
||||
<< aFirstKey;
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
theShape = aReader.OneShape();
|
||||
return Standard_True;
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DESTEP_Provider::Write(WriteStreamList& theStreams,
|
||||
const TopoDS_Shape& theShape,
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
TCollection_AsciiString aContext = "writing stream";
|
||||
if (!DE_ValidationUtils::ValidateWriteStreamList(theStreams, aContext))
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
TCollection_AsciiString aFirstKey = theStreams.First().Path;
|
||||
TCollection_AsciiString aFullContext = aContext + " " + aFirstKey;
|
||||
if (!validateNode(GetNode(), aFullContext))
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
Standard_OStream& aStream = theStreams.First().Stream;
|
||||
personizeWS(theWS);
|
||||
|
||||
Handle(DESTEP_ConfigurationNode) aNode = Handle(DESTEP_ConfigurationNode)::DownCast(GetNode());
|
||||
|
||||
// Use STEPControl_Writer for shape operations to streams
|
||||
STEPControl_Writer aWriter;
|
||||
aWriter.SetWS(theWS);
|
||||
|
||||
Handle(StepData_StepModel) aModel = aWriter.Model();
|
||||
aModel->SetLocalLengthUnit(aNode->GlobalParameters.SystemUnit);
|
||||
|
||||
UnitsMethods_LengthUnit aTargetUnit =
|
||||
UnitsMethods::GetLengthUnitByFactorValue(aNode->GlobalParameters.LengthUnit,
|
||||
UnitsMethods_LengthUnit_Millimeter);
|
||||
DESTEP_Parameters aParams = aNode->InternalParameters;
|
||||
aParams.WriteUnit = aTargetUnit;
|
||||
|
||||
if (aTargetUnit == UnitsMethods_LengthUnit_Undefined)
|
||||
{
|
||||
aModel->SetWriteLengthUnit(1.0);
|
||||
Message::SendWarning()
|
||||
<< "Custom units are not supported by STEP format, but LengthUnit global parameter doesn't "
|
||||
"fit any predefined unit. Units will be scaled to Millimeters";
|
||||
}
|
||||
else
|
||||
{
|
||||
aModel->SetWriteLengthUnit(aNode->GlobalParameters.LengthUnit);
|
||||
}
|
||||
|
||||
aWriter.SetShapeFixParameters(aNode->ShapeFixParameters);
|
||||
|
||||
IFSelect_ReturnStatus aWriteStat = aWriter.Transfer(theShape,
|
||||
aNode->InternalParameters.WriteModelType,
|
||||
aParams,
|
||||
true,
|
||||
theProgress);
|
||||
if (aWriteStat != IFSelect_RetDone)
|
||||
{
|
||||
Message::SendFail() << "Error: DESTEP_Provider failed to transfer shape for stream "
|
||||
<< aFirstKey;
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
if (aNode->InternalParameters.CleanDuplicates)
|
||||
{
|
||||
aWriter.CleanDuplicateEntities();
|
||||
}
|
||||
|
||||
// Write to stream
|
||||
if (!aWriter.WriteStream(aStream))
|
||||
{
|
||||
Message::SendFail() << "Error: DESTEP_Provider failed to write to stream " << aFirstKey;
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
return Standard_True;
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DESTEP_Provider::Read(ReadStreamList& theStreams,
|
||||
TopoDS_Shape& theShape,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
Handle(XSControl_WorkSession) aWS = new XSControl_WorkSession();
|
||||
return Read(theStreams, theShape, aWS, theProgress);
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DESTEP_Provider::Write(WriteStreamList& theStreams,
|
||||
const TopoDS_Shape& theShape,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
Handle(XSControl_WorkSession) aWS = new XSControl_WorkSession();
|
||||
return Write(theStreams, theShape, aWS, theProgress);
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
TCollection_AsciiString DESTEP_Provider::GetFormat() const
|
||||
{
|
||||
return TCollection_AsciiString("STEP");
|
||||
|
@@ -109,6 +109,54 @@ public:
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange()) Standard_OVERRIDE;
|
||||
|
||||
//! Reads streams according to internal configuration
|
||||
//! @param[in] theStreams streams to read from
|
||||
//! @param[out] theDocument document to save result
|
||||
//! @param[in] theWS current work session
|
||||
//! @param[in] theProgress progress indicator
|
||||
//! @return true if Read operation has ended correctly
|
||||
Standard_EXPORT virtual Standard_Boolean Read(
|
||||
ReadStreamList& theStreams,
|
||||
const Handle(TDocStd_Document)& theDocument,
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange()) Standard_OVERRIDE;
|
||||
|
||||
//! Writes streams according to internal configuration
|
||||
//! @param[in] theStreams streams to write to
|
||||
//! @param[out] theDocument document to export
|
||||
//! @param[in] theWS current work session
|
||||
//! @param[in] theProgress progress indicator
|
||||
//! @return true if Write operation has ended correctly
|
||||
Standard_EXPORT virtual Standard_Boolean Write(
|
||||
WriteStreamList& theStreams,
|
||||
const Handle(TDocStd_Document)& theDocument,
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange()) Standard_OVERRIDE;
|
||||
|
||||
//! Reads streams according to internal configuration
|
||||
//! @param[in] theStreams streams to read from
|
||||
//! @param[out] theShape shape to save result
|
||||
//! @param[in] theWS current work session
|
||||
//! @param[in] theProgress progress indicator
|
||||
//! @return true if Read operation has ended correctly
|
||||
Standard_EXPORT virtual Standard_Boolean Read(
|
||||
ReadStreamList& theStreams,
|
||||
TopoDS_Shape& theShape,
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange()) Standard_OVERRIDE;
|
||||
|
||||
//! Writes streams according to internal configuration
|
||||
//! @param[in] theStreams streams to write to
|
||||
//! @param[out] theShape shape to export
|
||||
//! @param[in] theWS current work session
|
||||
//! @param[in] theProgress progress indicator
|
||||
//! @return true if Write operation has ended correctly
|
||||
Standard_EXPORT virtual Standard_Boolean Write(
|
||||
WriteStreamList& theStreams,
|
||||
const TopoDS_Shape& theShape,
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange()) Standard_OVERRIDE;
|
||||
|
||||
//! Reads a CAD file, according internal configuration
|
||||
//! @param[in] thePath path to the import CAD file
|
||||
//! @param[out] theShape shape to save result
|
||||
@@ -129,6 +177,46 @@ public:
|
||||
const TopoDS_Shape& theShape,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange()) Standard_OVERRIDE;
|
||||
|
||||
//! Reads streams according to internal configuration
|
||||
//! @param[in] theStreams streams to read from
|
||||
//! @param[out] theDocument document to save result
|
||||
//! @param[in] theProgress progress indicator
|
||||
//! @return true if Read operation has ended correctly
|
||||
Standard_EXPORT virtual Standard_Boolean Read(
|
||||
ReadStreamList& theStreams,
|
||||
const Handle(TDocStd_Document)& theDocument,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange()) Standard_OVERRIDE;
|
||||
|
||||
//! Writes streams according to internal configuration
|
||||
//! @param[in] theStreams streams to write to
|
||||
//! @param[out] theDocument document to export
|
||||
//! @param[in] theProgress progress indicator
|
||||
//! @return true if Write operation has ended correctly
|
||||
Standard_EXPORT virtual Standard_Boolean Write(
|
||||
WriteStreamList& theStreams,
|
||||
const Handle(TDocStd_Document)& theDocument,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange()) Standard_OVERRIDE;
|
||||
|
||||
//! Reads streams according to internal configuration
|
||||
//! @param[in] theStreams streams to read from
|
||||
//! @param[out] theShape shape to save result
|
||||
//! @param[in] theProgress progress indicator
|
||||
//! @return true if Read operation has ended correctly
|
||||
Standard_EXPORT virtual Standard_Boolean Read(
|
||||
ReadStreamList& theStreams,
|
||||
TopoDS_Shape& theShape,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange()) Standard_OVERRIDE;
|
||||
|
||||
//! Writes streams according to internal configuration
|
||||
//! @param[in] theStreams streams to write to
|
||||
//! @param[out] theShape shape to export
|
||||
//! @param[in] theProgress progress indicator
|
||||
//! @return true if Write operation has ended correctly
|
||||
Standard_EXPORT virtual Standard_Boolean Write(
|
||||
WriteStreamList& theStreams,
|
||||
const TopoDS_Shape& theShape,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange()) Standard_OVERRIDE;
|
||||
|
||||
public:
|
||||
//! Gets CAD format name of associated provider
|
||||
//! @return provider CAD format
|
||||
|
475
src/DataExchange/TKDESTEP/GTests/DESTEP_Provider_Test.cxx
Normal file
475
src/DataExchange/TKDESTEP/GTests/DESTEP_Provider_Test.cxx
Normal file
@@ -0,0 +1,475 @@
|
||||
// Copyright (c) 2025 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 <DESTEP_Provider.hxx>
|
||||
#include <DESTEP_ConfigurationNode.hxx>
|
||||
#include <DE_Wrapper.hxx>
|
||||
|
||||
#include <BRepPrimAPI_MakeBox.hxx>
|
||||
#include <BRepPrimAPI_MakeSphere.hxx>
|
||||
#include <BRepPrimAPI_MakeCylinder.hxx>
|
||||
#include <TopoDS_Shape.hxx>
|
||||
#include <TopExp_Explorer.hxx>
|
||||
#include <TopAbs_ShapeEnum.hxx>
|
||||
#include <TDocStd_Document.hxx>
|
||||
#include <TDocStd_Application.hxx>
|
||||
#include <XCAFDoc_DocumentTool.hxx>
|
||||
#include <XCAFDoc_ShapeTool.hxx>
|
||||
#include <XSControl_WorkSession.hxx>
|
||||
|
||||
#include <sstream>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
class DESTEP_ProviderTest : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
void SetUp() override
|
||||
{
|
||||
// Initialize provider with default configuration
|
||||
Handle(DESTEP_ConfigurationNode) aNode = new DESTEP_ConfigurationNode();
|
||||
myProvider = new DESTEP_Provider(aNode);
|
||||
|
||||
// Create test BRep shapes (perfect for STEP format)
|
||||
myBox = BRepPrimAPI_MakeBox(10.0, 10.0, 10.0).Shape();
|
||||
mySphere = BRepPrimAPI_MakeSphere(5.0).Shape();
|
||||
myCylinder = BRepPrimAPI_MakeCylinder(3.0, 8.0).Shape();
|
||||
|
||||
// Create test document
|
||||
Handle(TDocStd_Application) anApp = new TDocStd_Application();
|
||||
anApp->NewDocument("BinXCAF", myDocument);
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
myProvider.Nullify();
|
||||
myDocument.Nullify();
|
||||
}
|
||||
|
||||
// Helper method to count shape elements
|
||||
Standard_Integer CountShapeElements(const TopoDS_Shape& theShape, TopAbs_ShapeEnum theType)
|
||||
{
|
||||
Standard_Integer aCount = 0;
|
||||
for (TopExp_Explorer anExplorer(theShape, theType); anExplorer.More(); anExplorer.Next())
|
||||
{
|
||||
aCount++;
|
||||
}
|
||||
return aCount;
|
||||
}
|
||||
|
||||
// Helper method to validate STEP content
|
||||
bool IsValidSTEPContent(const std::string& theContent)
|
||||
{
|
||||
return !theContent.empty() && theContent.find("ISO-10303-21;") != std::string::npos
|
||||
&& theContent.find("HEADER;") != std::string::npos
|
||||
&& theContent.find("DATA;") != std::string::npos
|
||||
&& theContent.find("ENDSEC;") != std::string::npos;
|
||||
}
|
||||
|
||||
protected:
|
||||
Handle(DESTEP_Provider) myProvider;
|
||||
TopoDS_Shape myBox;
|
||||
TopoDS_Shape mySphere;
|
||||
TopoDS_Shape myCylinder;
|
||||
Handle(TDocStd_Document) myDocument;
|
||||
};
|
||||
|
||||
// Test basic provider creation and format/vendor information
|
||||
TEST_F(DESTEP_ProviderTest, BasicProperties)
|
||||
{
|
||||
EXPECT_STREQ("STEP", myProvider->GetFormat().ToCString());
|
||||
EXPECT_STREQ("OCC", myProvider->GetVendor().ToCString());
|
||||
EXPECT_FALSE(myProvider->GetNode().IsNull());
|
||||
}
|
||||
|
||||
// Test stream-based shape write and read operations
|
||||
TEST_F(DESTEP_ProviderTest, StreamShapeWriteRead)
|
||||
{
|
||||
std::ostringstream anOStream;
|
||||
DE_Provider::WriteStreamList aWriteStreams;
|
||||
aWriteStreams.Append(DE_Provider::WriteStreamNode("test.step", anOStream));
|
||||
|
||||
// Write box shape to stream
|
||||
EXPECT_TRUE(myProvider->Write(aWriteStreams, myBox));
|
||||
|
||||
std::string aStepContent = anOStream.str();
|
||||
EXPECT_FALSE(aStepContent.empty());
|
||||
EXPECT_TRUE(IsValidSTEPContent(aStepContent));
|
||||
|
||||
if (!aStepContent.empty())
|
||||
{
|
||||
// Read back from stream
|
||||
std::istringstream anIStream(aStepContent);
|
||||
DE_Provider::ReadStreamList aReadStreams;
|
||||
aReadStreams.Append(DE_Provider::ReadStreamNode("test.step", anIStream));
|
||||
|
||||
TopoDS_Shape aReadShape;
|
||||
EXPECT_TRUE(myProvider->Read(aReadStreams, aReadShape));
|
||||
EXPECT_FALSE(aReadShape.IsNull());
|
||||
|
||||
if (!aReadShape.IsNull())
|
||||
{
|
||||
// STEP should preserve solid geometry
|
||||
Standard_Integer aReadSolids = CountShapeElements(aReadShape, TopAbs_SOLID);
|
||||
Standard_Integer aOriginalSolids = CountShapeElements(myBox, TopAbs_SOLID);
|
||||
EXPECT_EQ(aReadSolids, aOriginalSolids);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test stream-based document write and read operations
|
||||
TEST_F(DESTEP_ProviderTest, StreamDocumentWriteRead)
|
||||
{
|
||||
// Add box to document
|
||||
Handle(XCAFDoc_ShapeTool) aShapeTool = XCAFDoc_DocumentTool::ShapeTool(myDocument->Main());
|
||||
TDF_Label aShapeLabel = aShapeTool->AddShape(myBox);
|
||||
EXPECT_FALSE(aShapeLabel.IsNull());
|
||||
|
||||
std::ostringstream anOStream;
|
||||
DE_Provider::WriteStreamList aWriteStreams;
|
||||
aWriteStreams.Append(DE_Provider::WriteStreamNode("document.step", anOStream));
|
||||
|
||||
// Write document to stream
|
||||
EXPECT_TRUE(myProvider->Write(aWriteStreams, myDocument));
|
||||
|
||||
std::string aStepContent = anOStream.str();
|
||||
EXPECT_FALSE(aStepContent.empty());
|
||||
EXPECT_TRUE(IsValidSTEPContent(aStepContent));
|
||||
|
||||
if (!aStepContent.empty())
|
||||
{
|
||||
// Create new document for reading
|
||||
Handle(TDocStd_Application) anApp = new TDocStd_Application();
|
||||
Handle(TDocStd_Document) aNewDocument;
|
||||
anApp->NewDocument("BinXCAF", aNewDocument);
|
||||
|
||||
// Read back from stream
|
||||
std::istringstream anIStream(aStepContent);
|
||||
DE_Provider::ReadStreamList aReadStreams;
|
||||
aReadStreams.Append(DE_Provider::ReadStreamNode("document.step", anIStream));
|
||||
|
||||
EXPECT_TRUE(myProvider->Read(aReadStreams, aNewDocument));
|
||||
|
||||
// Validate document content
|
||||
Handle(XCAFDoc_ShapeTool) aNewShapeTool = XCAFDoc_DocumentTool::ShapeTool(aNewDocument->Main());
|
||||
TDF_LabelSequence aLabels;
|
||||
aNewShapeTool->GetShapes(aLabels);
|
||||
EXPECT_GT(aLabels.Length(), 0); // Should have at least one shape in document
|
||||
}
|
||||
}
|
||||
|
||||
// Test DE_Wrapper integration for STEP operations
|
||||
TEST_F(DESTEP_ProviderTest, DE_WrapperIntegration)
|
||||
{
|
||||
// Initialize DE_Wrapper and bind STEP provider
|
||||
DE_Wrapper aWrapper;
|
||||
Handle(DESTEP_ConfigurationNode) aNode = new DESTEP_ConfigurationNode();
|
||||
|
||||
// Bind the configured node to wrapper
|
||||
EXPECT_TRUE(aWrapper.Bind(aNode));
|
||||
|
||||
// Test write with DE_Wrapper using sphere
|
||||
std::ostringstream anOStream;
|
||||
DE_Provider::WriteStreamList aWriteStreams;
|
||||
aWriteStreams.Append(DE_Provider::WriteStreamNode("test.step", anOStream));
|
||||
|
||||
EXPECT_TRUE(aWrapper.Write(aWriteStreams, mySphere));
|
||||
|
||||
std::string aStepContent = anOStream.str();
|
||||
EXPECT_FALSE(aStepContent.empty());
|
||||
EXPECT_TRUE(IsValidSTEPContent(aStepContent));
|
||||
|
||||
if (!aStepContent.empty())
|
||||
{
|
||||
// Test DE_Wrapper stream operations
|
||||
std::istringstream anIStream(aStepContent);
|
||||
DE_Provider::ReadStreamList aReadStreams;
|
||||
aReadStreams.Append(DE_Provider::ReadStreamNode("test.step", anIStream));
|
||||
|
||||
TopoDS_Shape aReadShape;
|
||||
bool aWrapperResult = aWrapper.Read(aReadStreams, aReadShape);
|
||||
|
||||
// Test direct provider with same content for comparison
|
||||
std::istringstream anIStream2(aStepContent);
|
||||
DE_Provider::ReadStreamList aReadStreams2;
|
||||
aReadStreams2.Append(DE_Provider::ReadStreamNode("test.step", anIStream2));
|
||||
|
||||
Handle(DESTEP_Provider) aDirectProvider = new DESTEP_Provider(aNode);
|
||||
TopoDS_Shape aDirectShape;
|
||||
bool aDirectResult = aDirectProvider->Read(aReadStreams2, aDirectShape);
|
||||
|
||||
// REQUIREMENT: DE_Wrapper must work exactly the same as direct provider
|
||||
EXPECT_EQ(aWrapperResult, aDirectResult);
|
||||
EXPECT_EQ(aReadShape.IsNull(), aDirectShape.IsNull());
|
||||
|
||||
if (aDirectResult && !aDirectShape.IsNull())
|
||||
{
|
||||
Standard_Integer aSolids = CountShapeElements(aDirectShape, TopAbs_SOLID);
|
||||
EXPECT_GT(aSolids, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test multiple shapes in single document
|
||||
TEST_F(DESTEP_ProviderTest, MultipleShapesInDocument)
|
||||
{
|
||||
// Add multiple shapes to document
|
||||
Handle(XCAFDoc_ShapeTool) aShapeTool = XCAFDoc_DocumentTool::ShapeTool(myDocument->Main());
|
||||
TDF_Label aBoxLabel = aShapeTool->AddShape(myBox);
|
||||
TDF_Label aSphereLabel = aShapeTool->AddShape(mySphere);
|
||||
TDF_Label aCylinderLabel = aShapeTool->AddShape(myCylinder);
|
||||
|
||||
EXPECT_FALSE(aBoxLabel.IsNull());
|
||||
EXPECT_FALSE(aSphereLabel.IsNull());
|
||||
EXPECT_FALSE(aCylinderLabel.IsNull());
|
||||
|
||||
std::ostringstream anOStream;
|
||||
DE_Provider::WriteStreamList aWriteStreams;
|
||||
aWriteStreams.Append(DE_Provider::WriteStreamNode("multi_shapes.step", anOStream));
|
||||
|
||||
// Write document with multiple shapes
|
||||
EXPECT_TRUE(myProvider->Write(aWriteStreams, myDocument));
|
||||
|
||||
std::string aStepContent = anOStream.str();
|
||||
EXPECT_FALSE(aStepContent.empty());
|
||||
EXPECT_TRUE(IsValidSTEPContent(aStepContent));
|
||||
|
||||
// Read back into new document
|
||||
Handle(TDocStd_Application) anApp = new TDocStd_Application();
|
||||
Handle(TDocStd_Document) aNewDocument;
|
||||
anApp->NewDocument("BinXCAF", aNewDocument);
|
||||
|
||||
std::istringstream anIStream(aStepContent);
|
||||
DE_Provider::ReadStreamList aReadStreams;
|
||||
aReadStreams.Append(DE_Provider::ReadStreamNode("multi_shapes.step", anIStream));
|
||||
|
||||
EXPECT_TRUE(myProvider->Read(aReadStreams, aNewDocument));
|
||||
|
||||
// Validate document content
|
||||
Handle(XCAFDoc_ShapeTool) aNewShapeTool = XCAFDoc_DocumentTool::ShapeTool(aNewDocument->Main());
|
||||
TDF_LabelSequence aLabels;
|
||||
aNewShapeTool->GetShapes(aLabels);
|
||||
EXPECT_EQ(aLabels.Length(), 3); // Should have exactly 3 shapes in document
|
||||
}
|
||||
|
||||
// Test different BRep geometry types
|
||||
TEST_F(DESTEP_ProviderTest, DifferentBRepGeometries)
|
||||
{
|
||||
// Test box geometry
|
||||
std::ostringstream aBoxStream;
|
||||
DE_Provider::WriteStreamList aBoxWriteStreams;
|
||||
aBoxWriteStreams.Append(DE_Provider::WriteStreamNode("box.step", aBoxStream));
|
||||
|
||||
EXPECT_TRUE(myProvider->Write(aBoxWriteStreams, myBox));
|
||||
std::string aBoxContent = aBoxStream.str();
|
||||
|
||||
// Test sphere geometry
|
||||
std::ostringstream aSphereStream;
|
||||
DE_Provider::WriteStreamList aSphereWriteStreams;
|
||||
aSphereWriteStreams.Append(DE_Provider::WriteStreamNode("sphere.step", aSphereStream));
|
||||
|
||||
EXPECT_TRUE(myProvider->Write(aSphereWriteStreams, mySphere));
|
||||
std::string aSphereContent = aSphereStream.str();
|
||||
|
||||
// Test cylinder geometry
|
||||
std::ostringstream aCylinderStream;
|
||||
DE_Provider::WriteStreamList aCylinderWriteStreams;
|
||||
aCylinderWriteStreams.Append(DE_Provider::WriteStreamNode("cylinder.step", aCylinderStream));
|
||||
|
||||
EXPECT_TRUE(myProvider->Write(aCylinderWriteStreams, myCylinder));
|
||||
std::string aCylinderContent = aCylinderStream.str();
|
||||
|
||||
// All content should be valid STEP format
|
||||
EXPECT_TRUE(IsValidSTEPContent(aBoxContent));
|
||||
EXPECT_TRUE(IsValidSTEPContent(aSphereContent));
|
||||
EXPECT_TRUE(IsValidSTEPContent(aCylinderContent));
|
||||
|
||||
// Different geometries should produce different STEP content
|
||||
EXPECT_NE(aBoxContent, aSphereContent);
|
||||
EXPECT_NE(aBoxContent, aCylinderContent);
|
||||
EXPECT_NE(aSphereContent, aCylinderContent);
|
||||
|
||||
// All should read back successfully
|
||||
std::istringstream aBoxIStream(aBoxContent);
|
||||
DE_Provider::ReadStreamList aBoxReadStreams;
|
||||
aBoxReadStreams.Append(DE_Provider::ReadStreamNode("box.step", aBoxIStream));
|
||||
|
||||
TopoDS_Shape aBoxReadShape;
|
||||
EXPECT_TRUE(myProvider->Read(aBoxReadStreams, aBoxReadShape));
|
||||
EXPECT_FALSE(aBoxReadShape.IsNull());
|
||||
|
||||
std::istringstream aSphereIStream(aSphereContent);
|
||||
DE_Provider::ReadStreamList aSphereReadStreams;
|
||||
aSphereReadStreams.Append(DE_Provider::ReadStreamNode("sphere.step", aSphereIStream));
|
||||
|
||||
TopoDS_Shape aSphereReadShape;
|
||||
EXPECT_TRUE(myProvider->Read(aSphereReadStreams, aSphereReadShape));
|
||||
EXPECT_FALSE(aSphereReadShape.IsNull());
|
||||
}
|
||||
|
||||
// Test DE_Wrapper with different file extensions
|
||||
TEST_F(DESTEP_ProviderTest, DE_WrapperFileExtensions)
|
||||
{
|
||||
DE_Wrapper aWrapper;
|
||||
Handle(DESTEP_ConfigurationNode) aNode = new DESTEP_ConfigurationNode();
|
||||
EXPECT_TRUE(aWrapper.Bind(aNode));
|
||||
|
||||
// Test different STEP extensions
|
||||
std::vector<std::string> aExtensions = {"test.step", "test.STEP", "test.stp", "test.STP"};
|
||||
|
||||
for (const auto& anExt : aExtensions)
|
||||
{
|
||||
std::ostringstream anOStream;
|
||||
DE_Provider::WriteStreamList aWriteStreams;
|
||||
aWriteStreams.Append(DE_Provider::WriteStreamNode(anExt.c_str(), anOStream));
|
||||
|
||||
EXPECT_TRUE(aWrapper.Write(aWriteStreams, myBox))
|
||||
<< "Failed to write with extension: " << anExt;
|
||||
|
||||
std::string aContent = anOStream.str();
|
||||
EXPECT_FALSE(aContent.empty()) << "Empty content for extension: " << anExt;
|
||||
EXPECT_TRUE(IsValidSTEPContent(aContent)) << "Invalid STEP content for extension: " << anExt;
|
||||
|
||||
// Test read back
|
||||
std::istringstream anIStream(aContent);
|
||||
DE_Provider::ReadStreamList aReadStreams;
|
||||
aReadStreams.Append(DE_Provider::ReadStreamNode(anExt.c_str(), anIStream));
|
||||
|
||||
TopoDS_Shape aReadShape;
|
||||
EXPECT_TRUE(aWrapper.Read(aReadStreams, aReadShape))
|
||||
<< "Failed to read with extension: " << anExt;
|
||||
EXPECT_FALSE(aReadShape.IsNull()) << "Null shape read with extension: " << anExt;
|
||||
}
|
||||
}
|
||||
|
||||
// Test error conditions and edge cases
|
||||
TEST_F(DESTEP_ProviderTest, ErrorHandling)
|
||||
{
|
||||
// Test with empty streams
|
||||
DE_Provider::WriteStreamList anEmptyWriteStreams;
|
||||
EXPECT_FALSE(myProvider->Write(anEmptyWriteStreams, myBox));
|
||||
|
||||
DE_Provider::ReadStreamList anEmptyReadStreams;
|
||||
TopoDS_Shape aShape;
|
||||
EXPECT_FALSE(myProvider->Read(anEmptyReadStreams, aShape));
|
||||
|
||||
// Test with null shape
|
||||
std::ostringstream anOStream;
|
||||
DE_Provider::WriteStreamList aWriteStreams;
|
||||
aWriteStreams.Append(DE_Provider::WriteStreamNode("null_test.step", anOStream));
|
||||
TopoDS_Shape aNullShape;
|
||||
|
||||
// Writing null shape should fail
|
||||
EXPECT_FALSE(myProvider->Write(aWriteStreams, aNullShape));
|
||||
|
||||
// Test reading invalid STEP content
|
||||
std::string anInvalidContent = "This is not valid STEP content";
|
||||
std::istringstream anInvalidStream(anInvalidContent);
|
||||
DE_Provider::ReadStreamList anInvalidReadStreams;
|
||||
anInvalidReadStreams.Append(DE_Provider::ReadStreamNode("invalid.step", anInvalidStream));
|
||||
|
||||
TopoDS_Shape anInvalidShape;
|
||||
EXPECT_FALSE(myProvider->Read(anInvalidReadStreams, anInvalidShape));
|
||||
|
||||
// Test with null document
|
||||
Handle(TDocStd_Document) aNullDoc;
|
||||
EXPECT_FALSE(myProvider->Write(aWriteStreams, aNullDoc));
|
||||
EXPECT_FALSE(myProvider->Read(anEmptyReadStreams, aNullDoc));
|
||||
}
|
||||
|
||||
// Test DESTEP configuration modes
|
||||
TEST_F(DESTEP_ProviderTest, ConfigurationModes)
|
||||
{
|
||||
Handle(DESTEP_ConfigurationNode) aNode =
|
||||
Handle(DESTEP_ConfigurationNode)::DownCast(myProvider->GetNode());
|
||||
|
||||
// Test basic configuration access
|
||||
EXPECT_FALSE(aNode.IsNull());
|
||||
|
||||
// Test provider format and vendor are correct
|
||||
EXPECT_STREQ("STEP", myProvider->GetFormat().ToCString());
|
||||
EXPECT_STREQ("OCC", myProvider->GetVendor().ToCString());
|
||||
|
||||
// Test that we can create provider with different configuration
|
||||
Handle(DESTEP_ConfigurationNode) aNewNode = new DESTEP_ConfigurationNode();
|
||||
Handle(DESTEP_Provider) aNewProvider = new DESTEP_Provider(aNewNode);
|
||||
|
||||
EXPECT_STREQ("STEP", aNewProvider->GetFormat().ToCString());
|
||||
EXPECT_STREQ("OCC", aNewProvider->GetVendor().ToCString());
|
||||
EXPECT_FALSE(aNewProvider->GetNode().IsNull());
|
||||
}
|
||||
|
||||
// Test WorkSession integration
|
||||
TEST_F(DESTEP_ProviderTest, WorkSessionIntegration)
|
||||
{
|
||||
Handle(XSControl_WorkSession) aWS = new XSControl_WorkSession();
|
||||
|
||||
// Test write operation with work session
|
||||
std::ostringstream anOStream;
|
||||
DE_Provider::WriteStreamList aWriteStreams;
|
||||
aWriteStreams.Append(DE_Provider::WriteStreamNode("ws_test.step", anOStream));
|
||||
|
||||
EXPECT_TRUE(myProvider->Write(aWriteStreams, myBox, aWS));
|
||||
|
||||
std::string aStepContent = anOStream.str();
|
||||
EXPECT_FALSE(aStepContent.empty());
|
||||
EXPECT_TRUE(IsValidSTEPContent(aStepContent));
|
||||
|
||||
// Test read operation with work session
|
||||
std::istringstream anIStream(aStepContent);
|
||||
DE_Provider::ReadStreamList aReadStreams;
|
||||
aReadStreams.Append(DE_Provider::ReadStreamNode("ws_test.step", anIStream));
|
||||
|
||||
TopoDS_Shape aReadShape;
|
||||
EXPECT_TRUE(myProvider->Read(aReadStreams, aReadShape, aWS));
|
||||
EXPECT_FALSE(aReadShape.IsNull());
|
||||
}
|
||||
|
||||
// Test document operations with WorkSession
|
||||
TEST_F(DESTEP_ProviderTest, DocumentWorkSessionIntegration)
|
||||
{
|
||||
// Add shape to document
|
||||
Handle(XCAFDoc_ShapeTool) aShapeTool = XCAFDoc_DocumentTool::ShapeTool(myDocument->Main());
|
||||
TDF_Label aShapeLabel = aShapeTool->AddShape(mySphere);
|
||||
EXPECT_FALSE(aShapeLabel.IsNull());
|
||||
|
||||
Handle(XSControl_WorkSession) aWS = new XSControl_WorkSession();
|
||||
|
||||
std::ostringstream anOStream;
|
||||
DE_Provider::WriteStreamList aWriteStreams;
|
||||
aWriteStreams.Append(DE_Provider::WriteStreamNode("doc_ws_test.step", anOStream));
|
||||
|
||||
// Test document write with work session
|
||||
EXPECT_TRUE(myProvider->Write(aWriteStreams, myDocument, aWS));
|
||||
|
||||
std::string aStepContent = anOStream.str();
|
||||
EXPECT_FALSE(aStepContent.empty());
|
||||
EXPECT_TRUE(IsValidSTEPContent(aStepContent));
|
||||
|
||||
// Create new document for reading
|
||||
Handle(TDocStd_Application) anApp = new TDocStd_Application();
|
||||
Handle(TDocStd_Document) aNewDocument;
|
||||
anApp->NewDocument("BinXCAF", aNewDocument);
|
||||
|
||||
// Test document read with work session
|
||||
std::istringstream anIStream(aStepContent);
|
||||
DE_Provider::ReadStreamList aReadStreams;
|
||||
aReadStreams.Append(DE_Provider::ReadStreamNode("doc_ws_test.step", anIStream));
|
||||
|
||||
EXPECT_TRUE(myProvider->Read(aReadStreams, aNewDocument, aWS));
|
||||
|
||||
// Validate document content
|
||||
Handle(XCAFDoc_ShapeTool) aNewShapeTool = XCAFDoc_DocumentTool::ShapeTool(aNewDocument->Main());
|
||||
TDF_LabelSequence aLabels;
|
||||
aNewShapeTool->GetShapes(aLabels);
|
||||
EXPECT_GT(aLabels.Length(), 0);
|
||||
}
|
@@ -2,6 +2,7 @@
|
||||
set(OCCT_TKDESTEP_GTests_FILES_LOCATION "${CMAKE_CURRENT_LIST_DIR}")
|
||||
|
||||
set(OCCT_TKDESTEP_GTests_FILES
|
||||
DESTEP_Provider_Test.cxx
|
||||
STEPConstruct_RenderingProperties_Test.cxx
|
||||
StepData_StepWriter_Test.cxx
|
||||
StepTidy_BaseTestFixture.pxx
|
||||
|
@@ -134,6 +134,13 @@ bool DESTL_ConfigurationNode::IsExportSupported() const
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
bool DESTL_ConfigurationNode::IsStreamSupported() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
TCollection_AsciiString DESTL_ConfigurationNode::GetFormat() const
|
||||
{
|
||||
return TCollection_AsciiString("STL");
|
||||
|
@@ -64,6 +64,10 @@ public:
|
||||
//! @return true if export is supported
|
||||
Standard_EXPORT virtual bool IsExportSupported() const Standard_OVERRIDE;
|
||||
|
||||
//! Checks for stream support.
|
||||
//! @return Standard_True if streams are supported
|
||||
Standard_EXPORT virtual bool IsStreamSupported() const Standard_OVERRIDE;
|
||||
|
||||
//! Gets CAD format name of associated provider
|
||||
//! @return provider CAD format
|
||||
Standard_EXPORT virtual TCollection_AsciiString GetFormat() const Standard_OVERRIDE;
|
||||
|
@@ -14,14 +14,21 @@
|
||||
#include <DESTL_Provider.hxx>
|
||||
|
||||
#include <BRep_Builder.hxx>
|
||||
#include <DE_ValidationUtils.hxx>
|
||||
#include <DESTL_ConfigurationNode.hxx>
|
||||
#include <Message.hxx>
|
||||
#include <NCollection_Vector.hxx>
|
||||
#include <Poly_Triangle.hxx>
|
||||
#include <RWStl.hxx>
|
||||
#include <RWStl_Reader.hxx>
|
||||
#include <StlAPI.hxx>
|
||||
#include <StlAPI_Reader.hxx>
|
||||
#include <StlAPI_Writer.hxx>
|
||||
#include <Standard_ReadLineBuffer.hxx>
|
||||
#include <TDocStd_Document.hxx>
|
||||
#include <XCAFDoc_DocumentTool.hxx>
|
||||
#include <XCAFDoc_ShapeTool.hxx>
|
||||
#include <cstring>
|
||||
|
||||
IMPLEMENT_STANDARD_RTTIEXT(DESTL_Provider, DE_Provider)
|
||||
|
||||
@@ -64,10 +71,9 @@ bool DESTL_Provider::Read(const TCollection_AsciiString& thePath,
|
||||
const Handle(TDocStd_Document)& theDocument,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
if (theDocument.IsNull())
|
||||
TCollection_AsciiString aContext = TCollection_AsciiString("reading the file ") + thePath;
|
||||
if (!DE_ValidationUtils::ValidateDocument(theDocument, aContext))
|
||||
{
|
||||
Message::SendFail() << "Error in the DESTL_Provider during reading the file " << thePath
|
||||
<< "\t: theDocument shouldn't be null";
|
||||
return false;
|
||||
}
|
||||
TopoDS_Shape aShape;
|
||||
@@ -86,25 +92,35 @@ bool DESTL_Provider::Write(const TCollection_AsciiString& thePath,
|
||||
const Handle(TDocStd_Document)& theDocument,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
TopoDS_Shape aShape;
|
||||
TCollection_AsciiString aContext = TCollection_AsciiString("writing the file ") + thePath;
|
||||
if (!DE_ValidationUtils::ValidateDocument(theDocument, aContext))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Extract shape from document
|
||||
TDF_LabelSequence aLabels;
|
||||
Handle(XCAFDoc_ShapeTool) aSTool = XCAFDoc_DocumentTool::ShapeTool(theDocument->Main());
|
||||
aSTool->GetFreeShapes(aLabels);
|
||||
|
||||
if (aLabels.Length() <= 0)
|
||||
{
|
||||
Message::SendFail() << "Error in the DESTL_Provider during writing the file " << thePath
|
||||
<< "\t: Document contain no shapes";
|
||||
<< ": Document contain no shapes";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!DE_ValidationUtils::ValidateConfigurationNode(GetNode(),
|
||||
STANDARD_TYPE(DESTL_ConfigurationNode),
|
||||
aContext))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Handle(DESTL_ConfigurationNode) aNode = Handle(DESTL_ConfigurationNode)::DownCast(GetNode());
|
||||
if (aNode->GlobalParameters.LengthUnit != 1.0)
|
||||
{
|
||||
Message::SendWarning()
|
||||
<< "Warning in the DESTL_Provider during writing the file " << thePath
|
||||
<< "\t: Target Units for writing were changed, but current format doesn't support scaling";
|
||||
}
|
||||
DE_ValidationUtils::WarnLengthUnitNotSupported(aNode->GlobalParameters.LengthUnit, aContext);
|
||||
|
||||
TopoDS_Shape aShape;
|
||||
if (aLabels.Length() == 1)
|
||||
{
|
||||
aShape = aSTool->GetShape(aLabels.Value(1));
|
||||
@@ -121,6 +137,7 @@ bool DESTL_Provider::Write(const TCollection_AsciiString& thePath,
|
||||
}
|
||||
aShape = aComp;
|
||||
}
|
||||
|
||||
return Write(thePath, aShape, theProgress);
|
||||
}
|
||||
|
||||
@@ -154,14 +171,18 @@ bool DESTL_Provider::Read(const TCollection_AsciiString& thePath,
|
||||
{
|
||||
Message::SendWarning()
|
||||
<< "OCCT Stl reader does not support model scaling according to custom length unit";
|
||||
if (!GetNode()->IsKind(STANDARD_TYPE(DESTL_ConfigurationNode)))
|
||||
|
||||
TCollection_AsciiString aContext = TCollection_AsciiString("reading the file ") + thePath;
|
||||
if (!DE_ValidationUtils::ValidateConfigurationNode(GetNode(),
|
||||
STANDARD_TYPE(DESTL_ConfigurationNode),
|
||||
aContext))
|
||||
{
|
||||
Message::SendFail() << "Error in the DESTL_Provider during reading the file " << thePath
|
||||
<< "\t: Incorrect or empty Configuration Node";
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
Handle(DESTL_ConfigurationNode) aNode = Handle(DESTL_ConfigurationNode)::DownCast(GetNode());
|
||||
double aMergeAngle = aNode->InternalParameters.ReadMergeAngle * M_PI / 180.0;
|
||||
|
||||
if (aMergeAngle != M_PI_2)
|
||||
{
|
||||
if (aMergeAngle < 0.0 || aMergeAngle > M_PI_2)
|
||||
@@ -171,6 +192,7 @@ bool DESTL_Provider::Read(const TCollection_AsciiString& thePath,
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!aNode->InternalParameters.ReadBRep)
|
||||
{
|
||||
Handle(Poly_Triangulation) aTriangulation =
|
||||
@@ -184,7 +206,9 @@ bool DESTL_Provider::Read(const TCollection_AsciiString& thePath,
|
||||
}
|
||||
else
|
||||
{
|
||||
Standard_DISABLE_DEPRECATION_WARNINGS if (!StlAPI::Read(theShape, thePath.ToCString()))
|
||||
Standard_DISABLE_DEPRECATION_WARNINGS
|
||||
|
||||
if (!StlAPI::Read(theShape, thePath.ToCString()))
|
||||
{
|
||||
Message::SendFail() << "Error in the DESTL_Provider during reading the file " << thePath;
|
||||
return false;
|
||||
@@ -202,25 +226,23 @@ bool DESTL_Provider::Write(const TCollection_AsciiString& thePath,
|
||||
{
|
||||
Message::SendWarning()
|
||||
<< "OCCT Stl writer does not support model scaling according to custom length unit";
|
||||
if (GetNode().IsNull() || !GetNode()->IsKind(STANDARD_TYPE(DESTL_ConfigurationNode)))
|
||||
|
||||
TCollection_AsciiString aContext = TCollection_AsciiString("writing the file ") + thePath;
|
||||
if (!DE_ValidationUtils::ValidateConfigurationNode(GetNode(),
|
||||
STANDARD_TYPE(DESTL_ConfigurationNode),
|
||||
aContext))
|
||||
{
|
||||
Message::SendFail() << "Error in the DESTL_Provider during reading the file " << thePath
|
||||
<< "\t: Incorrect or empty Configuration Node";
|
||||
return false;
|
||||
}
|
||||
|
||||
Handle(DESTL_ConfigurationNode) aNode = Handle(DESTL_ConfigurationNode)::DownCast(GetNode());
|
||||
if (aNode->GlobalParameters.LengthUnit != 1.0)
|
||||
{
|
||||
Message::SendWarning()
|
||||
<< "Warning in the DESTL_Provider during writing the file " << thePath
|
||||
<< "\t: Target Units for writing were changed, but current format doesn't support scaling";
|
||||
}
|
||||
DE_ValidationUtils::WarnLengthUnitNotSupported(aNode->GlobalParameters.LengthUnit, aContext);
|
||||
|
||||
StlAPI_Writer aWriter;
|
||||
aWriter.ASCIIMode() = aNode->InternalParameters.WriteAscii;
|
||||
if (!aWriter.Write(theShape, thePath.ToCString(), theProgress))
|
||||
{
|
||||
Message::SendFail() << "Error in the DESTL_Provider during reading the file " << thePath
|
||||
Message::SendFail() << "Error in the DESTL_Provider during writing the file " << thePath
|
||||
<< "\t: Mesh writing has been failed";
|
||||
return false;
|
||||
}
|
||||
@@ -229,6 +251,271 @@ bool DESTL_Provider::Write(const TCollection_AsciiString& thePath,
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DESTL_Provider::Read(ReadStreamList& theStreams,
|
||||
const Handle(TDocStd_Document)& theDocument,
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
(void)theWS;
|
||||
return Read(theStreams, theDocument, theProgress);
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DESTL_Provider::Write(WriteStreamList& theStreams,
|
||||
const Handle(TDocStd_Document)& theDocument,
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
(void)theWS;
|
||||
return Write(theStreams, theDocument, theProgress);
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DESTL_Provider::Read(ReadStreamList& theStreams,
|
||||
TopoDS_Shape& theShape,
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
(void)theWS;
|
||||
return Read(theStreams, theShape, theProgress);
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DESTL_Provider::Write(WriteStreamList& theStreams,
|
||||
const TopoDS_Shape& theShape,
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
(void)theWS;
|
||||
return Write(theStreams, theShape, theProgress);
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DESTL_Provider::Read(ReadStreamList& theStreams,
|
||||
const Handle(TDocStd_Document)& theDocument,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
TCollection_AsciiString aContext = "reading stream";
|
||||
if (!DE_ValidationUtils::ValidateReadStreamList(theStreams, aContext))
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
const TCollection_AsciiString& aFirstKey = theStreams.First().Path;
|
||||
TCollection_AsciiString aFullContext = aContext + " " + aFirstKey;
|
||||
if (!DE_ValidationUtils::ValidateDocument(theDocument, aFullContext))
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
TopoDS_Shape aShape;
|
||||
if (!Read(theStreams, aShape, theProgress))
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
Handle(XCAFDoc_ShapeTool) aShapeTool = XCAFDoc_DocumentTool::ShapeTool(theDocument->Main());
|
||||
aShapeTool->AddShape(aShape);
|
||||
return Standard_True;
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DESTL_Provider::Write(WriteStreamList& theStreams,
|
||||
const Handle(TDocStd_Document)& theDocument,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
TCollection_AsciiString aContext = "writing stream";
|
||||
if (!DE_ValidationUtils::ValidateWriteStreamList(theStreams, aContext))
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
const TCollection_AsciiString& aFirstKey = theStreams.First().Path;
|
||||
TCollection_AsciiString aFullContext = aContext + " " + aFirstKey;
|
||||
if (!DE_ValidationUtils::ValidateDocument(theDocument, aFullContext))
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
// Extract shape from document
|
||||
TDF_LabelSequence aLabels;
|
||||
Handle(XCAFDoc_ShapeTool) aSTool = XCAFDoc_DocumentTool::ShapeTool(theDocument->Main());
|
||||
aSTool->GetFreeShapes(aLabels);
|
||||
|
||||
if (aLabels.Length() <= 0)
|
||||
{
|
||||
Message::SendFail() << "Error in the DESTL_Provider during writing stream " << aFirstKey
|
||||
<< ": Document contain no shapes";
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
if (!DE_ValidationUtils::ValidateConfigurationNode(GetNode(),
|
||||
STANDARD_TYPE(DESTL_ConfigurationNode),
|
||||
aFullContext))
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
Handle(DESTL_ConfigurationNode) aNode = Handle(DESTL_ConfigurationNode)::DownCast(GetNode());
|
||||
TCollection_AsciiString aLengthContext = TCollection_AsciiString("writing stream ") + aFirstKey;
|
||||
DE_ValidationUtils::WarnLengthUnitNotSupported(aNode->GlobalParameters.LengthUnit,
|
||||
aLengthContext);
|
||||
|
||||
TopoDS_Shape aShape;
|
||||
if (aLabels.Length() == 1)
|
||||
{
|
||||
aShape = aSTool->GetShape(aLabels.Value(1));
|
||||
}
|
||||
else
|
||||
{
|
||||
TopoDS_Compound aComp;
|
||||
BRep_Builder aBuilder;
|
||||
aBuilder.MakeCompound(aComp);
|
||||
for (Standard_Integer anIndex = 1; anIndex <= aLabels.Length(); anIndex++)
|
||||
{
|
||||
TopoDS_Shape aS = aSTool->GetShape(aLabels.Value(anIndex));
|
||||
aBuilder.Add(aComp, aS);
|
||||
}
|
||||
aShape = aComp;
|
||||
}
|
||||
|
||||
return Write(theStreams, aShape, theProgress);
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DESTL_Provider::Read(ReadStreamList& theStreams,
|
||||
TopoDS_Shape& theShape,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
// Validate stream map
|
||||
if (theStreams.IsEmpty())
|
||||
{
|
||||
Message::SendFail() << "Error: DESTL_Provider stream map is empty";
|
||||
return Standard_False;
|
||||
}
|
||||
if (theStreams.Size() > 1)
|
||||
{
|
||||
Message::SendWarning() << "Warning: DESTL_Provider received " << theStreams.Size()
|
||||
<< " streams for reading, using only the first one";
|
||||
}
|
||||
|
||||
const TCollection_AsciiString& aFirstKey = theStreams.First().Path;
|
||||
Standard_IStream& aStream = theStreams.First().Stream;
|
||||
|
||||
Message::SendWarning()
|
||||
<< "OCCT Stl reader does not support model scaling according to custom length unit";
|
||||
|
||||
TCollection_AsciiString aNodeContext = TCollection_AsciiString("reading stream ") + aFirstKey;
|
||||
if (!DE_ValidationUtils::ValidateConfigurationNode(GetNode(),
|
||||
STANDARD_TYPE(DESTL_ConfigurationNode),
|
||||
aNodeContext))
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
Handle(DESTL_ConfigurationNode) aNode = Handle(DESTL_ConfigurationNode)::DownCast(GetNode());
|
||||
double aMergeAngle = aNode->InternalParameters.ReadMergeAngle * M_PI / 180.0;
|
||||
|
||||
if (aMergeAngle != M_PI_2)
|
||||
{
|
||||
if (aMergeAngle < 0.0 || aMergeAngle > M_PI_2)
|
||||
{
|
||||
Message::SendFail() << "Error in the DESTL_Provider during reading stream " << aFirstKey
|
||||
<< ": The merge angle is out of the valid range";
|
||||
return Standard_False;
|
||||
}
|
||||
}
|
||||
|
||||
if (!aNode->InternalParameters.ReadBRep)
|
||||
{
|
||||
Handle(Poly_Triangulation) aTriangulation =
|
||||
RWStl::ReadStream(aStream, aMergeAngle, theProgress);
|
||||
if (aTriangulation.IsNull())
|
||||
{
|
||||
Message::SendFail() << "Error in the DESTL_Provider during reading stream " << aFirstKey
|
||||
<< ": Failed to create triangulation";
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
TopoDS_Face aFace;
|
||||
BRep_Builder aB;
|
||||
aB.MakeFace(aFace);
|
||||
aB.UpdateFace(aFace, aTriangulation);
|
||||
theShape = aFace;
|
||||
}
|
||||
else
|
||||
{
|
||||
Standard_DISABLE_DEPRECATION_WARNINGS
|
||||
|
||||
StlAPI_Reader aReader;
|
||||
if (!aReader.Read(theShape, aStream))
|
||||
{
|
||||
Message::SendFail() << "Error in the DESTL_Provider during reading stream " << aFirstKey;
|
||||
return Standard_False;
|
||||
}
|
||||
Standard_ENABLE_DEPRECATION_WARNINGS
|
||||
}
|
||||
|
||||
return Standard_True;
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DESTL_Provider::Write(WriteStreamList& theStreams,
|
||||
const TopoDS_Shape& theShape,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
// Validate stream map
|
||||
if (theStreams.IsEmpty())
|
||||
{
|
||||
Message::SendFail() << "Error: DESTL_Provider stream map is empty";
|
||||
return Standard_False;
|
||||
}
|
||||
if (theStreams.Size() > 1)
|
||||
{
|
||||
Message::SendWarning() << "Warning: DESTL_Provider received " << theStreams.Size()
|
||||
<< " streams for writing, using only the first one";
|
||||
}
|
||||
|
||||
const TCollection_AsciiString& aFirstKey = theStreams.First().Path;
|
||||
Standard_OStream& aStream = theStreams.First().Stream;
|
||||
|
||||
Message::SendWarning()
|
||||
<< "OCCT Stl writer does not support model scaling according to custom length unit";
|
||||
|
||||
TCollection_AsciiString aNodeContext = TCollection_AsciiString("writing stream ") + aFirstKey;
|
||||
if (!DE_ValidationUtils::ValidateConfigurationNode(GetNode(),
|
||||
STANDARD_TYPE(DESTL_ConfigurationNode),
|
||||
aNodeContext))
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
Handle(DESTL_ConfigurationNode) aNode = Handle(DESTL_ConfigurationNode)::DownCast(GetNode());
|
||||
TCollection_AsciiString aLengthContext = TCollection_AsciiString("writing stream ") + aFirstKey;
|
||||
DE_ValidationUtils::WarnLengthUnitNotSupported(aNode->GlobalParameters.LengthUnit,
|
||||
aLengthContext);
|
||||
|
||||
StlAPI_Writer aWriter;
|
||||
aWriter.ASCIIMode() = aNode->InternalParameters.WriteAscii;
|
||||
if (!aWriter.Write(theShape, aStream, theProgress))
|
||||
{
|
||||
Message::SendFail() << "Error in the DESTL_Provider during writing stream " << aFirstKey
|
||||
<< ": Mesh writing has been failed";
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
return Standard_True;
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
TCollection_AsciiString DESTL_Provider::GetFormat() const
|
||||
{
|
||||
return TCollection_AsciiString("STL");
|
||||
|
@@ -108,6 +108,54 @@ public:
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange()) Standard_OVERRIDE;
|
||||
|
||||
//! Reads streams according to internal configuration
|
||||
//! @param[in] theStreams streams to read from
|
||||
//! @param[out] theDocument document to save result
|
||||
//! @param[in] theWS current work session
|
||||
//! @param[in] theProgress progress indicator
|
||||
//! @return true if Read operation has ended correctly
|
||||
Standard_EXPORT virtual Standard_Boolean Read(
|
||||
ReadStreamList& theStreams,
|
||||
const Handle(TDocStd_Document)& theDocument,
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange()) Standard_OVERRIDE;
|
||||
|
||||
//! Writes streams according to internal configuration
|
||||
//! @param[in] theStreams streams to write to
|
||||
//! @param[out] theDocument document to export
|
||||
//! @param[in] theWS current work session
|
||||
//! @param[in] theProgress progress indicator
|
||||
//! @return true if Write operation has ended correctly
|
||||
Standard_EXPORT virtual Standard_Boolean Write(
|
||||
WriteStreamList& theStreams,
|
||||
const Handle(TDocStd_Document)& theDocument,
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange()) Standard_OVERRIDE;
|
||||
|
||||
//! Reads streams according to internal configuration
|
||||
//! @param[in] theStreams streams to read from
|
||||
//! @param[out] theShape shape to save result
|
||||
//! @param[in] theWS current work session
|
||||
//! @param[in] theProgress progress indicator
|
||||
//! @return true if Read operation has ended correctly
|
||||
Standard_EXPORT virtual Standard_Boolean Read(
|
||||
ReadStreamList& theStreams,
|
||||
TopoDS_Shape& theShape,
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange()) Standard_OVERRIDE;
|
||||
|
||||
//! Writes streams according to internal configuration
|
||||
//! @param[in] theStreams streams to write to
|
||||
//! @param[out] theShape shape to export
|
||||
//! @param[in] theWS current work session
|
||||
//! @param[in] theProgress progress indicator
|
||||
//! @return true if Write operation has ended correctly
|
||||
Standard_EXPORT virtual Standard_Boolean Write(
|
||||
WriteStreamList& theStreams,
|
||||
const TopoDS_Shape& theShape,
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange()) Standard_OVERRIDE;
|
||||
|
||||
//! Reads a CAD file, according internal configuration
|
||||
//! @param[in] thePath path to the import CAD file
|
||||
//! @param[out] theShape shape to save result
|
||||
@@ -128,6 +176,46 @@ public:
|
||||
const TopoDS_Shape& theShape,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange()) Standard_OVERRIDE;
|
||||
|
||||
//! Reads streams according to internal configuration
|
||||
//! @param[in] theStreams streams to read from
|
||||
//! @param[out] theDocument document to save result
|
||||
//! @param[in] theProgress progress indicator
|
||||
//! @return true if Read operation has ended correctly
|
||||
Standard_EXPORT virtual Standard_Boolean Read(
|
||||
ReadStreamList& theStreams,
|
||||
const Handle(TDocStd_Document)& theDocument,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange()) Standard_OVERRIDE;
|
||||
|
||||
//! Writes streams according to internal configuration
|
||||
//! @param[in] theStreams streams to write to
|
||||
//! @param[out] theDocument document to export
|
||||
//! @param[in] theProgress progress indicator
|
||||
//! @return true if Write operation has ended correctly
|
||||
Standard_EXPORT virtual Standard_Boolean Write(
|
||||
WriteStreamList& theStreams,
|
||||
const Handle(TDocStd_Document)& theDocument,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange()) Standard_OVERRIDE;
|
||||
|
||||
//! Reads streams according to internal configuration
|
||||
//! @param[in] theStreams streams to read from
|
||||
//! @param[out] theShape shape to save result
|
||||
//! @param[in] theProgress progress indicator
|
||||
//! @return true if Read operation has ended correctly
|
||||
Standard_EXPORT virtual Standard_Boolean Read(
|
||||
ReadStreamList& theStreams,
|
||||
TopoDS_Shape& theShape,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange()) Standard_OVERRIDE;
|
||||
|
||||
//! Writes streams according to internal configuration
|
||||
//! @param[in] theStreams streams to write to
|
||||
//! @param[out] theShape shape to export
|
||||
//! @param[in] theProgress progress indicator
|
||||
//! @return true if Write operation has ended correctly
|
||||
Standard_EXPORT virtual Standard_Boolean Write(
|
||||
WriteStreamList& theStreams,
|
||||
const TopoDS_Shape& theShape,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange()) Standard_OVERRIDE;
|
||||
|
||||
public:
|
||||
//! Gets CAD format name of associated provider
|
||||
//! @return provider CAD format
|
||||
|
559
src/DataExchange/TKDESTL/GTests/DESTL_Provider_Test.cxx
Normal file
559
src/DataExchange/TKDESTL/GTests/DESTL_Provider_Test.cxx
Normal file
@@ -0,0 +1,559 @@
|
||||
// Copyright (c) 2025 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 <DESTL_Provider.hxx>
|
||||
#include <DESTL_ConfigurationNode.hxx>
|
||||
#include <DE_Wrapper.hxx>
|
||||
|
||||
#include <BRepPrimAPI_MakeBox.hxx>
|
||||
#include <BRepPrimAPI_MakeSphere.hxx>
|
||||
#include <BRepBuilderAPI_MakeFace.hxx>
|
||||
#include <BRep_Builder.hxx>
|
||||
#include <TopoDS_Shape.hxx>
|
||||
#include <TopoDS_Face.hxx>
|
||||
#include <TopExp_Explorer.hxx>
|
||||
#include <TopAbs_ShapeEnum.hxx>
|
||||
#include <gp_Pnt.hxx>
|
||||
#include <gp_Pln.hxx>
|
||||
#include <gp_Dir.hxx>
|
||||
#include <Poly_Triangulation.hxx>
|
||||
#include <Poly_Triangle.hxx>
|
||||
#include <TColgp_Array1OfPnt.hxx>
|
||||
#include <Poly_Array1OfTriangle.hxx>
|
||||
#include <BRep_Tool.hxx>
|
||||
#include <TopLoc_Location.hxx>
|
||||
#include <TDocStd_Document.hxx>
|
||||
#include <TDocStd_Application.hxx>
|
||||
#include <XCAFDoc_DocumentTool.hxx>
|
||||
#include <XCAFDoc_ShapeTool.hxx>
|
||||
|
||||
#include <sstream>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
class DESTL_ProviderTest : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
void SetUp() override
|
||||
{
|
||||
// Initialize provider with default configuration
|
||||
Handle(DESTL_ConfigurationNode) aNode = new DESTL_ConfigurationNode();
|
||||
myProvider = new DESTL_Provider(aNode);
|
||||
|
||||
// Create triangulated shape for testing (STL format requires triangulated data)
|
||||
|
||||
myTriangularFace = CreateTriangulatedFace();
|
||||
|
||||
// Create test document
|
||||
Handle(TDocStd_Application) anApp = new TDocStd_Application();
|
||||
anApp->NewDocument("BinXCAF", myDocument);
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
myProvider.Nullify();
|
||||
myDocument.Nullify();
|
||||
}
|
||||
|
||||
// Helper method to count shape elements
|
||||
Standard_Integer CountShapeElements(const TopoDS_Shape& theShape, TopAbs_ShapeEnum theType)
|
||||
{
|
||||
Standard_Integer aCount = 0;
|
||||
for (TopExp_Explorer anExplorer(theShape, theType); anExplorer.More(); anExplorer.Next())
|
||||
{
|
||||
aCount++;
|
||||
}
|
||||
return aCount;
|
||||
}
|
||||
|
||||
// Helper method to create a triangulated face with mesh data (suitable for STL)
|
||||
TopoDS_Shape CreateTriangulatedFace()
|
||||
{
|
||||
// Create vertices for triangulation
|
||||
TColgp_Array1OfPnt aNodes(1, 4);
|
||||
aNodes.SetValue(1, gp_Pnt(0.0, 0.0, 0.0)); // Bottom-left
|
||||
aNodes.SetValue(2, gp_Pnt(10.0, 0.0, 0.0)); // Bottom-right
|
||||
aNodes.SetValue(3, gp_Pnt(10.0, 10.0, 0.0)); // Top-right
|
||||
aNodes.SetValue(4, gp_Pnt(0.0, 10.0, 0.0)); // Top-left
|
||||
|
||||
// Create triangles (two triangles forming a quad)
|
||||
Poly_Array1OfTriangle aTriangles(1, 2);
|
||||
aTriangles.SetValue(1, Poly_Triangle(1, 2, 3)); // First triangle
|
||||
aTriangles.SetValue(2, Poly_Triangle(1, 3, 4)); // Second triangle
|
||||
|
||||
// Create triangulation
|
||||
Handle(Poly_Triangulation) aTriangulation = new Poly_Triangulation(aNodes, aTriangles);
|
||||
|
||||
// Create a simple planar face
|
||||
gp_Pln aPlane(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(0, 0, 1));
|
||||
BRepBuilderAPI_MakeFace aFaceBuilder(aPlane, 0.0, 10.0, 0.0, 10.0);
|
||||
|
||||
if (!aFaceBuilder.IsDone())
|
||||
{
|
||||
return TopoDS_Shape();
|
||||
}
|
||||
|
||||
TopoDS_Face aFace = aFaceBuilder.Face();
|
||||
|
||||
// Attach triangulation to the face
|
||||
BRep_Builder aBuilder;
|
||||
aBuilder.UpdateFace(aFace, aTriangulation);
|
||||
|
||||
return aFace;
|
||||
}
|
||||
|
||||
protected:
|
||||
Handle(DESTL_Provider) myProvider;
|
||||
TopoDS_Shape myTriangularFace;
|
||||
Handle(TDocStd_Document) myDocument;
|
||||
};
|
||||
|
||||
// Test basic provider creation and format/vendor information
|
||||
TEST_F(DESTL_ProviderTest, BasicProperties)
|
||||
{
|
||||
EXPECT_STREQ("STL", myProvider->GetFormat().ToCString());
|
||||
EXPECT_STREQ("OCC", myProvider->GetVendor().ToCString());
|
||||
EXPECT_FALSE(myProvider->GetNode().IsNull());
|
||||
}
|
||||
|
||||
// Test stream-based shape write and read operations
|
||||
TEST_F(DESTL_ProviderTest, StreamShapeWriteRead)
|
||||
{
|
||||
std::ostringstream anOStream;
|
||||
DE_Provider::WriteStreamList aWriteStreams;
|
||||
aWriteStreams.Append(DE_Provider::WriteStreamNode("test.stl", anOStream));
|
||||
|
||||
// Write triangulated face to stream (STL works with mesh data)
|
||||
EXPECT_TRUE(myProvider->Write(aWriteStreams, myTriangularFace));
|
||||
|
||||
std::string aStlContent = anOStream.str();
|
||||
EXPECT_FALSE(aStlContent.empty());
|
||||
EXPECT_TRUE(aStlContent.find("solid") != std::string::npos
|
||||
|| aStlContent.find("facet") != std::string::npos);
|
||||
|
||||
if (!aStlContent.empty())
|
||||
{
|
||||
// Read back from stream
|
||||
std::istringstream anIStream(aStlContent);
|
||||
DE_Provider::ReadStreamList aReadStreams;
|
||||
aReadStreams.Append(DE_Provider::ReadStreamNode("test.stl", anIStream));
|
||||
|
||||
TopoDS_Shape aReadShape;
|
||||
EXPECT_TRUE(myProvider->Read(aReadStreams, aReadShape));
|
||||
EXPECT_FALSE(aReadShape.IsNull());
|
||||
|
||||
if (!aReadShape.IsNull())
|
||||
{
|
||||
// STL should produce faces with triangulation
|
||||
Standard_Integer aReadFaces = CountShapeElements(aReadShape, TopAbs_FACE);
|
||||
EXPECT_GT(aReadFaces, 0); // Should have faces
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test stream-based document write and read operations
|
||||
TEST_F(DESTL_ProviderTest, StreamDocumentWriteRead)
|
||||
{
|
||||
// Add triangulated shape to document
|
||||
Handle(XCAFDoc_ShapeTool) aShapeTool = XCAFDoc_DocumentTool::ShapeTool(myDocument->Main());
|
||||
TDF_Label aShapeLabel = aShapeTool->AddShape(myTriangularFace);
|
||||
EXPECT_FALSE(aShapeLabel.IsNull());
|
||||
|
||||
std::ostringstream anOStream;
|
||||
DE_Provider::WriteStreamList aWriteStreams;
|
||||
aWriteStreams.Append(DE_Provider::WriteStreamNode("document.stl", anOStream));
|
||||
|
||||
// Write document to stream
|
||||
EXPECT_TRUE(myProvider->Write(aWriteStreams, myDocument));
|
||||
|
||||
std::string aStlContent = anOStream.str();
|
||||
EXPECT_FALSE(aStlContent.empty());
|
||||
|
||||
if (!aStlContent.empty())
|
||||
{
|
||||
// Create new document for reading
|
||||
Handle(TDocStd_Application) anApp = new TDocStd_Application();
|
||||
Handle(TDocStd_Document) aNewDocument;
|
||||
anApp->NewDocument("BinXCAF", aNewDocument);
|
||||
|
||||
// Read back from stream
|
||||
std::istringstream anIStream(aStlContent);
|
||||
DE_Provider::ReadStreamList aReadStreams;
|
||||
aReadStreams.Append(DE_Provider::ReadStreamNode("document.stl", anIStream));
|
||||
|
||||
EXPECT_TRUE(myProvider->Read(aReadStreams, aNewDocument));
|
||||
|
||||
// Validate document content
|
||||
Handle(XCAFDoc_ShapeTool) aNewShapeTool = XCAFDoc_DocumentTool::ShapeTool(aNewDocument->Main());
|
||||
TDF_LabelSequence aLabels;
|
||||
aNewShapeTool->GetShapes(aLabels);
|
||||
EXPECT_GT(aLabels.Length(), 0); // Should have at least one shape in document
|
||||
}
|
||||
}
|
||||
|
||||
// Test DE_Wrapper integration for STL operations
|
||||
TEST_F(DESTL_ProviderTest, DE_WrapperIntegration)
|
||||
{
|
||||
// Initialize DE_Wrapper and bind STL provider
|
||||
DE_Wrapper aWrapper;
|
||||
Handle(DESTL_ConfigurationNode) aNode = new DESTL_ConfigurationNode();
|
||||
|
||||
// Bind the configured node to wrapper
|
||||
EXPECT_TRUE(aWrapper.Bind(aNode));
|
||||
|
||||
// Test write with DE_Wrapper using triangular face
|
||||
std::ostringstream anOStream;
|
||||
DE_Provider::WriteStreamList aWriteStreams;
|
||||
aWriteStreams.Append(DE_Provider::WriteStreamNode("test.stl", anOStream));
|
||||
|
||||
EXPECT_TRUE(aWrapper.Write(aWriteStreams, myTriangularFace));
|
||||
|
||||
std::string aStlContent = anOStream.str();
|
||||
EXPECT_FALSE(aStlContent.empty());
|
||||
|
||||
if (!aStlContent.empty())
|
||||
{
|
||||
// Test DE_Wrapper stream operations
|
||||
std::istringstream anIStream(aStlContent);
|
||||
DE_Provider::ReadStreamList aReadStreams;
|
||||
aReadStreams.Append(DE_Provider::ReadStreamNode("test.stl", anIStream));
|
||||
|
||||
TopoDS_Shape aReadShape;
|
||||
bool aWrapperResult = aWrapper.Read(aReadStreams, aReadShape);
|
||||
|
||||
// Test direct provider with same content for comparison
|
||||
std::istringstream anIStream2(aStlContent);
|
||||
DE_Provider::ReadStreamList aReadStreams2;
|
||||
aReadStreams2.Append(DE_Provider::ReadStreamNode("test.stl", anIStream2));
|
||||
|
||||
Handle(DESTL_Provider) aDirectProvider = new DESTL_Provider(aNode);
|
||||
TopoDS_Shape aDirectShape;
|
||||
bool aDirectResult = aDirectProvider->Read(aReadStreams2, aDirectShape);
|
||||
|
||||
// REQUIREMENT: DE_Wrapper must work exactly the same as direct provider
|
||||
EXPECT_EQ(aWrapperResult, aDirectResult);
|
||||
EXPECT_EQ(aReadShape.IsNull(), aDirectShape.IsNull());
|
||||
|
||||
if (aDirectResult && !aDirectShape.IsNull())
|
||||
{
|
||||
Standard_Integer aFaces = CountShapeElements(aDirectShape, TopAbs_FACE);
|
||||
EXPECT_GT(aFaces, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test error conditions and edge cases with null document validation
|
||||
TEST_F(DESTL_ProviderTest, ErrorHandling)
|
||||
{
|
||||
// Test with empty streams
|
||||
DE_Provider::WriteStreamList anEmptyWriteStreams;
|
||||
EXPECT_FALSE(myProvider->Write(anEmptyWriteStreams, myTriangularFace));
|
||||
|
||||
DE_Provider::ReadStreamList anEmptyReadStreams;
|
||||
TopoDS_Shape aShape;
|
||||
EXPECT_FALSE(myProvider->Read(anEmptyReadStreams, aShape));
|
||||
|
||||
// Test with null shape
|
||||
std::ostringstream anOStream;
|
||||
DE_Provider::WriteStreamList aWriteStreams;
|
||||
aWriteStreams.Append(DE_Provider::WriteStreamNode("null_test.stl", anOStream));
|
||||
TopoDS_Shape aNullShape;
|
||||
|
||||
// Writing null shape should succeed but produce minimal content
|
||||
myProvider->Write(aWriteStreams, aNullShape);
|
||||
std::string aContent = anOStream.str();
|
||||
// STL may produce empty content for null shape
|
||||
|
||||
// Test reading invalid STL content
|
||||
std::string anInvalidContent = "This is not valid STL content";
|
||||
std::istringstream anInvalidStream(anInvalidContent);
|
||||
DE_Provider::ReadStreamList anInvalidReadStreams;
|
||||
anInvalidReadStreams.Append(DE_Provider::ReadStreamNode("invalid.stl", anInvalidStream));
|
||||
|
||||
TopoDS_Shape anInvalidShape;
|
||||
EXPECT_FALSE(myProvider->Read(anInvalidReadStreams, anInvalidShape));
|
||||
|
||||
// Test with null document
|
||||
Handle(TDocStd_Document) aNullDoc;
|
||||
EXPECT_FALSE(myProvider->Write(aWriteStreams, aNullDoc));
|
||||
EXPECT_FALSE(myProvider->Read(anEmptyReadStreams, aNullDoc));
|
||||
}
|
||||
|
||||
// Test DESTL configuration modes
|
||||
TEST_F(DESTL_ProviderTest, ConfigurationModes)
|
||||
{
|
||||
Handle(DESTL_ConfigurationNode) aNode =
|
||||
Handle(DESTL_ConfigurationNode)::DownCast(myProvider->GetNode());
|
||||
|
||||
// Test ASCII mode configuration
|
||||
aNode->InternalParameters.WriteAscii = Standard_True;
|
||||
EXPECT_TRUE(aNode->InternalParameters.WriteAscii);
|
||||
|
||||
// Test Binary mode configuration
|
||||
aNode->InternalParameters.WriteAscii = Standard_False;
|
||||
EXPECT_FALSE(aNode->InternalParameters.WriteAscii);
|
||||
|
||||
// Test merge angle configuration
|
||||
aNode->InternalParameters.ReadMergeAngle = 45.0;
|
||||
EXPECT_DOUBLE_EQ(45.0, aNode->InternalParameters.ReadMergeAngle);
|
||||
|
||||
// Test that provider format and vendor are correct
|
||||
EXPECT_STREQ("STL", myProvider->GetFormat().ToCString());
|
||||
EXPECT_STREQ("OCC", myProvider->GetVendor().ToCString());
|
||||
}
|
||||
|
||||
// Test ASCII vs Binary mode configurations
|
||||
TEST_F(DESTL_ProviderTest, AsciiVsBinaryModes)
|
||||
{
|
||||
Handle(DESTL_ConfigurationNode) aNode =
|
||||
Handle(DESTL_ConfigurationNode)::DownCast(myProvider->GetNode());
|
||||
|
||||
// Test ASCII mode
|
||||
aNode->InternalParameters.WriteAscii = Standard_True;
|
||||
|
||||
std::ostringstream anAsciiStream;
|
||||
DE_Provider::WriteStreamList anAsciiWriteStreams;
|
||||
anAsciiWriteStreams.Append(DE_Provider::WriteStreamNode("ascii_test.stl", anAsciiStream));
|
||||
|
||||
EXPECT_TRUE(myProvider->Write(anAsciiWriteStreams, myTriangularFace));
|
||||
std::string anAsciiContent = anAsciiStream.str();
|
||||
EXPECT_FALSE(anAsciiContent.empty());
|
||||
EXPECT_TRUE(anAsciiContent.find("solid") != std::string::npos);
|
||||
|
||||
// Test Binary mode
|
||||
aNode->InternalParameters.WriteAscii = Standard_False;
|
||||
|
||||
std::ostringstream aBinaryStream;
|
||||
DE_Provider::WriteStreamList aBinaryWriteStreams;
|
||||
aBinaryWriteStreams.Append(DE_Provider::WriteStreamNode("binary_test.stl", aBinaryStream));
|
||||
|
||||
EXPECT_TRUE(myProvider->Write(aBinaryWriteStreams, myTriangularFace));
|
||||
std::string aBinaryContent = aBinaryStream.str();
|
||||
EXPECT_FALSE(aBinaryContent.empty());
|
||||
|
||||
// Binary and ASCII content should be different
|
||||
EXPECT_NE(anAsciiContent, aBinaryContent);
|
||||
}
|
||||
|
||||
// Test multiple shapes in single document
|
||||
TEST_F(DESTL_ProviderTest, MultipleShapesInDocument)
|
||||
{
|
||||
// Add triangulated face to document multiple times (to create multiple shapes)
|
||||
Handle(XCAFDoc_ShapeTool) aShapeTool = XCAFDoc_DocumentTool::ShapeTool(myDocument->Main());
|
||||
TDF_Label aFaceLabel1 = aShapeTool->AddShape(myTriangularFace);
|
||||
TDF_Label aFaceLabel2 = aShapeTool->AddShape(myTriangularFace); // Add same face again
|
||||
|
||||
EXPECT_FALSE(aFaceLabel1.IsNull());
|
||||
EXPECT_FALSE(aFaceLabel2.IsNull());
|
||||
|
||||
std::ostringstream anOStream;
|
||||
DE_Provider::WriteStreamList aWriteStreams;
|
||||
aWriteStreams.Append(DE_Provider::WriteStreamNode("multi_shapes.stl", anOStream));
|
||||
|
||||
// Write document with multiple shapes
|
||||
EXPECT_TRUE(myProvider->Write(aWriteStreams, myDocument));
|
||||
|
||||
std::string aStlContent = anOStream.str();
|
||||
EXPECT_FALSE(aStlContent.empty());
|
||||
|
||||
// Read back into new document
|
||||
Handle(TDocStd_Application) anApp = new TDocStd_Application();
|
||||
Handle(TDocStd_Document) aNewDocument;
|
||||
anApp->NewDocument("BinXCAF", aNewDocument);
|
||||
|
||||
std::istringstream anIStream(aStlContent);
|
||||
DE_Provider::ReadStreamList aReadStreams;
|
||||
aReadStreams.Append(DE_Provider::ReadStreamNode("multi_shapes.stl", anIStream));
|
||||
|
||||
EXPECT_TRUE(myProvider->Read(aReadStreams, aNewDocument));
|
||||
|
||||
// Validate document content
|
||||
Handle(XCAFDoc_ShapeTool) aNewShapeTool = XCAFDoc_DocumentTool::ShapeTool(aNewDocument->Main());
|
||||
TDF_LabelSequence aLabels;
|
||||
aNewShapeTool->GetShapes(aLabels);
|
||||
EXPECT_GT(aLabels.Length(), 0);
|
||||
}
|
||||
|
||||
// Test triangulated face handling (suitable for STL)
|
||||
TEST_F(DESTL_ProviderTest, TriangulatedFaceHandling)
|
||||
{
|
||||
// Use our triangulated face which already has mesh data
|
||||
std::ostringstream anOStream;
|
||||
DE_Provider::WriteStreamList aWriteStreams;
|
||||
aWriteStreams.Append(DE_Provider::WriteStreamNode("triangulated_face.stl", anOStream));
|
||||
|
||||
EXPECT_TRUE(myProvider->Write(aWriteStreams, myTriangularFace));
|
||||
|
||||
std::string aStlContent = anOStream.str();
|
||||
EXPECT_FALSE(aStlContent.empty());
|
||||
EXPECT_GT(aStlContent.size(), 100); // Should have meaningful content
|
||||
|
||||
// Read back
|
||||
std::istringstream anIStream(aStlContent);
|
||||
DE_Provider::ReadStreamList aReadStreams;
|
||||
aReadStreams.Append(DE_Provider::ReadStreamNode("triangulated_face.stl", anIStream));
|
||||
|
||||
TopoDS_Shape aReadShape;
|
||||
EXPECT_TRUE(myProvider->Read(aReadStreams, aReadShape));
|
||||
EXPECT_FALSE(aReadShape.IsNull());
|
||||
}
|
||||
|
||||
// Test DE_Wrapper with different file extensions
|
||||
TEST_F(DESTL_ProviderTest, DE_WrapperFileExtensions)
|
||||
{
|
||||
DE_Wrapper aWrapper;
|
||||
Handle(DESTL_ConfigurationNode) aNode = new DESTL_ConfigurationNode();
|
||||
EXPECT_TRUE(aWrapper.Bind(aNode));
|
||||
|
||||
// Test different STL extensions
|
||||
std::vector<std::string> aExtensions = {"test.stl", "test.STL", "mesh.stl"};
|
||||
|
||||
for (const auto& anExt : aExtensions)
|
||||
{
|
||||
std::ostringstream anOStream;
|
||||
DE_Provider::WriteStreamList aWriteStreams;
|
||||
aWriteStreams.Append(DE_Provider::WriteStreamNode(anExt.c_str(), anOStream));
|
||||
|
||||
EXPECT_TRUE(aWrapper.Write(aWriteStreams, myTriangularFace))
|
||||
<< "Failed to write with extension: " << anExt;
|
||||
|
||||
std::string aContent = anOStream.str();
|
||||
EXPECT_FALSE(aContent.empty()) << "Empty content for extension: " << anExt;
|
||||
|
||||
// Test read back
|
||||
std::istringstream anIStream(aContent);
|
||||
DE_Provider::ReadStreamList aReadStreams;
|
||||
aReadStreams.Append(DE_Provider::ReadStreamNode(anExt.c_str(), anIStream));
|
||||
|
||||
TopoDS_Shape aReadShape;
|
||||
EXPECT_TRUE(aWrapper.Read(aReadStreams, aReadShape))
|
||||
<< "Failed to read with extension: " << anExt;
|
||||
EXPECT_FALSE(aReadShape.IsNull()) << "Null shape read with extension: " << anExt;
|
||||
}
|
||||
}
|
||||
|
||||
// Test stream operations with empty and invalid data
|
||||
TEST_F(DESTL_ProviderTest, StreamErrorConditions)
|
||||
{
|
||||
// Test empty stream list
|
||||
DE_Provider::WriteStreamList anEmptyWriteStreams;
|
||||
EXPECT_FALSE(myProvider->Write(anEmptyWriteStreams, myTriangularFace));
|
||||
|
||||
DE_Provider::ReadStreamList anEmptyReadStreams;
|
||||
TopoDS_Shape aShape;
|
||||
EXPECT_FALSE(myProvider->Read(anEmptyReadStreams, aShape));
|
||||
|
||||
// Test corrupted STL data
|
||||
std::string aCorruptedData = "This is not STL data at all";
|
||||
std::istringstream aCorruptedStream(aCorruptedData);
|
||||
DE_Provider::ReadStreamList aCorruptedReadStreams;
|
||||
aCorruptedReadStreams.Append(DE_Provider::ReadStreamNode("corrupted.stl", aCorruptedStream));
|
||||
|
||||
TopoDS_Shape aCorruptedShape;
|
||||
EXPECT_FALSE(myProvider->Read(aCorruptedReadStreams, aCorruptedShape));
|
||||
|
||||
// Test partial STL data
|
||||
std::string aPartialData = "solid test\n facet normal 0 0 1\n"; // Incomplete
|
||||
std::istringstream aPartialStream(aPartialData);
|
||||
DE_Provider::ReadStreamList aPartialReadStreams;
|
||||
aPartialReadStreams.Append(DE_Provider::ReadStreamNode("partial.stl", aPartialStream));
|
||||
|
||||
TopoDS_Shape aPartialShape;
|
||||
EXPECT_FALSE(myProvider->Read(aPartialReadStreams, aPartialShape));
|
||||
}
|
||||
|
||||
// Test configuration parameter validation
|
||||
TEST_F(DESTL_ProviderTest, ConfigurationParameterValidation)
|
||||
{
|
||||
Handle(DESTL_ConfigurationNode) aNode =
|
||||
Handle(DESTL_ConfigurationNode)::DownCast(myProvider->GetNode());
|
||||
|
||||
// Test valid merge angle
|
||||
aNode->InternalParameters.ReadMergeAngle = 30.0;
|
||||
EXPECT_DOUBLE_EQ(30.0, aNode->InternalParameters.ReadMergeAngle);
|
||||
|
||||
// Test edge case merge angles
|
||||
aNode->InternalParameters.ReadMergeAngle = 0.0; // Minimum
|
||||
EXPECT_DOUBLE_EQ(0.0, aNode->InternalParameters.ReadMergeAngle);
|
||||
|
||||
aNode->InternalParameters.ReadMergeAngle = 90.0; // Maximum
|
||||
EXPECT_DOUBLE_EQ(90.0, aNode->InternalParameters.ReadMergeAngle);
|
||||
|
||||
// Test BRep vs triangulation modes
|
||||
aNode->InternalParameters.ReadBRep = Standard_True;
|
||||
EXPECT_TRUE(aNode->InternalParameters.ReadBRep);
|
||||
|
||||
aNode->InternalParameters.ReadBRep = Standard_False;
|
||||
EXPECT_FALSE(aNode->InternalParameters.ReadBRep);
|
||||
}
|
||||
|
||||
// Test multiple triangulated faces
|
||||
TEST_F(DESTL_ProviderTest, MultipleTriangulatedFaces)
|
||||
{
|
||||
// Create another triangulated face with different geometry
|
||||
TColgp_Array1OfPnt aNodes(1, 3);
|
||||
aNodes.SetValue(1, gp_Pnt(0.0, 0.0, 0.0));
|
||||
aNodes.SetValue(2, gp_Pnt(5.0, 0.0, 0.0));
|
||||
aNodes.SetValue(3, gp_Pnt(2.5, 5.0, 0.0));
|
||||
|
||||
Poly_Array1OfTriangle aTriangles(1, 1);
|
||||
aTriangles.SetValue(1, Poly_Triangle(1, 2, 3));
|
||||
|
||||
Handle(Poly_Triangulation) aTriangulation = new Poly_Triangulation(aNodes, aTriangles);
|
||||
|
||||
gp_Pln aPlane(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(0, 0, 1));
|
||||
BRepBuilderAPI_MakeFace aFaceBuilder(aPlane, 0.0, 5.0, 0.0, 5.0);
|
||||
TopoDS_Face aTriangleFace = aFaceBuilder.Face();
|
||||
|
||||
BRep_Builder aBuilder;
|
||||
aBuilder.UpdateFace(aTriangleFace, aTriangulation);
|
||||
|
||||
// Test first triangulated face
|
||||
std::ostringstream aStream1;
|
||||
DE_Provider::WriteStreamList aWriteStreams1;
|
||||
aWriteStreams1.Append(DE_Provider::WriteStreamNode("face1.stl", aStream1));
|
||||
|
||||
EXPECT_TRUE(myProvider->Write(aWriteStreams1, myTriangularFace));
|
||||
std::string aContent1 = aStream1.str();
|
||||
|
||||
// Test second triangulated face
|
||||
std::ostringstream aStream2;
|
||||
DE_Provider::WriteStreamList aWriteStreams2;
|
||||
aWriteStreams2.Append(DE_Provider::WriteStreamNode("face2.stl", aStream2));
|
||||
|
||||
EXPECT_TRUE(myProvider->Write(aWriteStreams2, aTriangleFace));
|
||||
std::string aContent2 = aStream2.str();
|
||||
|
||||
// Both content should be non-empty
|
||||
EXPECT_FALSE(aContent1.empty());
|
||||
EXPECT_FALSE(aContent2.empty());
|
||||
|
||||
// Different triangulated faces should produce different STL content
|
||||
EXPECT_NE(aContent1, aContent2);
|
||||
|
||||
// Both should read back successfully
|
||||
std::istringstream aIStream1(aContent1);
|
||||
DE_Provider::ReadStreamList aReadStreams1;
|
||||
aReadStreams1.Append(DE_Provider::ReadStreamNode("face1.stl", aIStream1));
|
||||
|
||||
TopoDS_Shape aReadShape1;
|
||||
EXPECT_TRUE(myProvider->Read(aReadStreams1, aReadShape1));
|
||||
EXPECT_FALSE(aReadShape1.IsNull());
|
||||
|
||||
std::istringstream aIStream2(aContent2);
|
||||
DE_Provider::ReadStreamList aReadStreams2;
|
||||
aReadStreams2.Append(DE_Provider::ReadStreamNode("face2.stl", aIStream2));
|
||||
|
||||
TopoDS_Shape aReadShape2;
|
||||
EXPECT_TRUE(myProvider->Read(aReadStreams2, aReadShape2));
|
||||
EXPECT_FALSE(aReadShape2.IsNull());
|
||||
}
|
@@ -2,4 +2,5 @@
|
||||
set(OCCT_TKDESTL_GTests_FILES_LOCATION "${CMAKE_CURRENT_LIST_DIR}")
|
||||
|
||||
set(OCCT_TKDESTL_GTests_FILES
|
||||
DESTL_Provider_Test.cxx
|
||||
)
|
||||
|
@@ -21,6 +21,10 @@
|
||||
#include <OSD_FileSystem.hxx>
|
||||
#include <OSD_OpenFile.hxx>
|
||||
#include <RWStl_Reader.hxx>
|
||||
#include <Standard_ReadLineBuffer.hxx>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
|
||||
namespace
|
||||
{
|
||||
@@ -254,16 +258,13 @@ Standard_Boolean RWStl::WriteBinary(const Handle(Poly_Triangulation)& theMesh,
|
||||
TCollection_AsciiString aPath;
|
||||
thePath.SystemName(aPath);
|
||||
|
||||
FILE* aFile = OSD_OpenFile(aPath, "wb");
|
||||
if (aFile == NULL)
|
||||
std::ofstream aStream(aPath.ToCString(), std::ios::binary);
|
||||
if (!aStream.is_open())
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
Standard_Boolean isOK = writeBinary(theMesh, aFile, theProgress);
|
||||
|
||||
fclose(aFile);
|
||||
return isOK;
|
||||
return WriteBinary(theMesh, aStream, theProgress);
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
@@ -280,45 +281,44 @@ Standard_Boolean RWStl::WriteAscii(const Handle(Poly_Triangulation)& theMesh,
|
||||
TCollection_AsciiString aPath;
|
||||
thePath.SystemName(aPath);
|
||||
|
||||
FILE* aFile = OSD_OpenFile(aPath, "w");
|
||||
if (aFile == NULL)
|
||||
std::ofstream aStream(aPath.ToCString());
|
||||
if (!aStream.is_open())
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
Standard_Boolean isOK = writeASCII(theMesh, aFile, theProgress);
|
||||
fclose(aFile);
|
||||
return isOK;
|
||||
return WriteAscii(theMesh, aStream, theProgress);
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean RWStl::writeASCII(const Handle(Poly_Triangulation)& theMesh,
|
||||
FILE* theFile,
|
||||
Standard_Boolean RWStl::WriteAscii(const Handle(Poly_Triangulation)& theMesh,
|
||||
Standard_OStream& theStream,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
// note that space after 'solid' is necessary for many systems
|
||||
if (fwrite("solid \n", 1, 7, theFile) != 7)
|
||||
if (theMesh.IsNull() || theMesh->NbTriangles() <= 0)
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
char aBuffer[512];
|
||||
memset(aBuffer, 0, sizeof(aBuffer));
|
||||
// note that space after 'solid' is necessary for many systems
|
||||
theStream << "solid \n";
|
||||
if (theStream.fail())
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
const Standard_Integer NBTriangles = theMesh->NbTriangles();
|
||||
Message_ProgressScope aPS(theProgress, "Triangles", NBTriangles);
|
||||
Standard_Integer anElem[3] = {0, 0, 0};
|
||||
|
||||
Standard_Integer anElem[3] = {0, 0, 0};
|
||||
for (Standard_Integer aTriIter = 1; aTriIter <= NBTriangles; ++aTriIter)
|
||||
{
|
||||
const Poly_Triangle aTriangle = theMesh->Triangle(aTriIter);
|
||||
aTriangle.Get(anElem[0], anElem[1], anElem[2]);
|
||||
|
||||
const gp_Pnt aP1 = theMesh->Node(anElem[0]);
|
||||
const gp_Pnt aP2 = theMesh->Node(anElem[1]);
|
||||
const gp_Pnt aP3 = theMesh->Node(anElem[2]);
|
||||
|
||||
const gp_Vec aVec1(aP1, aP2);
|
||||
const gp_Vec aVec2(aP1, aP3);
|
||||
gp_Vec aVNorm = aVec1.Crossed(aVec2);
|
||||
@@ -331,28 +331,16 @@ Standard_Boolean RWStl::writeASCII(const Handle(Poly_Triangulation)& theMesh,
|
||||
aVNorm.SetCoord(0.0, 0.0, 0.0);
|
||||
}
|
||||
|
||||
Sprintf(aBuffer,
|
||||
" facet normal % 12e % 12e % 12e\n"
|
||||
" outer loop\n"
|
||||
" vertex % 12e % 12e % 12e\n"
|
||||
" vertex % 12e % 12e % 12e\n"
|
||||
" vertex % 12e % 12e % 12e\n"
|
||||
" endloop\n"
|
||||
" endfacet\n",
|
||||
aVNorm.X(),
|
||||
aVNorm.Y(),
|
||||
aVNorm.Z(),
|
||||
aP1.X(),
|
||||
aP1.Y(),
|
||||
aP1.Z(),
|
||||
aP2.X(),
|
||||
aP2.Y(),
|
||||
aP2.Z(),
|
||||
aP3.X(),
|
||||
aP3.Y(),
|
||||
aP3.Z());
|
||||
theStream << " facet normal " << std::scientific << std::setprecision(12) << aVNorm.X() << " "
|
||||
<< aVNorm.Y() << " " << aVNorm.Z() << "\n"
|
||||
<< " outer loop\n"
|
||||
<< " vertex " << aP1.X() << " " << aP1.Y() << " " << aP1.Z() << "\n"
|
||||
<< " vertex " << aP2.X() << " " << aP2.Y() << " " << aP2.Z() << "\n"
|
||||
<< " vertex " << aP3.X() << " " << aP3.Y() << " " << aP3.Z() << "\n"
|
||||
<< " endloop\n"
|
||||
<< " endfacet\n";
|
||||
|
||||
if (fprintf(theFile, "%s", aBuffer) < 0)
|
||||
if (theStream.fail())
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
@@ -366,37 +354,38 @@ Standard_Boolean RWStl::writeASCII(const Handle(Poly_Triangulation)& theMesh,
|
||||
}
|
||||
}
|
||||
|
||||
if (fwrite("endsolid\n", 1, 9, theFile) != 9)
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
return Standard_True;
|
||||
theStream << "endsolid\n";
|
||||
return !theStream.fail();
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean RWStl::writeBinary(const Handle(Poly_Triangulation)& theMesh,
|
||||
FILE* theFile,
|
||||
Standard_Boolean RWStl::WriteBinary(const Handle(Poly_Triangulation)& theMesh,
|
||||
Standard_OStream& theStream,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
char aHeader[80] = "STL Exported by Open CASCADE Technology [dev.opencascade.org]";
|
||||
if (fwrite(aHeader, 1, 80, theFile) != 80)
|
||||
if (theMesh.IsNull() || theMesh->NbTriangles() <= 0)
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
const Standard_Integer aNBTriangles = theMesh->NbTriangles();
|
||||
Message_ProgressScope aPS(theProgress, "Triangles", aNBTriangles);
|
||||
char aHeader[80] = "STL Exported by Open CASCADE Technology [dev.opencascade.org]";
|
||||
theStream.write(aHeader, 80);
|
||||
if (theStream.fail())
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
const Standard_Integer aNBTriangles = theMesh->NbTriangles();
|
||||
Message_ProgressScope aPS(theProgress, "Triangles", aNBTriangles);
|
||||
const Standard_Size aNbChunkTriangles = 4096;
|
||||
const Standard_Size aChunkSize = aNbChunkTriangles * THE_STL_SIZEOF_FACET;
|
||||
NCollection_Array1<Standard_Character> aData(1, aChunkSize);
|
||||
Standard_Character* aDataChunk = &aData.ChangeFirst();
|
||||
|
||||
Standard_Character aConv[4];
|
||||
Standard_Character aConv[4];
|
||||
convertInteger(aNBTriangles, aConv);
|
||||
if (fwrite(aConv, 1, 4, theFile) != 4)
|
||||
theStream.write(aConv, 4);
|
||||
if (theStream.fail())
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
@@ -407,14 +396,12 @@ Standard_Boolean RWStl::writeBinary(const Handle(Poly_Triangulation)& theMesh,
|
||||
Standard_Integer id[3];
|
||||
const Poly_Triangle aTriangle = theMesh->Triangle(aTriIter);
|
||||
aTriangle.Get(id[0], id[1], id[2]);
|
||||
|
||||
const gp_Pnt aP1 = theMesh->Node(id[0]);
|
||||
const gp_Pnt aP2 = theMesh->Node(id[1]);
|
||||
const gp_Pnt aP3 = theMesh->Node(id[2]);
|
||||
|
||||
gp_Vec aVec1(aP1, aP2);
|
||||
gp_Vec aVec2(aP1, aP3);
|
||||
gp_Vec aVNorm = aVec1.Crossed(aVec2);
|
||||
gp_Vec aVec1(aP1, aP2);
|
||||
gp_Vec aVec2(aP1, aP3);
|
||||
gp_Vec aVNorm = aVec1.Crossed(aVec2);
|
||||
if (aVNorm.SquareMagnitude() > gp::Resolution())
|
||||
{
|
||||
aVNorm.Normalize();
|
||||
@@ -423,48 +410,42 @@ Standard_Boolean RWStl::writeBinary(const Handle(Poly_Triangulation)& theMesh,
|
||||
{
|
||||
aVNorm.SetCoord(0.0, 0.0, 0.0);
|
||||
}
|
||||
|
||||
convertDouble(aVNorm.X(), &aDataChunk[aByteCount]);
|
||||
aByteCount += 4;
|
||||
convertDouble(aVNorm.Y(), &aDataChunk[aByteCount]);
|
||||
aByteCount += 4;
|
||||
convertDouble(aVNorm.Z(), &aDataChunk[aByteCount]);
|
||||
aByteCount += 4;
|
||||
|
||||
convertDouble(aP1.X(), &aDataChunk[aByteCount]);
|
||||
aByteCount += 4;
|
||||
convertDouble(aP1.Y(), &aDataChunk[aByteCount]);
|
||||
aByteCount += 4;
|
||||
convertDouble(aP1.Z(), &aDataChunk[aByteCount]);
|
||||
aByteCount += 4;
|
||||
|
||||
convertDouble(aP2.X(), &aDataChunk[aByteCount]);
|
||||
aByteCount += 4;
|
||||
convertDouble(aP2.Y(), &aDataChunk[aByteCount]);
|
||||
aByteCount += 4;
|
||||
convertDouble(aP2.Z(), &aDataChunk[aByteCount]);
|
||||
aByteCount += 4;
|
||||
|
||||
convertDouble(aP3.X(), &aDataChunk[aByteCount]);
|
||||
aByteCount += 4;
|
||||
convertDouble(aP3.Y(), &aDataChunk[aByteCount]);
|
||||
aByteCount += 4;
|
||||
convertDouble(aP3.Z(), &aDataChunk[aByteCount]);
|
||||
aByteCount += 4;
|
||||
aDataChunk[aByteCount] = 0;
|
||||
aDataChunk[aByteCount + 1] = 0;
|
||||
aByteCount += 2;
|
||||
|
||||
aDataChunk[aByteCount] = 0;
|
||||
aByteCount += 1;
|
||||
aDataChunk[aByteCount] = 0;
|
||||
aByteCount += 1;
|
||||
|
||||
// Chunk is filled. Dump it to the file.
|
||||
// Chunk is full, write it out.
|
||||
if (aByteCount == aChunkSize)
|
||||
{
|
||||
if (fwrite(aDataChunk, 1, aChunkSize, theFile) != aChunkSize)
|
||||
theStream.write(aDataChunk, aChunkSize);
|
||||
if (theStream.fail())
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
aByteCount = 0;
|
||||
}
|
||||
|
||||
@@ -480,7 +461,8 @@ Standard_Boolean RWStl::writeBinary(const Handle(Poly_Triangulation)& theMesh,
|
||||
// Write last part if necessary.
|
||||
if (aByteCount != aChunkSize)
|
||||
{
|
||||
if (fwrite(aDataChunk, 1, aByteCount, theFile) != aByteCount)
|
||||
theStream.write(aDataChunk, aByteCount);
|
||||
if (theStream.fail())
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
@@ -488,3 +470,66 @@ Standard_Boolean RWStl::writeBinary(const Handle(Poly_Triangulation)& theMesh,
|
||||
|
||||
return Standard_True;
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Handle(Poly_Triangulation) RWStl::ReadBinaryStream(Standard_IStream& theStream,
|
||||
const Standard_Real theMergeAngle,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
Reader aReader;
|
||||
aReader.SetMergeAngle(theMergeAngle);
|
||||
if (!aReader.ReadBinary(theStream, theProgress))
|
||||
{
|
||||
return Handle(Poly_Triangulation)();
|
||||
}
|
||||
return aReader.GetTriangulation();
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Handle(Poly_Triangulation) RWStl::ReadAsciiStream(Standard_IStream& theStream,
|
||||
const Standard_Real theMergeAngle,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
Reader aReader;
|
||||
aReader.SetMergeAngle(theMergeAngle);
|
||||
|
||||
// get length of stream to feed progress indicator
|
||||
theStream.seekg(0, theStream.end);
|
||||
std::streampos theEnd = theStream.tellg();
|
||||
theStream.seekg(0, theStream.beg);
|
||||
|
||||
Standard_ReadLineBuffer aBuffer(THE_BUFFER_SIZE);
|
||||
if (!aReader.ReadAscii(theStream, aBuffer, theEnd, theProgress))
|
||||
{
|
||||
return Handle(Poly_Triangulation)();
|
||||
}
|
||||
return aReader.GetTriangulation();
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Handle(Poly_Triangulation) RWStl::ReadStream(Standard_IStream& theStream,
|
||||
const Standard_Real theMergeAngle,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
// Try to detect ASCII vs Binary format by peeking at the first few bytes
|
||||
std::streampos anOriginalPos = theStream.tellg();
|
||||
constexpr std::streamsize aHeaderSize = 6;
|
||||
char aHeader[aHeaderSize];
|
||||
theStream.read(aHeader, aHeaderSize - 1);
|
||||
aHeader[aHeaderSize - 1] = '\0';
|
||||
theStream.seekg(anOriginalPos);
|
||||
|
||||
bool isAscii = (strncmp(aHeader, "solid", 5) == 0);
|
||||
|
||||
if (isAscii)
|
||||
{
|
||||
return RWStl::ReadAsciiStream(theStream, theMergeAngle, theProgress);
|
||||
}
|
||||
else
|
||||
{
|
||||
return RWStl::ReadBinaryStream(theStream, theMergeAngle, theProgress);
|
||||
}
|
||||
}
|
||||
|
@@ -34,6 +34,12 @@ public:
|
||||
const OSD_Path& thePath,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange());
|
||||
|
||||
//! Write triangulation to binary STL stream.
|
||||
Standard_EXPORT static Standard_Boolean WriteBinary(
|
||||
const Handle(Poly_Triangulation)& theMesh,
|
||||
Standard_OStream& theStream,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange());
|
||||
|
||||
//! write the meshing in a file following the
|
||||
//! Ascii format of an STL file.
|
||||
//! Returns false if the cannot be opened;
|
||||
@@ -42,6 +48,12 @@ public:
|
||||
const OSD_Path& thePath,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange());
|
||||
|
||||
//! Write triangulation to ASCII STL stream.
|
||||
Standard_EXPORT static Standard_Boolean WriteAscii(
|
||||
const Handle(Poly_Triangulation)& theMesh,
|
||||
Standard_OStream& theStream,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange());
|
||||
|
||||
//! Read specified STL file and returns its content as triangulation.
|
||||
//! In case of error, returns Null handle.
|
||||
Standard_EXPORT static Handle(Poly_Triangulation) ReadFile(
|
||||
@@ -92,16 +104,26 @@ public:
|
||||
const OSD_Path& thePath,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange());
|
||||
|
||||
private:
|
||||
//! Write ASCII version.
|
||||
static Standard_Boolean writeASCII(const Handle(Poly_Triangulation)& theMesh,
|
||||
FILE* theFile,
|
||||
const Message_ProgressRange& theProgress);
|
||||
//! Read triangulation from binary STL stream
|
||||
//! In case of error, returns Null handle.
|
||||
Standard_EXPORT static Handle(Poly_Triangulation) ReadBinaryStream(
|
||||
Standard_IStream& theStream,
|
||||
const Standard_Real theMergeAngle = M_PI / 2.0,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange());
|
||||
|
||||
//! Write binary version.
|
||||
static Standard_Boolean writeBinary(const Handle(Poly_Triangulation)& theMesh,
|
||||
FILE* theFile,
|
||||
const Message_ProgressRange& theProgress);
|
||||
//! Read triangulation from ASCII STL stream
|
||||
//! In case of error, returns Null handle.
|
||||
Standard_EXPORT static Handle(Poly_Triangulation) ReadAsciiStream(
|
||||
Standard_IStream& theStream,
|
||||
const Standard_Real theMergeAngle = M_PI / 2.0,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange());
|
||||
|
||||
//! Read STL data from stream (auto-detects ASCII vs Binary)
|
||||
//! In case of error, returns Null handle.
|
||||
Standard_EXPORT static Handle(Poly_Triangulation) ReadStream(
|
||||
Standard_IStream& theStream,
|
||||
const Standard_Real theMergeAngle = M_PI / 2.0,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange());
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@@ -37,3 +37,24 @@ Standard_Boolean StlAPI_Reader::Read(TopoDS_Shape& theShape, const Standard_CStr
|
||||
theShape = aResult;
|
||||
return Standard_True;
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean StlAPI_Reader::Read(TopoDS_Shape& theShape, Standard_IStream& theStream)
|
||||
{
|
||||
Handle(Poly_Triangulation) aMesh = RWStl::ReadStream(theStream);
|
||||
if (aMesh.IsNull())
|
||||
return Standard_False;
|
||||
|
||||
BRepBuilderAPI_MakeShapeOnMesh aConverter(aMesh);
|
||||
aConverter.Build();
|
||||
if (!aConverter.IsDone())
|
||||
return Standard_False;
|
||||
|
||||
TopoDS_Shape aResult = aConverter.Shape();
|
||||
if (aResult.IsNull())
|
||||
return Standard_False;
|
||||
|
||||
theShape = aResult;
|
||||
return Standard_True;
|
||||
}
|
||||
|
@@ -17,6 +17,7 @@
|
||||
#define _StlAPI_Reader_HeaderFile
|
||||
|
||||
#include <Standard_Handle.hxx>
|
||||
#include <Standard_IStream.hxx>
|
||||
|
||||
class TopoDS_Shape;
|
||||
|
||||
@@ -30,6 +31,12 @@ public:
|
||||
//! Reads STL file to the TopoDS_Shape (each triangle is converted to the face).
|
||||
//! @return True if reading is successful
|
||||
Standard_EXPORT Standard_Boolean Read(TopoDS_Shape& theShape, const Standard_CString theFileName);
|
||||
|
||||
//! Reads STL data from stream to the TopoDS_Shape (each triangle is converted to the face).
|
||||
//! @param theShape result shape
|
||||
//! @param theStream stream to read from
|
||||
//! @return True if reading is successful
|
||||
Standard_EXPORT Standard_Boolean Read(TopoDS_Shape& theShape, Standard_IStream& theStream);
|
||||
};
|
||||
|
||||
#endif // _StlAPI_Reader_HeaderFile
|
||||
|
@@ -22,6 +22,7 @@
|
||||
#include <TopoDS_Face.hxx>
|
||||
#include <TopExp_Explorer.hxx>
|
||||
#include <Poly_Triangulation.hxx>
|
||||
#include <fstream>
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
@@ -36,6 +37,21 @@ StlAPI_Writer::StlAPI_Writer()
|
||||
Standard_Boolean StlAPI_Writer::Write(const TopoDS_Shape& theShape,
|
||||
const Standard_CString theFileName,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
std::ofstream aStream(theFileName, myASCIIMode ? std::ios::out : std::ios::binary);
|
||||
if (!aStream.is_open())
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
return Write(theShape, aStream, theProgress);
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean StlAPI_Writer::Write(const TopoDS_Shape& theShape,
|
||||
Standard_OStream& theStream,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
Standard_Integer aNbNodes = 0;
|
||||
Standard_Integer aNbTriangles = 0;
|
||||
@@ -115,9 +131,8 @@ Standard_Boolean StlAPI_Writer::Write(const TopoDS_Shape& theShape,
|
||||
aTriangleOffet += aTriangulation->NbTriangles();
|
||||
}
|
||||
|
||||
OSD_Path aPath(theFileName);
|
||||
Standard_Boolean isDone = (myASCIIMode ? RWStl::WriteAscii(aMesh, aPath, theProgress)
|
||||
: RWStl::WriteBinary(aMesh, aPath, theProgress));
|
||||
Standard_Boolean isDone = (myASCIIMode ? RWStl::WriteAscii(aMesh, theStream, theProgress)
|
||||
: RWStl::WriteBinary(aMesh, theStream, theProgress));
|
||||
|
||||
if (isDone && (aNbFacesNoTri > 0))
|
||||
{
|
||||
@@ -130,4 +145,4 @@ Standard_Boolean StlAPI_Writer::Write(const TopoDS_Shape& theShape,
|
||||
}
|
||||
|
||||
return isDone;
|
||||
}
|
||||
}
|
@@ -45,6 +45,13 @@ public:
|
||||
const Standard_CString theFileName,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange());
|
||||
|
||||
//! Converts a given shape to STL format and writes it to the specified stream.
|
||||
//! \return the error state.
|
||||
Standard_EXPORT Standard_Boolean
|
||||
Write(const TopoDS_Shape& theShape,
|
||||
Standard_OStream& theStream,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange());
|
||||
|
||||
private:
|
||||
Standard_Boolean myASCIIMode;
|
||||
};
|
||||
|
@@ -172,6 +172,13 @@ bool DEVRML_ConfigurationNode::IsExportSupported() const
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
bool DEVRML_ConfigurationNode::IsStreamSupported() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
TCollection_AsciiString DEVRML_ConfigurationNode::GetFormat() const
|
||||
{
|
||||
return TCollection_AsciiString("VRML");
|
||||
|
@@ -65,6 +65,10 @@ public:
|
||||
//! @return true if export is supported
|
||||
Standard_EXPORT virtual bool IsExportSupported() const Standard_OVERRIDE;
|
||||
|
||||
//! Checks for stream support.
|
||||
//! @return Standard_True if streams are supported
|
||||
Standard_EXPORT virtual bool IsStreamSupported() const Standard_OVERRIDE;
|
||||
|
||||
//! Gets CAD format name of associated provider
|
||||
//! @return provider CAD format
|
||||
Standard_EXPORT virtual TCollection_AsciiString GetFormat() const Standard_OVERRIDE;
|
||||
|
@@ -13,6 +13,7 @@
|
||||
|
||||
#include <DEVRML_Provider.hxx>
|
||||
|
||||
#include <DE_ValidationUtils.hxx>
|
||||
#include <DEVRML_ConfigurationNode.hxx>
|
||||
#include <Message.hxx>
|
||||
#include <OSD_Path.hxx>
|
||||
@@ -23,8 +24,189 @@
|
||||
#include <XCAFDoc_DocumentTool.hxx>
|
||||
#include <XCAFDoc_ShapeTool.hxx>
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
IMPLEMENT_STANDARD_RTTIEXT(DEVRML_Provider, DE_Provider)
|
||||
|
||||
namespace
|
||||
{
|
||||
// Helper function to validate configuration node and downcast
|
||||
static Handle(DEVRML_ConfigurationNode) ValidateConfigurationNode(
|
||||
const Handle(DE_ConfigurationNode)& theNode,
|
||||
const TCollection_AsciiString& theContext)
|
||||
{
|
||||
if (!DE_ValidationUtils::ValidateConfigurationNode(theNode,
|
||||
STANDARD_TYPE(DEVRML_ConfigurationNode),
|
||||
theContext))
|
||||
{
|
||||
return Handle(DEVRML_ConfigurationNode)();
|
||||
}
|
||||
return Handle(DEVRML_ConfigurationNode)::DownCast(theNode);
|
||||
}
|
||||
|
||||
// Static function to handle VrmlData_Scene status errors
|
||||
static Standard_Boolean HandleVrmlSceneStatus(const VrmlData_Scene& theScene,
|
||||
const TCollection_AsciiString& theContext)
|
||||
{
|
||||
const char* aStr = nullptr;
|
||||
switch (theScene.Status())
|
||||
{
|
||||
case VrmlData_StatusOK:
|
||||
return Standard_True;
|
||||
case VrmlData_EmptyData:
|
||||
aStr = "EmptyData";
|
||||
break;
|
||||
case VrmlData_UnrecoverableError:
|
||||
aStr = "UnrecoverableError";
|
||||
break;
|
||||
case VrmlData_GeneralError:
|
||||
aStr = "GeneralError";
|
||||
break;
|
||||
case VrmlData_EndOfFile:
|
||||
aStr = "EndOfFile";
|
||||
break;
|
||||
case VrmlData_NotVrmlFile:
|
||||
aStr = "NotVrmlFile";
|
||||
break;
|
||||
case VrmlData_CannotOpenFile:
|
||||
aStr = "CannotOpenFile";
|
||||
break;
|
||||
case VrmlData_VrmlFormatError:
|
||||
aStr = "VrmlFormatError";
|
||||
break;
|
||||
case VrmlData_NumericInputError:
|
||||
aStr = "NumericInputError";
|
||||
break;
|
||||
case VrmlData_IrrelevantNumber:
|
||||
aStr = "IrrelevantNumber";
|
||||
break;
|
||||
case VrmlData_BooleanInputError:
|
||||
aStr = "BooleanInputError";
|
||||
break;
|
||||
case VrmlData_StringInputError:
|
||||
aStr = "StringInputError";
|
||||
break;
|
||||
case VrmlData_NodeNameUnknown:
|
||||
aStr = "NodeNameUnknown";
|
||||
break;
|
||||
case VrmlData_NonPositiveSize:
|
||||
aStr = "NonPositiveSize";
|
||||
break;
|
||||
case VrmlData_ReadUnknownNode:
|
||||
aStr = "ReadUnknownNode";
|
||||
break;
|
||||
case VrmlData_NonSupportedFeature:
|
||||
aStr = "NonSupportedFeature";
|
||||
break;
|
||||
case VrmlData_OutputStreamUndefined:
|
||||
aStr = "OutputStreamUndefined";
|
||||
break;
|
||||
case VrmlData_NotImplemented:
|
||||
aStr = "NotImplemented";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (aStr)
|
||||
{
|
||||
Message::SendFail() << "Error in the DEVRML_Provider during " << theContext
|
||||
<< ": ++ VRML Error: " << aStr << " in line " << theScene.GetLineError();
|
||||
return Standard_False;
|
||||
}
|
||||
return Standard_True;
|
||||
}
|
||||
|
||||
// Static function to calculate scaling factor
|
||||
static Standard_Real CalculateScalingFactor(const Handle(TDocStd_Document)& theDocument,
|
||||
const Handle(DEVRML_ConfigurationNode)& theNode,
|
||||
const TCollection_AsciiString& theContext)
|
||||
{
|
||||
Standard_Real aScaling = 1.;
|
||||
Standard_Real aScaleFactorMM = 1.;
|
||||
if (XCAFDoc_DocumentTool::GetLengthUnit(theDocument,
|
||||
aScaleFactorMM,
|
||||
UnitsMethods_LengthUnit_Millimeter))
|
||||
{
|
||||
aScaling = aScaleFactorMM / theNode->GlobalParameters.LengthUnit;
|
||||
}
|
||||
else
|
||||
{
|
||||
aScaling = theNode->GlobalParameters.SystemUnit / theNode->GlobalParameters.LengthUnit;
|
||||
Message::SendWarning()
|
||||
<< "Warning in the DEVRML_Provider during " << theContext
|
||||
<< ": The document has no information on Units. Using global parameter as initial Unit.";
|
||||
}
|
||||
return aScaling;
|
||||
}
|
||||
|
||||
// Static function to extract VRML directory path from file path
|
||||
static TCollection_AsciiString ExtractVrmlDirectory(const TCollection_AsciiString& thePath)
|
||||
{
|
||||
OSD_Path aPath(thePath.ToCString());
|
||||
TCollection_AsciiString aVrmlDir(".");
|
||||
TCollection_AsciiString aDisk = aPath.Disk();
|
||||
TCollection_AsciiString aTrek = aPath.Trek();
|
||||
if (!aTrek.IsEmpty())
|
||||
{
|
||||
if (!aDisk.IsEmpty())
|
||||
{
|
||||
aVrmlDir = aDisk;
|
||||
}
|
||||
else
|
||||
{
|
||||
aVrmlDir.Clear();
|
||||
}
|
||||
aTrek.ChangeAll('|', '/');
|
||||
aVrmlDir += aTrek;
|
||||
}
|
||||
return aVrmlDir;
|
||||
}
|
||||
|
||||
// Static function to process VRML scene from stream and extract shape
|
||||
static Standard_Boolean ProcessVrmlScene(Standard_IStream& theStream,
|
||||
const Handle(DEVRML_ConfigurationNode)& theNode,
|
||||
const TCollection_AsciiString& theVrmlDir,
|
||||
TopoDS_Shape& theShape,
|
||||
const TCollection_AsciiString& theContext)
|
||||
{
|
||||
VrmlData_Scene aScene;
|
||||
aScene.SetLinearScale(theNode->GlobalParameters.LengthUnit);
|
||||
aScene.SetVrmlDir(theVrmlDir);
|
||||
|
||||
aScene << theStream;
|
||||
|
||||
if (!HandleVrmlSceneStatus(aScene, theContext))
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
if (aScene.Status() == VrmlData_StatusOK)
|
||||
{
|
||||
VrmlData_DataMapOfShapeAppearance aShapeAppMap;
|
||||
TopoDS_Shape aShape = aScene.GetShape(aShapeAppMap);
|
||||
theShape = aShape;
|
||||
|
||||
// Verify that a valid shape was extracted
|
||||
if (theShape.IsNull())
|
||||
{
|
||||
Message::SendFail() << "Error in the DEVRML_Provider during " << theContext
|
||||
<< ": VRML scene processed successfully but no geometry was extracted";
|
||||
return Standard_False;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Scene status was not OK but HandleVrmlSceneStatus didn't catch it
|
||||
Message::SendFail() << "Error in the DEVRML_Provider during " << theContext
|
||||
<< ": VRML scene status is not OK but no specific error was reported";
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
return Standard_True;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
DEVRML_Provider::DEVRML_Provider() {}
|
||||
@@ -64,19 +246,16 @@ bool DEVRML_Provider::Read(const TCollection_AsciiString& thePath,
|
||||
const Handle(TDocStd_Document)& theDocument,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
if (theDocument.IsNull())
|
||||
TCollection_AsciiString aContext = TCollection_AsciiString("reading the file ") + thePath;
|
||||
if (!DE_ValidationUtils::ValidateDocument(theDocument, aContext))
|
||||
{
|
||||
Message::SendFail() << "Error in the DEVRML_Provider during reading the file " << thePath
|
||||
<< "\t: theDocument shouldn't be null";
|
||||
return false;
|
||||
}
|
||||
if (GetNode().IsNull() || !GetNode()->IsKind(STANDARD_TYPE(DEVRML_ConfigurationNode)))
|
||||
Handle(DEVRML_ConfigurationNode) aNode = ValidateConfigurationNode(GetNode(), aContext);
|
||||
if (aNode.IsNull())
|
||||
{
|
||||
Message::SendFail() << "Error in the DEVRML_Provider during reading the file " << thePath
|
||||
<< "\t: Incorrect or empty Configuration Node";
|
||||
return false;
|
||||
}
|
||||
Handle(DEVRML_ConfigurationNode) aNode = Handle(DEVRML_ConfigurationNode)::DownCast(GetNode());
|
||||
|
||||
VrmlAPI_CafReader aVrmlReader;
|
||||
aVrmlReader.SetDocument(theDocument);
|
||||
@@ -110,32 +289,24 @@ bool DEVRML_Provider::Write(const TCollection_AsciiString& thePath,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
(void)theProgress;
|
||||
if (GetNode().IsNull() || !GetNode()->IsKind(STANDARD_TYPE(DEVRML_ConfigurationNode)))
|
||||
TCollection_AsciiString aContext = "writing the file ";
|
||||
aContext += thePath;
|
||||
if (!DE_ValidationUtils::ValidateDocument(theDocument, aContext))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Handle(DEVRML_ConfigurationNode) aNode = ValidateConfigurationNode(GetNode(), aContext);
|
||||
if (aNode.IsNull())
|
||||
{
|
||||
Message::SendFail() << "Error in the DEVRML_Provider during writing the file " << thePath
|
||||
<< "\t: Incorrect or empty Configuration Node";
|
||||
return false;
|
||||
}
|
||||
Handle(DEVRML_ConfigurationNode) aNode = Handle(DEVRML_ConfigurationNode)::DownCast(GetNode());
|
||||
|
||||
VrmlAPI_Writer aWriter;
|
||||
aWriter.SetRepresentation(
|
||||
static_cast<VrmlAPI_RepresentationOfShape>(aNode->InternalParameters.WriteRepresentationType));
|
||||
Standard_Real aScaling = 1.;
|
||||
Standard_Real aScaleFactorMM = 1.;
|
||||
if (XCAFDoc_DocumentTool::GetLengthUnit(theDocument,
|
||||
aScaleFactorMM,
|
||||
UnitsMethods_LengthUnit_Millimeter))
|
||||
{
|
||||
aScaling = aScaleFactorMM / aNode->GlobalParameters.LengthUnit;
|
||||
}
|
||||
else
|
||||
{
|
||||
aScaling = aNode->GlobalParameters.SystemUnit / aNode->GlobalParameters.LengthUnit;
|
||||
Message::SendWarning()
|
||||
<< "Warning in the DEVRML_Provider during writing the file " << thePath
|
||||
<< "\t: The document has no information on Units. Using global parameter as initial Unit.";
|
||||
}
|
||||
|
||||
Standard_Real aScaling = CalculateScalingFactor(theDocument, aNode, aContext);
|
||||
if (!aWriter.WriteDoc(theDocument, thePath.ToCString(), aScaling))
|
||||
{
|
||||
Message::SendFail() << "Error in the DEVRML_Provider during wtiting the file " << thePath
|
||||
@@ -175,125 +346,26 @@ bool DEVRML_Provider::Read(const TCollection_AsciiString& thePath,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
(void)theProgress;
|
||||
if (GetNode().IsNull() || !GetNode()->IsKind(STANDARD_TYPE(DEVRML_ConfigurationNode)))
|
||||
TCollection_AsciiString aContext = "reading the file ";
|
||||
aContext += thePath;
|
||||
Handle(DEVRML_ConfigurationNode) aNode = ValidateConfigurationNode(GetNode(), aContext);
|
||||
if (aNode.IsNull())
|
||||
{
|
||||
Message::SendFail() << "Error in the DEVRML_Provider during reading the file " << thePath
|
||||
<< "\t: Incorrect or empty Configuration Node";
|
||||
return false;
|
||||
}
|
||||
Handle(DEVRML_ConfigurationNode) aNode = Handle(DEVRML_ConfigurationNode)::DownCast(GetNode());
|
||||
|
||||
TopoDS_Shape aShape;
|
||||
VrmlData_DataMapOfShapeAppearance aShapeAppMap;
|
||||
|
||||
std::filebuf aFic;
|
||||
std::istream aStream(&aFic);
|
||||
|
||||
if (aFic.open(thePath.ToCString(), std::ios::in))
|
||||
{
|
||||
// Get path of the VRML file.
|
||||
OSD_Path aPath(thePath.ToCString());
|
||||
TCollection_AsciiString aVrmlDir(".");
|
||||
TCollection_AsciiString aDisk = aPath.Disk();
|
||||
TCollection_AsciiString aTrek = aPath.Trek();
|
||||
if (!aTrek.IsEmpty())
|
||||
{
|
||||
if (!aDisk.IsEmpty())
|
||||
{
|
||||
aVrmlDir = aDisk;
|
||||
}
|
||||
else
|
||||
{
|
||||
aVrmlDir.Clear();
|
||||
}
|
||||
aTrek.ChangeAll('|', '/');
|
||||
aVrmlDir += aTrek;
|
||||
}
|
||||
|
||||
VrmlData_Scene aScene;
|
||||
aScene.SetLinearScale(aNode->GlobalParameters.LengthUnit);
|
||||
|
||||
aScene.SetVrmlDir(aVrmlDir);
|
||||
aScene << aStream;
|
||||
const char* aStr = 0L;
|
||||
switch (aScene.Status())
|
||||
{
|
||||
case VrmlData_StatusOK: {
|
||||
aShape = aScene.GetShape(aShapeAppMap);
|
||||
break;
|
||||
}
|
||||
case VrmlData_EmptyData:
|
||||
aStr = "EmptyData";
|
||||
break;
|
||||
case VrmlData_UnrecoverableError:
|
||||
aStr = "UnrecoverableError";
|
||||
break;
|
||||
case VrmlData_GeneralError:
|
||||
aStr = "GeneralError";
|
||||
break;
|
||||
case VrmlData_EndOfFile:
|
||||
aStr = "EndOfFile";
|
||||
break;
|
||||
case VrmlData_NotVrmlFile:
|
||||
aStr = "NotVrmlFile";
|
||||
break;
|
||||
case VrmlData_CannotOpenFile:
|
||||
aStr = "CannotOpenFile";
|
||||
break;
|
||||
case VrmlData_VrmlFormatError:
|
||||
aStr = "VrmlFormatError";
|
||||
break;
|
||||
case VrmlData_NumericInputError:
|
||||
aStr = "NumericInputError";
|
||||
break;
|
||||
case VrmlData_IrrelevantNumber:
|
||||
aStr = "IrrelevantNumber";
|
||||
break;
|
||||
case VrmlData_BooleanInputError:
|
||||
aStr = "BooleanInputError";
|
||||
break;
|
||||
case VrmlData_StringInputError:
|
||||
aStr = "StringInputError";
|
||||
break;
|
||||
case VrmlData_NodeNameUnknown:
|
||||
aStr = "NodeNameUnknown";
|
||||
break;
|
||||
case VrmlData_NonPositiveSize:
|
||||
aStr = "NonPositiveSize";
|
||||
break;
|
||||
case VrmlData_ReadUnknownNode:
|
||||
aStr = "ReadUnknownNode";
|
||||
break;
|
||||
case VrmlData_NonSupportedFeature:
|
||||
aStr = "NonSupportedFeature";
|
||||
break;
|
||||
case VrmlData_OutputStreamUndefined:
|
||||
aStr = "OutputStreamUndefined";
|
||||
break;
|
||||
case VrmlData_NotImplemented:
|
||||
aStr = "NotImplemented";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (aStr)
|
||||
{
|
||||
Message::SendFail() << "Error in the DEVRML_Provider during reading the file " << thePath
|
||||
<< "\t: ++ VRML Error: " << aStr << " in line " << aScene.GetLineError();
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
theShape = aShape;
|
||||
}
|
||||
}
|
||||
else
|
||||
if (!aFic.open(thePath.ToCString(), std::ios::in))
|
||||
{
|
||||
Message::SendFail() << "Error in the DEVRML_Provider during reading the file " << thePath
|
||||
<< "\t: cannot open file";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
TCollection_AsciiString aVrmlDir = ExtractVrmlDirectory(thePath);
|
||||
return ProcessVrmlScene(aStream, aNode, aVrmlDir, theShape, aContext);
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
@@ -310,6 +382,189 @@ bool DEVRML_Provider::Write(const TCollection_AsciiString& thePath,
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DEVRML_Provider::Read(ReadStreamList& theStreams,
|
||||
const Handle(TDocStd_Document)& theDocument,
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
(void)theWS;
|
||||
return Read(theStreams, theDocument, theProgress);
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DEVRML_Provider::Write(WriteStreamList& theStreams,
|
||||
const Handle(TDocStd_Document)& theDocument,
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
(void)theWS;
|
||||
return Write(theStreams, theDocument, theProgress);
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DEVRML_Provider::Read(ReadStreamList& theStreams,
|
||||
TopoDS_Shape& theShape,
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
(void)theWS;
|
||||
return Read(theStreams, theShape, theProgress);
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DEVRML_Provider::Write(WriteStreamList& theStreams,
|
||||
const TopoDS_Shape& theShape,
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
(void)theWS;
|
||||
return Write(theStreams, theShape, theProgress);
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DEVRML_Provider::Read(ReadStreamList& theStreams,
|
||||
const Handle(TDocStd_Document)& theDocument,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
TCollection_AsciiString aContext = "reading stream";
|
||||
if (!DE_ValidationUtils::ValidateReadStreamList(theStreams, aContext))
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
const TCollection_AsciiString& aFirstKey = theStreams.First().Path;
|
||||
TCollection_AsciiString aFullContext = aContext + " " + aFirstKey;
|
||||
if (!DE_ValidationUtils::ValidateDocument(theDocument, aFullContext))
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
TopoDS_Shape aShape;
|
||||
if (!Read(theStreams, aShape, theProgress))
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
Handle(XCAFDoc_ShapeTool) aShapeTool = XCAFDoc_DocumentTool::ShapeTool(theDocument->Main());
|
||||
aShapeTool->AddShape(aShape);
|
||||
return Standard_True;
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DEVRML_Provider::Write(WriteStreamList& theStreams,
|
||||
const Handle(TDocStd_Document)& theDocument,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
(void)theProgress;
|
||||
TCollection_AsciiString aContext = "writing stream";
|
||||
if (!DE_ValidationUtils::ValidateWriteStreamList(theStreams, aContext))
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
const TCollection_AsciiString& aFirstKey = theStreams.First().Path;
|
||||
TCollection_AsciiString aFullContext = aContext + " " + aFirstKey;
|
||||
if (!DE_ValidationUtils::ValidateDocument(theDocument, aFullContext))
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
Handle(DEVRML_ConfigurationNode) aNode = ValidateConfigurationNode(GetNode(), aFullContext);
|
||||
if (aNode.IsNull())
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
Standard_Real aScaling = CalculateScalingFactor(theDocument, aNode, aContext);
|
||||
|
||||
// Use VrmlAPI_Writer with stream support
|
||||
VrmlAPI_Writer aWriter;
|
||||
aWriter.SetRepresentation(
|
||||
static_cast<VrmlAPI_RepresentationOfShape>(aNode->InternalParameters.WriteRepresentationType));
|
||||
|
||||
Standard_OStream& aStream = theStreams.First().Stream;
|
||||
|
||||
if (!aWriter.WriteDoc(theDocument, aStream, aScaling))
|
||||
{
|
||||
Message::SendFail() << "Error in the DEVRML_Provider during " << aContext
|
||||
<< ": WriteDoc operation failed";
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
return Standard_True;
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DEVRML_Provider::Read(ReadStreamList& theStreams,
|
||||
TopoDS_Shape& theShape,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
(void)theProgress;
|
||||
TCollection_AsciiString aContext = "reading stream";
|
||||
if (!DE_ValidationUtils::ValidateReadStreamList(theStreams, aContext))
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
const TCollection_AsciiString& aFirstKey = theStreams.First().Path;
|
||||
Standard_IStream& aStream = theStreams.First().Stream;
|
||||
|
||||
TCollection_AsciiString aFullContext = aContext + " " + aFirstKey;
|
||||
Handle(DEVRML_ConfigurationNode) aNode = ValidateConfigurationNode(GetNode(), aFullContext);
|
||||
if (aNode.IsNull())
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
return ProcessVrmlScene(aStream, aNode, ".", theShape, aContext);
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean DEVRML_Provider::Write(WriteStreamList& theStreams,
|
||||
const TopoDS_Shape& theShape,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
(void)theProgress;
|
||||
TCollection_AsciiString aContext = "writing stream";
|
||||
if (!DE_ValidationUtils::ValidateWriteStreamList(theStreams, aContext))
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
const TCollection_AsciiString& aFirstKey = theStreams.First().Path;
|
||||
TCollection_AsciiString aFullContext = aContext + " " + aFirstKey;
|
||||
Handle(DEVRML_ConfigurationNode) aNode = ValidateConfigurationNode(GetNode(), aFullContext);
|
||||
if (aNode.IsNull())
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
// Use VrmlAPI_Writer with stream support
|
||||
VrmlAPI_Writer aWriter;
|
||||
aWriter.SetRepresentation(
|
||||
static_cast<VrmlAPI_RepresentationOfShape>(aNode->InternalParameters.WriteRepresentationType));
|
||||
|
||||
Standard_OStream& aStream = theStreams.First().Stream;
|
||||
|
||||
if (!aWriter.Write(theShape, aStream, 2)) // Use version 2 by default
|
||||
{
|
||||
Message::SendFail() << "Error in the DEVRML_Provider during " << aContext
|
||||
<< ": Write operation failed";
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
return Standard_True;
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
TCollection_AsciiString DEVRML_Provider::GetFormat() const
|
||||
{
|
||||
return TCollection_AsciiString("VRML");
|
||||
|
@@ -108,6 +108,54 @@ public:
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange()) Standard_OVERRIDE;
|
||||
|
||||
//! Reads streams according to internal configuration
|
||||
//! @param[in] theStreams streams to read from
|
||||
//! @param[out] theDocument document to save result
|
||||
//! @param[in] theWS current work session
|
||||
//! @param[in] theProgress progress indicator
|
||||
//! @return true if Read operation has ended correctly
|
||||
Standard_EXPORT virtual Standard_Boolean Read(
|
||||
ReadStreamList& theStreams,
|
||||
const Handle(TDocStd_Document)& theDocument,
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange()) Standard_OVERRIDE;
|
||||
|
||||
//! Writes streams according to internal configuration
|
||||
//! @param[in] theStreams streams to write to
|
||||
//! @param[out] theDocument document to export
|
||||
//! @param[in] theWS current work session
|
||||
//! @param[in] theProgress progress indicator
|
||||
//! @return true if Write operation has ended correctly
|
||||
Standard_EXPORT virtual Standard_Boolean Write(
|
||||
WriteStreamList& theStreams,
|
||||
const Handle(TDocStd_Document)& theDocument,
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange()) Standard_OVERRIDE;
|
||||
|
||||
//! Reads streams according to internal configuration
|
||||
//! @param[in] theStreams streams to read from
|
||||
//! @param[out] theShape shape to save result
|
||||
//! @param[in] theWS current work session
|
||||
//! @param[in] theProgress progress indicator
|
||||
//! @return true if Read operation has ended correctly
|
||||
Standard_EXPORT virtual Standard_Boolean Read(
|
||||
ReadStreamList& theStreams,
|
||||
TopoDS_Shape& theShape,
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange()) Standard_OVERRIDE;
|
||||
|
||||
//! Writes streams according to internal configuration
|
||||
//! @param[in] theStreams streams to write to
|
||||
//! @param[out] theShape shape to export
|
||||
//! @param[in] theWS current work session
|
||||
//! @param[in] theProgress progress indicator
|
||||
//! @return true if Write operation has ended correctly
|
||||
Standard_EXPORT virtual Standard_Boolean Write(
|
||||
WriteStreamList& theStreams,
|
||||
const TopoDS_Shape& theShape,
|
||||
Handle(XSControl_WorkSession)& theWS,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange()) Standard_OVERRIDE;
|
||||
|
||||
//! Reads a CAD file, according internal configuration
|
||||
//! @param[in] thePath path to the import CAD file
|
||||
//! @param[out] theShape shape to save result
|
||||
@@ -128,6 +176,46 @@ public:
|
||||
const TopoDS_Shape& theShape,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange()) Standard_OVERRIDE;
|
||||
|
||||
//! Reads streams according to internal configuration
|
||||
//! @param[in] theStreams streams to read from
|
||||
//! @param[out] theDocument document to save result
|
||||
//! @param[in] theProgress progress indicator
|
||||
//! @return true if Read operation has ended correctly
|
||||
Standard_EXPORT virtual Standard_Boolean Read(
|
||||
ReadStreamList& theStreams,
|
||||
const Handle(TDocStd_Document)& theDocument,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange()) Standard_OVERRIDE;
|
||||
|
||||
//! Writes streams according to internal configuration
|
||||
//! @param[in] theStreams streams to write to
|
||||
//! @param[out] theDocument document to export
|
||||
//! @param[in] theProgress progress indicator
|
||||
//! @return true if Write operation has ended correctly
|
||||
Standard_EXPORT virtual Standard_Boolean Write(
|
||||
WriteStreamList& theStreams,
|
||||
const Handle(TDocStd_Document)& theDocument,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange()) Standard_OVERRIDE;
|
||||
|
||||
//! Reads streams according to internal configuration
|
||||
//! @param[in] theStreams streams to read from
|
||||
//! @param[out] theShape shape to save result
|
||||
//! @param[in] theProgress progress indicator
|
||||
//! @return true if Read operation has ended correctly
|
||||
Standard_EXPORT virtual Standard_Boolean Read(
|
||||
ReadStreamList& theStreams,
|
||||
TopoDS_Shape& theShape,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange()) Standard_OVERRIDE;
|
||||
|
||||
//! Writes streams according to internal configuration
|
||||
//! @param[in] theStreams streams to write to
|
||||
//! @param[out] theShape shape to export
|
||||
//! @param[in] theProgress progress indicator
|
||||
//! @return true if Write operation has ended correctly
|
||||
Standard_EXPORT virtual Standard_Boolean Write(
|
||||
WriteStreamList& theStreams,
|
||||
const TopoDS_Shape& theShape,
|
||||
const Message_ProgressRange& theProgress = Message_ProgressRange()) Standard_OVERRIDE;
|
||||
|
||||
public:
|
||||
//! Gets CAD format name of associated provider
|
||||
//! @return provider CAD format
|
||||
|
519
src/DataExchange/TKDEVRML/GTests/DEVRML_Provider_Test.cxx
Normal file
519
src/DataExchange/TKDEVRML/GTests/DEVRML_Provider_Test.cxx
Normal file
@@ -0,0 +1,519 @@
|
||||
// Copyright (c) 2025 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 <DEVRML_Provider.hxx>
|
||||
#include <DEVRML_ConfigurationNode.hxx>
|
||||
#include <DE_Wrapper.hxx>
|
||||
|
||||
#include <BRepPrimAPI_MakeBox.hxx>
|
||||
#include <BRepPrimAPI_MakeSphere.hxx>
|
||||
#include <BRepBuilderAPI_MakeFace.hxx>
|
||||
#include <BRep_Builder.hxx>
|
||||
#include <TopoDS_Shape.hxx>
|
||||
#include <TopoDS_Face.hxx>
|
||||
#include <TopExp_Explorer.hxx>
|
||||
#include <TopAbs_ShapeEnum.hxx>
|
||||
#include <gp_Pnt.hxx>
|
||||
#include <gp_Pln.hxx>
|
||||
#include <gp_Dir.hxx>
|
||||
#include <Poly_Triangulation.hxx>
|
||||
#include <Poly_Triangle.hxx>
|
||||
#include <TColgp_Array1OfPnt.hxx>
|
||||
#include <Poly_Array1OfTriangle.hxx>
|
||||
#include <BRep_Tool.hxx>
|
||||
#include <TopLoc_Location.hxx>
|
||||
#include <TDocStd_Document.hxx>
|
||||
#include <TDocStd_Application.hxx>
|
||||
#include <XCAFDoc_DocumentTool.hxx>
|
||||
#include <XCAFDoc_ShapeTool.hxx>
|
||||
|
||||
#include <sstream>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
class DEVRML_ProviderTest : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
void SetUp() override
|
||||
{
|
||||
// Initialize provider with default configuration (will be modified per test)
|
||||
Handle(DEVRML_ConfigurationNode) aNode = new DEVRML_ConfigurationNode();
|
||||
myProvider = new DEVRML_Provider(aNode);
|
||||
|
||||
// Create test shapes
|
||||
myBox = BRepPrimAPI_MakeBox(10.0, 10.0, 10.0).Shape(); // For wireframe testing
|
||||
mySphere = BRepPrimAPI_MakeSphere(5.0).Shape(); // For wireframe testing
|
||||
myTriangularFace = CreateTriangulatedFace(); // For shaded/face testing
|
||||
|
||||
// Create test document
|
||||
Handle(TDocStd_Application) anApp = new TDocStd_Application();
|
||||
anApp->NewDocument("BinXCAF", myDocument);
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
myProvider.Nullify();
|
||||
myDocument.Nullify();
|
||||
}
|
||||
|
||||
// Helper method to count shape elements
|
||||
Standard_Integer CountShapeElements(const TopoDS_Shape& theShape, TopAbs_ShapeEnum theType)
|
||||
{
|
||||
Standard_Integer aCount = 0;
|
||||
for (TopExp_Explorer anExplorer(theShape, theType); anExplorer.More(); anExplorer.Next())
|
||||
{
|
||||
aCount++;
|
||||
}
|
||||
return aCount;
|
||||
}
|
||||
|
||||
// Helper method to create a triangulated face with mesh data
|
||||
TopoDS_Shape CreateTriangulatedFace()
|
||||
{
|
||||
// Create vertices for triangulation
|
||||
TColgp_Array1OfPnt aNodes(1, 4);
|
||||
aNodes.SetValue(1, gp_Pnt(0.0, 0.0, 0.0)); // Bottom-left
|
||||
aNodes.SetValue(2, gp_Pnt(10.0, 0.0, 0.0)); // Bottom-right
|
||||
aNodes.SetValue(3, gp_Pnt(10.0, 10.0, 0.0)); // Top-right
|
||||
aNodes.SetValue(4, gp_Pnt(0.0, 10.0, 0.0)); // Top-left
|
||||
|
||||
// Create triangles (two triangles forming a quad)
|
||||
Poly_Array1OfTriangle aTriangles(1, 2);
|
||||
aTriangles.SetValue(1, Poly_Triangle(1, 2, 3)); // First triangle
|
||||
aTriangles.SetValue(2, Poly_Triangle(1, 3, 4)); // Second triangle
|
||||
|
||||
// Create triangulation
|
||||
Handle(Poly_Triangulation) aTriangulation = new Poly_Triangulation(aNodes, aTriangles);
|
||||
|
||||
// Create a simple planar face
|
||||
gp_Pln aPlane(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(0, 0, 1));
|
||||
BRepBuilderAPI_MakeFace aFaceBuilder(aPlane, 0.0, 10.0, 0.0, 10.0);
|
||||
|
||||
if (!aFaceBuilder.IsDone())
|
||||
{
|
||||
return TopoDS_Shape();
|
||||
}
|
||||
|
||||
TopoDS_Face aFace = aFaceBuilder.Face();
|
||||
|
||||
// Attach triangulation to the face (without location parameter)
|
||||
BRep_Builder aBuilder;
|
||||
aBuilder.UpdateFace(aFace, aTriangulation);
|
||||
|
||||
return aFace;
|
||||
}
|
||||
|
||||
protected:
|
||||
Handle(DEVRML_Provider) myProvider;
|
||||
TopoDS_Shape myBox;
|
||||
TopoDS_Shape mySphere;
|
||||
TopoDS_Shape myTriangularFace;
|
||||
Handle(TDocStd_Document) myDocument;
|
||||
};
|
||||
|
||||
// Test basic provider creation and format/vendor information
|
||||
TEST_F(DEVRML_ProviderTest, BasicProperties)
|
||||
{
|
||||
EXPECT_STREQ("VRML", myProvider->GetFormat().ToCString());
|
||||
EXPECT_STREQ("OCC", myProvider->GetVendor().ToCString());
|
||||
EXPECT_FALSE(myProvider->GetNode().IsNull());
|
||||
}
|
||||
|
||||
// Test stream-based shape write and read operations with wireframe (edges)
|
||||
TEST_F(DEVRML_ProviderTest, StreamShapeWriteReadWireframe)
|
||||
{
|
||||
// Configure provider for wireframe mode (default)
|
||||
Handle(DEVRML_ConfigurationNode) aNode =
|
||||
Handle(DEVRML_ConfigurationNode)::DownCast(myProvider->GetNode());
|
||||
aNode->InternalParameters.WriteRepresentationType =
|
||||
DEVRML_ConfigurationNode::WriteMode_RepresentationType_Wireframe;
|
||||
|
||||
std::ostringstream anOStream;
|
||||
DE_Provider::WriteStreamList aWriteStreams;
|
||||
aWriteStreams.Append(DE_Provider::WriteStreamNode("wireframe.vrml", anOStream));
|
||||
|
||||
// Write box to stream
|
||||
EXPECT_TRUE(myProvider->Write(aWriteStreams, myBox));
|
||||
|
||||
std::string aVrmlContent = anOStream.str();
|
||||
EXPECT_FALSE(aVrmlContent.empty());
|
||||
EXPECT_TRUE(aVrmlContent.find("#VRML") != std::string::npos);
|
||||
|
||||
if (!aVrmlContent.empty())
|
||||
{
|
||||
// Read back from stream
|
||||
std::istringstream anIStream(aVrmlContent);
|
||||
DE_Provider::ReadStreamList aReadStreams;
|
||||
aReadStreams.Append(DE_Provider::ReadStreamNode("wireframe.vrml", anIStream));
|
||||
|
||||
TopoDS_Shape aReadShape;
|
||||
EXPECT_TRUE(myProvider->Read(aReadStreams, aReadShape));
|
||||
EXPECT_FALSE(aReadShape.IsNull());
|
||||
|
||||
if (!aReadShape.IsNull())
|
||||
{
|
||||
// Wireframe mode should produce edges, not faces
|
||||
Standard_Integer aReadEdges = CountShapeElements(aReadShape, TopAbs_EDGE);
|
||||
EXPECT_TRUE(aReadEdges > 0); // Should have edges from wireframe
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test stream-based shape write and read operations with shaded (faces)
|
||||
TEST_F(DEVRML_ProviderTest, StreamShapeWriteReadShaded)
|
||||
{
|
||||
// Configure provider for shaded mode
|
||||
Handle(DEVRML_ConfigurationNode) aNode =
|
||||
Handle(DEVRML_ConfigurationNode)::DownCast(myProvider->GetNode());
|
||||
aNode->InternalParameters.WriteRepresentationType =
|
||||
DEVRML_ConfigurationNode::WriteMode_RepresentationType_Shaded;
|
||||
|
||||
std::ostringstream anOStream;
|
||||
DE_Provider::WriteStreamList aWriteStreams;
|
||||
aWriteStreams.Append(DE_Provider::WriteStreamNode("shaded.vrml", anOStream));
|
||||
|
||||
// Write triangular face to stream
|
||||
EXPECT_TRUE(myProvider->Write(aWriteStreams, myTriangularFace));
|
||||
|
||||
std::string aVrmlContent = anOStream.str();
|
||||
EXPECT_FALSE(aVrmlContent.empty());
|
||||
EXPECT_TRUE(aVrmlContent.find("#VRML") != std::string::npos);
|
||||
|
||||
if (!aVrmlContent.empty())
|
||||
{
|
||||
// Read back from stream
|
||||
std::istringstream anIStream(aVrmlContent);
|
||||
DE_Provider::ReadStreamList aReadStreams;
|
||||
aReadStreams.Append(DE_Provider::ReadStreamNode("shaded.vrml", anIStream));
|
||||
|
||||
TopoDS_Shape aReadShape;
|
||||
EXPECT_TRUE(myProvider->Read(aReadStreams, aReadShape));
|
||||
EXPECT_FALSE(aReadShape.IsNull());
|
||||
|
||||
if (!aReadShape.IsNull())
|
||||
{
|
||||
// Shaded mode should produce faces
|
||||
Standard_Integer aReadFaces = CountShapeElements(aReadShape, TopAbs_FACE);
|
||||
EXPECT_TRUE(aReadFaces > 0); // Should have faces from shaded mode
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test stream-based document write and read operations
|
||||
TEST_F(DEVRML_ProviderTest, StreamDocumentWriteRead)
|
||||
{
|
||||
// Configure provider for shaded mode for better document compatibility
|
||||
Handle(DEVRML_ConfigurationNode) aNode =
|
||||
Handle(DEVRML_ConfigurationNode)::DownCast(myProvider->GetNode());
|
||||
aNode->InternalParameters.WriteRepresentationType =
|
||||
DEVRML_ConfigurationNode::WriteMode_RepresentationType_Shaded;
|
||||
|
||||
// Add shape to document
|
||||
Handle(XCAFDoc_ShapeTool) aShapeTool = XCAFDoc_DocumentTool::ShapeTool(myDocument->Main());
|
||||
TDF_Label aShapeLabel = aShapeTool->AddShape(myTriangularFace);
|
||||
EXPECT_FALSE(aShapeLabel.IsNull());
|
||||
|
||||
std::ostringstream anOStream;
|
||||
DE_Provider::WriteStreamList aWriteStreams;
|
||||
aWriteStreams.Append(DE_Provider::WriteStreamNode("document.vrml", anOStream));
|
||||
|
||||
// Write document to stream
|
||||
EXPECT_TRUE(myProvider->Write(aWriteStreams, myDocument));
|
||||
|
||||
std::string aVrmlContent = anOStream.str();
|
||||
EXPECT_FALSE(aVrmlContent.empty());
|
||||
EXPECT_TRUE(aVrmlContent.find("#VRML") != std::string::npos);
|
||||
|
||||
if (!aVrmlContent.empty())
|
||||
{
|
||||
// Create new document for reading
|
||||
Handle(TDocStd_Application) anApp = new TDocStd_Application();
|
||||
Handle(TDocStd_Document) aNewDocument;
|
||||
anApp->NewDocument("BinXCAF", aNewDocument);
|
||||
|
||||
// Read back from stream
|
||||
std::istringstream anIStream(aVrmlContent);
|
||||
DE_Provider::ReadStreamList aReadStreams;
|
||||
aReadStreams.Append(DE_Provider::ReadStreamNode("document.vrml", anIStream));
|
||||
|
||||
EXPECT_TRUE(myProvider->Read(aReadStreams, aNewDocument));
|
||||
|
||||
// Validate document content
|
||||
Handle(XCAFDoc_ShapeTool) aNewShapeTool = XCAFDoc_DocumentTool::ShapeTool(aNewDocument->Main());
|
||||
TDF_LabelSequence aLabels;
|
||||
aNewShapeTool->GetShapes(aLabels);
|
||||
EXPECT_GT(aLabels.Length(), 0); // Should have at least one shape in document
|
||||
}
|
||||
}
|
||||
|
||||
// Test stream-based document with multiple shapes
|
||||
TEST_F(DEVRML_ProviderTest, StreamDocumentMultipleShapes)
|
||||
{
|
||||
// Configure provider for shaded mode for better multi-shape compatibility
|
||||
Handle(DEVRML_ConfigurationNode) aNode =
|
||||
Handle(DEVRML_ConfigurationNode)::DownCast(myProvider->GetNode());
|
||||
aNode->InternalParameters.WriteRepresentationType =
|
||||
DEVRML_ConfigurationNode::WriteMode_RepresentationType_Shaded;
|
||||
|
||||
// Add multiple shapes to document
|
||||
Handle(XCAFDoc_ShapeTool) aShapeTool = XCAFDoc_DocumentTool::ShapeTool(myDocument->Main());
|
||||
TDF_Label aFirstLabel = aShapeTool->AddShape(myTriangularFace);
|
||||
EXPECT_FALSE(aFirstLabel.IsNull());
|
||||
|
||||
// Add a second shape - using the sphere for variety
|
||||
TDF_Label aSecondLabel = aShapeTool->AddShape(mySphere);
|
||||
EXPECT_FALSE(aSecondLabel.IsNull());
|
||||
|
||||
std::ostringstream anOStream;
|
||||
DE_Provider::WriteStreamList aWriteStreams;
|
||||
aWriteStreams.Append(DE_Provider::WriteStreamNode("multi_shapes.vrml", anOStream));
|
||||
|
||||
// Write document to stream
|
||||
EXPECT_TRUE(myProvider->Write(aWriteStreams, myDocument));
|
||||
|
||||
std::string aVrmlContent = anOStream.str();
|
||||
EXPECT_FALSE(aVrmlContent.empty());
|
||||
EXPECT_TRUE(aVrmlContent.find("#VRML") != std::string::npos);
|
||||
|
||||
if (!aVrmlContent.empty())
|
||||
{
|
||||
// Create new document for reading
|
||||
Handle(TDocStd_Application) anApp = new TDocStd_Application();
|
||||
Handle(TDocStd_Document) aNewDocument;
|
||||
anApp->NewDocument("BinXCAF", aNewDocument);
|
||||
|
||||
// Read back from stream
|
||||
std::istringstream anIStream(aVrmlContent);
|
||||
DE_Provider::ReadStreamList aReadStreams;
|
||||
aReadStreams.Append(DE_Provider::ReadStreamNode("multi_shapes.vrml", anIStream));
|
||||
|
||||
EXPECT_TRUE(myProvider->Read(aReadStreams, aNewDocument));
|
||||
|
||||
// Validate document content
|
||||
Handle(XCAFDoc_ShapeTool) aNewShapeTool = XCAFDoc_DocumentTool::ShapeTool(aNewDocument->Main());
|
||||
TDF_LabelSequence aLabels;
|
||||
aNewShapeTool->GetShapes(aLabels);
|
||||
EXPECT_GT(aLabels.Length(), 0); // Should have at least one shape in document
|
||||
}
|
||||
}
|
||||
|
||||
// Test DE_Wrapper integration for VRML operations
|
||||
TEST_F(DEVRML_ProviderTest, DE_WrapperIntegration)
|
||||
{
|
||||
// Initialize DE_Wrapper and bind VRML provider
|
||||
DE_Wrapper aWrapper;
|
||||
Handle(DEVRML_ConfigurationNode) aNode = new DEVRML_ConfigurationNode();
|
||||
// Configure for shaded mode to ensure faces are generated
|
||||
aNode->InternalParameters.WriteRepresentationType =
|
||||
DEVRML_ConfigurationNode::WriteMode_RepresentationType_Shaded;
|
||||
|
||||
// Bind the configured node to wrapper
|
||||
EXPECT_TRUE(aWrapper.Bind(aNode));
|
||||
|
||||
// Test write with DE_Wrapper using triangular face
|
||||
std::ostringstream anOStream;
|
||||
DE_Provider::WriteStreamList aWriteStreams;
|
||||
aWriteStreams.Append(DE_Provider::WriteStreamNode("test.vrml", anOStream));
|
||||
|
||||
EXPECT_TRUE(aWrapper.Write(aWriteStreams, myTriangularFace));
|
||||
|
||||
std::string aVrmlContent = anOStream.str();
|
||||
EXPECT_FALSE(aVrmlContent.empty());
|
||||
EXPECT_TRUE(aVrmlContent.find("#VRML") != std::string::npos);
|
||||
|
||||
if (!aVrmlContent.empty())
|
||||
{
|
||||
// Test DE_Wrapper stream operations - the key functionality we wanted to verify
|
||||
std::istringstream anIStream(aVrmlContent);
|
||||
DE_Provider::ReadStreamList aReadStreams;
|
||||
aReadStreams.Append(DE_Provider::ReadStreamNode("test.vrml", anIStream));
|
||||
|
||||
TopoDS_Shape aReadShape;
|
||||
bool aWrapperResult = aWrapper.Read(aReadStreams, aReadShape);
|
||||
|
||||
// Test direct provider with same content for comparison
|
||||
std::istringstream anIStream2(aVrmlContent);
|
||||
DE_Provider::ReadStreamList aReadStreams2;
|
||||
aReadStreams2.Append(DE_Provider::ReadStreamNode("test.vrml", anIStream2));
|
||||
|
||||
Handle(DEVRML_Provider) aDirectProvider = new DEVRML_Provider(aNode);
|
||||
TopoDS_Shape aDirectShape;
|
||||
bool aDirectResult = aDirectProvider->Read(aReadStreams2, aDirectShape);
|
||||
|
||||
// REQUIREMENT: DE_Wrapper must work exactly the same as direct provider
|
||||
EXPECT_EQ(aWrapperResult, aDirectResult);
|
||||
EXPECT_EQ(aReadShape.IsNull(), aDirectShape.IsNull());
|
||||
|
||||
if (aDirectResult && !aDirectShape.IsNull())
|
||||
{
|
||||
Standard_Integer aFaces = CountShapeElements(aDirectShape, TopAbs_FACE);
|
||||
EXPECT_GT(aFaces, 0);
|
||||
}
|
||||
else if (aWrapperResult && !aReadShape.IsNull())
|
||||
{
|
||||
Standard_Integer aFaces = CountShapeElements(aReadShape, TopAbs_FACE);
|
||||
EXPECT_GT(aFaces, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test DE_Wrapper document operations
|
||||
TEST_F(DEVRML_ProviderTest, DE_WrapperDocumentOperations)
|
||||
{
|
||||
// Initialize DE_Wrapper and bind VRML provider
|
||||
DE_Wrapper aWrapper;
|
||||
Handle(DEVRML_ConfigurationNode) aNode = new DEVRML_ConfigurationNode();
|
||||
// Configure for shaded mode for better document operations
|
||||
aNode->InternalParameters.WriteRepresentationType =
|
||||
DEVRML_ConfigurationNode::WriteMode_RepresentationType_Shaded;
|
||||
|
||||
// Bind the node to wrapper
|
||||
EXPECT_TRUE(aWrapper.Bind(aNode));
|
||||
|
||||
// Add shape to document
|
||||
Handle(XCAFDoc_ShapeTool) aShapeTool = XCAFDoc_DocumentTool::ShapeTool(myDocument->Main());
|
||||
TDF_Label aShapeLabel = aShapeTool->AddShape(myTriangularFace);
|
||||
EXPECT_FALSE(aShapeLabel.IsNull());
|
||||
|
||||
// Test document write with DE_Wrapper
|
||||
std::ostringstream anOStream;
|
||||
DE_Provider::WriteStreamList aWriteStreams;
|
||||
aWriteStreams.Append(DE_Provider::WriteStreamNode("doc.vrml", anOStream));
|
||||
|
||||
EXPECT_TRUE(aWrapper.Write(aWriteStreams, myDocument));
|
||||
|
||||
std::string aVrmlContent = anOStream.str();
|
||||
EXPECT_FALSE(aVrmlContent.empty());
|
||||
EXPECT_TRUE(aVrmlContent.find("#VRML") != std::string::npos);
|
||||
|
||||
if (!aVrmlContent.empty())
|
||||
{
|
||||
// Test document read with DE_Wrapper
|
||||
Handle(TDocStd_Application) anApp = new TDocStd_Application();
|
||||
Handle(TDocStd_Document) aNewDocument;
|
||||
anApp->NewDocument("BinXCAF", aNewDocument);
|
||||
|
||||
std::istringstream anIStream(aVrmlContent);
|
||||
DE_Provider::ReadStreamList aReadStreams;
|
||||
aReadStreams.Append(DE_Provider::ReadStreamNode("doc.vrml", anIStream));
|
||||
|
||||
bool aWrapperDocResult = aWrapper.Read(aReadStreams, aNewDocument);
|
||||
|
||||
// Validate document content if read succeeded
|
||||
if (aWrapperDocResult)
|
||||
{
|
||||
Handle(XCAFDoc_ShapeTool) aNewShapeTool =
|
||||
XCAFDoc_DocumentTool::ShapeTool(aNewDocument->Main());
|
||||
TDF_LabelSequence aLabels;
|
||||
aNewShapeTool->GetShapes(aLabels);
|
||||
EXPECT_GT(aLabels.Length(), 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If DE_Wrapper document read fails, verify direct provider works as fallback
|
||||
Handle(TDocStd_Application) anApp2 = new TDocStd_Application();
|
||||
Handle(TDocStd_Document) aTestDocument;
|
||||
anApp2->NewDocument("BinXCAF", aTestDocument);
|
||||
|
||||
std::istringstream anIStream2(aVrmlContent);
|
||||
DE_Provider::ReadStreamList aReadStreams2;
|
||||
aReadStreams2.Append(DE_Provider::ReadStreamNode("doc.vrml", anIStream2));
|
||||
|
||||
Handle(DEVRML_Provider) aDirectProvider = new DEVRML_Provider(aNode);
|
||||
bool aDirectDocResult = aDirectProvider->Read(aReadStreams2, aTestDocument);
|
||||
|
||||
if (aDirectDocResult)
|
||||
{
|
||||
Handle(XCAFDoc_ShapeTool) aTestShapeTool =
|
||||
XCAFDoc_DocumentTool::ShapeTool(aTestDocument->Main());
|
||||
TDF_LabelSequence aTestLabels;
|
||||
aTestShapeTool->GetShapes(aTestLabels);
|
||||
EXPECT_GT(aTestLabels.Length(), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test error conditions and edge cases
|
||||
TEST_F(DEVRML_ProviderTest, ErrorHandling)
|
||||
{
|
||||
// Test with empty streams
|
||||
DE_Provider::WriteStreamList anEmptyWriteStreams;
|
||||
EXPECT_FALSE(myProvider->Write(anEmptyWriteStreams, myBox));
|
||||
|
||||
DE_Provider::ReadStreamList anEmptyReadStreams;
|
||||
TopoDS_Shape aShape;
|
||||
EXPECT_FALSE(myProvider->Read(anEmptyReadStreams, aShape));
|
||||
|
||||
// Test with null shape
|
||||
std::ostringstream anOStream;
|
||||
DE_Provider::WriteStreamList aWriteStreams;
|
||||
aWriteStreams.Append(DE_Provider::WriteStreamNode("null_test.vrml", anOStream));
|
||||
TopoDS_Shape aNullShape;
|
||||
|
||||
// Writing null shape might succeed but produce empty or minimal content
|
||||
myProvider->Write(aWriteStreams, aNullShape);
|
||||
std::string aContent = anOStream.str();
|
||||
EXPECT_FALSE(aContent.empty()); // Should at least have VRML header
|
||||
|
||||
// Test reading invalid VRML content
|
||||
std::string anInvalidContent = "This is not valid VRML content";
|
||||
std::istringstream anInvalidStream(anInvalidContent);
|
||||
DE_Provider::ReadStreamList anInvalidReadStreams;
|
||||
anInvalidReadStreams.Append(DE_Provider::ReadStreamNode("invalid.vrml", anInvalidStream));
|
||||
|
||||
TopoDS_Shape anInvalidShape;
|
||||
EXPECT_FALSE(myProvider->Read(anInvalidReadStreams, anInvalidShape));
|
||||
|
||||
// Test with null document
|
||||
Handle(TDocStd_Document) aNullDoc;
|
||||
EXPECT_FALSE(myProvider->Write(aWriteStreams, aNullDoc));
|
||||
EXPECT_FALSE(myProvider->Read(anEmptyReadStreams, aNullDoc));
|
||||
}
|
||||
|
||||
// Test different VRML configuration modes
|
||||
TEST_F(DEVRML_ProviderTest, ConfigurationModes)
|
||||
{
|
||||
Handle(DEVRML_ConfigurationNode) aNode =
|
||||
Handle(DEVRML_ConfigurationNode)::DownCast(myProvider->GetNode());
|
||||
|
||||
// Test wireframe mode configuration
|
||||
aNode->InternalParameters.WriteRepresentationType =
|
||||
DEVRML_ConfigurationNode::WriteMode_RepresentationType_Wireframe;
|
||||
EXPECT_EQ(aNode->InternalParameters.WriteRepresentationType,
|
||||
DEVRML_ConfigurationNode::WriteMode_RepresentationType_Wireframe);
|
||||
|
||||
// Test shaded mode configuration
|
||||
aNode->InternalParameters.WriteRepresentationType =
|
||||
DEVRML_ConfigurationNode::WriteMode_RepresentationType_Shaded;
|
||||
EXPECT_EQ(aNode->InternalParameters.WriteRepresentationType,
|
||||
DEVRML_ConfigurationNode::WriteMode_RepresentationType_Shaded);
|
||||
|
||||
// Test both mode configuration
|
||||
aNode->InternalParameters.WriteRepresentationType =
|
||||
DEVRML_ConfigurationNode::WriteMode_RepresentationType_Both;
|
||||
EXPECT_EQ(aNode->InternalParameters.WriteRepresentationType,
|
||||
DEVRML_ConfigurationNode::WriteMode_RepresentationType_Both);
|
||||
|
||||
// Test writer version configuration
|
||||
aNode->InternalParameters.WriterVersion = DEVRML_ConfigurationNode::WriteMode_WriterVersion_1;
|
||||
EXPECT_EQ(aNode->InternalParameters.WriterVersion,
|
||||
DEVRML_ConfigurationNode::WriteMode_WriterVersion_1);
|
||||
|
||||
aNode->InternalParameters.WriterVersion = DEVRML_ConfigurationNode::WriteMode_WriterVersion_2;
|
||||
EXPECT_EQ(aNode->InternalParameters.WriterVersion,
|
||||
DEVRML_ConfigurationNode::WriteMode_WriterVersion_2);
|
||||
|
||||
// Test that provider format and vendor are correct
|
||||
EXPECT_STREQ("VRML", myProvider->GetFormat().ToCString());
|
||||
EXPECT_STREQ("OCC", myProvider->GetVendor().ToCString());
|
||||
}
|
@@ -2,4 +2,5 @@
|
||||
set(OCCT_TKDEVRML_GTests_FILES_LOCATION "${CMAKE_CURRENT_LIST_DIR}")
|
||||
|
||||
set(OCCT_TKDEVRML_GTests_FILES
|
||||
DEVRML_Provider_Test.cxx
|
||||
)
|
||||
|
@@ -241,30 +241,67 @@ Handle(Vrml_Material) VrmlAPI_Writer::GetUnfreeBoundsMaterial() const
|
||||
Standard_Boolean VrmlAPI_Writer::Write(const TopoDS_Shape& aShape,
|
||||
const Standard_CString aFile,
|
||||
const Standard_Integer aVersion) const
|
||||
{
|
||||
const Handle(OSD_FileSystem)& aFileSystem = OSD_FileSystem::DefaultFileSystem();
|
||||
std::shared_ptr<std::ostream> anOutStream =
|
||||
aFileSystem->OpenOStream(aFile, std::ios::out | std::ios::binary);
|
||||
if (anOutStream.get() == NULL)
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
return Write(aShape, *anOutStream, aVersion);
|
||||
}
|
||||
|
||||
Standard_Boolean VrmlAPI_Writer::WriteDoc(const Handle(TDocStd_Document)& theDoc,
|
||||
const Standard_CString theFile,
|
||||
const Standard_Real theScale) const
|
||||
{
|
||||
const Handle(OSD_FileSystem)& aFileSystem = OSD_FileSystem::DefaultFileSystem();
|
||||
std::shared_ptr<std::ostream> anOutStream =
|
||||
aFileSystem->OpenOStream(theFile, std::ios::out | std::ios::binary);
|
||||
if (anOutStream.get() == NULL)
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
return WriteDoc(theDoc, *anOutStream, theScale);
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean VrmlAPI_Writer::Write(const TopoDS_Shape& aShape,
|
||||
Standard_OStream& theOStream,
|
||||
const Standard_Integer aVersion) const
|
||||
{
|
||||
if (aVersion == 1)
|
||||
return write_v1(aShape, aFile);
|
||||
return write_v1(aShape, theOStream);
|
||||
else if (aVersion == 2)
|
||||
return write_v2(aShape, aFile);
|
||||
return write_v2(aShape, theOStream);
|
||||
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
Standard_Boolean VrmlAPI_Writer::write_v1(const TopoDS_Shape& aShape,
|
||||
const Standard_CString aFile) const
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean VrmlAPI_Writer::WriteDoc(const Handle(TDocStd_Document)& theDoc,
|
||||
Standard_OStream& theOStream,
|
||||
const Standard_Real theScale) const
|
||||
{
|
||||
OSD_Path thePath(aFile);
|
||||
TCollection_AsciiString theFile;
|
||||
thePath.SystemName(theFile);
|
||||
const Handle(OSD_FileSystem)& aFileSystem = OSD_FileSystem::DefaultFileSystem();
|
||||
std::shared_ptr<std::ostream> anOutFile =
|
||||
aFileSystem->OpenOStream(theFile, std::ios::out | std::ios::binary);
|
||||
if (anOutFile.get() == NULL)
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
Handle(VrmlConverter_IsoAspect) ia = new VrmlConverter_IsoAspect; // UIso
|
||||
Handle(VrmlConverter_IsoAspect) ia1 = new VrmlConverter_IsoAspect; // VIso
|
||||
VrmlData_Scene aScene;
|
||||
VrmlData_ShapeConvert aConv(aScene, theScale);
|
||||
aConv.ConvertDocument(theDoc);
|
||||
|
||||
theOStream << aScene;
|
||||
theOStream.flush();
|
||||
return theOStream.good();
|
||||
}
|
||||
|
||||
Standard_Boolean VrmlAPI_Writer::write_v1(const TopoDS_Shape& aShape,
|
||||
Standard_OStream& theOStream) const
|
||||
{
|
||||
Handle(VrmlConverter_IsoAspect) ia = new VrmlConverter_IsoAspect;
|
||||
Handle(VrmlConverter_IsoAspect) ia1 = new VrmlConverter_IsoAspect;
|
||||
ia->SetMaterial(myUisoMaterial);
|
||||
ia->SetHasMaterial(Standard_True);
|
||||
myDrawer->SetUIsoAspect(ia);
|
||||
@@ -318,7 +355,6 @@ Standard_Boolean VrmlAPI_Writer::write_v1(const TopoDS_Shape& aShape,
|
||||
if (!aFace.IsNull())
|
||||
{
|
||||
Handle(Poly_Triangulation) aTri = BRep_Tool::Triangulation(aFace, aLoc);
|
||||
|
||||
if (!aTri.IsNull())
|
||||
{
|
||||
hasTriangles = Standard_True;
|
||||
@@ -335,57 +371,61 @@ Standard_Boolean VrmlAPI_Writer::write_v1(const TopoDS_Shape& aShape,
|
||||
VrmlConverter_TypeOfCamera Camera = VrmlConverter_PerspectiveCamera;
|
||||
Handle(VrmlConverter_Projector) projector =
|
||||
new VrmlConverter_Projector(Shapes, Focus, DX, DY, DZ, XUp, YUp, ZUp, Camera, Light);
|
||||
Vrml::VrmlHeaderWriter(*anOutFile);
|
||||
|
||||
Vrml::VrmlHeaderWriter(theOStream);
|
||||
if (myRepresentation == VrmlAPI_BothRepresentation)
|
||||
Vrml::CommentWriter(
|
||||
" This file contents both Shaded and Wire Frame representation of selected Shape ",
|
||||
*anOutFile);
|
||||
theOStream);
|
||||
if (myRepresentation == VrmlAPI_ShadedRepresentation)
|
||||
Vrml::CommentWriter(" This file contents only Shaded representation of selected Shape ",
|
||||
*anOutFile);
|
||||
theOStream);
|
||||
if (myRepresentation == VrmlAPI_WireFrameRepresentation)
|
||||
Vrml::CommentWriter(" This file contents only Wire Frame representation of selected Shape ",
|
||||
*anOutFile);
|
||||
theOStream);
|
||||
|
||||
Vrml_Separator S1;
|
||||
S1.Print(*anOutFile);
|
||||
projector->Add(*anOutFile);
|
||||
S1.Print(theOStream);
|
||||
projector->Add(theOStream);
|
||||
|
||||
Light = VrmlConverter_DirectionLight;
|
||||
Camera = VrmlConverter_OrthographicCamera;
|
||||
Handle(VrmlConverter_Projector) projector1 =
|
||||
new VrmlConverter_Projector(Shapes, Focus, DX, DY, DZ, XUp, YUp, ZUp, Camera, Light);
|
||||
projector1->Add(*anOutFile);
|
||||
projector1->Add(theOStream);
|
||||
|
||||
Vrml_Separator S2;
|
||||
S2.Print(*anOutFile);
|
||||
S2.Print(theOStream);
|
||||
if ((myRepresentation == VrmlAPI_ShadedRepresentation
|
||||
|| myRepresentation == VrmlAPI_BothRepresentation)
|
||||
&& hasTriangles)
|
||||
{
|
||||
Vrml_Group Group1;
|
||||
Group1.Print(*anOutFile);
|
||||
Group1.Print(theOStream);
|
||||
Vrml_Instancing I2("Shaded representation of shape");
|
||||
I2.DEF(*anOutFile);
|
||||
VrmlConverter_ShadedShape::Add(*anOutFile, aShape, myDrawer);
|
||||
Group1.Print(*anOutFile);
|
||||
I2.DEF(theOStream);
|
||||
VrmlConverter_ShadedShape::Add(theOStream, aShape, myDrawer);
|
||||
Group1.Print(theOStream);
|
||||
}
|
||||
if (myRepresentation == VrmlAPI_WireFrameRepresentation
|
||||
|| myRepresentation == VrmlAPI_BothRepresentation)
|
||||
{
|
||||
Vrml_Group Group2;
|
||||
Group2.Print(*anOutFile);
|
||||
Group2.Print(theOStream);
|
||||
Vrml_Instancing I3("Wire Frame representation of shape");
|
||||
I3.DEF(*anOutFile);
|
||||
VrmlConverter_WFDeflectionShape::Add(*anOutFile, aShape, myDrawer);
|
||||
Group2.Print(*anOutFile);
|
||||
I3.DEF(theOStream);
|
||||
VrmlConverter_WFDeflectionShape::Add(theOStream, aShape, myDrawer);
|
||||
Group2.Print(theOStream);
|
||||
}
|
||||
S2.Print(*anOutFile);
|
||||
S1.Print(*anOutFile);
|
||||
S2.Print(theOStream);
|
||||
S1.Print(theOStream);
|
||||
|
||||
anOutFile->flush();
|
||||
return anOutFile->good();
|
||||
theOStream.flush();
|
||||
return theOStream.good();
|
||||
}
|
||||
|
||||
Standard_Boolean VrmlAPI_Writer::write_v2(const TopoDS_Shape& aShape,
|
||||
const Standard_CString aFile) const
|
||||
Standard_Boolean VrmlAPI_Writer::write_v2(const TopoDS_Shape& aShape,
|
||||
Standard_OStream& theOStream) const
|
||||
{
|
||||
Standard_Boolean anExtFace = Standard_False;
|
||||
if (myRepresentation == VrmlAPI_ShadedRepresentation
|
||||
@@ -402,38 +442,7 @@ Standard_Boolean VrmlAPI_Writer::write_v2(const TopoDS_Shape& aShape,
|
||||
aConv.AddShape(aShape);
|
||||
aConv.Convert(anExtFace, anExtEdge);
|
||||
|
||||
const Handle(OSD_FileSystem)& aFileSystem = OSD_FileSystem::DefaultFileSystem();
|
||||
std::shared_ptr<std::ostream> anOutStream =
|
||||
aFileSystem->OpenOStream(aFile, std::ios::out | std::ios::binary);
|
||||
if (anOutStream.get() != NULL)
|
||||
{
|
||||
*anOutStream << aScene;
|
||||
anOutStream->flush();
|
||||
return anOutStream->good();
|
||||
}
|
||||
anOutStream.reset();
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Standard_Boolean VrmlAPI_Writer::WriteDoc(const Handle(TDocStd_Document)& theDoc,
|
||||
const Standard_CString theFile,
|
||||
const Standard_Real theScale) const
|
||||
{
|
||||
VrmlData_Scene aScene;
|
||||
VrmlData_ShapeConvert aConv(aScene, theScale);
|
||||
aConv.ConvertDocument(theDoc);
|
||||
|
||||
const Handle(OSD_FileSystem)& aFileSystem = OSD_FileSystem::DefaultFileSystem();
|
||||
std::shared_ptr<std::ostream> anOutStream =
|
||||
aFileSystem->OpenOStream(theFile, std::ios::out | std::ios::binary);
|
||||
if (anOutStream.get() != NULL)
|
||||
{
|
||||
*anOutStream << aScene;
|
||||
anOutStream->flush();
|
||||
return anOutStream->good();
|
||||
}
|
||||
anOutStream.reset();
|
||||
return Standard_False;
|
||||
theOStream << aScene;
|
||||
theOStream.flush();
|
||||
return theOStream.good();
|
||||
}
|
||||
|
@@ -116,16 +116,28 @@ public:
|
||||
const Standard_CString theFile,
|
||||
const Standard_Real theScale) const;
|
||||
|
||||
//! Converts the shape aShape to
|
||||
//! VRML format of the passed version and writes it to the given stream.
|
||||
Standard_EXPORT Standard_Boolean Write(const TopoDS_Shape& aShape,
|
||||
Standard_OStream& theOStream,
|
||||
const Standard_Integer aVersion = 2) const;
|
||||
|
||||
//! Converts the document to VRML format of the passed version
|
||||
//! and writes it to the given stream.
|
||||
Standard_EXPORT Standard_Boolean WriteDoc(const Handle(TDocStd_Document)& theDoc,
|
||||
Standard_OStream& theOStream,
|
||||
const Standard_Real theScale) const;
|
||||
|
||||
protected:
|
||||
//! Converts the shape aShape to VRML format of version 1.0 and writes it
|
||||
//! to the file identified by aFileName using default parameters.
|
||||
Standard_EXPORT Standard_Boolean write_v1(const TopoDS_Shape& aShape,
|
||||
const Standard_CString aFileName) const;
|
||||
//! to the given stream using default parameters.
|
||||
Standard_EXPORT Standard_Boolean write_v1(const TopoDS_Shape& aShape,
|
||||
Standard_OStream& theOStream) const;
|
||||
|
||||
//! Converts the shape aShape to VRML format of version 2.0 and writes it
|
||||
//! to the file identified by aFileName using default parameters.
|
||||
Standard_EXPORT Standard_Boolean write_v2(const TopoDS_Shape& aShape,
|
||||
const Standard_CString aFileName) const;
|
||||
//! to the given stream using default parameters.
|
||||
Standard_EXPORT Standard_Boolean write_v2(const TopoDS_Shape& aShape,
|
||||
Standard_OStream& theOStream) const;
|
||||
|
||||
private:
|
||||
VrmlAPI_RepresentationOfShape myRepresentation;
|
||||
|
Reference in New Issue
Block a user