]> OCCT Git - occt-copy.git/commitdiff
Add loader *.obj files.
authorisk <isk@opencascade.com>
Sat, 20 Feb 2016 05:17:21 +0000 (08:17 +0300)
committerisk <isk@opencascade.com>
Fri, 18 Mar 2016 09:45:05 +0000 (12:45 +0300)
20 files changed:
samples/tcl/video.tcl [new file with mode: 0644]
src/MeshVS/CafShapePrs.cpp [new file with mode: 0644]
src/MeshVS/CafShapePrs.h [new file with mode: 0644]
src/MeshVS/FILES
src/MeshVS/FaceIterator.cpp [new file with mode: 0644]
src/MeshVS/FaceIterator.h [new file with mode: 0644]
src/MeshVS/MeshDataSource.cpp [new file with mode: 0644]
src/MeshVS/MeshDataSource.h [new file with mode: 0644]
src/MeshVS/MeshPresentation.cpp [new file with mode: 0644]
src/MeshVS/MeshPresentation.h [new file with mode: 0644]
src/MeshVS/MeshPrsBuilder.cpp [new file with mode: 0644]
src/MeshVS/MeshPrsBuilder.h [new file with mode: 0644]
src/MeshVS/MeshScalarProperty.h [new file with mode: 0644]
src/MeshVS/ObjDataSource.cpp [new file with mode: 0644]
src/MeshVS/ObjDataSource.h [new file with mode: 0644]
src/MeshVS/ObjDataWriter.cpp [new file with mode: 0644]
src/MeshVS/ObjDataWriter.h [new file with mode: 0644]
src/TKMeshVS/EXTERNLIB
src/TKViewerTest/EXTERNLIB
src/ViewerTest/ViewerTest.cxx

diff --git a/samples/tcl/video.tcl b/samples/tcl/video.tcl
new file mode 100644 (file)
index 0000000..a503fe3
--- /dev/null
@@ -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 (file)
index 0000000..fe87b36
--- /dev/null
@@ -0,0 +1,16 @@
+#include <CafShapePrs.h>
+
+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 (file)
index 0000000..79bab90
--- /dev/null
@@ -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 <XCAFPrs_AISObject.hxx>
+#include <XCAFPrs_Style.hxx>
+
+typedef NCollection_DataMap<TopoDS_Shape, Handle(AIS_ColoredDrawer), TopTools_ShapeMapHasher> 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
index 40672f91fb3eda405c13d0af3269c9977577e94a..14720cb01e413d0a9952d9d7449d047530a07a5f 100755 (executable)
@@ -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 (file)
index 0000000..4cc10e7
--- /dev/null
@@ -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 <FaceIterator.h>
+
+#include <AIS_ColoredShape.hxx>
+#include <AIS_ConnectedInteractive.hxx>
+#include <BRepAdaptor_Surface.hxx>
+#include <BRepLProp_SLProps.hxx>
+#include <BRep_Tool.hxx>
+#include <CafShapePrs.h>
+#include <Poly_Array1OfTriangle.hxx>
+#include <Poly_Triangulation.hxx>
+#include <TopExp.hxx>
+#include <TopExp_Explorer.hxx>
+#include <TopoDS.hxx>
+
+// =======================================================================
+// 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 (file)
index 0000000..d2190d1
--- /dev/null
@@ -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 <AIS_ListOfInteractive.hxx>
+#include <gp_Trsf.hxx>
+#include <TopoDS_Face.hxx>
+#include <TopLoc_Location.hxx>
+#include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
+
+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 (file)
index 0000000..b58f595
--- /dev/null
@@ -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 <MeshDataSource.h>
+
+#include <Standard_CLocaleSentry.hxx>
+#include <MeshVS_Drawer.hxx>
+#include <MeshVS_DrawerAttribute.hxx>
+#include <Message.hxx>
+#include <Message_Messenger.hxx> 
+#include <Message_ProgressSentry.hxx> 
+#include <NCollection_Handle.hxx>
+#include <TColgp_SequenceOfXYZ.hxx>
+#include <TColStd_DataMapOfIntegerReal.hxx>
+#include <TColStd_DataMapOfIntegerInteger.hxx>
+#include <TColStd_Array1OfInteger.hxx>
+#include <TColStd_Array1OfReal.hxx>
+#include <TColStd_MapIteratorOfPackedMapOfInteger.hxx>
+#include <TCollection_ExtendedString.hxx>
+#include <Quantity_Color.hxx>
+
+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<Graphic3d_Vec4i>::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 (file)
index 0000000..ef9372b
--- /dev/null
@@ -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 <MeshScalarProperty.h>
+
+#include <MeshVS_DataSource.hxx>
+#include <MeshVS_EntityType.hxx>
+#include <MeshVS_ElementalColorPrsBuilder.hxx>
+#include <MeshVS_NodalColorPrsBuilder.hxx>
+#include <MeshVS_PrsBuilder.hxx>
+#include <Message_ProgressIndicator.hxx>
+#include <NCollection_DataMap.hxx>
+#include <TColStd_HArray2OfInteger.hxx>
+#include <TColStd_HArray2OfReal.hxx>
+
+#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<TCollection_AsciiString>& FileComments() const
+  {
+    return myComments;
+  }
+
+  //! Return list of sub-groups with materials.
+  const NCollection_Vector<MeshGroup>& Groups() { return myGroups; }
+
+  //! Return overall nodes number.
+  Standard_Integer NbNodes()    const { return myNodes.Length(); }
+
+  //! Return vector of nodes.
+  const NCollection_Vector<Graphic3d_Vec3>& 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<Graphic3d_Vec4i>& 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<Graphic3d_Vec4ub>& 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<Graphic3d_Vec3>& 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<Graphic3d_Vec2>& 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<TCollection_AsciiString>
+                                       myComments;            //!< file comments
+  NCollection_Vector<Graphic3d_Vec3>   myNodes;               //!< vector of nodes
+  NCollection_Vector<Graphic3d_Vec3>   myNormals;             //!< vector of nodal normals (optional)
+  NCollection_Vector<Graphic3d_Vec2>   myNodesUV;             //!< vector of UV nodes (optional)
+  NCollection_Vector<Graphic3d_Vec4ub> myNodalColors;         //!< vector of nodal colors  (optional)
+  NCollection_Vector<Graphic3d_Vec4i>  myElements;            //!< vector of elements
+  MeshScalarProperties                 myNodalQuantities;     //!< per-node    scalar quantities
+  MeshScalarProperties                 myElementalQuantities; //!< per-element scalar quantities
+
+  NCollection_Vector<MeshGroup>        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 (file)
index 0000000..ff6d0f3
--- /dev/null
@@ -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 <MeshVS_Drawer.hxx>
+#include <MeshVS_DrawerAttribute.hxx>
+#include <MeshVS_Tool.hxx>
+
+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 (file)
index 0000000..06cbec2
--- /dev/null
@@ -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 <MeshVS_Mesh.hxx>
+
+//! 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 (file)
index 0000000..5c575d1
--- /dev/null
@@ -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 <TargetConditionals.h>
+#endif
+
+#include "MeshPrsBuilder.h"
+
+#include <Aspect_TypeOfLine.hxx>
+#include <MeshVS_Buffer.hxx>
+#include <MeshVS_DataSource.hxx>
+#include <MeshVS_Drawer.hxx>
+#include <MeshVS_DrawerAttribute.hxx>
+#include <MeshVS_EntityType.hxx>
+#include <MeshVS_Mesh.hxx>
+#include <MeshVS_Tool.hxx>
+#include <Message.hxx>
+#include <Message_Messenger.hxx>
+#include <Graphic3d_ArrayOfTriangles.hxx>
+#include <Graphic3d_ArrayOfSegments.hxx>
+#include <Graphic3d_AspectFillArea3d.hxx>
+#include <Graphic3d_AspectLine3d.hxx>
+#include <Graphic3d_Texture2Dmanual.hxx>
+#include <Image_PixMap.hxx>
+#include <Prs3d_Drawer.hxx>
+#include <Prs3d_ShadingAspect.hxx>
+#include <TColStd_Array1OfInteger.hxx>
+#include <TColStd_HArray1OfReal.hxx>
+#include <TColStd_HPackedMapOfInteger.hxx>
+#include <TColStd_MapIteratorOfPackedMapOfInteger.hxx>
+
+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<Image_ColorRGBA> (0, aColIter);
+    Image_ColorRGBA& aColor1 = anImage->ChangeValue<Image_ColorRGBA> (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 (file)
index 0000000..80430d3
--- /dev/null
@@ -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 <MeshVS_PrsBuilder.hxx>
+#include <Graphic3d_Texture2D.hxx>
+#include <Graphic3d_TextureParams.hxx>
+
+//! 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 (file)
index 0000000..604f9fd
--- /dev/null
@@ -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 <gp_XYZ.hxx>
+#include <Graphic3d_Vec.hxx>
+#include <NCollection_Vector.hxx>
+#include <NCollection_Sequence.hxx>
+#include <Precision.hxx>
+#include <TCollection_AsciiString.hxx>
+
+//! 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<Standard_Real> myValues;     //!< property values
+  NCollection_Vector<float>         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<Handle(MeshScalarProperty)> MeshScalarProperties;
+
+#endif // MeshScalarProperty_H
diff --git a/src/MeshVS/ObjDataSource.cpp b/src/MeshVS/ObjDataSource.cpp
new file mode 100644 (file)
index 0000000..edb1394
--- /dev/null
@@ -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 <ObjDataSource.h>
+
+#include <Standard_CLocaleSentry.hxx>
+#include <Message.hxx>
+#include <Message_Messenger.hxx>
+#include <Message_ProgressSentry.hxx>
+#include <OSD_OpenFile.hxx>
+#include <OSD_Timer.hxx>
+#include <TCollection_ExtendedString.hxx>
+#include <Quantity_Color.hxx>
+
+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<TCollection_AsciiString, MeshMaterial>& 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<TCollection_AsciiString, MeshMaterial>* 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<Graphic3d_Vec3> aVerts;
+  NCollection_Vector<Graphic3d_Vec2> aVertParams;
+  NCollection_Vector<Graphic3d_Vec3> aNorms;
+  NCollection_DataMap<Graphic3d_Vec3i, Standard_Integer, ObjVec3iHasher> aPackedIndices;
+  NCollection_DataMap<TCollection_AsciiString, MeshMaterial> 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 (file)
index 0000000..65da9a0
--- /dev/null
@@ -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 <MeshDataSource.h>
+
+//! 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 (file)
index 0000000..6b40b63
--- /dev/null
@@ -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 <ObjDataWriter.h>
+
+#include <FaceIterator.h>
+#include <CafShapePrs.h>
+
+#include <BRep_Tool.hxx>
+#include <BRepAdaptor_Surface.hxx>
+#include <BRepLProp_SLProps.hxx>
+#include <Message.hxx>
+#include <Message_Messenger.hxx>
+#include <Message_ProgressSentry.hxx>
+#include <OSD_OpenFile.hxx>
+#include <Poly_Array1OfTriangle.hxx>
+#include <Poly_Triangulation.hxx>
+#include <Standard_CLocaleSentry.hxx>
+#include <TDataStd_Name.hxx>
+#include <TopoDS.hxx>
+
+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<TCollection_AsciiString> aComments;
+  for (NCollection_Sequence<TCollection_AsciiString>::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 (file)
index 0000000..6e19830
--- /dev/null
@@ -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 <MeshDataSource.h>
+
+#include <AIS_ListOfInteractive.hxx>
+
+//! 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
index c9eebc5d24e737a91870dc591bce712bea1dfcf0..c903445c7ad106a8cc7b08c6c3a87cffa2716376 100644 (file)
@@ -4,3 +4,5 @@ TKService
 TKernel
 TKG3d
 TKG2d
+TKXCAF
+TKLCAF
\ No newline at end of file
index 9181318b9306346f1d44b65bfa93c89646e28aa0..be30a305761f92625f32b81c0383471f08c14c26 100755 (executable)
@@ -1,4 +1,6 @@
 TKGeomBase
+TKXCAF
+TKLCAF
 TKFillet
 TKBRep
 TKTopAlgo
@@ -15,6 +17,7 @@ TKTopTest
 TKG3d
 TKOffset
 TKMesh
+TKMeshVS
 TKV3d
 TKDraw
 TKOpenGl
index 9de0d1464dfccd51a88ecea08e66c4edf3425fe7..ddcf3cedea463cd3c54c1e597847a4a4ef7ad051 100644 (file)
@@ -5386,6 +5386,283 @@ static int VAutoActivateSelection (Draw_Interpretor& theDi,
   return 0;
 }
 
+#include <ObjDataSource.h>
+#include <MeshPresentation.h>
+#include <MeshVS_Drawer.hxx>
+#include <MeshPrsBuilder.h>
+#include <MeshVS_MeshPrsBuilder.hxx>
+#include <MeshVS_DrawerAttribute.hxx>
+#include <Message.hxx>
+#include <Message_Messenger.hxx>
+namespace
+{
+  std::vector<TCollection_AsciiString> Split (const TCollection_AsciiString& pSource,
+                                              const TCollection_AsciiString& pSeparator)
+  {
+    std::vector<TCollection_AsciiString> 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<TCollection_AsciiString> 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<TCollection_AsciiString> 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<MeshGroup>& 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 <ObjDataWriter.h>
+#include <AIS_ListOfInteractive.hxx>
+// =============================================================================
+// 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",