//=================================================================================================
+bool DE_ConfigurationNode::IsStreamSupported() const
+{
+ return false;
+}
+
+//=================================================================================================
+
bool DE_ConfigurationNode::CheckExtension(const TCollection_AsciiString& theExtension) const
{
TCollection_AsciiString anExtension(theExtension);
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;
#include <DE_ConfigurationNode.hxx>
#include <Message.hxx>
+#include <NCollection_IndexedDataMap.hxx>
IMPLEMENT_STANDARD_RTTIEXT(DE_Provider, Standard_Transient)
<< " 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;
+}
#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;
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
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
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
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
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
--- /dev/null
+// 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;
+}
\ No newline at end of file
--- /dev/null
+// 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
\ No newline at end of file
#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>
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)
+ 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();
+ for (DE_ConfigurationFormatMap::Iterator aFormatIter(myConfiguration); aFormatIter.More();
+ aFormatIter.Next())
+ {
+ for (DE_ConfigurationVendorMap::Iterator aVendorIter(aFormatIter.Value()); aVendorIter.More();
+ aVendorIter.Next())
{
- aBuffer = new NCollection_Buffer(NCollection_BaseAllocator::CommonBaseAllocator(), 2048);
- aStream->read((char*)aBuffer->ChangeData(), 2048);
- aBuffer->ChangeData()[2047] = '\0';
+ const Handle(DE_ConfigurationNode)& aNode = aVendorIter.Value();
+ 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();
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->IsExportSupported() && aNode->CheckExtension(anExtr)
+ && aNode->UpdateLoad(Standard_False, myKeepUpdates))
{
theProvider = aNode->BuildProvider();
aNode->GlobalParameters = GlobalParameters;
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);
+}
#define _DE_Wrapper_HeaderFile
#include <DE_ConfigurationNode.hxx>
+#include <DE_Provider.hxx>
#include <Message_ProgressRange.hxx>
#include <NCollection_DataMap.hxx>
#include <NCollection_IndexedDataMap.hxx>
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
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
DE_ShapeFixConfigurationNode.cxx
DE_ShapeFixConfigurationNode.hxx
DE_ShapeFixParameters.hxx
+ DE_ValidationUtils.cxx
+ DE_ValidationUtils.hxx
DE_Wrapper.cxx
DE_Wrapper.hxx
)
#include <DEGLTF_Provider.hxx>
+#include <DE_ValidationUtils.hxx>
#include <Message.hxx>
#include <RWGltf_CafWriter.hxx>
#include <TDocStd_Document.hxx>
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());
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());
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);
#include <DEIGES_Provider.hxx>
+#include <DE_ValidationUtils.hxx>
#include <DEIGES_ConfigurationNode.hxx>
#include <IGESCAFControl_Reader.hxx>
#include <IGESCAFControl_Writer.hxx>
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() {}
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
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;
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";
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";
return false;
}
- if (!(aWriter.Write(thePath.ToCString())))
+ if (!aWriter.Write(thePath.ToCString()))
{
Message::SendFail() << "DEIGES_Provider: Error on writing file " << thePath;
resetStatic();
{
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);
+}
+
+*/
#include <DEOBJ_Provider.hxx>
#include <BRep_Builder.hxx>
+#include <DE_ValidationUtils.hxx>
#include <DEOBJ_ConfigurationNode.hxx>
#include <RWObj_CafReader.hxx>
#include <RWObj_CafWriter.hxx>
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());
#include <DEPLY_Provider.hxx>
#include <BRep_Builder.hxx>
+#include <DE_ValidationUtils.hxx>
#include <DEPLY_ConfigurationNode.hxx>
#include <DE_Wrapper.hxx>
#include <Message.hxx>
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());
//=================================================================================================
+bool DESTEP_ConfigurationNode::IsStreamSupported() const
+{
+ return true;
+}
+
+//=================================================================================================
+
TCollection_AsciiString DESTEP_ConfigurationNode::GetFormat() const
{
return TCollection_AsciiString("STEP");
//! @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;
#include <DESTEP_Provider.hxx>
+#include <DE_ValidationUtils.hxx>
#include <DESTEP_ConfigurationNode.hxx>
#include <DESTEP_Parameters.hxx>
#include <Interface_Static.hxx>
#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() {}
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
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);
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());
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";
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());
//=================================================================================================
+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");
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
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
--- /dev/null
+// 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);
+}
\ No newline at end of file
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
//=================================================================================================
+bool DESTL_ConfigurationNode::IsStreamSupported() const
+{
+ return true;
+}
+
+//=================================================================================================
+
TCollection_AsciiString DESTL_ConfigurationNode::GetFormat() const
{
return TCollection_AsciiString("STL");
//! @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;
#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)
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;
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;
}
- Handle(DESTL_ConfigurationNode) aNode = Handle(DESTL_ConfigurationNode)::DownCast(GetNode());
- if (aNode->GlobalParameters.LengthUnit != 1.0)
+ if (!DE_ValidationUtils::ValidateConfigurationNode(GetNode(),
+ STANDARD_TYPE(DESTL_ConfigurationNode),
+ aContext))
{
- 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";
+ return false;
}
+ Handle(DESTL_ConfigurationNode) aNode = Handle(DESTL_ConfigurationNode)::DownCast(GetNode());
+ DE_ValidationUtils::WarnLengthUnitNotSupported(aNode->GlobalParameters.LengthUnit, aContext);
+
+ TopoDS_Shape aShape;
if (aLabels.Length() == 1)
{
aShape = aSTool->GetShape(aLabels.Value(1));
}
aShape = aComp;
}
+
return Write(thePath, aShape, theProgress);
}
{
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)
return false;
}
}
+
if (!aNode->InternalParameters.ReadBRep)
{
Handle(Poly_Triangulation) aTriangulation =
}
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;
{
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;
}
//=================================================================================================
+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");
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
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
--- /dev/null
+// 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());
+}
set(OCCT_TKDESTL_GTests_FILES_LOCATION "${CMAKE_CURRENT_LIST_DIR}")
set(OCCT_TKDESTL_GTests_FILES
+ DESTL_Provider_Test.cxx
)
#include <OSD_FileSystem.hxx>
#include <OSD_OpenFile.hxx>
#include <RWStl_Reader.hxx>
+#include <Standard_ReadLineBuffer.hxx>
+#include <iomanip>
+#include <iostream>
+#include <cstring>
namespace
{
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);
}
//=================================================================================================
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);
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());
-
- if (fprintf(theFile, "%s", aBuffer) < 0)
+ 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 (theStream.fail())
{
return Standard_False;
}
}
}
- 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;
}
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();
{
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;
}
// 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;
}
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);
+ }
+}
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;
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(
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());
+
+ //! 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());
- //! Write binary version.
- static Standard_Boolean writeBinary(const Handle(Poly_Triangulation)& theMesh,
- FILE* theFile,
- const Message_ProgressRange& theProgress);
+ //! 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
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;
+}
#define _StlAPI_Reader_HeaderFile
#include <Standard_Handle.hxx>
+#include <Standard_IStream.hxx>
class TopoDS_Shape;
//! 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
#include <TopoDS_Face.hxx>
#include <TopExp_Explorer.hxx>
#include <Poly_Triangulation.hxx>
+#include <fstream>
//=================================================================================================
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;
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))
{
}
return isDone;
-}
+}
\ No newline at end of file
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;
};
//=================================================================================================
+bool DEVRML_ConfigurationNode::IsStreamSupported() const
+{
+ return true;
+}
+
+//=================================================================================================
+
TCollection_AsciiString DEVRML_ConfigurationNode::GetFormat() const
{
return TCollection_AsciiString("VRML");
//! @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;
#include <DEVRML_Provider.hxx>
+#include <DE_ValidationUtils.hxx>
#include <DEVRML_ConfigurationNode.hxx>
#include <Message.hxx>
#include <OSD_Path.hxx>
#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() {}
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);
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
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);
}
//=================================================================================================
//=================================================================================================
+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");
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
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
--- /dev/null
+// 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());
+}
\ No newline at end of file
set(OCCT_TKDEVRML_GTests_FILES_LOCATION "${CMAKE_CURRENT_LIST_DIR}")
set(OCCT_TKDEVRML_GTests_FILES
+ DEVRML_Provider_Test.cxx
)
const Standard_CString aFile,
const Standard_Integer aVersion) const
{
- if (aVersion == 1)
- return write_v1(aShape, aFile);
- else if (aVersion == 2)
- return write_v2(aShape, aFile);
+ 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 Standard_False;
+ return Write(aShape, *anOutStream, aVersion);
}
-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,
+ const Standard_CString theFile,
+ 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 =
+ std::shared_ptr<std::ostream> anOutStream =
aFileSystem->OpenOStream(theFile, std::ios::out | std::ios::binary);
- if (anOutFile.get() == NULL)
+ if (anOutStream.get() == NULL)
{
return Standard_False;
}
- Handle(VrmlConverter_IsoAspect) ia = new VrmlConverter_IsoAspect; // UIso
- Handle(VrmlConverter_IsoAspect) ia1 = new VrmlConverter_IsoAspect; // VIso
+
+ 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, theOStream);
+ else if (aVersion == 2)
+ return write_v2(aShape, theOStream);
+
+ return Standard_False;
+}
+
+//=================================================================================================
+
+Standard_Boolean VrmlAPI_Writer::WriteDoc(const Handle(TDocStd_Document)& theDoc,
+ Standard_OStream& theOStream,
+ const Standard_Real theScale) const
+{
+ 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);
if (!aFace.IsNull())
{
Handle(Poly_Triangulation) aTri = BRep_Tool::Triangulation(aFace, aLoc);
-
if (!aTri.IsNull())
{
hasTriangles = Standard_True;
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
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();
}
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;