From 5c52d14a08c9003a1722b6b922d1481e414ba2ee Mon Sep 17 00:00:00 2001 From: isk Date: Sat, 20 Feb 2016 08:17:21 +0300 Subject: [PATCH] Add loader *.obj files. --- samples/tcl/video.tcl | 61 +++ src/MeshVS/CafShapePrs.cpp | 16 + src/MeshVS/CafShapePrs.h | 62 +++ src/MeshVS/FILES | 16 + src/MeshVS/FaceIterator.cpp | 150 +++++++ src/MeshVS/FaceIterator.h | 64 +++ src/MeshVS/MeshDataSource.cpp | 278 ++++++++++++ src/MeshVS/MeshDataSource.h | 304 +++++++++++++ src/MeshVS/MeshPresentation.cpp | 137 ++++++ src/MeshVS/MeshPresentation.h | 57 +++ src/MeshVS/MeshPrsBuilder.cpp | 726 ++++++++++++++++++++++++++++++++ src/MeshVS/MeshPrsBuilder.h | 147 +++++++ src/MeshVS/MeshScalarProperty.h | 124 ++++++ src/MeshVS/ObjDataSource.cpp | 680 ++++++++++++++++++++++++++++++ src/MeshVS/ObjDataSource.h | 43 ++ src/MeshVS/ObjDataWriter.cpp | 354 ++++++++++++++++ src/MeshVS/ObjDataWriter.h | 49 +++ src/TKMeshVS/EXTERNLIB | 2 + src/TKViewerTest/EXTERNLIB | 3 + src/ViewerTest/ViewerTest.cxx | 285 +++++++++++++ 20 files changed, 3558 insertions(+) create mode 100644 samples/tcl/video.tcl create mode 100644 src/MeshVS/CafShapePrs.cpp create mode 100644 src/MeshVS/CafShapePrs.h create mode 100644 src/MeshVS/FaceIterator.cpp create mode 100644 src/MeshVS/FaceIterator.h create mode 100644 src/MeshVS/MeshDataSource.cpp create mode 100644 src/MeshVS/MeshDataSource.h create mode 100644 src/MeshVS/MeshPresentation.cpp create mode 100644 src/MeshVS/MeshPresentation.h create mode 100644 src/MeshVS/MeshPrsBuilder.cpp create mode 100644 src/MeshVS/MeshPrsBuilder.h create mode 100644 src/MeshVS/MeshScalarProperty.h create mode 100644 src/MeshVS/ObjDataSource.cpp create mode 100644 src/MeshVS/ObjDataSource.h create mode 100644 src/MeshVS/ObjDataWriter.cpp create mode 100644 src/MeshVS/ObjDataWriter.h diff --git a/samples/tcl/video.tcl b/samples/tcl/video.tcl new file mode 100644 index 0000000000..a503fe3a39 --- /dev/null +++ b/samples/tcl/video.tcl @@ -0,0 +1,61 @@ +pload ALL + +vclear +vclose all + +vinit name=View1 w=512 h=512 +vsetdispmode 1 +vcamera -persp -fovy 90 + +vzbufftrihedron + +set folderTyre "D:/TmpFiles/for_video/Tyre" +set folderEnv "D:/TmpFiles/for_video/Environment" + +#road +puts "Loading road..." +vdisplayobj road "${folderEnv}/roadV2.obj" +vlocrotate road 0 0 0 1 0 0 90 +vlocscale road 1 1 0 102400 +vloctranslate road 0 1 3.5 +#vlocscale road + +#building0 +puts "Loading the first building..." +vdisplayobj building0 "${folderEnv}/Building N100715.obj" +vlocscale building0 1 1 1 10922 +vlocrotate building0 0 0 0 1 0 0 90 +vlocrotate building0 0 0 0 0 1 0 45 +vloctranslate building0 -6 3 3 + +#House N090614 +puts "Loading the second building..." +vdisplayobj HouseN090614 "${folderEnv}/House N090614.obj" +vloctranslate HouseN090614 0 0 1000 +vlocrotate HouseN090614 0 0 0 1 0 0 90 +vlocscale HouseN090614 1 1 1 1024 + +#Building1 +puts "Loading the third building..." +vdisplayobj building1 "${folderEnv}/Building N101213.obj" +vlocrotate building1 0 0 0 1 0 0 90 +vlocscale building1 1 1 1 21845 +vloctranslate building1 -1 1 0 +vlocrotate building1 0 0 0 0 1 0 45 + +#Tyre +puts "Loading tyre..." +vdisplayobj tyre "${folderTyre}/tyre.obj" +vloctranslate tyre 0 -10000 400 + +#vlight del 0 +#vlight del 1 +#vlight add positional head 0 pos 0.5 0.5 50.85 +#vlight change 0 sm 0.06 +#vlight change 0 int 160.0 + + +#vrenderparams -ray -gi -rayDepth 8 +vtextureenv on 4 +vrenderparams -ray -env on +vfit diff --git a/src/MeshVS/CafShapePrs.cpp b/src/MeshVS/CafShapePrs.cpp new file mode 100644 index 0000000000..fe87b36e7b --- /dev/null +++ b/src/MeshVS/CafShapePrs.cpp @@ -0,0 +1,16 @@ +#include + +IMPLEMENT_STANDARD_RTTIEXT(CafShapePrs, XCAFPrs_AISObject) + +// ======================================================================= +// function : CafShapePrs +// purpose : +// ======================================================================= +CafShapePrs::CafShapePrs (const TDF_Label& theLabel, + const XCAFPrs_Style& theStyle, + const Graphic3d_MaterialAspect& theMaterial) +: XCAFPrs_AISObject (theLabel), + myDefStyle (theStyle) +{ + SetMaterial (theMaterial); +} diff --git a/src/MeshVS/CafShapePrs.h b/src/MeshVS/CafShapePrs.h new file mode 100644 index 0000000000..79bab905e4 --- /dev/null +++ b/src/MeshVS/CafShapePrs.h @@ -0,0 +1,62 @@ +// Copyright (c) 2015 OPEN CASCADE SAS +// +// This file is part of commercial software by OPEN CASCADE SAS. +// +// This software is furnished in accordance with the terms and conditions +// of the contract and with the inclusion of this copyright notice. +// This software or any other copy thereof may not be provided or otherwise +// be made available to any third party. +// No ownership title to the software is transferred hereby. +// +// OPEN CASCADE SAS makes no representation or warranties with respect to the +// performance of this software, and specifically disclaims any responsibility +// for any damages, special or consequential, connected with its use. + +#ifndef CafShapePrs_Header +#define CafShapePrs_Header + +#include +#include + +typedef NCollection_DataMap CafDataMapOfShapeColor; + +//! Interactive object for shape in DECAF document. +class CafShapePrs : public XCAFPrs_AISObject +{ + +public: + + //! Default constructor. + Standard_EXPORT CafShapePrs (const TDF_Label& theLabel, + const XCAFPrs_Style& theStyle, + const Graphic3d_MaterialAspect& theMaterial); + + //! Search custom aspect for specified shape. + Standard_Boolean FindCustomAspects (const TopoDS_Shape& theShape, + Handle(AIS_ColoredDrawer)& theAspects) const + { + return myShapeColors.Find (theShape, theAspects); + } + + //! Access the styles map. + const CafDataMapOfShapeColor& ShapeColors() const { return myShapeColors; } + + //! Override default style. + virtual void DefaultStyle (XCAFPrs_Style& theStyle) const Standard_OVERRIDE + { + theStyle = myDefStyle; + } + +protected: + + XCAFPrs_Style myDefStyle; //!< default style + +public: //! @name Declaration of CASCADE RTTI + + DEFINE_STANDARD_RTTIEXT(CafShapePrs, XCAFPrs_AISObject) + +}; + +DEFINE_STANDARD_HANDLE (CafShapePrs, XCAFPrs_AISObject) + +#endif diff --git a/src/MeshVS/FILES b/src/MeshVS/FILES index 40672f91fb..14720cb01e 100755 --- a/src/MeshVS/FILES +++ b/src/MeshVS/FILES @@ -84,3 +84,19 @@ MeshVS_TwoNodes.hxx MeshVS_TwoNodesHasher.hxx MeshVS_VectorPrsBuilder.cxx MeshVS_VectorPrsBuilder.hxx + +MeshDataSource.h +MeshDataSource.cpp +ObjDataSource.h +ObjDataSource.cpp +MeshScalarProperty.h +MeshPresentation.h +MeshPresentation.cpp +MeshPrsBuilder.h +MeshPrsBuilder.cpp +ObjDataWriter.h +ObjDataWriter.cpp +FaceIterator.h +FaceIterator.cpp +CafShapePrs.h +CafShapePrs.cpp diff --git a/src/MeshVS/FaceIterator.cpp b/src/MeshVS/FaceIterator.cpp new file mode 100644 index 0000000000..4cc10e75a9 --- /dev/null +++ b/src/MeshVS/FaceIterator.cpp @@ -0,0 +1,150 @@ +// Copyright (c) 2015 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 + +// ======================================================================= +// function : FaceIterator +// purpose : +// ======================================================================= +FaceIterator::FaceIterator (const AIS_ListOfInteractive& thePrsList) +: myPrsIter (thePrsList) +{ + Next(); +} + +// ======================================================================= +// function : Next +// purpose : +// ======================================================================= +void FaceIterator::Next() +{ + for (; myPrsIter.More(); myPrsIter.Next()) + { + Handle(AIS_ConnectedInteractive) aConnected = Handle(AIS_ConnectedInteractive)::DownCast (myPrsIter.Value()); + Handle(AIS_Shape) aShapePrs = Handle(AIS_Shape)::DownCast (!aConnected.IsNull() ? aConnected->ConnectedTo() : myPrsIter.Value()); + + ShapePrs = Handle(CafShapePrs)::DownCast (aShapePrs); + myPrsLocation = TopLoc_Location(); + if (ShapePrs.IsNull()) + { + Triangulation.Nullify(); + Face.Nullify(); + myFacesMap.Clear(); + continue; + } + else if (!aConnected.IsNull() + && aConnected->LocalTransformation().Form() != gp_Identity) + { + myPrsLocation = TopLoc_Location (aConnected->LocalTransformation()); + } + + TopoDS_Shape aShape = ShapePrs->Shape(); + if (aShape.IsNull()) + { + Triangulation.Nullify(); + Face.Nullify(); + myFacesMap.Clear(); + continue; + } + + if (myFacesMap.IsEmpty()) + { + // should be replaced by TopTools_OrientedShapeMaphasher to export correctly composed solids + // (e.g. shared face should be exported twice with different order of triangles + // and possible unique color) + TopExp::MapShapesAndAncestors (aShape, TopAbs_FACE, TopAbs_SHAPE, myFacesMap); + if (myFacesMap.IsEmpty()) + { + Triangulation.Nullify(); + Face.Nullify(); + continue; + } + + // register compounds generated by XCAFPrs_AISObject for grouping elements with the same style + const CafDataMapOfShapeColor& aColorsMap = ShapePrs->ShapeColors(); + for (CafDataMapOfShapeColor::Iterator aShapeMapIter (aColorsMap); aShapeMapIter.More(); aShapeMapIter.Next()) + { + if (aShapeMapIter.Key().ShapeType() != TopAbs_COMPOUND + || aShapeMapIter.Key().IsEqual (aShape)) + { + continue; + } + + for (TopExp_Explorer aCompFaceIter (aShapeMapIter.Key(), TopAbs_FACE); aCompFaceIter.More(); aCompFaceIter.Next()) + { + const Standard_Integer anIndex = myFacesMap.FindIndex (aCompFaceIter.Current()); + if (anIndex != 0) + { + myFacesMap.ChangeFromIndex (anIndex).Append (aShapeMapIter.Key()); + } + } + } + + myFaceIter = TopTools_IndexedDataMapOfShapeListOfShape::Iterator (myFacesMap); + } + for (; myFaceIter.More(); myFaceIter.Next()) + { + Face = TopoDS::Face (myFaceIter.Key()); + Triangulation = BRep_Tool::Triangulation (Face, myFaceLocation); + Trsf = myPrsLocation.Multiplied (myFaceLocation).Transformation(); + if ( Triangulation.IsNull() + || Triangulation->Triangles().Length() == 0 + || !Triangulation->HasUVNodes()) + { + continue; + } + + Handle(AIS_ColoredDrawer) aCustomDrawer; + if (!ShapePrs->FindCustomAspects (Face, aCustomDrawer)) + { + for (TopTools_ListOfShape::Iterator aParentIter (myFaceIter.Value()); aParentIter.More(); aParentIter.Next()) + { + if (ShapePrs->FindCustomAspects (aParentIter.Value(), aCustomDrawer)) + { + break; + } + } + if (aCustomDrawer.IsNull()) + { + ShapePrs->FindCustomAspects (aShape, aCustomDrawer); + } + } + Drawer = aCustomDrawer; + if (Drawer.IsNull()) + { + Drawer = aShapePrs->Attributes(); + } + + myFaceIter.Next(); + return; + } + Triangulation.Nullify(); + Face.Nullify(); + myFacesMap.Clear(); + myFaceIter = TopTools_IndexedDataMapOfShapeListOfShape::Iterator(); + Drawer.Nullify(); + } +} diff --git a/src/MeshVS/FaceIterator.h b/src/MeshVS/FaceIterator.h new file mode 100644 index 0000000000..d2190d174f --- /dev/null +++ b/src/MeshVS/FaceIterator.h @@ -0,0 +1,64 @@ +// Copyright (c) 2015 OPEN CASCADE SAS +// +// This file is part of commercial software by OPEN CASCADE SAS. +// +// This software is furnished in accordance with the terms and conditions +// of the contract and with the inclusion of this copyright notice. +// This software or any other copy thereof may not be provided or otherwise +// be made available to any third party. +// No ownership title to the software is transferred hereby. +// +// OPEN CASCADE SAS makes no representation or warranties with respect to the +// performance of this software, and specifically disclaims any responsibility +// for any damages, special or consequential, connected with its use. + +#ifndef FaceIterator_H +#define FaceIterator_H + +#include +#include +#include +#include +#include + +class CafShapePrs; +class Prs3d_Drawer; +class Poly_Triangulation; + +//! Auxiliary class to iterate through triangulated faces in presentations list. +class FaceIterator +{ + +public: + + Handle(CafShapePrs) ShapePrs; + TopoDS_Face Face; + Handle(Prs3d_Drawer) Drawer; + Handle(Poly_Triangulation) Triangulation; + gp_Trsf Trsf; + +public: + + //! Main constructor. + Standard_EXPORT FaceIterator (const AIS_ListOfInteractive& thePrsList); + + //! Return true if iterator points to the valid triangulation. + bool More() const + { + return !Triangulation.IsNull(); + } + + //! Find next value. + Standard_EXPORT void Next(); + +private: + + AIS_ListOfInteractive::Iterator myPrsIter; + TopLoc_Location myPrsLocation; + TopTools_IndexedDataMapOfShapeListOfShape myFacesMap; + TopTools_IndexedDataMapOfShapeListOfShape::Iterator myFaceIter; + TopLoc_Location myFaceLocation; + +}; + +#endif // FaceIterator_H diff --git a/src/MeshVS/MeshDataSource.cpp b/src/MeshVS/MeshDataSource.cpp new file mode 100644 index 0000000000..b58f595a6c --- /dev/null +++ b/src/MeshVS/MeshDataSource.cpp @@ -0,0 +1,278 @@ +// Copyright (c) 2014-2015 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 + +IMPLEMENT_STANDARD_RTTIEXT(MeshScalarProperty, Standard_Transient) + +IMPLEMENT_STANDARD_RTTIEXT(MeshDataSource, MeshVS_DataSource) + +//================================================================ +// Function : Constructor +// Purpose : +//================================================================ +MeshDataSource::MeshDataSource() +{ + // +} + +//================================================================ +// Function : Clear +// Purpose : +//================================================================ +void MeshDataSource::Clear() +{ + myUsedNodes.Clear(); + myFreeNodes.Clear(); + myUsedElements.Clear(); + myComments.Clear(); + myNodes.Clear(); + myNormals.Clear(); + myNodesUV.Clear(); + myNodalColors.Clear(); + myElements.Clear(); + myNodalQuantities.Clear(); + myElementalQuantities.Clear(); + myGroups.Clear(); +} + +//================================================================ +// Function : GetGeom +// Purpose : +//================================================================ +Standard_Boolean MeshDataSource::GetGeom (const Standard_Integer theID, + const Standard_Boolean theIsElement, + TColStd_Array1OfReal& theCoords, + Standard_Integer& theNbNodes, + MeshVS_EntityType& theType) const +{ + const Standard_Integer aLow = theCoords.Lower(); + if (theIsElement) + { + if (theID < 0 || theID >= myUsedElements.Extent()) + { + return Standard_False; + } + + const Graphic3d_Vec4i& anElem = myElements.Value (theID); + theType = MeshVS_ET_Face; + theNbNodes = anElem[3] == -1 ? 3 : 4; + for (Standard_Integer aNodeIter = 0, aCoordIter = aLow - 1; aNodeIter < theNbNodes; ++aNodeIter) + { + const Graphic3d_Vec3& aNode = myNodes.Value (anElem[aNodeIter]); + theCoords (++aCoordIter) = aNode.x(); + theCoords (++aCoordIter) = aNode.y(); + theCoords (++aCoordIter) = aNode.z(); + } + return Standard_True; + } + else if (theID < 0 || theID >= myUsedNodes.Extent()) + { + return Standard_False; + } + + theType = MeshVS_ET_Node; + theNbNodes = 1; + const Graphic3d_Vec3& aNode = myNodes.Value (theID); + theCoords (aLow) = aNode.x(); + theCoords (aLow + 1) = aNode.y(); + theCoords (aLow + 2) = aNode.z(); + return Standard_True; +} + +//================================================================ +// Function : GetNodesByElement +// Purpose : +//================================================================ +Standard_Boolean MeshDataSource::GetNodesByElement (const Standard_Integer theID, + TColStd_Array1OfInteger& theNodeIDs, + Standard_Integer& theNbNodes) const +{ + if (theID < 0 || theID >= myUsedElements.Extent()) + { + return Standard_False; + } + + const Graphic3d_Vec4i& anElem = myElements.Value (theID); + theNbNodes = anElem[3] == -1 ? 3 : 4; + if (theNodeIDs.Length() < theNbNodes) + { + return Standard_False; + } + + const Standard_Integer aLow = theNodeIDs.Lower(); + theNodeIDs (aLow) = anElem[0]; + theNodeIDs (aLow + 1) = anElem[1]; + theNodeIDs (aLow + 2) = anElem[2]; + if (theNbNodes == 4) + { + theNodeIDs (aLow + 3) = anElem[3]; + } + return Standard_True; +} + +//================================================================ +// Function : GetNodeNormal +// Purpose : +//================================================================ +Standard_Boolean MeshDataSource::GetNodeNormal (const Standard_Integer theRankNode, + const Standard_Integer theElementId, + Standard_Real& theNX, + Standard_Real& theNY, + Standard_Real& theNZ) const +{ + if (theElementId < 0 || theElementId >= myUsedElements.Extent() + || !HasNormals()) + { + return Standard_False; + } + + const Graphic3d_Vec4i& anElem = myElements.Value (theElementId); + const Graphic3d_Vec3& aNorm = myNormals.Value (anElem[theRankNode - 1]); + theNX = Standard_Real(aNorm.x()); + theNY = Standard_Real(aNorm.y()); + theNZ = Standard_Real(aNorm.z()); + return Standard_True; +} + +inline void truncateToRange (Standard_Real& theValue, + const Standard_Real theLower, + const Standard_Real theUpper) +{ + if (theValue <= theLower) + { + theValue = theLower; + } + else if (theValue >= theUpper) + { + theValue = theUpper; + } +} + +//================================================================ +// Function : FillPropertyBuilder +// Purpose : +//================================================================ +void MeshDataSource::FillPropertyBuilder (const Handle(MeshVS_PrsBuilder)& theBuilder, + const Handle(MeshScalarProperty)& theProperty) const +{ + Handle(MeshVS_NodalColorPrsBuilder) aNodalBuilder = Handle(MeshVS_NodalColorPrsBuilder) ::DownCast (theBuilder); + Handle(MeshVS_ElementalColorPrsBuilder) anElemBuilder = Handle(MeshVS_ElementalColorPrsBuilder)::DownCast (theBuilder); + if ((aNodalBuilder.IsNull() && anElemBuilder.IsNull()) + || theProperty.IsNull()) + { + return; + } + + //theBuilder->UseTexture (Standard_True); + const Standard_Boolean isGrayscale = (theProperty->Name() == "intensity"); + + const Standard_Real aLowerValue = isGrayscale ? 0.0 : theProperty->LowerValue(); + const Standard_Real aRange = isGrayscale ? 1.0 : theProperty->UpperValue() - theProperty->LowerValue(); + + const Graphic3d_Vec3d aScale00 = isGrayscale ? Graphic3d_Vec3d (0.0, 0.0, 0.0) : Graphic3d_Vec3d (0.0, 0.0, 1.0); + const Graphic3d_Vec3d aScale05 = isGrayscale ? Graphic3d_Vec3d (0.5, 0.5, 0.5) : Graphic3d_Vec3d (0.0, 1.0, 0.0); + const Graphic3d_Vec3d aScale10 = isGrayscale ? Graphic3d_Vec3d (1.0, 1.0, 1.0) : Graphic3d_Vec3d (1.0, 0.0, 0.0); + Graphic3d_Vec3d aColor; + for (Standard_Integer anElemIter = theProperty->LowerIndex(); anElemIter <= theProperty->UpperIndex(); ++anElemIter) + { + if (aRange <= Precision::Confusion()) + { + aColor = aScale00; + } + else + { + Standard_Real aValue = (theProperty->Value (anElemIter) - aLowerValue) / aRange; + if (aValue < 0.5) + { + aValue *= 2.0; + aColor = aScale00 * (1.0 - aValue) + aScale05 * aValue; + } + else + { + aValue = (aValue - 0.5) * 2.0; + aColor = aScale05 * (1.0 - aValue) + aScale10 * aValue; + } + truncateToRange (aColor.r(), 0.0, 1.0); + truncateToRange (aColor.g(), 0.0, 1.0); + truncateToRange (aColor.b(), 0.0, 1.0); + } + + const Quantity_Color aQColor (aColor.r(), aColor.g(), aColor.b(), Quantity_TOC_RGB); + if (!aNodalBuilder.IsNull()) + { + aNodalBuilder->SetColor (anElemIter, aQColor); + } + else + { + anElemBuilder->SetColor1 (anElemIter, aQColor); + } + } +} + +//================================================================ +// Function : FillNodalColorsBuilder +// Purpose : +//================================================================ +void MeshDataSource::FillNodalColorsBuilder (const Handle(MeshVS_NodalColorPrsBuilder)& theBuilder) const +{ + if (theBuilder.IsNull() + || !HasNodalColors()) + { + return; + } + + for (Standard_Integer aNodeIter = myNodalColors.Lower(); aNodeIter <= myNodalColors.Upper(); ++aNodeIter) + { + const Graphic3d_Vec4ub& aColor = myNodalColors.Value (aNodeIter); + const Quantity_Color aQColor (aColor.r() / 255.0, aColor.g() / 255.0, aColor.b() / 255.0, Quantity_TOC_RGB); + theBuilder->SetColor (aNodeIter, aQColor); + } +} + +//================================================================ +// Function : NbElements +// Purpose : +//================================================================ +void MeshDataSource::NbElements (Standard_Integer& theNbTris, + Standard_Integer& theNbQuads) const +{ + for (NCollection_Vector::Iterator anElemIter (myElements); anElemIter.More(); anElemIter.Next()) + { + const Graphic3d_Vec4i& anElem = anElemIter.Value(); + if (anElem[3] == -1) + { + ++theNbTris; + } + else + { + ++theNbQuads; + } + } +} diff --git a/src/MeshVS/MeshDataSource.h b/src/MeshVS/MeshDataSource.h new file mode 100644 index 0000000000..ef9372b6b6 --- /dev/null +++ b/src/MeshVS/MeshDataSource.h @@ -0,0 +1,304 @@ +// Copyright (c) 2015 OPEN CASCADE SAS +// +// This file is part of commercial software by OPEN CASCADE SAS. +// +// This software is furnished in accordance with the terms and conditions +// of the contract and with the inclusion of this copyright notice. +// This software or any other copy thereof may not be provided or otherwise +// be made available to any third party. +// No ownership title to the software is transferred hereby. +// +// OPEN CASCADE SAS makes no representation or warranties with respect to the +// performance of this software, and specifically disclaims any responsibility +// for any damages, special or consequential, connected with its use. + +#ifndef MeshDataSource_H +#define MeshDataSource_H + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(_WIN32) + #define ftell64(a) _ftelli64(a) + #define fseek64(a,b,c) _fseeki64(a,b,c) +#else + #define ftell64(a) ftello(a) + #define fseek64(a,b,c) fseeko(a,b,c) +#endif + +//! Material definition. +struct MeshMaterial +{ + Graphic3d_MaterialAspect Aspect; + TCollection_AsciiString Texture; +}; + +//! Mesh sub-group definition +struct MeshGroup +{ + TCollection_AsciiString Name; //!< group name + Standard_Integer NodeLower; //!< index of lower Vertex + Standard_Integer NodeUpper; //!< index of upper Vertex + Standard_Integer ElemLower; //!< index of lower Element + Standard_Integer ElemUpper; //!< index of upper Element + MeshMaterial Material; //!< associated material + + MeshGroup() : NodeLower (-1), NodeUpper (-1), ElemLower (-1), ElemUpper (-1) {} + +}; + +//! The DataSource for working with mesh data. +class MeshDataSource : public MeshVS_DataSource +{ + +public: + + //! Empty constructor. + Standard_EXPORT MeshDataSource(); + + //! Clear mesh structure. + Standard_EXPORT void Clear(); + + //! Read the mesh from specified file. + virtual Standard_Boolean Read (const TCollection_AsciiString& theFile, + const Handle(Message_ProgressIndicator)& theProgress = NULL, + const Standard_Integer theIndexLimit = -1, + const Standard_Integer theMemoryLimitMiB = -1) = 0; + + //! Returns geometry information about node or element by co-ordinates. + //! For element this method must return all its nodes co-ordinates in the strict order: X, Y, Z and + //! with nodes order is the same as in wire bounding the face or link. + //! @param theIsElement flag to retrieve information about Element or Node + //! @param theNbNodes number of nodes of element, it is recommended to return 1 for node + //! @param theType element type + Standard_EXPORT virtual Standard_Boolean GetGeom (const Standard_Integer theID, + const Standard_Boolean theIsElement, + TColStd_Array1OfReal& theCoords, + Standard_Integer& theNbNodes, + MeshVS_EntityType& theType) const Standard_OVERRIDE; + + //! This method is similar to GetGeom, but returns only element or node type. + virtual Standard_Boolean GetGeomType (const Standard_Integer /*theID*/, + const Standard_Boolean theIsElement, + MeshVS_EntityType& theType) const Standard_OVERRIDE + { + theType = theIsElement ? MeshVS_ET_Face : MeshVS_ET_Node; + return Standard_True; + } + + //! Return pointer which represents element or node data structure. + virtual Standard_Address GetAddr (const Standard_Integer /*theID*/, + const Standard_Boolean /*theIsElement*/) const Standard_OVERRIDE { return NULL; } + + //! This method returns information about what node this element consist of. + Standard_EXPORT virtual Standard_Boolean GetNodesByElement (const Standard_Integer theID, + TColStd_Array1OfInteger& theNodeIDs, + Standard_Integer& theNbNodes) const Standard_OVERRIDE; + + //! This method returns map of all nodes the object consist of. + virtual const TColStd_PackedMapOfInteger& GetAllNodes() const Standard_OVERRIDE { return myFreeNodes; } + + //! This method returns map of all elements the object consist of. + virtual const TColStd_PackedMapOfInteger& GetAllElements() const Standard_OVERRIDE { return myUsedElements; } + + //! This method return normal of node ranknode of face Id, + //! which is using for smooth shading presentation. + //! Returns false if normal isn't defined. + Standard_EXPORT virtual Standard_Boolean GetNodeNormal (const Standard_Integer theRankNode, + const Standard_Integer theElementId, + Standard_Real& theNX, + Standard_Real& theNY, + Standard_Real& theNZ) const Standard_OVERRIDE; + +public: + + //! Return file comments. + const NCollection_Sequence& FileComments() const + { + return myComments; + } + + //! Return list of sub-groups with materials. + const NCollection_Vector& Groups() { return myGroups; } + + //! Return overall nodes number. + Standard_Integer NbNodes() const { return myNodes.Length(); } + + //! Return vector of nodes. + const NCollection_Vector& Nodes() const { return myNodes; } + + //! Return overall elements number. + Standard_Integer NbElements() const { return myElements.Length(); } + + //! Determine elements number. + Standard_EXPORT void NbElements (Standard_Integer& theNbTris, + Standard_Integer& theNbQuads) const; + + //! Return vector of elements. + const NCollection_Vector& Elements() const { return myElements; } + + //! Return per-node scalar properties. + const MeshScalarProperties& NodalQuantities() const { return myNodalQuantities; } + + //! Return per-element scalar properties. + const MeshScalarProperties& ElementalQuantities() const { return myElementalQuantities; } + + //! Return true if per-node colors have been assigned + Standard_Boolean HasNodalColors() const + { + return myNodalColors.Length() == myNodes.Length() + && !myNodalColors.IsEmpty(); + } + + //! Return vector of nodal colors (optional). + const NCollection_Vector& NodalColors() const { return myNodalColors; } + + //! Return true if per-node normals have been assigned + Standard_Boolean HasNormals() const + { + return myNormals.Length() == myNodes.Length() + && !myNormals.IsEmpty(); + } + + //! Return vector of nodal normals (optional). + const NCollection_Vector& Normals() const { return myNormals; } + + //! Return true if per-node UV parameters have been assigned + Standard_Boolean HasUV() const + { + return myNodesUV.Length() == myNodes.Length() + && !myNodesUV.IsEmpty(); + } + + //! Return vector of nodal UV parameters (optional). + const NCollection_Vector& NodesUV() const { return myNodesUV; } + + //! Return true if texture has been assigned. + Standard_Boolean HasTexture() const + { + Standard_Integer aTextureCount = 0; + for (auto anIter = myGroups.cbegin(); anIter != myGroups.cend(); ++anIter) + { + aTextureCount += (anIter->Material.Texture.IsEmpty()) ? 0 : 1; + } + return !myGroups.IsEmpty() + //&& !myGroups.First().Material.Texture.IsEmpty() + && aTextureCount + && HasUV(); + } + + //! Return assigned texture. + TCollection_AsciiString Texture() const + { + return HasTexture() ? myGroups.First().Material.Texture : ""; + } + +public: + + //! Fill-in nodal (MeshVS_NodalColorPrsBuilder) or elemental (MeshVS_ElementalColorPrsBuilder) builder. + Standard_EXPORT void FillPropertyBuilder (const Handle(MeshVS_PrsBuilder)& theBuilder, + const Handle(MeshScalarProperty)& theProperty) const; + + //! Fill-in nodal (MeshVS_NodalColorPrsBuilder) builder by colors. + Standard_EXPORT void FillNodalColorsBuilder (const Handle(MeshVS_NodalColorPrsBuilder)& theBuilder) const; + +public: + + //! Append new vertex. + void AddNodePosition (const Graphic3d_Vec3& thePosition) + { + myNodes.Append (thePosition); + myUsedNodes.Add (myNodes.Upper()); + } + + //! Append new vertex. + void AddNodePosition (const gp_XYZ& thePosition) + { + myNodes.Append (Graphic3d_Vec3 ((float )thePosition.X(), + (float )thePosition.Y(), + (float )thePosition.Z())); + myUsedNodes.Add (myNodes.Upper()); + } + + //! Append new normal. + void AddNodeNormal (const Graphic3d_Vec3& theNormal) + { + myNormals.Append (theNormal); + } + + //! Append new normal. + void AddNodeNormal (const gp_XYZ& theNormal) + { + myNormals.Append (Graphic3d_Vec3 ((float )theNormal.X(), + (float )theNormal.Y(), + (float )theNormal.Z())); + } + + //! Append new UV parameters pair. + void AddNodeUV (const Graphic3d_Vec2& theUV) + { + myNodesUV.Append (theUV); + } + + //! Append new color. + void AddNodeColor (const Graphic3d_Vec4ub& theColor) + { + myNodalColors.Append (theColor); + } + + //! Append node property. + void AddNodeProperty (const Standard_Integer thePropIndex, + const Standard_Real theValue) + { + myNodalQuantities.ChangeValue (thePropIndex)->AppendValue (theValue); + } + + //! Append new element. + void AddElement (const Graphic3d_Vec4i& theNodeIndices) + { + myElements.Append (theNodeIndices); + myUsedElements.Add (myElements.Upper()); + } + + //! Append element property. + void AddElementProperty (const Standard_Integer thePropIndex, + const Standard_Real theValue) + { + myElementalQuantities.ChangeValue (thePropIndex)->AppendValue (theValue); + } + +protected: + + TColStd_PackedMapOfInteger myUsedNodes; //!< used node indices + TColStd_PackedMapOfInteger myFreeNodes; //!< indices of free nodes + TColStd_PackedMapOfInteger myUsedElements; //!< used element indices + NCollection_Sequence + myComments; //!< file comments + NCollection_Vector myNodes; //!< vector of nodes + NCollection_Vector myNormals; //!< vector of nodal normals (optional) + NCollection_Vector myNodesUV; //!< vector of UV nodes (optional) + NCollection_Vector myNodalColors; //!< vector of nodal colors (optional) + NCollection_Vector myElements; //!< vector of elements + MeshScalarProperties myNodalQuantities; //!< per-node scalar quantities + MeshScalarProperties myElementalQuantities; //!< per-element scalar quantities + + NCollection_Vector myGroups; //!< sub-groups with materials + +public: + + DEFINE_STANDARD_RTTIEXT(MeshDataSource, MeshVS_DataSource) + +}; + +DEFINE_STANDARD_HANDLE(MeshDataSource, MeshVS_DataSource) + +#endif // MeshDataSource_H diff --git a/src/MeshVS/MeshPresentation.cpp b/src/MeshVS/MeshPresentation.cpp new file mode 100644 index 0000000000..ff6d0f3e61 --- /dev/null +++ b/src/MeshVS/MeshPresentation.cpp @@ -0,0 +1,137 @@ +// Copyright (c) 2015 OPEN CASCADE SAS +// +// This file is part of commercial software by OPEN CASCADE SAS. +// +// This software is furnished in accordance with the terms and conditions +// of the contract and with the inclusion of this copyright notice. +// This software or any other copy thereof may not be provided or otherwise +// be made available to any third party. +// No ownership title to the software is transferred hereby. +// +// OPEN CASCADE SAS makes no representation or warranties with respect to the +// performance of this software, and specifically disclaims any responsibility +// for any damages, special or consequential, connected with its use. + +#include "MeshPresentation.h" + +#include +#include +#include + +IMPLEMENT_STANDARD_RTTIEXT(MeshPresentation, MeshVS_Mesh) + +// ======================================================================= +// function : MeshPresentation +// purpose : +// ======================================================================= +MeshPresentation::MeshPresentation() +{} + +// ======================================================================= +// function : SetMaterial +// purpose : +// ======================================================================= +void MeshPresentation::SetMaterial (const Graphic3d_MaterialAspect& theMat) +{ + Handle(MeshVS_Drawer) aDrawer = GetDrawer(); + if (aDrawer.IsNull()) + { + return; + } + + aDrawer->SetMaterial (MeshVS_DA_FrontMaterial, theMat); + aDrawer->SetMaterial (MeshVS_DA_BackMaterial, theMat); + Standard_Boolean hasReflection = Standard_True; + aDrawer->GetBoolean (MeshVS_DA_Reflection, hasReflection); + Graphic3d_MaterialAspect aMat = theMat; + if (!hasReflection) + { + aMat.SetReflectionModeOff (Graphic3d_TOR_AMBIENT); + aMat.SetReflectionModeOff (Graphic3d_TOR_DIFFUSE); + aMat.SetReflectionModeOff (Graphic3d_TOR_SPECULAR); + aMat.SetReflectionModeOff (Graphic3d_TOR_EMISSION); + } + Handle(Graphic3d_AspectFillArea3d) anAreaAsp = MeshVS_Tool::CreateAspectFillArea3d (aDrawer, aMat); + Handle(Graphic3d_AspectLine3d) anOldLineAsp = new Graphic3d_AspectLine3d(); + Handle(Graphic3d_AspectText3d) anOldTextAsp = new Graphic3d_AspectText3d(); + Handle(Graphic3d_AspectMarker3d) anOldPntAsp = new Graphic3d_AspectMarker3d(); + Handle(Graphic3d_AspectFillArea3d) anOldAreaAps = new Graphic3d_AspectFillArea3d(); + + const PrsMgr_Presentations& aPrsList = Presentations(); + for (Standard_Integer aPrsIt = 1; aPrsIt <= aPrsList.Length(); ++aPrsIt) + { + const PrsMgr_ModedPresentation& aPrsModed = aPrsList.Value (aPrsIt); + if (aPrsModed.Mode() == MeshVS_DMF_WireFrame + || aPrsModed.Mode() == MeshVS_DMF_NodalColorDataPrs + || aPrsModed.Mode() == MeshVS_DMF_ElementalColorDataPrs) + { + continue; + } + + const Handle(Prs3d_Presentation)& aPrs = aPrsModed.Presentation()->Presentation(); + for (Graphic3d_SequenceOfGroup::Iterator aGroupIt (aPrs->Groups()); aGroupIt.More(); aGroupIt.Next()) + { + const Handle(Graphic3d_Group)& aGroup = aGroupIt.Value(); + if (!aGroup->IsGroupPrimitivesAspectSet (Graphic3d_ASPECT_FILL_AREA)) + { + continue; + } + + aGroup->GroupPrimitivesAspect (anOldLineAsp, anOldTextAsp, anOldPntAsp, anOldAreaAps); + anAreaAsp->SetTextureMap (anOldAreaAps->TextureMap()); + if (anOldAreaAps->TextureMapState()) + { + anAreaAsp->SetTextureMapOn(); + } + else + { + anAreaAsp->SetTextureMapOff(); + } + + aGroup->SetGroupPrimitivesAspect (anAreaAsp); + } + } +} + +// ======================================================================= +// function : SetClosed +// purpose : +// ======================================================================= +void MeshPresentation::SetClosed (const bool theIsClosed) +{ + const PrsMgr_Presentations& aPrsList = Presentations(); + for (Standard_Integer aPrsIt = 1; aPrsIt <= aPrsList.Length(); ++aPrsIt) + { + const PrsMgr_ModedPresentation& aPrsModed = aPrsList.Value (aPrsIt); + if (aPrsModed.Mode() == MeshVS_DMF_WireFrame + || aPrsModed.Mode() == MeshVS_DMF_Shrink) + { + continue; + } + + const Handle(Prs3d_Presentation)& aPrs = aPrsModed.Presentation()->Presentation(); + for (Graphic3d_SequenceOfGroup::Iterator aGroupIt (aPrs->Groups()); aGroupIt.More(); aGroupIt.Next()) + { + const Handle(Graphic3d_Group)& aGroup = aGroupIt.Value(); + if (aGroup->IsGroupPrimitivesAspectSet (Graphic3d_ASPECT_FILL_AREA)) + { + aGroup->SetClosed (theIsClosed); + } + } + } +} + +// ======================================================================= +// function : SetClosed +// purpose : +// ======================================================================= +void MeshPresentation::Compute (const Handle(PrsMgr_PresentationManager3d)& thePrsMgr, + const Handle(Prs3d_Presentation)& thePrs, + const Standard_Integer theMode) +{ + MeshVS_Mesh::Compute (thePrsMgr, thePrs, theMode); + + // mark mesh as closed without checks for Capping algorithm but without suppressing back faces, + // thus artifacts on shells will appear only with capping option turned on and not in normal mode + SetClosed (true); +} diff --git a/src/MeshVS/MeshPresentation.h b/src/MeshVS/MeshPresentation.h new file mode 100644 index 0000000000..06cbec27de --- /dev/null +++ b/src/MeshVS/MeshPresentation.h @@ -0,0 +1,57 @@ +// Copyright (c) 2015 OPEN CASCADE SAS +// +// This file is part of commercial software by OPEN CASCADE SAS. +// +// This software is furnished in accordance with the terms and conditions +// of the contract and with the inclusion of this copyright notice. +// This software or any other copy thereof may not be provided or otherwise +// be made available to any third party. +// No ownership title to the software is transferred hereby. +// +// OPEN CASCADE SAS makes no representation or warranties with respect to the +// performance of this software, and specifically disclaims any responsibility +// for any damages, special or consequential, connected with its use. + +#ifndef MeshPresentation_H +#define MeshPresentation_H + +#include + +//! Interactive presentation for the mesh. +class MeshPresentation : public MeshVS_Mesh +{ +public: + + //! Empty constructor. + Standard_EXPORT MeshPresentation(); + + //! Return presentation type. + virtual AIS_KindOfInteractive Type() const Standard_OVERRIDE { return AIS_KOI_Object; } + + //! Return presentation signature. + virtual Standard_Integer Signature() const Standard_OVERRIDE { return 0; } + + //! Setup new material. + virtual void SetMaterial (const Graphic3d_NameOfMaterial theName) Standard_OVERRIDE + { + SetMaterial (Graphic3d_MaterialAspect (theName)); + } + + //! Setup new material. + virtual void SetMaterial (const Graphic3d_MaterialAspect& theMat) Standard_OVERRIDE; + + //! Override presentation compute. + virtual void Compute (const Handle(PrsMgr_PresentationManager3d)& thePrsMgr, + const Handle(Prs3d_Presentation)& thePrs, + const Standard_Integer theMode) Standard_OVERRIDE; + + //! Setup closed flag. + void SetClosed (const bool theIsClosed); + +public: + + DEFINE_STANDARD_RTTIEXT(MeshPresentation, MeshVS_Mesh) + +}; + +#endif // MeshPresentation_H diff --git a/src/MeshVS/MeshPrsBuilder.cpp b/src/MeshVS/MeshPrsBuilder.cpp new file mode 100644 index 0000000000..5c575d1197 --- /dev/null +++ b/src/MeshVS/MeshPrsBuilder.cpp @@ -0,0 +1,726 @@ +// Copyright (c) 2015 OPEN CASCADE SAS +// +// This file is part of commercial software by OPEN CASCADE SAS. +// +// This software is furnished in accordance with the terms and conditions +// of the contract and with the inclusion of this copyright notice. +// This software or any other copy thereof may not be provided or otherwise +// be made available to any third party. +// No ownership title to the software is transferred hereby. +// +// OPEN CASCADE SAS makes no representation or warranties with respect to the +// performance of this software, and specifically disclaims any responsibility +// for any damages, special or consequential, connected with its use. + +#ifdef __APPLE__ + #import +#endif + +#include "MeshPrsBuilder.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const int THE_NB_COLORS = 128; + +//! Auxiliary wrapper +class MeshTexture : public Graphic3d_Texture2Dmanual +{ +public: + + //! Main constructor. + MeshTexture (const TCollection_AsciiString& theFileName) + : Graphic3d_Texture2Dmanual (theFileName), myPathOrig (theFileName) {} + + //! Image reader. + virtual Handle(Image_PixMap) GetImage() const Standard_OVERRIDE + { + #if (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) || defined(__ANDROID__) + // mobile version is build without FreeImage to reduce binaries size - use Qt instead + Handle(PixMapQt) anImage = new PixMapQt(); + if(!anImage->Load (myPathOrig)) + { + Message::DefaultMessenger()->Send (TCollection_AsciiString ("Can not read image ") + myPathOrig + "!", Message_Fail); + return Handle(Image_PixMap)(); + } + return anImage; + #else + return Graphic3d_Texture2Dmanual::GetImage(); + #endif + } + +private: + + TCollection_AsciiString myPathOrig; + +public: + + DEFINE_STANDARD_RTTIEXT(MeshTexture, Graphic3d_Texture2Dmanual) + +}; + +DEFINE_STANDARD_HANDLE(MeshTexture, Graphic3d_Texture2Dmanual) + +IMPLEMENT_STANDARD_RTTIEXT(MeshPrsTexture, Graphic3d_Texture2D) +IMPLEMENT_STANDARD_RTTIEXT(MeshTexture, Graphic3d_Texture2Dmanual) +IMPLEMENT_STANDARD_RTTIEXT(MeshPrsBuilder, MeshVS_PrsBuilder) + +//================================================================ +// Function : MeshPrsBuilder +// Purpose : +//================================================================ +MeshPrsBuilder::MeshPrsBuilder (const Handle(MeshVS_Mesh)& theMesh, + const MeshVS_DisplayModeFlags& theFlags) +: MeshVS_PrsBuilder (theMesh, theFlags, Handle(MeshVS_DataSource)(), -1, MeshVS_BP_NodalColor), + myIsElemental (Standard_False), + myIsGrayscale (Standard_False), + myRangeFrom (0.0), + myRangeTo (1.0), + myToMapTexture(Standard_False), + myToFlipV (Standard_False) +{ +#if (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) || defined(__ANDROID__) + myToFlipV = Standard_True; +#else + myToFlipV = Standard_False; +#endif + + SetExcluding (Standard_True); +} + +//================================================================ +// Function : buildTextured +// Purpose : +//================================================================ +void MeshPrsBuilder::buildTextured (const Handle(Prs3d_Presentation)& thePrs, + const TColStd_PackedMapOfInteger& theIDs, + TColStd_PackedMapOfInteger& theIDsToExclude) const + +{ + myPrsGroup.Nullify(); + + Handle(MeshDataSource) aSource = Handle(MeshDataSource)::DownCast (GetDataSource()); + Handle(MeshVS_Drawer) aDrawer = GetDrawer(); + if (aSource.IsNull() + || aDrawer.IsNull()) + { + return; + } + + // subtract the hidden elements and ids to exclude (to minimize allocated memory) + TColStd_PackedMapOfInteger anIDs; + anIDs.Assign (theIDs); + Handle(TColStd_HPackedMapOfInteger) aHiddenElems = myParentMesh->GetHiddenElems(); + if (!aHiddenElems.IsNull()) + { + anIDs.Subtract (aHiddenElems->Map()); + } + anIDs.Subtract (theIDsToExclude); + + Standard_Boolean hasReflection = Standard_True; + Standard_Boolean isSmoothShading = Standard_False; + aDrawer->GetBoolean (MeshVS_DA_Reflection, hasReflection); + aDrawer->GetBoolean (MeshVS_DA_SmoothShading, isSmoothShading); + + MeshGroup aFullGroup; + aFullGroup.NodeLower = aSource->Nodes().Lower(); + aFullGroup.NodeUpper = aSource->Nodes().Upper(); + aFullGroup.ElemLower = aSource->Elements().Lower(); + aFullGroup.ElemUpper = aSource->Elements().Upper(); + for (Standard_Integer aGroupIter = 0; aGroupIter == 0 || aGroupIter <= aSource->Groups().Upper(); ++aGroupIter) + { + const MeshGroup& aGroup = !aSource->Groups().IsEmpty() ? aSource->Groups().Value (aGroupIter) : aFullGroup; + const Standard_Integer aNbNodes = aGroup.NodeUpper - aGroup.NodeLower + 1; + if (aGroup.NodeLower < 0 + || aGroup.NodeUpper < 0 + || aGroup.ElemLower < 0 + || aGroup.ElemUpper < 0 + || aNbNodes < 1) + { + continue; + } + + Handle(MeshTexture) aTexture; + if (!aGroup.Material.Texture.IsEmpty() + && myToMapTexture + && aSource->HasUV()) + { + aTexture = new MeshTexture (aGroup.Material.Texture); + } + + Standard_Integer aNbTris = 0; + for (Standard_Integer anElemIter = aGroup.ElemLower; anElemIter <= aGroup.ElemUpper; ++anElemIter) + { + if (!anIDs.Contains (anElemIter)) { continue; } + const Graphic3d_Vec4i& anElem = aSource->Elements().Value (anElemIter); + ++aNbTris; + if (anElem[3] != -1) + { + ++aNbTris; + } + } + if (aNbTris < 1) + { + continue; + } + + Handle(Graphic3d_ArrayOfTriangles) aTriangles = new Graphic3d_ArrayOfTriangles (aNbNodes, aNbTris * 3, + aSource->HasNormals() || isSmoothShading, Standard_False, !aTexture.IsNull()); + // fill nodes + if (!aTexture.IsNull()) + { + if (aSource->HasNormals()) + { + for (Standard_Integer aNodeIter = aGroup.NodeLower; aNodeIter <= aGroup.NodeUpper; ++aNodeIter) + { + const Graphic3d_Vec3& aNode = aSource->Nodes() .Value (aNodeIter); + const Graphic3d_Vec3& aNorm = aSource->Normals().Value (aNodeIter); + const Graphic3d_Vec2& anUV = aSource->NodesUV().Value (aNodeIter); + const float aV = myToFlipV ? (1.0f - anUV.y()) : anUV.y(); + aTriangles->AddVertex (aNode.x(), aNode.y(), aNode.z(), + aNorm.x(), aNorm.y(), aNorm.z(), + anUV.x(), aV); + } + } + else + { + for (Standard_Integer aNodeIter = aGroup.NodeLower; aNodeIter <= aGroup.NodeUpper; ++aNodeIter) + { + const Graphic3d_Vec3& aNode = aSource->Nodes() .Value (aNodeIter); + const Graphic3d_Vec2& anUV = aSource->NodesUV().Value (aNodeIter); + const float aV = myToFlipV ? (1.0f - anUV.y()) : anUV.y(); + aTriangles->AddVertex (aNode.x(), aNode.y(), aNode.z(), + anUV.x(), aV); + } + } + } + else + { + if (aSource->HasNormals()) + { + for (Standard_Integer aNodeIter = aGroup.NodeLower; aNodeIter <= aGroup.NodeUpper; ++aNodeIter) + { + const Graphic3d_Vec3& aNode = aSource->Nodes() .Value (aNodeIter); + const Graphic3d_Vec3& aNorm = aSource->Normals().Value (aNodeIter); + aTriangles->AddVertex (aNode.x(), aNode.y(), aNode.z(), + aNorm.x(), aNorm.y(), aNorm.z()); + } + } + else + { + for (Standard_Integer aNodeIter = aGroup.NodeLower; aNodeIter <= aGroup.NodeUpper; ++aNodeIter) + { + const Graphic3d_Vec3& aNode = aSource->Nodes().Value (aNodeIter); + aTriangles->AddVertex (aNode.x(), aNode.y(), aNode.z()); + } + } + } + + // fill indices + for (Standard_Integer anElemIter = aGroup.ElemLower; anElemIter <= aGroup.ElemUpper; ++anElemIter) + { + if (!anIDs.Contains (anElemIter)) { continue; } + const Graphic3d_Vec4i& anElem = aSource->Elements().Value (anElemIter); + aTriangles->AddEdge (anElem[0] + 1 - aGroup.NodeLower); + aTriangles->AddEdge (anElem[1] + 1 - aGroup.NodeLower); + aTriangles->AddEdge (anElem[2] + 1 - aGroup.NodeLower); + if (anElem[3] != -1) + { + aTriangles->AddEdge (anElem[0] + 1 - aGroup.NodeLower); + aTriangles->AddEdge (anElem[2] + 1 - aGroup.NodeLower); + aTriangles->AddEdge (anElem[3] + 1 - aGroup.NodeLower); + } + } + + // reconstruct normals + if (!aSource->HasNormals() && isSmoothShading) + { + // compute normal at each node, taking into account size of each element (e.g. without pre-normalization) + for (Standard_Integer anElemIter = aGroup.ElemLower; anElemIter <= aGroup.ElemUpper; ++anElemIter) + { + if (!anIDs.Contains (anElemIter)) { continue; } + const Graphic3d_Vec4i& anElem = aSource->Elements().Value (anElemIter); + + const Graphic3d_Vec3& aNode0 = aSource->Nodes().Value (anElem[0]); + const Graphic3d_Vec3& aNode1 = aSource->Nodes().Value (anElem[1]); + const Graphic3d_Vec3& aNode2 = aSource->Nodes().Value (anElem[2]); + + const Graphic3d_Vec3 aVec01 = aNode1 - aNode0; + const Graphic3d_Vec3 aVec02 = aNode2 - aNode0; + const Graphic3d_Vec3 aCross = Graphic3d_Vec3::Cross (aVec01, aVec02); + const Graphic3d_Vec3d aTriNorm (aCross.x(), aCross.y(), aCross.z()); + const Standard_Integer aNbElemNodes = anElem[3] != -1 ? 4 : 3; + Graphic3d_Vec3d aNorm; + for (Standard_Integer aNodeIter = 0; aNodeIter < aNbElemNodes; ++aNodeIter) + { + // Graphic3d_ArrayOfPrimitives zeroes values in costructor + const Standard_Integer aNodeIndex = anElem[aNodeIter] + 1 - aGroup.NodeLower; + aTriangles->VertexNormal (aNodeIndex, aNorm.x(), aNorm.y(), aNorm.z()); + aNorm += aTriNorm; + aTriangles->SetVertexNormal (aNodeIndex, aNorm.x(), aNorm.y(), aNorm.z()); + } + } + + // normalize + for (Standard_Integer anElemIter = aGroup.ElemLower; anElemIter <= aGroup.ElemUpper; ++anElemIter) + { + if (!anIDs.Contains (anElemIter)) { continue; } + const Graphic3d_Vec4i& anElem = aSource->Elements().Value (anElemIter); + const Standard_Integer aNbElemNodes = anElem[3] != -1 ? 4 : 3; + Graphic3d_Vec3d aNorm; + for (Standard_Integer aNodeIter = 0; aNodeIter < aNbElemNodes; ++aNodeIter) + { + const Standard_Integer aNodeIndex = anElem[aNodeIter] + 1 - aGroup.NodeLower; + aTriangles->VertexNormal (aNodeIndex, aNorm.x(), aNorm.y(), aNorm.z()); + aNorm.Normalize(); + aTriangles->SetVertexNormal (aNodeIndex, aNorm.x(), aNorm.y(), aNorm.z()); + } + } + } + + Graphic3d_MaterialAspect aMat[2]; + aDrawer->GetMaterial(MeshVS_DA_FrontMaterial, aMat[0]); + aDrawer->GetMaterial(MeshVS_DA_BackMaterial, aMat[1]); + if (aMat[0].Name() == Graphic3d_NOM_DEFAULT + && aGroup.Material.Aspect.Name() != Graphic3d_NOM_DEFAULT) + { + aMat[0] = aGroup.Material.Aspect; + aMat[1] = aGroup.Material.Aspect; + } + if (!hasReflection) + { + aMat[0].SetReflectionModeOff (Graphic3d_TOR_AMBIENT); + aMat[0].SetReflectionModeOff (Graphic3d_TOR_DIFFUSE); + aMat[0].SetReflectionModeOff (Graphic3d_TOR_SPECULAR); + aMat[0].SetReflectionModeOff (Graphic3d_TOR_EMISSION); + } + + Handle(Graphic3d_AspectFillArea3d) anAreaAsp = MeshVS_Tool::CreateAspectFillArea3d (aDrawer, aMat[0]); + if (!aTexture.IsNull()) + { + anAreaAsp->SetTextureMap (aTexture); + anAreaAsp->SetTextureMapOn(); + } + + Handle(Graphic3d_Group) aPrsGroup = thePrs->NewGroup(); + aPrsGroup->SetGroupPrimitivesAspect (anAreaAsp); + aPrsGroup->AddPrimitiveArray (aTriangles); + } +} + +//================================================================ +// Function : Build +// Purpose : +//================================================================ +void MeshPrsBuilder::Build (const Handle(Prs3d_Presentation)& thePrs, + const TColStd_PackedMapOfInteger& theIDs, + TColStd_PackedMapOfInteger& theIDsToExclude, + const Standard_Boolean theIsElement, + const Standard_Integer theDisplayMode) const +{ + myPrsGroup.Nullify(); + if (myProperty.IsNull()) + { + buildTextured (thePrs, theIDs, theIDsToExclude); + return; + } + + Handle(MeshVS_DataSource) aSource = GetDataSource(); + Handle(MeshVS_Drawer) aDrawer = GetDrawer(); + if (aSource.IsNull() + || aDrawer.IsNull() + || myProperty.IsNull()) + { + return; + } + + Standard_Integer aMaxFaceNodes = 0; + if (!aDrawer->GetInteger (MeshVS_DA_MaxFaceNodes, aMaxFaceNodes) + || aMaxFaceNodes <= 0 ) + { + return; + } + + MeshVS_Buffer aCoordsBuf (3 * aMaxFaceNodes * sizeof(Standard_Real)); + TColStd_Array1OfReal aCoords (aCoordsBuf, 1, 3 * aMaxFaceNodes); + if ((theDisplayMode & GetFlags()) == 0 + || !theIsElement) + { + return; + } + + const Standard_Real aLowerValue = propertyLowerValue(); + const Standard_Real anUpperValue = propertyUpperValue(); + const Standard_Real aRange = anUpperValue - aLowerValue; + + // subtract the hidden elements and ids to exclude (to minimize allocated memory) + TColStd_PackedMapOfInteger anIDs; + anIDs.Assign (theIDs); + Handle(TColStd_HPackedMapOfInteger) aHiddenElems = myParentMesh->GetHiddenElems(); + if (!aHiddenElems.IsNull()) + { + anIDs.Subtract (aHiddenElems->Map()); + } + anIDs.Subtract (theIDsToExclude); + + Standard_Boolean isReflect = Standard_False, isMeshSmoothShading = Standard_False; + aDrawer->GetBoolean (MeshVS_DA_ColorReflection, isReflect); + aDrawer->GetBoolean (MeshVS_DA_SmoothShading, isMeshSmoothShading); + + // Following parameter are used for texture presentation only + int nbColors = THE_NB_COLORS;///myTextureColorMap.Length(); // Number of colors from color map + int nbTextureColors = nbColors; // Number of colors in texture (it will be pow of 2) + + Graphic3d_MaterialAspect aMaterials[2] = + { + Graphic3d_MaterialAspect (Graphic3d_NOM_PLASTIC), + Graphic3d_MaterialAspect (Graphic3d_NOM_PLASTIC) + }; + for (Standard_Integer aMatIter = 0; aMatIter < 2; ++aMatIter) + { + Graphic3d_MaterialAspect& aMat = aMaterials[aMatIter]; + if (!isReflect) + { + aMat.SetReflectionModeOff (Graphic3d_TOR_SPECULAR); + aMat.SetReflectionModeOff (Graphic3d_TOR_AMBIENT); + aMat.SetReflectionModeOff (Graphic3d_TOR_DIFFUSE); + aMat.SetReflectionModeOff (Graphic3d_TOR_EMISSION); + } + else + { + aMat.SetAmbient (0.5); + aMat.SetDiffuse (0.5); + aMat.SetSpecular(0.0); + aMat.SetEmissive(0.0); + } + } + + Standard_Integer aNbFacePrimitives = 0; + Standard_Integer aNbEdgePrimitives = 0; + for (TColStd_MapIteratorOfPackedMapOfInteger it (anIDs); it.More(); it.Next()) + { + MeshVS_EntityType aType = MeshVS_ET_NONE; + Standard_Integer aNbNodes = 0; + if (!aSource->GetGeom (it.Key(), Standard_True, aCoords, aNbNodes, aType) + || aType != MeshVS_ET_Face) + { + continue; + } + + aNbEdgePrimitives += aNbNodes; // add edge segments + aNbFacePrimitives += aNbNodes - 2; // add face triangles + } + + Standard_Boolean toShowEdges = Standard_True; + aDrawer->GetBoolean (MeshVS_DA_ShowEdges, toShowEdges); + + // Here we do not use indices arrays because they are not effective for some mesh + // drawing modes: shrinking mode (displaces the vertices inside the polygon), 3D + // cell rendering (normal interpolation is not always applicable - flat shading), + // elemental coloring (color interpolation is impossible) + + Handle(Graphic3d_ArrayOfTriangles) aFaceTriangles = new Graphic3d_ArrayOfTriangles (aNbFacePrimitives * 3, 0, + Standard_True, Standard_False, Standard_True); + Handle(Graphic3d_ArrayOfSegments) anEdgeSegments; + if (toShowEdges) + { + anEdgeSegments = new Graphic3d_ArrayOfSegments (aNbEdgePrimitives * 2); + } + + gp_Pnt P, Start; + Standard_Real aMin = gp::Resolution() * gp::Resolution(); + gp_Dir aDefNorm = gp::DZ(); + + TColStd_Array1OfInteger aNodes (1, 10); + for (TColStd_MapIteratorOfPackedMapOfInteger it (anIDs); it.More(); it.Next()) + { + Standard_Integer aKey = it.Key(); + Standard_Integer aNbNodes = 0; + MeshVS_EntityType aType = MeshVS_ET_NONE; + if (!aSource->GetGeom (aKey, Standard_True, aCoords, aNbNodes, aType) + || aType != MeshVS_ET_Face + || aNbNodes > 10 + || !aSource->GetNodesByElement (aKey, aNodes, aNbNodes)) + { + continue; + } + + // Preparing normal(s) to show reflections if requested + Handle(TColStd_HArray1OfReal) aNormals; + Standard_Boolean hasNormals = isReflect + && aSource->GetNormalsByElement (aKey, isMeshSmoothShading, aMaxFaceNodes, aNormals); + + for (Standard_Integer aNodeIdx = 0; aNodeIdx < aNbNodes - 2; ++aNodeIdx) + { + for (Standard_Integer aSubIdx = 0; aSubIdx < 3; ++aSubIdx) + { + gp_XYZ aPnt (aCoords (3 * (aSubIdx == 0 ? 0 : (aNodeIdx + aSubIdx)) + 1), + aCoords (3 * (aSubIdx == 0 ? 0 : (aNodeIdx + aSubIdx)) + 2), + aCoords (3 * (aSubIdx == 0 ? 0 : (aNodeIdx + aSubIdx)) + 3)); + + gp_Vec aNorm = aDefNorm; + if (hasNormals) + { + gp_Vec aTestNorm (aNormals->Value (3 * (aSubIdx == 0 ? 0 : (aNodeIdx + aSubIdx)) + 1), + aNormals->Value (3 * (aSubIdx == 0 ? 0 : (aNodeIdx + aSubIdx)) + 2), + aNormals->Value (3 * (aSubIdx == 0 ? 0 : (aNodeIdx + aSubIdx)) + 3)); + + if (aTestNorm.SquareMagnitude() > aMin) + { + aNorm = gp_Dir (aTestNorm); + } + } + + // retrieve nodal value + Standard_Integer aNodeIndex = aKey; + if (!myIsElemental) + { + aNodeIndex = aNodes (aSubIdx == 0 ? 1 : (aNodeIdx + aSubIdx + 1)); + } + + Standard_Real aTexCoordU = 0.25; + Standard_Real aTexCoordV = 0.25; + const Standard_Real aValue = myProperty->Value (aNodeIndex); + if (aRange > gp::Resolution() + && !IsNaN (aValue)) + { + const Standard_Real aNormVal = (aValue - aLowerValue) / aRange; + aTexCoordU = (aNormVal * (nbColors - 1.0) + 0.5) / nbTextureColors; + aTexCoordV = 0.75; + } + + // Transform texture coordinate in accordance with number of colors specified + // by upper level and real size of OpenGL texture. The OpenGL texture has border + // colors interpolated with the colors from the color map, thats why we need to + // shrink texture coordinates around the middle point to exclude areas where the + // map colors are interpolated with the borders color + aFaceTriangles->AddVertex (aPnt, aNorm, gp_Pnt2d (aTexCoordU, aTexCoordV)); + } + } + + if (!anEdgeSegments.IsNull()) + { + for (Standard_Integer aNodeIdx = 0; aNodeIdx < aNbNodes; ++aNodeIdx) // border segmentation + { + const Standard_Integer aNextIdx = (aNodeIdx + 1) % aNbNodes; + + anEdgeSegments->AddVertex (aCoords (3 * aNodeIdx + 1), + aCoords (3 * aNodeIdx + 2), + aCoords (3 * aNodeIdx + 3)); + + anEdgeSegments->AddVertex (aCoords (3 * aNextIdx + 1), + aCoords (3 * aNextIdx + 2), + aCoords (3 * aNextIdx + 3)); + } + } + + // if IsExcludingOn then presentation must not be built by other builders + if (IsExcludingOn()) + { + theIDsToExclude.Add (aKey); + } + } + + Aspect_TypeOfLine anEdgeType = Aspect_TOL_SOLID; + Standard_Integer anEdgeInt; + Standard_Real anEdgeWidth; + Quantity_Color anInteriorColor, anEdgeColor, aLineColor; + + aDrawer->GetColor (MeshVS_DA_InteriorColor, anInteriorColor); + aDrawer->GetColor (MeshVS_DA_EdgeColor, anEdgeColor); + aDrawer->GetColor (MeshVS_DA_BeamColor, aLineColor); + aDrawer->GetDouble (MeshVS_DA_EdgeWidth, anEdgeWidth); + + if (aDrawer->GetInteger (MeshVS_DA_EdgeType, anEdgeInt)) + { + anEdgeType = (Aspect_TypeOfLine )anEdgeInt; + } + + Handle(Prs3d_Drawer) aPrs3dDrawer = myParentMesh->Attributes(); + if (aPrs3dDrawer.IsNull()) + { + return; + } + + aPrs3dDrawer->SetShadingAspect (new Prs3d_ShadingAspect()); + + myFillAsp = new Graphic3d_AspectFillArea3d(); + *myFillAsp = *aPrs3dDrawer->ShadingAspect()->Aspect(); + + myFillAsp->SetFrontMaterial(aMaterials[0]); + myFillAsp->SetBackMaterial (aMaterials[1]); + + Handle(Graphic3d_Texture2D) aTexture = createTexture (myIsGrayscale, myRangeFrom, myRangeTo, myProperty->IsInversed()); + if (aTexture.IsNull()) + { + return; + } + + myFillAsp->SetTextureMapOn(); + myFillAsp->SetTextureMap (aTexture); + myFillAsp->SetInteriorColor (Quantity_NOC_WHITE); + + myFillAsp->SetDistinguishOff(); + myFillAsp->SetEdgeOff(); + + Handle(Graphic3d_Group) aGroup1 = thePrs->NewGroup(); + aGroup1->SetGroupPrimitivesAspect (myFillAsp); + aGroup1->AddPrimitiveArray (aFaceTriangles); + + myPrsGroup = aGroup1; + + if (toShowEdges) + { + Handle(Graphic3d_Group) aGroup2 = thePrs->NewGroup(); + + Handle(Graphic3d_AspectLine3d) anLAsp = new Graphic3d_AspectLine3d (anEdgeColor, anEdgeType, anEdgeWidth); + aGroup2->SetGroupPrimitivesAspect (anLAsp); + aGroup2->AddPrimitiveArray (anEdgeSegments); + } +} + +//================================================================ +// Function : SetProperty +// Purpose : +//================================================================ +void MeshPrsBuilder::SetProperty (const Handle(MeshScalarProperty)& theProperty, + const Standard_Boolean theIsElemental) +{ + myProperty = theProperty; + myIsElemental = theIsElemental; + if (!myProperty.IsNull()) + { + myRangeFrom = myProperty->ColorscaleRangeFrom(); + myRangeTo = myProperty->ColorscaleRangeTo(); + } +} + +//================================================================ +// Function : SetRange +// Purpose : +//================================================================ +void MeshPrsBuilder::SetRange (const Standard_Real theFrom, + const Standard_Real theTo, + const bool theIsInversed) +{ + Standard_Real aPrec = 1.0 / Standard_Real(THE_NB_COLORS * 10); + if (Abs (myRangeFrom - theFrom) < aPrec + && Abs (myRangeTo - theTo) < aPrec + && (myProperty.IsNull() || myProperty->IsInversed() == theIsInversed)) + { + return; + } + + myRangeFrom = theFrom; + myRangeTo = theTo; + if (!myProperty.IsNull()) + { + myProperty->SetInversed (theIsInversed); + myProperty->SetColorscaleRange (theFrom, theTo); + } + if (myPrsGroup.IsNull()) + { + return; + } + + Handle(Graphic3d_Texture2D) aTexture = createTexture (myIsGrayscale, myRangeFrom, myRangeTo, theIsInversed); + if (aTexture.IsNull()) + { + return; + } + + myFillAsp->SetTextureMap (aTexture); + myPrsGroup->SetGroupPrimitivesAspect (myFillAsp); +} + +//================================================================ +// Function : createTexture +// Purpose : +//================================================================ +Handle(Graphic3d_Texture2D) MeshPrsBuilder::createTexture (const Standard_Boolean theIsGrayscale, + const Standard_Real theFrom, + const Standard_Real theTo, + const bool theIsInversed) +{ + const Standard_Integer aNbColors = THE_NB_COLORS; + + const Graphic3d_Vec3d anOut = Graphic3d_Vec3d (0.5, 0.5, 0.5); + Graphic3d_Vec3d aScale00 = theIsGrayscale ? Graphic3d_Vec3d (0.0, 0.0, 0.0) : Graphic3d_Vec3d (0.0, 0.0, 1.0); + Graphic3d_Vec3d aScale05 = theIsGrayscale ? Graphic3d_Vec3d (0.5, 0.5, 0.5) : Graphic3d_Vec3d (0.0, 1.0, 0.0); + Graphic3d_Vec3d aScale10 = theIsGrayscale ? Graphic3d_Vec3d (1.0, 1.0, 1.0) : Graphic3d_Vec3d (1.0, 0.0, 0.0); + if (theIsInversed) + { + std::swap (aScale00, aScale10); + } + + const Standard_Real aRange = Max (theTo - theFrom, 0.01); + const Standard_Real aRangeInv = 1.0 / aRange; + const Standard_Real aMiddle = theFrom + 0.5 * aRange; + const Standard_Real aFrom = theFrom; + + // create and fill image with colors + Handle(Image_PixMap) anImage = new Image_PixMap(); + if (!anImage->InitTrash (Image_PixMap::ImgRGBA, aNbColors, 2)) + { + return NULL; + } + + Image_ColorRGBA anOutColor; + anOutColor.r() = Standard_Byte(255.0 * anOut.r()); + anOutColor.g() = Standard_Byte(255.0 * anOut.g()); + anOutColor.b() = Standard_Byte(255.0 * anOut.b()); + anOutColor.a() = 0xFF; + + anImage->SetTopDown (false); + for (Standard_Size aColIter = 0; aColIter < Standard_Size(aNbColors); ++aColIter) + { + const Standard_Real aValue = Standard_Real(aColIter) / Standard_Real(aNbColors - 1); + Graphic3d_Vec3d aColorVal; + if (aValue < theFrom + || aValue > theTo) + { + aColorVal = anOut; + } + else if (aValue < aMiddle) + { + const Standard_Real aHalfVal = (aValue - aFrom) * 2.0 * aRangeInv; + aColorVal = aScale00 * (1.0 - aHalfVal) + aScale05 * aHalfVal; + } + else + { + const Standard_Real aHalfVal = (aValue - aFrom) * 2.0 * aRangeInv - 1.0; + aColorVal = aScale05 * (1.0 - aHalfVal) + aScale10 * aHalfVal; + } + + Image_ColorRGBA& aColor0 = anImage->ChangeValue (0, aColIter); + Image_ColorRGBA& aColor1 = anImage->ChangeValue (1, aColIter); + aColor0.r() = Standard_Byte(255.0 * aColorVal.r()); + aColor0.g() = Standard_Byte(255.0 * aColorVal.g()); + aColor0.b() = Standard_Byte(255.0 * aColorVal.b()); + aColor0.a() = 0xFF; + aColor1 = anOutColor; + } + + // create texture + return new MeshPrsTexture (anImage); +} diff --git a/src/MeshVS/MeshPrsBuilder.h b/src/MeshVS/MeshPrsBuilder.h new file mode 100644 index 0000000000..80430d39fc --- /dev/null +++ b/src/MeshVS/MeshPrsBuilder.h @@ -0,0 +1,147 @@ +// Copyright (c) 2015 OPEN CASCADE SAS +// +// This file is part of commercial software by OPEN CASCADE SAS. +// +// This software is furnished in accordance with the terms and conditions +// of the contract and with the inclusion of this copyright notice. +// This software or any other copy thereof may not be provided or otherwise +// be made available to any third party. +// No ownership title to the software is transferred hereby. +// +// OPEN CASCADE SAS makes no representation or warranties with respect to the +// performance of this software, and specifically disclaims any responsibility +// for any damages, special or consequential, connected with its use. + +#ifndef MeshPrsBuilder_H +#define MeshPrsBuilder_H + +#include "MeshDataSource.h" + +#include +#include +#include + +//! Auxiliary class to hold texture. +class MeshPrsTexture : public Graphic3d_Texture2D +{ +public: + + MeshPrsTexture (const Handle(Image_PixMap)& theImg) + : Graphic3d_Texture2D (theImg, Graphic3d_TOT_2D) + { + myParams->SetModulate (Standard_True); + myParams->SetFilter (Graphic3d_TOTF_BILINEAR); + } + +public: + + DEFINE_STANDARD_RTTIEXT(MeshPrsTexture, Graphic3d_Texture2D) + +}; + +DEFINE_STANDARD_HANDLE(MeshPrsTexture, Graphic3d_Texture2D) + +//! Auxiliary builder for Nodal or Elemental mesh properties using textured colorscale. +class MeshPrsBuilder : public MeshVS_PrsBuilder +{ + +public: + + //! Default constructor. + Standard_EXPORT MeshPrsBuilder (const Handle(MeshVS_Mesh)& theMesh, + const MeshVS_DisplayModeFlags& theFlags); + + //! Setup textures when available. + Standard_Boolean ToMapTextures() const { return myToMapTexture; } + + //! Setup textures when available. + void SetMapTextures (const Standard_Boolean theToMap) { myToMapTexture = theToMap; } + +public: + + //! Setup property to display. + Standard_EXPORT void SetProperty (const Handle(MeshScalarProperty)& theProperty, + const Standard_Boolean theIsElemental); + + //! Grayscale flag. + Standard_Boolean IsGrayscale() const + { + return myIsGrayscale; + } + + //! Specify using grayscale or B->G->R colorscale + void SetGrayscale (const Standard_Boolean theIsGrayscale) + { + myIsGrayscale = theIsGrayscale; + } + + //! Adjust colorscale range. + Standard_EXPORT void SetRange (const Standard_Real theFrom, + const Standard_Real theTo, + const bool theIsInversed); + +public: + + //! Main builder. + Standard_EXPORT virtual void Build (const Handle(Prs3d_Presentation)& thePrs, + const TColStd_PackedMapOfInteger& theIDs, + TColStd_PackedMapOfInteger& theIDsToExclude, + const Standard_Boolean theIsElement, + const Standard_Integer theDisplayMode) const Standard_OVERRIDE; + +protected: + + //! Textured presentation builder. + void buildTextured (const Handle(Prs3d_Presentation)& thePrs, + const TColStd_PackedMapOfInteger& theIDs, + TColStd_PackedMapOfInteger& theIDsToExclude) const; + + //! Auxiliary method to create texture. + static Handle(Graphic3d_Texture2D) createTexture (const Standard_Boolean theIsGrayscale, + const Standard_Real theFrom, + const Standard_Real theTo, + const bool theIsInversed); + + //! Return lower property value. + Standard_Real propertyLowerValue() const + { + if (myProperty.IsNull()) + { + return 0.0; + } + return myIsGrayscale ? Min (0.0, myProperty->LowerValue()) : myProperty->LowerValue(); + } + + //! Return upper property value. + Standard_Real propertyUpperValue() const + { + if (myProperty.IsNull()) + { + return 1.0; + } + return myIsGrayscale ? Max (1.0, myProperty->UpperValue()) : myProperty->UpperValue(); + } + +protected: + + Handle(MeshScalarProperty) myProperty; //!< property to display + Standard_Boolean myIsElemental; //!< flag indicating elemental property + Standard_Boolean myIsGrayscale; //!< flag to create grayscale colorscale + Standard_Real myRangeFrom; //!< colorscale range, lower value + Standard_Real myRangeTo; //!< colorscale range, upper value + + Standard_Boolean myToMapTexture;//!< setup textures when available + Standard_Boolean myToFlipV; //!< flip texture coordinates vertically + + mutable Handle(Graphic3d_Group) myPrsGroup; //!< presentation group with triangles + mutable Handle(Graphic3d_AspectFillArea3d) myFillAsp; + +public: + + DEFINE_STANDARD_RTTIEXT(MeshPrsBuilder, MeshVS_PrsBuilder) + +}; + +DEFINE_STANDARD_HANDLE(MeshPrsBuilder, MeshVS_PrsBuilder) + +#endif // MeshPrsBuilder_H diff --git a/src/MeshVS/MeshScalarProperty.h b/src/MeshVS/MeshScalarProperty.h new file mode 100644 index 0000000000..604f9fdd69 --- /dev/null +++ b/src/MeshVS/MeshScalarProperty.h @@ -0,0 +1,124 @@ +// Copyright (c) 2015 OPEN CASCADE SAS +// +// This file is part of commercial software by OPEN CASCADE SAS. +// +// This software is furnished in accordance with the terms and conditions +// of the contract and with the inclusion of this copyright notice. +// This software or any other copy thereof may not be provided or otherwise +// be made available to any third party. +// No ownership title to the software is transferred hereby. +// +// OPEN CASCADE SAS makes no representation or warranties with respect to the +// performance of this software, and specifically disclaims any responsibility +// for any damages, special or consequential, connected with its use. + +#ifndef MeshScalarProperty_H +#define MeshScalarProperty_H + +#include +#include +#include +#include +#include +#include + +//! Return true for NaN. +inline bool IsNaN (const double theValue) +{ +#if defined(_MSC_VER) + return ::_isnan (theValue) != 0; +#else + return std::isnan (theValue); +#endif +} + +//! Property assigned to Mesh elements or nodes +class MeshScalarProperty : public Standard_Transient +{ + +public: + + //! Return property name. + const TCollection_AsciiString& Name() const { return myName; } + + //! Return lower index. + Standard_Integer LowerIndex() const { return myValues.Lower(); } + + //! Return upper index. + Standard_Integer UpperIndex() const { return myValues.Upper(); } + + //! Return value for specified index. + Standard_Real Value (const Standard_Integer theIndex) const { return myValues.Value (theIndex); } + + //! Return lower value of the property. + Standard_Real LowerValue() const { return myValueLower; } + + //! Return lower value of the property. + Standard_Real UpperValue() const { return myValueUpper; } + + //! Return true if values has opposite meaning (greater value is better). + bool IsInversed() const { return myIsInversed; } + + //! Setup flag inficating that values has opposite meaning (greater value is better) or normal meaning (greater value is badder). + void SetInversed(const bool theIsInversed) { myIsInversed = theIsInversed; } + + //! Return colorscale range (from). + Standard_Real ColorscaleRangeFrom() const { return myCSRangeFrom; } + + //! Return colorscale range (to). + Standard_Real ColorscaleRangeTo() const { return myCSRangeTo; } + + //! Setup colorscale range. + void SetColorscaleRange (const Standard_Real theFrom, + const Standard_Real theTo) + { + myCSRangeFrom = theFrom; + myCSRangeTo = theTo; + } + +public: + + //! Default constructor. + MeshScalarProperty (const TCollection_AsciiString& theName) + : myName (theName), + myValueLower ( Precision::Infinite()), + myValueUpper (-Precision::Infinite()), + myCSRangeFrom(0.0), + myCSRangeTo (1.0), + myIsInversed (false) + {} + + //! Append new value + void AppendValue (const Standard_Real theValue) + { + myValues.Append ((float )theValue); + + if (!IsNaN (theValue)) + { + myValueLower = Min (myValueLower, theValue); + myValueUpper = Max (myValueUpper, theValue); + } + } + +protected: + + TCollection_AsciiString myName; //!< property name + //NCollection_Vector myValues; //!< property values + NCollection_Vector myValues; //!< property values + Standard_Real myValueLower; //!< values range - lower value + Standard_Real myValueUpper; //!< values range - upper value + Standard_Real myCSRangeFrom;//!< colorscale range - from + Standard_Real myCSRangeTo; //!< colorscale range - to + bool myIsInversed; //!< values meaning + +public: + + DEFINE_STANDARD_RTTIEXT(MeshScalarProperty, Standard_Transient) + +}; + +DEFINE_STANDARD_HANDLE(MeshScalarProperty, Standard_Transient) + +typedef NCollection_Vector MeshScalarProperties; + +#endif // MeshScalarProperty_H diff --git a/src/MeshVS/ObjDataSource.cpp b/src/MeshVS/ObjDataSource.cpp new file mode 100644 index 0000000000..edb139450c --- /dev/null +++ b/src/MeshVS/ObjDataSource.cpp @@ -0,0 +1,680 @@ +// Copyright (c) 2015 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 + +IMPLEMENT_STANDARD_RTTIEXT(ObjDataSource, MeshDataSource) + +//! Simple wrapper. +struct FileSentry +{ + FILE* File; + + FileSentry (const TCollection_AsciiString& theFile) + : File (OSD_OpenFile (theFile.ToCString(), "rb")) {} + + ~FileSentry() + { + if (File != NULL) + { + ::fclose (File); + } + } +}; + +//! Read 3 float values. +inline bool objReadVec3 (const char* thePos, + char*& theNext, + Graphic3d_Vec3& theVec) +{ + const char* aPos = thePos; + theVec.x() = (float )Strtod (aPos, &theNext); + aPos = theNext; + theVec.y() = (float )Strtod (aPos, &theNext); + aPos = theNext; + theVec.z() = (float )Strtod (aPos, &theNext); + return aPos != theNext; +} + +//! Read string. +inline bool objReadName (const char* thePos, + TCollection_AsciiString& theName) +{ + TCollection_AsciiString aName = TCollection_AsciiString (thePos); + Standard_Integer aTail = aName.Length(); + if (aTail > 0 + && aName.Value (aTail) == '\n') + { + aName.SetValue (aTail--, '\0'); // replace '\n' + } + if (aTail > 0 + && aName.Value (aTail) == '\r') + { + aName.SetValue (aTail--, '\0'); // replace '\r' + } + theName = aName.ToCString(); + theName.LeftAdjust(); + theName.RightAdjust(); + return !theName.IsEmpty(); +} + +//! Reader of mtl files. +class ObjMaterialReader +{ +public: + + //! Main constructor. + ObjMaterialReader (NCollection_DataMap& theMaterials) + : myFile (NULL), myMaterials (&theMaterials), myNbLines (0) {} + + //! Destructor. + ~ObjMaterialReader() + { + if (myFile != NULL) + { + ::fclose (myFile); + } + } + + //! Read the file. + Standard_Boolean Read (const TCollection_AsciiString& theFolder, + const TCollection_AsciiString& theFile) + { + myPath = theFolder + theFile; + myFile = OSD_OpenFile (myPath.ToCString(), "rb"); + if (myFile == NULL) + { + Message::DefaultMessenger()->Send (TCollection_AsciiString ("OBJ material file '") + myPath + "' is not found!", Message_Warning); + return Standard_False; + } + + char aLine[256] = {}; + TCollection_AsciiString aMatName; + MeshMaterial aMat; + const Standard_Integer aNbMatOld = myMaterials->Extent(); + bool hasAspect = false; + for (; ::feof (myFile) == 0 && ::fgets (aLine, 255, myFile) != NULL; ) + { + ++myNbLines; + + const char* aPos = aLine; + if (*aLine == '#' + || *aLine == '\n' + || *aLine == '\0') + { + continue; + } + + if (::memcmp (aLine, "newmtl ", 7) == 0) + { + aPos += 7; + if (!aMatName.IsEmpty()) + { + if (hasAspect) + { + aMat.Aspect.SetMaterialType (Graphic3d_MATERIAL_PHYSIC); + aMat.Aspect.SetMaterialName (aMatName.ToCString()); + } + else + { + // reset incomplete material definition + aMat.Aspect = Graphic3d_MaterialAspect(); + } + myMaterials->Bind (aMatName, aMat); + hasAspect = false; + } + + aMatName = TCollection_AsciiString(aPos); + aMat = MeshMaterial(); + if (!objReadName (aPos, aMatName)) + { + Message::DefaultMessenger()->Send (TCollection_AsciiString("Empty OBJ material at line ") + myNbLines + " in file " + myPath, Message_Warning); + } + } + else if (::memcmp (aLine, "Ka ", 3) == 0) + { + aPos += 3; + char* aNext = NULL; + Graphic3d_Vec3 aColor; + objReadVec3 (aPos, aNext, aColor); + aPos = aNext; + if (validateColor (aColor)) + { + Quantity_Color aQColor (aColor.r(), aColor.g(), aColor.b(), Quantity_TOC_RGB); + aMat.Aspect.SetAmbientColor (aQColor); + hasAspect = true; + } + } + else if (::memcmp (aLine, "Kd ", 3) == 0) + { + aPos += 3; + char* aNext = NULL; + Graphic3d_Vec3 aColor; + objReadVec3 (aPos, aNext, aColor); + aPos = aNext; + if (validateColor (aColor)) + { + Quantity_Color aQColor (aColor.r(), aColor.g(), aColor.b(), Quantity_TOC_RGB); + aMat.Aspect.SetDiffuseColor (aQColor); + hasAspect = true; + } + } + else if (::memcmp (aLine, "Ks ", 3) == 0) + { + aPos += 3; + char* aNext = NULL; + Graphic3d_Vec3 aColor; + objReadVec3 (aPos, aNext, aColor); + aPos = aNext; + if (validateColor (aColor)) + { + Quantity_Color aQColor (aColor.r(), aColor.g(), aColor.b(), Quantity_TOC_RGB); + aMat.Aspect.SetSpecularColor (aQColor); + } + } + else if (::memcmp (aLine, "Ns ", 3) == 0) + { + aPos += 3; + char* aNext = NULL; + Standard_Real aSpecular = Strtod (aPos, &aNext); + aPos = aNext; + if (aSpecular >= 0.0 + && aSpecular <= 128.0) + { + aMat.Aspect.SetShininess (aSpecular / 128.0); + } + } + else if (::memcmp (aLine, "Tr ", 3) == 0) + { + aPos += 3; + char* aNext = NULL; + Standard_Real anAlpha = Strtod (aPos, &aNext); + aPos = aNext; + if (validateScalar (anAlpha)) + { + //aMat.Aspect.SetTransparency (anAlpha); + } + } + else if (::memcmp (aLine, "map_Kd ", 7) == 0) + { + aPos += 7; + if (!objReadName (aPos, aMat.Texture)) + { + // + } + else + { + aMat.Texture = theFolder + aMat.Texture; + } + } + /*else if (::memcmp (aLine, "illum ", 6) == 0) + { + aPos += 6; + char* aNext = NULL; + const int aModel = strtol (aPos, &aNext, 10); + aPos = aNext; + if (aModel < 0 || aModel > 10) + { + // unknown model + } + }*/ + } + + if (!aMatName.IsEmpty()) + { + if (hasAspect) + { + aMat.Aspect.SetMaterialType (Graphic3d_MATERIAL_PHYSIC); + aMat.Aspect.SetMaterialName (aMatName.ToCString()); + } + else + { + // reset incomplete material definition + aMat.Aspect = Graphic3d_MaterialAspect(); + } + myMaterials->Bind (aMatName, aMat); + } + return myMaterials->Extent() != aNbMatOld; + } + +private: + + //! Validate scalar value + inline bool validateScalar (const Standard_Real theValue) + { + if (theValue < 0.0 + || theValue > 1.0) + { + Message::DefaultMessenger()->Send (TCollection_AsciiString("Invalid scalar in OBJ material at line ") + myNbLines + " in file " + myPath, Message_Warning); + return false; + } + return true; + } + + //! Validate RGB color + inline bool validateColor (const Graphic3d_Vec3& theVec) + { + if (theVec.r() < 0.0 || theVec.r() > 1.0 + || theVec.g() < 0.0 || theVec.g() > 1.0 + || theVec.b() < 0.0 || theVec.b() > 1.0) + { + Message::DefaultMessenger()->Send (TCollection_AsciiString("Invalid color in OBJ material at line ") + myNbLines + " in file " + myPath, Message_Warning); + return false; + } + return true; + } + +private: + + FILE* myFile; + TCollection_AsciiString myPath; + NCollection_DataMap* myMaterials; + Standard_Integer myNbLines; + +}; + +//================================================================ +// Function : Constructor +// Purpose : +//================================================================ +ObjDataSource::ObjDataSource() +{ + // +} + +//! Hasher for 3 ordered integers. +class ObjVec3iHasher +{ +public: + + static Standard_Integer HashCode (const Graphic3d_Vec3i& theKey, + const Standard_Integer theUpper) + { + return ::HashCode (::HashCodes ((Standard_CString )&theKey, sizeof(Graphic3d_Vec3i)), theUpper); + } + + static Standard_Boolean IsEqual (const Graphic3d_Vec3i& theKey1, + const Graphic3d_Vec3i& theKey2) + { + return theKey1[0] == theKey2[0] + && theKey1[1] == theKey2[1] + && theKey1[2] == theKey2[2]; + } + +}; + +//================================================================ +// Function : Read +// Purpose : +//================================================================ +Standard_Boolean ObjDataSource::Read (const TCollection_AsciiString& theFile, + const Handle(Message_ProgressIndicator)& theProgress, + const Standard_Integer /*theIndexLimit*/, + const Standard_Integer theMemLimitMiB) +{ + Clear(); + + Standard_CLocaleSentry aLocaleSentry; + FileSentry aFile (theFile); + if (aFile.File == NULL) + { + Message::DefaultMessenger()->Send (TCollection_AsciiString ("File '") + theFile + "' is not found!", Message_Fail); + return Standard_False; + } + + // determine file location to load associated files + TCollection_AsciiString aFolder; + { + OSD_Path aPath (theFile); + aPath.SetName (""); + aPath.SetExtension (""); + aPath.SystemName (aFolder); + } + + // determine length of file + ::fseek64 (aFile.File, 0, SEEK_END); + const int64_t aFileLen = ::ftell64 (aFile.File); + if (aFileLen <= 0L) + { + Message::DefaultMessenger()->Send (TCollection_AsciiString ("File '") + theFile + "' is empty!", Message_Fail); + return Standard_False; + } + ::fseek64 (aFile.File, 0, SEEK_SET); + + const Standard_Integer aNbMiBTotal = Standard_Integer(aFileLen / (1024 * 1024)); + Standard_Integer aNbMiBPassed = 0; + Message_ProgressSentry aPSentry (theProgress, "Reading text OBJ file", 0, aNbMiBTotal, 1); + OSD_Timer aTimer; + aTimer.Start(); + + // Each node in the Element specifies independent indices of Vertex position, Texture coordinates and Normal. + // This scheme does not match natural definition of Primitive Array where each unique set of nodal properties defines Vertex + // (thus node at the same location but with different normal should be duplicated). + // The following code converts OBJ definition of nodal properties to Primitive Array definition. + NCollection_Vector aVerts; + NCollection_Vector aVertParams; + NCollection_Vector aNorms; + NCollection_DataMap aPackedIndices; + NCollection_DataMap aMaterials; + TCollection_AsciiString anActiveMat; + MeshGroup aGroup; + + const size_t aMemLimitBytes = theMemLimitMiB == -1 + ? size_t(-1) + : (theMemLimitMiB * 1024 * 1024); + size_t aMemEstim = 0; + + char aLine[256] = {}; + Standard_Integer aNbLines = 0; + bool isStart = true; + for (; ::feof (aFile.File) == 0 && ::fgets (aLine, 255, aFile.File) != NULL; ) + { + ++aNbLines; + if (aTimer.ElapsedTime() > 1.0) + { + if (!aPSentry.More()) + { + return Standard_False; + } + + const Standard_Integer aNbMiBRead = Standard_Integer(::ftell64 (aFile.File) / (1024 * 1024)); + for (; aNbMiBPassed < aNbMiBRead; ++aNbMiBPassed) { aPSentry.Next(); } + aTimer.Reset(); + aTimer.Start(); + } + + const char* aPos = aLine; + if (*aLine == '#') + { + if (isStart) + { + TCollection_AsciiString aComment (aLine + 1); + aComment.LeftAdjust(); + aComment.RightAdjust(); + if (!aComment.IsEmpty()) + { + myComments.Append (aComment); + } + } + continue; + } + else if (*aLine == '\n' + || *aLine == '\0') + { + + continue; + } + isStart = false; + + if (::memcmp (aLine, "v ", 2) == 0) + { + aPos += 2; + char* aNext = NULL; + Graphic3d_Vec3 aVert; + objReadVec3 (aPos, aNext, aVert); + aPos = aNext; + + aMemEstim += sizeof(Graphic3d_Vec3); + if (aMemEstim >= aMemLimitBytes) + { + Message::DefaultMessenger()->Send (TCollection_AsciiString("OBJ file contains more than ") + myElements.Size() + " elements and " + aVerts.Size() + " vertices" + + "\nwhich does not fit into " + theMemLimitMiB + " MiB limit." + + "\nMesh data will be truncated!", Message_Fail); + return Standard_False; + } + + aVerts.Append (aVert); + } + else if (::memcmp (aLine, "vn ", 3) == 0) + { + aPos += 3; + char* aNext = NULL; + Graphic3d_Vec3 aNorm; + objReadVec3 (aPos, aNext, aNorm); + aPos = aNext; + + aMemEstim += sizeof(Graphic3d_Vec3); + if (aMemEstim >= aMemLimitBytes) + { + Message::DefaultMessenger()->Send (TCollection_AsciiString("OBJ file contains more than ") + myElements.Size() + " elements and " + aVerts.Size() + " vertices" + + "\nwhich does not fit into " + theMemLimitMiB + " MiB limit." + + "\nMesh data will be truncated!", Message_Fail); + return Standard_False; + } + + aNorms.Append (aNorm); + } + else if (::memcmp (aLine, "vt ", 3) == 0) + { + aPos += 3; + char* aNext = NULL; + Graphic3d_Vec2 anUV; + anUV.x() = (float )Strtod (aPos, &aNext); + aPos = aNext; + anUV.y() = (float )Strtod (aPos, &aNext); + aPos = aNext; + + aMemEstim += sizeof(Graphic3d_Vec2); + if (aMemEstim >= aMemLimitBytes) + { + Message::DefaultMessenger()->Send (TCollection_AsciiString("OBJ file contains more than ") + myElements.Size() + " elements and " + aVerts.Size() + " vertices" + + "\nwhich does not fit into " + theMemLimitMiB + " MiB limit." + + "\nMesh data will be truncated!", Message_Fail); + return Standard_False; + } + + aVertParams.Append (anUV); + } + else if (::memcmp (aLine, "f ", 2) == 0) + { + aPos += 2; + char* aNext = NULL; + + Graphic3d_Vec4i aTriNodes (-1, -1, -1, -1); + for (int aNode = 0; aNode < 4; ++aNode) + { + Graphic3d_Vec3i a3Indices (-1, -1, -1); + a3Indices[0] = strtol (aPos, &aNext, 10) - 1; + if (aNext == aPos) + { + continue; + } + + // parse UV index + aPos = aNext; + if (*aPos == '/') + { + ++aPos; + a3Indices[1] = strtol (aPos, &aNext, 10) - 1; + aPos = aNext; + + // parse Normal index + if (*aPos == '/') + { + ++aPos; + a3Indices[2] = strtol (aPos, &aNext, 10) - 1; + aPos = aNext; + } + } + if (*aPos != ' ' + && *aPos != '\n' + && *aPos != '\0') + { + ++aPos; + } + + // handle negative indices + if (a3Indices[0] < -1) + { + a3Indices[0] += aVerts.Upper() + 2; + } + if (a3Indices[1] < -1) + { + a3Indices[1] += aVertParams.Upper() + 2; + } + if (a3Indices[2] < -1) + { + a3Indices[2] += aNorms.Upper() + 2; + } + + Standard_Integer anIndex = -1; + if (!aPackedIndices.Find (a3Indices, anIndex)) + { + if (a3Indices[0] >= 0) + { + aMemEstim += sizeof(Graphic3d_Vec3); + } + if (a3Indices[1] >= 0) + { + aMemEstim += sizeof(Graphic3d_Vec2); + } + if (a3Indices[2] >= 0) + { + aMemEstim += sizeof(Graphic3d_Vec3); + } + aMemEstim += sizeof(Graphic3d_Vec4i) + sizeof(Standard_Integer); // naive map + if (aMemEstim >= aMemLimitBytes) + { + Message::DefaultMessenger()->Send (TCollection_AsciiString("OBJ file contains more than ") + myElements.Size() + " elements and " + aVerts.Size() + " vertices" + + "\nwhich does not fit into " + theMemLimitMiB + " MiB limit." + + "\nMesh data will be truncated!", Message_Fail); + return Standard_False; + } + + if (a3Indices[0] < aVerts.Lower() || a3Indices[0] > aVerts.Upper()) + { + Message::DefaultMessenger()->Send (TCollection_AsciiString("Invalid OBJ syntax at line ") + aNbLines, Message_Fail); + return Standard_False; + } + AddNodePosition (aVerts.Value (a3Indices[0])); + aGroup.NodeUpper = myNodes.Upper(); + if (aGroup.NodeLower < 0) + { + aGroup.NodeLower = aGroup.NodeUpper; + } + if (a3Indices[1] >= 0) + { + if (a3Indices[1] < aVertParams.Lower() || a3Indices[1] > aVertParams.Upper()) + { + Message::DefaultMessenger()->Send (TCollection_AsciiString("Invalid OBJ syntax at line ") + aNbLines, Message_Fail); + return Standard_False; + } + AddNodeUV (aVertParams.Value (a3Indices[1])); + } + if (a3Indices[2] >= 0) + { + if (a3Indices[2] < aNorms.Lower() || a3Indices[2] > aNorms.Upper()) + { + Message::DefaultMessenger()->Send (TCollection_AsciiString("Invalid OBJ syntax at line ") + aNbLines, Message_Fail); + return Standard_False; + } + AddNodeNormal (aNorms.Value (a3Indices[2])); + } + anIndex = myNodes.Upper(); + aPackedIndices.Bind (a3Indices, anIndex); + } + aTriNodes[aNode] = anIndex; + } + + if (aTriNodes[0] < 0 + || aTriNodes[1] < 0 + || aTriNodes[2] < 0) + { + continue; + } + + aMemEstim += sizeof(Graphic3d_Vec4i); + if (aMemEstim >= aMemLimitBytes) + { + Message::DefaultMessenger()->Send (TCollection_AsciiString("OBJ file contains more than ") + myElements.Size() + " elements and " + aVerts.Size() + " vertices" + + "\nwhich does not fit into " + theMemLimitMiB + " MiB limit." + + "\nMesh data will be truncated!", Message_Fail); + return Standard_False; + } + + AddElement (aTriNodes); + aGroup.ElemUpper = myElements.Upper(); + if (aGroup.ElemLower < 0) + { + aGroup.ElemLower = aGroup.ElemUpper; + if (!anActiveMat.IsEmpty()) + { + aMaterials.Find (anActiveMat, aGroup.Material); + } + } + } + else if (::memcmp (aLine, "g ", 2) == 0) + { + if (aGroup.ElemLower >= 0 + && aGroup.ElemLower != aGroup.ElemUpper) + { + myGroups.Append (aGroup); + aGroup = MeshGroup(); + aPackedIndices.Clear(); // vertices might be duplicated after this... + } + + TCollection_AsciiString aGroupName; + if (!objReadName (aPos + 2, aGroupName)) + { + Message::DefaultMessenger()->Send (TCollection_AsciiString("Invalid OBJ syntax at line ") + aNbLines, Message_Warning); + continue; + } + } + else if (::memcmp (aLine, "mtllib ", 7) == 0) + { + TCollection_AsciiString aMatPath; + if (!objReadName (aPos + 7, aMatPath)) + { + Message::DefaultMessenger()->Send (TCollection_AsciiString("Invalid OBJ syntax at line ") + aNbLines, Message_Warning); + continue; + } + + ObjMaterialReader aMatReader (aMaterials); + aMatReader.Read (aFolder, aMatPath); + } + else if (::memcmp (aLine, "usemtl ", 7) == 0) + { + TCollection_AsciiString aMatName; + if (!objReadName (aPos + 7, aMatName)) + { + Message::DefaultMessenger()->Send (TCollection_AsciiString("Invalid OBJ syntax at line ") + aNbLines, Message_Warning); + continue; + } + else if (!aMaterials.IsBound (aMatName)) + { + Message::DefaultMessenger()->Send (TCollection_AsciiString("Use of undefined OBJ material at line ") + aNbLines, Message_Warning); + continue; + } + + anActiveMat = aMatName; + } + } + + if (aGroup.ElemLower >= 0 + && aGroup.ElemLower != aGroup.ElemUpper) + { + myGroups.Append (aGroup); + } + + for (; aNbMiBPassed < aNbMiBTotal; ++aNbMiBPassed) { aPSentry.Next(); } + return Standard_True; +} diff --git a/src/MeshVS/ObjDataSource.h b/src/MeshVS/ObjDataSource.h new file mode 100644 index 0000000000..65da9a0491 --- /dev/null +++ b/src/MeshVS/ObjDataSource.h @@ -0,0 +1,43 @@ +// Copyright (c) 2015 OPEN CASCADE SAS +// +// This file is part of commercial software by OPEN CASCADE SAS. +// +// This software is furnished in accordance with the terms and conditions +// of the contract and with the inclusion of this copyright notice. +// This software or any other copy thereof may not be provided or otherwise +// be made available to any third party. +// No ownership title to the software is transferred hereby. +// +// OPEN CASCADE SAS makes no representation or warranties with respect to the +// performance of this software, and specifically disclaims any responsibility +// for any damages, special or consequential, connected with its use. + +#ifndef ObjDataSource_H +#define ObjDataSource_H + +#include + +//! The DataSource for working with OBJ mesh reader. +class ObjDataSource : public MeshDataSource +{ + +public: + + //! Empty constructor. + Standard_EXPORT ObjDataSource(); + + //! Read the mesh from specified file. + Standard_EXPORT virtual Standard_Boolean Read (const TCollection_AsciiString& theFile, + const Handle(Message_ProgressIndicator)& theProgress, + const Standard_Integer theIndexLimit, + const Standard_Integer theMemoryLimitMiB) Standard_OVERRIDE; + +public: + + DEFINE_STANDARD_RTTIEXT(ObjDataSource, MeshDataSource) + +}; + +DEFINE_STANDARD_HANDLE(ObjDataSource, MeshDataSource) + +#endif // ObjDataSource_H diff --git a/src/MeshVS/ObjDataWriter.cpp b/src/MeshVS/ObjDataWriter.cpp new file mode 100644 index 0000000000..6b40b637d3 --- /dev/null +++ b/src/MeshVS/ObjDataWriter.cpp @@ -0,0 +1,354 @@ +// Copyright (c) 2015 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 + +IMPLEMENT_STANDARD_RTTIEXT(ObjDataWriter, Standard_Transient) + +//! Auxiliary class to write OBJ. +class ObjWriter +{ + +public: + + //! Main constructor. + ObjWriter (const TCollection_AsciiString& theName, + const Standard_Boolean theHasNormals) + : myFile (OSD_OpenFile (theName.ToCString(), "wb")), + myName (theName), + myHasNormals (theHasNormals == Standard_True) + { + if (myFile == NULL) + { + Message::DefaultMessenger()->Send (TCollection_AsciiString ("File can not be created!\n") + theName, Message_Fail); + return; + } + } + + //! Destructor, will emit error message if file was not closed. + ~ObjWriter() + { + if (myFile != NULL) + { + ::fclose (myFile); + Message::DefaultMessenger()->Send (TCollection_AsciiString ("File can not be written!\n") + myName, Message_Fail); + } + } + + //! Return true if file has been opened. + bool IsOpened() const { return myFile != NULL; } + + //! Correctly close the file. + void Close() + { + ::fclose (myFile); + myFile = NULL; + } + + //! Write the header. + bool WriteHeader (const Standard_Integer theNbNodes, + const Standard_Integer theNbElems) + { + return ::Fprintf (myFile, "# Exported by OpenCASCADE CAD Assistant [www.opencascade.com]\n" + "# Vertices: %d\n" + "# Faces: %d\n", theNbNodes, theNbElems) != 0; + } + + //! Writing a triangle + bool WriteTriangle (const Graphic3d_Vec4i& theTri) + { + if (myHasNormals) + { + return Fprintf (myFile, "f %d//%d %d//%d %d//%d\n", + theTri[0] + 1, theTri[0] + 1, + theTri[1] + 1, theTri[1] + 1, + theTri[2] + 1, theTri[2] + 1) != 0; + } + return Fprintf (myFile, "f %d %d %d\n", + theTri[0] + 1, + theTri[1] + 1, + theTri[2] + 1) != 0; + } + + //! Writing a quad + bool WriteQuad (const Graphic3d_Vec4i& theQuad) + { + if (myHasNormals) + { + return Fprintf (myFile, "f %d//%d %d//%d %d//%d %d//%d\n", + theQuad[0] + 1, theQuad[0] + 1, + theQuad[1] + 1, theQuad[1] + 1, + theQuad[2] + 1, theQuad[2] + 1, + theQuad[3] + 1, theQuad[3] + 1) != 0; + } + return Fprintf (myFile, "f %d %d %d %d\n", + theQuad[0] + 1, + theQuad[1] + 1, + theQuad[2] + 1, + theQuad[3] + 1) != 0; + } + + //! Writing a vector + bool WriteVertex (const Graphic3d_Vec3& theValue) + { + return Fprintf (myFile, "v %f %f %f\n", theValue.x(), theValue.y(), theValue.z()) != 0; + } + + //! Writing a vector + bool WriteNormal (const Graphic3d_Vec3& theValue) + { + return Fprintf (myFile, "vn %f %f %f\n", theValue.x(), theValue.y(), theValue.z()) != 0; + } + + //! Writing a group name + bool WriteGroup (const TCollection_AsciiString& theValue) + { + return Fprintf (myFile, "g %s\n", theValue.ToCString()) != 0; + } + +private: + + FILE* myFile; + TCollection_AsciiString myName; + bool myHasNormals; + bool myIsOpened; + +}; + +//================================================================ +// Function : Constructor +// Purpose : +//================================================================ +ObjDataWriter::ObjDataWriter() +{ + // +} + +//================================================================ +// Function : Write +// Purpose : +//================================================================ +Standard_Boolean ObjDataWriter::Write (const Handle(MeshDataSource)& theDataSrc, + const TCollection_AsciiString& theFile, + const Handle(Message_ProgressIndicator)& /*theProgress*/) +{ + if (theDataSrc.IsNull()) + { + return Standard_False; + } + + // header + /*NCollection_IndexedMap aComments; + for (NCollection_Sequence::Iterator aCommentIter (theDataSrc->FileComments()); aCommentIter.More(); aCommentIter.Next()) + { + aComments.Add (aCommentIter.Value()); + } + aComments.Add ("Exported by OpenCASCADE CAD Assistant [www.opencascade.com]");*/ + + Standard_CLocaleSentry aLocaleSentry; + ObjWriter anObjFile (theFile, theDataSrc->HasNormals()); + if (!anObjFile.IsOpened() + || !anObjFile.WriteHeader (theDataSrc->NbNodes(), theDataSrc->NbElements())) + { + return Standard_False; + } + + for (Standard_Integer aNodeIter = 0; aNodeIter < theDataSrc->NbNodes(); ++aNodeIter) + { + const Graphic3d_Vec3& aNode = theDataSrc->Nodes().Value (aNodeIter); + if (!anObjFile.WriteVertex (aNode)) + { + return Standard_False; + } + } + if (theDataSrc->HasNormals()) + { + for (Standard_Integer aNodeIter = 0; aNodeIter < theDataSrc->NbNodes(); ++aNodeIter) + { + const Graphic3d_Vec3& aNormal = theDataSrc->Normals().Value (aNodeIter); + if (!anObjFile.WriteNormal (aNormal)) + { + return Standard_False; + } + } + } + + for (Standard_Integer anElemIter = 0; anElemIter < theDataSrc->NbElements(); ++anElemIter) + { + const Graphic3d_Vec4i& anElem = theDataSrc->Elements().Value (anElemIter); + if (anElem[3] == -1) + { + if (!anObjFile.WriteTriangle (anElem)) + { + return Standard_False; + } + } + else + { + if (!anObjFile.WriteQuad (anElem)) + { + return Standard_False; + } + } + } + + anObjFile.Close(); + return Standard_True; +} + +//! Trivial convertor +inline Graphic3d_Vec3 objXyzToVec (const gp_XYZ& thePnt) +{ + return Graphic3d_Vec3 ((float )thePnt.X(), (float )thePnt.Y(), (float )thePnt.Z()); +} + +//================================================================ +// Function : Write +// Purpose : +//================================================================ +Standard_Boolean ObjDataWriter::Write (const AIS_ListOfInteractive& thePrsList, + const TCollection_AsciiString& theFile, + const Handle(Message_ProgressIndicator)& /*theProgress*/) +{ + if (thePrsList.IsEmpty()) + { + return Standard_False; + } + + Standard_Integer aNbNodesAll = 0; + Standard_Integer aNbElemsAll = 0; + for (FaceIterator aFaceIter (thePrsList); aFaceIter.More(); aFaceIter.Next()) + { + aNbNodesAll += aFaceIter.Triangulation->Nodes().Length(); + aNbElemsAll += aFaceIter.Triangulation->Triangles().Length(); + } + + if (aNbNodesAll == 0 + || aNbElemsAll == 0) + { + Message::DefaultMessenger()->Send (TCollection_AsciiString ("No mesh data to save!\n"), Message_Fail); + return Standard_False; + } + + Standard_CLocaleSentry aLocaleSentry; + ObjWriter anObjFile (theFile, Standard_True); + if (!anObjFile.IsOpened() + || !anObjFile.WriteHeader (aNbNodesAll, aNbElemsAll)) + { + return Standard_False; + } + + // write vertices + BRepAdaptor_Surface aFaceAdaptor; + BRepLProp_SLProps aSLTool (1, 1e-12); + gp_Dir aNormal; + Standard_Integer aFirstNode = 0; + Graphic3d_Vec4i aTriNodes (-1, -1, -1, -1); + Standard_Integer aNbFaces = 0; + TCollection_AsciiString aPrevGroup; + for (FaceIterator aFaceIter (thePrsList); aFaceIter.More(); aFaceIter.Next()) + { + ++aNbFaces; + const Standard_Integer aLower = aFaceIter.Triangulation->Triangles().Lower(); + const Standard_Boolean isMirrored = aFaceIter.Trsf.VectorialPart().Determinant() < 0.0; + const Handle(Poly_Triangulation)& aTriangulation = aFaceIter.Triangulation; + + TCollection_AsciiString aRefName; + Handle(TDataStd_Name) aNodeName; + if (aFaceIter.ShapePrs->GetLabel().FindAttribute (TDataStd_Name::GetID(), aNodeName)) + { + aRefName = TCollection_AsciiString (aNodeName->Get()); + } + if (!aRefName.IsEmpty() + && !aRefName.IsEqual (aPrevGroup) + && !anObjFile.WriteGroup (aRefName)) + { + return Standard_False; + } + + // write nodes + const TColgp_Array1OfPnt& aNodes = aTriangulation->Nodes(); + const gp_Trsf aTrsf = aFaceIter.Trsf; + for (Standard_Integer aNodeIter = aNodes.Lower(); aNodeIter <= aNodes.Upper(); ++aNodeIter) + { + gp_Pnt aNode = aNodes (aNodeIter); + aNode.Transform (aTrsf); + if (!anObjFile.WriteVertex (objXyzToVec (aNode.XYZ()))) + { + return Standard_False; + } + } + + // write normals + TopoDS_Face aFace = TopoDS::Face (aFaceIter.Face.Oriented (TopAbs_FORWARD)); + aFace.Location (TopLoc_Location()); + aFaceAdaptor.Initialize (aFace, Standard_False); + aSLTool.SetSurface (aFaceAdaptor); + const TColgp_Array1OfPnt2d& aNodeUVs = aTriangulation->UVNodes(); + for (Standard_Integer aNodeIter = aNodes.Lower(); aNodeIter <= aNodes.Upper(); ++aNodeIter) + { + const gp_XY& anUV = aNodeUVs.Value (aNodeIter).XY(); + aSLTool.SetParameters (anUV.X(), anUV.Y()); + gp_Dir aNormal ((aSLTool.IsNormalDefined() ? aSLTool.Normal() : gp::DZ()).XYZ()); + aNormal.Transform (aTrsf); + if (aFaceIter.Face.Orientation() == TopAbs_REVERSED) + { + aNormal.Reverse(); + } + if (!anObjFile.WriteNormal (objXyzToVec (aNormal.XYZ()))) + { + return Standard_False; + } + } + + // write indices + for (Poly_Array1OfTriangle::Iterator anElemIter (aFaceIter.Triangulation->Triangles()); anElemIter.More(); anElemIter.Next()) + { + if ((aFaceIter.Face.Orientation() == TopAbs_REVERSED) ^ isMirrored) + { + anElemIter.Value().Get (aTriNodes[0], aTriNodes[2], aTriNodes[1]); + } + else + { + anElemIter.Value().Get (aTriNodes[0], aTriNodes[1], aTriNodes[2]); + } + aTriNodes[0] = aFirstNode + aTriNodes[0] - aLower; + aTriNodes[1] = aFirstNode + aTriNodes[1] - aLower; + aTriNodes[2] = aFirstNode + aTriNodes[2] - aLower; + if (!anObjFile.WriteTriangle (aTriNodes)) + { + return Standard_False; + } + } + aFirstNode += aFaceIter.Triangulation->NbNodes(); + } + + anObjFile.Close(); + return Standard_True; +} diff --git a/src/MeshVS/ObjDataWriter.h b/src/MeshVS/ObjDataWriter.h new file mode 100644 index 0000000000..6e19830cb7 --- /dev/null +++ b/src/MeshVS/ObjDataWriter.h @@ -0,0 +1,49 @@ +// Copyright (c) 2015 OPEN CASCADE SAS +// +// This file is part of commercial software by OPEN CASCADE SAS. +// +// This software is furnished in accordance with the terms and conditions +// of the contract and with the inclusion of this copyright notice. +// This software or any other copy thereof may not be provided or otherwise +// be made available to any third party. +// No ownership title to the software is transferred hereby. +// +// OPEN CASCADE SAS makes no representation or warranties with respect to the +// performance of this software, and specifically disclaims any responsibility +// for any damages, special or consequential, connected with its use. + +#ifndef ObjDataWriter_H +#define ObjDataWriter_H + +#include + +#include + +//! Mesh writer to the OBJ format. +class ObjDataWriter : public Standard_Transient +{ + +public: + + //! Empty constructor. + Standard_EXPORT ObjDataWriter(); + + //! Write the mesh into specified file. + Standard_EXPORT Standard_Boolean Write (const Handle(MeshDataSource)& theDataSrc, + const TCollection_AsciiString& theFile, + const Handle(Message_ProgressIndicator)& theProgress); + + //! Write the mesh presentation of the model into specified file. + Standard_EXPORT Standard_Boolean Write (const AIS_ListOfInteractive& thePrsList, + const TCollection_AsciiString& theFile, + const Handle(Message_ProgressIndicator)& theProgress); + +public: + + DEFINE_STANDARD_RTTIEXT(ObjDataWriter, Standard_Transient) + +}; + +DEFINE_STANDARD_HANDLE(ObjDataWriter, Standard_Transient) + +#endif // ObjDataWriter_H diff --git a/src/TKMeshVS/EXTERNLIB b/src/TKMeshVS/EXTERNLIB index c9eebc5d24..c903445c7a 100644 --- a/src/TKMeshVS/EXTERNLIB +++ b/src/TKMeshVS/EXTERNLIB @@ -4,3 +4,5 @@ TKService TKernel TKG3d TKG2d +TKXCAF +TKLCAF \ No newline at end of file diff --git a/src/TKViewerTest/EXTERNLIB b/src/TKViewerTest/EXTERNLIB index 9181318b93..be30a30576 100755 --- a/src/TKViewerTest/EXTERNLIB +++ b/src/TKViewerTest/EXTERNLIB @@ -1,4 +1,6 @@ TKGeomBase +TKXCAF +TKLCAF TKFillet TKBRep TKTopAlgo @@ -15,6 +17,7 @@ TKTopTest TKG3d TKOffset TKMesh +TKMeshVS TKV3d TKDraw TKOpenGl diff --git a/src/ViewerTest/ViewerTest.cxx b/src/ViewerTest/ViewerTest.cxx index 9de0d1464d..ddcf3cedea 100644 --- a/src/ViewerTest/ViewerTest.cxx +++ b/src/ViewerTest/ViewerTest.cxx @@ -5386,6 +5386,283 @@ static int VAutoActivateSelection (Draw_Interpretor& theDi, return 0; } +#include +#include +#include +#include +#include +#include +#include +#include +namespace +{ + std::vector Split (const TCollection_AsciiString& pSource, + const TCollection_AsciiString& pSeparator) + { + std::vector result; + + TCollection_AsciiString token; + const Standard_Integer aSize = pSource.Length(); + unsigned int previousPos = 1; + unsigned int currentPos = 1; + while ((currentPos = pSource.FirstLocationInSet(pSeparator, currentPos, aSize)) != 0) + { + result.push_back(pSource.SubString(previousPos, currentPos - previousPos)); + + previousPos = ++currentPos; + } + + // Save last element. + result.push_back(pSource.SubString(previousPos, aSize)); + + return result; + } + + //! Returns true for grayscale properties. + inline bool isGrayscaleProperty (const TCollection_AsciiString& theName) + { + return theName == "intensity"; + } + + Handle(MeshPresentation) createMeshPresentation (const Handle(MeshDataSource)& theDataSource, + const TCollection_AsciiString& theEntry, + TCollection_AsciiString& theSelEntry, + Handle(MeshScalarProperty)& theSelProperty) + { + theSelEntry.Clear(); + theSelProperty.Nullify(); + if (theDataSource.IsNull()) + { + return Handle(MeshPresentation)(); + } + + theSelEntry = theEntry; + if (theEntry.IsEmpty()) + { + if (theDataSource->HasTexture()) + { + theSelEntry = "ply_textured"; + } + else if (theDataSource->HasNodalColors()) + { + theSelEntry = "ply_colored"; + } + /*else if (theDataSource->HasNormals()) + { + theSelEntry = "ply_smoothshaded"; + }*/ + else + { + theSelEntry = "ply_smoothshaded"; + //theSelEntry = "ply_shaded"; + } + } + + std::cout << theSelEntry << std::endl; + + Handle(MeshPresentation) aMesh = new MeshPresentation(); + Handle(MeshVS_Drawer) aDrawer = aMesh->GetDrawer(); + aDrawer->SetBoolean(MeshVS_DA_ShowEdges, Standard_False); + aDrawer->SetBoolean(MeshVS_DA_SmoothShading, theDataSource->HasNormals()); + aMesh->SetDataSource(theDataSource); + aMesh->SetMaterial(Graphic3d_NOM_PLASTIC); // myMatAspect + if (theSelEntry == "ply_textured") + { + //myPrsCaps |= DisplayCaps_Texture; + aDrawer->SetBoolean(MeshVS_DA_SmoothShading, Standard_True); + aDrawer->SetColor(MeshVS_DA_InteriorColor, Quantity_NOC_GRAY65); + Handle(MeshPrsBuilder) aBuilder = new MeshPrsBuilder(aMesh, MeshVS_DMF_Shading); + aBuilder->SetMapTextures(Standard_True); + aMesh->AddBuilder(aBuilder, Standard_True); + aMesh->SetDisplayMode(MeshVS_DMF_Shading); + } + else if (theSelEntry == "ply_colored") + { + //myPrsCaps |= DisplayCaps_VertColor; + aDrawer->SetBoolean(MeshVS_DA_ColorReflection, Standard_True); + + Handle(MeshVS_NodalColorPrsBuilder) aBuilder = new MeshVS_NodalColorPrsBuilder(aMesh, MeshVS_DMF_NodalColorDataPrs); + theDataSource->FillNodalColorsBuilder(aBuilder); + aMesh->AddBuilder(aBuilder, Standard_True); + aMesh->SetDisplayMode(MeshVS_DMF_NodalColorDataPrs); + } + else if (theSelEntry == "ply_wireframe") + { + aMesh->AddBuilder(new MeshVS_MeshPrsBuilder(aMesh.operator->()), Standard_True); + aMesh->SetDisplayMode(MeshVS_DMF_WireFrame); + } + else if (theSelEntry == "ply_smoothshaded") + { + aDrawer->SetBoolean(MeshVS_DA_SmoothShading, Standard_True); + aDrawer->SetColor(MeshVS_DA_InteriorColor, Quantity_NOC_GRAY65); + Handle(MeshPrsBuilder) aBuilder = new MeshPrsBuilder(aMesh, MeshVS_DMF_Shading); + aBuilder->SetMapTextures(Standard_False); + aMesh->AddBuilder(aBuilder, Standard_True); + aMesh->SetDisplayMode(MeshVS_DMF_Shading); + } + else if (theSelEntry == "ply_shaded") + { + aDrawer->SetColor(MeshVS_DA_InteriorColor, Quantity_NOC_GRAY65); + aDrawer->SetBoolean(MeshVS_DA_SmoothShading, Standard_False); + aMesh->AddBuilder(new MeshVS_MeshPrsBuilder(aMesh.operator->()), Standard_True); + aMesh->SetDisplayMode(MeshVS_DMF_Shading); + } + else if (theSelEntry == "ply_shrink") + { + aDrawer->SetColor(MeshVS_DA_InteriorColor, Quantity_NOC_GRAY65); + aMesh->AddBuilder(new MeshVS_MeshPrsBuilder(aMesh.operator->()), Standard_True); + aMesh->SetDisplayMode(MeshVS_DMF_Shrink); + } + //else if (theSelEntry.startsWith("ply_group_nodalprops\n")) + else if (theSelEntry.Search("ply_group_nodalprops\n") != -1) + { + //myPrsCaps |= DisplayCaps_Texture; + std::vector aList = Split(theEntry, "\n"); + const int aPropIndex = aList.size() != 2 ? 0 : aList.back().IntegerValue(); + + theSelProperty = theDataSource->NodalQuantities().Value(aPropIndex); + const Standard_Boolean isGrayscale = isGrayscaleProperty(theSelProperty->Name()); + const Standard_Integer aMeshEdgesLimit = 100000; + if (!isGrayscale + && (aMeshEdgesLimit < 0 || theDataSource->NbNodes() <= aMeshEdgesLimit)) + { + aDrawer->SetBoolean(MeshVS_DA_ShowEdges, Standard_True); + } + aDrawer->SetBoolean(MeshVS_DA_ColorReflection, Standard_True); + + Handle(MeshPrsBuilder) aBuilder = new MeshPrsBuilder(aMesh, MeshVS_DMF_NodalColorDataPrs); + aBuilder->SetProperty(theSelProperty, Standard_False); + aBuilder->SetGrayscale(isGrayscale); + + aMesh->AddBuilder(aBuilder, Standard_True); + aMesh->SetDisplayMode(MeshVS_DMF_NodalColorDataPrs); + } + //else if (theSelEntry.startsWith("ply_group_elemprops\n")) + else if (theSelEntry.Search("ply_group_elemprops\n") != -1) + { + //myPrsCaps |= DisplayCaps_Texture; + std::vector aList = Split(theEntry, "\n"); + const int aPropIndex = aList.size() != 2 ? 0 : aList.back().IntegerValue(); + + aDrawer->SetBoolean(MeshVS_DA_ColorReflection, Standard_True); + + theSelProperty = theDataSource->ElementalQuantities().Value(aPropIndex); + + Handle(MeshPrsBuilder) aBuilder = new MeshPrsBuilder(aMesh, MeshVS_DMF_ElementalColorDataPrs); + aBuilder->SetProperty(theSelProperty, Standard_True); + aBuilder->SetGrayscale(isGrayscaleProperty(theSelProperty->Name())); + + aMesh->AddBuilder(aBuilder, Standard_True); + aMesh->SetDisplayMode(MeshVS_DMF_ElementalColorDataPrs); + } + + return aMesh; + } +} + +// ============================================================================= +// function : VDisplayObj +// purpose : +// ============================================================================= +static int VDisplayObj (Draw_Interpretor& theDi, + Standard_Integer theArgNb, + const char** theArgVec) +{ + if (theArgNb < 3) + { + theDi << theArgVec[0] << "Error: wrong number of arguments.\n"; + return 1; + } + + const TCollection_AsciiString aName (theArgVec[1]); + const TCollection_AsciiString aPath (theArgVec[2]); + + if (GetMapOfAIS().IsBound2(aName)) + { + theDi << aName << "already exist.\n"; + return 1; + } + + Handle(ObjDataSource) aLoader = new ObjDataSource(); + + Standard_Boolean aResult = aLoader->Read (aPath, NULL, -1, -1); + + if (!aResult) + { + theDi << "Error: can't read a file: '" << aPath.ToCString() << "'\n"; + return 1; + } + + /*const NCollection_Vector& aGroups = aLoader->Groups(); + for (auto anIter = aGroups.cbegin(); anIter != aGroups.cend(); ++anIter) + { + const Quantity_Color& aDiffuseColor = anIter->Material.Aspect.DiffuseColor(); + const Graphic3d_BSDF& aBSDF = anIter->Material.Aspect.BSDF(); + + std::cout << anIter->Material.Texture << std::endl; + std::cout << aDiffuseColor.Red() << ", " << aDiffuseColor.Green() << ", " << aDiffuseColor.Green() << std::endl; + std::cout << aBSDF.Kd.x() << ", " << aBSDF.Kd.y() << ", " << aBSDF.Kd.z() << std::endl << std::endl; + }*/ + + Handle(MeshScalarProperty) aProperty; + TCollection_AsciiString aSelEntry; + Handle(MeshVS_Mesh) aMesh = createMeshPresentation(aLoader, "", aSelEntry, aProperty); + + ViewerTest::Display(aName, aMesh, Standard_False); + + return 0; +} + +#include +#include +// ============================================================================= +// function : VSaveObj +// purpose : +// ============================================================================= +static int VSaveObj (Draw_Interpretor& theDi, + Standard_Integer theArgNb, + const char** theArgVec) +{ + if (theArgNb < 3) + { + theDi << theArgVec[0] << "Error: wrong number of arguments.\n"; + return 1; + } + + const TCollection_AsciiString aPath (theArgVec[1]); + AIS_ListOfInteractive aList; + Handle(ObjDataWriter) aWriter = new ObjDataWriter(); + + for (Standard_Integer anIter = 2; anIter < theArgNb; ++anIter) + { + TCollection_AsciiString aName (theArgVec[anIter]); + + if (!GetMapOfAIS().IsBound2(aName)) + { + theDi << aName << "is not exist.\n"; + continue; + } + + Handle(AIS_InteractiveObject) anObject = Handle(AIS_InteractiveObject)::DownCast(GetMapOfAIS().Find2(aName)); + if (anObject.IsNull()) + { + theDi << aName << "is not an interactive object.\n"; + continue; + } + + /*Handle(MeshVS_Mesh) aMesh = Handle(MeshVS_Mesh)::DownCast(anObject); + if (!aMesh.IsNull()) + { + aWriter->Write (aMesh->GetDataSource(), aPath, NULL); + }*/ + + aList.Append(anObject); + } + aWriter->Write (aList, aPath, NULL); + + return 0; +} + //============================================================================== //function : ViewerTest::Commands //purpose : Add all the viewer command in the Draw_Interpretor @@ -5435,6 +5712,14 @@ void ViewerTest::Commands(Draw_Interpretor& theCommands) "\n\t\t: -redisplay recomputes presentation of objects.", __FILE__, VDisplay2, group); + theCommands.Add("vdisplayobj", + "vdisplayobj name path", + __FILE__, VDisplayObj, group); + + theCommands.Add("vsaveobj", + "vsaveobj file names", + __FILE__, VSaveObj, group); + theCommands.Add ("vupdate", "vupdate name1 [name2] ... [name n]" "\n\t\t: Updates named objects in interactive context", -- 2.39.5