From fc552d842e7da8c0f9b0f705235121a336ab9ee9 Mon Sep 17 00:00:00 2001 From: kgv Date: Fri, 3 May 2019 17:50:28 +0300 Subject: [PATCH] 0030692: Data Exchange - introduce base framework RWMesh for importing mesh data formats into XDE document RWMesh_CafReader - added new interface class for common workflow for reading mesh data files into XDE document. OSD_Path - added auxiliary methods splitting path into folder+file pair and checking relative/absolute path semantically: OSD_Path::FolderAndFileFromPath(), ::IsRelativePath(), ::IsAbsolutePath(). V3d_TypeOfOrientation enumeration has been extended with aliases (like front/left) for Z-up and Y-up conventions. V3d_View::SetProj() now accepts argument for asking Y-up instead of Z-up. Added command vviewproj defining standard camera direction. Commands vaxo, vleft, vright, vtop, vbottom, vfront, vbottom now redirect to vviewproj. TCollection_AsciiString::SubString() now uses Standard_OutOfRange_Always_Raise_if() to suppress GCC warning. Eliminated gcc 4.4 compilation errors within Standard_OutOfRange_Raise_if,Standard_RangeError_Raise_if. --- adm/MODULES | 2 +- adm/UDLIST | 2 + src/FSD/FILES | 2 + src/FSD/FSD_Base64Decoder.cxx | 87 ++++ src/FSD/FSD_Base64Decoder.hxx | 30 ++ src/Image/FILES | 2 + src/Image/Image_Texture.cxx | 304 ++++++++++++ src/Image/Image_Texture.hxx | 115 +++++ src/OS/DataExchange.tcl | 2 +- src/OSD/OSD_Path.cxx | 37 ++ src/OSD/OSD_Path.hxx | 120 ++++- src/QANCollection/QANCollection_Test.cxx | 111 +++++ src/RWMesh/FILES | 6 + src/RWMesh/RWMesh_CafReader.cxx | 387 +++++++++++++++ src/RWMesh/RWMesh_CafReader.hxx | 228 +++++++++ src/RWMesh/RWMesh_CoordinateSystem.hxx | 34 ++ .../RWMesh_CoordinateSystemConverter.cxx | 77 +++ .../RWMesh_CoordinateSystemConverter.hxx | 196 ++++++++ src/RWMesh/RWMesh_NodeAttributes.hxx | 32 ++ src/Standard/FILES | 1 + src/Standard/Standard_OutOfRange.hxx | 10 +- src/Standard/Standard_RangeError.hxx | 2 +- src/Standard/Standard_ReadBuffer.hxx | 145 ++++++ src/TCollection/TCollection_AsciiString.lxx | 6 +- src/TKRWMesh/CMakeLists.txt | 3 + src/TKRWMesh/EXTERNLIB | 9 + src/TKRWMesh/FILES | 2 + src/TKRWMesh/PACKAGES | 1 + src/TKXSDRAW/EXTERNLIB | 2 + src/V3d/V3d_TypeOfOrientation.hxx | 83 ++-- src/V3d/V3d_View.cxx | 48 +- src/V3d/V3d_View.hxx | 5 +- src/ViewerTest/ViewerTest_ViewerCommands.cxx | 395 ++++++++++++---- src/XCAFPrs/FILES | 4 + src/XCAFPrs/XCAFPrs_DocumentExplorer.cxx | 441 ++++++++++++++++++ src/XCAFPrs/XCAFPrs_DocumentExplorer.hxx | 174 +++++++ src/XCAFPrs/XCAFPrs_DocumentIdIterator.hxx | 90 ++++ src/XCAFPrs/XCAFPrs_DocumentNode.hxx | 39 ++ tests/collections/n/osdpath | 48 ++ 39 files changed, 3111 insertions(+), 171 deletions(-) create mode 100644 src/FSD/FSD_Base64Decoder.cxx create mode 100644 src/FSD/FSD_Base64Decoder.hxx create mode 100644 src/Image/Image_Texture.cxx create mode 100644 src/Image/Image_Texture.hxx create mode 100644 src/RWMesh/FILES create mode 100644 src/RWMesh/RWMesh_CafReader.cxx create mode 100644 src/RWMesh/RWMesh_CafReader.hxx create mode 100644 src/RWMesh/RWMesh_CoordinateSystem.hxx create mode 100644 src/RWMesh/RWMesh_CoordinateSystemConverter.cxx create mode 100644 src/RWMesh/RWMesh_CoordinateSystemConverter.hxx create mode 100644 src/RWMesh/RWMesh_NodeAttributes.hxx create mode 100644 src/Standard/Standard_ReadBuffer.hxx create mode 100644 src/TKRWMesh/CMakeLists.txt create mode 100644 src/TKRWMesh/EXTERNLIB create mode 100644 src/TKRWMesh/FILES create mode 100644 src/TKRWMesh/PACKAGES create mode 100644 src/XCAFPrs/XCAFPrs_DocumentExplorer.cxx create mode 100644 src/XCAFPrs/XCAFPrs_DocumentExplorer.hxx create mode 100644 src/XCAFPrs/XCAFPrs_DocumentIdIterator.hxx create mode 100644 src/XCAFPrs/XCAFPrs_DocumentNode.hxx create mode 100644 tests/collections/n/osdpath diff --git a/adm/MODULES b/adm/MODULES index e65fb379ee..2ec6ef3029 100644 --- a/adm/MODULES +++ b/adm/MODULES @@ -3,5 +3,5 @@ ModelingData TKG2d TKG3d TKGeomBase TKBRep ModelingAlgorithms TKGeomAlgo TKTopAlgo TKPrim TKBO TKBool TKHLR TKFillet TKOffset TKFeat TKMesh TKXMesh TKShHealing Visualization TKService TKV3d TKOpenGl TKMeshVS TKIVtk TKD3DHost ApplicationFramework TKCDF TKLCAF TKCAF TKBinL TKXmlL TKBin TKXml TKStdL TKStd TKTObj TKBinTObj TKXmlTObj TKVCAF -DataExchange TKXSBase TKSTEPBase TKSTEPAttr TKSTEP209 TKSTEP TKIGES TKXCAF TKXDEIGES TKXDESTEP TKSTL TKVRML TKXmlXCAF TKBinXCAF +DataExchange TKXSBase TKSTEPBase TKSTEPAttr TKSTEP209 TKSTEP TKIGES TKXCAF TKXDEIGES TKXDESTEP TKSTL TKVRML TKXmlXCAF TKBinXCAF TKRWMesh Draw TKDraw TKTopTest TKViewerTest TKXSDRAW TKDCAF TKXDEDRAW TKTObjDRAW TKQADraw TKIVtkDraw DRAWEXE diff --git a/adm/UDLIST b/adm/UDLIST index 79e58c7eb1..032662b297 100644 --- a/adm/UDLIST +++ b/adm/UDLIST @@ -439,3 +439,5 @@ n Geom2dEvaluator t TKVCAF n XCAFView n XCAFNoteObjects +t TKRWMesh +n RWMesh diff --git a/src/FSD/FILES b/src/FSD/FILES index 5b2934ed31..20ecdc5ef1 100755 --- a/src/FSD/FILES +++ b/src/FSD/FILES @@ -1,4 +1,6 @@ FILES +FSD_Base64Decoder.cxx +FSD_Base64Decoder.hxx FSD_BinaryFile.cxx FSD_BinaryFile.hxx FSD_BStream.hxx diff --git a/src/FSD/FSD_Base64Decoder.cxx b/src/FSD/FSD_Base64Decoder.cxx new file mode 100644 index 0000000000..0959f1eb85 --- /dev/null +++ b/src/FSD/FSD_Base64Decoder.cxx @@ -0,0 +1,87 @@ +// Author: Kirill Gavrilov +// Copyright (c) 2016-2019 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#include + +#include +#include + +// ======================================================================= +// function : Decode +// purpose : +// ======================================================================= +Handle(NCollection_Buffer) FSD_Base64Decoder::Decode (const Standard_Byte* theStr, + const Standard_Size theLen) +{ + //! Look-up table for decoding base64 stream. + static const Standard_Byte THE_BASE64_FROM[128] = + { + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 62, 255, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 0, 255, 255, 255, + 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 63, + 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255 + }; + + Handle(NCollection_Buffer) aData = new NCollection_Buffer (NCollection_BaseAllocator::CommonBaseAllocator()); + if (!aData->Allocate (3 * theLen / 4)) + { + Message::DefaultMessenger()->Send ("Fail to allocate memory.", Message_Fail); + return Handle(NCollection_Buffer)(); + } + + Standard_Byte* aDataPtr = aData->ChangeData(); + const Standard_Byte* anEnd = theStr + theLen; + for (const Standard_Byte* aByteIter = theStr; aByteIter < anEnd; aByteIter += 4) + { + // get values for each group of four base 64 characters + const Standard_Byte b4[4] = + { + aByteIter + 0 < anEnd && aByteIter[0] <= 'z' ? THE_BASE64_FROM[aByteIter[0]] : Standard_Byte(0xFF), + aByteIter + 1 < anEnd && aByteIter[1] <= 'z' ? THE_BASE64_FROM[aByteIter[1]] : Standard_Byte(0xFF), + aByteIter + 2 < anEnd && aByteIter[2] <= 'z' ? THE_BASE64_FROM[aByteIter[2]] : Standard_Byte(0xFF), + aByteIter + 3 < anEnd && aByteIter[3] <= 'z' ? THE_BASE64_FROM[aByteIter[3]] : Standard_Byte(0xFF) + }; + + // transform into a group of three bytes + const Standard_Byte b3[3] = + { + Standard_Byte(((b4[0] & 0x3F) << 2) + ((b4[1] & 0x30) >> 4)), + Standard_Byte(((b4[1] & 0x0F) << 4) + ((b4[2] & 0x3C) >> 2)), + Standard_Byte(((b4[2] & 0x03) << 6) + ((b4[3] & 0x3F) >> 0)) + }; + + // add the byte to the return value if it isn't part of an '=' character (indicated by 0xFF) + if (b4[1] != 0xFF) + { + *aDataPtr = b3[0]; + ++aDataPtr; + } + if (b4[2] != 0xFF) + { + *aDataPtr = b3[1]; + ++aDataPtr; + } + if (b4[3] != 0xFF) + { + *aDataPtr = b3[2]; + ++aDataPtr; + } + } + + return aData; +} diff --git a/src/FSD/FSD_Base64Decoder.hxx b/src/FSD/FSD_Base64Decoder.hxx new file mode 100644 index 0000000000..1c1abc353b --- /dev/null +++ b/src/FSD/FSD_Base64Decoder.hxx @@ -0,0 +1,30 @@ +// Author: Kirill Gavrilov +// Copyright (c) 2016-2019 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 _FSD_Base64Decoder_HeaderFile +#define _FSD_Base64Decoder_HeaderFile + +#include + +//! Tool decoding base64 stream. +class FSD_Base64Decoder +{ +public: + + //! Function decoding base64 stream. + Standard_EXPORT static Handle(NCollection_Buffer) Decode (const Standard_Byte* theStr, + const Standard_Size theLen); +}; + +#endif // _FSD_Base64Decoder_HeaderFile diff --git a/src/Image/FILES b/src/Image/FILES index 40118d5bca..8055875c29 100755 --- a/src/Image/FILES +++ b/src/Image/FILES @@ -8,5 +8,7 @@ Image_PixMap.cxx Image_PixMap.hxx Image_PixMapData.hxx Image_PixMapTypedData.hxx +Image_Texture.cxx +Image_Texture.hxx Image_VideoRecorder.cxx Image_VideoRecorder.hxx diff --git a/src/Image/Image_Texture.cxx b/src/Image/Image_Texture.cxx new file mode 100644 index 0000000000..6e9e752147 --- /dev/null +++ b/src/Image/Image_Texture.cxx @@ -0,0 +1,304 @@ +// Author: Kirill Gavrilov +// Copyright (c) 2015-2019 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#include + +#include +#include +#include +#include + +IMPLEMENT_STANDARD_RTTIEXT(Image_Texture, Standard_Transient) + +// ================================================================ +// Function : Image_Texture +// Purpose : +// ================================================================ +Image_Texture::Image_Texture (const TCollection_AsciiString& theFileName) +: myImagePath (theFileName), + myOffset (-1), + myLength (-1) +{ + // share textures with unique file paths + if (!theFileName.IsEmpty()) + { + myTextureId = TCollection_AsciiString ("texture://") + theFileName; + } +} + +// ================================================================ +// Function : Image_Texture +// Purpose : +// ================================================================ +Image_Texture::Image_Texture (const TCollection_AsciiString& theFileName, + int64_t theOffset, + int64_t theLength) +: myImagePath (theFileName), + myOffset (theOffset), + myLength (theLength) +{ + // share textures with unique file paths + if (!theFileName.IsEmpty()) + { + char aBuff[60]; + Sprintf (aBuff, ";%" PRId64 ",%" PRId64, theOffset, theLength); + myTextureId = TCollection_AsciiString ("texture://") + theFileName + aBuff; + } +} + +// ================================================================ +// Function : Image_Texture +// Purpose : +// ================================================================ +Image_Texture::Image_Texture (const Handle(NCollection_Buffer)& theBuffer, + const TCollection_AsciiString& theId) +: myBuffer (theBuffer), + myOffset (-1), + myLength (-1) +{ + if (!theId.IsEmpty()) + { + myTextureId = TCollection_AsciiString ("texturebuf://") + theId; + } +} + +// ================================================================ +// Function : ReadImage +// Purpose : +// ================================================================ +Handle(Image_PixMap) Image_Texture::ReadImage() const +{ + Handle(Image_PixMap) anImage; + if (!myBuffer.IsNull()) + { + anImage = loadImageBuffer (myBuffer, myTextureId); + } + else if (myOffset >= 0) + { + anImage = loadImageOffset (myImagePath, myOffset, myLength); + } + else + { + anImage = loadImageFile (myImagePath); + } + + if (anImage.IsNull()) + { + return Handle(Image_PixMap)(); + } + return anImage; +} + +// ================================================================ +// Function : loadImageFile +// Purpose : +// ================================================================ +Handle(Image_PixMap) Image_Texture::loadImageFile (const TCollection_AsciiString& thePath) const +{ + Handle(Image_AlienPixMap) anImage = new Image_AlienPixMap(); + if (!anImage->Load (thePath)) + { + return Handle(Image_PixMap)(); + } + return anImage; +} + +// ================================================================ +// Function : loadImageBuffer +// Purpose : +// ================================================================ +Handle(Image_PixMap) Image_Texture::loadImageBuffer (const Handle(NCollection_Buffer)& theBuffer, + const TCollection_AsciiString& theId) const +{ + if (theBuffer.IsNull()) + { + return Handle(Image_PixMap)(); + } + else if (theBuffer->Size() > (Standard_Size )IntegerLast()) + { + Message::DefaultMessenger()->Send (TCollection_AsciiString ("Error: Image file size is too big '") + theId + "'.", Message_Fail); + return Handle(Image_PixMap)(); + } + + Handle(Image_AlienPixMap) anImage = new Image_AlienPixMap(); + if (!anImage->Load (theBuffer->Data(), (int )theBuffer->Size(), theId)) + { + return Handle(Image_PixMap)(); + } + return anImage; +} + +// ================================================================ +// Function : loadImageOffset +// Purpose : +// ================================================================ +Handle(Image_PixMap) Image_Texture::loadImageOffset (const TCollection_AsciiString& thePath, + int64_t theOffset, + int64_t theLength) const +{ + if (theLength > IntegerLast()) + { + Message::DefaultMessenger()->Send (TCollection_AsciiString ("Error: Image file size is too big '") + thePath + "'.", Message_Fail); + return Handle(Image_PixMap)(); + } + + std::ifstream aFile; + OSD_OpenStream (aFile, thePath.ToCString(), std::ios::in | std::ios::binary); + if (!aFile) + { + Message::DefaultMessenger()->Send (TCollection_AsciiString ("Error: Image file '") + thePath + "' cannot be opened.", Message_Fail); + return Handle(Image_PixMap)(); + } + aFile.seekg ((std::streamoff )theOffset, std::ios_base::beg); + if (!aFile.good()) + { + Message::DefaultMessenger()->Send (TCollection_AsciiString ("Error: Image is defined with invalid file offset '") + thePath + "'.", Message_Fail); + return Handle(Image_PixMap)(); + } + + Handle(Image_AlienPixMap) anImage = new Image_AlienPixMap(); + if (!anImage->Load (aFile, thePath)) + { + return Handle(Image_PixMap)(); + } + return anImage; +} + +// ================================================================ +// Function : ProbeImageFileFormat +// Purpose : +// ================================================================ +TCollection_AsciiString Image_Texture::ProbeImageFileFormat() const +{ + static const int THE_PROBE_SIZE = 20; + char aBuffer[THE_PROBE_SIZE]; + if (!myBuffer.IsNull()) + { + memcpy (aBuffer, myBuffer->Data(), myBuffer->Size() < THE_PROBE_SIZE ? myBuffer->Size() : THE_PROBE_SIZE); + } + else + { + std::ifstream aFileIn; + OSD_OpenStream (aFileIn, myImagePath.ToCString(), std::ios::in | std::ios::binary); + if (!aFileIn) + { + Message::DefaultMessenger()->Send (TCollection_AsciiString ("Error: Unable to open file ") + myImagePath + "!", Message_Fail); + return false; + } + if (myOffset >= 0) + { + aFileIn.seekg ((std::streamoff )myOffset, std::ios_base::beg); + if (!aFileIn.good()) + { + Message::DefaultMessenger()->Send (TCollection_AsciiString ("Error: Image is defined with invalid file offset '") + myImagePath + "'.", Message_Fail); + return false; + } + } + + if (!aFileIn.read (aBuffer, THE_PROBE_SIZE)) + { + Message::DefaultMessenger()->Send (TCollection_AsciiString ("Error: unable to read image file '") + myImagePath + "'", Message_Fail); + return false; + } + } + + if (memcmp (aBuffer, "\x89" "PNG\r\n" "\x1A" "\n", 8) == 0) + { + return "png"; + } + else if (memcmp (aBuffer, "\xFF\xD8\xFF", 3) == 0) + { + return "jpg"; + } + else if (memcmp (aBuffer, "GIF87a", 6) == 0 + || memcmp (aBuffer, "GIF89a", 6) == 0) + { + return "gif"; + } + else if (memcmp (aBuffer, "II\x2A\x00", 4) == 0 + || memcmp (aBuffer, "MM\x00\x2A", 4) == 0) + { + return "tiff"; + } + else if (memcmp (aBuffer, "BM", 2) == 0) + { + return "bmp"; + } + else if (memcmp (aBuffer, "RIFF", 4) == 0 + && memcmp (aBuffer + 8, "WEBP", 4) == 0) + { + return "webp"; + } + return ""; +} + +// ================================================================ +// Function : WriteImage +// Purpose : +// ================================================================ +Standard_Boolean Image_Texture::WriteImage (const TCollection_AsciiString& theFile) +{ + Handle(NCollection_Buffer) aBuffer = myBuffer; + if (myBuffer.IsNull()) + { + std::ifstream aFileIn; + OSD_OpenStream (aFileIn, myImagePath.ToCString(), std::ios::in | std::ios::binary); + if (!aFileIn) + { + Message::DefaultMessenger()->Send (TCollection_AsciiString ("Error: Unable to open file ") + myImagePath + "!", Message_Fail); + return Standard_False; + } + + Standard_Size aLen = (Standard_Size )myLength; + if (myOffset >= 0) + { + aFileIn.seekg ((std::streamoff )myOffset, std::ios_base::beg); + if (!aFileIn.good()) + { + Message::DefaultMessenger()->Send (TCollection_AsciiString ("Error: Image is defined with invalid file offset '") + myImagePath + "'.", Message_Fail); + return Standard_False; + } + } + else + { + aFileIn.seekg (0, std::ios_base::end); + aLen = (Standard_Size )aFileIn.tellg(); + aFileIn.seekg (0, std::ios_base::beg); + } + + aBuffer = new NCollection_Buffer (NCollection_BaseAllocator::CommonBaseAllocator(), aLen); + if (!aFileIn.read ((char* )aBuffer->ChangeData(), aBuffer->Size())) + { + Message::DefaultMessenger()->Send (TCollection_AsciiString ("Error: unable to read image file '") + myImagePath + "'", Message_Fail); + return Standard_False; + } + } + + std::ofstream aFileOut; + OSD_OpenStream (aFileOut, theFile.ToCString(), std::ios::out | std::ios::binary | std::ios::trunc); + if (!aFileOut) + { + Message::DefaultMessenger()->Send (TCollection_AsciiString ("Error: Unable to create file ") + theFile + "!", Message_Fail); + return Standard_False; + } + + aFileOut.write ((const char* )aBuffer->Data(), aBuffer->Size()); + aFileOut.close(); + if (!aFileOut.good()) + { + Message::DefaultMessenger()->Send (TCollection_AsciiString ("Error: Unable to write file ") + theFile + "!", Message_Fail); + return Standard_False; + } + return Standard_True; +} diff --git a/src/Image/Image_Texture.hxx b/src/Image/Image_Texture.hxx new file mode 100644 index 0000000000..f55458bcf5 --- /dev/null +++ b/src/Image/Image_Texture.hxx @@ -0,0 +1,115 @@ +// Author: Kirill Gavrilov +// Copyright (c) 2015-2019 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 _Image_Texture_HeaderFile +#define _Image_Texture_HeaderFile + +#include +#include + +class Image_PixMap; + +//! Texture image definition. +//! The image can be stored as path to image file, as file path with the given offset and as a data buffer of encoded image. +class Image_Texture : public Standard_Transient +{ + DEFINE_STANDARD_RTTIEXT(Image_Texture, Standard_Transient) +public: + + //! Constructor pointing to file location. + Standard_EXPORT explicit Image_Texture (const TCollection_AsciiString& theFileName); + + //! Constructor pointing to file part. + Standard_EXPORT explicit Image_Texture (const TCollection_AsciiString& theFileName, + int64_t theOffset, + int64_t theLength); + + //! Constructor pointing to buffer. + Standard_EXPORT explicit Image_Texture (const Handle(NCollection_Buffer)& theBuffer, + const TCollection_AsciiString& theId); + + //! Return generated texture id. + const TCollection_AsciiString& TextureId() const { return myTextureId; } + + //! Return image file path. + const TCollection_AsciiString& FilePath() const { return myImagePath; } + + //! Return offset within file. + int64_t FileOffset() const { return myOffset; } + + //! Return length of image data within the file after offset. + int64_t FileLength() const { return myLength; } + + //! Return buffer holding encoded image content. + const Handle(NCollection_Buffer)& DataBuffer() const { return myBuffer; } + + //! Return image file format. + Standard_EXPORT TCollection_AsciiString ProbeImageFileFormat() const; + + //! Image reader. + Standard_EXPORT virtual Handle(Image_PixMap) ReadImage() const; + + //! Write image to specified file without decoding data. + Standard_EXPORT virtual Standard_Boolean WriteImage (const TCollection_AsciiString& theFile); + +public: //! @name hasher interface + + //! Hash value, for Map interface. + static int HashCode (const Handle(Image_Texture)& theTexture, const int theUpper) + { + return !theTexture.IsNull() + ? TCollection_AsciiString::HashCode (theTexture->myTextureId, theUpper) + : 0; + } + + //! Matching two instances, for Map interface. + static Standard_Boolean IsEqual (const Handle(Image_Texture)& theTex1, + const Handle(Image_Texture)& theTex2) + { + if (theTex1.IsNull() != theTex2.IsNull()) + { + return Standard_False; + } + else if (theTex1.IsNull()) + { + return Standard_True; + } + return theTex1->myTextureId.IsEqual (theTex2->myTextureId); + } + +protected: + + //! Read image from normal image file. + Standard_EXPORT virtual Handle(Image_PixMap) loadImageFile (const TCollection_AsciiString& thePath) const; + + //! Read image from file with some offset. + Standard_EXPORT virtual Handle(Image_PixMap) loadImageOffset (const TCollection_AsciiString& thePath, + int64_t theOffset, + int64_t theLength) const; + + //! Read image from buffer. + Standard_EXPORT virtual Handle(Image_PixMap) loadImageBuffer (const Handle(NCollection_Buffer)& theBuffer, + const TCollection_AsciiString& theId) const; + +protected: + + TCollection_AsciiString myTextureId; //!< generated texture id + TCollection_AsciiString myImagePath; //!< image file path + Handle(NCollection_Buffer) myBuffer; //!< image buffer + int64_t myOffset; //!< offset within file + int64_t myLength; //!< length within file + +}; + +#endif // _Image_Texture_HeaderFile diff --git a/src/OS/DataExchange.tcl b/src/OS/DataExchange.tcl index 75cb56bf05..e72af9b7bd 100644 --- a/src/OS/DataExchange.tcl +++ b/src/OS/DataExchange.tcl @@ -17,7 +17,7 @@ proc DataExchange:toolkits { } { return [list TKXSBase TKSTEPBase TKSTEPAttr TKSTEP209 TKSTEP TKIGES \ TKXCAF TKXDEIGES TKXDESTEP \ - TKSTL TKVRML TKXmlXCAF TKBinXCAF] + TKSTL TKVRML TKXmlXCAF TKBinXCAF TKRWMesh] } ;# ;# Autres UDs a prendre. diff --git a/src/OSD/OSD_Path.cxx b/src/OSD/OSD_Path.cxx index 397fadb4a3..edd5189de2 100644 --- a/src/OSD/OSD_Path.cxx +++ b/src/OSD/OSD_Path.cxx @@ -1635,3 +1635,40 @@ Standard_Boolean LocateExecFile(OSD_Path& ) { return Standard_False ; } + +// ======================================================================= +// function : FolderAndFileFromPath +// purpose : +// ======================================================================= +void OSD_Path::FolderAndFileFromPath (const TCollection_AsciiString& theFilePath, + TCollection_AsciiString& theFolder, + TCollection_AsciiString& theFileName) +{ + Standard_Integer aLastSplit = -1; + Standard_CString aString = theFilePath.ToCString(); + for (Standard_Integer anIter = 0; anIter < theFilePath.Length(); ++anIter) + { + if (aString[anIter] == '/' + || aString[anIter] == '\\') + { + aLastSplit = anIter; + } + } + + if (aLastSplit == -1) + { + theFolder.Clear(); + theFileName = theFilePath; + return; + } + + theFolder = theFilePath.SubString (1, aLastSplit + 1); + if (aLastSplit + 2 <= theFilePath.Length()) + { + theFileName = theFilePath.SubString (aLastSplit + 2, theFilePath.Length()); + } + else + { + theFileName.Clear(); + } +} diff --git a/src/OSD/OSD_Path.hxx b/src/OSD/OSD_Path.hxx index 66cc192095..163c80487b 100644 --- a/src/OSD/OSD_Path.hxx +++ b/src/OSD/OSD_Path.hxx @@ -20,27 +20,14 @@ #include #include #include - #include -#include #include -#include -class Standard_ConstructionError; -class Standard_NullObject; -class OSD_OSDError; -class Standard_NumericError; -class Standard_ProgramError; -class TCollection_AsciiString; - - class OSD_Path { public: - DEFINE_STANDARD_ALLOC - //! Creates a Path object initialized to an empty string. //! i.e. current directory. Standard_EXPORT OSD_Path(); @@ -199,10 +186,12 @@ public: //! "which" Unix utility. Uses the path environment variable. //! Returns False if executable file not found. Standard_EXPORT Standard_Boolean LocateExecFile (OSD_Path& aPath); - + +public: + //! Returns the relative file path between the absolute directory //! path and the absolute file path . - //! If starts with "/", pathes are handled as + //! If starts with "/", paths are handled as //! on Unix, if it starts with a letter followed by ":", as on //! WNT. In particular on WNT directory names are not key sensitive. //! If handling fails, an empty string is returned. @@ -215,18 +204,108 @@ public: //! If handling fails, an empty string is returned. Standard_EXPORT static TCollection_AsciiString AbsolutePath (const TCollection_AsciiString& DirPath, const TCollection_AsciiString& RelFilePath); + //! Split absolute filepath into folder path and file name. + //! Example: IN theFilePath ='/media/cdrom/image.jpg' + //! OUT theFolder ='/media/cdrom/' + //! OUT theFileName ='image.jpg' + //! @param theFilePath [in] file path + //! @param theFolder [out] folder path (with trailing separator) + //! @param theFileName [out] file name + Standard_EXPORT static void FolderAndFileFromPath (const TCollection_AsciiString& theFilePath, + TCollection_AsciiString& theFolder, + TCollection_AsciiString& theFileName); + //! Detect absolute DOS-path also used in Windows. + //! The total path length is limited to 256 characters. + //! Sample path: + //! C:\folder\file + //! @return true if DOS path syntax detected. + static Standard_Boolean IsDosPath (const char* thePath) { return thePath[0] != '\0' && thePath[1] == ':'; } + //! Detect extended-length NT path (can be only absolute). + //! Approximate maximum path is 32767 characters. + //! Sample path: + //! \\?\D:\very long path + //! File I/O functions in the Windows API convert "/" to "\" as part of converting the name to an NT-style name, except when using the "\\?\" prefix. + //! @return true if extended-length NT path syntax detected. + static Standard_Boolean IsNtExtendedPath (const char* thePath) { return ::memcmp (thePath, "\\\\?\\", 4) == 0; } -protected: + //! UNC is a naming convention used primarily to specify and map network drives in Microsoft Windows. + //! Sample path: + //! \\server\share\file + //! @return true if UNC path syntax detected. + static Standard_Boolean IsUncPath (const char* thePath) + { + if (::memcmp (thePath, "\\\\", 2) == 0) + { + return thePath[2] != '?' + || IsUncExtendedPath (thePath); + } + return ::memcmp (thePath, "//", 2) == 0; + } + //! Detect extended-length UNC path. + //! Sample path: + //! \\?\UNC\server\share + //! @return true if extended-length UNC path syntax detected. + static Standard_Boolean IsUncExtendedPath (const char* thePath) { return ::memcmp (thePath, "\\\\?\\UNC\\", 8) == 0; } + //! Detect absolute UNIX-path. + //! Sample path: + //! /media/cdrom/file + //! @return true if UNIX path syntax detected. + static Standard_Boolean IsUnixPath (const char* thePath) { return thePath[0] == '/' && thePath[1] != '/'; } + //! Detect special URLs on Android platform. + //! Sample path: + //! content://filename + //! @return true if content path syntax detected + static Standard_Boolean IsContentProtocolPath (const char* thePath) { return ::memcmp (thePath, "content://", 10) == 0; } + //! Detect remote protocol path (http / ftp / ...). + //! Actually shouldn't be remote... + //! Sample path: + //! http://domain/path/file + //! @return true if remote protocol path syntax detected. + static Standard_Boolean IsRemoteProtocolPath (const char* thePath) + { + const char* anIter = thePath; + if (*anIter == ':') + { + return false; + } + for (; *anIter != '\0'; ++anIter) + { + if (*anIter == ':') + { + return *(++anIter) == '/' + && *(++anIter) == '/'; + } + } + return false; + } -private: + //! Method to recognize path is absolute or not. + //! Detection is based on path syntax - no any filesystem / network access performed. + //! @return true if path is incomplete (relative). + static Standard_Boolean IsRelativePath (const char* thePath) + { + return !IsUncPath (thePath) + && !IsDosPath (thePath) + && !IsNtExtendedPath (thePath) + && !IsUnixPath (thePath) + && !IsRemoteProtocolPath (thePath); + } + //! Method to recognize path is absolute or not. + //! Detection is based on path syntax - no any filesystem / network access performed. + //! @return true if path is complete (absolute) + static Standard_Boolean IsAbsolutePath (const char* thePath) + { + return !IsRelativePath (thePath); + } +private: TCollection_AsciiString myNode; TCollection_AsciiString myUserName; @@ -238,13 +317,6 @@ private: Standard_Boolean myUNCFlag; OSD_SysType mySysDep; - }; - - - - - - #endif // _OSD_Path_HeaderFile diff --git a/src/QANCollection/QANCollection_Test.cxx b/src/QANCollection/QANCollection_Test.cxx index 918c9694cc..e09c1d4980 100644 --- a/src/QANCollection/QANCollection_Test.cxx +++ b/src/QANCollection/QANCollection_Test.cxx @@ -21,6 +21,7 @@ #include +#include #include #include @@ -1224,6 +1225,114 @@ static Standard_Integer QANColTestVec4 (Draw_Interpretor& theDI, Standard_Intege return 0; } +//! Print file path flags deduced from path string. +static Standard_Integer QAOsdPathType (Draw_Interpretor& theDI, Standard_Integer theNbArgs, const char** theArgVec) +{ + if (theNbArgs != 2) + { + std::cout << "Syntax error: wrong number of arguments\n"; + return 1; + } + + TCollection_AsciiString aPath (theArgVec[1]); + if (OSD_Path::IsAbsolutePath (aPath.ToCString())) + { + theDI << "absolute "; + } + if (OSD_Path::IsRelativePath (aPath.ToCString())) + { + theDI << "relative "; + } + if (OSD_Path::IsUnixPath (aPath.ToCString())) + { + theDI << "unix "; + } + if (OSD_Path::IsDosPath (aPath.ToCString())) + { + theDI << "dos "; + } + if (OSD_Path::IsUncPath (aPath.ToCString())) + { + theDI << "unc "; + } + if (OSD_Path::IsNtExtendedPath (aPath.ToCString())) + { + theDI << "ntextended "; + } + if (OSD_Path::IsUncExtendedPath (aPath.ToCString())) + { + theDI << "uncextended "; + } + if (OSD_Path::IsRemoteProtocolPath (aPath.ToCString())) + { + theDI << "protocol "; + } + if (OSD_Path::IsContentProtocolPath (aPath.ToCString())) + { + theDI << "content "; + } + return 0; +} + +//! Print file path part deduced from path string. +static Standard_Integer QAOsdPathPart (Draw_Interpretor& theDI, Standard_Integer theNbArgs, const char** theArgVec) +{ + TCollection_AsciiString aPath; + enum PathPart + { + PathPart_NONE, + PathPart_Folder, + PathPart_FileName, + }; + PathPart aPart = PathPart_NONE; + for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter) + { + TCollection_AsciiString anArgCase (theArgVec[anArgIter]); + anArgCase.LowerCase(); + if (aPart == PathPart_NONE + && anArgCase == "-folder") + { + aPart = PathPart_Folder; + } + else if (aPart == PathPart_NONE + && anArgCase == "-filename") + { + aPart = PathPart_FileName; + } + else if (aPath.IsEmpty()) + { + aPath = theArgVec[anArgIter]; + } + else + { + std::cout << "Syntax error at '" << theArgVec[anArgIter] << "'\n"; + return 1; + } + } + if (aPath.IsEmpty() + || aPart == PathPart_NONE) + { + std::cout << "Syntax error: wrong number of arguments\n"; + return 1; + } + + TCollection_AsciiString aFolder, aFileName; + OSD_Path::FolderAndFileFromPath (aPath, aFolder, aFileName); + switch (aPart) + { + case PathPart_Folder: + theDI << aFolder; + return 0; + case PathPart_FileName: + theDI << aFileName; + return 0; + case PathPart_NONE: + default: + return 1; + } +} + + void QANCollection::CommandsTest(Draw_Interpretor& theCommands) { const char *group = "QANCollection"; @@ -1242,4 +1351,6 @@ void QANCollection::CommandsTest(Draw_Interpretor& theCommands) { theCommands.Add("QANColTestArrayMove", "QANColTestArrayMove (is expected to give error)", __FILE__, QANColTestArrayMove, group); theCommands.Add("QANColTestVec4", "QANColTestVec4 test Vec4 implementation", __FILE__, QANColTestVec4, group); theCommands.Add("QATestAtof", "QATestAtof [nbvalues [nbdigits [min [max]]]]", __FILE__, QATestAtof, group); + theCommands.Add("QAOsdPathType", "QAOsdPathType path : Print file path flags deduced from path string", __FILE__, QAOsdPathType, group); + theCommands.Add("QAOsdPathPart", "QAOsdPathPart path [-folder][-fileName] : Print file path part", __FILE__, QAOsdPathPart, group); } diff --git a/src/RWMesh/FILES b/src/RWMesh/FILES new file mode 100644 index 0000000000..902571c6e9 --- /dev/null +++ b/src/RWMesh/FILES @@ -0,0 +1,6 @@ +RWMesh_CoordinateSystem.hxx +RWMesh_CoordinateSystemConverter.cxx +RWMesh_CoordinateSystemConverter.hxx +RWMesh_CafReader.cxx +RWMesh_CafReader.hxx +RWMesh_NodeAttributes.hxx diff --git a/src/RWMesh/RWMesh_CafReader.cxx b/src/RWMesh/RWMesh_CafReader.cxx new file mode 100644 index 0000000000..6db946c90d --- /dev/null +++ b/src/RWMesh/RWMesh_CafReader.cxx @@ -0,0 +1,387 @@ +// Author: Kirill Gavrilov +// Copyright (c) 2016-2019 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +IMPLEMENT_STANDARD_RTTIEXT(RWMesh_CafReader, Standard_Transient) + +// ======================================================================= +// function : RWMesh_CafReader +// purpose : +// ======================================================================= +RWMesh_CafReader::RWMesh_CafReader() +: myToFillDoc (Standard_True), + myToFillIncomplete (Standard_True), + myMemoryLimitMiB (-1), + myExtraStatus (RWMesh_CafReaderStatusEx_NONE) +{ + // +} + +// ======================================================================= +// function : ~RWMesh_CafReader +// purpose : +// ======================================================================= +RWMesh_CafReader::~RWMesh_CafReader() +{ + // +} + +// ======================================================================= +// function : SingleShape +// purpose : +// ======================================================================= +TopoDS_Shape RWMesh_CafReader::SingleShape() const +{ + if (myRootShapes.Size() > 1) + { + BRep_Builder aBuilder; + TopoDS_Compound aCompound; + aBuilder.MakeCompound (aCompound); + for (TopTools_SequenceOfShape::Iterator aRootIter (myRootShapes); aRootIter.More(); aRootIter.Next()) + { + aBuilder.Add (aCompound, aRootIter.Value()); + } + return aCompound; + } + else if (!myRootShapes.IsEmpty()) + { + return myRootShapes.First(); + } + return TopoDS_Shape(); +} + +// ======================================================================= +// function : perform +// purpose : +// ======================================================================= +Standard_Boolean RWMesh_CafReader::perform (const TCollection_AsciiString& theFile, + const Handle(Message_ProgressIndicator)& theProgress, + const Standard_Boolean theToProbe) +{ + Standard_Integer aNewRootsLower = 1; + Handle(XCAFDoc_ShapeTool) aShapeTool = !myXdeDoc.IsNull() + ? XCAFDoc_DocumentTool::ShapeTool (myXdeDoc->Main()) + : Handle(XCAFDoc_ShapeTool)(); + if (!myXdeDoc.IsNull()) + { + TDF_LabelSequence aRootLabels; + aShapeTool->GetFreeShapes (aRootLabels); + aNewRootsLower = aRootLabels.Upper() + 1; + } + + OSD_Timer aLoadingTimer; + aLoadingTimer.Start(); + const Standard_Boolean isDone = performMesh (theFile, theProgress, theToProbe); + if (theToProbe + || (!theProgress.IsNull() && theProgress->UserBreak())) + { + return isDone; + } + else if (!isDone) + { + if (!myToFillIncomplete) + { + return Standard_False; + } + + myExtraStatus |= RWMesh_CafReaderStatusEx_Partial; + } + + BRep_Builder aBuilder; + TopoDS_Shape aShape; + if (myRootShapes.Size() > 1) + { + TopoDS_Compound aCompound; + aBuilder.MakeCompound (aCompound); + for (TopTools_SequenceOfShape::Iterator aRootIter (myRootShapes); aRootIter.More(); aRootIter.Next()) + { + aBuilder.Add (aCompound, aRootIter.Value()); + } + aShape = aCompound; + } + else if (!myRootShapes.IsEmpty()) + { + aShape = myRootShapes.First(); + } + + Standard_Integer aNbNodes = 0, aNbElems = 0, aNbFaces = 0; + if (!aShape.IsNull()) + { + TopLoc_Location aDummyLoc; + for (TopExp_Explorer aFaceIter (aShape, TopAbs_FACE); aFaceIter.More(); aFaceIter.Next()) + { + const TopoDS_Face& aFace = TopoDS::Face (aFaceIter.Current()); + if (const Handle(Poly_Triangulation)& aPolyTri = BRep_Tool::Triangulation (aFace, aDummyLoc)) + { + ++aNbFaces; + aNbNodes += aPolyTri->NbNodes(); + aNbElems += aPolyTri->NbTriangles(); + } + } + } + if (!isDone && aNbElems < 100) + { + return Standard_False; + } + + if (myToFillDoc + && !myXdeDoc.IsNull()) + { + const Standard_Boolean wasAutoNaming = aShapeTool->AutoNaming(); + aShapeTool->SetAutoNaming (Standard_False); + const TCollection_AsciiString aRootName; // = generateRootName (theFile); + for (TopTools_SequenceOfShape::Iterator aRootIter (myRootShapes); aRootIter.More(); aRootIter.Next()) + { + addShapeIntoDoc (aRootIter.Value(), TDF_Label(), aRootName); + } + aShapeTool->UpdateAssemblies(); + aShapeTool->SetAutoNaming (wasAutoNaming); + } + if (!myXdeDoc.IsNull()) + { + generateNames (theFile, aNewRootsLower, Standard_False); + } + + aLoadingTimer.Stop(); + + TCollection_AsciiString aStats = TCollection_AsciiString("[") + aNbNodes + " nodes] [" + aNbElems + " 2d elements]"; + if (!isDone) + { + Message::DefaultMessenger()->Send (TCollection_AsciiString ("Mesh ") + theFile + + "\n" + aStats + + "\n[PARTIALLY read in " + aLoadingTimer.ElapsedTime() + " s]", Message_Info); + } + else + { + Message::DefaultMessenger()->Send (TCollection_AsciiString ("Mesh ") + theFile + + "\n" + aStats + + "\n[read in " + aLoadingTimer.ElapsedTime() + " s]", Message_Info); + } + return Standard_True; +} + +// ======================================================================= +// function : addShapeIntoDoc +// purpose : +// ======================================================================= +Standard_Boolean RWMesh_CafReader::addShapeIntoDoc (const TopoDS_Shape& theShape, + const TDF_Label& theLabel, + const TCollection_AsciiString& theParentName) +{ + if (theShape.IsNull() + || myXdeDoc.IsNull()) + { + return Standard_False; + } + + Handle(XCAFDoc_ShapeTool) aShapeTool = XCAFDoc_DocumentTool::ShapeTool (myXdeDoc->Main()); + + TopLoc_Location aDummyLoc; + + const TopAbs_ShapeEnum aShapeType = theShape.ShapeType(); + TopoDS_Shape aShapeToAdd = theShape; + Standard_Boolean toMakeAssembly = Standard_False; + if (theShape.ShapeType() == TopAbs_COMPOUND) + { + TCollection_AsciiString aFirstName; + RWMesh_NodeAttributes aSubFaceAttribs; + for (TopoDS_Iterator aSubShapeIter (theShape, Standard_True, Standard_False); !toMakeAssembly && aSubShapeIter.More(); aSubShapeIter.Next()) + { + if (aSubShapeIter.Value().ShapeType() != TopAbs_FACE) + { + toMakeAssembly = Standard_True; + break; + } + + const TopoDS_Face& aFace = TopoDS::Face (aSubShapeIter.Value()); + toMakeAssembly = toMakeAssembly + || (myAttribMap.Find (aFace, aSubFaceAttribs) && !aSubFaceAttribs.Name.IsEmpty()); + } + + // create empty compound to add as assembly + if (toMakeAssembly) + { + TopoDS_Compound aCompound; + BRep_Builder aBuilder; + aBuilder.MakeCompound (aCompound); + aCompound.Location (theShape.Location()); + aShapeToAdd = aCompound; + } + } + + TDF_Label aNewLabel; + if (theLabel.IsNull()) + { + // add new shape + aNewLabel = aShapeTool->AddShape (aShapeToAdd, toMakeAssembly); + } + else if (aShapeTool->IsAssembly (theLabel)) + { + // add shape as component + aNewLabel = aShapeTool->AddComponent (theLabel, aShapeToAdd, toMakeAssembly); + } + else + { + // add shape as sub-shape + aNewLabel = aShapeTool->AddSubShape (theLabel, theShape); + if (!aNewLabel.IsNull()) + { + Handle(XCAFDoc_ShapeMapTool) aShapeMapTool = XCAFDoc_ShapeMapTool::Set (aNewLabel); + aShapeMapTool->SetShape (theShape); + } + } + if (aNewLabel.IsNull()) + { + return Standard_False; + } + + // if new label is a reference get referred shape + TDF_Label aNewRefLabel = aNewLabel; + aShapeTool->GetReferredShape (aNewLabel, aNewRefLabel); + + // store name + RWMesh_NodeAttributes aShapeAttribs; + myAttribMap.Find (theShape, aShapeAttribs); + if (aShapeAttribs.Name.IsEmpty()) + { + if (theLabel.IsNull()) + { + aShapeAttribs.Name = theParentName; + } + if (aShapeAttribs.Name.IsEmpty() + && !theLabel.IsNull()) + { + aShapeAttribs.Name = shapeTypeToString (aShapeType); + } + } + if (!aShapeAttribs.Name.IsEmpty()) + { + TDataStd_Name::Set (aNewRefLabel, aShapeAttribs.Name); + } + + // store color + Handle(XCAFDoc_ColorTool) aColorTool = XCAFDoc_DocumentTool::ColorTool (myXdeDoc->Main()); + if (aShapeAttribs.Style.IsSetColorSurf()) + { + aColorTool->SetColor (aNewRefLabel, aShapeAttribs.Style.GetColorSurfRGBA(), XCAFDoc_ColorSurf); + } + if (aShapeAttribs.Style.IsSetColorCurv()) + { + aColorTool->SetColor (aNewRefLabel, aShapeAttribs.Style.GetColorCurv(), XCAFDoc_ColorCurv); + } + + // store sub-shapes (iterator is set to ignore Location) + TCollection_AsciiString aDummyName; + for (TopoDS_Iterator aSubShapeIter (theShape, Standard_True, Standard_False); aSubShapeIter.More(); aSubShapeIter.Next()) + { + addShapeIntoDoc (aSubShapeIter.Value(), aNewRefLabel, aDummyName); + } + return Standard_True; +} + +// ======================================================================= +// function : generateNames +// purpose : +// ======================================================================= +void RWMesh_CafReader::generateNames (const TCollection_AsciiString& theFile, + const Standard_Integer theRootLower, + const Standard_Boolean theWithSubLabels) +{ + if (myXdeDoc.IsNull()) + { + return; + } + + TCollection_AsciiString aDummyFolder, aFileName; + OSD_Path::FolderAndFileFromPath (theFile, aDummyFolder, aFileName); + const TCollection_AsciiString aRootName = myRootPrefix + aFileName; + + Handle(XCAFDoc_ShapeTool) aShapeTool = XCAFDoc_DocumentTool::ShapeTool (myXdeDoc->Main()); + TDF_LabelSequence aRootLabels; + aShapeTool->GetFreeShapes (aRootLabels); + if (aRootLabels.Upper() < theRootLower) + { + return; + } + + // replace empty names + Handle(TDataStd_Name) aNodeName; + Standard_Integer aRootIndex = aRootLabels.Lower(); + TDF_LabelSequence aNewRootLabels; + for (TDF_LabelSequence::Iterator aRootIter (aRootLabels); aRootIter.More(); ++aRootIndex, aRootIter.Next()) + { + if (aRootIndex < theRootLower) + { + continue; + } + else if (theWithSubLabels) + { + aNewRootLabels.Append (aRootIter.Value()); + } + + const TDF_Label aLabel = aRootIter.Value(); + TDF_Label aRefLab = aLabel; + XCAFDoc_ShapeTool::GetReferredShape (aLabel, aRefLab); + if (!aRefLab.FindAttribute (TDataStd_Name::GetID(), aNodeName)) + { + TDataStd_Name::Set (aRefLab, aRootName); + } + if (aLabel != aRefLab + && !aLabel.FindAttribute (TDataStd_Name::GetID(), aNodeName)) + { + TDataStd_Name::Set (aLabel, aRootName); + } + } + + if (theWithSubLabels) + { + for (XCAFPrs_DocumentExplorer aDocIter (myXdeDoc, + aNewRootLabels, + XCAFPrs_DocumentExplorerFlags_OnlyLeafNodes | XCAFPrs_DocumentExplorerFlags_NoStyle); + aDocIter.More(); aDocIter.Next()) + { + if (aDocIter.CurrentDepth() == 0 + || aDocIter.Current().RefLabel.FindAttribute (TDataStd_Name::GetID(), aNodeName)) + { + continue; + } + + const TopoDS_Shape aShape = XCAFDoc_ShapeTool::GetShape (aDocIter.Current().RefLabel); + if (!aShape.IsNull()) + { + TDataStd_Name::Set (aDocIter.Current().RefLabel, shapeTypeToString (aShape.ShapeType())); + } + } + } +} diff --git a/src/RWMesh/RWMesh_CafReader.hxx b/src/RWMesh/RWMesh_CafReader.hxx new file mode 100644 index 0000000000..ef5b58bab1 --- /dev/null +++ b/src/RWMesh/RWMesh_CafReader.hxx @@ -0,0 +1,228 @@ +// Author: Kirill Gavrilov +// Copyright (c) 2016-2019 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 _RWMesh_CafReader_HeaderFile +#define _RWMesh_CafReader_HeaderFile + +#include +#include +#include +#include +#include +#include + +class Message_ProgressIndicator; +class TDocStd_Document; + +//! Extended status bits. +enum RWMesh_CafReaderStatusEx +{ + RWMesh_CafReaderStatusEx_NONE = 0, //!< empty status + RWMesh_CafReaderStatusEx_Partial = 0x01, //!< partial read (due to unexpected EOF, syntax error, memory limit) +}; + +//! The general interface for importing mesh data into XDE document. +//! +//! The tool implements auxiliary structures for creating an XDE document in two steps: +//! 1) Creating TopoDS_Shape hierarchy (myRootShapes) +//! and Shape attributes (myAttribMap) separately within performMesh(). +//! Attributes include names and styles. +//! 2) Filling XDE document from these auxiliary structures. +//! Named elements are expanded within document structure, while Compounds having no named children will remain collapsed. +//! In addition, unnamed nodes can be filled with generated names like "Face", "Compound" via generateNames() method, +//! and the very root unnamed node can be filled from file name like "MyModel.obj". +class RWMesh_CafReader : public Standard_Transient +{ + DEFINE_STANDARD_RTTIEXT(RWMesh_CafReader, Standard_Transient) +public: + + //! Empty constructor. + Standard_EXPORT RWMesh_CafReader(); + + //! Destructor. + Standard_EXPORT virtual ~RWMesh_CafReader(); + + //! Return target document. + const Handle(TDocStd_Document)& Document() const { return myXdeDoc; } + + //! Set target document. + void SetDocument (const Handle(TDocStd_Document)& theDoc) { myXdeDoc = theDoc; } + + //! Return prefix for generating root labels names. + const TCollection_AsciiString& RootPrefix() const { return myRootPrefix; } + + //! Set prefix for generating root labels names + void SetRootPrefix (const TCollection_AsciiString& theRootPrefix) { myRootPrefix = theRootPrefix; } + + //! Flag indicating if partially read file content should be put into the XDE document, TRUE by default. + //! + //! Partial read means unexpected end of file, critical parsing syntax errors in the middle of file, or reached memory limit + //! indicated by performMesh() returning FALSE. + //! Partial read allows importing a model even in case of formal reading failure, + //! so that it will be up to user to decide if processed data has any value. + //! + //! In case of partial read (performMesh() returns FALSE, but there are some data that could be put into document), + //! Perform() will return TRUE and result flag will have failure bit set. + //! @sa MemoryLimitMiB(), ExtraStatus(). + Standard_Boolean ToFillIncompleteDocument() const { return myToFillIncomplete; } + + //! Set flag allowing partially read file content to be put into the XDE document. + void SetFillIncompleteDocument (Standard_Boolean theToFillIncomplete) { myToFillIncomplete = theToFillIncomplete; } + + //! Return memory usage limit in MiB, -1 by default which means no limit. + Standard_Integer MemoryLimitMiB() const { return myMemoryLimitMiB; } + + //! Set memory usage limit in MiB; can be ignored by reader implementation! + void SetMemoryLimitMiB (Standard_Integer theLimitMiB) { myMemoryLimitMiB = theLimitMiB; } + +public: + + //! Return coordinate system converter. + const RWMesh_CoordinateSystemConverter& CoordinateSystemConverter() const { return myCoordSysConverter; } + + //! Set coordinate system converter. + void SetCoordinateSystemConverter (const RWMesh_CoordinateSystemConverter& theConverter) { myCoordSysConverter = theConverter; } + + //! Return the length unit to convert into while reading the file, defined as scale factor for m (meters); + //! -1.0 by default, which means that NO conversion will be applied. + Standard_Real SystemLengthUnit() const { return myCoordSysConverter.OutputLengthUnit(); } + + //! Set system length units to convert into while reading the file, defined as scale factor for m (meters). + void SetSystemLengthUnit (Standard_Real theUnits) { myCoordSysConverter.SetOutputLengthUnit (theUnits); } + + //! Return TRUE if system coordinate system has been defined; FALSE by default. + Standard_Boolean HasSystemCoordinateSystem() const { return myCoordSysConverter.HasOutputCoordinateSystem(); } + + //! Return system coordinate system; UNDEFINED by default, which means that no conversion will be done. + const gp_Ax3& SystemCoordinateSystem() const { return myCoordSysConverter.OutputCoordinateSystem(); } + + //! Set system origin coordinate system to perform conversion into during read. + void SetSystemCoordinateSystem (const gp_Ax3& theCS) { myCoordSysConverter.SetOutputCoordinateSystem (theCS); } + + //! Set system origin coordinate system to perform conversion into during read. + void SetSystemCoordinateSystem (RWMesh_CoordinateSystem theCS) { myCoordSysConverter.SetOutputCoordinateSystem (theCS); } + + //! Return the length unit to convert from while reading the file, defined as scale factor for m (meters). + //! Can be undefined (-1.0) if file format is unitless. + Standard_Real FileLengthUnit() const { return myCoordSysConverter.InputLengthUnit(); } + + //! Set (override) file length units to convert from while reading the file, defined as scale factor for m (meters). + void SetFileLengthUnit (Standard_Real theUnits) { myCoordSysConverter.SetInputLengthUnit (theUnits); } + + //! Return TRUE if file origin coordinate system has been defined. + Standard_Boolean HasFileCoordinateSystem() const { return myCoordSysConverter.HasInputCoordinateSystem(); } + + //! Return file origin coordinate system; can be UNDEFINED, which means no conversion will be done. + const gp_Ax3& FileCoordinateSystem() const { return myCoordSysConverter.InputCoordinateSystem(); } + + //! Set (override) file origin coordinate system to perform conversion during read. + void SetFileCoordinateSystem (const gp_Ax3& theCS) { myCoordSysConverter.SetInputCoordinateSystem (theCS); } + + //! Set (override) file origin coordinate system to perform conversion during read. + void SetFileCoordinateSystem (RWMesh_CoordinateSystem theCS) { myCoordSysConverter.SetInputCoordinateSystem (theCS); } + +public: + + //! Read the data from specified file. + //! The Document instance should be set beforehand. + bool Perform (const TCollection_AsciiString& theFile, + const Handle(Message_ProgressIndicator)& theProgress) + { + return perform (theFile, theProgress, Standard_False); + } + + //! Return extended status flags. + //! @sa RWMesh_CafReaderStatusEx enumeration. + Standard_Integer ExtraStatus() const { return myExtraStatus; } + +public: + + //! Return result as a single shape. + Standard_EXPORT TopoDS_Shape SingleShape() const; + + //! Return the list of complementary files - external references (textures, data, etc.). + const NCollection_IndexedMap& ExternalFiles() const { return myExternalFiles; } + + //! Return metadata map. + const TColStd_IndexedDataMapOfStringString& Metadata() const { return myMetadata; } + + //! Read the header data from specified file without reading entire model. + //! The main purpose is collecting metadata and external references - for copying model into a new location, for example. + //! Can be NOT implemented (unsupported by format / reader). + Standard_Boolean ProbeHeader (const TCollection_AsciiString& theFile, + const Handle(Message_ProgressIndicator)& theProgress = Handle(Message_ProgressIndicator)()) + { + return perform (theFile, theProgress, Standard_True); + } + +protected: + + //! Read the data from specified file. + //! Default implementation calls performMesh() and fills XDE document from collected shapes. + //! @param theFile file to read + //! @param optional progress indicator + //! @param theToProbe flag indicating that mesh data should be skipped and only basing information to be read + virtual Standard_Boolean perform (const TCollection_AsciiString& theFile, + const Handle(Message_ProgressIndicator)& theProgress, + const Standard_Boolean theToProbe); + + //! Read the mesh from specified file - interface to be implemented by sub-classes. + virtual Standard_Boolean performMesh (const TCollection_AsciiString& theFile, + const Handle(Message_ProgressIndicator)& theProgress, + const Standard_Boolean theToProbe) = 0; + +//! @name tools for filling XDE document +protected: + + //! Append new shape into the document (recursively). + Standard_EXPORT Standard_Boolean addShapeIntoDoc (const TopoDS_Shape& theShape, + const TDF_Label& theLabel, + const TCollection_AsciiString& theParentName); + + //! Generate names for root labels starting from specified index. + Standard_EXPORT void generateNames (const TCollection_AsciiString& theFile, + const Standard_Integer theRootLower, + const Standard_Boolean theWithSubLabels); + + //! Return shape type as string. + //! @sa TopAbs::ShapeTypeToString() + static TCollection_AsciiString shapeTypeToString (TopAbs_ShapeEnum theType) + { + TCollection_AsciiString aString = TopAbs::ShapeTypeToString (theType); + aString.Capitalize(); + return aString; + } + +protected: + + Handle(TDocStd_Document) myXdeDoc; //!< target document + + TColStd_IndexedDataMapOfStringString + myMetadata; //!< metadata map + NCollection_IndexedMap + myExternalFiles; //!< the list of complementary files - external references (textures, data, etc.) + TCollection_AsciiString myRootPrefix; //!< root folder for generating root labels names + TopTools_SequenceOfShape myRootShapes; //!< sequence of result root shapes + RWMesh_NodeAttributeMap myAttribMap; //!< map of per-shape attributes + + RWMesh_CoordinateSystemConverter + myCoordSysConverter; //!< coordinate system converter + Standard_Boolean myToFillDoc; //!< fill document from shape sequence + Standard_Boolean myToFillIncomplete; //!< fill the document with partially retrieved data even if reader has failed with error + Standard_Integer myMemoryLimitMiB; //!< memory usage limit + Standard_Integer myExtraStatus; //!< extra status bitmask + +}; + +#endif // _RWMesh_CafReader_HeaderFile diff --git a/src/RWMesh/RWMesh_CoordinateSystem.hxx b/src/RWMesh/RWMesh_CoordinateSystem.hxx new file mode 100644 index 0000000000..6a06967999 --- /dev/null +++ b/src/RWMesh/RWMesh_CoordinateSystem.hxx @@ -0,0 +1,34 @@ +// Author: Kirill Gavrilov +// Copyright: Open CASCADE 2015-2019 +// +// 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 _RWMesh_CoordinateSystem_HeaderFile +#define _RWMesh_CoordinateSystem_HeaderFile + +//! Standard coordinate system definition. +//! Open CASCADE does not force application using specific coordinate system, +//! although Draw Harness and samples define +Z-up +Y-forward coordinate system for camera view manipulation. +//! This enumeration defines two commonly used conventions - Z-up and Y-up.. +enum RWMesh_CoordinateSystem +{ + RWMesh_CoordinateSystem_Undefined = -1, //!< undefined + RWMesh_CoordinateSystem_posYfwd_posZup = 0, //!< +YForward+Zup+Xright + RWMesh_CoordinateSystem_negZfwd_posYup, //!< -ZForward+Yup+Xright + + RWMesh_CoordinateSystem_Blender = RWMesh_CoordinateSystem_posYfwd_posZup, //!< coordinate system used by Blender (+YForward+Zup+Xright) + RWMesh_CoordinateSystem_glTF = RWMesh_CoordinateSystem_negZfwd_posYup, //!< coordinate system used by glTF (-ZForward+Yup+Xright) + RWMesh_CoordinateSystem_Zup = RWMesh_CoordinateSystem_Blender, //!< Z-up coordinate system (+YForward+Zup+Xright) + RWMesh_CoordinateSystem_Yup = RWMesh_CoordinateSystem_glTF, //!< Y-up coordinate system (-ZForward+Yup+Xright) +}; + +#endif // _RWMesh_CoordinateSystem_HeaderFile diff --git a/src/RWMesh/RWMesh_CoordinateSystemConverter.cxx b/src/RWMesh/RWMesh_CoordinateSystemConverter.cxx new file mode 100644 index 0000000000..1978f61e7f --- /dev/null +++ b/src/RWMesh/RWMesh_CoordinateSystemConverter.cxx @@ -0,0 +1,77 @@ +// Author: Kirill Gavrilov +// Copyright (c) 2015-2019 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#include + +#include + +// ================================================================ +// Function : RWMesh_CoordinateSystemConverter +// Purpose : +// ================================================================ +RWMesh_CoordinateSystemConverter::RWMesh_CoordinateSystemConverter() +: myInputLengthUnit (-1.0), + myOutputLengthUnit(-1.0), + myHasInputAx3 (Standard_False), + myHasOutputAx3(Standard_False), + // + myUnitFactor (1), + myHasScale (Standard_False), + myIsEmpty (Standard_True) +{ + // +} + +// ================================================================ +// Function : Init +// Purpose : +// ================================================================ +void RWMesh_CoordinateSystemConverter::Init (const gp_Ax3& theInputSystem, + Standard_Real theInputLengthUnit, + const gp_Ax3& theOutputSystem, + Standard_Real theOutputLengthUnit) +{ + myInputLengthUnit = theInputLengthUnit; + myOutputLengthUnit = theOutputLengthUnit; + myInputAx3 = theInputSystem; + myOutputAx3 = theOutputSystem; + if (theInputLengthUnit > 0.0 + && theOutputLengthUnit > 0.0) + { + myUnitFactor = theInputLengthUnit / theOutputLengthUnit; + myHasScale = Abs(myUnitFactor - 1.0) > gp::Resolution(); + } + else + { + myUnitFactor = 1.0; + myHasScale = Standard_False; + } + + gp_Trsf aTrsf; + if (myHasInputAx3 + && myHasOutputAx3) + { + aTrsf.SetTransformation (theOutputSystem, theInputSystem); + if (aTrsf.TranslationPart().IsEqual (gp_XYZ (0.0, 0.0, 0.0), gp::Resolution()) + && aTrsf.GetRotation().IsEqual (gp_Quaternion())) + { + aTrsf = gp_Trsf(); + } + } + + myTrsf = aTrsf; + myTrsfInv = aTrsf.Inverted(); + myTrsf.GetMat4 (myNormTrsf); + myIsEmpty = !myHasScale && myTrsf.Form() == gp_Identity; +} diff --git a/src/RWMesh/RWMesh_CoordinateSystemConverter.hxx b/src/RWMesh/RWMesh_CoordinateSystemConverter.hxx new file mode 100644 index 0000000000..295a770115 --- /dev/null +++ b/src/RWMesh/RWMesh_CoordinateSystemConverter.hxx @@ -0,0 +1,196 @@ +// Author: Kirill Gavrilov +// Copyright: Open CASCADE 2015-2019 +// +// 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 _RWMesh_CoordinateSystemConverter_HeaderFile +#define _RWMesh_CoordinateSystemConverter_HeaderFile + +#include + +#include +#include +#include +#include +#include +#include + +//! Coordinate system converter defining the following tools: +//! - Initialization for commonly used coordinate systems Z-up and Y-up. +//! - Perform length unit conversion (scaling). +//! - Conversion of three basic elements: +//! a) mesh node Positions, +//! b) mesh node Normals, +//! c) model nodes Transformations (locations). +//! +//! RWMesh_CoordinateSystem enumeration is used for convenient conversion between two commonly +//! used coordinate systems, to make sure that imported model is oriented up. +//! But gp_Ax3 can be used instead for defining a conversion between arbitrary systems (e.g. including non-zero origin). +//! +//! The converter requires defining explicitly both input and output systems, +//! so that if either input or output is undefined, then conversion will be skipped. +//! Length units conversion and coordinate system conversion are decomposed, +//! so that application might specify no length units conversion but Y-up to Z-up coordinate system conversion. +//! +//! Class defines dedicated methods for parameters of input and output systems. +//! This allows passing tool through several initialization steps, +//! so that a reader can initialize input length units (only if file format defines such information), +//! while application specifies output length units, and conversion will be done only when both defined. +class RWMesh_CoordinateSystemConverter +{ +public: + + //! Return a standard coordinate system definition. + static gp_Ax3 StandardCoordinateSystem (RWMesh_CoordinateSystem theSys) + { + switch (theSys) + { + case RWMesh_CoordinateSystem_posYfwd_posZup: return gp_Ax3 (gp::Origin(), gp::DZ(), gp::DX()); + case RWMesh_CoordinateSystem_negZfwd_posYup: return gp_Ax3 (gp::Origin(), gp::DY(), gp::DX()); + case RWMesh_CoordinateSystem_Undefined: break; + } + return gp_Ax3(); + } + +public: + + //! Empty constructor. + Standard_EXPORT RWMesh_CoordinateSystemConverter(); + + //! Return TRUE if there is no transformation (target and current coordinates systems are same). + Standard_Boolean IsEmpty() const { return myIsEmpty; } + + //! Return source length units, defined as scale factor to m (meters). + //! -1.0 by default, which means that NO conversion will be applied (regardless output length unit). + Standard_Real InputLengthUnit() const { return myInputLengthUnit; } + + //! Set source length units as scale factor to m (meters). + void SetInputLengthUnit (Standard_Real theInputScale) + { + Init (myInputAx3, theInputScale, myOutputAx3, myOutputLengthUnit); + } + + //! Return destination length units, defined as scale factor to m (meters). + //! -1.0 by default, which means that NO conversion will be applied (regardless input length unit). + Standard_Real OutputLengthUnit() const { return myOutputLengthUnit; } + + //! Set destination length units as scale factor to m (meters). + void SetOutputLengthUnit (Standard_Real theOutputScale) + { + Init (myInputAx3, myInputLengthUnit, myOutputAx3, theOutputScale); + } + + //! Return TRUE if source coordinate system has been set; FALSE by default. + Standard_Boolean HasInputCoordinateSystem() const { return myHasInputAx3; } + + //! Source coordinate system; UNDEFINED by default. + const gp_Ax3& InputCoordinateSystem() const { return myInputAx3; } + + //! Set source coordinate system. + void SetInputCoordinateSystem (const gp_Ax3& theSysFrom) + { + myHasInputAx3 = Standard_True; + Init (theSysFrom, myInputLengthUnit, myOutputAx3, myOutputLengthUnit); + } + + //! Set source coordinate system. + void SetInputCoordinateSystem (RWMesh_CoordinateSystem theSysFrom) + { + myHasInputAx3 = theSysFrom != RWMesh_CoordinateSystem_Undefined; + Init (StandardCoordinateSystem (theSysFrom), myInputLengthUnit, myOutputAx3, myOutputLengthUnit); + } + + //! Return TRUE if destination coordinate system has been set; FALSE by default. + Standard_Boolean HasOutputCoordinateSystem() const { return myHasOutputAx3; } + + //! Destination coordinate system; UNDEFINED by default. + const gp_Ax3& OutputCoordinateSystem() const { return myOutputAx3; } + + //! Set destination coordinate system. + void SetOutputCoordinateSystem (const gp_Ax3& theSysTo) + { + myHasOutputAx3 = Standard_True; + Init (myInputAx3, myInputLengthUnit, theSysTo, myOutputLengthUnit); + } + + //! Set destination coordinate system. + void SetOutputCoordinateSystem (RWMesh_CoordinateSystem theSysTo) + { + myHasOutputAx3 = theSysTo != RWMesh_CoordinateSystem_Undefined; + Init (myInputAx3, myInputLengthUnit, StandardCoordinateSystem (theSysTo), myOutputLengthUnit); + } + + //! Initialize transformation. + Standard_EXPORT void Init (const gp_Ax3& theInputSystem, + Standard_Real theInputLengthUnit, + const gp_Ax3& theOutputSystem, + Standard_Real theOutputLengthUnit); + +public: + + //! Transform transformation. + void TransformTransformation (gp_Trsf& theTrsf) const + { + if (myHasScale) + { + gp_XYZ aTransPart = theTrsf.TranslationPart(); + aTransPart *= myUnitFactor; + theTrsf.SetTranslationPart (aTransPart); + } + if (myTrsf.Form() != gp_Identity) + { + theTrsf = myTrsf * theTrsf * myTrsfInv; + } + } + + //! Transform position. + void TransformPosition (gp_XYZ& thePos) const + { + if (myHasScale) + { + thePos *= myUnitFactor; + } + if (myTrsf.Form() != gp_Identity) + { + myTrsf.Transforms (thePos); + } + } + + //! Transform normal (e.g. exclude translation/scale part of transformation). + void TransformNormal (Graphic3d_Vec3& theNorm) const + { + if (myTrsf.Form() != gp_Identity) + { + const Graphic3d_Vec4 aNorm = myNormTrsf * Graphic3d_Vec4 (theNorm, 0.0f); + theNorm = aNorm.xyz(); + } + } + +private: + + gp_Ax3 myInputAx3; //!< source coordinate system + gp_Ax3 myOutputAx3; //!< destination coordinate system + Standard_Real myInputLengthUnit; //!< source length units, defined as scale factor to m (meters); -1.0 by default which means UNDEFINED + Standard_Real myOutputLengthUnit; //!< destination length units, defined as scale factor to m (meters); -1.0 by default which means UNDEFINED + Standard_Boolean myHasInputAx3; //!< flag indicating if source coordinate system is defined or not + Standard_Boolean myHasOutputAx3; //!< flag indicating if destination coordinate system is defined or not + + gp_Trsf myTrsf; //!< transformation from input Ax3 to output Ax3 + gp_Trsf myTrsfInv; //!< inversed transformation from input Ax3 to output Ax3 + Graphic3d_Mat4 myNormTrsf; //!< transformation 4x4 matrix from input Ax3 to output Ax3 + Standard_Real myUnitFactor; //!< unit scale factor + Standard_Boolean myHasScale; //!< flag indicating that length unit transformation should be performed + Standard_Boolean myIsEmpty; //!< flag indicating that transformation is empty + +}; + +#endif // _RWMesh_CoordinateSystemConverter_HeaderFile diff --git a/src/RWMesh/RWMesh_NodeAttributes.hxx b/src/RWMesh/RWMesh_NodeAttributes.hxx new file mode 100644 index 0000000000..adc7110410 --- /dev/null +++ b/src/RWMesh/RWMesh_NodeAttributes.hxx @@ -0,0 +1,32 @@ +// Author: Kirill Gavrilov +// Copyright (c) 2016-2019 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 _RWMesh_NodeAttributes_HeaderFile +#define _RWMesh_NodeAttributes_HeaderFile + +#include +#include +#include +#include + +//! Attributes of the node. +struct RWMesh_NodeAttributes +{ + TCollection_AsciiString Name; //!< name for the user + TCollection_AsciiString RawName; //!< name within low-level format structure + XCAFPrs_Style Style; //!< presentation style +}; +typedef NCollection_DataMap RWMesh_NodeAttributeMap; + +#endif // _RWMesh_NodeAttributes_HeaderFile diff --git a/src/Standard/FILES b/src/Standard/FILES index 96f430fa5f..1199f5f973 100755 --- a/src/Standard/FILES +++ b/src/Standard/FILES @@ -76,6 +76,7 @@ Standard_PExtCharacter.hxx Standard_PrimitiveTypes.hxx Standard_ProgramError.hxx Standard_RangeError.hxx +Standard_ReadBuffer.hxx Standard_Real.cxx Standard_Real.hxx Standard_ShortReal.cxx diff --git a/src/Standard/Standard_OutOfRange.hxx b/src/Standard/Standard_OutOfRange.hxx index 0d2cf80a95..25b07d6cba 100644 --- a/src/Standard/Standard_OutOfRange.hxx +++ b/src/Standard/Standard_OutOfRange.hxx @@ -25,18 +25,20 @@ class Standard_OutOfRange; DEFINE_STANDARD_HANDLE(Standard_OutOfRange, Standard_RangeError) -#if !defined No_Exception && !defined No_Standard_OutOfRange -#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2)) +#if (defined(__GNUC__) && __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) // suppress false-positive warnings produced by GCC optimizer - #define Standard_OutOfRange_Raise_if(CONDITION, MESSAGE) \ + #define Standard_OutOfRange_Always_Raise_if(CONDITION, MESSAGE) \ _Pragma("GCC diagnostic push") \ _Pragma("GCC diagnostic ignored \"-Wstrict-overflow\"") \ if (CONDITION) throw Standard_OutOfRange(MESSAGE); \ _Pragma("GCC diagnostic pop") #else - #define Standard_OutOfRange_Raise_if(CONDITION, MESSAGE) \ + #define Standard_OutOfRange_Always_Raise_if(CONDITION, MESSAGE) \ if (CONDITION) throw Standard_OutOfRange(MESSAGE); #endif + +#if !defined No_Exception && !defined No_Standard_OutOfRange + #define Standard_OutOfRange_Raise_if(CONDITION, MESSAGE) Standard_OutOfRange_Always_Raise_if(CONDITION, MESSAGE) #else #define Standard_OutOfRange_Raise_if(CONDITION, MESSAGE) #endif diff --git a/src/Standard/Standard_RangeError.hxx b/src/Standard/Standard_RangeError.hxx index 52477fb053..719924ca6f 100644 --- a/src/Standard/Standard_RangeError.hxx +++ b/src/Standard/Standard_RangeError.hxx @@ -26,7 +26,7 @@ class Standard_RangeError; DEFINE_STANDARD_HANDLE(Standard_RangeError, Standard_DomainError) #if !defined No_Exception && !defined No_Standard_RangeError -#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2)) +#if (defined(__GNUC__) && __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) // suppress false-positive warnings produced by GCC optimizer #define Standard_RangeError_Raise_if(CONDITION, MESSAGE) \ _Pragma("GCC diagnostic push") \ diff --git a/src/Standard/Standard_ReadBuffer.hxx b/src/Standard/Standard_ReadBuffer.hxx new file mode 100644 index 0000000000..e741e399fe --- /dev/null +++ b/src/Standard/Standard_ReadBuffer.hxx @@ -0,0 +1,145 @@ +// Copyright (c) 2017-2019 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 _Standard_ReadBuffer_HeaderFile +#define _Standard_ReadBuffer_HeaderFile + +#include + +#include + +//! Auxiliary tool for buffered reading from input stream within chunks of constant size. +class Standard_ReadBuffer +{ +public: + + //! Constructor with initialization. + Standard_ReadBuffer (int64_t theDataLen, + size_t theChunkLen) + : myBufferPtr(NULL), + myBufferEnd(NULL), + myDataLen (0), + myDataRead (0), + myChunkLen (0), + myNbChunks (0), + myBufferLen(0) + { + Init (theDataLen, theChunkLen); + } + + //! Initialize the buffer. + //! @param theDataLen the full length of input data to read from stream. + //! @param theChunkLen the length of single chunk to read + void Init (int64_t theDataLen, + size_t theChunkLen) + { + myDataRead = 0; + myDataLen = theDataLen - theDataLen % int64_t(theChunkLen); + myChunkLen = theChunkLen; + myNbChunks = sizeof(myBuffer) / theChunkLen; + myBufferLen = theChunkLen * myNbChunks; + + myBufferEnd = myBuffer + sizeof(myBuffer); + myBufferPtr = myBuffer + sizeof(myBuffer); + memset (myBuffer, 0, sizeof(myBuffer)); + + if (theChunkLen > sizeof(myBuffer)) + { + Standard_ProgramError::Raise ("Internal error - chunk size is greater then preallocated buffer"); + } + } + + //! Return TRUE if amount of read bytes is equal to requested length of entire data. + bool IsDone() const + { + return myDataRead == myDataLen; + } + + //! Read next chunk. + //! @return pointer to the chunk or NULL on error / end of reading buffer + template + Chunk_T* ReadChunk (Stream_T& theStream) + { + return reinterpret_cast (readRawDataChunk (theStream)); + } + + //! Read next chunk. + //! @return pointer to the chunk or NULL on error / end of reading buffer + template + char* ReadDataChunk (Stream_T& theStream) + { + return readRawDataChunk (theStream); + } + +private: + + //! Read next chunk. + //! @return pointer to the chunk or NULL on error / end of reading buffer + template + char* readRawDataChunk (Stream_T& theStream) + { + myBufferPtr += myChunkLen; + if (myBufferPtr < myBufferEnd) + { + return myBufferPtr; + } + + const int64_t aDataLeft = myDataLen - myDataRead; + if (aDataLeft == 0) // myDataLen should be multiple of myChunkLen + { + myBufferPtr = NULL; + return NULL; + } + + const size_t aDataToRead = int64_t(myBufferLen) > aDataLeft ? size_t(aDataLeft) : myBufferLen; + if (!readStream (theStream, aDataToRead)) + { + myBufferPtr = NULL; + return NULL; + } + + myBufferPtr = myBuffer; + myBufferEnd = myBuffer + aDataToRead; + myDataRead += aDataToRead; + return myBufferPtr; + } + + //! Read from stl stream. + bool readStream (std::istream& theStream, + size_t theLen) + { + theStream.read (myBuffer, theLen); + return theStream.good(); + } + + //! Read from FILE stream. + bool readStream (FILE* theStream, + size_t theLen) + { + return ::fread (myBuffer, 1, theLen, theStream) == theLen; + } + +private: + + char myBuffer[4096]; //!< data cache + char* myBufferPtr; //!< current position within the buffer + const char* myBufferEnd; //!< end of the buffer + int64_t myDataLen; //!< length of entire data to read + int64_t myDataRead; //!< amount of data already processed + size_t myChunkLen; //!< length of single chunk that caller would like to read (e.g. iterator increment) + size_t myNbChunks; //!< number of cached chunks + size_t myBufferLen; //!< effective length of the buffer to be read at once (multiple of chunk length) + +}; + +#endif // _Standard_ReadBuffer_HeaderFile diff --git a/src/TCollection/TCollection_AsciiString.lxx b/src/TCollection/TCollection_AsciiString.lxx index 6cc80dc268..2eef2fd155 100644 --- a/src/TCollection/TCollection_AsciiString.lxx +++ b/src/TCollection/TCollection_AsciiString.lxx @@ -114,9 +114,9 @@ inline Standard_Boolean TCollection_AsciiString::IsEqual(const TCollection_Ascii inline TCollection_AsciiString TCollection_AsciiString::SubString(const Standard_Integer FromIndex, const Standard_Integer ToIndex) const { - - if (ToIndex > mylength || FromIndex <= 0 || FromIndex > ToIndex ) throw Standard_OutOfRange(); - + // note the we are doing here weird casts just to suppress annoying and meaningless warning -Wstrict-overflow + Standard_OutOfRange_Always_Raise_if(FromIndex <= 0 || ToIndex <= 0 || (unsigned int)ToIndex > (unsigned int)mylength || (unsigned int)FromIndex > (unsigned int)ToIndex, + "TCollection_AsciiString::SubString() out of range"); return TCollection_AsciiString( &mystring [ FromIndex - 1 ] , ToIndex - FromIndex + 1 ) ; } diff --git a/src/TKRWMesh/CMakeLists.txt b/src/TKRWMesh/CMakeLists.txt new file mode 100644 index 0000000000..3c70004dfc --- /dev/null +++ b/src/TKRWMesh/CMakeLists.txt @@ -0,0 +1,3 @@ +project(TKRWMesh) + +OCCT_INCLUDE_CMAKE_FILE (adm/cmake/occt_toolkit) diff --git a/src/TKRWMesh/EXTERNLIB b/src/TKRWMesh/EXTERNLIB new file mode 100644 index 0000000000..ab12f64b7b --- /dev/null +++ b/src/TKRWMesh/EXTERNLIB @@ -0,0 +1,9 @@ +TKernel +TKMath +TKMesh +TKXCAF +TKLCAF +TKV3d +TKBRep +TKG3d +TKService diff --git a/src/TKRWMesh/FILES b/src/TKRWMesh/FILES new file mode 100644 index 0000000000..ca4f0e567b --- /dev/null +++ b/src/TKRWMesh/FILES @@ -0,0 +1,2 @@ +EXTERNLIB +PACKAGES diff --git a/src/TKRWMesh/PACKAGES b/src/TKRWMesh/PACKAGES new file mode 100644 index 0000000000..9330e3e37b --- /dev/null +++ b/src/TKRWMesh/PACKAGES @@ -0,0 +1 @@ +RWMesh diff --git a/src/TKXSDRAW/EXTERNLIB b/src/TKXSDRAW/EXTERNLIB index 77584f87a3..f72b131d24 100755 --- a/src/TKXSDRAW/EXTERNLIB +++ b/src/TKXSDRAW/EXTERNLIB @@ -19,3 +19,5 @@ TKIGES TKSTL TKVRML TKLCAF +TKDCAF +TKRWMesh diff --git a/src/V3d/V3d_TypeOfOrientation.hxx b/src/V3d/V3d_TypeOfOrientation.hxx index fb3a4f561c..a586abead7 100644 --- a/src/V3d/V3d_TypeOfOrientation.hxx +++ b/src/V3d/V3d_TypeOfOrientation.hxx @@ -17,35 +17,64 @@ #ifndef _V3d_TypeOfOrientation_HeaderFile #define _V3d_TypeOfOrientation_HeaderFile -//! Determines the type of orientation. +//! Determines the type of orientation as a combination of standard DX/DY/DZ directions. +//! This enumeration defines a model orientation looking towards the user's eye, which is an opposition to Camera main direction. +//! For example, V3d_Xneg defines +X Camera main direction. +//! +//! This enumeration defines only main Camera direction, so that the Camera up direction should be defined elsewhere for unambiguous Camera definition. +//! Open CASCADE does not force application using specific coordinate system, although Draw Harness and samples define +Z-up +Y-forward coordinate system for camera view manipulation. +//! Therefore, this enumeration also defines V3d_TypeOfOrientation_Zup_* aliases defining front/back/left/top camera orientations for +Z-up convention +//! as well as V3d_TypeOfOrientation_Yup_* aliases for another commonly used in other systems +Y-up convention. +//! Applications using other coordinate system can define their own enumeration, when found suitable. enum V3d_TypeOfOrientation { -V3d_Xpos, -V3d_Ypos, -V3d_Zpos, -V3d_Xneg, -V3d_Yneg, -V3d_Zneg, -V3d_XposYpos, -V3d_XposZpos, -V3d_YposZpos, -V3d_XnegYneg, -V3d_XnegYpos, -V3d_XnegZneg, -V3d_XnegZpos, -V3d_YnegZneg, -V3d_YnegZpos, -V3d_XposYneg, -V3d_XposZneg, -V3d_YposZneg, -V3d_XposYposZpos, -V3d_XposYnegZpos, -V3d_XposYposZneg, -V3d_XnegYposZpos, -V3d_XposYnegZneg, -V3d_XnegYposZneg, -V3d_XnegYnegZpos, -V3d_XnegYnegZneg + V3d_Xpos, //!< (+Y+Z) view + V3d_Ypos, //!< (-X+Z) view + V3d_Zpos, //!< (+X+Y) view + V3d_Xneg, //!< (-Y+Z) view + V3d_Yneg, //!< (+X+Z) view + V3d_Zneg, //!< (+X-Y) view + + V3d_XposYpos, + V3d_XposZpos, + V3d_YposZpos, + V3d_XnegYneg, + V3d_XnegYpos, + V3d_XnegZneg, + V3d_XnegZpos, + V3d_YnegZneg, + V3d_YnegZpos, + V3d_XposYneg, + V3d_XposZneg, + V3d_YposZneg, + V3d_XposYposZpos, + V3d_XposYnegZpos, + V3d_XposYposZneg, + V3d_XnegYposZpos, + V3d_XposYnegZneg, + V3d_XnegYposZneg, + V3d_XnegYnegZpos, + V3d_XnegYnegZneg, + + // +Z-up +Y-forward convention + V3d_TypeOfOrientation_Zup_AxoLeft = V3d_XnegYnegZpos, //!< +Z-up +Y-forward Left +Front+Top + V3d_TypeOfOrientation_Zup_AxoRight = V3d_XposYnegZpos, //!< +Z-up +Y-forward Right+Front+Top + V3d_TypeOfOrientation_Zup_Front = V3d_Yneg, //!< +Z-up +Y-forward Front (+X+Z) view + V3d_TypeOfOrientation_Zup_Back = V3d_Ypos, //!< +Z-up +Y-forward Back (-X+Z) view + V3d_TypeOfOrientation_Zup_Top = V3d_Zpos, //!< +Z-up +Y-forward Top (+X+Y) view + V3d_TypeOfOrientation_Zup_Bottom = V3d_Zneg, //!< +Z-up +Y-forward Bottom (+X-Y) view + V3d_TypeOfOrientation_Zup_Left = V3d_Xneg, //!< +Z-up +Y-forward Left (-Y+Z) view + V3d_TypeOfOrientation_Zup_Right = V3d_Xpos, //!< +Z-up +Y-forward Right (+Y+Z) view + + // +Y-up -Z-forward convention + V3d_TypeOfOrientation_Yup_AxoLeft = V3d_XnegYposZpos, //!< +Y-up -Z-forward Left +Front+Top + V3d_TypeOfOrientation_Yup_AxoRight = V3d_XposYposZpos, //!< +Y-up -Z-forward Right+Front+Top + V3d_TypeOfOrientation_Yup_Front = V3d_Zpos, //!< +Y-up -Z-forward Front (+X+Y) view + V3d_TypeOfOrientation_Yup_Back = V3d_Zneg, //!< +Y-up -Z-forward Back (-X+Y) view + V3d_TypeOfOrientation_Yup_Top = V3d_Ypos, //!< +Y-up -Z-forward Top (+X-Z) view + V3d_TypeOfOrientation_Yup_Bottom = V3d_Yneg, //!< +Y-up -Z-forward Bottom (-X-Z) view + V3d_TypeOfOrientation_Yup_Left = V3d_Xpos, //!< +Y-up -Z-forward Left (-Z+Y) view + V3d_TypeOfOrientation_Yup_Right = V3d_Xneg, //!< +Y-up -Z-forward Right (+Z+Y) view }; #endif // _V3d_TypeOfOrientation_HeaderFile diff --git a/src/V3d/V3d_View.cxx b/src/V3d/V3d_View.cxx index af34004aa0..b67123ac85 100644 --- a/src/V3d/V3d_View.cxx +++ b/src/V3d/V3d_View.cxx @@ -1019,38 +1019,42 @@ void V3d_View::SetProj( const Standard_Real Vx,const Standard_Real Vy, const Sta //function : SetProj //purpose : //============================================================================= -void V3d_View::SetProj( const V3d_TypeOfOrientation Orientation ) +void V3d_View::SetProj (const V3d_TypeOfOrientation theOrientation, + const Standard_Boolean theIsYup) { - Standard_Real Xpn=0; - Standard_Real Ypn=0; - Standard_Real Zpn=0; - - switch (Orientation) { - case V3d_Zpos : - Ypn = 1.; - break; - case V3d_Zneg : - Ypn = -1.; - break; - default: - Zpn = 1.; + Graphic3d_Vec3d anUp = theIsYup ? Graphic3d_Vec3d (0.0, 1.0, 0.0) : Graphic3d_Vec3d (0.0, 0.0, 1.0); + if (theIsYup) + { + if (theOrientation == V3d_Ypos + || theOrientation == V3d_Yneg) + { + anUp.SetValues (0.0, 0.0, -1.0); + } + } + else + { + if (theOrientation == V3d_Zpos) + { + anUp.SetValues (0.0, 1.0, 0.0); + } + else if (theOrientation == V3d_Zneg) + { + anUp.SetValues (0.0, -1.0, 0.0); + } } - const gp_Dir aBck = V3d::GetProjAxis (Orientation); + const gp_Dir aBck = V3d::GetProjAxis (theOrientation); // retain camera panning from origin when switching projection - Handle(Graphic3d_Camera) aCamera = Camera(); - - gp_Pnt anOriginVCS = aCamera->ConvertWorld2View (gp::Origin()); - Standard_Real aPanX = anOriginVCS.X(); - Standard_Real aPanY = anOriginVCS.Y(); + const Handle(Graphic3d_Camera)& aCamera = Camera(); + const gp_Pnt anOriginVCS = aCamera->ConvertWorld2View (gp::Origin()); aCamera->SetCenter (gp_Pnt (0, 0, 0)); aCamera->SetDirection (gp_Dir (aBck.X(), aBck.Y(), aBck.Z()).Reversed()); - aCamera->SetUp (gp_Dir (Xpn, Ypn, Zpn)); + aCamera->SetUp (gp_Dir (anUp.x(), anUp.y(), anUp.z())); aCamera->OrthogonalizeUp(); - Panning (aPanX, aPanY); + Panning (anOriginVCS.X(), anOriginVCS.Y()); AutoZFit(); diff --git a/src/V3d/V3d_View.hxx b/src/V3d/V3d_View.hxx index 9249d97787..d1e6129bf4 100644 --- a/src/V3d/V3d_View.hxx +++ b/src/V3d/V3d_View.hxx @@ -410,7 +410,10 @@ public: Standard_EXPORT void SetProj (const Standard_Real Vx, const Standard_Real Vy, const Standard_Real Vz); //! Defines the orientation of the projection . - Standard_EXPORT void SetProj (const V3d_TypeOfOrientation Orientation); + //! @param theOrientation camera direction + //! @param theIsYup flag indicating Y-up (TRUE) or Z-up (FALSE) convention + Standard_EXPORT void SetProj (const V3d_TypeOfOrientation theOrientation, + const Standard_Boolean theIsYup = Standard_False); //! Defines the position of the view point. Standard_EXPORT void SetAt (const Standard_Real X, const Standard_Real Y, const Standard_Real Z); diff --git a/src/ViewerTest/ViewerTest_ViewerCommands.cxx b/src/ViewerTest/ViewerTest_ViewerCommands.cxx index 465947ff6b..523c03bab2 100644 --- a/src/ViewerTest/ViewerTest_ViewerCommands.cxx +++ b/src/ViewerTest/ViewerTest_ViewerCommands.cxx @@ -3180,97 +3180,307 @@ void ViewerTest::GetMousePosition(Standard_Integer& Xpix,Standard_Integer& Ypix) } //============================================================================== -//function : ViewProject: implements VAxo, VTop, VLeft, ... -//purpose : Switches to an axonometric, top, left and other views +//function : VViewProj +//purpose : Switch view projection //============================================================================== - -static int ViewProject(Draw_Interpretor& di, const V3d_TypeOfOrientation ori) +static int VViewProj (Draw_Interpretor& , + Standard_Integer theNbArgs, + const char** theArgVec) { - if ( ViewerTest::CurrentView().IsNull() ) + static Standard_Boolean isYup = Standard_False; + const Handle(V3d_View)& aView = ViewerTest::CurrentView(); + if (aView.IsNull()) { - di<<"Call vinit before this command, please\n"; + std::cout << "Error: no active view\n"; return 1; } - ViewerTest::CurrentView()->SetProj(ori); - return 0; -} - -//============================================================================== -//function : VAxo -//purpose : Switch to an Axonometric view -//Draw arg : No args -//============================================================================== - -static int VAxo(Draw_Interpretor& di, Standard_Integer , const char** ) -{ - return ViewProject(di, V3d_XposYnegZpos); -} - -//============================================================================== -//function : VTop -//purpose : Switch to a Top View -//Draw arg : No args -//============================================================================== - -static int VTop(Draw_Interpretor& di, Standard_Integer , const char** ) -{ - return ViewProject(di, V3d_Zpos); -} - -//============================================================================== -//function : VBottom -//purpose : Switch to a Bottom View -//Draw arg : No args -//============================================================================== - -static int VBottom(Draw_Interpretor& di, Standard_Integer , const char** ) -{ - return ViewProject(di, V3d_Zneg); -} - -//============================================================================== -//function : VLeft -//purpose : Switch to a Left View -//Draw arg : No args -//============================================================================== - -static int VLeft(Draw_Interpretor& di, Standard_Integer , const char** ) -{ - return ViewProject(di, V3d_Xneg); -} - -//============================================================================== -//function : VRight -//purpose : Switch to a Right View -//Draw arg : No args -//============================================================================== + TCollection_AsciiString aCmdName (theArgVec[0]); + Standard_Boolean isGeneralCmd = Standard_False; + if (aCmdName == "vfront") + { + aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Front : V3d_TypeOfOrientation_Zup_Front, isYup); + } + else if (aCmdName == "vback") + { + aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Back : V3d_TypeOfOrientation_Zup_Back, isYup); + } + else if (aCmdName == "vtop") + { + aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Top : V3d_TypeOfOrientation_Zup_Top, isYup); + } + else if (aCmdName == "vbottom") + { + aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Bottom : V3d_TypeOfOrientation_Zup_Bottom, isYup); + } + else if (aCmdName == "vleft") + { + aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Left : V3d_TypeOfOrientation_Zup_Left, isYup); + } + else if (aCmdName == "vright") + { + aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Right : V3d_TypeOfOrientation_Zup_Right, isYup); + } + else if (aCmdName == "vaxo") + { + aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_AxoRight : V3d_TypeOfOrientation_Zup_AxoRight, isYup); + } + else + { + isGeneralCmd = Standard_True; + for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter) + { + TCollection_AsciiString anArgCase (theArgVec[anArgIter]); + anArgCase.LowerCase(); + if (anArgCase == "-zup") + { + isYup = Standard_False; + } + else if (anArgCase == "-yup") + { + isYup = Standard_True; + } + else if (anArgCase == "-front" + || anArgCase == "front" + || anArgCase == "-f" + || anArgCase == "f") + { + aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Front : V3d_TypeOfOrientation_Zup_Front, isYup); + } + else if (anArgCase == "-back" + || anArgCase == "back" + || anArgCase == "-b" + || anArgCase == "b") + { + aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Back : V3d_TypeOfOrientation_Zup_Back, isYup); + } + else if (anArgCase == "-top" + || anArgCase == "top" + || anArgCase == "-t" + || anArgCase == "t") + { + aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Top : V3d_TypeOfOrientation_Zup_Top, isYup); + } + else if (anArgCase == "-bottom" + || anArgCase == "bottom" + || anArgCase == "-bot" + || anArgCase == "bot" + || anArgCase == "-b" + || anArgCase == "b") + { + aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Bottom : V3d_TypeOfOrientation_Zup_Bottom, isYup); + } + else if (anArgCase == "-left" + || anArgCase == "left" + || anArgCase == "-l" + || anArgCase == "l") + { + aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Left : V3d_TypeOfOrientation_Zup_Left, isYup); + } + else if (anArgCase == "-right" + || anArgCase == "right" + || anArgCase == "-r" + || anArgCase == "r") + { + aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Right : V3d_TypeOfOrientation_Zup_Right, isYup); + } + else if (anArgCase == "-axoleft" + || anArgCase == "-leftaxo" + || anArgCase == "axoleft" + || anArgCase == "leftaxo") + { + aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_AxoLeft : V3d_TypeOfOrientation_Zup_AxoLeft, isYup); + } + else if (anArgCase == "-axo" + || anArgCase == "axo" + || anArgCase == "-a" + || anArgCase == "a" + || anArgCase == "-axoright" + || anArgCase == "-rightaxo" + || anArgCase == "axoright" + || anArgCase == "rightaxo") + { + aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_AxoRight : V3d_TypeOfOrientation_Zup_AxoRight, isYup); + } + else if (anArgCase == "+x") + { + aView->SetProj (V3d_Xpos, isYup); + } + else if (anArgCase == "-x") + { + aView->SetProj (V3d_Xneg, isYup); + } + else if (anArgCase == "+y") + { + aView->SetProj (V3d_Ypos, isYup); + } + else if (anArgCase == "-y") + { + aView->SetProj (V3d_Yneg, isYup); + } + else if (anArgCase == "+z") + { + aView->SetProj (V3d_Zpos, isYup); + } + else if (anArgCase == "-z") + { + aView->SetProj (V3d_Zneg, isYup); + } + else if (anArgCase == "+x+y+z") + { + aView->SetProj (V3d_XposYposZpos, isYup); + } + else if (anArgCase == "+x+y-z") + { + aView->SetProj (V3d_XposYposZneg, isYup); + } + else if (anArgCase == "+x-y+z") + { + aView->SetProj (V3d_XposYnegZpos, isYup); + } + else if (anArgCase == "+x-y-z") + { + aView->SetProj (V3d_XposYnegZneg, isYup); + } + else if (anArgCase == "-x+y+z") + { + aView->SetProj (V3d_XnegYposZpos, isYup); + } + else if (anArgCase == "-x+y-z") + { + aView->SetProj (V3d_XnegYposZneg, isYup); + } + else if (anArgCase == "-x-y+z") + { + aView->SetProj (V3d_XnegYnegZpos, isYup); + } + else if (anArgCase == "-x-y-z") + { + aView->SetProj (V3d_XnegYnegZneg, isYup); + } + else if (anArgCase == "+x+y") + { + aView->SetProj (V3d_XposYpos, isYup); + } + else if (anArgCase == "+x-y") + { + aView->SetProj (V3d_XposYneg, isYup); + } + else if (anArgCase == "-x+y") + { + aView->SetProj (V3d_XnegYpos, isYup); + } + else if (anArgCase == "-x-y") + { + aView->SetProj (V3d_XnegYneg, isYup); + } + else if (anArgCase == "+x+z") + { + aView->SetProj (V3d_XposZpos, isYup); + } + else if (anArgCase == "+x-z") + { + aView->SetProj (V3d_XposZneg, isYup); + } + else if (anArgCase == "-x+z") + { + aView->SetProj (V3d_XnegZpos, isYup); + } + else if (anArgCase == "-x-z") + { + aView->SetProj (V3d_XnegZneg, isYup); + } + else if (anArgCase == "+y+z") + { + aView->SetProj (V3d_YposZpos, isYup); + } + else if (anArgCase == "+y-z") + { + aView->SetProj (V3d_YposZneg, isYup); + } + else if (anArgCase == "-y+z") + { + aView->SetProj (V3d_YnegZpos, isYup); + } + else if (anArgCase == "-y-z") + { + aView->SetProj (V3d_YnegZneg, isYup); + } + else if (anArgIter + 1 < theNbArgs + && anArgCase == "-frame" + && TCollection_AsciiString (theArgVec[anArgIter + 1]).Length() == 4) + { + TCollection_AsciiString aFrameDef (theArgVec[++anArgIter]); + aFrameDef.LowerCase(); + gp_Dir aRight, anUp; + if (aFrameDef.Value (2) == aFrameDef.Value (4)) + { + std::cout << "Syntax error at '" << theArgVec[anArgIter] << "'\n"; + return 1; + } -static int VRight(Draw_Interpretor& di, Standard_Integer , const char** ) -{ - return ViewProject(di, V3d_Xpos); -} + if (aFrameDef.Value (2) == 'x') + { + aRight = aFrameDef.Value (1) == '+' ? gp::DX() : -gp::DX(); + } + else if (aFrameDef.Value (2) == 'y') + { + aRight = aFrameDef.Value (1) == '+' ? gp::DY() : -gp::DY(); + } + else if (aFrameDef.Value (2) == 'z') + { + aRight = aFrameDef.Value (1) == '+' ? gp::DZ() : -gp::DZ(); + } + else + { + std::cout << "Syntax error at '" << theArgVec[anArgIter] << "'\n"; + return 1; + } -//============================================================================== -//function : VFront -//purpose : Switch to a Front View -//Draw arg : No args -//============================================================================== + if (aFrameDef.Value (4) == 'x') + { + anUp = aFrameDef.Value (3) == '+' ? gp::DX() : -gp::DX(); + } + else if (aFrameDef.Value (4) == 'y') + { + anUp = aFrameDef.Value (3) == '+' ? gp::DY() : -gp::DY(); + } + else if (aFrameDef.Value (4) == 'z') + { + anUp = aFrameDef.Value (3) == '+' ? gp::DZ() : -gp::DZ(); + } + else + { + std::cout << "Syntax error at '" << theArgVec[anArgIter] << "'\n"; + return 1; + } -static int VFront(Draw_Interpretor& di, Standard_Integer , const char** ) -{ - return ViewProject(di, V3d_Yneg); -} + const Handle(Graphic3d_Camera)& aCamera = aView->Camera(); + const gp_Pnt anOriginVCS = aCamera->ConvertWorld2View (gp::Origin()); + const gp_Dir aDir = anUp.Crossed (aRight); + aCamera->SetCenter (gp_Pnt (0, 0, 0)); + aCamera->SetDirection (aDir); + aCamera->SetUp (anUp); + aCamera->OrthogonalizeUp(); -//============================================================================== -//function : VBack -//purpose : Switch to a Back View -//Draw arg : No args -//============================================================================== + aView->Panning (anOriginVCS.X(), anOriginVCS.Y()); + aView->Update(); + } + else + { + std::cout << "Syntax error at '" << theArgVec[anArgIter] << "'\n"; + return 1; + } + } + } -static int VBack(Draw_Interpretor& di, Standard_Integer , const char** ) -{ - return ViewProject(di, V3d_Ypos); + if (!isGeneralCmd + && theNbArgs != 1) + { + std::cout << "Syntax error: wrong number of arguments\n"; + return 1; + } + return 0; } //============================================================================== @@ -13543,27 +13753,38 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands) theCommands.Add("vhelp" , "vhelp : display help on the viewer commands", __FILE__,VHelp,group); + theCommands.Add("vviewproj", + "vviewproj [top|bottom|left|right|front|back|axoLeft|axoRight]" + "\n\t\t: [+-X+-Y+-Z] [-Zup|-Yup] [-frame +-X+-Y]" + "\n\t\t: Setup view direction" + "\n\t\t: -Yup use Y-up convention instead of Zup (which is default)." + "\n\t\t: +-X+-Y+-Z define direction as combination of DX, DY and DZ;" + "\n\t\t: for example '+Z' will show front of the model," + "\n\t\t: '-X-Y+Z' will define left axonometrical view." + "\n\t\t: -frame define camera Up and Right directions (regardless Up convention);" + "\n\t\t: for example '+X+Z' will show front of the model with Z-up." + __FILE__,VViewProj,group); theCommands.Add("vtop" , "vtop or : Top view. Orientation +X+Y" , - __FILE__,VTop,group); + __FILE__,VViewProj,group); theCommands.Add("vbottom" , "vbottom : Bottom view. Orientation +X-Y" , - __FILE__,VBottom,group); + __FILE__,VViewProj,group); theCommands.Add("vleft" , "vleft : Left view. Orientation -Y+Z" , - __FILE__,VLeft,group); + __FILE__,VViewProj,group); theCommands.Add("vright" , "vright : Right view. Orientation +Y+Z" , - __FILE__,VRight,group); + __FILE__,VViewProj,group); theCommands.Add("vaxo" , " vaxo or : Axonometric view. Orientation +X-Y+Z", - __FILE__,VAxo,group); + __FILE__,VViewProj,group); theCommands.Add("vfront" , "vfront : Front view. Orientation +X+Z" , - __FILE__,VFront,group); + __FILE__,VViewProj,group); theCommands.Add("vback" , "vback : Back view. Orientation -X+Z" , - __FILE__,VBack,group); + __FILE__,VViewProj,group); theCommands.Add("vpick" , "vpick : vpick X Y Z [shape subshape] ( all variables as string )", VPick,group); diff --git a/src/XCAFPrs/FILES b/src/XCAFPrs/FILES index a0185927e8..77d00e029b 100644 --- a/src/XCAFPrs/FILES +++ b/src/XCAFPrs/FILES @@ -8,6 +8,10 @@ XCAFPrs_DataMapIteratorOfDataMapOfStyleTransient.hxx XCAFPrs_IndexedDataMapOfShapeStyle.hxx XCAFPrs_DataMapOfStyleShape.hxx XCAFPrs_DataMapOfStyleTransient.hxx +XCAFPrs_DocumentExplorer.cxx +XCAFPrs_DocumentExplorer.hxx +XCAFPrs_DocumentIdIterator.hxx +XCAFPrs_DocumentNode.hxx XCAFPrs_Driver.cxx XCAFPrs_Driver.hxx XCAFPrs_Style.cxx diff --git a/src/XCAFPrs/XCAFPrs_DocumentExplorer.cxx b/src/XCAFPrs/XCAFPrs_DocumentExplorer.cxx new file mode 100644 index 0000000000..c5fbb70891 --- /dev/null +++ b/src/XCAFPrs/XCAFPrs_DocumentExplorer.cxx @@ -0,0 +1,441 @@ +// Author: Kirill Gavrilov +// Copyright (c) 2017-2019 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#include + +#include +#include +#include +#include +#include +#include + +namespace +{ + //! Return merged style for the child node. + static XCAFPrs_Style mergedStyle (const Handle(XCAFDoc_ColorTool)& theColorTool, + const XCAFPrs_Style& theParenStyle, + const TDF_Label& theLabel, + const TDF_Label& theRefLabel) + { + if (theColorTool.IsNull()) + { + return theParenStyle; + } + + XCAFPrs_Style aStyle = theParenStyle; + Quantity_ColorRGBA aColor; + if (theColorTool->GetColor (theRefLabel, XCAFDoc_ColorGen, aColor)) + { + aStyle.SetColorCurv (aColor.GetRGB()); + aStyle.SetColorSurf (aColor); + } + if (theColorTool->GetColor (theRefLabel, XCAFDoc_ColorSurf, aColor)) + { + aStyle.SetColorSurf (aColor); + } + if (theColorTool->GetColor (theRefLabel, XCAFDoc_ColorCurv, aColor)) + { + aStyle.SetColorCurv (aColor.GetRGB()); + } + + if (theLabel != theRefLabel) + { + // override Reference style with Instance style when defined (bad model?) + if (theColorTool->GetColor (theLabel, XCAFDoc_ColorGen, aColor)) + { + aStyle.SetColorCurv (aColor.GetRGB()); + aStyle.SetColorSurf (aColor); + } + if (theColorTool->GetColor (theLabel, XCAFDoc_ColorSurf, aColor)) + { + aStyle.SetColorSurf (aColor); + } + if (theColorTool->GetColor (theLabel, XCAFDoc_ColorCurv, aColor)) + { + aStyle.SetColorCurv (aColor.GetRGB()); + } + } + + return aStyle; + } +} + +// ======================================================================= +// function : DefineChildId +// purpose : +// ======================================================================= +TCollection_AsciiString XCAFPrs_DocumentExplorer::DefineChildId (const TDF_Label& theLabel, + const TCollection_AsciiString& theParentId) +{ + TCollection_AsciiString anEntryId; + TDF_Tool::Entry (theLabel, anEntryId); + return !theParentId.IsEmpty() + ? theParentId + "/" + anEntryId + "." + : anEntryId + "."; +} + +// ======================================================================= +// function : FindLabelFromPathId +// purpose : +// ======================================================================= +TDF_Label XCAFPrs_DocumentExplorer::FindLabelFromPathId (const Handle(TDocStd_Document)& theDocument, + const TCollection_AsciiString& theId, + TopLoc_Location& theParentLocation, + TopLoc_Location& theLocation) +{ + theParentLocation = TopLoc_Location(); + theLocation = TopLoc_Location(); + TDF_Label anInstanceLabel; + for (XCAFPrs_DocumentIdIterator anPathIter (theId); anPathIter.More();) + { + TDF_Label aSubLabel; + { + const TCollection_AsciiString& anOcafId = anPathIter.Value(); + TDF_Tool::Label (theDocument->Main().Data(), anOcafId, aSubLabel); + if (aSubLabel.IsNull()) + { + return TDF_Label(); + } + } + + anPathIter.Next(); + if (!anPathIter.More()) + { + theParentLocation = theLocation; + } + + TopLoc_Location aLocTrsf = XCAFDoc_ShapeTool::GetLocation (aSubLabel); + theLocation = theLocation * aLocTrsf; + anInstanceLabel = aSubLabel; + } + return anInstanceLabel; +} + +// ======================================================================= +// function : FindShapeFromPathId +// purpose : +// ======================================================================= +TopoDS_Shape XCAFPrs_DocumentExplorer::FindShapeFromPathId (const Handle(TDocStd_Document)& theDocument, + const TCollection_AsciiString& theId) +{ + TopLoc_Location aLocation; + TDF_Label anInstanceLabel = FindLabelFromPathId (theDocument, theId, aLocation); + if (anInstanceLabel.IsNull()) + { + return TopoDS_Shape(); + } + + TDF_Label aRefLabel = anInstanceLabel; + XCAFDoc_ShapeTool::GetReferredShape (anInstanceLabel, aRefLabel); + if (aRefLabel.IsNull()) + { + return TopoDS_Shape(); + } + + TopoDS_Shape aShape = XCAFDoc_ShapeTool::GetShape (aRefLabel); + if (aShape.IsNull()) + { + return TopoDS_Shape(); + } + + aShape.Location (aLocation); + return aShape; +} + +// ======================================================================= +// function : XCAFPrs_DocumentExplorer +// purpose : +// ======================================================================= +XCAFPrs_DocumentExplorer::XCAFPrs_DocumentExplorer() +: myTop (-1), + myHasMore (Standard_False), + myFlags (XCAFPrs_DocumentExplorerFlags_None) +{ + // +} + +// ======================================================================= +// function : XCAFPrs_DocumentExplorer +// purpose : +// ======================================================================= +XCAFPrs_DocumentExplorer::XCAFPrs_DocumentExplorer (const Handle(TDocStd_Document)& theDocument, + const XCAFPrs_DocumentExplorerFlags theFlags, + const XCAFPrs_Style& theDefStyle) +: myTop (-1), + myHasMore (Standard_False), + myFlags (XCAFPrs_DocumentExplorerFlags_None) +{ + Handle(XCAFDoc_ShapeTool) aShapeTool = XCAFDoc_DocumentTool::ShapeTool (theDocument->Main()); + TDF_LabelSequence aRootLabels; + aShapeTool->GetFreeShapes (aRootLabels); + Init (theDocument, aRootLabels, theFlags, theDefStyle); +} + +// ======================================================================= +// function : XCAFPrs_DocumentExplorer +// purpose : +// ======================================================================= +XCAFPrs_DocumentExplorer::XCAFPrs_DocumentExplorer (const Handle(TDocStd_Document)& theDocument, + const TDF_LabelSequence& theRoots, + const XCAFPrs_DocumentExplorerFlags theFlags, + const XCAFPrs_Style& theDefStyle) +: myTop (-1), + myHasMore (Standard_False), + myFlags (XCAFPrs_DocumentExplorerFlags_None) +{ + Init (theDocument, theRoots, theFlags, theDefStyle); +} + +// ======================================================================= +// function : Init +// purpose : +// ======================================================================= +void XCAFPrs_DocumentExplorer::Init (const Handle(TDocStd_Document)& theDocument, + const TDF_Label& theRoot, + const XCAFPrs_DocumentExplorerFlags theFlags, + const XCAFPrs_Style& theDefStyle) +{ + TDF_LabelSequence aSeq; + aSeq.Append (theRoot); + Init (theDocument, aSeq, theFlags, theDefStyle); +} + +// ======================================================================= +// function : Init +// purpose : +// ======================================================================= +void XCAFPrs_DocumentExplorer::Init (const Handle(TDocStd_Document)& theDocument, + const TDF_LabelSequence& theRoots, + const XCAFPrs_DocumentExplorerFlags theFlags, + const XCAFPrs_Style& theDefStyle) +{ + if ((theFlags & XCAFPrs_DocumentExplorerFlags_NoStyle) != 0) + { + myColorTool = XCAFDoc_DocumentTool::ColorTool (theDocument->Main()); + } + else + { + myColorTool.Nullify(); + } + + ///myColorTool = theColorTool; + myDefStyle = theDefStyle; + myRoots = theRoots; + myRootIter = TDF_LabelSequence::Iterator (myRoots); + myFlags = theFlags; + initRoot(); +} + +// ======================================================================= +// function : initRoot +// purpose : +// ======================================================================= +void XCAFPrs_DocumentExplorer::initRoot() +{ + for (;;) + { + // reset the stack + for (Standard_Integer aStackIter = 0; aStackIter <= myTop; ++aStackIter) + { + myNodeStack.SetValue (aStackIter, XCAFPrs_DocumentNode()); + } + myTop = -1; + if (!myRootIter.More()) + { + myHasMore = Standard_False; + initCurrent (Standard_False); + return; + } + + const TDF_Label& aRootLab = myRootIter.Value(); + if (aRootLab.IsNull()) + { + // assert - invalid input + //Standard_ProgramError::Raise ("CadDocumentExplorer - NULL label in the input"); + myRootIter.Next(); + continue; + } + + myHasMore = Standard_True; + TDF_Label aRefLabel = aRootLab; + XCAFDoc_ShapeTool::GetReferredShape (aRootLab, aRefLabel); + if (XCAFDoc_ShapeTool::IsAssembly (aRefLabel)) + { + Next(); + } + else + { + initCurrent (Standard_False); + } + return; + } +} + +// ======================================================================= +// function : initCurrent +// purpose : +// ======================================================================= +void XCAFPrs_DocumentExplorer::initCurrent (Standard_Boolean theIsAssmebly) +{ + myCurrent = XCAFPrs_DocumentNode(); + if (theIsAssmebly) + { + if (myTop < 0) + { + Standard_ProgramError::Raise ("CadDocumentExplorer - internal error"); + } + myCurrent = myNodeStack.Value (myTop); + } + else if (myTop < 0) + { + if (!myRootIter.More()) + { + return; + } + + myCurrent.Label = myRootIter.Value(); + myCurrent.RefLabel = myCurrent.Label; + XCAFDoc_ShapeTool::GetReferredShape (myCurrent.Label, myCurrent.RefLabel); + myCurrent.LocalTrsf= XCAFDoc_ShapeTool::GetLocation (myCurrent.Label); + myCurrent.Location = myCurrent.LocalTrsf; + myCurrent.Style = mergedStyle (myColorTool, myDefStyle, myCurrent.Label, myCurrent.RefLabel); + myCurrent.Id = DefineChildId (myCurrent.Label, TCollection_AsciiString()); + } + else + { + const XCAFPrs_DocumentNode& aTopNodeInStack = myNodeStack.Value (myTop); + myCurrent.Label = aTopNodeInStack.ChildIter.Value(); + myCurrent.RefLabel = myCurrent.Label; + XCAFDoc_ShapeTool::GetReferredShape (myCurrent.Label, myCurrent.RefLabel); + myCurrent.LocalTrsf= XCAFDoc_ShapeTool::GetLocation (myCurrent.Label); + myCurrent.Location = aTopNodeInStack.Location * myCurrent.LocalTrsf; + myCurrent.Style = mergedStyle (myColorTool, aTopNodeInStack.Style, myCurrent.Label, myCurrent.RefLabel); + myCurrent.Id = DefineChildId (myCurrent.Label, aTopNodeInStack.Id); + } +} + +// ======================================================================= +// function : Next +// purpose : +// ======================================================================= +void XCAFPrs_DocumentExplorer::Next() +{ + if (!myHasMore) + { + Standard_ProgramError::Raise ("CadDocumentExplorer::Next() - out of range"); + return; // assert + } + + if (myTop < 0) + { + const TDF_Label& aRootLab = myRootIter.Value(); + TDF_Label aRefLabel = aRootLab; + XCAFDoc_ShapeTool::GetReferredShape (aRootLab, aRefLabel); + if (!XCAFDoc_ShapeTool::IsAssembly (aRefLabel)) + { + // already visited once + myRootIter.Next(); + initRoot(); + return; + } + + // push and try to find + myTop = 0; + XCAFPrs_DocumentNode aNodeInStack; + aNodeInStack.IsAssembly = Standard_True; + aNodeInStack.Label = aRootLab; + aNodeInStack.RefLabel = aRefLabel; + aNodeInStack.ChildIter = TDF_ChildIterator (aNodeInStack.RefLabel); + aNodeInStack.LocalTrsf = XCAFDoc_ShapeTool::GetLocation (aNodeInStack.Label); + aNodeInStack.Location = aNodeInStack.LocalTrsf; + aNodeInStack.Style = mergedStyle (myColorTool, myDefStyle, aNodeInStack.Label, aNodeInStack.RefLabel); + aNodeInStack.Id = DefineChildId (aNodeInStack.Label, TCollection_AsciiString()); + myNodeStack.SetValue (0, aNodeInStack); + if ((myFlags & XCAFPrs_DocumentExplorerFlags_OnlyLeafNodes) == 0) + { + initCurrent (Standard_True); + return; + } + } + else + { + if (!myCurrent.IsAssembly) + { + myNodeStack.ChangeValue (myTop).ChildIter.Next(); + } + } + + for (;;) + { + if (myNodeStack.Value (myTop).ChildIter.More()) + { + const TDF_Label& aNodeTop = myNodeStack.Value (myTop).ChildIter.Value(); + if (aNodeTop.IsNull() + || (!aNodeTop.HasChild() && !aNodeTop.HasAttribute())) + { + myNodeStack.ChangeValue (myTop).ChildIter.Next(); + continue; + } + + TDF_Label aRefLabel = aNodeTop; + XCAFDoc_ShapeTool::GetReferredShape (aNodeTop, aRefLabel); + if (!XCAFDoc_ShapeTool::IsAssembly (aRefLabel)) + { + myHasMore = Standard_True; + initCurrent (Standard_False); + return; + } + else if (aRefLabel.HasAttribute() + || aRefLabel.HasChild()) + { + const XCAFPrs_DocumentNode& aParent = myNodeStack.Value (myTop); + ++myTop; + + XCAFPrs_DocumentNode aNodeInStack; + aNodeInStack.IsAssembly = Standard_True; + aNodeInStack.Label = aNodeTop; + aNodeInStack.RefLabel = aRefLabel; + aNodeInStack.LocalTrsf = XCAFDoc_ShapeTool::GetLocation (aNodeInStack.Label); + aNodeInStack.Location = aParent.Location * aNodeInStack.LocalTrsf; + aNodeInStack.Style = mergedStyle (myColorTool, aParent.Style, aNodeInStack.Label, aNodeInStack.RefLabel); + aNodeInStack.Id = DefineChildId (aNodeInStack.Label, aParent.Id); + aNodeInStack.ChildIter = TDF_ChildIterator (aNodeInStack.RefLabel); + myNodeStack.SetValue (myTop, aNodeInStack); + if ((myFlags & XCAFPrs_DocumentExplorerFlags_OnlyLeafNodes) == 0) + { + initCurrent (Standard_True); + return; + } + } + else + { + myNodeStack.ChangeValue (myTop).ChildIter.Next(); + } + } + else + { + myNodeStack.SetValue (myTop, XCAFPrs_DocumentNode()); + --myTop; + if (myTop < 0) + { + myRootIter.Next(); + initRoot(); + return; + } + + myNodeStack.ChangeValue (myTop).ChildIter.Next(); + } + } +} diff --git a/src/XCAFPrs/XCAFPrs_DocumentExplorer.hxx b/src/XCAFPrs/XCAFPrs_DocumentExplorer.hxx new file mode 100644 index 0000000000..f617b905d4 --- /dev/null +++ b/src/XCAFPrs/XCAFPrs_DocumentExplorer.hxx @@ -0,0 +1,174 @@ +// Author: Kirill Gavrilov +// Copyright (c) 2017-2019 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 _XCAFPrs_DocumentExplorer_HeaderFile +#define _XCAFPrs_DocumentExplorer_HeaderFile + +#include +#include +#include +#include +#include + +class TDocStd_Document; +class XCAFDoc_ShapeTool; +class XCAFDoc_ColorTool; + +typedef Standard_Integer XCAFPrs_DocumentExplorerFlags; + +//! Document explorer flags. +enum +{ + XCAFPrs_DocumentExplorerFlags_None = 0x00, //!< no flags + XCAFPrs_DocumentExplorerFlags_OnlyLeafNodes = 0x01, //!< explore only leaf nodes (skip assembly nodes) + XCAFPrs_DocumentExplorerFlags_NoStyle = 0x02, //!< do not fetch styles +}; + +//! Document iterator through shape nodes. +class XCAFPrs_DocumentExplorer +{ +public: //! @name string identification tools + + //! Construct a unique string identifier for the given label. + //! The identifier is a concatenation of label entries (TDF_Tool::Entry() with tailing '.') of hierarchy from parent to child + //! joined via '/' and looking like this: + //! @code + //! 0:1:1:1./0:1:1:1:9./0:1:1:5:7. + //! @endcode + //! This generation scheme also allows finding originating labels using TDF_Tool::Label(). + //! The tailing dot simplifies parent equality check. + //! @param theLabel child label to define id + //! @param theParentId parent string identifier defined by this method + Standard_EXPORT static TCollection_AsciiString DefineChildId (const TDF_Label& theLabel, + const TCollection_AsciiString& theParentId); + + //! Find a shape entity based on a text identifier constructed from OCAF labels defining full path. + //! @sa DefineChildId() + Standard_EXPORT static TDF_Label FindLabelFromPathId (const Handle(TDocStd_Document)& theDocument, + const TCollection_AsciiString& theId, + TopLoc_Location& theParentLocation, + TopLoc_Location& theLocation); + + //! Find a shape entity based on a text identifier constructed from OCAF labels defining full path. + //! @sa DefineChildId() + static TDF_Label FindLabelFromPathId (const Handle(TDocStd_Document)& theDocument, + const TCollection_AsciiString& theId, + TopLoc_Location& theLocation) + { + TopLoc_Location aDummy; + return FindLabelFromPathId (theDocument, theId, aDummy, theLocation); + } + + //! Find a shape entity based on a text identifier constructed from OCAF labels defining full path. + //! @sa DefineChildId() + Standard_EXPORT static TopoDS_Shape FindShapeFromPathId (const Handle(TDocStd_Document)& theDocument, + const TCollection_AsciiString& theId); + +public: + + //! Empty constructor. + Standard_EXPORT XCAFPrs_DocumentExplorer(); + + //! Constructor for exploring the whole document. + //! @param theDocument document to explore + //! @param theFlags iteration flags + //! @param theDefStyle default style for nodes with undefined style + Standard_EXPORT XCAFPrs_DocumentExplorer (const Handle(TDocStd_Document)& theDocument, + const XCAFPrs_DocumentExplorerFlags theFlags, + const XCAFPrs_Style& theDefStyle = XCAFPrs_Style()); + + //! Constructor for exploring specified list of root shapes in the document. + //! @param theDocument document to explore + //! @param theRoots root labels to explore within specified document + //! @param theFlags iteration flags + //! @param theDefStyle default style for nodes with undefined style + Standard_EXPORT XCAFPrs_DocumentExplorer (const Handle(TDocStd_Document)& theDocument, + const TDF_LabelSequence& theRoots, + const XCAFPrs_DocumentExplorerFlags theFlags, + const XCAFPrs_Style& theDefStyle = XCAFPrs_Style()); + + //! Initialize the iterator from a single root shape in the document. + //! @param theDocument document to explore + //! @param theRoot single root label to explore within specified document + //! @param theFlags iteration flags + //! @param theDefStyle default style for nodes with undefined style + Standard_EXPORT void Init (const Handle(TDocStd_Document)& theDocument, + const TDF_Label& theRoot, + const XCAFPrs_DocumentExplorerFlags theFlags, + const XCAFPrs_Style& theDefStyle = XCAFPrs_Style()); + + //! Initialize the iterator from the list of root shapes in the document. + //! @param theDocument document to explore + //! @param theRoots root labels to explore within specified document + //! @param theFlags iteration flags + //! @param theDefStyle default style for nodes with undefined style + Standard_EXPORT void Init (const Handle(TDocStd_Document)& theDocument, + const TDF_LabelSequence& theRoots, + const XCAFPrs_DocumentExplorerFlags theFlags, + const XCAFPrs_Style& theDefStyle = XCAFPrs_Style()); + + //! Return TRUE if iterator points to the valid node. + Standard_Boolean More() const { return myHasMore; } + + //! Return current position. + const XCAFPrs_DocumentNode& Current() const { return myCurrent; } + + //! Return current position. + XCAFPrs_DocumentNode& ChangeCurrent() { return myCurrent; } + + //! Return current position within specified assembly depth. + const XCAFPrs_DocumentNode& Current (Standard_Integer theDepth) const + { + const Standard_Integer aCurrDepth = CurrentDepth(); + if (theDepth == aCurrDepth) + { + return myCurrent; + } + + Standard_OutOfRange_Raise_if (theDepth < 0 || theDepth > myTop, + "XCAFPrs_DocumentExplorer::Current() out of range"); + return myNodeStack.Value (theDepth); + } + + //! Return depth of the current node in hierarchy, starting from 0. + //! Zero means Root label. + Standard_Integer CurrentDepth() const { return myCurrent.IsAssembly ? myTop : myTop + 1; } + + //! Go to the next node. + Standard_EXPORT void Next(); + +protected: + + //! Initialize root label. + Standard_EXPORT void initRoot(); + + //! Initialize properties for a current label. + Standard_EXPORT void initCurrent (Standard_Boolean theIsAssmebly); + +protected: + + Handle(XCAFDoc_ColorTool) myColorTool; //!< color tool + TDF_LabelSequence myRoots; //!< sequence of root labels + TDF_LabelSequence::Iterator myRootIter; //!< current root label + NCollection_Vector + myNodeStack; //!< node stack + Standard_Integer myTop; //!< top position in the node stack + Standard_Boolean myHasMore; //!< global flag indicating that iterator points to the label + XCAFPrs_Style myDefStyle; //!< default style + XCAFPrs_DocumentNode myCurrent; //!< current label info + XCAFPrs_DocumentExplorerFlags myFlags; //!< iteration flags + +}; + +#endif // _XCAFPrs_DocumentExplorer_HeaderFile diff --git a/src/XCAFPrs/XCAFPrs_DocumentIdIterator.hxx b/src/XCAFPrs/XCAFPrs_DocumentIdIterator.hxx new file mode 100644 index 0000000000..5d0c9dc2f4 --- /dev/null +++ b/src/XCAFPrs/XCAFPrs_DocumentIdIterator.hxx @@ -0,0 +1,90 @@ +// Author: Kirill Gavrilov +// Copyright (c) 2017-2019 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 _XCAFPrs_DocumentIdIterator_HeaderFile +#define _XCAFPrs_DocumentIdIterator_HeaderFile + +#include + +#include +#include +#include + +//! Auxiliary tool for iterating through Path identification string. +class XCAFPrs_DocumentIdIterator +{ +public: + //! Main constructor. + XCAFPrs_DocumentIdIterator (const TCollection_AsciiString& thePath) + : myPath (thePath), myPosition (0) + { + Next(); + } + + //! Return TRUE if iterator points to a value. + bool More() const { return !mySubId.IsEmpty(); } + + //! Return current value. + const TCollection_AsciiString& Value() const { return mySubId; } + + //! Find the next value. + void Next(); + +private: + + // Disable assignment operator. + XCAFPrs_DocumentIdIterator& operator= (const XCAFPrs_DocumentIdIterator& ); + +private: + const TCollection_AsciiString& myPath; //!< full path + TCollection_AsciiString mySubId; //!< current value + Standard_Integer myPosition; //!< last processed new-line symbol +}; + +// ======================================================================= +// function : Next +// purpose : +// ======================================================================= +inline void XCAFPrs_DocumentIdIterator::Next() +{ + for (Standard_Integer aCharIndex = myPosition + 1; aCharIndex <= myPath.Length(); ++aCharIndex) + { + if (myPath.Value (aCharIndex) == '/') + { + // intermediate items have trailing dot and separator before the next item + const Standard_Integer aLen = aCharIndex - myPosition - 2; + if (aLen < 1) + { + return; // assert - should never happen for valid IDs! + } + + mySubId = myPath.SubString (myPosition + 1, aCharIndex - 2); + myPosition = aCharIndex; + return; + } + } + if (myPosition < myPath.Length()) + { + // last item has only trailing dot + mySubId = myPath.SubString (myPosition + 1, myPath.Length() - 1); + myPosition = myPath.Length(); + } + else + { + mySubId.Clear(); + myPosition = myPath.Length(); + } +} + +#endif // _XCAFPrs_DocumentIdIterator_HeaderFile diff --git a/src/XCAFPrs/XCAFPrs_DocumentNode.hxx b/src/XCAFPrs/XCAFPrs_DocumentNode.hxx new file mode 100644 index 0000000000..9126a40fc8 --- /dev/null +++ b/src/XCAFPrs/XCAFPrs_DocumentNode.hxx @@ -0,0 +1,39 @@ +// Author: Kirill Gavrilov +// Copyright (c) 2017-2019 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 _XCAFPrs_DocumentNode_HeaderFile +#define _XCAFPrs_DocumentNode_HeaderFile + +#include + +#include +#include +#include + +//! Structure defining document node. +struct XCAFPrs_DocumentNode +{ + TCollection_AsciiString Id; //!< string identifier + TDF_Label Label; //!< label in the document + TDF_Label RefLabel; //!< reference label in the document + XCAFPrs_Style Style; //!< node style + TopLoc_Location Location; //!< node global transformation + TopLoc_Location LocalTrsf; //!< node transformation relative to parent + TDF_ChildIterator ChildIter; //!< child iterator + Standard_Boolean IsAssembly; //!< flag indicating that this label is assembly + + XCAFPrs_DocumentNode() : IsAssembly (Standard_False) {} +}; + +#endif // _XCAFPrs_DocumentNode_HeaderFile diff --git a/tests/collections/n/osdpath b/tests/collections/n/osdpath new file mode 100644 index 0000000000..ff9c8f07c9 --- /dev/null +++ b/tests/collections/n/osdpath @@ -0,0 +1,48 @@ +puts "=============" +puts "OSD_Path - test file path parsing tools" +puts "=============" + +pload QAcommands + +if { [QAOsdPathType {c:\folder\file.png}] != "absolute dos " } { puts "Error: DOS path misdetection" } +if { [QAOsdPathType {c:\file.png}] != "absolute dos " } { puts "Error: DOS path misdetection" } +if { [QAOsdPathType "D:\\"] != "absolute dos " } { puts "Error: DOS root misdetection" } +if { [QAOsdPathType {\\share\file.pdf}] != "absolute unc " } { puts "Error: UNC path misdetection" } +if { [QAOsdPathType {\\?\C:\documents\file.docx}] != "absolute ntextended " } { puts "Error: NT Extended path misdetection" } +if { [QAOsdPathType {\\?\UNC\server\share\file.zip}] != "absolute unc ntextended uncextended " } { puts "Error: UNC extended path misdetection" } +if { [QAOsdPathType {https://www.server.org/file.gif}] != "absolute protocol " } { puts "Error: remote protocal path misdetection" } +if { [QAOsdPathType {content://file.jpg}] != "absolute protocol content " } { puts "Error: content protocal path misdetection" } +if { [QAOsdPathType {/home/username/file.txt}] != "absolute unix " } { puts "Error: Unix path misdetection" } +if { [QAOsdPathType {/boot.bin}] != "absolute unix " } { puts "Error: Unix path misdetection" } +if { [QAOsdPathType {/}] != "absolute unix " } { puts "Error: Unix root misdetection" } +if { [QAOsdPathType {./subfolder/../file.txt}] != "relative " } { puts "Error: Realtive path misdetection" } +if { [QAOsdPathType {../file.txt}] != "relative " } { puts "Error: Realtive path misdetection" } +if { [QAOsdPathType {.}] != "relative " } { puts "Error: Realtive path misdetection" } +if { [QAOsdPathType {..}] != "relative " } { puts "Error: Realtive path misdetection" } +if { [QAOsdPathType {image.png}] != "relative " } { puts "Error: Realtive path misdetection" } + +if { [QAOsdPathPart {image.png} -folder] != "" } { puts "Error: Empty folder misdetected" } +if { [QAOsdPathPart {image.png} -fileName] != "image.png" } { puts "Error: File name misdetected" } +if { [QAOsdPathPart {c:\folder\file.png} -folder] != "c:\\folder\\" } { puts "Error: DOS folder misdetected" } +if { [QAOsdPathPart {c:\folder\file.png} -fileName] != "file.png" } { puts "Error: DOS file name misdetected" } +if { [QAOsdPathPart {c:\file.png} -folder] != "c:\\" } { puts "Error: DOS folder misdetected" } +if { [QAOsdPathPart {c:\file.png} -fileName] != "file.png" } { puts "Error: DOS file name misdetected" } +if { [QAOsdPathPart "D:\\" -folder] != "D:\\" } { puts "Error: DOS root misdetected" } +if { [QAOsdPathPart "D:\\" -fileName] != "" } { puts "Error: DOS root misdetected" } +if { [QAOsdPathPart "/" -folder] != "/" } { puts "Error: Unit root misdetected" } +if { [QAOsdPathPart "/" -fileName] != "" } { puts "Error: Unit root misdetected" } +if { [QAOsdPathPart {subfolder/file.txt} -folder] != "subfolder/" } { puts "Error: Relative folder misdetected" } +if { [QAOsdPathPart {subfolder/file.txt} -fileName] != "file.txt" } { puts "Error: Relative file name misdetected" } +if { [QAOsdPathPart {./subfolder/../file.txt} -folder] != "./subfolder/../" } { puts "Error: Relative folder misdetected" } +if { [QAOsdPathPart {./subfolder/../file.txt} -fileName] != "file.txt" } { puts "Error: Relative file name misdetected" } +if { [QAOsdPathPart {../../file.txt} -folder] != "../../" } { puts "Error: Relative folder misdetected" } +if { [QAOsdPathPart {../../file.txt} -fileName] != "file.txt" } { puts "Error: Relative file name misdetected" } +if { [QAOsdPathPart {/home/username/file.txt} -folder] != "/home/username/" } { puts "Error: Unix folder misdetected" } +if { [QAOsdPathPart {/home/username/file.txt} -fileName] != "file.txt" } { puts "Error: Unix file name misdetected" } + +if { [QAOsdPathPart {content://file.jpg} -folder] != "content://" } { puts "Error: Content folder misdetected" } +if { [QAOsdPathPart {content://file.jpg} -fileName] != "file.jpg" } { puts "Error: Content file name misdetected" } +if { [QAOsdPathPart {ftp://server.org/file.gif} -folder] != "ftp://server.org/" } { puts "Error: Remote protocol folder misdetected" } +if { [QAOsdPathPart {ftp://server.org/file.gif} -fileName] != "file.gif" } { puts "Error: Remote protocol file name misdetected" } +if { [QAOsdPathPart {\\?\UNC\server\file.zip} -folder] != "\\\\?\\UNC\\server\\" } { puts "Error: UNC folder misdetected" } +if { [QAOsdPathPart {\\?\UNC\server\file.zip} -fileName] != "file.zip" } { puts "Error: UNC filename misdetected" } -- 2.20.1