// Copyright (c) 1995-1999 Matra Datavision
// Copyright (c) 1999-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.

#ifndef _Prs3d_Drawer_HeaderFile
#define _Prs3d_Drawer_HeaderFile

#include <Standard.hxx>

#include <Standard_Integer.hxx>
#include <Aspect_TypeOfDeflection.hxx>
#include <Graphic3d_GroupAspect.hxx>
#include <Graphic3d_PresentationAttributes.hxx>
#include <Graphic3d_ShaderProgram.hxx>
#include <Standard_Real.hxx>
#include <Prs3d_VertexDrawMode.hxx>
#include <Prs3d_DimensionUnits.hxx>
#include <Prs3d_TypeOfHLR.hxx>
#include <Standard_Transient.hxx>
#include <GeomAbs_Shape.hxx>

class Prs3d_IsoAspect;
class Prs3d_LineAspect;
class Prs3d_TextAspect;
class Prs3d_ShadingAspect;
class Prs3d_PointAspect;
class Prs3d_PlaneAspect;
class Prs3d_ArrowAspect;
class Prs3d_DatumAspect;
class Prs3d_DimensionAspect;
class TCollection_AsciiString;

//! A graphic attribute manager which governs how
//! objects such as color, width, line thickness and deflection are displayed.
//! A drawer includes an instance of the Aspect classes with particular default values.
class Prs3d_Drawer : public Graphic3d_PresentationAttributes
{
  DEFINE_STANDARD_RTTIEXT(Prs3d_Drawer, Graphic3d_PresentationAttributes)
public:
  //! Default constructor.
  Standard_EXPORT Prs3d_Drawer();

  //! Setup all own aspects with default values.
  Standard_EXPORT void SetupOwnDefaults();

  //! Sets the type of chordal deflection.
  //! This indicates whether the deflection value is absolute or relative to the size of the object.
  Standard_EXPORT void SetTypeOfDeflection(const Aspect_TypeOfDeflection theTypeOfDeflection);

  //! Returns the type of chordal deflection.
  //! This indicates whether the deflection value is absolute or relative to the size of the object.
  Aspect_TypeOfDeflection TypeOfDeflection() const
  {
    return myHasOwnTypeOfDeflection || myLink.IsNull() ? myTypeOfDeflection
                                                       : myLink->TypeOfDeflection();
  }

  //! Returns true if the drawer has a type of deflection setting active.
  bool HasOwnTypeOfDeflection() const { return myHasOwnTypeOfDeflection; }

  //! Resets HasOwnTypeOfDeflection() flag, e.g. undoes SetTypeOfDeflection().
  void UnsetOwnTypeOfDeflection()
  {
    myHasOwnTypeOfDeflection = false;
    myTypeOfDeflection       = Aspect_TOD_RELATIVE;
  }

  //! Defines the maximal chordial deviation when drawing any curve.
  //! Even if the type of deviation is set to TOD_Relative, this value is used by:
  //!   Prs3d_DeflectionCurve
  //!   Prs3d_WFDeflectionSurface
  //!   Prs3d_WFDeflectionRestrictedFace
  void SetMaximalChordialDeviation(const double theChordialDeviation)
  {
    myChordialDeviation = theChordialDeviation;
  }

  //! Returns the maximal chordal deviation. The default value is 0.0001.
  //! Drawings of curves or patches are made with respect to an absolute maximal chordal deviation.
  double MaximalChordialDeviation() const
  {
    return myChordialDeviation > 0.0
             ? myChordialDeviation
             : (!myLink.IsNull() ? myLink->MaximalChordialDeviation() : 0.0001);
  }

  //! Returns true if the drawer has a maximal chordial deviation setting active.
  bool HasOwnMaximalChordialDeviation() const { return myChordialDeviation > 0.0; }

  //! Resets HasOwnMaximalChordialDeviation() flag, e.g. undoes SetMaximalChordialDeviation().
  void UnsetOwnMaximalChordialDeviation() { myChordialDeviation = -1.0; }

  //! Sets the type of HLR algorithm used by drawer's interactive objects
  Standard_EXPORT void SetTypeOfHLR(const Prs3d_TypeOfHLR theTypeOfHLR);

  //! Returns the type of HLR algorithm currently in use.
  Standard_EXPORT Prs3d_TypeOfHLR TypeOfHLR() const;

  //! Returns true if the type of HLR is not equal to Prs3d_TOH_NotSet.
  bool HasOwnTypeOfHLR() const { return (myTypeOfHLR != Prs3d_TOH_NotSet); }

  //! Defines the maximum value allowed for the first and last
  //! parameters of an infinite curve.
  void SetMaximalParameterValue(const double theValue) { myMaximalParameterValue = theValue; }

  //! Sets the maximum value allowed for the first and last parameters of an infinite curve.
  //! By default, this value is 500000.
  double MaximalParameterValue() const
  {
    return myMaximalParameterValue > 0.0
             ? myMaximalParameterValue
             : (!myLink.IsNull() ? myLink->MaximalParameterValue() : 500000.0);
  }

  //! Returns true if the drawer has a maximum value allowed for the first and last
  //! parameters of an infinite curve setting active.
  bool HasOwnMaximalParameterValue() const { return myMaximalParameterValue > 0.0; }

  //! Resets HasOwnMaximalParameterValue() flag, e.g. undoes SetMaximalParameterValue().
  void UnsetOwnMaximalParameterValue() { myMaximalParameterValue = -1.0; }

  //! Sets IsoOnPlane on or off by setting the parameter theIsEnabled to true or false.
  Standard_EXPORT void SetIsoOnPlane(const bool theIsEnabled);

  //! Returns True if the drawing of isos on planes is enabled.
  bool IsoOnPlane() const
  {
    return myHasOwnIsoOnPlane || myLink.IsNull() ? myIsoOnPlane : myLink->IsoOnPlane();
  }

  //! Returns true if the drawer has IsoOnPlane setting active.
  bool HasOwnIsoOnPlane() const { return myHasOwnIsoOnPlane; }

  //! Resets HasOwnIsoOnPlane() flag, e.g. undoes SetIsoOnPlane().
  void UnsetOwnIsoOnPlane()
  {
    myHasOwnIsoOnPlane = false;
    myIsoOnPlane       = false;
  }

  //! Returns True if the drawing of isos on triangulation is enabled.
  bool IsoOnTriangulation() const
  {
    return myHasOwnIsoOnTriangulation || myLink.IsNull() ? myIsoOnTriangulation
                                                         : myLink->IsoOnTriangulation();
  }

  //! Returns true if the drawer has IsoOnTriangulation setting active.
  bool HasOwnIsoOnTriangulation() const { return myHasOwnIsoOnTriangulation; }

  //! Resets HasOwnIsoOnTriangulation() flag, e.g. undoes SetIsoOnTriangulation().
  void UnsetOwnIsoOnTriangulation()
  {
    myHasOwnIsoOnTriangulation = false;
    myIsoOnTriangulation       = false;
  }

  //! Enables or disables isolines on triangulation by setting the parameter theIsEnabled to true or
  //! false.
  Standard_EXPORT void SetIsoOnTriangulation(const bool theToEnable);

  //! Sets the discretisation parameter theValue.
  void SetDiscretisation(const int theValue) { myNbPoints = theValue; }

  //! Returns the discretisation setting.
  int Discretisation() const
  {
    return myNbPoints != -1 ? myNbPoints : (!myLink.IsNull() ? myLink->Discretisation() : 30);
  }

  //! Returns true if the drawer has discretisation setting active.
  bool HasOwnDiscretisation() const { return myNbPoints != -1; }

  //! Resets HasOwnDiscretisation() flag, e.g. undoes SetDiscretisation().
  void UnsetOwnDiscretisation() { myNbPoints = -1; }

  //! Sets the deviation coefficient theCoefficient.
  //! Also sets the hasOwnDeviationCoefficient flag to true and
  //! myPreviousDeviationCoefficient
  Standard_EXPORT void SetDeviationCoefficient(const double theCoefficient);

  //! Returns the deviation coefficient.
  //! Drawings of curves or patches are made with respect
  //! to a maximal chordal deviation. A Deviation coefficient
  //! is used in the shading display mode. The shape is
  //! seen decomposed into triangles. These are used to
  //! calculate reflection of light from the surface of the
  //! object. The triangles are formed from chords of the
  //! curves in the shape. The deviation coefficient gives
  //! the highest value of the angle with which a chord can
  //! deviate from a tangent to a curve. If this limit is
  //! reached, a new triangle is begun.
  //! This deviation is absolute and is set through the
  //! method: SetMaximalChordialDeviation. The default value is 0.001.
  //! In drawing shapes, however, you are allowed to ask
  //! for a relative deviation. This deviation will be:
  //! SizeOfObject * DeviationCoefficient.
  double DeviationCoefficient() const
  {
    return myDeviationCoefficient > 0.0
             ? myDeviationCoefficient
             : (!myLink.IsNull() ? myLink->DeviationCoefficient() : 0.001);
  }

  //! Resets HasOwnDeviationCoefficient() flag, e.g. undoes previous SetDeviationCoefficient().
  void SetDeviationCoefficient() { myDeviationCoefficient = -1.0; }

  //! Returns true if there is a local setting for deviation
  //! coefficient in this framework for a specific interactive object.
  bool HasOwnDeviationCoefficient() const { return myDeviationCoefficient > 0.0; }

  //! Saves the previous value used for the chordal
  //! deviation coefficient.
  double PreviousDeviationCoefficient() const
  {
    return HasOwnDeviationCoefficient() ? myPreviousDeviationCoefficient : 0.0;
  }

  //! Updates the previous value used for the chordal deviation coefficient to the current state.
  void UpdatePreviousDeviationCoefficient()
  {
    if (HasOwnDeviationCoefficient())
    {
      myPreviousDeviationCoefficient = DeviationCoefficient();
    }
  }

  //! Sets the deviation angle theAngle.
  //! Also sets the hasOwnDeviationAngle flag to true, and myPreviousDeviationAngle.
  Standard_EXPORT void SetDeviationAngle(const double theAngle);

  //! Returns the value for deviation angle in radians, 20 * M_PI / 180 by default.
  double DeviationAngle() const
  {
    return myDeviationAngle > 0.0
             ? myDeviationAngle
             : (!myLink.IsNull() ? myLink->DeviationAngle() : 20.0 * M_PI / 180.0);
  }

  //! Resets HasOwnDeviationAngle() flag, e.g. undoes previous SetDeviationAngle().
  void SetDeviationAngle() { myDeviationAngle = -1.0; }

  //! Returns true if there is a local setting for deviation
  //! angle in this framework for a specific interactive object.
  bool HasOwnDeviationAngle() const { return myDeviationAngle > 0.0; }

  //! Returns the previous deviation angle
  double PreviousDeviationAngle() const
  {
    return HasOwnDeviationAngle() ? myPreviousDeviationAngle : 0.0;
  }

  //! Updates the previous deviation angle to the current value
  void UpdatePreviousDeviationAngle()
  {
    if (HasOwnDeviationAngle())
    {
      myPreviousDeviationAngle = DeviationAngle();
    }
  }

  //! Sets IsAutoTriangulated on or off by setting the parameter theIsEnabled to true or false.
  //! If this flag is True automatic re-triangulation with deflection-check logic will be applied.
  //! Else this feature will be disable and triangulation is expected to be computed by application
  //! itself and no shading presentation at all if unavailable.
  Standard_EXPORT void SetAutoTriangulation(const bool theIsEnabled);

  //! Returns True if automatic triangulation is enabled.
  bool IsAutoTriangulation() const
  {
    return myHasOwnIsAutoTriangulated || myLink.IsNull() ? myIsAutoTriangulated
                                                         : myLink->IsAutoTriangulation();
  }

  //! Returns true if the drawer has IsoOnPlane setting active.
  bool HasOwnIsAutoTriangulation() const { return myHasOwnIsAutoTriangulated; }

  //! Resets HasOwnIsAutoTriangulation() flag, e.g. undoes SetAutoTriangulation().
  void UnsetOwnIsAutoTriangulation()
  {
    myHasOwnIsAutoTriangulated = false;
    myIsAutoTriangulated       = true;
  }

  //! Defines own attributes for drawing an U isoparametric curve of a face,
  //! settings from linked Drawer or NULL if neither was set.
  //!
  //! These attributes are used by the following algorithms:
  //!   Prs3d_WFDeflectionSurface
  //!   Prs3d_WFDeflectionRestrictedFace
  Standard_EXPORT const occ::handle<Prs3d_IsoAspect>& UIsoAspect() const;

  void SetUIsoAspect(const occ::handle<Prs3d_IsoAspect>& theAspect) { myUIsoAspect = theAspect; }

  //! Returns true if the drawer has its own attribute for
  //! UIso aspect that overrides the one in the link.
  bool HasOwnUIsoAspect() const { return !myUIsoAspect.IsNull(); }

  //! Defines own attributes for drawing an V isoparametric curve of a face,
  //! settings from linked Drawer or NULL if neither was set.
  //!
  //! These attributes are used by the following algorithms:
  //!   Prs3d_WFDeflectionSurface
  //!   Prs3d_WFDeflectionRestrictedFace
  Standard_EXPORT const occ::handle<Prs3d_IsoAspect>& VIsoAspect() const;

  //! Sets the appearance of V isoparameters - theAspect.
  void SetVIsoAspect(const occ::handle<Prs3d_IsoAspect>& theAspect) { myVIsoAspect = theAspect; }

  //! Returns true if the drawer has its own attribute for
  //! VIso aspect that overrides the one in the link.
  bool HasOwnVIsoAspect() const { return !myVIsoAspect.IsNull(); }

  //! Returns own wire aspect settings, settings from linked Drawer or NULL if neither was set.
  //! These attributes are used by the algorithm Prs3d_WFShape.
  Standard_EXPORT const occ::handle<Prs3d_LineAspect>& WireAspect() const;

  //! Sets the parameter theAspect for display of wires.
  void SetWireAspect(const occ::handle<Prs3d_LineAspect>& theAspect) { myWireAspect = theAspect; }

  //! Returns true if the drawer has its own attribute for
  //! wire aspect that overrides the one in the link.
  bool HasOwnWireAspect() const { return !myWireAspect.IsNull(); }

  //! Sets WireDraw on or off by setting the parameter theIsEnabled to true or false.
  Standard_EXPORT void SetWireDraw(const bool theIsEnabled);

  //! Returns True if the drawing of the wire is enabled.
  bool WireDraw() const
  {
    return myHasOwnWireDraw || myLink.IsNull() ? myWireDraw : myLink->WireDraw();
  }

  //! Returns true if the drawer has its own attribute for
  //! "draw wires" flag that overrides the one in the link.
  bool HasOwnWireDraw() const { return myHasOwnWireDraw; }

  //! Resets HasOwnWireDraw() flag, e.g. undoes SetWireDraw().
  void UnsetOwnWireDraw()
  {
    myHasOwnWireDraw = false;
    myWireDraw       = true;
  }

  //! Returns own point aspect setting, settings from linked Drawer or NULL if neither was set.
  //! These attributes are used by the algorithms Prs3d_Point.
  Standard_EXPORT const occ::handle<Prs3d_PointAspect>& PointAspect() const;

  //! Sets the parameter theAspect for display attributes of points
  void SetPointAspect(const occ::handle<Prs3d_PointAspect>& theAspect)
  {
    myPointAspect = theAspect;
  }

  //! Returns true if the drawer has its own attribute for
  //! point aspect that overrides the one in the link.
  bool HasOwnPointAspect() const { return !myPointAspect.IsNull(); }

  //! Sets own point aspect, which is a yellow Aspect_TOM_PLUS marker by default.
  //! Returns FALSE if the drawer already has its own attribute for point aspect.
  Standard_EXPORT bool SetupOwnPointAspect(
    const occ::handle<Prs3d_Drawer>& theDefaults = occ::handle<Prs3d_Drawer>());

  //! Returns own settings for line aspects, settings from linked Drawer or NULL if neither was set.
  //! These attributes are used by the following algorithms:
  //!   Prs3d_Curve
  //!   Prs3d_Line
  //!   Prs3d_HLRShape
  Standard_EXPORT const occ::handle<Prs3d_LineAspect>& LineAspect() const;

  //! Sets the parameter theAspect for display attributes of lines.
  void SetLineAspect(const occ::handle<Prs3d_LineAspect>& theAspect) { myLineAspect = theAspect; }

  //! Returns true if the drawer has its own attribute for
  //! line aspect that overrides the one in the link.
  bool HasOwnLineAspect() const { return !myLineAspect.IsNull(); }

  //! Sets own line aspects, which are
  //! single U and single V gray75 solid isolines (::UIsoAspect(), ::VIsoAspect()),
  //! red wire (::WireAspect()), yellow line (::LineAspect()),
  //! yellow seen line (::SeenLineAspect()), dashed yellow hidden line (::HiddenLineAspect()),
  //! green free boundary (::FreeBoundaryAspect()), yellow unfree boundary
  //! (::UnFreeBoundaryAspect()). Returns FALSE if own line aspect are already set.
  Standard_EXPORT bool SetOwnLineAspects(
    const occ::handle<Prs3d_Drawer>& theDefaults = occ::handle<Prs3d_Drawer>());

  //! Sets own line aspects for datums.
  //! Returns FALSE if own line for datums are already set.
  Standard_EXPORT bool SetOwnDatumAspects(
    const occ::handle<Prs3d_Drawer>& theDefaults = occ::handle<Prs3d_Drawer>());

  //! Returns own settings for text aspect, settings from linked Drawer or NULL if neither was set.
  Standard_EXPORT const occ::handle<Prs3d_TextAspect>& TextAspect() const;

  //! Sets the parameter theAspect for display attributes of text.
  void SetTextAspect(const occ::handle<Prs3d_TextAspect>& theAspect) { myTextAspect = theAspect; }

  //! Returns true if the drawer has its own attribute for
  //! text aspect that overrides the one in the link.
  bool HasOwnTextAspect() const { return !myTextAspect.IsNull(); }

  //! Returns own settings for shading aspects, settings from linked Drawer or NULL if neither was
  //! set.
  Standard_EXPORT const occ::handle<Prs3d_ShadingAspect>& ShadingAspect() const;

  //! Sets the parameter theAspect for display attributes of shading.
  void SetShadingAspect(const occ::handle<Prs3d_ShadingAspect>& theAspect)
  {
    myShadingAspect = theAspect;
  }

  //! Returns true if the drawer has its own attribute for
  //! shading aspect that overrides the one in the link.
  bool HasOwnShadingAspect() const { return !myShadingAspect.IsNull(); }

  //! Sets own shading aspect, which is Graphic3d_NameOfMaterial_Brass material by default.
  //! Returns FALSE if the drawer already has its own attribute for shading aspect.
  Standard_EXPORT bool SetupOwnShadingAspect(
    const occ::handle<Prs3d_Drawer>& theDefaults = occ::handle<Prs3d_Drawer>());

  //! Returns own settings for seen line aspects, settings of linked Drawer or NULL if neither was
  //! set.
  Standard_EXPORT const occ::handle<Prs3d_LineAspect>& SeenLineAspect() const;

  //! Sets the parameter theAspect for the display of seen lines in hidden line removal mode.
  void SetSeenLineAspect(const occ::handle<Prs3d_LineAspect>& theAspect)
  {
    mySeenLineAspect = theAspect;
  }

  //! Returns true if the drawer has its own attribute for
  //! seen line aspect that overrides the one in the link.
  bool HasOwnSeenLineAspect() const { return !mySeenLineAspect.IsNull(); }

  //! Returns own settings for the appearance of planes, settings from linked Drawer or NULL if
  //! neither was set.
  Standard_EXPORT const occ::handle<Prs3d_PlaneAspect>& PlaneAspect() const;

  //! Sets the parameter theAspect for the display of planes.
  void SetPlaneAspect(const occ::handle<Prs3d_PlaneAspect>& theAspect)
  {
    myPlaneAspect = theAspect;
  }

  //! Returns true if the drawer has its own attribute for
  //! plane aspect that overrides the one in the link.
  bool HasOwnPlaneAspect() const { return !myPlaneAspect.IsNull(); }

  //! Returns own attributes for display of arrows, settings from linked Drawer or NULL if neither
  //! was set.
  Standard_EXPORT const occ::handle<Prs3d_ArrowAspect>& ArrowAspect() const;

  //! Sets the parameter theAspect for display attributes of arrows.
  void SetArrowAspect(const occ::handle<Prs3d_ArrowAspect>& theAspect)
  {
    myArrowAspect = theAspect;
  }

  //! Returns true if the drawer has its own attribute for
  //! arrow aspect that overrides the one in the link.
  bool HasOwnArrowAspect() const { return !myArrowAspect.IsNull(); }

  //! Enables the drawing of an arrow at the end of each line.
  //! By default the arrows are not drawn.
  Standard_EXPORT void SetLineArrowDraw(const bool theIsEnabled);

  //! Returns True if drawing an arrow at the end of each edge is enabled
  //! and False otherwise (the default).
  bool LineArrowDraw() const
  {
    return myHasOwnLineArrowDraw || myLink.IsNull() ? myLineArrowDraw : myLink->LineArrowDraw();
  }

  //! Returns true if the drawer has its own attribute for
  //! "draw arrow" flag that overrides the one in the link.
  bool HasOwnLineArrowDraw() const { return myHasOwnLineArrowDraw; }

  //! Reset HasOwnLineArrowDraw() flag, e.g. undoes SetLineArrowDraw().
  void UnsetOwnLineArrowDraw()
  {
    myHasOwnLineArrowDraw = false;
    myLineArrowDraw       = false;
  }

  //! Returns own settings for hidden line aspects, settings from linked Drawer or NULL if neither
  //! was set.
  Standard_EXPORT const occ::handle<Prs3d_LineAspect>& HiddenLineAspect() const;

  //! Sets the parameter theAspect for the display of hidden lines in hidden line removal mode.
  void SetHiddenLineAspect(const occ::handle<Prs3d_LineAspect>& theAspect)
  {
    myHiddenLineAspect = theAspect;
  }

  //! Returns true if the drawer has its own attribute for
  //! hidden lines aspect that overrides the one in the link.
  bool HasOwnHiddenLineAspect() const { return !myHiddenLineAspect.IsNull(); }

  //! Returns true if the hidden lines are to be drawn.
  //! By default the hidden lines are not drawn.
  bool DrawHiddenLine() const
  {
    return myHasOwnDrawHiddenLine || myLink.IsNull() ? myDrawHiddenLine : myLink->DrawHiddenLine();
  }

  //! Enables the DrawHiddenLine function.
  Standard_EXPORT void EnableDrawHiddenLine();

  //! Disables the DrawHiddenLine function.
  Standard_EXPORT void DisableDrawHiddenLine();

  //! Returns true if the drawer has its own attribute for
  //! "draw hidden lines" flag that overrides the one in the link.
  bool HasOwnDrawHiddenLine() const { return myHasOwnDrawHiddenLine; }

  //! Resets HasOwnDrawHiddenLine() flag, e.g. unsets
  //! EnableDrawHiddenLine()/DisableDrawHiddenLine().
  void UnsetOwnDrawHiddenLine()
  {
    myHasOwnDrawHiddenLine = false;
    myDrawHiddenLine       = false;
  }

  //! Returns own settings for the appearance of vectors, settings from linked Drawer or NULL if
  //! neither was set.
  Standard_EXPORT const occ::handle<Prs3d_LineAspect>& VectorAspect() const;

  //! Sets the modality theAspect for the display of vectors.
  void SetVectorAspect(const occ::handle<Prs3d_LineAspect>& theAspect)
  {
    myVectorAspect = theAspect;
  }

  //! Returns true if the drawer has its own attribute for
  //! vector aspect that overrides the one in the link.
  bool HasOwnVectorAspect() const { return !myVectorAspect.IsNull(); }

  //! Sets the mode of visualization of vertices of a TopoDS_Shape instance.
  //! By default, only stand-alone vertices (not belonging topologically to an edge) are drawn,
  //! that corresponds to Prs3d_VDM_Standalone mode.
  //! Switching to Prs3d_VDM_Standalone mode makes all shape's vertices visible.
  //! To inherit this parameter from the global drawer instance ("the link") when it is present,
  //! Prs3d_VDM_Inherited value should be used.
  Standard_EXPORT void SetVertexDrawMode(const Prs3d_VertexDrawMode theMode);

  //! Returns the current mode of visualization of vertices of a TopoDS_Shape instance.
  Standard_EXPORT Prs3d_VertexDrawMode VertexDrawMode() const;

  //! Returns true if the vertex draw mode is not equal to <b>Prs3d_VDM_Inherited</b>.
  //! This means that individual vertex draw mode value (i.e. not inherited from the global
  //! drawer) is used for a specific interactive object.
  bool HasOwnVertexDrawMode() const { return (myVertexDrawMode != Prs3d_VDM_Inherited); }

  //! Returns own settings for the appearance of datums, settings from linked Drawer or NULL if
  //! neither was set.
  Standard_EXPORT const occ::handle<Prs3d_DatumAspect>& DatumAspect() const;

  //! Sets the modality theAspect for the display of datums.
  void SetDatumAspect(const occ::handle<Prs3d_DatumAspect>& theAspect)
  {
    myDatumAspect = theAspect;
  }

  //! Returns true if the drawer has its own attribute for
  //! datum aspect that overrides the one in the link.
  bool HasOwnDatumAspect() const { return !myDatumAspect.IsNull(); }

  //! Returns own LineAspect for section wire, settings from linked Drawer or NULL if neither was
  //! set. These attributes are used by the algorithm Prs3d_WFShape.
  Standard_EXPORT const occ::handle<Prs3d_LineAspect>& SectionAspect() const;

  //! Sets the parameter theAspect for display attributes of sections.
  void SetSectionAspect(const occ::handle<Prs3d_LineAspect>& theAspect)
  {
    mySectionAspect = theAspect;
  }

  //! Returns true if the drawer has its own attribute for
  //! section aspect that overrides the one in the link.
  bool HasOwnSectionAspect() const { return !mySectionAspect.IsNull(); }

  //! Sets the parameter theAspect for the display of free boundaries.
  //! The method sets aspect owned by the drawer that will be used during
  //! visualization instead of the one set in link.
  void SetFreeBoundaryAspect(const occ::handle<Prs3d_LineAspect>& theAspect)
  {
    myFreeBoundaryAspect = theAspect;
  }

  //! Returns own settings for presentation of free boundaries, settings from linked Drawer or NULL
  //! if neither was set. In other words, this settings affect boundaries which are not shared.
  //! These attributes are used by the algorithm Prs3d_WFShape
  Standard_EXPORT const occ::handle<Prs3d_LineAspect>& FreeBoundaryAspect() const;

  //! Returns true if the drawer has its own attribute for
  //! free boundaries aspect that overrides the one in the link.
  bool HasOwnFreeBoundaryAspect() const { return !myFreeBoundaryAspect.IsNull(); }

  //! Enables or disables drawing of free boundaries for shading presentations.
  //! The method sets drawing flag owned by the drawer that will be used during
  //! visualization instead of the one set in link.
  //! theIsEnabled is a boolean flag indicating whether the free boundaries should be
  //! drawn or not.
  Standard_EXPORT void SetFreeBoundaryDraw(const bool theIsEnabled);

  //! Returns True if the drawing of the free boundaries is enabled
  //! True is the default setting.
  bool FreeBoundaryDraw() const
  {
    return myHasOwnFreeBoundaryDraw || myLink.IsNull() ? myFreeBoundaryDraw
                                                       : myLink->FreeBoundaryDraw();
  }

  //! Returns true if the drawer has its own attribute for
  //! "draw free boundaries" flag that overrides the one in the link.
  bool HasOwnFreeBoundaryDraw() const { return myHasOwnFreeBoundaryDraw; }

  //! Resets HasOwnFreeBoundaryDraw() flag, e.g. undoes SetFreeBoundaryDraw().
  void UnsetOwnFreeBoundaryDraw()
  {
    myHasOwnFreeBoundaryDraw = false;
    myFreeBoundaryDraw       = true;
  }

  //! Sets the parameter theAspect for the display of shared boundaries.
  //! The method sets aspect owned by the drawer that will be used during
  //! visualization instead of the one set in link.
  void SetUnFreeBoundaryAspect(const occ::handle<Prs3d_LineAspect>& theAspect)
  {
    myUnFreeBoundaryAspect = theAspect;
  }

  //! Returns own settings for shared boundary line aspects, settings from linked Drawer or NULL if
  //! neither was set. These attributes are used by the algorithm Prs3d_WFShape
  Standard_EXPORT const occ::handle<Prs3d_LineAspect>& UnFreeBoundaryAspect() const;

  //! Returns true if the drawer has its own attribute for
  //! unfree boundaries aspect that overrides the one in the link.
  bool HasOwnUnFreeBoundaryAspect() const { return !myUnFreeBoundaryAspect.IsNull(); }

  //! Enables or disables drawing of shared boundaries for shading presentations.
  //! The method sets drawing flag owned by the drawer that will be used during
  //! visualization instead of the one set in link.
  //! theIsEnabled is a boolean flag indicating whether the shared boundaries should be drawn or
  //! not.
  Standard_EXPORT void SetUnFreeBoundaryDraw(const bool theIsEnabled);

  //! Returns True if the drawing of the shared boundaries is enabled.
  //! True is the default setting.
  bool UnFreeBoundaryDraw() const
  {
    return myHasOwnUnFreeBoundaryDraw || myLink.IsNull() ? myUnFreeBoundaryDraw
                                                         : myLink->UnFreeBoundaryDraw();
  }

  //! Returns true if the drawer has its own attribute for
  //! "draw shared boundaries" flag that overrides the one in the link.
  bool HasOwnUnFreeBoundaryDraw() const { return myHasOwnUnFreeBoundaryDraw; }

  //! Resets HasOwnUnFreeBoundaryDraw() flag, e.g. undoes SetUnFreeBoundaryDraw().
  void UnsetOwnUnFreeBoundaryDraw()
  {
    myHasOwnUnFreeBoundaryDraw = false;
    myUnFreeBoundaryDraw       = true;
  }

  //! Sets line aspect for face boundaries.
  //! The method sets line aspect owned by the drawer that will be used during
  //! visualization instead of the one set in link.
  //! theAspect is the line aspect that determines the look of the face boundaries.
  void SetFaceBoundaryAspect(const occ::handle<Prs3d_LineAspect>& theAspect)
  {
    myFaceBoundaryAspect = theAspect;
  }

  //! Returns own line aspect of face boundaries, settings from linked Drawer or NULL if neither was
  //! set.
  Standard_EXPORT const occ::handle<Prs3d_LineAspect>& FaceBoundaryAspect() const;

  //! Returns true if the drawer has its own attribute for
  //! face boundaries aspect that overrides the one in the link.
  bool HasOwnFaceBoundaryAspect() const { return !myFaceBoundaryAspect.IsNull(); }

  //! Sets own face boundary aspect, which is a black solid line by default.
  //! Returns FALSE if the drawer already has its own attribute for face boundary aspect.
  Standard_EXPORT bool SetupOwnFaceBoundaryAspect(
    const occ::handle<Prs3d_Drawer>& theDefaults = occ::handle<Prs3d_Drawer>());

  //! Enables or disables face boundary drawing for shading presentations.
  //! The method sets drawing flag owned by the drawer that will be used during
  //! visualization instead of the one set in link.
  //! theIsEnabled is a boolean flag indicating whether the face boundaries should be drawn or not.
  Standard_EXPORT void SetFaceBoundaryDraw(const bool theIsEnabled);

  //! Checks whether the face boundary drawing is enabled or not.
  bool FaceBoundaryDraw() const
  {
    return myHasOwnFaceBoundaryDraw || myLink.IsNull() ? myFaceBoundaryDraw
                                                       : myLink->FaceBoundaryDraw();
  }

  //! Returns true if the drawer has its own attribute for
  //! "draw face boundaries" flag that overrides the one in the link.
  bool HasOwnFaceBoundaryDraw() const { return myHasOwnFaceBoundaryDraw; }

  //! Resets HasOwnFaceBoundaryDraw() flag, e.g. undoes SetFaceBoundaryDraw().
  void UnsetOwnFaceBoundaryDraw()
  {
    myHasOwnFaceBoundaryDraw = false;
    myFaceBoundaryDraw       = false;
  }

  //! Returns true if the drawer has its own attribute for face boundaries upper edge continuity
  //! class that overrides the one in the link.
  bool HasOwnFaceBoundaryUpperContinuity() const { return myFaceBoundaryUpperContinuity != -1; }

  //! Get the most edge continuity class; GeomAbs_CN by default (all edges).
  GeomAbs_Shape FaceBoundaryUpperContinuity() const
  {
    return HasOwnFaceBoundaryUpperContinuity()
             ? (GeomAbs_Shape)myFaceBoundaryUpperContinuity
             : (!myLink.IsNull() ? myLink->FaceBoundaryUpperContinuity() : GeomAbs_CN);
  }

  //! Set the most edge continuity class for face boundaries.
  void SetFaceBoundaryUpperContinuity(GeomAbs_Shape theMostAllowedEdgeClass)
  {
    myFaceBoundaryUpperContinuity = theMostAllowedEdgeClass;
  }

  //! Unset the most edge continuity class for face boundaries.
  void UnsetFaceBoundaryUpperContinuity() { myFaceBoundaryUpperContinuity = -1; }

  //! Returns own settings for the appearance of dimensions, settings from linked Drawer or NULL if
  //! neither was set.
  Standard_EXPORT const occ::handle<Prs3d_DimensionAspect>& DimensionAspect() const;

  //! Sets the settings for the appearance of dimensions.
  //! The method sets aspect owned by the drawer that will be used during
  //! visualization instead of the one set in link.
  void SetDimensionAspect(const occ::handle<Prs3d_DimensionAspect>& theAspect)
  {
    myDimensionAspect = theAspect;
  }

  //! Returns true if the drawer has its own attribute for
  //! the appearance of dimensions that overrides the one in the link.
  bool HasOwnDimensionAspect() const { return !myDimensionAspect.IsNull(); }

  //! Sets dimension length model units for computing of dimension presentation.
  //! The method sets value owned by the drawer that will be used during
  //! visualization instead of the one set in link.
  Standard_EXPORT void SetDimLengthModelUnits(const TCollection_AsciiString& theUnits);

  //! Sets dimension angle model units for computing of dimension presentation.
  //! The method sets value owned by the drawer that will be used during
  //! visualization instead of the one set in link.
  Standard_EXPORT void SetDimAngleModelUnits(const TCollection_AsciiString& theUnits);

  //! Returns length model units for the dimension presentation.
  const TCollection_AsciiString& DimLengthModelUnits() const
  {
    return myHasOwnDimLengthModelUnits || myLink.IsNull() ? myDimensionModelUnits.GetLengthUnits()
                                                          : myLink->DimLengthModelUnits();
  }

  //! Returns angle model units for the dimension presentation.
  const TCollection_AsciiString& DimAngleModelUnits() const
  {
    return myHasOwnDimAngleModelUnits || myLink.IsNull() ? myDimensionModelUnits.GetAngleUnits()
                                                         : myLink->DimAngleModelUnits();
  }

  //! Returns true if the drawer has its own attribute for
  //! dimension length model units that overrides the one in the link.
  bool HasOwnDimLengthModelUnits() const { return myHasOwnDimLengthModelUnits; }

  //! Resets HasOwnDimLengthModelUnits() flag, e.g. undoes SetDimLengthModelUnits().
  void UnsetOwnDimLengthModelUnits()
  {
    myHasOwnDimLengthModelUnits = false;
    myDimensionModelUnits.SetLengthUnits("m");
  }

  //! Returns true if the drawer has its own attribute for
  //! dimension angle model units that overrides the one in the link.
  bool HasOwnDimAngleModelUnits() const { return myHasOwnDimAngleModelUnits; }

  //! Resets HasOwnDimAngleModelUnits() flag, e.g. undoes SetDimAngleModelUnits().
  void UnsetOwnDimAngleModelUnits()
  {
    myHasOwnDimAngleModelUnits = false;
    myDimensionModelUnits.SetAngleUnits("rad");
  }

  //! Sets length units in which value for dimension presentation is displayed.
  //! The method sets value owned by the drawer that will be used during
  //! visualization instead of the one set in link.
  Standard_EXPORT void SetDimLengthDisplayUnits(const TCollection_AsciiString& theUnits);

  //! Sets angle units in which value for dimension presentation is displayed.
  //! The method sets value owned by the drawer that will be used during
  //! visualization instead of the one set in link.
  Standard_EXPORT void SetDimAngleDisplayUnits(const TCollection_AsciiString& theUnits);

  //! Returns length units in which dimension presentation is displayed.
  const TCollection_AsciiString& DimLengthDisplayUnits() const
  {
    return myHasOwnDimLengthDisplayUnits || myLink.IsNull()
             ? myDimensionDisplayUnits.GetLengthUnits()
             : myLink->DimLengthDisplayUnits();
  }

  //! Returns angle units in which dimension presentation is displayed.
  const TCollection_AsciiString& DimAngleDisplayUnits() const
  {
    return myHasOwnDimAngleDisplayUnits || myLink.IsNull() ? myDimensionDisplayUnits.GetAngleUnits()
                                                           : myLink->DimAngleDisplayUnits();
  }

  //! Returns true if the drawer has its own attribute for
  //! length units in which dimension presentation is displayed
  //! that overrides the one in the link.
  bool HasOwnDimLengthDisplayUnits() const { return myHasOwnDimLengthDisplayUnits; }

  //! Resets HasOwnDimLengthModelUnits() flag, e.g. undoes SetDimLengthDisplayUnits().
  void UnsetOwnDimLengthDisplayUnits()
  {
    myHasOwnDimLengthDisplayUnits = false;
    myDimensionDisplayUnits.SetLengthUnits("m");
  }

  //! Returns true if the drawer has its own attribute for
  //! angle units in which dimension presentation is displayed
  //! that overrides the one in the link.
  bool HasOwnDimAngleDisplayUnits() const { return myHasOwnDimAngleDisplayUnits; }

  //! Resets HasOwnDimAngleDisplayUnits() flag, e.g. undoes SetDimLengthDisplayUnits().
  void UnsetOwnDimAngleDisplayUnits()
  {
    myHasOwnDimAngleDisplayUnits = false;
    myDimensionDisplayUnits.SetAngleUnits("deg");
  }

public:
  //! Returns the drawer to which the current object references.
  const occ::handle<Prs3d_Drawer>& Link() const { return myLink; }

  //! Returns true if the current object has a link on the other drawer.
  bool HasLink() const { return !myLink.IsNull(); }

  //! Sets theDrawer as a link to which the current object references.
  void Link(const occ::handle<Prs3d_Drawer>& theDrawer) { SetLink(theDrawer); }

  //! Sets theDrawer as a link to which the current object references.
  void SetLink(const occ::handle<Prs3d_Drawer>& theDrawer) { myLink = theDrawer; }

  //! Removes local attributes.
  Standard_EXPORT void ClearLocalAttributes();

  //! Assign shader program for specified type of primitives.
  //! @param theProgram new program to set (might be NULL)
  //! @param theAspect  the type of primitives
  //! @param theToOverrideDefaults if true then non-overridden attributes using defaults will be
  //! allocated and copied from the Link;
  //!                              otherwise, only already customized attributes will be changed
  //! @return TRUE if presentation should be recomputed after creating aspects not previously
  //! customized (if theToOverrideDefaults is also TRUE)
  Standard_EXPORT bool SetShaderProgram(const occ::handle<Graphic3d_ShaderProgram>& theProgram,
                                        const Graphic3d_GroupAspect                 theAspect,
                                        const bool theToOverrideDefaults = false);

  //! Sets Shading Model type for the shading aspect.
  Standard_EXPORT bool SetShadingModel(Graphic3d_TypeOfShadingModel theModel,
                                       bool                         theToOverrideDefaults = false);

  //! Dumps the content of me into the stream
  Standard_EXPORT void DumpJson(Standard_OStream& theOStream, int theDepth = -1) const override;

public: //! @name deprecated methods
  Standard_DEPRECATED("SetDeviationAngle() should be used instead")
  void SetHLRAngle(const double theAngle) { SetDeviationAngle(theAngle); }

  Standard_DEPRECATED("DeviationAngle() should be used instead")
  double HLRAngle() const { return DeviationAngle(); }

  Standard_DEPRECATED("SetDeviationAngle() should be used instead")
  void SetHLRAngle() { SetDeviationAngle(); }

  Standard_DEPRECATED("HasOwnDeviationAngle() should be used instead")
  bool HasOwnHLRDeviationAngle() const { return HasOwnDeviationAngle(); }

  Standard_DEPRECATED("PreviousDeviationAngle() should be used instead")
  double PreviousHLRDeviationAngle() const { return PreviousDeviationAngle(); }

protected:
  occ::handle<Prs3d_Drawer> myLink;

  int                     myNbPoints;
  double                  myMaximalParameterValue;
  double                  myChordialDeviation;
  Aspect_TypeOfDeflection myTypeOfDeflection;
  bool                    myHasOwnTypeOfDeflection;
  Prs3d_TypeOfHLR         myTypeOfHLR;
  double                  myDeviationCoefficient;
  double                  myPreviousDeviationCoefficient;
  double                  myDeviationAngle;
  double                  myPreviousDeviationAngle;
  bool                    myIsoOnPlane;
  bool                    myHasOwnIsoOnPlane;
  bool                    myIsoOnTriangulation;
  bool                    myHasOwnIsoOnTriangulation;
  bool                    myIsAutoTriangulated;
  bool                    myHasOwnIsAutoTriangulated;

  occ::handle<Prs3d_IsoAspect>     myUIsoAspect;
  occ::handle<Prs3d_IsoAspect>     myVIsoAspect;
  occ::handle<Prs3d_LineAspect>    myWireAspect;
  bool                             myWireDraw;
  bool                             myHasOwnWireDraw;
  occ::handle<Prs3d_PointAspect>   myPointAspect;
  occ::handle<Prs3d_LineAspect>    myLineAspect;
  occ::handle<Prs3d_TextAspect>    myTextAspect;
  occ::handle<Prs3d_ShadingAspect> myShadingAspect;
  occ::handle<Prs3d_PlaneAspect>   myPlaneAspect;
  occ::handle<Prs3d_LineAspect>    mySeenLineAspect;
  occ::handle<Prs3d_ArrowAspect>   myArrowAspect;
  bool                             myLineArrowDraw;
  bool                             myHasOwnLineArrowDraw;
  occ::handle<Prs3d_LineAspect>    myHiddenLineAspect;
  bool                             myDrawHiddenLine;
  bool                             myHasOwnDrawHiddenLine;
  occ::handle<Prs3d_LineAspect>    myVectorAspect;
  Prs3d_VertexDrawMode             myVertexDrawMode;
  occ::handle<Prs3d_DatumAspect>   myDatumAspect;
  occ::handle<Prs3d_LineAspect>    mySectionAspect;

  occ::handle<Prs3d_LineAspect> myFreeBoundaryAspect;
  bool                          myFreeBoundaryDraw;
  bool                          myHasOwnFreeBoundaryDraw;
  occ::handle<Prs3d_LineAspect> myUnFreeBoundaryAspect;
  bool                          myUnFreeBoundaryDraw;
  bool                          myHasOwnUnFreeBoundaryDraw;
  occ::handle<Prs3d_LineAspect> myFaceBoundaryAspect;
  // clang-format off
  int              myFaceBoundaryUpperContinuity; //!< the most edge continuity class (GeomAbs_Shape) to be included to face boundaries presentation, or -1 if undefined
  // clang-format on
  bool myFaceBoundaryDraw;
  bool myHasOwnFaceBoundaryDraw;

  occ::handle<Prs3d_DimensionAspect> myDimensionAspect;
  Prs3d_DimensionUnits               myDimensionModelUnits;
  bool                               myHasOwnDimLengthModelUnits;
  bool                               myHasOwnDimAngleModelUnits;
  Prs3d_DimensionUnits               myDimensionDisplayUnits;
  bool                               myHasOwnDimLengthDisplayUnits;
  bool                               myHasOwnDimAngleDisplayUnits;
};

#endif // _Prs3d_Drawer_HeaderFile
