0031682: Visualization - Prs3d_ShadingAspect::SetTransparency() has no effect with...
[occt.git] / src / V3d / V3d_Viewer.cxx
CommitLineData
973c2be1 1// Copyright (c) 1999-2014 OPEN CASCADE SAS
b311480e 2//
973c2be1 3// This file is part of Open CASCADE Technology software library.
b311480e 4//
d5f74e42 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
973c2be1 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.
b311480e 10//
973c2be1 11// Alternatively, this file may be used under the terms of Open CASCADE
12// commercial license or contractual agreement.
b311480e 13
6a24c6de 14#include <V3d_Viewer.hxx>
42cf5bc1 15
42cf5bc1 16#include <Aspect_Grid.hxx>
c357e426 17#include <Aspect_IdentDefinitionError.hxx>
67b3d2a8 18#include <Graphic3d_ArrayOfSegments.hxx>
19#include <Graphic3d_AspectLine3d.hxx>
42cf5bc1 20#include <Graphic3d_AspectMarker3d.hxx>
67b3d2a8 21#include <Graphic3d_AspectText3d.hxx>
42cf5bc1 22#include <Graphic3d_GraphicDriver.hxx>
23#include <Graphic3d_Group.hxx>
24#include <Graphic3d_Structure.hxx>
8ed07085 25#include <Graphic3d_Text.hxx>
c357e426 26#include <Standard_ErrorHandler.hxx>
42cf5bc1 27#include <Standard_Type.hxx>
7fd59977 28#include <V3d.hxx>
6942f04a 29#include <V3d_BadValue.hxx>
42cf5bc1 30#include <V3d_CircularGrid.hxx>
6a24c6de 31#include <V3d_AmbientLight.hxx>
32#include <V3d_DirectionalLight.hxx>
42cf5bc1 33#include <V3d_RectangularGrid.hxx>
34#include <V3d_View.hxx>
7fd59977 35
6a24c6de 36IMPLEMENT_STANDARD_RTTIEXT(V3d_Viewer, Standard_Transient)
37
38// ========================================================================
39// function : V3d_Viewer
40// purpose :
41// ========================================================================
42V3d_Viewer::V3d_Viewer (const Handle(Graphic3d_GraphicDriver)& theDriver)
43: myDriver (theDriver),
44 myStructureManager (new Graphic3d_StructureManager (theDriver)),
45 myZLayerGenId (1, IntegerLast()),
46 myBackground (Quantity_NOC_GRAY30),
47 myViewSize (1000.0),
48 myViewProj (V3d_XposYnegZpos),
49 myVisualization (V3d_ZBUFFER),
dc89236f 50 myShadingModel (Graphic3d_TOSM_VERTEX),
6a24c6de 51 myDefaultTypeOfView (V3d_ORTHOGRAPHIC),
52 myComputedMode (Standard_True),
53 myDefaultComputedMode (Standard_False),
54 myPrivilegedPlane (gp_Ax3 (gp_Pnt (0.,0.,0), gp_Dir (0.,0.,1.), gp_Dir (1.,0.,0.))),
55 myDisplayPlane (Standard_False),
56 myDisplayPlaneLength (1000.0),
57 myGridType (Aspect_GT_Rectangular),
58 myGridEcho (Standard_True),
59 myGridEchoLastVert (ShortRealLast(), ShortRealLast(), ShortRealLast())
60{
61 myRGrid = new V3d_RectangularGrid (this, Quantity_Color (Quantity_NOC_GRAY50), Quantity_Color (Quantity_NOC_GRAY70));
62 myCGrid = new V3d_CircularGrid (this, Quantity_Color (Quantity_NOC_GRAY50), Quantity_Color (Quantity_NOC_GRAY70));
63}
92efcf78 64
c357e426 65// ========================================================================
66// function : V3d_Viewer
67// purpose :
68// ========================================================================
6942f04a 69V3d_Viewer::V3d_Viewer (const Handle(Graphic3d_GraphicDriver)& theDriver,
6a24c6de 70 const Standard_ExtString ,
71 const Standard_CString ,
dc89236f 72 const Standard_Real theViewSize,
73 const V3d_TypeOfOrientation theViewProj,
74 const Quantity_Color& theViewBackground,
75 const V3d_TypeOfVisualization theVisualization,
76 const Graphic3d_TypeOfShadingModel theShadingModel,
77 const Standard_Boolean theComputedMode,
78 const Standard_Boolean theDefaultComputedMode)
6a24c6de 79: myDriver (theDriver),
80 myStructureManager (new Graphic3d_StructureManager (theDriver)),
81 myZLayerGenId (1, IntegerLast()),
82 myBackground (theViewBackground),
83 myViewSize (theViewSize),
84 myViewProj (theViewProj),
85 myVisualization (theVisualization),
86 myShadingModel (theShadingModel),
87 myDefaultTypeOfView (V3d_ORTHOGRAPHIC),
88 myComputedMode (theComputedMode),
89 myDefaultComputedMode (theDefaultComputedMode),
90 myPrivilegedPlane (gp_Ax3 (gp_Pnt (0.,0.,0), gp_Dir (0.,0.,1.), gp_Dir (1.,0.,0.))),
91 myDisplayPlane (Standard_False),
92 myDisplayPlaneLength (theViewSize),
93 myGridType (Aspect_GT_Rectangular),
94 myGridEcho (Standard_True),
95 myGridEchoLastVert (ShortRealLast(), ShortRealLast(), ShortRealLast())
96{
97 myRGrid = new V3d_RectangularGrid (this, Quantity_Color (Quantity_NOC_GRAY50), Quantity_Color (Quantity_NOC_GRAY70));
98 myCGrid = new V3d_CircularGrid (this, Quantity_Color (Quantity_NOC_GRAY50), Quantity_Color (Quantity_NOC_GRAY70));
6942f04a 99 SetDefaultViewSize (theViewSize);
7fd59977 100}
101
c357e426 102// ========================================================================
103// function : CreateView
104// purpose :
105// ========================================================================
b5ac8292 106Handle(V3d_View) V3d_Viewer::CreateView ()
107{
6a24c6de 108 return new V3d_View(this, myDefaultTypeOfView);
7fd59977 109}
110
c357e426 111// ========================================================================
112// function : SetViewOn
113// purpose :
114// ========================================================================
115void V3d_Viewer::SetViewOn()
116{
6a24c6de 117 for (V3d_ListOfView::Iterator aDefViewIter (myDefinedViews); aDefViewIter.More(); aDefViewIter.Next())
c357e426 118 {
6a24c6de 119 SetViewOn (aDefViewIter.Value());
c357e426 120 }
7fd59977 121}
122
c357e426 123// ========================================================================
124// function : SetViewOff
125// purpose :
126// ========================================================================
127void V3d_Viewer::SetViewOff()
128{
6a24c6de 129 for (V3d_ListOfView::Iterator aDefViewIter (myDefinedViews); aDefViewIter.More(); aDefViewIter.Next())
c357e426 130 {
6a24c6de 131 SetViewOff (aDefViewIter.Value());
c357e426 132 }
7fd59977 133}
134
c357e426 135// ========================================================================
136// function : SetViewOn
137// purpose :
138// ========================================================================
139void V3d_Viewer::SetViewOn (const Handle(V3d_View)& theView)
140{
141 Handle(Graphic3d_CView) aViewImpl = theView->View();
6a24c6de 142 if (!aViewImpl->IsDefined() || myActiveViews.Contains (theView))
c357e426 143 {
6a24c6de 144 return;
145 }
c357e426 146
6a24c6de 147 myActiveViews.Append (theView);
148 aViewImpl->Activate();
149 for (V3d_ListOfLight::Iterator anActiveLightIter (myActiveLights); anActiveLightIter.More(); anActiveLightIter.Next())
150 {
151 theView->SetLightOn (anActiveLightIter.Value());
7fd59977 152 }
6a24c6de 153
154 theView->SetGrid (myPrivilegedPlane, Grid ());
155 theView->SetGridActivity (Grid ()->IsActive ());
39235bed 156 if (theView->SetImmediateUpdate (Standard_False))
157 {
158 theView->Redraw();
159 theView->SetImmediateUpdate (Standard_True);
160 }
7fd59977 161}
162
c357e426 163// ========================================================================
164// function : SetViewOff
165// purpose :
166// ========================================================================
167void V3d_Viewer::SetViewOff (const Handle(V3d_View)& theView)
168{
169 Handle(Graphic3d_CView) aViewImpl = theView->View();
6a24c6de 170 if (aViewImpl->IsDefined() && myActiveViews.Contains (theView))
c357e426 171 {
6a24c6de 172 myActiveViews.Remove (theView);
c357e426 173 aViewImpl->Deactivate() ;
7fd59977 174 }
175}
176
c357e426 177// ========================================================================
178// function : Redraw
179// purpose :
180// ========================================================================
6a24c6de 181void V3d_Viewer::Redraw() const
679ecdee 182{
6a24c6de 183 for (V3d_ListOfView::Iterator aDefViewIter (myDefinedViews); aDefViewIter.More(); aDefViewIter.Next())
c357e426 184 {
6a24c6de 185 aDefViewIter.Value()->Redraw();
c357e426 186 }
7fd59977 187}
188
c357e426 189// ========================================================================
190// function : RedrawImmediate
191// purpose :
192// ========================================================================
679ecdee 193void V3d_Viewer::RedrawImmediate() const
194{
6a24c6de 195 for (V3d_ListOfView::Iterator aDefViewIter (myDefinedViews); aDefViewIter.More(); aDefViewIter.Next())
c357e426 196 {
6a24c6de 197 aDefViewIter.Value()->RedrawImmediate();
c357e426 198 }
679ecdee 199}
200
c357e426 201// ========================================================================
202// function : Invalidate
203// purpose :
204// ========================================================================
679ecdee 205void V3d_Viewer::Invalidate() const
206{
6a24c6de 207 for (V3d_ListOfView::Iterator aDefViewIter (myDefinedViews); aDefViewIter.More(); aDefViewIter.Next())
c357e426 208 {
6a24c6de 209 aDefViewIter.Value()->Invalidate();
c357e426 210 }
679ecdee 211}
212
c357e426 213// ========================================================================
214// function : Remove
215// purpose :
216// ========================================================================
217void V3d_Viewer::Remove()
218{
219 myStructureManager->Remove();
7fd59977 220}
221
c357e426 222// ========================================================================
223// function : Erase
224// purpose :
225// ========================================================================
226void V3d_Viewer::Erase() const
227{
228 myStructureManager->Erase();
7fd59977 229}
230
c357e426 231// ========================================================================
232// function : UnHighlight
233// purpose :
234// ========================================================================
235void V3d_Viewer::UnHighlight() const
236{
237 myStructureManager->UnHighlight();
7fd59977 238}
239
6a24c6de 240void V3d_Viewer::SetDefaultViewSize (const Standard_Real theSize)
b8ddfc2f 241{
9775fa61 242 if (theSize <= 0.0)
243 throw V3d_BadValue("V3d_Viewer::SetDefaultViewSize, bad size");
6a24c6de 244 myViewSize = theSize;
7fd59977 245}
246
c357e426 247// ========================================================================
6a24c6de 248// function : IfMoreViews
c357e426 249// purpose :
250// ========================================================================
6a24c6de 251Standard_Boolean V3d_Viewer::IfMoreViews() const
c357e426 252{
6a24c6de 253 return myDefinedViews.Size() < myStructureManager->MaxNumOfViews();
7fd59977 254}
255
6a24c6de 256// ========================================================================
257// function : AddView
258// purpose :
259// ========================================================================
260void V3d_Viewer::AddView (const Handle(V3d_View)& theView)
261{
262 if (!myDefinedViews.Contains (theView))
263 {
264 myDefinedViews.Append (theView);
265 }
7fd59977 266}
267
6a24c6de 268// ========================================================================
269// function : DelView
270// purpose :
271// ========================================================================
272void V3d_Viewer::DelView (const Handle(V3d_View)& theView)
273{
274 myActiveViews.Remove (theView);
275 myDefinedViews.Remove (theView);
7fd59977 276}
277
c5751993 278//=======================================================================
1c728f2d 279//function : InsertLayerBefore
c5751993 280//purpose :
281//=======================================================================
1c728f2d 282Standard_Boolean V3d_Viewer::InsertLayerBefore (Graphic3d_ZLayerId& theNewLayerId,
283 const Graphic3d_ZLayerSettings& theSettings,
284 const Graphic3d_ZLayerId theLayerAfter)
c5751993 285{
1c728f2d 286 if (myZLayerGenId.Next (theNewLayerId))
c357e426 287 {
1c728f2d 288 myLayerIds.Add (theNewLayerId);
289 myDriver->InsertLayerBefore (theNewLayerId, theSettings, theLayerAfter);
290 return Standard_True;
c357e426 291 }
1c728f2d 292 return Standard_False;
293}
294
295//=======================================================================
296//function : InsertLayerAfter
297//purpose :
298//=======================================================================
299Standard_Boolean V3d_Viewer::InsertLayerAfter (Graphic3d_ZLayerId& theNewLayerId,
300 const Graphic3d_ZLayerSettings& theSettings,
301 const Graphic3d_ZLayerId theLayerBefore)
302{
303 if (myZLayerGenId.Next (theNewLayerId))
c357e426 304 {
1c728f2d 305 myLayerIds.Add (theNewLayerId);
306 myDriver->InsertLayerAfter (theNewLayerId, theSettings, theLayerBefore);
307 return Standard_True;
c357e426 308 }
1c728f2d 309 return Standard_False;
c5751993 310}
311
312//=======================================================================
c357e426 313//function : RemoveZLayer
314//purpose :
c5751993 315//=======================================================================
8f138407 316Standard_Boolean V3d_Viewer::RemoveZLayer (const Graphic3d_ZLayerId theLayerId)
c5751993 317{
c357e426 318 if (!myLayerIds.Contains (theLayerId)
319 || theLayerId < myZLayerGenId.Lower()
320 || theLayerId > myZLayerGenId.Upper())
321 {
322 return Standard_False;
323 }
324
325 myDriver->RemoveZLayer (theLayerId);
326 myLayerIds.Remove (theLayerId);
327 myZLayerGenId.Free (theLayerId);
328
329 return Standard_True;
c5751993 330}
331
59f45b7c 332//=======================================================================
c357e426 333//function : GetAllZLayers
59f45b7c 334//purpose :
335//=======================================================================
c357e426 336void V3d_Viewer::GetAllZLayers (TColStd_SequenceOfInteger& theLayerSeq) const
59f45b7c 337{
c357e426 338 myDriver->ZLayers (theLayerSeq);
59f45b7c 339}
340
341//=======================================================================
c357e426 342//function : SetZLayerSettings
343//purpose :
59f45b7c 344//=======================================================================
8f138407 345void V3d_Viewer::SetZLayerSettings (const Graphic3d_ZLayerId theLayerId, const Graphic3d_ZLayerSettings& theSettings)
59f45b7c 346{
c357e426 347 myDriver->SetZLayerSettings (theLayerId, theSettings);
59f45b7c 348}
349
350//=======================================================================
c357e426 351//function : ZLayerSettings
59f45b7c 352//purpose :
353//=======================================================================
1c728f2d 354const Graphic3d_ZLayerSettings& V3d_Viewer::ZLayerSettings (const Graphic3d_ZLayerId theLayerId) const
59f45b7c 355{
c357e426 356 return myDriver->ZLayerSettings (theLayerId);
59f45b7c 357}
6942f04a 358
359//=======================================================================
6a24c6de 360//function : UpdateLights
361//purpose :
362//=======================================================================
363void V3d_Viewer::UpdateLights()
364{
365 for (V3d_ListOfView::Iterator anActiveViewIter (myActiveViews); anActiveViewIter.More(); anActiveViewIter.Next())
366 {
367 anActiveViewIter.Value()->UpdateLights();
368 }
369}
370
371//=======================================================================
372//function : SetLightOn
6942f04a 373//purpose :
374//=======================================================================
6a24c6de 375void V3d_Viewer::SetLightOn (const Handle(V3d_Light)& theLight)
6942f04a 376{
6a24c6de 377 if (!myActiveLights.Contains (theLight))
378 {
379 myActiveLights.Append (theLight);
380 }
381
382 for (V3d_ListOfView::Iterator anActiveViewIter (myActiveViews); anActiveViewIter.More(); anActiveViewIter.Next())
383 {
384 anActiveViewIter.Value()->SetLightOn (theLight);
385 }
6942f04a 386}
387
388//=======================================================================
6a24c6de 389//function : SetLightOff
6942f04a 390//purpose :
391//=======================================================================
6a24c6de 392void V3d_Viewer::SetLightOff (const Handle(V3d_Light)& theLight)
6942f04a 393{
6a24c6de 394 myActiveLights.Remove (theLight);
395 for (V3d_ListOfView::Iterator anActiveViewIter (myActiveViews); anActiveViewIter.More(); anActiveViewIter.Next())
396 {
397 anActiveViewIter.Value()->SetLightOff (theLight);
398 }
6942f04a 399}
400
401//=======================================================================
6a24c6de 402//function : SetLightOn
6942f04a 403//purpose :
404//=======================================================================
6a24c6de 405void V3d_Viewer::SetLightOn()
6942f04a 406{
6a24c6de 407 for (V3d_ListOfLight::Iterator aDefLightIter (myDefinedLights); aDefLightIter.More(); aDefLightIter.Next())
408 {
409 if (!myActiveLights.Contains (aDefLightIter.Value()))
410 {
411 myActiveLights.Append (aDefLightIter.Value());
412 for (V3d_ListOfView::Iterator anActiveViewIter (myActiveViews); anActiveViewIter.More(); anActiveViewIter.Next())
413 {
414 anActiveViewIter.Value()->SetLightOn (aDefLightIter.Value());
415 }
416 }
417 }
6942f04a 418}
419
420//=======================================================================
6a24c6de 421//function : SetLightOff
6942f04a 422//purpose :
423//=======================================================================
6a24c6de 424void V3d_Viewer::SetLightOff()
6942f04a 425{
6a24c6de 426 for (V3d_ListOfLight::Iterator anActiveLightIter (myActiveLights); anActiveLightIter.More(); anActiveLightIter.Next())
427 {
428 for (V3d_ListOfView::Iterator anActiveViewIter (myActiveViews); anActiveViewIter.More(); anActiveViewIter.Next())
429 {
430 anActiveViewIter.Value()->SetLightOff (anActiveLightIter.Value());
431 }
432 }
433 myActiveLights.Clear();
973c2be1 434}
832ae82d 435
436//=======================================================================
6a24c6de 437//function : IsGlobalLight
832ae82d 438//purpose :
439//=======================================================================
6a24c6de 440Standard_Boolean V3d_Viewer::IsGlobalLight (const Handle(V3d_Light)& theLight) const
832ae82d 441{
6a24c6de 442 return myActiveLights.Contains (theLight);
832ae82d 443}
444
445//=======================================================================
6a24c6de 446//function : AddLight
832ae82d 447//purpose :
448//=======================================================================
6a24c6de 449void V3d_Viewer::AddLight (const Handle(V3d_Light)& theLight)
832ae82d 450{
6a24c6de 451 if (!myDefinedLights.Contains (theLight))
452 {
453 myDefinedLights.Append (theLight);
454 }
455}
456
457//=======================================================================
458//function : DelLight
459//purpose :
460//=======================================================================
461void V3d_Viewer::DelLight (const Handle(V3d_Light)& theLight)
462{
463 SetLightOff (theLight);
464 myDefinedLights.Remove (theLight);
465}
466
467//=======================================================================
468//function : SetDefaultLights
469//purpose :
470//=======================================================================
471void V3d_Viewer::SetDefaultLights()
472{
473 while (!myDefinedLights.IsEmpty())
474 {
475 Handle(V3d_Light) aLight = myDefinedLights.First();
476 DelLight (aLight);
477 }
478
992ed6b3 479 Handle(V3d_DirectionalLight) aDirLight = new V3d_DirectionalLight (V3d_Zneg, Quantity_NOC_WHITE, Standard_True);
480 Handle(V3d_AmbientLight) anAmbLight = new V3d_AmbientLight (Quantity_NOC_WHITE);
481 AddLight (aDirLight);
482 AddLight (anAmbLight);
483 SetLightOn (aDirLight);
484 SetLightOn (anAmbLight);
832ae82d 485}
67b3d2a8 486
487//=======================================================================
488//function : SetPrivilegedPlane
489//purpose :
490//=======================================================================
491void V3d_Viewer::SetPrivilegedPlane (const gp_Ax3& thePlane)
492{
493 myPrivilegedPlane = thePlane;
494 Grid()->SetDrawMode(Grid()->DrawMode());
495 for (V3d_ListOfView::Iterator anActiveViewIter (myActiveViews); anActiveViewIter.More(); anActiveViewIter.Next())
496 {
497 anActiveViewIter.Value()->SetGrid (myPrivilegedPlane, Grid());
498 }
499
500 if (myDisplayPlane)
501 {
502 DisplayPrivilegedPlane (Standard_True, myDisplayPlaneLength);
503 }
504}
505
506//=======================================================================
507//function : DisplayPrivilegedPlane
508//purpose :
509//=======================================================================
510void V3d_Viewer::DisplayPrivilegedPlane (const Standard_Boolean theOnOff, const Standard_Real theSize)
511{
512 myDisplayPlane = theOnOff;
513 myDisplayPlaneLength = theSize;
514
515 if (!myDisplayPlane)
516 {
517 if (!myPlaneStructure.IsNull())
518 {
519 myPlaneStructure->Erase();
520 }
521 return;
522 }
523
524 if (myPlaneStructure.IsNull())
525 {
526 myPlaneStructure = new Graphic3d_Structure (StructureManager());
527 myPlaneStructure->SetInfiniteState (Standard_True);
528 myPlaneStructure->Display();
529 }
530 else
531 {
532 myPlaneStructure->Clear();
533 }
534
535 Handle(Graphic3d_Group) aGroup = myPlaneStructure->NewGroup();
536
537 Handle(Graphic3d_AspectLine3d) aLineAttrib = new Graphic3d_AspectLine3d (Quantity_NOC_GRAY60, Aspect_TOL_SOLID, 1.0);
538 aGroup->SetGroupPrimitivesAspect (aLineAttrib);
539
540 Handle(Graphic3d_AspectText3d) aTextAttrib = new Graphic3d_AspectText3d();
541 aTextAttrib->SetColor (Quantity_Color (Quantity_NOC_ROYALBLUE1));
542 aGroup->SetGroupPrimitivesAspect (aTextAttrib);
543
544 Handle(Graphic3d_ArrayOfSegments) aPrims = new Graphic3d_ArrayOfSegments (6);
545
546 const gp_Pnt& p0 = myPrivilegedPlane.Location();
547
548 const gp_Pnt pX (p0.XYZ() + myDisplayPlaneLength * myPrivilegedPlane.XDirection().XYZ());
549 aPrims->AddVertex (p0);
550 aPrims->AddVertex (pX);
8ed07085 551 Handle(Graphic3d_Text) aText = new Graphic3d_Text (1.0f / 81.0f);
552 aText->SetText ("X");
553 aText->SetPosition (pX);
554 aGroup->AddText (aText);
67b3d2a8 555
556 const gp_Pnt pY (p0.XYZ() + myDisplayPlaneLength * myPrivilegedPlane.YDirection().XYZ());
557 aPrims->AddVertex (p0);
558 aPrims->AddVertex (pY);
8ed07085 559 aText = new Graphic3d_Text (1.0f / 81.0f);
560 aText->SetText ("Y");
561 aText->SetPosition (pY);
562 aGroup->AddText (aText);
67b3d2a8 563
564 const gp_Pnt pZ (p0.XYZ() + myDisplayPlaneLength * myPrivilegedPlane.Direction().XYZ());
565 aPrims->AddVertex (p0);
566 aPrims->AddVertex (pZ);
8ed07085 567 aText = new Graphic3d_Text (1.0f / 81.0f);
568 aText->SetText ("Z");
569 aText->SetPosition (pZ);
570 aGroup->AddText (aText);
67b3d2a8 571
572 aGroup->AddPrimitiveArray (aPrims);
573
574 myPlaneStructure->Display();
575}
bc73b006 576
577//=======================================================================
578//function : DumpJson
579//purpose :
580//=======================================================================
581void V3d_Viewer::DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth) const
582{
583 OCCT_DUMP_TRANSIENT_CLASS_BEGIN (theOStream)
584
585 OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myPrivilegedPlane)
586}