diff --git a/src/Image/Image_PixMap.cxx b/src/Image/Image_PixMap.cxx index 362c154a25..67ca4fdd40 100644 --- a/src/Image/Image_PixMap.cxx +++ b/src/Image/Image_PixMap.cxx @@ -19,9 +19,6 @@ #include - - - IMPLEMENT_STANDARD_RTTIEXT(Image_PixMap,Standard_Transient) // ======================================================================= @@ -339,6 +336,136 @@ Quantity_Color Image_PixMap::PixelColor (const Standard_Integer theX, return Quantity_Color (0.0, 0.0, 0.0, Quantity_TOC_RGB); } +// ======================================================================= +// function : SetPixelColor +// purpose : +// ======================================================================= +void Image_PixMap::SetPixelColor (const Standard_Integer theX, + const Standard_Integer theY, + const NCollection_Vec4& theColor) +{ + if (IsEmpty() + || theX < 0 || Standard_Size(theX) >= SizeX() + || theY < 0 || Standard_Size(theY) >= SizeY()) + { + return; + } + + switch (myImgFormat) + { + case ImgGrayF: + { + ChangeValue (theY, theX) = theColor.r(); + return; + } + case ImgAlphaF: + { + ChangeValue (theY, theX) = theColor.a(); + return; + } + case ImgRGBAF: + { + Image_ColorRGBAF& aPixel = ChangeValue (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 (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 (theY, theX); + aPixel.r() = theColor.r(); + aPixel.g() = theColor.g(); + aPixel.b() = theColor.b(); + return; + } + case ImgBGRF: + { + Image_ColorBGRF& aPixel = ChangeValue (theY, theX); + aPixel.r() = theColor.r(); + aPixel.g() = theColor.g(); + aPixel.b() = theColor.b(); + return; + } + case ImgRGBA: + { + Image_ColorRGBA& aPixel = ChangeValue (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 (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 (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 (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 (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 (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 (theY, theX) = Standard_Byte(theColor.r() * 255.0f); + return; + } + case ImgAlpha: + { + ChangeValue (theY, theX) = Standard_Byte(theColor.a() * 255.0f); + return; + } + case ImgUNKNOWN: + { + return; + } + } +} + // ======================================================================= // function : SwapRgbaBgra // purpose : diff --git a/src/Image/Image_PixMap.hxx b/src/Image/Image_PixMap.hxx index e5c7830c07..b67d3121ef 100644 --- a/src/Image/Image_PixMap.hxx +++ b/src/Image/Image_PixMap.hxx @@ -18,7 +18,7 @@ #include #include -#include +#include //! 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 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 aColor = theColor; + SetPixelColor (theX, theY, NCollection_Vec4 (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& 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. diff --git a/src/MeshVS/FILES b/src/MeshVS/FILES index 40672f91fb..2147435121 100755 --- a/src/MeshVS/FILES +++ b/src/MeshVS/FILES @@ -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 index 075fcf08d8..0000000000 --- a/src/MeshVS/MeshVS_ColorHasher.cxx +++ /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 -#include - -//================================================================ -// 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; -} diff --git a/src/MeshVS/MeshVS_ColorHasher.hxx b/src/MeshVS/MeshVS_ColorHasher.hxx index 46b14ab2e0..5eb27c6d48 100644 --- a/src/MeshVS/MeshVS_ColorHasher.hxx +++ b/src/MeshVS/MeshVS_ColorHasher.hxx @@ -16,48 +16,9 @@ #ifndef _MeshVS_ColorHasher_HeaderFile #define _MeshVS_ColorHasher_HeaderFile -#include -#include -#include - -#include -#include -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 +Standard_DEPRECATED("This type name is deprecated - Quantity_ColorHasher should be used instead") +typedef Quantity_ColorHasher MeshVS_ColorHasher; #endif // _MeshVS_ColorHasher_HeaderFile diff --git a/src/MeshVS/MeshVS_DataMapOfColorMapOfInteger.hxx b/src/MeshVS/MeshVS_DataMapOfColorMapOfInteger.hxx index 527934bc9c..6ae3a5ecd9 100644 --- a/src/MeshVS/MeshVS_DataMapOfColorMapOfInteger.hxx +++ b/src/MeshVS/MeshVS_DataMapOfColorMapOfInteger.hxx @@ -16,13 +16,11 @@ #ifndef MeshVS_DataMapOfColorMapOfInteger_HeaderFile #define MeshVS_DataMapOfColorMapOfInteger_HeaderFile -#include +#include #include -#include #include -typedef NCollection_DataMap MeshVS_DataMapOfColorMapOfInteger; -typedef NCollection_DataMap::Iterator MeshVS_DataMapIteratorOfDataMapOfColorMapOfInteger; - +typedef NCollection_DataMap MeshVS_DataMapOfColorMapOfInteger; +typedef NCollection_DataMap::Iterator MeshVS_DataMapIteratorOfDataMapOfColorMapOfInteger; #endif diff --git a/src/Quantity/FILES b/src/Quantity/FILES index c5bd950287..2599056e51 100755 --- a/src/Quantity/FILES +++ b/src/Quantity/FILES @@ -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 index 0000000000..65fc4509f3 --- /dev/null +++ b/src/Quantity/Quantity_ColorHasher.hxx @@ -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 + +//! 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 diff --git a/src/StdSelect/FILES b/src/StdSelect/FILES index 394026ceec..8284738453 100644 --- a/src/StdSelect/FILES +++ b/src/StdSelect/FILES @@ -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 index 0000000000..d071e396b8 --- /dev/null +++ b/src/StdSelect/StdSelect_TypeOfSelectionImage.hxx @@ -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 diff --git a/src/StdSelect/StdSelect_ViewerSelector3d.cxx b/src/StdSelect/StdSelect_ViewerSelector3d.cxx index 7347948c75..c3803ba076 100644 --- a/src/StdSelect/StdSelect_ViewerSelector3d.cxx +++ b/src/StdSelect/StdSelect_ViewerSelector3d.cxx @@ -52,6 +52,10 @@ #include #include #include +#include +#include +#include +#include #include #include @@ -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 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 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 (theRow, theCol) = ShortRealLast(); + return; + } + + const SelectMgr_SortCriterion& aSortCriterion = myMainSel->PickedData (thePicked); + myUnnormImage.ChangeValue (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 (aRowIter, aColIter); + if (aDepth <= -ShortRealLast() + || aDepth >= ShortRealLast()) + { + myImage->SetPixelColor (Standard_Integer(aColIter), Standard_Integer(aRowIter), + NCollection_Vec4 (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 (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 (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 (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 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 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 (theImage.SizeX()); + const Standard_Integer aSizeY = static_cast (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; +} diff --git a/src/StdSelect/StdSelect_ViewerSelector3d.hxx b/src/StdSelect/StdSelect_ViewerSelector3d.hxx index 48c428322d..c4c093604f 100644 --- a/src/StdSelect/StdSelect_ViewerSelector3d.hxx +++ b/src/StdSelect/StdSelect_ViewerSelector3d.hxx @@ -25,7 +25,9 @@ #include #include #include +#include #include +#include 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 . Standard_EXPORT void DisplaySensitive (const Handle(V3d_View)& theView); diff --git a/src/ViewerTest/ViewerTest_ViewerCommands.cxx b/src/ViewerTest/ViewerTest_ViewerCommands.cxx index d4a1ec3f4a..417771ce22 100644 --- a/src/ViewerTest/ViewerTest_ViewerCommands.cxx +++ b/src/ViewerTest/ViewerTest_ViewerCommands.cxx @@ -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 index 0000000000..00c840c669 --- /dev/null +++ b/tests/bugs/vis/bug28205_1 @@ -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 index 0000000000..6791fa624d --- /dev/null +++ b/tests/bugs/vis/bug28205_2 @@ -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