0028205: Visualization - add functionality for dumping results of detection algorithm...
authorisk <isk@opencascade.com>
Fri, 9 Dec 2016 10:50:40 +0000 (13:50 +0300)
committerapn <apn@opencascade.com>
Thu, 22 Dec 2016 09:46:49 +0000 (12:46 +0300)
StdSelect_ViewerSelector3d::ToPixMap() - added new method for dumping
detection results into an image.

15 files changed:
src/Image/Image_PixMap.cxx
src/Image/Image_PixMap.hxx
src/MeshVS/FILES
src/MeshVS/MeshVS_ColorHasher.cxx [deleted file]
src/MeshVS/MeshVS_ColorHasher.hxx
src/MeshVS/MeshVS_DataMapOfColorMapOfInteger.hxx
src/Quantity/FILES
src/Quantity/Quantity_ColorHasher.hxx [new file with mode: 0644]
src/StdSelect/FILES
src/StdSelect/StdSelect_TypeOfSelectionImage.hxx [new file with mode: 0644]
src/StdSelect/StdSelect_ViewerSelector3d.cxx
src/StdSelect/StdSelect_ViewerSelector3d.hxx
src/ViewerTest/ViewerTest_ViewerCommands.cxx
tests/bugs/vis/bug28205_1 [new file with mode: 0644]
tests/bugs/vis/bug28205_2 [new file with mode: 0644]

index 362c154..67ca4fd 100644 (file)
@@ -19,9 +19,6 @@
 
 #include <algorithm>
 
-
-
-
 IMPLEMENT_STANDARD_RTTIEXT(Image_PixMap,Standard_Transient)
 
 // =======================================================================
@@ -340,6 +337,136 @@ Quantity_Color Image_PixMap::PixelColor (const Standard_Integer theX,
 }
 
 // =======================================================================
+// function : SetPixelColor
+// purpose  :
+// =======================================================================
+void Image_PixMap::SetPixelColor (const Standard_Integer theX,
+                                  const Standard_Integer theY,
+                                  const NCollection_Vec4<float>& theColor)
+{
+  if (IsEmpty()
+   || theX < 0 || Standard_Size(theX) >= SizeX()
+   || theY < 0 || Standard_Size(theY) >= SizeY())
+  {
+    return;
+  }
+
+  switch (myImgFormat)
+  {
+    case ImgGrayF:
+    {
+      ChangeValue<Standard_ShortReal> (theY, theX) = theColor.r();
+      return;
+    }
+    case ImgAlphaF:
+    {
+      ChangeValue<Standard_ShortReal> (theY, theX) = theColor.a();
+      return;
+    }
+    case ImgRGBAF:
+    {
+      Image_ColorRGBAF& aPixel = ChangeValue<Image_ColorRGBAF> (theY, theX);
+      aPixel.r() = theColor.r();
+      aPixel.g() = theColor.g();
+      aPixel.b() = theColor.b();
+      aPixel.a() = theColor.a();
+      return;
+    }
+    case ImgBGRAF:
+    {
+      Image_ColorBGRAF& aPixel = ChangeValue<Image_ColorBGRAF> (theY, theX);
+      aPixel.r() = theColor.r();
+      aPixel.g() = theColor.g();
+      aPixel.b() = theColor.b();
+      aPixel.a() = theColor.a();
+      return;
+    }
+    case ImgRGBF:
+    {
+      Image_ColorRGBF& aPixel = ChangeValue<Image_ColorRGBF> (theY, theX);
+      aPixel.r() = theColor.r();
+      aPixel.g() = theColor.g();
+      aPixel.b() = theColor.b();
+      return;
+    }
+    case ImgBGRF:
+    {
+      Image_ColorBGRF& aPixel = ChangeValue<Image_ColorBGRF> (theY, theX);
+      aPixel.r() = theColor.r();
+      aPixel.g() = theColor.g();
+      aPixel.b() = theColor.b();
+      return;
+    }
+    case ImgRGBA:
+    {
+      Image_ColorRGBA& aPixel = ChangeValue<Image_ColorRGBA> (theY, theX);
+      aPixel.r() = Standard_Byte(theColor.r() * 255.0f);
+      aPixel.g() = Standard_Byte(theColor.g() * 255.0f);
+      aPixel.b() = Standard_Byte(theColor.b() * 255.0f);
+      aPixel.a() = Standard_Byte(theColor.a() * 255.0f);
+      return;
+    }
+    case ImgBGRA:
+    {
+      Image_ColorBGRA& aPixel = ChangeValue<Image_ColorBGRA> (theY, theX);
+      aPixel.r() = Standard_Byte(theColor.r() * 255.0f);
+      aPixel.g() = Standard_Byte(theColor.g() * 255.0f);
+      aPixel.b() = Standard_Byte(theColor.b() * 255.0f);
+      aPixel.a() = Standard_Byte(theColor.a() * 255.0f);
+      return;
+    }
+    case ImgRGB32:
+    {
+      Image_ColorRGB32& aPixel = ChangeValue<Image_ColorRGB32> (theY, theX);
+      aPixel.r()  = Standard_Byte(theColor.r() * 255.0f);
+      aPixel.g()  = Standard_Byte(theColor.g() * 255.0f);
+      aPixel.b()  = Standard_Byte(theColor.b() * 255.0f);
+      aPixel.a_() = 255;
+      return;
+    }
+    case ImgBGR32:
+    {
+      Image_ColorBGR32& aPixel = ChangeValue<Image_ColorBGR32> (theY, theX);
+      aPixel.r()  = Standard_Byte(theColor.r() * 255.0f);
+      aPixel.g()  = Standard_Byte(theColor.g() * 255.0f);
+      aPixel.b()  = Standard_Byte(theColor.b() * 255.0f);
+      aPixel.a_() = 255;
+      return;
+    }
+    case ImgRGB:
+    {
+      Image_ColorRGB& aPixel = ChangeValue<Image_ColorRGB> (theY, theX);
+      aPixel.r() = Standard_Byte(theColor.r() * 255.0f);
+      aPixel.g() = Standard_Byte(theColor.g() * 255.0f);
+      aPixel.b() = Standard_Byte(theColor.b() * 255.0f);
+      return;
+    }
+    case ImgBGR:
+    {
+      Image_ColorBGR& aPixel = ChangeValue<Image_ColorBGR> (theY, theX);
+      aPixel.r() = Standard_Byte(theColor.r() * 255.0f);
+      aPixel.g() = Standard_Byte(theColor.g() * 255.0f);
+      aPixel.b() = Standard_Byte(theColor.b() * 255.0f);
+      return;
+    }
+    case ImgGray:
+    {
+      ChangeValue<Standard_Byte> (theY, theX) = Standard_Byte(theColor.r() * 255.0f);
+      return;
+    }
+    case ImgAlpha:
+    {
+      ChangeValue<Standard_Byte> (theY, theX) = Standard_Byte(theColor.a() * 255.0f);
+      return;
+    }
+    case ImgUNKNOWN:
+    {
+      return;
+    }
+  }
+}
+
+// =======================================================================
 // function : SwapRgbaBgra
 // purpose  :
 // =======================================================================
index e5c7830..b67d312 100644 (file)
@@ -18,7 +18,7 @@
 
 #include <Image_PixMapData.hxx>
 #include <Standard_Transient.hxx>
-#include <Quantity_Color.hxx>
+#include <Quantity_ColorRGBA.hxx>
 
 //! Class represents packed image plane.
 class Image_PixMap : public Standard_Transient
@@ -119,8 +119,9 @@ public: // high-level API
   Standard_EXPORT virtual ~Image_PixMap();
 
   //! Returns the pixel color. This function is relatively slow.
-  //! @param theX - column index from left
-  //! @param theY - row    index from top
+  //! Beware that this method takes coordinates in opposite order in contrast to ::Value() and ::ChangeValue().
+  //! @param theX column index from left
+  //! @param theY row    index from top
   //! @return the pixel color
   inline Quantity_Color PixelColor (const Standard_Integer theX,
                                     const Standard_Integer theY) const
@@ -131,10 +132,37 @@ public: // high-level API
 
   //! Returns the pixel color. This function is relatively slow.
   //! theAlpha argument is set to color intensity (0 - transparent, 1 - opaque)
+  //! Beware that this method takes coordinates in opposite order in contrast to ::Value() and ::ChangeValue().
   Standard_EXPORT Quantity_Color PixelColor (const Standard_Integer theX,
                                              const Standard_Integer theY,
                                              Quantity_Parameter&    theAlpha) const;
 
+  //! Sets the pixel color. This function is relatively slow.
+  //! Beware that this method takes coordinates in opposite order in contrast to ::Value() and ::ChangeValue().
+  void SetPixelColor (const Standard_Integer    theX,
+                      const Standard_Integer    theY,
+                      const Quantity_ColorRGBA& theColor)
+  {
+    const NCollection_Vec4<float> aColor = theColor;
+    SetPixelColor (theX, theY, aColor);
+  }
+
+  //! Sets the pixel color. This function is relatively slow.
+  //! Beware that this method takes coordinates in opposite order in contrast to ::Value() and ::ChangeValue().
+  void SetPixelColor(const Standard_Integer theX,
+                     const Standard_Integer theY,
+                     const Quantity_Color&  theColor)
+  {
+    const NCollection_Vec3<float> aColor = theColor;
+    SetPixelColor (theX, theY, NCollection_Vec4<float> (aColor, 1.0f));
+  }
+
+  //! Sets the pixel color. This function is relatively slow.
+  //! Beware that this method takes coordinates in opposite order in contrast to ::Value() and ::ChangeValue().
+  Standard_EXPORT void SetPixelColor (const Standard_Integer theX,
+                                      const Standard_Integer theY,
+                                      const NCollection_Vec4<float>& theColor);
+
   //! Initialize image plane as wrapper over alien data.
   //! Data will not be copied! Notice that caller should ensure
   //! that data pointer will not be released during this wrapper lifetime.
index 40672f9..2147435 100755 (executable)
@@ -1,7 +1,6 @@
 MeshVS_Array1OfSequenceOfInteger.hxx
 MeshVS_Buffer.hxx
 MeshVS_BuilderPriority.hxx
-MeshVS_ColorHasher.cxx
 MeshVS_ColorHasher.hxx
 MeshVS_CommonSensitiveEntity.hxx
 MeshVS_CommonSensitiveEntity.cxx
diff --git a/src/MeshVS/MeshVS_ColorHasher.cxx b/src/MeshVS/MeshVS_ColorHasher.cxx
deleted file mode 100644 (file)
index 075fcf0..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-// Created on: 2003-12-05
-// Created by: Alexander SOLOVYOV
-// Copyright (c) 2003-2014 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 <MeshVS_ColorHasher.hxx>
-#include <Quantity_Color.hxx>
-
-//================================================================
-// Function : HashCode
-// Purpose  : 
-//================================================================
-Standard_Integer MeshVS_ColorHasher::HashCode ( const Quantity_Color& theCol, const Standard_Integer theUpper )
-{
-  Standard_Integer r = Standard_Integer( 255 * theCol.Red   () ),
-                   g = Standard_Integer( 255 * theCol.Green () ),
-                   b = Standard_Integer( 255 * theCol.Blue  () );
-
-  #define MESHPRS_HASH_BYTE(val) { \
-    aHash += (val);              \
-    aHash += (aHash << 10);      \
-    aHash ^= (aHash >> 6);       \
-  }
-  Standard_Integer aHash = 0;
-  MESHPRS_HASH_BYTE ( r )
-  MESHPRS_HASH_BYTE ( g )
-  MESHPRS_HASH_BYTE ( b )
-  aHash += (aHash << 3);
-  aHash ^= (aHash >> 11);
-  aHash += (aHash << 15);
-  return (( aHash & 0x7fff ) % theUpper) + 1;
-  #undef MESHPRS_HASH_BYTE
-}
-
-//================================================================
-// Function : IsEqual
-// Purpose  : 
-//================================================================
-Standard_Boolean MeshVS_ColorHasher::IsEqual( const Quantity_Color& K1, const Quantity_Color& K2 )
-{
-  return K1==K2;
-}
index 46b14ab..5eb27c6 100644 (file)
 #ifndef _MeshVS_ColorHasher_HeaderFile
 #define _MeshVS_ColorHasher_HeaderFile
 
-#include <Standard.hxx>
-#include <Standard_DefineAlloc.hxx>
-#include <Standard_Handle.hxx>
-
-#include <Standard_Integer.hxx>
-#include <Standard_Boolean.hxx>
-class Quantity_Color;
-
-
-//! Hasher for using in ColorToIdsMap from MeshVS
-class MeshVS_ColorHasher 
-{
-public:
-
-  DEFINE_STANDARD_ALLOC
-
-  
-  Standard_EXPORT static Standard_Integer HashCode (const Quantity_Color& K, const Standard_Integer Upper);
-  
-  Standard_EXPORT static Standard_Boolean IsEqual (const Quantity_Color& K1, const Quantity_Color& K2);
-
-
-
-
-protected:
-
-
-
-
-
-private:
-
-
-
-
-
-};
-
-
-
-
-
+#include <Quantity_ColorHasher.hxx>
 
+Standard_DEPRECATED("This type name is deprecated - Quantity_ColorHasher should be used instead")
+typedef Quantity_ColorHasher MeshVS_ColorHasher;
 
 #endif // _MeshVS_ColorHasher_HeaderFile
index 527934b..6ae3a5e 100644 (file)
 #ifndef MeshVS_DataMapOfColorMapOfInteger_HeaderFile
 #define MeshVS_DataMapOfColorMapOfInteger_HeaderFile
 
-#include <Quantity_Color.hxx>
+#include <Quantity_ColorHasher.hxx>
 #include <TColStd_MapOfInteger.hxx>
-#include <MeshVS_ColorHasher.hxx>
 #include <NCollection_DataMap.hxx>
 
-typedef NCollection_DataMap<Quantity_Color,TColStd_MapOfInteger,MeshVS_ColorHasher> MeshVS_DataMapOfColorMapOfInteger;
-typedef NCollection_DataMap<Quantity_Color,TColStd_MapOfInteger,MeshVS_ColorHasher>::Iterator MeshVS_DataMapIteratorOfDataMapOfColorMapOfInteger;
-
+typedef NCollection_DataMap<Quantity_Color, TColStd_MapOfInteger, Quantity_ColorHasher>           MeshVS_DataMapOfColorMapOfInteger;
+typedef NCollection_DataMap<Quantity_Color, TColStd_MapOfInteger, Quantity_ColorHasher>::Iterator MeshVS_DataMapIteratorOfDataMapOfColorMapOfInteger;
 
 #endif
index c5bd950..2599056 100755 (executable)
@@ -14,6 +14,7 @@ Quantity_Coefficient.hxx
 Quantity_CoefficientOfExpansion.hxx
 Quantity_Color.cxx
 Quantity_Color.hxx
+Quantity_ColorHasher.hxx
 Quantity_ColorRGBA.hxx
 Quantity_ColorDefinitionError.hxx
 Quantity_Concentration.hxx
diff --git a/src/Quantity/Quantity_ColorHasher.hxx b/src/Quantity/Quantity_ColorHasher.hxx
new file mode 100644 (file)
index 0000000..65fc450
--- /dev/null
@@ -0,0 +1,58 @@
+// Created on: 2016-12-13
+// Copyright (c) 2016 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#ifndef _Quantity_ColorHasher_HeaderFile
+#define _Quantity_ColorHasher_HeaderFile
+
+#include <Quantity_Color.hxx>
+
+//! Hasher of Quantity_Color.
+struct Quantity_ColorHasher
+{
+  //! Returns hash code for the given color.
+  static Standard_Integer HashCode (const Quantity_Color&  theColor,
+                                    const Standard_Integer theUpper)
+  {
+    Standard_Integer aRed   = Standard_Integer (255 * theColor.Red());
+    Standard_Integer aGreen = Standard_Integer (255 * theColor.Green());
+    Standard_Integer aBlue  = Standard_Integer (255 * theColor.Blue());
+
+    Standard_Integer aHash = 0;
+    updateHash (aHash, aRed);
+    updateHash (aHash, aGreen);
+    updateHash (aHash, aBlue);
+    aHash += (aHash << 3);
+    aHash ^= (aHash >> 11);
+    aHash += (aHash << 15);
+    return ((aHash & 0x7fff) % theUpper) + 1;
+  }
+
+  //! Returns true if two colors are equal.
+  static Standard_Boolean IsEqual (const Quantity_Color& theColor1,
+                                   const Quantity_Color& theColor2)
+  {
+    return theColor1 == theColor2;
+  }
+
+protected:
+  static void updateHash (Standard_Integer&      theHash,
+                          const Standard_Integer theValue)
+  {
+    theHash += theValue;
+    theHash += (theHash << 10);
+    theHash ^= (theHash >> 6);
+  }
+};
+
+#endif
index 394026c..8284738 100644 (file)
@@ -23,6 +23,7 @@ StdSelect_ShapeTypeFilter.lxx
 StdSelect_TypeOfEdge.hxx
 StdSelect_TypeOfFace.hxx
 StdSelect_TypeOfResult.hxx
+StdSelect_TypeOfSelectionImage.hxx
 StdSelect_ViewerSelector3d.cxx
 StdSelect_ViewerSelector3d.hxx
 StdSelect_ViewerSelector3d.lxx
diff --git a/src/StdSelect/StdSelect_TypeOfSelectionImage.hxx b/src/StdSelect/StdSelect_TypeOfSelectionImage.hxx
new file mode 100644 (file)
index 0000000..d071e39
--- /dev/null
@@ -0,0 +1,30 @@
+// Created on: 2016-12-09
+// Copyright (c) 2016 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#ifndef _StdSelect_TypeOfSelectionImage_HeaderFile
+#define _StdSelect_TypeOfSelectionImage_HeaderFile
+
+//! Type of output selection image.
+enum StdSelect_TypeOfSelectionImage
+{
+  StdSelect_TypeOfSelectionImage_NormalizedDepth = 0,     //!< normalized   depth (grayscale)
+  StdSelect_TypeOfSelectionImage_NormalizedDepthInverted, //!< normalized   depth, inverted
+  StdSelect_TypeOfSelectionImage_UnnormalizedDepth,       //!< unnormalized depth (grayscale)
+  StdSelect_TypeOfSelectionImage_ColoredDetectedObject,   //!< color of detected object
+  StdSelect_TypeOfSelectionImage_ColoredEntity,           //!< random color for each entity
+  StdSelect_TypeOfSelectionImage_ColoredOwner,            //!< random color for each owner
+  StdSelect_TypeOfSelectionImage_ColoredSelectionMode     //!< color of selection mode
+};
+
+#endif
index 7347948..c3803ba 100644 (file)
 #include <Aspect_Window.hxx>
 #include <Graphic3d_AspectMarker3d.hxx>
 #include <Graphic3d_ArrayOfPoints.hxx>
+#include <math_BullardGenerator.hxx>
+#include <Message.hxx>
+#include <Message_Messenger.hxx>
+#include <Quantity_ColorHasher.hxx>
 #include <Poly_Connect.hxx>
 #include <TColStd_HArray1OfInteger.hxx>
 
@@ -669,3 +673,438 @@ void StdSelect_ViewerSelector3d::updateZLayers (const Handle(V3d_View)& theView)
     myZLayerOrderMap.Bind (aLayerIter.Value(), aPos);
   }
 }
+
+namespace
+{
+  //! Abstract class for filling pixel with color.
+  class BaseFiller : public Standard_Transient
+  {
+    DEFINE_STANDARD_RTTI_INLINE(BaseFiller, Standard_Transient)
+  public:
+
+    //! Main constructor.
+    BaseFiller (Image_PixMap&               thePixMap,
+                StdSelect_ViewerSelector3d* theSelector)
+    : myImage  (&thePixMap),
+      myMainSel(theSelector) {}
+
+    //! Fill pixel at specified position.
+    virtual void Fill (const Standard_Integer theCol,
+                       const Standard_Integer theRow,
+                       const Standard_Integer thePicked) = 0;
+
+    //! Flush results into final image.
+    virtual void Flush() {}
+
+  protected:
+
+    //! Find the new unique random color.
+    void randomPastelColor (Quantity_Color& theColor)
+    {
+      for (;;)
+      {
+        nextRandomPastelColor (theColor);
+        if (myUniqueColors.Add (theColor))
+        {
+          return;
+        }
+      }
+    }
+
+    //! Fills the given color as random.
+    void nextRandomPastelColor (Quantity_Color& theColor)
+    {
+      theColor = Quantity_Color (Standard_Real(myBullardGenerator.NextInt() % 256) / 255.0,
+                                 Standard_Real(myBullardGenerator.NextInt() % 256) / 255.0,
+                                 Standard_Real(myBullardGenerator.NextInt() % 256) / 255.0,
+                                 Quantity_TOC_RGB);
+    }
+
+  protected:
+    Image_PixMap*               myImage;
+    StdSelect_ViewerSelector3d* myMainSel;
+    math_BullardGenerator       myBullardGenerator;
+    NCollection_Map<Quantity_Color, Quantity_ColorHasher> myUniqueColors;
+  };
+
+  //! Help class for filling pixel with random color.
+  class GeneratedEntityColorFiller : public BaseFiller
+  {
+    DEFINE_STANDARD_RTTI_INLINE(GeneratedEntityColorFiller, BaseFiller)
+  public:
+    GeneratedEntityColorFiller (Image_PixMap& thePixMap,
+                                StdSelect_ViewerSelector3d* theSelector,
+                                const SelectMgr_SelectableObjectSet& theSelObjects)
+    : BaseFiller (thePixMap, theSelector)
+    {
+      // generate per-entity colors in the order as they have been activated
+      for (SelectMgr_SelectableObjectSet::Iterator anObjIter (theSelObjects); anObjIter.More(); anObjIter.Next())
+      {
+        const Handle(SelectMgr_SelectableObject)& anObj = anObjIter.Value();
+        for (anObj->Init(); anObj->More(); anObj->Next())
+        {
+          const Handle(SelectMgr_Selection)& aSel = anObj->CurrentSelection();
+          for (aSel->Init(); aSel->More(); aSel->Next())
+          {
+            const Handle(SelectMgr_SensitiveEntity)& aSens = aSel->Sensitive();
+            if (!myMapEntityColors.IsBound (aSens->BaseSensitive()))
+            {
+              Quantity_Color aColor;
+              randomPastelColor (aColor);
+              myMapEntityColors.Bind (aSens->BaseSensitive(), aColor);
+            }
+          }
+        }
+      }
+    }
+
+    virtual void Fill (const Standard_Integer theCol,
+                       const Standard_Integer theRow,
+                       const Standard_Integer thePicked) Standard_OVERRIDE
+    {
+      if (thePicked < 1
+       || thePicked > myMainSel->NbPicked())
+      {
+        myImage->SetPixelColor (theCol, theRow, Quantity_Color(Quantity_NOC_BLACK));
+        return;
+      }
+
+      const Handle(SelectBasics_SensitiveEntity)& aPickedEntity = myMainSel->PickedEntity (thePicked);
+      Quantity_Color aColor (Quantity_NOC_BLACK);
+      myMapEntityColors.Find (aPickedEntity, aColor);
+      myImage->SetPixelColor (theCol, theRow, aColor);
+    }
+
+  protected:
+    NCollection_DataMap<Handle(SelectBasics_SensitiveEntity), Quantity_Color> myMapEntityColors;
+  };
+
+  //! Help class for filling pixel with normalized depth of ray.
+  class NormalizedDepthFiller : public BaseFiller
+  {
+    DEFINE_STANDARD_RTTI_INLINE(NormalizedDepthFiller, BaseFiller)
+  public:
+    NormalizedDepthFiller (Image_PixMap& thePixMap,
+                           StdSelect_ViewerSelector3d* theSelector,
+                           const Standard_Boolean theToInverse)
+    : BaseFiller (thePixMap, theSelector),
+      myDepthMin ( RealLast()),
+      myDepthMax (-RealLast()),
+      myToInverse(theToInverse)
+    {
+      myUnnormImage.InitZero (Image_PixMap::ImgGrayF, thePixMap.SizeX(), thePixMap.SizeY());
+    }
+
+    //! Accumulate the data.
+    virtual void Fill (const Standard_Integer theCol,
+                       const Standard_Integer theRow,
+                       const Standard_Integer thePicked) Standard_OVERRIDE
+    {
+      if (myUnnormImage.IsEmpty())
+      {
+        return;
+      }
+
+      if (thePicked < 1
+       || thePicked > myMainSel->NbPicked())
+      {
+        myUnnormImage.ChangeValue<float> (theRow, theCol) = ShortRealLast();
+        return;
+      }
+
+      const SelectMgr_SortCriterion& aSortCriterion = myMainSel->PickedData (thePicked);
+      myUnnormImage.ChangeValue<float> (theRow, theCol) = float(aSortCriterion.Depth);
+      myDepthMin = Min (myDepthMin, aSortCriterion.Depth);
+      myDepthMax = Max (myDepthMax, aSortCriterion.Depth);
+    }
+
+    //! Normalize the depth values.
+    virtual void Flush() Standard_OVERRIDE
+    {
+      Standard_Real aFrom  = 0.0;
+      Standard_Real aDelta = 1.0;
+      if (myDepthMin <= myDepthMax)
+      {
+        aFrom = myDepthMin;
+        if (myDepthMin != myDepthMax)
+        {
+          aDelta = myDepthMax - myDepthMin;
+        }
+      }
+      for (Standard_Size aRowIter = 0; aRowIter < myUnnormImage.SizeY(); ++aRowIter)
+      {
+        for (Standard_Size aColIter = 0; aColIter < myUnnormImage.SizeX(); ++aColIter)
+        {
+          float aDepth = myUnnormImage.Value<float> (aRowIter, aColIter);
+          if (aDepth <= -ShortRealLast()
+           || aDepth >=  ShortRealLast())
+          {
+            myImage->SetPixelColor (Standard_Integer(aColIter), Standard_Integer(aRowIter),
+                                    NCollection_Vec4<float> (0.0f, 0.0f, 0.0f, 1.0f));
+            continue;
+          }
+
+          float aNormDepth = float((Standard_Real(aDepth) - aFrom) / aDelta);
+          if (myToInverse)
+          {
+            aNormDepth = 1.0f - aNormDepth;
+          }
+          myImage->SetPixelColor (Standard_Integer(aColIter), Standard_Integer(aRowIter),
+                                  NCollection_Vec4<float> (aNormDepth, aNormDepth, aNormDepth, 1.0f));
+        }
+      }
+    }
+
+  private:
+    Image_PixMap     myUnnormImage;
+    Standard_Real    myDepthMin;
+    Standard_Real    myDepthMax;
+    Standard_Boolean myToInverse;
+  };
+
+  //! Help class for filling pixel with unnormalized depth of ray.
+  class UnnormalizedDepthFiller : public BaseFiller
+  {
+    DEFINE_STANDARD_RTTI_INLINE(UnnormalizedDepthFiller, BaseFiller)
+  public:
+    UnnormalizedDepthFiller (Image_PixMap&               thePixMap,
+                             StdSelect_ViewerSelector3d* theSelector)
+    : BaseFiller (thePixMap, theSelector) {}
+
+    virtual void Fill (const Standard_Integer theCol,
+                       const Standard_Integer theRow,
+                       const Standard_Integer thePicked) Standard_OVERRIDE
+    {
+      if (thePicked < 1
+       || thePicked > myMainSel->NbPicked())
+      {
+        myImage->SetPixelColor (theCol, theRow, NCollection_Vec4<float> (0.0f, 0.0f, 0.0f, 1.0f));
+        return;
+      }
+
+      const SelectMgr_SortCriterion& aSortCriterion = myMainSel->PickedData (thePicked);
+      const float aDepth = float(aSortCriterion.Depth);
+      myImage->SetPixelColor (theCol, theRow, NCollection_Vec4<float> (aDepth, aDepth, aDepth, 1.0f));
+    }
+  };
+
+  //! Help class for filling pixel with color of detected object.
+  class GeneratedOwnerColorFiller : public BaseFiller
+  {
+    DEFINE_STANDARD_RTTI_INLINE(GeneratedOwnerColorFiller, BaseFiller)
+  public:
+    GeneratedOwnerColorFiller (Image_PixMap& thePixMap,
+                               StdSelect_ViewerSelector3d* theSelector,
+                               const SelectMgr_SelectableObjectSet& theSelObjects)
+    : BaseFiller (thePixMap, theSelector)
+    {
+      // generate per-owner colors in the order as they have been activated
+      for (SelectMgr_SelectableObjectSet::Iterator anObjIter (theSelObjects); anObjIter.More(); anObjIter.Next())
+      {
+        const Handle(SelectMgr_SelectableObject)& anObj = anObjIter.Value();
+        for (anObj->Init(); anObj->More(); anObj->Next())
+        {
+          const Handle(SelectMgr_Selection)& aSel = anObj->CurrentSelection();
+          for (aSel->Init(); aSel->More(); aSel->Next())
+          {
+            const Handle(SelectMgr_SensitiveEntity)& aSens   = aSel->Sensitive();
+            const Handle(SelectBasics_EntityOwner)&  anOwner = aSens->BaseSensitive()->OwnerId();
+            if (!myMapOwnerColors.IsBound (anOwner))
+            {
+              Quantity_Color aColor;
+              randomPastelColor (aColor);
+              myMapOwnerColors.Bind (anOwner, aColor);
+            }
+          }
+        }
+      }
+    }
+
+    virtual void Fill (const Standard_Integer theCol,
+                       const Standard_Integer theRow,
+                       const Standard_Integer thePicked) Standard_OVERRIDE
+    {
+      if (thePicked < 1
+       || thePicked > myMainSel->NbPicked())
+      {
+        myImage->SetPixelColor (theCol, theRow, Quantity_Color(Quantity_NOC_BLACK));
+        return;
+      }
+
+      const Handle(SelectMgr_EntityOwner)& aPickedOwner = myMainSel->Picked (thePicked);
+      Quantity_Color aColor (Quantity_NOC_BLACK);
+      myMapOwnerColors.Find (aPickedOwner, aColor);
+      myImage->SetPixelColor (theCol, theRow, aColor);
+    }
+
+  protected:
+    NCollection_DataMap<Handle(SelectBasics_EntityOwner), Quantity_Color> myMapOwnerColors;
+  };
+
+  //! Help class for filling pixel with random color for each selection mode.
+  class GeneratedSelModeColorFiller : public BaseFiller
+  {
+    DEFINE_STANDARD_RTTI_INLINE(GeneratedSelModeColorFiller, BaseFiller)
+  public:
+    GeneratedSelModeColorFiller (Image_PixMap&               thePixMap,
+                                 StdSelect_ViewerSelector3d* theSelector)
+    : BaseFiller (thePixMap, theSelector)
+    {
+      // generate standard modes in proper order, consider custom objects would use similar scheme
+      myMapSelectionModeColors.Bind (     0, Quantity_NOC_WHITE);          // default (entire object selection)
+      myMapSelectionModeColors.Bind (     1, Quantity_NOC_YELLOW);         // TopAbs_VERTEX
+      myMapSelectionModeColors.Bind (     2, Quantity_NOC_GREEN);          // TopAbs_EDGE
+      myMapSelectionModeColors.Bind (     3, Quantity_NOC_RED);            // TopAbs_WIRE
+      myMapSelectionModeColors.Bind (     4, Quantity_NOC_BLUE1);          // TopAbs_FACE
+      myMapSelectionModeColors.Bind (     5, Quantity_NOC_CYAN1);          // TopAbs_SHELL
+      myMapSelectionModeColors.Bind (     6, Quantity_NOC_PURPLE);         // TopAbs_SOLID
+      myMapSelectionModeColors.Bind (     7, Quantity_NOC_MAGENTA1);       // TopAbs_COMPSOLID
+      myMapSelectionModeColors.Bind (     8, Quantity_NOC_BROWN);          // TopAbs_COMPOUND
+      myMapSelectionModeColors.Bind (0x0010, Quantity_NOC_PINK);           // MeshVS_SMF_Volume
+      myMapSelectionModeColors.Bind (0x001E, Quantity_NOC_LIMEGREEN);      // MeshVS_SMF_Element
+      myMapSelectionModeColors.Bind (0x001F, Quantity_NOC_DARKOLIVEGREEN); // MeshVS_SMF_All
+      myMapSelectionModeColors.Bind (0x0100, Quantity_NOC_GOLD);           // MeshVS_SMF_Group
+    }
+
+    virtual void Fill (const Standard_Integer theCol,
+                       const Standard_Integer theRow,
+                       const Standard_Integer thePicked) Standard_OVERRIDE
+    {
+      if (thePicked < 1
+       || thePicked > myMainSel->NbPicked())
+      {
+        myImage->SetPixelColor (theCol, theRow, Quantity_Color (Quantity_NOC_BLACK));
+        return;
+      }
+
+      Standard_Integer aSelectionMode = -1;
+      const Handle(SelectMgr_SelectableObject)&   aSelectable = myMainSel->Picked       (thePicked)->Selectable();
+      const Handle(SelectBasics_SensitiveEntity)& anEntity    = myMainSel->PickedEntity (thePicked);
+      for (aSelectable->Init(); aSelectable->More(); aSelectable->Next())
+      {
+        const Handle(SelectMgr_Selection)& aSelection = aSelectable->CurrentSelection();
+        for (aSelection->Init(); aSelection->More(); aSelection->Next())
+        {
+          if (aSelection->Sensitive()->BaseSensitive() == anEntity)
+          {
+            aSelectionMode = aSelection->Mode();
+            break;
+          }
+        }
+      }
+      if (aSelectionMode == -1)
+      {
+        myImage->SetPixelColor (theCol, theRow, Quantity_Color (Quantity_NOC_BLACK));
+        return;
+      }
+
+      if (!myMapSelectionModeColors.IsBound (aSelectionMode))
+      {
+        Quantity_Color aColor;
+        randomPastelColor (aColor);
+        myMapSelectionModeColors.Bind (aSelectionMode, aColor);
+      }
+
+      const Quantity_Color& aColor = myMapSelectionModeColors.Find (aSelectionMode);
+      myImage->SetPixelColor (theCol, theRow, aColor);
+    }
+
+  protected:
+    NCollection_DataMap<Standard_Integer, Quantity_Color> myMapSelectionModeColors;
+  };
+
+  //! Help class for filling pixel with color of detected shape.
+  class DetectedObjectColorFiller : public BaseFiller
+  {
+    DEFINE_STANDARD_RTTI_INLINE(DetectedObjectColorFiller, BaseFiller)
+  public:
+    DetectedObjectColorFiller (Image_PixMap&               thePixMap,
+                               StdSelect_ViewerSelector3d* theSelector)
+    : BaseFiller (thePixMap, theSelector) {}
+
+    virtual void Fill (const Standard_Integer theCol,
+                       const Standard_Integer theRow,
+                       const Standard_Integer thePicked) Standard_OVERRIDE
+    {
+      Quantity_Color aColor (Quantity_NOC_BLACK);
+      if (thePicked > 0
+       && thePicked <= myMainSel->NbPicked())
+      {
+        const Handle(SelectMgr_SelectableObject)& aSelectable = myMainSel->Picked (thePicked)->Selectable();
+        aColor = aSelectable->Attributes()->Color();
+      }
+      myImage->SetPixelColor (theCol, theRow, aColor);
+    }
+  };
+
+}
+
+//=======================================================================
+//function : ToPixMap
+//purpose  :
+//=======================================================================
+Standard_Boolean StdSelect_ViewerSelector3d::ToPixMap (Image_PixMap&                        theImage,
+                                                       const Handle(V3d_View)&              theView,
+                                                       const StdSelect_TypeOfSelectionImage theType,
+                                                       const Standard_Integer               thePickedIndex)
+{
+  if (theImage.IsEmpty())
+  {
+    Standard_ProgramError::Raise ("StdSelect_ViewerSelector3d::ToPixMap() has been called with empty image");
+    return Standard_False;
+  }
+
+  Handle(BaseFiller) aFiller;
+  switch (theType)
+  {
+    case StdSelect_TypeOfSelectionImage_NormalizedDepth:
+    case StdSelect_TypeOfSelectionImage_NormalizedDepthInverted:
+    {
+      aFiller = new NormalizedDepthFiller (theImage, this,
+                                           theType == StdSelect_TypeOfSelectionImage_NormalizedDepthInverted);
+      break;
+    }
+    case StdSelect_TypeOfSelectionImage_UnnormalizedDepth:
+    {
+      aFiller = new UnnormalizedDepthFiller (theImage, this);
+      break;
+    }
+    case StdSelect_TypeOfSelectionImage_ColoredDetectedObject:
+    {
+      aFiller = new DetectedObjectColorFiller (theImage, this);
+      break;
+    }
+    case StdSelect_TypeOfSelectionImage_ColoredEntity:
+    {
+      aFiller = new GeneratedEntityColorFiller (theImage, this, mySelectableObjects);
+      break;
+    }
+    case StdSelect_TypeOfSelectionImage_ColoredOwner:
+    {
+      aFiller = new GeneratedOwnerColorFiller (theImage, this, mySelectableObjects);
+      break;
+    }
+    case StdSelect_TypeOfSelectionImage_ColoredSelectionMode:
+    {
+      aFiller = new GeneratedSelModeColorFiller (theImage, this);
+      break;
+    }
+  }
+  if (aFiller.IsNull())
+  {
+    return Standard_False;
+  }
+
+  const Standard_Integer aSizeX = static_cast<Standard_Integer> (theImage.SizeX());
+  const Standard_Integer aSizeY = static_cast<Standard_Integer> (theImage.SizeY());
+  for (Standard_Integer aRowIter = 0; aRowIter < aSizeY; ++aRowIter)
+  {
+    for (Standard_Integer aColIter = 0; aColIter < aSizeX; ++aColIter)
+    {
+      Pick (aColIter, aRowIter, theView);
+      aFiller->Fill (aColIter, aRowIter, thePickedIndex);
+    }
+  }
+  aFiller->Flush();
+  return Standard_True;
+}
index 48c4283..c4c0936 100644 (file)
@@ -25,7 +25,9 @@
 #include <Graphic3d_SequenceOfHClipPlane.hxx>
 #include <SelectMgr_ViewerSelector.hxx>
 #include <SelectMgr_Selection.hxx>
+#include <StdSelect_TypeOfSelectionImage.hxx>
 #include <NCollection_Handle.hxx>
+#include <V3d_ImageDumpOptions.hxx>
 
 class Graphic3d_Group;
 class Graphic3d_Structure;
@@ -69,6 +71,18 @@ public:
   Standard_EXPORT void Pick (const TColgp_Array1OfPnt2d& thePolyline,
                              const Handle(V3d_View)& theView);
 
+  //! Dump of detection results into image.
+  //! This method performs axis picking for each pixel in the image
+  //! and generates a color depending on picking results and selection image type.
+  //! @param theImage       result image, should be initialized
+  //! @param theView        3D view defining camera position
+  //! @param theType        type of image to define
+  //! @param thePickedIndex index of picked entity (1 means topmost)
+  Standard_EXPORT Standard_Boolean ToPixMap (Image_PixMap&                        theImage,
+                                             const Handle(V3d_View)&              theView,
+                                             const StdSelect_TypeOfSelectionImage theType,
+                                             const Standard_Integer               thePickedIndex = 1);
+
   //! Displays sensitives in view <theView>.
   Standard_EXPORT void DisplaySensitive (const Handle(V3d_View)& theView);
   
index d4a1ec3..417771c 100644 (file)
@@ -10202,6 +10202,141 @@ static int VSelectionProperties (Draw_Interpretor& theDi,
   return 0;
 }
 
+//===============================================================================================
+//function : VDumpSelectionImage
+//purpose  :
+//===============================================================================================
+static int VDumpSelectionImage (Draw_Interpretor& /*theDi*/,
+                                Standard_Integer  theArgsNb,
+                                const char**      theArgVec)
+{
+  if (theArgsNb < 2)
+  {
+    std::cout << "Syntax error: wrong number arguments for '" << theArgVec[0] << "'\n";
+    return 1;
+  }
+
+  const Handle(AIS_InteractiveContext)& aContext = ViewerTest::GetAISContext();
+  if (aContext.IsNull())
+  {
+    std::cout << "Error: no active view.\n";
+    return 1;
+  }
+
+  TCollection_AsciiString aFile;
+  StdSelect_TypeOfSelectionImage aType = StdSelect_TypeOfSelectionImage_NormalizedDepth;
+  Image_PixMap::ImgFormat anImgFormat = Image_PixMap::ImgBGR;
+  Standard_Integer aPickedIndex = 1;
+  for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
+  {
+    TCollection_AsciiString aParam (theArgVec[anArgIter]);
+    aParam.LowerCase();
+    if (aParam == "-type")
+    {
+      if (++anArgIter >= theArgsNb)
+      {
+        std::cout << "Syntax error: wrong number parameters of flag '-depth'.\n";
+        return 1;
+      }
+
+      TCollection_AsciiString aValue (theArgVec[anArgIter]);
+      aValue.LowerCase();
+      if (aValue == "depth"
+       || aValue == "normdepth"
+       || aValue == "normalizeddepth")
+      {
+        aType       = StdSelect_TypeOfSelectionImage_NormalizedDepth;
+        anImgFormat = Image_PixMap::ImgGrayF;
+      }
+      if (aValue == "depthinverted"
+       || aValue == "normdepthinverted"
+       || aValue == "normalizeddepthinverted"
+       || aValue == "inverted")
+      {
+        aType       = StdSelect_TypeOfSelectionImage_NormalizedDepthInverted;
+        anImgFormat = Image_PixMap::ImgGrayF;
+      }
+      else if (aValue == "unnormdepth"
+            || aValue == "unnormalizeddepth")
+      {
+        aType       = StdSelect_TypeOfSelectionImage_UnnormalizedDepth;
+        anImgFormat = Image_PixMap::ImgGrayF;
+      }
+      else if (aValue == "objectcolor"
+            || aValue == "object"
+            || aValue == "color")
+      {
+        aType = StdSelect_TypeOfSelectionImage_ColoredDetectedObject;
+      }
+      else if (aValue == "entitycolor"
+            || aValue == "entity")
+      {
+        aType = StdSelect_TypeOfSelectionImage_ColoredEntity;
+      }
+      else if (aValue == "ownercolor"
+            || aValue == "owner")
+      {
+        aType = StdSelect_TypeOfSelectionImage_ColoredOwner;
+      }
+      else if (aValue == "selectionmodecolor"
+            || aValue == "selectionmode"
+            || aValue == "selmodecolor"
+            || aValue == "selmode")
+      {
+        aType = StdSelect_TypeOfSelectionImage_ColoredSelectionMode;
+      }
+    }
+    else if (aParam == "-picked"
+          || aParam == "-pickeddepth"
+          || aParam == "-pickedindex")
+    {
+      if (++anArgIter >= theArgsNb)
+      {
+        std::cout << "Syntax error: wrong number parameters at '" << aParam << "'.\n";
+        return 1;
+      }
+
+      aPickedIndex = Draw::Atoi (theArgVec[anArgIter]);
+    }
+    else if (aFile.IsEmpty())
+    {
+      aFile = theArgVec[anArgIter];
+    }
+    else
+    {
+      std::cout << "Syntax error: unknown argument '" << theArgVec[anArgIter] << "'.\n";
+      return 1;
+    }
+  }
+  if (aFile.IsEmpty())
+  {
+    std::cout << "Syntax error: image file name is missing.\n";
+    return 1;
+  }
+
+  const Handle(V3d_View)& aView = ViewerTest::CurrentView();
+  Standard_Integer aWidth = 0, aHeight = 0;
+  aView->Window()->Size (aWidth, aHeight);
+
+  Image_AlienPixMap aPixMap;
+  if (!aPixMap.InitZero (anImgFormat, aWidth, aHeight))
+  {
+    std::cout << "Error: can't allocate image.\n";
+    return 1;
+  }
+  if (!aContext->MainSelector()->ToPixMap (aPixMap, aView, aType, aPickedIndex))
+  {
+    std::cout << "Error: can't generate selection image.\n";
+    return 1;
+  }
+  if (!aPixMap.Save (aFile))
+  {
+    std::cout << "Error: can't save selection image.\n";
+    return 0;
+  }
+  return 0;
+}
+
 //=======================================================================
 //function : ViewerCommands
 //purpose  :
@@ -10834,6 +10969,17 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
     "\n    -print                  : prints current state of all mentioned parameters",
     __FILE__, VSelectionProperties, group);
 
+  theCommands.Add ("vseldump",
+                   "vseldump file -type {depth|unnormDepth|object|owner|selMode|entity}=depth -pickedIndex Index=1"
+                   "\n\t\t: Generate an image based on detection results:"
+                   "\n\t\t:   depth       normalized depth values"
+                   "\n\t\t:   unnormDepth unnormalized depth values"
+                   "\n\t\t:   object      color of detected object"
+                   "\n\t\t:   owner       color of detected owner"
+                   "\n\t\t:   selMode     color of selection mode"
+                   "\n\t\t:   entity      color of etected entity",
+                   __FILE__, VDumpSelectionImage, group);
+
 #if defined(_WIN32)
   theCommands.Add("vprogressive",
     "vprogressive",
diff --git a/tests/bugs/vis/bug28205_1 b/tests/bugs/vis/bug28205_1
new file mode 100644 (file)
index 0000000..00c840c
--- /dev/null
@@ -0,0 +1,21 @@
+puts "================================================================================================="
+puts "0028205: Visualization - add functionality for dumping results of detection algorithms into image"
+puts "Selection image from normalized depth"
+puts "================================================================================================="
+
+box b0 1 2 3
+box b1 3 2 1 1 2 3
+
+vdisplay -noupdate -dispMode 1 b0 b1
+vsetcolor -noupdate b0 green
+vsetcolor -noupdate b1 red
+vfit
+
+vrotate -mouseStart 300 200 -mouseMove 100 200
+
+vseldump $imagedir/${casename}_depth.png    -type depth
+vseldump $imagedir/${casename}_depthinv.png -type depthInverted
+vseldump $imagedir/${casename}_object.png   -type objectColor
+vseldump $imagedir/${casename}_owner.png    -type ownerColor
+vseldump $imagedir/${casename}_entity.png   -type entityColor
+vdump $imagedir/${casename}.png
diff --git a/tests/bugs/vis/bug28205_2 b/tests/bugs/vis/bug28205_2
new file mode 100644 (file)
index 0000000..6791fa6
--- /dev/null
@@ -0,0 +1,24 @@
+puts "================================================================================================="
+puts "0028205: Visualization - add functionality for dumping results of detection algorithms into image"
+puts "Selection image from colors of selection modes."
+puts "================================================================================================="
+
+pload MODELING VISUALIZATION
+vclear
+vinit View1
+box b0 0 0 0 1 1 1
+box b1 2 2 2 1 1 1
+box b2 4 4 4 1 1 1
+box b3 6 6 6 1 1 1
+
+vdisplay -dispMode 1 b0 b1 b2 b3
+vfit
+
+vselmode b0 1 1
+vselmode b0 2 1
+vselmode b1 4 1
+vselmode b2 2 1
+vselmode b3 3 1
+
+vseldump $imagedir/${casename}_selmode.png -type selectionModeColor
+vdump $imagedir/${casename}.png