1 // Copyright (c) 2020 OPEN CASCADE SAS
2 //
3 // This file is part of Open CASCADE Technology software library.
4 //
5 // This library is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU Lesser General Public License version 2.1 as published
7 // by the Free Software Foundation, with special exception defined in the file
8 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9 // distribution for complete text of the license and disclaimer of any warranty.
10 //
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
13 
14 #include <SelectMgr_SelectionImageFiller.hxx>
15 
16 #include <SelectMgr_ViewerSelector.hxx>
17 
18 namespace
19 {
20   //! Help class for filling pixel with random color.
21   class GeneratedEntityColorFiller : public SelectMgr_SelectionImageFiller
22   {
23   public:
GeneratedEntityColorFiller(Image_PixMap & thePixMap,SelectMgr_ViewerSelector * theSelector)24     GeneratedEntityColorFiller (Image_PixMap& thePixMap,
25                                 SelectMgr_ViewerSelector* theSelector)
26     : SelectMgr_SelectionImageFiller (thePixMap, theSelector)
27     {
28       // generate per-entity colors in the order as they have been activated
29       for (SelectMgr_SelectableObjectSet::Iterator anObjIter (theSelector->SelectableObjects()); anObjIter.More(); anObjIter.Next())
30       {
31         const Handle(SelectMgr_SelectableObject)& anObj = anObjIter.Value();
32         for (SelectMgr_SequenceOfSelection::Iterator aSelIter (anObj->Selections()); aSelIter.More(); aSelIter.Next())
33         {
34           const Handle(SelectMgr_Selection)& aSel = aSelIter.Value();
35           for (NCollection_Vector<Handle(SelectMgr_SensitiveEntity)>::Iterator aSelEntIter (aSel->Entities()); aSelEntIter.More(); aSelEntIter.Next())
36           {
37             const Handle(SelectMgr_SensitiveEntity)& aSens = aSelEntIter.Value();
38             if (!myMapEntityColors.IsBound (aSens->BaseSensitive()))
39             {
40               Quantity_Color aColor;
41               randomPastelColor (aColor);
42               myMapEntityColors.Bind (aSens->BaseSensitive(), aColor);
43             }
44           }
45         }
46       }
47     }
48 
Fill(const Standard_Integer theCol,const Standard_Integer theRow,const Standard_Integer thePicked)49     virtual void Fill (const Standard_Integer theCol,
50                        const Standard_Integer theRow,
51                        const Standard_Integer thePicked) Standard_OVERRIDE
52     {
53       if (thePicked < 1
54        || thePicked > myMainSel->NbPicked())
55       {
56         myImage->SetPixelColor (theCol, theRow, Quantity_Color(Quantity_NOC_BLACK));
57         return;
58       }
59 
60       const Handle(Select3D_SensitiveEntity)& aPickedEntity = myMainSel->PickedEntity (thePicked);
61       Quantity_Color aColor (Quantity_NOC_BLACK);
62       myMapEntityColors.Find (aPickedEntity, aColor);
63       myImage->SetPixelColor (theCol, theRow, aColor);
64     }
65 
66   protected:
67     NCollection_DataMap<Handle(Select3D_SensitiveEntity), Quantity_Color> myMapEntityColors;
68   };
69 
70   //! Help class for filling pixel with random color.
71   class GeneratedEntityTypeColorFiller : public SelectMgr_SelectionImageFiller
72   {
73   public:
GeneratedEntityTypeColorFiller(Image_PixMap & thePixMap,SelectMgr_ViewerSelector * theSelector)74     GeneratedEntityTypeColorFiller (Image_PixMap& thePixMap,
75                                     SelectMgr_ViewerSelector* theSelector)
76     : SelectMgr_SelectionImageFiller (thePixMap, theSelector)
77     {
78       // generate per-entity colors in the order as they have been activated
79       for (SelectMgr_SelectableObjectSet::Iterator anObjIter (theSelector->SelectableObjects()); anObjIter.More(); anObjIter.Next())
80       {
81         const Handle(SelectMgr_SelectableObject)& anObj = anObjIter.Value();
82         for (SelectMgr_SequenceOfSelection::Iterator aSelIter (anObj->Selections()); aSelIter.More(); aSelIter.Next())
83         {
84           const Handle(SelectMgr_Selection)& aSel = aSelIter.Value();
85           for (NCollection_Vector<Handle(SelectMgr_SensitiveEntity)>::Iterator aSelEntIter (aSel->Entities()); aSelEntIter.More(); aSelEntIter.Next())
86           {
87             const Handle(SelectMgr_SensitiveEntity)& aSens = aSelEntIter.Value();
88             if (!myMapEntityColors.IsBound (aSens->BaseSensitive()->DynamicType()))
89             {
90               Quantity_Color aColor;
91               randomPastelColor (aColor);
92               myMapEntityColors.Bind (aSens->BaseSensitive()->DynamicType(), aColor);
93             }
94           }
95         }
96       }
97     }
98 
Fill(const Standard_Integer theCol,const Standard_Integer theRow,const Standard_Integer thePicked)99     virtual void Fill (const Standard_Integer theCol,
100                        const Standard_Integer theRow,
101                        const Standard_Integer thePicked) Standard_OVERRIDE
102     {
103       if (thePicked < 1
104        || thePicked > myMainSel->NbPicked())
105       {
106         myImage->SetPixelColor (theCol, theRow, Quantity_Color(Quantity_NOC_BLACK));
107         return;
108       }
109 
110       const Handle(Select3D_SensitiveEntity)& aPickedEntity = myMainSel->PickedEntity (thePicked);
111       Quantity_Color aColor (Quantity_NOC_BLACK);
112       myMapEntityColors.Find (aPickedEntity->DynamicType(), aColor);
113       myImage->SetPixelColor (theCol, theRow, aColor);
114     }
115 
116   protected:
117     NCollection_DataMap<Handle(Standard_Type), Quantity_Color> myMapEntityColors;
118   };
119 
120   //! Help class for filling pixel with normalized depth of ray.
121   class NormalizedDepthFiller : public SelectMgr_SelectionImageFiller
122   {
123   public:
NormalizedDepthFiller(Image_PixMap & thePixMap,SelectMgr_ViewerSelector * theSelector,const Standard_Boolean theToInverse)124     NormalizedDepthFiller (Image_PixMap& thePixMap,
125                            SelectMgr_ViewerSelector* theSelector,
126                            const Standard_Boolean theToInverse)
127     : SelectMgr_SelectionImageFiller (thePixMap, theSelector),
128       myDepthMin ( RealLast()),
129       myDepthMax (-RealLast()),
130       myToInverse(theToInverse)
131     {
132       myUnnormImage.InitZero (Image_Format_GrayF, thePixMap.SizeX(), thePixMap.SizeY());
133     }
134 
135     //! Accumulate the data.
Fill(const Standard_Integer theCol,const Standard_Integer theRow,const Standard_Integer thePicked)136     virtual void Fill (const Standard_Integer theCol,
137                        const Standard_Integer theRow,
138                        const Standard_Integer thePicked) Standard_OVERRIDE
139     {
140       if (myUnnormImage.IsEmpty())
141       {
142         return;
143       }
144 
145       if (thePicked < 1
146        || thePicked > myMainSel->NbPicked())
147       {
148         myUnnormImage.ChangeValue<float> (theRow, theCol) = ShortRealLast();
149         return;
150       }
151 
152       const SelectMgr_SortCriterion& aSortCriterion = myMainSel->PickedData (thePicked);
153       myUnnormImage.ChangeValue<float> (theRow, theCol) = float(aSortCriterion.Depth);
154       myDepthMin = Min (myDepthMin, aSortCriterion.Depth);
155       myDepthMax = Max (myDepthMax, aSortCriterion.Depth);
156     }
157 
158     //! Normalize the depth values.
Flush()159     virtual void Flush() Standard_OVERRIDE
160     {
161       float aFrom  = 0.0f;
162       float aDelta = 1.0f;
163       if (myDepthMin <= myDepthMax)
164       {
165         aFrom  = float(myDepthMin);
166         aDelta = float(myDepthMax) - float(myDepthMin);
167         if (aDelta <= ShortRealEpsilon())
168         {
169           aDelta = 1.0f;
170         }
171       }
172       for (Standard_Size aRowIter = 0; aRowIter < myUnnormImage.SizeY(); ++aRowIter)
173       {
174         for (Standard_Size aColIter = 0; aColIter < myUnnormImage.SizeX(); ++aColIter)
175         {
176           float aDepth = myUnnormImage.Value<float> (aRowIter, aColIter);
177           if (aDepth <= -ShortRealLast()
178            || aDepth >=  ShortRealLast())
179           {
180             myImage->SetPixelColor (Standard_Integer(aColIter), Standard_Integer(aRowIter),
181                                     Quantity_ColorRGBA (0.0f, 0.0f, 0.0f, 1.0f));
182             continue;
183           }
184 
185           float aNormDepth = (aDepth - aFrom) / aDelta;
186           if (myToInverse)
187           {
188             aNormDepth = 1.0f - aNormDepth;
189           }
190           myImage->SetPixelColor (Standard_Integer(aColIter), Standard_Integer(aRowIter),
191                                   Quantity_ColorRGBA (aNormDepth, aNormDepth, aNormDepth, 1.0f));
192         }
193       }
194     }
195 
196   private:
197     Image_PixMap     myUnnormImage;
198     Standard_Real    myDepthMin;
199     Standard_Real    myDepthMax;
200     Standard_Boolean myToInverse;
201   };
202 
203   //! Help class for filling pixel with unnormalized depth of ray.
204   class UnnormalizedDepthFiller : public SelectMgr_SelectionImageFiller
205   {
206   public:
UnnormalizedDepthFiller(Image_PixMap & thePixMap,SelectMgr_ViewerSelector * theSelector)207     UnnormalizedDepthFiller (Image_PixMap& thePixMap,
208                              SelectMgr_ViewerSelector* theSelector)
209     : SelectMgr_SelectionImageFiller (thePixMap, theSelector) {}
210 
Fill(const Standard_Integer theCol,const Standard_Integer theRow,const Standard_Integer thePicked)211     virtual void Fill (const Standard_Integer theCol,
212                        const Standard_Integer theRow,
213                        const Standard_Integer thePicked) Standard_OVERRIDE
214     {
215       if (thePicked < 1
216        || thePicked > myMainSel->NbPicked())
217       {
218         myImage->SetPixelColor (theCol, theRow, Quantity_ColorRGBA (0.0f, 0.0f, 0.0f, 1.0f));
219         return;
220       }
221 
222       const SelectMgr_SortCriterion& aSortCriterion = myMainSel->PickedData (thePicked);
223       const float aDepth = float(aSortCriterion.Depth);
224       myImage->SetPixelColor (theCol, theRow, Quantity_ColorRGBA (Graphic3d_Vec4 (aDepth, aDepth, aDepth, 1.0f)));
225     }
226   };
227 
228   //! Help class for filling pixel with color of detected object.
229   class GeneratedOwnerColorFiller : public SelectMgr_SelectionImageFiller
230   {
231   public:
GeneratedOwnerColorFiller(Image_PixMap & thePixMap,SelectMgr_ViewerSelector * theSelector)232     GeneratedOwnerColorFiller (Image_PixMap& thePixMap,
233                                SelectMgr_ViewerSelector* theSelector)
234     : SelectMgr_SelectionImageFiller (thePixMap, theSelector)
235     {
236       // generate per-owner colors in the order as they have been activated
237       for (SelectMgr_SelectableObjectSet::Iterator anObjIter (theSelector->SelectableObjects()); anObjIter.More(); anObjIter.Next())
238       {
239         const Handle(SelectMgr_SelectableObject)& anObj = anObjIter.Value();
240         for (SelectMgr_SequenceOfSelection::Iterator aSelIter (anObj->Selections()); aSelIter.More(); aSelIter.Next())
241         {
242           const Handle(SelectMgr_Selection)& aSel = aSelIter.Value();
243           for (NCollection_Vector<Handle(SelectMgr_SensitiveEntity)>::Iterator aSelEntIter (aSel->Entities()); aSelEntIter.More(); aSelEntIter.Next())
244           {
245             const Handle(SelectMgr_SensitiveEntity)& aSens = aSelEntIter.Value();
246             const Handle(SelectMgr_EntityOwner)&   anOwner = aSens->BaseSensitive()->OwnerId();
247             if (!myMapOwnerColors.IsBound (anOwner))
248             {
249               Quantity_Color aColor;
250               randomPastelColor (aColor);
251               myMapOwnerColors.Bind (anOwner, aColor);
252             }
253           }
254         }
255       }
256     }
257 
Fill(const Standard_Integer theCol,const Standard_Integer theRow,const Standard_Integer thePicked)258     virtual void Fill (const Standard_Integer theCol,
259                        const Standard_Integer theRow,
260                        const Standard_Integer thePicked) Standard_OVERRIDE
261     {
262       if (thePicked < 1
263        || thePicked > myMainSel->NbPicked())
264       {
265         myImage->SetPixelColor (theCol, theRow, Quantity_Color(Quantity_NOC_BLACK));
266         return;
267       }
268 
269       const Handle(SelectMgr_EntityOwner)& aPickedOwner = myMainSel->Picked (thePicked);
270       Quantity_Color aColor (Quantity_NOC_BLACK);
271       myMapOwnerColors.Find (aPickedOwner, aColor);
272       myImage->SetPixelColor (theCol, theRow, aColor);
273     }
274 
275   protected:
276     NCollection_DataMap<Handle(SelectMgr_EntityOwner), Quantity_Color> myMapOwnerColors;
277   };
278 
279   //! Help class for filling pixel with random color for each selection mode.
280   class GeneratedSelModeColorFiller : public SelectMgr_SelectionImageFiller
281   {
282   public:
GeneratedSelModeColorFiller(Image_PixMap & thePixMap,SelectMgr_ViewerSelector * theSelector)283     GeneratedSelModeColorFiller (Image_PixMap& thePixMap,
284                                  SelectMgr_ViewerSelector* theSelector)
285     : SelectMgr_SelectionImageFiller (thePixMap, theSelector)
286     {
287       // generate standard modes in proper order, consider custom objects would use similar scheme
288       myMapSelectionModeColors.Bind (     0, Quantity_NOC_WHITE);          // default (entire object selection)
289       myMapSelectionModeColors.Bind (     1, Quantity_NOC_YELLOW);         // TopAbs_VERTEX
290       myMapSelectionModeColors.Bind (     2, Quantity_NOC_GREEN);          // TopAbs_EDGE
291       myMapSelectionModeColors.Bind (     3, Quantity_NOC_RED);            // TopAbs_WIRE
292       myMapSelectionModeColors.Bind (     4, Quantity_NOC_BLUE1);          // TopAbs_FACE
293       myMapSelectionModeColors.Bind (     5, Quantity_NOC_CYAN1);          // TopAbs_SHELL
294       myMapSelectionModeColors.Bind (     6, Quantity_NOC_PURPLE);         // TopAbs_SOLID
295       myMapSelectionModeColors.Bind (     7, Quantity_NOC_MAGENTA1);       // TopAbs_COMPSOLID
296       myMapSelectionModeColors.Bind (     8, Quantity_NOC_BROWN);          // TopAbs_COMPOUND
297       myMapSelectionModeColors.Bind (0x0010, Quantity_NOC_PINK);           // MeshVS_SMF_Volume
298       myMapSelectionModeColors.Bind (0x001E, Quantity_NOC_LIMEGREEN);      // MeshVS_SMF_Element
299       myMapSelectionModeColors.Bind (0x001F, Quantity_NOC_DARKOLIVEGREEN); // MeshVS_SMF_All
300       myMapSelectionModeColors.Bind (0x0100, Quantity_NOC_GOLD);           // MeshVS_SMF_Group
301     }
302 
Fill(const Standard_Integer theCol,const Standard_Integer theRow,const Standard_Integer thePicked)303     virtual void Fill (const Standard_Integer theCol,
304                        const Standard_Integer theRow,
305                        const Standard_Integer thePicked) Standard_OVERRIDE
306     {
307       if (thePicked < 1
308        || thePicked > myMainSel->NbPicked())
309       {
310         myImage->SetPixelColor (theCol, theRow, Quantity_Color (Quantity_NOC_BLACK));
311         return;
312       }
313 
314       Standard_Integer aSelectionMode = -1;
315       const Handle(SelectMgr_SelectableObject)& aSelectable = myMainSel->Picked       (thePicked)->Selectable();
316       const Handle(Select3D_SensitiveEntity)&   anEntity    = myMainSel->PickedEntity (thePicked);
317       for (SelectMgr_SequenceOfSelection::Iterator aSelIter (aSelectable->Selections()); aSelIter.More(); aSelIter.Next())
318       {
319         const Handle(SelectMgr_Selection)& aSelection = aSelIter.Value();
320         for (NCollection_Vector<Handle(SelectMgr_SensitiveEntity)>::Iterator aSelEntIter (aSelection->Entities()); aSelEntIter.More(); aSelEntIter.Next())
321         {
322           if (aSelEntIter.Value()->BaseSensitive() == anEntity)
323           {
324             aSelectionMode = aSelection->Mode();
325             break;
326           }
327         }
328       }
329       if (aSelectionMode == -1)
330       {
331         myImage->SetPixelColor (theCol, theRow, Quantity_Color (Quantity_NOC_BLACK));
332         return;
333       }
334 
335       if (!myMapSelectionModeColors.IsBound (aSelectionMode))
336       {
337         Quantity_Color aColor;
338         randomPastelColor (aColor);
339         myMapSelectionModeColors.Bind (aSelectionMode, aColor);
340       }
341 
342       const Quantity_Color& aColor = myMapSelectionModeColors.Find (aSelectionMode);
343       myImage->SetPixelColor (theCol, theRow, aColor);
344     }
345 
346   protected:
347     NCollection_DataMap<Standard_Integer, Quantity_Color> myMapSelectionModeColors;
348   };
349 
350   //! Help class for filling pixel with color of detected shape.
351   class DetectedObjectColorFiller : public SelectMgr_SelectionImageFiller
352   {
353   public:
DetectedObjectColorFiller(Image_PixMap & thePixMap,SelectMgr_ViewerSelector * theSelector)354     DetectedObjectColorFiller (Image_PixMap& thePixMap,
355                                SelectMgr_ViewerSelector* theSelector)
356     : SelectMgr_SelectionImageFiller (thePixMap, theSelector) {}
357 
Fill(const Standard_Integer theCol,const Standard_Integer theRow,const Standard_Integer thePicked)358     virtual void Fill (const Standard_Integer theCol,
359                        const Standard_Integer theRow,
360                        const Standard_Integer thePicked) Standard_OVERRIDE
361     {
362       Quantity_Color aColor (Quantity_NOC_BLACK);
363       if (thePicked > 0
364        && thePicked <= myMainSel->NbPicked())
365       {
366         const Handle(SelectMgr_SelectableObject)& aSelectable = myMainSel->Picked (thePicked)->Selectable();
367         aColor = aSelectable->Attributes()->Color();
368       }
369       myImage->SetPixelColor (theCol, theRow, aColor);
370     }
371   };
372 
373   //! Help class for filling pixel with normal direction value.
374   class SurfaceNormalFiller : public SelectMgr_SelectionImageFiller
375   {
376   public:
SurfaceNormalFiller(Image_PixMap & thePixMap,SelectMgr_ViewerSelector * theSelector)377     SurfaceNormalFiller (Image_PixMap& thePixMap,
378                          SelectMgr_ViewerSelector* theSelector)
379     : SelectMgr_SelectionImageFiller (thePixMap, theSelector) {}
380 
Fill(const Standard_Integer theCol,const Standard_Integer theRow,const Standard_Integer thePicked)381     virtual void Fill (const Standard_Integer theCol,
382                        const Standard_Integer theRow,
383                        const Standard_Integer thePicked) Standard_OVERRIDE
384     {
385       if (thePicked <= 0
386        || thePicked > myMainSel->NbPicked())
387       {
388         myImage->SetPixelColor (theCol, theRow, Quantity_NOC_BLACK);
389       }
390       else
391       {
392         const SelectMgr_SortCriterion& aPickedData = myMainSel->PickedData (thePicked);
393         Graphic3d_Vec3 aNormal = aPickedData.Normal;
394         aNormal.Normalize();
395         if (aNormal.Modulus() > 0.0f)
396         {
397           myImage->SetPixelColor (theCol, theRow, Quantity_ColorRGBA (aNormal.x() * 0.5f + 0.5f,
398                                                                       aNormal.y() * 0.5f + 0.5f,
399                                                                       aNormal.z() * 0.5f + 0.5f, 1.0f));
400         }
401         else
402         {
403           myImage->SetPixelColor (theCol, theRow, Quantity_NOC_BLACK);
404         }
405       }
406     }
407   };
408 }
409 
410 // =======================================================================
411 // function : CreateFiller
412 // purpose  :
413 // =======================================================================
Handle(SelectMgr_SelectionImageFiller)414 Handle(SelectMgr_SelectionImageFiller) SelectMgr_SelectionImageFiller::CreateFiller (Image_PixMap& thePixMap,
415                                                                                      SelectMgr_ViewerSelector* theSelector,
416                                                                                      StdSelect_TypeOfSelectionImage theType)
417 {
418   switch (theType)
419   {
420     case StdSelect_TypeOfSelectionImage_NormalizedDepth:
421     case StdSelect_TypeOfSelectionImage_NormalizedDepthInverted:
422     {
423       return new NormalizedDepthFiller (thePixMap, theSelector, theType == StdSelect_TypeOfSelectionImage_NormalizedDepthInverted);
424     }
425     case StdSelect_TypeOfSelectionImage_UnnormalizedDepth:
426     {
427       return new UnnormalizedDepthFiller (thePixMap, theSelector);
428     }
429     case StdSelect_TypeOfSelectionImage_ColoredDetectedObject:
430     {
431       return new DetectedObjectColorFiller (thePixMap, theSelector);
432     }
433     case StdSelect_TypeOfSelectionImage_ColoredEntity:
434     {
435       return new GeneratedEntityColorFiller (thePixMap, theSelector);
436     }
437     case StdSelect_TypeOfSelectionImage_ColoredEntityType:
438     {
439       return new GeneratedEntityTypeColorFiller (thePixMap, theSelector);
440     }
441     case StdSelect_TypeOfSelectionImage_ColoredOwner:
442     {
443       return new GeneratedOwnerColorFiller (thePixMap, theSelector);
444     }
445     case StdSelect_TypeOfSelectionImage_ColoredSelectionMode:
446     {
447       return new GeneratedSelModeColorFiller (thePixMap, theSelector);
448     }
449     case StdSelect_TypeOfSelectionImage_SurfaceNormal:
450     {
451       return new SurfaceNormalFiller (thePixMap, theSelector);
452     }
453   }
454   return Handle(SelectMgr_SelectionImageFiller)();
455 }
456