aa50d38bbec227a54ba05ff2b8f349dfadcaebe1
[occt.git] / src / AIS / AIS_ColoredShape.cxx
1 // Created on: 2014-04-24
2 // Created by: Kirill Gavrilov
3 // Copyright (c) 2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #include <AIS_ColoredShape.hxx>
17
18 #include <AIS_InteractiveContext.hxx>
19 #include <BRep_Builder.hxx>
20 #include <BRepTools.hxx>
21 #include <gp_Pnt2d.hxx>
22 #include <Graphic3d_AspectFillArea3d.hxx>
23 #include <Graphic3d_AspectLine3d.hxx>
24 #include <Graphic3d_Group.hxx>
25 #include <Graphic3d_StructureManager.hxx>
26 #include <Graphic3d_Texture2Dmanual.hxx>
27 #include <Precision.hxx>
28 #include <Prs3d_LineAspect.hxx>
29 #include <Prs3d_IsoAspect.hxx>
30 #include <Prs3d_Presentation.hxx>
31 #include <Prs3d_ShadingAspect.hxx>
32 #include <Prs3d_Root.hxx>
33 #include <PrsMgr_PresentationManager3d.hxx>
34 #include <Standard_ErrorHandler.hxx>
35 #include <StdPrs_ShadedShape.hxx>
36 #include <StdPrs_ToolShadedShape.hxx>
37 #include <StdPrs_WFDeflectionShape.hxx>
38 #include <StdPrs_WFShape.hxx>
39 #include <TopExp_Explorer.hxx>
40 #include <TopoDS.hxx>
41 #include <TopoDS_Compound.hxx>
42 #include <TopoDS_Iterator.hxx>
43
44 IMPLEMENT_STANDARD_HANDLE (AIS_ColoredDrawer, AIS_Drawer)
45 IMPLEMENT_STANDARD_RTTIEXT(AIS_ColoredDrawer, AIS_Drawer)
46
47 IMPLEMENT_STANDARD_HANDLE (AIS_ColoredShape, AIS_Shape)
48 IMPLEMENT_STANDARD_RTTIEXT(AIS_ColoredShape, AIS_Shape)
49
50 //=======================================================================
51 //function : AIS_ColoredShape
52 //purpose  :
53 //=======================================================================
54 AIS_ColoredShape::AIS_ColoredShape (const TopoDS_Shape& theShape)
55 : AIS_Shape (theShape)
56 {
57   // disable dedicated line aspects
58   myDrawer->SetFreeBoundaryAspect  (myDrawer->LineAspect());
59   myDrawer->SetUnFreeBoundaryAspect(myDrawer->LineAspect());
60   myDrawer->SetSeenLineAspect      (myDrawer->LineAspect());
61 }
62
63 //=======================================================================
64 //function : AIS_ColoredShape
65 //purpose  :
66 //=======================================================================
67 AIS_ColoredShape::AIS_ColoredShape (const Handle(AIS_Shape)& theShape)
68 : AIS_Shape (theShape->Shape())
69 {
70   // disable dedicated line aspects
71   myDrawer->SetFreeBoundaryAspect  (myDrawer->LineAspect());
72   myDrawer->SetUnFreeBoundaryAspect(myDrawer->LineAspect());
73   myDrawer->SetSeenLineAspect      (myDrawer->LineAspect());
74   if (theShape->HasMaterial())
75   {
76     SetMaterial (theShape->Material());
77   }
78   if (theShape->HasColor())
79   {
80     SetColor (theShape->Color());
81   }
82   if (theShape->HasWidth())
83   {
84     SetWidth (theShape->Width());
85   }
86   if (theShape->IsTransparent())
87   {
88     SetTransparency (theShape->Transparency());
89   }
90 }
91
92 //=======================================================================
93 //function : CustomAspects
94 //purpose  :
95 //=======================================================================
96 Handle(AIS_ColoredDrawer) AIS_ColoredShape::CustomAspects (const TopoDS_Shape& theShape)
97 {
98   Handle(AIS_ColoredDrawer) aDrawer;
99   myShapeColors.Find (theShape, aDrawer);
100   if (aDrawer.IsNull())
101   {
102     aDrawer = new AIS_ColoredDrawer (myDrawer);
103     myShapeColors.Bind (theShape, aDrawer);
104     LoadRecomputable (AIS_WireFrame);
105     LoadRecomputable (AIS_Shaded);
106   }
107   return aDrawer;
108 }
109
110 //=======================================================================
111 //function : ClearCustomAspects
112 //purpose  :
113 //=======================================================================
114 void AIS_ColoredShape::ClearCustomAspects()
115 {
116   if (myShapeColors.IsEmpty())
117   {
118     return;
119   }
120   myShapeColors.Clear();
121   LoadRecomputable (AIS_WireFrame);
122   LoadRecomputable (AIS_Shaded);
123 }
124
125 //=======================================================================
126 //function : UnsetCustomAspects
127 //purpose  :
128 //=======================================================================
129 void AIS_ColoredShape::UnsetCustomAspects (const TopoDS_Shape&    theShape,
130                                            const Standard_Boolean theToUnregister)
131 {
132   if (!myShapeColors.IsBound (theShape))
133   {
134     return;
135   }
136
137   LoadRecomputable (AIS_WireFrame);
138   LoadRecomputable (AIS_Shaded);
139   if (theToUnregister)
140   {
141     myShapeColors.UnBind (theShape);
142     return;
143   }
144
145   myShapeColors.ChangeFind (theShape) = new AIS_ColoredDrawer (myDrawer);
146 }
147
148 //=======================================================================
149 //function : SetCustomColor
150 //purpose  :
151 //=======================================================================
152 void AIS_ColoredShape::SetCustomColor (const TopoDS_Shape&   theShape,
153                                        const Quantity_Color& theColor)
154 {
155   if (theShape.IsNull())
156   {
157     return;
158   }
159
160   const Handle(AIS_ColoredDrawer)& aDrawer = CustomAspects (theShape);
161   setColor (aDrawer, theColor);
162   aDrawer->SetOwnColor (theColor);
163   LoadRecomputable (AIS_WireFrame);
164   LoadRecomputable (AIS_Shaded);
165 }
166
167 //=======================================================================
168 //function : SetCustomWidth
169 //purpose  :
170 //=======================================================================
171 void AIS_ColoredShape::SetCustomWidth (const TopoDS_Shape& theShape,
172                                        const Standard_Real theLineWidth)
173 {
174   if (theShape.IsNull())
175   {
176     return;
177   }
178
179   const Handle(AIS_ColoredDrawer)& aDrawer = CustomAspects (theShape);
180   setWidth (CustomAspects (theShape), theLineWidth);
181   aDrawer->SetOwnWidth (theLineWidth);
182   LoadRecomputable (AIS_WireFrame);
183   LoadRecomputable (AIS_Shaded);
184 }
185
186 //=======================================================================
187 //function : SetColor
188 //purpose  :
189 //=======================================================================
190
191 void AIS_ColoredShape::SetColor (const Quantity_Color&  theColor)
192 {
193   setColor (myDrawer, theColor);
194   myOwnColor  = theColor;
195   hasOwnColor = Standard_True;
196   LoadRecomputable (AIS_WireFrame);
197   LoadRecomputable (AIS_Shaded);
198   for (DataMapOfShapeColor::Iterator anIter (myShapeColors); anIter.More(); anIter.Next())
199   {
200     const Handle(AIS_ColoredDrawer)& aDrawer = anIter.Value();
201     if (aDrawer->HasOwnColor())
202     {
203       continue;
204     }
205
206     if (aDrawer->HasShadingAspect())
207     {
208       aDrawer->ShadingAspect()->SetColor (theColor, myCurrentFacingModel);
209     }
210     if (aDrawer->HasLineAspect())
211     {
212       aDrawer->LineAspect()->SetColor (theColor);
213     }
214     if (aDrawer->HasWireAspect())
215     {
216       aDrawer->WireAspect()->SetColor (theColor);
217     }
218   }
219 }
220
221 //=======================================================================
222 //function : SetWidth
223 //purpose  :
224 //=======================================================================
225
226 void AIS_ColoredShape::SetWidth (const Standard_Real    theLineWidth)
227 {
228   setWidth (myDrawer, theLineWidth);
229   myOwnWidth = theLineWidth;
230   LoadRecomputable (AIS_WireFrame);
231   LoadRecomputable (AIS_Shaded);
232   for (DataMapOfShapeColor::Iterator anIter (myShapeColors); anIter.More(); anIter.Next())
233   {
234     const Handle(AIS_ColoredDrawer)& aDrawer = anIter.Value();
235     if (aDrawer->HasOwnWidth())
236     {
237       continue;
238     }
239
240     if (aDrawer->HasLineAspect())
241     {
242       aDrawer->LineAspect()->SetWidth (theLineWidth);
243     }
244     if (aDrawer->HasWireAspect())
245     {
246       aDrawer->WireAspect()->SetWidth (theLineWidth);
247     }
248   }
249 }
250
251 //=======================================================================
252 //function : SetTransparency
253 //purpose  :
254 //=======================================================================
255
256 void AIS_ColoredShape::SetTransparency (const Standard_Real theValue)
257 {
258   setTransparency (myDrawer, theValue);
259   myTransparency = theValue;
260   LoadRecomputable (AIS_WireFrame);
261   LoadRecomputable (AIS_Shaded);
262   for (DataMapOfShapeColor::Iterator anIter (myShapeColors); anIter.More(); anIter.Next())
263   {
264     const Handle(AIS_Drawer)& aDrawer = anIter.Value();
265     if (aDrawer->HasShadingAspect())
266     {
267       aDrawer->ShadingAspect()->SetTransparency (theValue, myCurrentFacingModel);
268     }
269   }
270 }
271
272 //=======================================================================
273 //function : Compute
274 //purpose  :
275 //=======================================================================
276 void AIS_ColoredShape::Compute (const Handle(PrsMgr_PresentationManager3d)& ,
277                                 const Handle(Prs3d_Presentation)&           thePrs,
278                                 const Standard_Integer                      theMode)
279 {
280   thePrs->Clear();
281   if (IsInfinite())
282   {
283     thePrs->SetInfiniteState (Standard_True);
284   }
285
286   const Standard_Boolean isClosed = StdPrs_ToolShadedShape::IsClosed (myshape);
287   if (theMode == AIS_Shaded)
288   {
289     // compute mesh for entire shape beforehand to ensure consistency and optimizations (parallelization)
290     Standard_Real anAnglePrev, anAngleNew, aCoeffPrev, aCoeffNew;
291     Standard_Boolean isOwnDeviationAngle       = OwnDeviationAngle      (anAngleNew, anAnglePrev);
292     Standard_Boolean isOwnDeviationCoefficient = OwnDeviationCoefficient(aCoeffNew,  aCoeffPrev);
293     if ((isOwnDeviationAngle       && Abs (anAngleNew - anAnglePrev) > Precision::Angular())
294      || (isOwnDeviationCoefficient && Abs (aCoeffNew  - aCoeffPrev)  > Precision::Confusion()))
295     {
296       BRepTools::Clean (myshape);
297     }
298     StdPrs_ShadedShape::Tessellate (myshape, myDrawer);
299   }
300
301   // 1) myShapeColors + myshape --> array[TopAbs_ShapeEnum] of map of color-to-compound
302   DataMapOfShapeCompd aTypeKeyshapeDrawshapeArray[(size_t )TopAbs_SHAPE];
303   dispatchColors (myshape, myShapeColors, aTypeKeyshapeDrawshapeArray);
304
305   // 2) finally add appropriate presentations (1 color -- 1 compound) according to theMode
306   Handle(AIS_ColoredDrawer) aCustomDrawer;
307   for (size_t aShType = 0; aShType < (size_t )TopAbs_SHAPE; ++aShType)
308   {
309     DataMapOfShapeCompd& aKeyshapeDrawshapeMap = aTypeKeyshapeDrawshapeArray[aShType];
310     for (DataMapOfShapeCompd::Iterator aMapIter (aKeyshapeDrawshapeMap);
311          aMapIter.More(); aMapIter.Next())
312     {
313       const TopoDS_Shape&    aShapeKey  = aMapIter.Key();   // key shape with detailed color or a base shape
314       const TopoDS_Compound& aShapeDraw = aMapIter.Value(); // compound of subshapes with <aShType> type
315       Handle(AIS_Drawer)     aDrawer;
316       if (myShapeColors.Find (aShapeKey, aCustomDrawer))
317       {
318         aDrawer = aCustomDrawer;
319         if (aCustomDrawer->IsHidden())
320         {
321           continue;
322         }
323       }
324       else
325       {
326         aDrawer = myDrawer;
327       }
328
329       // Draw each kind of subshapes and personal-colored shapes in a separate group
330       // since it's necessary to set transparency/material for all subshapes
331       // without affecting their unique colors
332       Handle(Graphic3d_Group) aCurrGroup = Prs3d_Root::NewGroup (thePrs);
333       switch (theMode)
334       {
335         default:
336         case AIS_Shaded:
337         {
338           if ((Standard_Integer )aShapeDraw.ShapeType() <= TopAbs_FACE
339            && !IsInfinite())
340           {
341             StdPrs_ShadedShape::Add (thePrs, aShapeDraw, aDrawer);
342
343             aDrawer->SetShadingAspectGlobal (Standard_False);
344             Handle(Graphic3d_AspectFillArea3d) anAsp = aDrawer->ShadingAspect()->Aspect();
345             isClosed ? anAsp->SuppressBackFace() : anAsp->AllowBackFace();
346             aCurrGroup->SetGroupPrimitivesAspect (anAsp);
347             break;
348           }
349           // compute wire-frame otherwise
350         }
351         case AIS_WireFrame:
352         {
353           StdPrs_WFDeflectionShape::Add (thePrs, aShapeDraw, aDrawer);
354           break;
355         }
356       }
357     }
358   }
359 }
360
361 //=======================================================================
362 //function : dispatchColors
363 //purpose  :
364 //=======================================================================
365 Standard_Boolean AIS_ColoredShape::dispatchColors (const TopoDS_Shape&        theBaseKey,
366                                                    const TopoDS_Shape&        theSubshapeToParse,
367                                                    const DataMapOfShapeShape& theSubshapeKeyshapeMap,
368                                                    const TopAbs_ShapeEnum     theParentType,
369                                                    DataMapOfShapeCompd*       theTypeKeyshapeDrawshapeArray)
370 {
371   TopAbs_ShapeEnum aShType = theSubshapeToParse.ShapeType();
372   if (aShType == TopAbs_SHAPE)
373   {
374     return Standard_False;
375   }
376
377   // check own setting of current shape
378   TopoDS_Shape     aKeyShape   = theBaseKey;
379   Standard_Boolean isOverriden = theSubshapeKeyshapeMap.Find (theSubshapeToParse, aKeyShape);
380
381   // iterate on sub-shapes
382   BRep_Builder aBBuilder;
383   TopoDS_Shape aShapeCopy = theSubshapeToParse.EmptyCopied();
384   aShapeCopy.Closed (theSubshapeToParse.Closed());
385   Standard_Boolean isSubOverride = Standard_False;
386   Standard_Integer nbDef = 0;
387   for (TopoDS_Iterator it (theSubshapeToParse); it.More(); it.Next())
388   {
389     if (dispatchColors (theBaseKey, it.Value(),
390                         theSubshapeKeyshapeMap, aShType,
391                         theTypeKeyshapeDrawshapeArray))
392     {
393       isSubOverride = Standard_True;
394     }
395     else
396     {
397       aBBuilder.Add (aShapeCopy, it.Value());
398       ++nbDef;
399     }
400   }
401   if (aShType == TopAbs_FACE || !isSubOverride)
402   {
403     aShapeCopy = theSubshapeToParse;
404   }
405   else if (nbDef == 0)
406   {
407     return isOverriden || isSubOverride; // empty compound
408   }
409
410   // if any of styles is overridden regarding to default one, add rest to map
411   if (isOverriden
412   || (isSubOverride && theParentType != TopAbs_WIRE  // avoid drawing edges when vertex color is overridden
413                     && theParentType != TopAbs_FACE) // avoid drawing edges of the same color as face
414   || (theParentType == TopAbs_SHAPE && !(isOverriden || isSubOverride))) // bind original shape to default color
415   {
416     TopoDS_Compound aCompound;
417     DataMapOfShapeCompd& aKeyshapeDrawshapeMap = theTypeKeyshapeDrawshapeArray[(size_t )aShType];
418     if (!aKeyshapeDrawshapeMap.FindFromKey (aKeyShape, aCompound))
419     {
420       aBBuilder.MakeCompound (aCompound);
421       aKeyshapeDrawshapeMap.Add (aKeyShape, aCompound);
422     }
423     aBBuilder.Add (aCompound, aShapeCopy);
424   }
425   return isOverriden || isSubOverride;
426 }
427
428 //=======================================================================
429 //function : dispatchColors
430 //purpose  :
431 //=======================================================================
432 void AIS_ColoredShape::dispatchColors (const TopoDS_Shape&        theBaseShape,
433                                        const DataMapOfShapeColor& theKeyshapeColorMap,
434                                        DataMapOfShapeCompd*       theTypeKeyshapeDrawshapeArray)
435 {
436   // Extract <theShapeColors> map (KeyshapeColored -> Color)
437   // to subshapes map (Subshape -> KeyshapeColored).
438   // This needed when colored shape is not part of <theBaseShape>
439   // (but subshapes are) and actually container for subshapes.
440   DataMapOfShapeShape aSubshapeKeyshapeMap;
441   for (DataMapOfShapeColor::Iterator anIt (theKeyshapeColorMap);
442        anIt.More(); anIt.Next())
443   {
444     const TopoDS_Shape&   aSh = anIt.Key();
445     TopAbs_ShapeEnum    aType = aSh.ShapeType();
446     TopAbs_ShapeEnum aSubType = (aType == TopAbs_SOLID || aType == TopAbs_SHELL)
447                               ? TopAbs_FACE
448                               : (aType == TopAbs_WIRE ? TopAbs_EDGE : TopAbs_SHAPE);
449     switch (aSubType)
450     {
451       case TopAbs_SHAPE:
452       {
453         aSubshapeKeyshapeMap.Bind (aSh, aSh);
454         break;
455       }
456       default:
457       {
458         for (TopExp_Explorer anExp (aSh, aSubType); anExp.More(); anExp.Next())
459         {
460           if (!aSubshapeKeyshapeMap.IsBound (anExp.Current()))
461           {
462             aSubshapeKeyshapeMap.Bind (anExp.Current(), aSh);
463           }
464         }
465       }
466     }
467   }
468
469   // Fill the array of maps per shape type
470   dispatchColors (theBaseShape, theBaseShape,
471                   aSubshapeKeyshapeMap, TopAbs_SHAPE,
472                   theTypeKeyshapeDrawshapeArray);
473 }