1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-08-09 13:22:24 +03:00

Cosmetics and comments

This commit is contained in:
vpa
2016-04-06 15:29:24 +03:00
parent 5efc1678e3
commit 3969f2848a
13 changed files with 177 additions and 45 deletions

View File

@@ -125,9 +125,14 @@ public:
//! Remove group from this structure
virtual void RemoveGroup (const Handle(Graphic3d_Group)& theGroup) = 0;
//! Returns the number of LODs of the structure
virtual Standard_Integer NbDetailLevels() const = 0;
virtual void SetDetailLevelRange (const Standard_Integer theIdOfLOD, const Standard_Real theFrom, const Standard_Real theTo) = 0;
//! Sets range of LOD.
//! @param theLodIdx corresponds to the index of LOD in map of LOD manager. In case if no LOD was
//! removed, the LODs in map are located in order of addition and IDs are identical to the addition
//! iteration number
virtual void SetDetailLevelRange (const Standard_Integer theLodIdx, const Standard_Real theFrom, const Standard_Real theTo) = 0;
public:

View File

@@ -23,9 +23,15 @@
#include <Standard_Macro.hxx>
#include <Standard_Transient.hxx>
//! This structure is used for ranged LODs to store the lower and upper
//! boundaries of the interval where the LOD is visible.
//! It also performs the comparison that checks if the given value
//! is in or out of the range.
struct Graphic3d_RangeOfLOD
{
public:
//! Constructs a range with the given boundaries
Graphic3d_RangeOfLOD (const Standard_Real theFrom, const Standard_Real theTo)
: myTo (theTo),
myFrom (theFrom)
@@ -34,6 +40,8 @@ public:
"The upper boundary of the interval must be greater than lower one!");
}
//! Returns true, if the given value is between the lower and
//! upper boundaries
Standard_Boolean IsIn (const Standard_Real theVal) const
{
return (myFrom < theVal) && (theVal < myTo);
@@ -59,9 +67,14 @@ private:
Standard_Real myTo;
};
//! Base class for level of detail representation.
//! It provides an interface to create and customize graphic groups for
//! the LOD and contains information about the range for ranged LODs.
class Graphic3d_LOD : public Standard_Transient
{
public:
//! Destroys graphic groups of the LOD
Standard_EXPORT virtual ~Graphic3d_LOD();
Standard_EXPORT void SetRange (const Standard_Real theFrom, const Standard_Real theTo);
@@ -71,6 +84,7 @@ public:
return myRange;
}
//! Create a new group within this LOD
Standard_EXPORT virtual Handle(Graphic3d_Group) NewGroup (const Handle(Graphic3d_Structure)& /*theParentStruct*/)
{
return NULL;
@@ -81,11 +95,17 @@ public:
return myGroups;
}
//! If theWithDestruction is true, all the graphic groups of LOD will be destroyed
//! and new group must be created for further displaying.
//! If theWithDestruction is false, all the data of groups is reset to defauls
//! so it is threated like empty.
Standard_EXPORT virtual void Clear (const Standard_Boolean theWithDestruction);
DEFINE_STANDARD_RTTIEXT (Graphic3d_LOD, Standard_Transient)
protected:
//! Creates a new LOD that is visible from any distance
Standard_EXPORT Graphic3d_LOD() : myRange (-DBL_MAX, DBL_MAX) {};
protected:

View File

@@ -21,6 +21,9 @@
class Graphic3d_CStructure;
class Graphic3d_Camera;
//! This class implements computation of distance metrics for determinig
//! LOD visibility. It computes distance from center of geometry of the object
//! to camera's eye position.
class Graphic3d_LODDistanceSelector : public Graphic3d_LODSelector
{
public:

View File

@@ -23,36 +23,55 @@ IMPLEMENT_STANDARD_RTTIEXT (Graphic3d_LODManager, Standard_Transient)
// purpose :
//=======================================================================
Graphic3d_LODManager::Graphic3d_LODManager (const Handle(Graphic3d_Structure)& theParentStructure)
: myCurrentLODIdx (-1),
: myLodIndexes (NULL),
myIsToSortLods (Standard_False),
myCurrentLODIdx (-1),
mySelector (new Graphic3d_LODDistanceSelector())
{
myStructure = theParentStructure.operator->();
}
//=======================================================================
// function : Destructor
// purpose :
//=======================================================================
Graphic3d_LODManager::~Graphic3d_LODManager()
{
Clear (Standard_True);
myLODs.Clear();
myLodIndexes.Nullify();
mySelector.Nullify();
}
//=======================================================================
// function : GetCurrentLODIdx
// purpose :
//=======================================================================
Standard_Integer Graphic3d_LODManager::GetCurrentLODIdx (const Handle(Graphic3d_Camera)& theCamera)
Standard_Boolean Graphic3d_LODManager::HasLodToDisplay (const Handle(Graphic3d_Camera)& theCamera)
{
if (theCamera->WorldViewProjState() == myPrevCameraState && myCurrentLODIdx != -1)
return myCurrentLODIdx;
return Standard_True;
if (myIsToSortLods)
sortLODs();
myPrevCameraState = theCamera->WorldViewProjState();
const Standard_Real aMetric = mySelector->ComputeMetric (myStructure->CStructure(), theCamera);
if (myLODs.Value (0)->GetRange().IsLess (aMetric))
if (myLODs.FindKey (1)->GetRange().IsLess (aMetric))
{
myCurrentLODIdx = -1;
return Standard_False;
}
else if (myLODs.Value (myLODs.Size() - 1)->GetRange().IsGreater (aMetric))
else if (myLODs.FindKey (myLODs.Extent())->GetRange().IsGreater (aMetric))
{
myCurrentLODIdx = myLODs.Size() - 1;
myCurrentLODIdx = myLODs.Extent();
}
else
{
for (Standard_Integer aLodIdx = 0; aLodIdx < myLODs.Size(); ++aLodIdx)
for (Standard_Integer aLodIdx = 1; aLodIdx <= myLODs.Extent(); ++aLodIdx)
{
if (myLODs.Value (aLodIdx)->GetRange().IsIn (aMetric))
if (myLODs.FindKey (aLodIdx)->GetRange().IsIn (aMetric))
{
myCurrentLODIdx = aLodIdx;
break;
@@ -60,19 +79,22 @@ Standard_Integer Graphic3d_LODManager::GetCurrentLODIdx (const Handle(Graphic3d_
}
}
return myCurrentLODIdx;
return Standard_True;
}
//=======================================================================
// function : SetRange
// purpose :
//=======================================================================
void Graphic3d_LODManager::SetRange (const Standard_Integer theLodIdx,
void Graphic3d_LODManager::SetRange (Standard_Integer theLodIdx,
const Standard_Real theFrom,
const Standard_Real theTo)
{
myLODs.ChangeValue (theLodIdx)->SetRange (theFrom, theTo);
sortLODs();
if (theLodIdx < 1 || theLodIdx > myLODs.Extent())
return;
myLODs.FindKey (theLodIdx)->SetRange (theFrom, theTo);
myIsToSortLods = Standard_True;
}
//=======================================================================
@@ -81,7 +103,7 @@ void Graphic3d_LODManager::SetRange (const Standard_Integer theLodIdx,
//=======================================================================
const Graphic3d_SequenceOfGroup& Graphic3d_LODManager::GetCurrentGroups() const
{
return myLODs.Value (myCurrentLODIdx)->GetDrawGroups();
return myLODs.FindKey (myCurrentLODIdx)->GetDrawGroups();
}
//=======================================================================
@@ -90,9 +112,9 @@ const Graphic3d_SequenceOfGroup& Graphic3d_LODManager::GetCurrentGroups() const
//=======================================================================
void Graphic3d_LODManager::GetCombinedBndBox (Graphic3d_BndBox4f& theBndBox) const
{
for (Standard_Integer aLodIdx = 0; aLodIdx < myLODs.Size(); ++aLodIdx)
for (Standard_Integer aLodIdx = 1; aLodIdx <= myLODs.Extent(); ++aLodIdx)
{
const Graphic3d_SequenceOfGroup& aGroups = myLODs.Value (aLodIdx)->GetDrawGroups();
const Graphic3d_SequenceOfGroup& aGroups = myLODs.FindKey (aLodIdx)->GetDrawGroups();
for (Graphic3d_SequenceOfGroup::Iterator aGroupIter (aGroups); aGroupIter.More(); aGroupIter.Next())
{
theBndBox.Combine (aGroupIter.Value()->BoundingBox());
@@ -106,9 +128,9 @@ void Graphic3d_LODManager::GetCombinedBndBox (Graphic3d_BndBox4f& theBndBox) con
//=======================================================================
Standard_Boolean Graphic3d_LODManager::IsEmpty() const
{
for (Standard_Integer aLodIdx = 0; aLodIdx < myLODs.Size(); ++aLodIdx)
for (Standard_Integer aLodIdx = 1; aLodIdx <= myLODs.Extent(); ++aLodIdx)
{
const Graphic3d_SequenceOfGroup& aGroups = myLODs.Value (aLodIdx)->GetDrawGroups();
const Graphic3d_SequenceOfGroup& aGroups = myLODs.FindKey (aLodIdx)->GetDrawGroups();
if (!aGroups.IsEmpty())
return Standard_False;
}
@@ -122,9 +144,9 @@ Standard_Boolean Graphic3d_LODManager::IsEmpty() const
//=======================================================================
void Graphic3d_LODManager::Clear (const Standard_Boolean theWithDestruction)
{
for (Standard_Integer aLodIdx = 0; aLodIdx < myLODs.Size(); ++aLodIdx)
for (Standard_Integer aLodIdx = 1; aLodIdx <= myLODs.Extent(); ++aLodIdx)
{
myLODs.Value (aLodIdx)->Clear (theWithDestruction);
myLODs.FindKey (aLodIdx)->Clear (theWithDestruction);
}
}
@@ -134,8 +156,13 @@ void Graphic3d_LODManager::Clear (const Standard_Boolean theWithDestruction)
//=======================================================================
const Handle(Graphic3d_LOD)& Graphic3d_LODManager::GetLodById (const Standard_Integer theLodIdx)
{
Standard_ASSERT_RAISE (theLodIdx >= 0 || theLodIdx < myLODs.Size(),
Standard_ASSERT_RAISE (theLodIdx > 0 || theLodIdx <= myLODs.Size(),
"Index of LOD is out of range");
return myLODs.Value (theLodIdx);
return myLODs.FindKey (theLodIdx);
}
Standard_Boolean Graphic3d_LODManager::HasLod (const Handle(Graphic3d_LOD)& theLod) const
{
return myLODs.Contains (theLod);
}

View File

@@ -18,65 +18,108 @@
#include <Graphic3d_CStructure.hxx>
#include <Graphic3d_Camera.hxx>
#include <Graphic3d_LOD.hxx>
#include <Graphic3d_LODSelector.hxx>
#include <Graphic3d_LODDistanceSelector.hxx>
#include <Graphic3d_SequenceOfGroup.hxx>
#include <Graphic3d_StructurePtr.hxx>
#include <NCollection_Vector.hxx>
#include <NCollection_IndexedMap.hxx>
#include <Standard.hxx>
#include <Standard_Handle.hxx>
#include <TColStd_HArray1OfInteger.hxx>
class Graphic3d_LOD;
typedef NCollection_IndexedMap<Handle(Graphic3d_LOD)> Graphic3d_MapOfLODs;
//! This class is used to manage all the LODs of one Graphic3d_Structure.
//! It provides an interface for the following actions:
//! - addition of a new LOD;
//! - management of current method for LOD metrics calculation;
//! - access to LODs and its characteristics, such as quantity, range,
//! combined bounding box.
//! The class also runs a procedure that picks the LOD that should be
//! rendered according to the current state of camera and stores choosen
//! LOD index.
class Graphic3d_LODManager : public Standard_Transient
{
public:
Standard_EXPORT virtual ~Graphic3d_LODManager() {};
//! Nullifies the pointer to current selector and clears used data maps,
//! destroys the LODs used, so they can not be referenced to after the destruction
//! of corresponding LOD manager
Standard_EXPORT virtual ~Graphic3d_LODManager();
//! Sets up a method for LOD metrics computation
Standard_EXPORT void SetSelector (const Handle(Graphic3d_LODSelector)& theSelector)
{
mySelector = theSelector;
}
//! Returns a number of addded detail levels
Standard_EXPORT inline Standard_Integer NbOfDetailLevels() const
{
return myLODs.Size();
}
//! For ranged LODs, sets the distance interval where the LOD will be visible.
//! @param theLodIdx the index of LOD in sorted list
Standard_EXPORT void SetRange (const Standard_Integer theLodIdx,
const Standard_Real theFrom,
const Standard_Real theTo);
Standard_EXPORT Standard_Integer GetCurrentLODIdx (const Handle(Graphic3d_Camera)& theCamera);
//! Returns own index of the LOD that is displayed
Standard_EXPORT Standard_Boolean HasLodToDisplay (const Handle(Graphic3d_Camera)& theCamera);
//! Returns graphic groups of the LOD that must be displayed according to the current
//! camera state
Standard_EXPORT const Graphic3d_SequenceOfGroup& GetCurrentGroups() const;
Standard_EXPORT virtual Handle(Graphic3d_LOD) AddNewLOD() = 0;
//! Returns combined bounding box for all LOD groups that were added to this
//! manager
Standard_EXPORT void GetCombinedBndBox (Graphic3d_BndBox4f& theBndBox) const;
//! Returns false if at least one of LODs has non-empty sequence of Graphic3d_Groups
Standard_EXPORT Standard_Boolean IsEmpty() const;
//! Iterates through added LODs and clears up its resources.
//! If theWithDestruction is true, all the graphic groups of each LOD will be destroyed
//! and new group must be created for further displaying.
//! If theWithDestruction is false, all the data of groups is reset to defauls
//! so it is threated like empty.
Standard_EXPORT void Clear (const Standard_Boolean theWithDestruction);
//! The indexes are from 1 to NbOfDetailLevels(). The ID of the element corresponds
//! to the index of the LOD in the map of LOD manager. Therefore, in case if no LOD was
//! removed, the LODs in map are located in order of addition and IDs are identical to
//! the addition iteration number
Standard_EXPORT const Handle(Graphic3d_LOD)& GetLodById (const Standard_Integer theLodIdx);
//! Checks if the given LOD is added to this manager
Standard_EXPORT Standard_Boolean HasLod (const Handle(Graphic3d_LOD)& theLod) const;
DEFINE_STANDARD_RTTIEXT (Graphic3d_LODManager, Standard_Transient)
protected:
//! Creates an empty manager with invalid LOD metrics calculation method
Standard_EXPORT Graphic3d_LODManager (const Handle(Graphic3d_Structure)& theParentStructure);
//! Sorts LODs in the map according to its ranges to improve search for LOD to display.
//! After the sort is done, flag myIsToSortLods will be set to false.
Standard_EXPORT virtual void sortLODs() {};
protected:
NCollection_Vector<Handle(Graphic3d_LOD)> myLODs;
Graphic3d_MapOfLODs myLODs; //!< Map of LODs
Handle(TColStd_HArray1OfInteger) myLodIndexes; //!< Array of LOD indexes, for sorting purposes
Standard_Boolean myIsToSortLods; //!< Is true when LODs must be sorted before picking procedure. For example, when new LOD was added
private:
Standard_Integer myCurrentLODIdx;
Handle(Graphic3d_LODSelector) mySelector;
Graphic3d_StructurePtr myStructure;
Graphic3d_WorldViewProjState myPrevCameraState;
Standard_Integer myCurrentLODIdx; //!< Index of current LOD that should be rendered; is -1 by default.
Handle(Graphic3d_LODSelector) mySelector; //!< A wrapper that performs measurement of LOD metrics
Graphic3d_StructurePtr myStructure; //!< A pointer to graphic structure that is common for all LODs
Graphic3d_WorldViewProjState myPrevCameraState; //!< Previous state of the camera for current LOD detection procedure
};
DEFINE_STANDARD_HANDLE (Graphic3d_LODManager, Standard_Transient)

View File

@@ -23,10 +23,14 @@
class Graphic3d_CStructure;
class Graphic3d_Camera;
//! Base interface for classes implementing computation of
//! LOD visibility metrics
class Graphic3d_LODSelector : public Standard_Transient
{
public:
//! Computes the value of LOD visibility metrics according to current camera state
//! and choosen approach for metrics calculation
virtual Standard_Real ComputeMetric (const Handle(Graphic3d_CStructure)& theParentStructure,
const Handle(Graphic3d_Camera)& theCamera) = 0;

View File

@@ -484,8 +484,13 @@ public:
//! Returns the low-level structure
const Handle(Graphic3d_CStructure)& CStructure() const;
//! Returns number of LODs created for this structure
Standard_EXPORT Standard_Integer NbDetailLevels() const;
//! Sets range of LOD.
//! @param theLodIdx corresponds to the index of LOD in map of LOD manager. In case if no LOD was
//! removed, the LODs in map are located in order of addition and IDs are identical to the addition
//! iteration number
Standard_EXPORT void SetDetailLevelRange (const Standard_Integer theIdOfLOD, const Standard_Real theFrom, const Standard_Real theTo);
friend class Graphic3d_Group;

View File

@@ -21,6 +21,9 @@
#include <OpenGl_AspectLine.hxx>
#include <OpenGl_Structure.hxx>
//! This class provides an implementation of TKOpenGl-dependent LOD
//! functionality, such as creation of new graphic groups and cleaning
//! up graphic resources
class OpenGl_LOD : public Graphic3d_LOD
{
public:
@@ -28,8 +31,10 @@ public:
Standard_EXPORT OpenGl_LOD() : Graphic3d_LOD () {};
Standard_EXPORT ~OpenGl_LOD() {};
//! Creates new graphic group for LOD rendering and adds it to the map
Standard_EXPORT virtual Handle(Graphic3d_Group) NewGroup (const Handle(Graphic3d_Structure)& theParentStruct) Standard_OVERRIDE;
//! Releases graphic resources of each created graphic group
void ReleaseGraphicResources (const Handle(OpenGl_Context)& theGlCtx);
DEFINE_STANDARD_RTTIEXT (OpenGl_LOD, Graphic3d_LOD)

View File

@@ -28,19 +28,19 @@ namespace
{
public:
CompareLODS (const NCollection_Vector<Handle(Graphic3d_LOD)>& theLODs)
CompareLODS (const Graphic3d_MapOfLODs& theLODs)
: myLODs (theLODs) {}
Standard_Boolean operator() (const Handle(Graphic3d_LOD)& theLeft, const Handle(Graphic3d_LOD)& theRight) const
Standard_Boolean operator() (const Standard_Integer theLeftIdx, const Standard_Integer theRightIdx) const
{
return theLeft->GetRange() < theRight->GetRange();
return myLODs.FindKey (theLeftIdx)->GetRange() < myLODs.FindKey (theRightIdx)->GetRange();
}
private:
void operator = (const CompareLODS&);
private:
const NCollection_Vector<Handle(Graphic3d_LOD)>& myLODs;
const Graphic3d_MapOfLODs& myLODs;
};
}
@@ -62,8 +62,8 @@ OpenGl_LODManager::OpenGl_LODManager (const Handle(Graphic3d_Structure)& thePare
Handle(Graphic3d_LOD) OpenGl_LODManager::AddNewLOD()
{
Handle(Graphic3d_LOD) aNewLOD = new OpenGl_LOD();
myLODs.Append (aNewLOD);
sortLODs();
myLODs.Add (aNewLOD);
myIsToSortLods = Standard_True;
return aNewLOD;
}
@@ -73,5 +73,14 @@ Handle(Graphic3d_LOD) OpenGl_LODManager::AddNewLOD()
//=======================================================================
void OpenGl_LODManager::sortLODs()
{
std::sort (myLODs.begin(), myLODs.end(), CompareLODS (myLODs));
Standard_Integer aIndArrSize = myLODs.Extent();
myLodIndexes.Nullify();
myLodIndexes = new TColStd_HArray1OfInteger (0, aIndArrSize - 1);
for (Standard_Integer aIdx = 0; aIdx < aIndArrSize; ++aIdx)
{
myLodIndexes->SetValue (aIdx, aIdx + 1);
}
TColStd_Array1OfInteger& anIdxArr = myLodIndexes->ChangeArray1();
std::sort (anIdxArr.begin(), anIdxArr.end(), CompareLODS (myLODs));
myIsToSortLods = Standard_False;
}

View File

@@ -18,18 +18,28 @@
#include <Graphic3d_LODManager.hxx>
//! This class provides an API for LOD manager to TKOpenGl
//! structures, such as OpenGl_Structure. It also implements
//! the TKOpenGl-dependent functionality of LOD manager, for
//! example, creation of a new LOD.
class OpenGl_LODManager : public Graphic3d_LODManager
{
public:
//! Creates new empty manager and checks the parent structure pointer for validity
Standard_EXPORT OpenGl_LODManager (const Handle(Graphic3d_Structure)& theParentStructure);
Standard_EXPORT virtual ~OpenGl_LODManager() {};
//! Creates new LOD without any graphic groups and marks map of LODs for sorting
Standard_EXPORT virtual Handle(Graphic3d_LOD) AddNewLOD() Standard_OVERRIDE;
DEFINE_STANDARD_RTTIEXT (OpenGl_LODManager, Graphic3d_LODManager)
protected:
//! Sorts added LODs according to its ranges in order to speed up
//! the process of picking the LOD to display
Standard_EXPORT virtual void sortLODs() Standard_OVERRIDE;
};

View File

@@ -560,7 +560,7 @@ void OpenGl_Structure::Render (const Handle(OpenGl_Workspace) &theWorkspace) con
return;
}
if (!myLODManager.IsNull() && myLODManager->GetCurrentLODIdx (theWorkspace->View()->Camera()) == -1)
if (!myLODManager.IsNull() && !myLODManager->HasLodToDisplay (theWorkspace->View()->Camera()))
return;
const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext();
@@ -755,7 +755,7 @@ void OpenGl_Structure::ReleaseGlResources (const Handle(OpenGl_Context)& theGlCt
}
if (!myLODManager.IsNull())
{
for (Standard_Integer aLodIdx = 0; aLodIdx < myLODManager->NbOfDetailLevels(); ++aLodIdx)
for (Standard_Integer aLodIdx = 1; aLodIdx <= myLODManager->NbOfDetailLevels(); ++aLodIdx)
{
Handle(OpenGl_LOD) aLod = Handle(OpenGl_LOD)::DownCast (myLODManager->GetLodById (aLodIdx));
aLod->ReleaseGraphicResources (theGlCtx);
@@ -796,17 +796,17 @@ Handle(Graphic3d_CStructure) OpenGl_Structure::ShadowLink (const Handle(Graphic3
//function : SetDetailLevelRange
//purpose :
//=======================================================================
void OpenGl_Structure::SetDetailLevelRange (const Standard_Integer theIdOfLOD,
void OpenGl_Structure::SetDetailLevelRange (const Standard_Integer theLodIdx,
const Standard_Real theFrom,
const Standard_Real theTo)
{
Standard_ASSERT_RAISE (theFrom < theTo,
"The upper boundary of the interval must be greater than lower one!");
if (myLODManager.IsNull() || theIdOfLOD < 0 || theIdOfLOD > myLODManager->NbOfDetailLevels())
if (myLODManager.IsNull() || theLodIdx < 1 || theLodIdx > myLODManager->NbOfDetailLevels())
return;
myLODManager->SetRange (theIdOfLOD, theFrom, theTo);
myLODManager->SetRange (theLodIdx, theFrom, theTo);
}
//=======================================================================

View File

@@ -106,7 +106,7 @@ public:
//! Remove group from this structure
Standard_EXPORT virtual void RemoveGroup (const Handle(Graphic3d_Group)& theGroup) Standard_OVERRIDE;
Standard_EXPORT virtual void SetDetailLevelRange (const Standard_Integer theIdOfLOD,
Standard_EXPORT virtual void SetDetailLevelRange (const Standard_Integer theLodIdx,
const Standard_Real theFrom,
const Standard_Real theTo) Standard_OVERRIDE;

View File

@@ -1542,10 +1542,11 @@ static int MeshLod (Draw_Interpretor& theDI,
VDisplayAISObject (aShapeName, anOriginMesh);
aCtx->Deactivate (anOriginMesh);
Standard_Integer aLodIdx = 0;
Standard_Integer aLodIdx = 1;
for (NCollection_List<DetailLevelData>::Iterator aLodDataIter (myLODDataList); aLodDataIter.More(); aLodDataIter.Next())
{
anOriginMesh->Presentation()->SetDetailLevelRange (aLodIdx, aLodDataIter.Value().myFrom, aLodDataIter.Value().myTo);
aLodIdx++;
}
Draw::Set (aShapeName, new XSDRAWSTLVRML_DrawableMesh (anOriginMesh));