1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-05-16 10:54:53 +03:00

OCC22144 NIS performance and memory usage update

This commit is contained in:
AGV 2011-05-19 10:30:28 +00:00 committed by bugmaster
parent d51c7072ea
commit ffe2bea78c
24 changed files with 3742 additions and 842 deletions

View File

@ -1,5 +1,7 @@
EXTERNLIB EXTERNLIB
FILES FILES
NIS_Allocator.cxx
NIS_Allocator.hxx
NIS_Drawer.cxx NIS_Drawer.cxx
NIS_Drawer.hxx NIS_Drawer.hxx
NIS_DrawList.cxx NIS_DrawList.cxx

59
src/NIS/NIS_Allocator.cxx Normal file
View File

@ -0,0 +1,59 @@
// File: NIS_Allocator.cpp
// Created: 22.10.10 17:35
// Author: Alexander GRIGORIEV
// Copyright: Open Cascade 2010
#include <NIS_Allocator.hxx>
IMPLEMENT_STANDARD_HANDLE (NIS_Allocator, NCollection_IncAllocator)
IMPLEMENT_STANDARD_RTTIEXT (NIS_Allocator, NCollection_IncAllocator)
//=======================================================================
//function : NIS_Allocator
//purpose :
//=======================================================================
NIS_Allocator::NIS_Allocator (const size_t theBlockSize)
: NCollection_IncAllocator (theBlockSize),
myNAllocated (0),
myNFreed (0)
{}
//=======================================================================
//function : ResetCounters
//purpose :
//=======================================================================
void NIS_Allocator::ResetCounters ()
{
myNAllocated = 0;
myNFreed = 0;
}
//=======================================================================
//function : Allocate
//purpose :
//=======================================================================
void* NIS_Allocator::Allocate (const size_t size)
{
size_t* pResult = reinterpret_cast<size_t*>
(NCollection_IncAllocator::Allocate(size + sizeof(size_t)));
pResult[0] = size;
myNAllocated += size;
return &pResult[1];
}
//=======================================================================
//function : Free
//purpose :
//=======================================================================
void NIS_Allocator::Free (void *anAddress)
{
if (anAddress) {
size_t* pAddress = reinterpret_cast<size_t*>(anAddress) - 1;
myNFreed += pAddress[0];
NCollection_IncAllocator::Free(pAddress);
}
}

76
src/NIS/NIS_Allocator.hxx Normal file
View File

@ -0,0 +1,76 @@
// File: NIS_Allocator.h
// Created: 22.10.10 17:22
// Author: Alexander GRIGORIEV
// Copyright: Open Cascade 2010
#ifndef NIS_Allocator_HeaderFile
#define NIS_Allocator_HeaderFile
#include <NCollection_IncAllocator.hxx>
/**
* Subclass of Incremental Allocator. It is aware of the total
* allocated and released memory. Used in NIS_Interactive context as
* private allocator that manages all memory used by interactive objects.
*/
class NIS_Allocator : public NCollection_IncAllocator
{
public:
// ---------- PUBLIC METHODS ----------
/**
* Constructor.
*/
Standard_EXPORT NIS_Allocator (const size_t theBlockSize = 24600);
/**
* Query the total number of allocated bytes
*/
inline Standard_Size NAllocated () const
{
return myNAllocated;
}
/**
* Query the total number of released bytes
*/
inline Standard_Size NFreed () const
{
return myNFreed;
}
/**
* Set both counters to zero. Should be called with method Reset of the base
* class NCollection_IncAlocator.
*/
Standard_EXPORT void ResetCounters ();
/**
* Allocate memory with given size. Returns NULL on failure
*/
Standard_EXPORT virtual void* Allocate (const size_t size);
/*
* Free a previously allocated memory. Does nothing but count released bytes.
*/
Standard_EXPORT virtual void Free (void *anAddress);
private:
// ---------- PRIVATE FIELDS ----------
Standard_Size myNAllocated;
Standard_Size myNFreed;
public:
// Declaration of CASCADE RTTI
DEFINE_STANDARD_RTTI (NIS_Allocator)
};
// Definition of HANDLE object using Standard_DefineHandle.hxx
DEFINE_STANDARD_HANDLE (NIS_Allocator, NCollection_IncAllocator)
#endif

View File

@ -4,6 +4,7 @@
// Copyright: Open Cascade 2007 // Copyright: Open Cascade 2007
#include <NIS_Drawer.hxx> #include <NIS_Drawer.hxx>
#include <NIS_View.hxx>
#ifdef WNT #ifdef WNT
#include <windows.h> #include <windows.h>
@ -16,12 +17,21 @@
//======================================================================= //=======================================================================
NIS_DrawList::NIS_DrawList () NIS_DrawList::NIS_DrawList ()
: myListID (0)
{ {
#ifdef ARRAY_LISTS
myListID = 0;
#else
myListID[0] = 0;
myListID[1] = 0;
myListID[2] = 0;
myListID[3] = 0;
myListID[4] = 0;
#endif
myIsUpdated[0] = Standard_True; myIsUpdated[0] = Standard_True;
myIsUpdated[1] = Standard_True; myIsUpdated[1] = Standard_True;
myIsUpdated[2] = Standard_True; myIsUpdated[2] = Standard_True;
myIsUpdated[3] = Standard_True; myIsUpdated[3] = Standard_True;
myIsUpdated[4] = Standard_True;
} }
//======================================================================= //=======================================================================
@ -30,13 +40,22 @@ NIS_DrawList::NIS_DrawList ()
//======================================================================= //=======================================================================
NIS_DrawList::NIS_DrawList (const Handle_NIS_View& theView) NIS_DrawList::NIS_DrawList (const Handle_NIS_View& theView)
: myView (theView), : myView (theView)
myListID (0)
{ {
#ifdef ARRAY_LISTS
myListID = 0;
#else
myListID[0] = 0;
myListID[1] = 0;
myListID[2] = 0;
myListID[3] = 0;
myListID[4] = 0;
#endif
myIsUpdated[0] = Standard_True; myIsUpdated[0] = Standard_True;
myIsUpdated[1] = Standard_True; myIsUpdated[1] = Standard_True;
myIsUpdated[2] = Standard_True; myIsUpdated[2] = Standard_True;
myIsUpdated[3] = Standard_True; myIsUpdated[3] = Standard_True;
myIsUpdated[4] = Standard_True;
} }
//======================================================================= //=======================================================================
@ -46,8 +65,67 @@ NIS_DrawList::NIS_DrawList (const Handle_NIS_View& theView)
NIS_DrawList::~NIS_DrawList () NIS_DrawList::~NIS_DrawList ()
{ {
if (myListID != 0) //if (myListID != 0)
glDeleteLists (myListID, 4); //glDeleteLists (myListID, 5);
}
//=======================================================================
//function : ClearListID
//purpose : Set myListID to 0.
//=======================================================================
void NIS_DrawList::ClearListID (const Standard_Integer theType)
{
#ifndef ARRAY_LISTS
if (theType >= 0) {
// To be called only in Callback context (i.e. when GL context is active)
if (myListID[theType] > 0) {
glDeleteLists(myListID[theType], 1);
myListID[theType] = 0;
}
myIsUpdated[theType] = Standard_False;
}
#endif
}
//=======================================================================
//function : ClearListID
//purpose : Set myListID to 0.
//=======================================================================
void NIS_DrawList::ClearListID (const Handle_NIS_View& theView)
{
#ifdef ARRAY_LISTS
if (myListID > 0)
myView->GetExListId().Add(myListID);
myListID = 0;
#else
NIS_View * pView = (myView.IsNull()) ?
theView.operator->() : myView.operator->();
if (pView) {
if (myListID[0] > 0)
pView->GetExListId().Add(myListID[0]);
myListID[0] = 0;
if (myListID[1] > 0)
pView->GetExListId().Add(myListID[1]);
myListID[1] = 0;
if (myListID[2] > 0)
pView->GetExListId().Add(myListID[2]);
myListID[2] = 0;
if (myListID[3] > 0)
pView->GetExListId().Add(myListID[3]);
myListID[3] = 0;
if (myListID[4] > 0)
pView->GetExListId().Add(myListID[4]);
myListID[4] = 0;
}
#endif
myIsUpdated[0] = Standard_False;
myIsUpdated[1] = Standard_False;
myIsUpdated[2] = Standard_False;
myIsUpdated[3] = Standard_False;
myIsUpdated[4] = Standard_False;
} }
//======================================================================= //=======================================================================
@ -57,9 +135,14 @@ NIS_DrawList::~NIS_DrawList ()
void NIS_DrawList::BeginPrepare (const Standard_Integer theType) void NIS_DrawList::BeginPrepare (const Standard_Integer theType)
{ {
#ifdef ARRAY_LISTS
if (myListID == 0) if (myListID == 0)
myListID = glGenLists(4); myListID = glGenLists(5);
glNewList (GetListID (theType), GL_COMPILE); #else
if (GetListID(theType) == 0)
myListID[theType] = glGenLists(1);
#endif
glNewList (GetListID(theType), GL_COMPILE);
} }
//======================================================================= //=======================================================================
@ -70,7 +153,7 @@ void NIS_DrawList::BeginPrepare (const Standard_Integer theType)
void NIS_DrawList::EndPrepare (const Standard_Integer theType) void NIS_DrawList::EndPrepare (const Standard_Integer theType)
{ {
glEndList (); glEndList ();
myIsUpdated[theType&0x3] = Standard_False; myIsUpdated[theType] = Standard_False;
} }
//======================================================================= //=======================================================================
@ -120,9 +203,20 @@ Standard_Boolean NIS_DrawList::SetDynHilighted
void NIS_DrawList::SetUpdated (const Standard_Integer theType, void NIS_DrawList::SetUpdated (const Standard_Integer theType,
const Standard_Boolean theFlag) const Standard_Boolean theFlag)
{ {
if ( theFlag ) if (theFlag)
SetUpdated( theType ); SetUpdated(theType);
else else
myIsUpdated [theType&0x3] = Standard_False; myIsUpdated [theType] = Standard_False;
} }
//=======================================================================
//function : SetUpdated
//purpose :
//=======================================================================
void NIS_DrawList::SetUpdated (const Standard_Integer theType)
{
myIsUpdated [theType] = Standard_True;
if (theType == NIS_Drawer::Draw_Hilighted)
myDynHilighted.Clear();
}

View File

@ -12,9 +12,18 @@
#include <NCollection_List.hxx> #include <NCollection_List.hxx>
class NIS_InteractiveContext; class NIS_InteractiveContext;
/**
* This macro defines that OpenGL draw lists will be allocated as array of 5
* integers and any of them would not be deleted unless all interactive objects
* in the given drawer are removed.
* When the macro is undefined every draw list is created when needed and it is
* destroyed when there is no objects to show in this draw list.
*/
//#define ARRAY_LISTS
/** /**
* Block of comments describing class NIS_DrawList * Implementation of a set of OpenGL draw lists for a given NIS_Drawer and
* given NIS_View. Stored in NIS_Drawer instances.
*/ */
class NIS_DrawList class NIS_DrawList
@ -43,8 +52,26 @@ class NIS_DrawList
* @param theType * @param theType
* Integer value coinciding with the enumerated NIS_Drawer:DrawType. * Integer value coinciding with the enumerated NIS_Drawer:DrawType.
*/ */
inline Standard_Integer GetListID (const Standard_Integer theType) inline Standard_Integer GetListID (const Standard_Integer theType) const
{ return myListID + (theType&0x3); } #ifdef ARRAY_LISTS
{ return myListID + theType; }
#else
{ return myListID[theType]; }
#endif
/**
* Set myListID to 0.
* @return
* Previous value of myListID
*/
Standard_EXPORT void ClearListID (const Standard_Integer theType);
/**
* Set myListID to 0.
* @return
* Previous value of myListID
*/
Standard_EXPORT void ClearListID (const Handle_NIS_View& theView=NULL);
/** /**
* This method is called to start recording a new list. It must be eventually * This method is called to start recording a new list. It must be eventually
@ -74,14 +101,13 @@ class NIS_DrawList
* @param theType * @param theType
* Integer value coinciding with the enumerated NIS_Drawer::DrawType. * Integer value coinciding with the enumerated NIS_Drawer::DrawType.
*/ */
inline Standard_Boolean IsUpdated (const Standard_Integer theType) inline Standard_Boolean IsUpdated (const Standard_Integer theType) const
{ return myIsUpdated [theType&0x3]; } { return myIsUpdated [theType]; }
/** /**
* Set the flag indicating that the List should be updated (rebuilt). * Set the flag indicating that the List should be updated (rebuilt).
*/ */
inline void SetUpdated (const Standard_Integer theType) Standard_EXPORT void SetUpdated (const Standard_Integer theType);
{ myIsUpdated [theType&0x3] = Standard_True; }
/** /**
* Query if the given list should be processed by Dynamic Hilighting. * Query if the given list should be processed by Dynamic Hilighting.
@ -108,10 +134,10 @@ class NIS_DrawList
Standard_EXPORT void SetUpdated (const Standard_Integer, Standard_EXPORT void SetUpdated (const Standard_Integer,
const Standard_Boolean); const Standard_Boolean);
#ifdef ARRAY_LISTS
inline void SetListID (const Standard_Integer theID) inline void SetListID (const Standard_Integer theID)
{ myListID = theID; } { myListID = theID; }
#endif
private: private:
// ---------- PRIVATE METHODS (PROHIBITED) ---------- // ---------- PRIVATE METHODS (PROHIBITED) ----------
@ -122,8 +148,12 @@ class NIS_DrawList
// ---------- PRIVATE FIELDS ---------- // ---------- PRIVATE FIELDS ----------
Handle_NIS_View myView; Handle_NIS_View myView;
#ifdef ARRAY_LISTS
Standard_Integer myListID; Standard_Integer myListID;
Standard_Boolean myIsUpdated[4]; #else
Standard_Integer myListID[5];
#endif
Standard_Boolean myIsUpdated[5];
NCollection_List<Handle_NIS_InteractiveObject> myDynHilighted; NCollection_List<Handle_NIS_InteractiveObject> myDynHilighted;
}; };

View File

@ -4,6 +4,7 @@
// Copyright: Open Cascade 2007 // Copyright: Open Cascade 2007
#include <NIS_Drawer.hxx> #include <NIS_Drawer.hxx>
#include <NIS_View.hxx>
#include <NIS_InteractiveContext.hxx> #include <NIS_InteractiveContext.hxx>
#include <NIS_InteractiveObject.hxx> #include <NIS_InteractiveObject.hxx>
#include <TColStd_MapIteratorOfPackedMapOfInteger.hxx> #include <TColStd_MapIteratorOfPackedMapOfInteger.hxx>
@ -34,6 +35,9 @@ void NIS_Drawer::Assign (const Handle_NIS_Drawer& theOther)
{ {
if (theOther->IsKind(DynamicType()) == Standard_False) if (theOther->IsKind(DynamicType()) == Standard_False)
Standard_TypeMismatch::Raise ("NIS_Drawer::Assign"); Standard_TypeMismatch::Raise ("NIS_Drawer::Assign");
myIniId = theOther->myIniId;
myObjPerDrawer = theOther->myObjPerDrawer;
myTransparency = theOther->myTransparency;
} }
//======================================================================= //=======================================================================
@ -43,7 +47,9 @@ void NIS_Drawer::Assign (const Handle_NIS_Drawer& theOther)
Standard_Integer NIS_Drawer::HashCode(const Standard_Integer theN) const Standard_Integer NIS_Drawer::HashCode(const Standard_Integer theN) const
{ {
return ::HashCode (DynamicType(), theN); Standard_Integer aKey = ::HashCode (DynamicType(), theN);
aKey += (myIniId / myObjPerDrawer);
return ((aKey & 0x7fffffff) % theN) + 1;
} }
//======================================================================= //=======================================================================
@ -56,7 +62,13 @@ Standard_Boolean NIS_Drawer::IsEqual (const Handle_NIS_Drawer& theOther) const
Standard_Boolean aResult (Standard_False); Standard_Boolean aResult (Standard_False);
if (theOther.IsNull() == Standard_False) if (theOther.IsNull() == Standard_False)
if (DynamicType() == theOther->DynamicType()) if (DynamicType() == theOther->DynamicType())
aResult = (myMapID.Extent() < 2048); if (theOther->myIniId/theOther->myObjPerDrawer == myIniId/myObjPerDrawer)
aResult = Standard_True;
if (aResult)
if (fabs(myTransparency - theOther->myTransparency) > 0.01)
aResult = Standard_False;
return aResult; return aResult;
} }
@ -78,6 +90,36 @@ void NIS_Drawer::AfterDraw (const DrawType, const NIS_DrawList&)
{ {
} }
//=======================================================================
//function : UpdateExListId
//purpose :
//=======================================================================
void NIS_Drawer::UpdateExListId (const Handle_NIS_View& theView) const
{
if (theView.IsNull()) {
if (myCtx) {
if (myCtx->myViews.IsEmpty() == Standard_False) {
const Handle(NIS_View)& aView = myCtx->myViews.First();
NCollection_List<NIS_DrawList *>::Iterator anIterL(myLists);
for (; anIterL.More(); anIterL.Next()) {
NIS_DrawList * const pList = anIterL.Value();
pList->ClearListID(aView);
}
}
}
} else {
NCollection_List<NIS_DrawList *>::Iterator anIterL(myLists);
for (; anIterL.More(); anIterL.Next()) {
NIS_DrawList * const pList = anIterL.Value();
if (pList->GetView() == theView) {
pList->ClearListID(theView);
break;
}
}
}
}
//======================================================================= //=======================================================================
//function : redraw //function : redraw
//purpose : //purpose :
@ -93,12 +135,24 @@ void NIS_Drawer::redraw (const DrawType theType,
NCollection_List<NIS_DrawList*>::Iterator anIter (myLists); NCollection_List<NIS_DrawList*>::Iterator anIter (myLists);
for (; anIter.More(); anIter.Next()) { for (; anIter.More(); anIter.Next()) {
NIS_DrawList& aDrawList = * anIter.ChangeValue(); NIS_DrawList& aDrawList = * anIter.ChangeValue();
if (aDrawList.GetView() == theView) { const Handle_NIS_View& aView = aDrawList.GetView();
if (aView == theView || aView.IsNull()) {
if (aDrawList.IsUpdated(theType)) { if (aDrawList.IsUpdated(theType)) {
// Get the IDs of objects concerned
TColStd_PackedMapOfInteger mapObj;
mapObj.Intersection (myCtx->myMapObjects[theType], myMapID);
#ifndef ARRAY_LISTS
// Release the list that is no more in use
if (mapObj.IsEmpty() && theType != Draw_DynHilighted) {
aDrawList.ClearListID(theType);
break;
}
#endif
aDrawList.BeginPrepare(theType); aDrawList.BeginPrepare(theType);
prepareList (theType, aDrawList); prepareList (theType, aDrawList, mapObj);
aDrawList.EndPrepare(theType); aDrawList.EndPrepare(theType);
} }
if (aDrawList.GetListID(theType) > 0)
aDrawList.Call(theType); aDrawList.Call(theType);
break; break;
} }
@ -158,6 +212,28 @@ void NIS_Drawer::SetUpdated (const DrawType theType1,
const_cast<Bnd_B3f&>(myBox).Clear(); const_cast<Bnd_B3f&>(myBox).Clear();
} }
//=======================================================================
//function : SetUpdated
//purpose :
//=======================================================================
void NIS_Drawer::SetUpdated (const DrawType theType1,
const DrawType theType2,
const DrawType theType3,
const DrawType theType4) const
{
NCollection_List<NIS_DrawList*>::Iterator anIter (myLists);
for (; anIter.More(); anIter.Next()) {
NIS_DrawList& aDrawList = * anIter.ChangeValue();
aDrawList.SetUpdated (theType1);
aDrawList.SetUpdated (theType2);
aDrawList.SetUpdated (theType3);
aDrawList.SetUpdated (theType4);
}
const_cast<Bnd_B3f&>(myBox).Clear();
}
//======================================================================= //=======================================================================
//function : SetDynamicHilighted //function : SetDynamicHilighted
//purpose : //purpose :
@ -180,7 +256,8 @@ void NIS_Drawer::SetDynamicHilighted
} else } else
for (; anIter.More(); anIter.Next()) { for (; anIter.More(); anIter.Next()) {
NIS_DrawList& aDrawList = * anIter.ChangeValue(); NIS_DrawList& aDrawList = * anIter.ChangeValue();
if (aDrawList.GetView() == theView) { const Handle(NIS_View)& aView = aDrawList.GetView();
if (aView == theView || aView.IsNull()) {
aDrawList.SetDynHilighted (isHilighted, theObj); aDrawList.SetDynHilighted (isHilighted, theObj);
theObj->myIsDynHilighted = isHilighted; theObj->myIsDynHilighted = isHilighted;
aDrawList.SetUpdated (Draw_DynHilighted); aDrawList.SetUpdated (Draw_DynHilighted);
@ -202,8 +279,11 @@ void NIS_Drawer::removeObject (const NIS_InteractiveObject * theObj,
// Stop dynamic hilighting if it has been activated // Stop dynamic hilighting if it has been activated
if (theObj->IsDynHilighted()) if (theObj->IsDynHilighted())
SetDynamicHilighted (Standard_False, theObj); SetDynamicHilighted (Standard_False, theObj);
if (myMapID.IsEmpty()) {
UpdateExListId(NULL);
}
// Set Updated for the draw type. // Set Updated for the draw type.
if (theObj->IsHidden() == Standard_False && isUpdateViews) else if (theObj->IsHidden() == Standard_False && isUpdateViews)
SetUpdated (theObj->DrawType()); SetUpdated (theObj->DrawType());
} }
@ -213,6 +293,7 @@ void NIS_Drawer::removeObject (const NIS_InteractiveObject * theObj,
//======================================================================= //=======================================================================
void NIS_Drawer::addObject (const NIS_InteractiveObject * theObj, void NIS_Drawer::addObject (const NIS_InteractiveObject * theObj,
const Standard_Boolean isShareList,
const Standard_Boolean isUpdateViews) const Standard_Boolean isUpdateViews)
{ {
myMapID.Add (theObj->ID()); myMapID.Add (theObj->ID());
@ -220,10 +301,14 @@ void NIS_Drawer::addObject (const NIS_InteractiveObject * theObj,
// Fill the drawer (if new) with DrawList instances for available Views. // Fill the drawer (if new) with DrawList instances for available Views.
if ( myLists.IsEmpty()) if ( myLists.IsEmpty())
{ {
NCollection_List<Handle_NIS_View>::Iterator anIter (GetContext()->myViews); if (isShareList)
myLists.Append (createDefaultList(NULL));
else {
NCollection_List<Handle_NIS_View>::Iterator anIter(GetContext()->myViews);
for (; anIter.More(); anIter.Next()) for (; anIter.More(); anIter.Next())
myLists.Append (createDefaultList(anIter.Value())); myLists.Append (createDefaultList(anIter.Value()));
} }
}
if (theObj->IsHidden() == Standard_False && isUpdateViews) if (theObj->IsHidden() == Standard_False && isUpdateViews)
SetUpdated (theObj->DrawType()); SetUpdated (theObj->DrawType());
@ -245,7 +330,8 @@ const Bnd_B3f& NIS_Drawer::GetBox (const NIS_View * pView) const
NCollection_List<NIS_DrawList*>::Iterator anIterL (myLists); NCollection_List<NIS_DrawList*>::Iterator anIterL (myLists);
for (; anIterL.More(); anIterL.Next()) { for (; anIterL.More(); anIterL.Next()) {
NIS_DrawList& aDrawList = * anIterL.ChangeValue(); NIS_DrawList& aDrawList = * anIterL.ChangeValue();
if (aDrawList.GetView().operator->() == pView) const Handle(NIS_View)& aView = aDrawList.GetView();
if (aView.IsNull() || aView.operator->() == pView)
break; break;
} }
if (anIterL.More()) if (anIterL.More())
@ -269,8 +355,9 @@ const Bnd_B3f& NIS_Drawer::GetBox (const NIS_View * pView) const
//function : prepareList //function : prepareList
//purpose : //purpose :
//======================================================================= //=======================================================================
void NIS_Drawer::prepareList( const NIS_Drawer::DrawType theType, void NIS_Drawer::prepareList(const NIS_Drawer::DrawType theType,
const NIS_DrawList& theDrawList ) const NIS_DrawList& theDrawList,
const TColStd_PackedMapOfInteger& mapObj)
{ {
if (!myCtx) if (!myCtx)
return; return;
@ -280,17 +367,15 @@ void NIS_Drawer::prepareList( const NIS_Drawer::DrawType theType,
if (theType == NIS_Drawer::Draw_DynHilighted) { if (theType == NIS_Drawer::Draw_DynHilighted) {
NCollection_List<Handle_NIS_InteractiveObject>::Iterator NCollection_List<Handle_NIS_InteractiveObject>::Iterator
anIter (theDrawList.DynHilightedList()); anIter (theDrawList.DynHilightedList());
for (; anIter.More(); anIter.Next()) if (anIter.More()) {
{
BeforeDraw (theType, theDrawList); BeforeDraw (theType, theDrawList);
for (; anIter.More(); anIter.Next())
Draw (anIter.Value(), NIS_Drawer::Draw_DynHilighted, theDrawList); Draw (anIter.Value(), NIS_Drawer::Draw_DynHilighted, theDrawList);
AfterDraw (theType, theDrawList); AfterDraw (theType, theDrawList);
} }
} else { } else {
// The common part of two maps (objects for this draw type & objects in // The common part of two maps (objects for this draw type & objects in
// the current Drawer) is used for updating the presentation. // the current Drawer) is used for updating the presentation.
TColStd_PackedMapOfInteger mapObj;
mapObj.Intersection (myCtx->myMapObjects[theType&0x3], myMapID);
TColStd_MapIteratorOfPackedMapOfInteger anIter (mapObj); TColStd_MapIteratorOfPackedMapOfInteger anIter (mapObj);
if (anIter.More()) { if (anIter.More()) {
BeforeDraw (theType, theDrawList); BeforeDraw (theType, theDrawList);
@ -313,5 +398,5 @@ void NIS_Drawer::prepareList( const NIS_Drawer::DrawType theType,
NIS_DrawList* NIS_Drawer::createDefaultList NIS_DrawList* NIS_Drawer::createDefaultList
(const Handle_NIS_View& theView) const (const Handle_NIS_View& theView) const
{ {
return new NIS_DrawList( theView ); return new NIS_DrawList(theView);
} }

View File

@ -28,21 +28,91 @@ class NIS_View;
template <class A> class NCollection_Vector; template <class A> class NCollection_Vector;
/** /**
* Abstract Drawer type * Abstract Drawer type.
* Drawer provides the immediate OpenGL drawing for every NIS_InteractiveObject
* maneged by the given Drawer instance. Each Drawer instance has reciprocal
* link with a number of NIS_InteractiveObject instances of the same
* (corresponding to Drawer) type. The idea is to group the drawing for all
* referred interactive objects using the same pre- and post-treatment like
* color setting, matrix, polygon offset, line thickness and what not.
*
* @section nis_drawer_visualprop Visual properties of Drawer
* Normally visual properties of any NIS_InteractiveObject are stored in its
* Drawer instance, but not in an object. For example, if an interactive object
* has method SetColor() then the color is stored in the corresponding Drawer
* rather than in the interactive object itself. This scheme avoid useless
* duplication when a lot of objects have similar properties like color. Please
* see @see nis_interactiveobject_drawer to learn how this mechanism
* works from the side of NIS_InteractiveObject.
*
* @section nis_drawer_drawing Drawing
* There are 3 virtual methods to implement OpenGL drawing in this API. They
* define the drawing cycle that consists of filling the internal OpenGL draw
* list with commands. This drawing cycle is triggered when the corresponding
* internal instance of NIS_DrawList has 'IsUpdated' flag (you can set this
* flag by means of public methods NIS_Drawer::SetUpdated()).
* <ul>
* <li><b>BeforeDraw()</b> : contains all OpenGL commands that define the
* common set of visual properties for all managed interactive objects.
* This method is called once in the beginning of drawing cycle for the
* Drawer instance</li>
* <li><b>Draw()</b> : all OpenGL commands that are specific to a given
* interactive object, usually definition of vertices, triangles, lines,
* or their arrays.</li>
* <li><b>AfterDraw()</b> : commands that revert the status of OpenGL context
* to the state before execution of BeforeDraw(). This method is called
* once in the end of drawing cycle.</li>
* </ul>
* Each of these methods receives NIS_DrawList and DrawType, both identify the
* OpenGL draw list that should be filled with commands. Based on DrawType
* you will be able to define different presentation - the most important case
* is how hilighted (selected) interactive object is presented.
* <p>
* For advanced purposes you also can redefine the virtual method redraw(), it
* is dedicated to higher-level management of draw lists and ordering of
* their update when necessary.
*
* @section nis_drawer_distinction Distinction of Drawer instances
* Every Drawer should define which interactive objects it may manage and
* which - may not. The same idea could be shaped alternatively: every
* interactive object should understand to what Drawer it can attach itself.
* This question is answerd by special virtual method IsEqual() that compares
* two Drawers of the same type. <b>Two instances of Drawer are equal if they
* have the same set of visual properties that are implemented in BeforeDraw().
* </b> The method IsEqual() is the core of Drawer architecture and it must
* be implemented very carefully for any new type. Particularly, for any
* derived class the method IsEqual() should first call the same method of
* its superclass.
* <p>
* For the optimal efficiency of OpenGL drawing it is better to keep the size
* of draw list (i.e., the number of interactive objects in a Drawer instance)
* not too small and not too big. The latter limitation is entered by the
* protected field myObjPerDrawer. It is used in method IsEqual() of the base
* Drawer class: two Drawers are not equal if they are initialized on objects
* that have too different IDs -- even if all visual properties of these two
* Drawer instances coincide.
* <p>
* @section nis_drawer_cloning Cloning Drawer instances
* It is possible to clone a Drawer instance with the viryual method Assign().
* This method copies all visual properties and other important data from the
* Drawer provided as parameter. Method Clone() also should be very carefully
* implemented for any new Drawer type, to make sure that all necessary data
* fields and structures are properly copied.
*/ */
class NIS_Drawer : public Standard_Transient class NIS_Drawer : public Standard_Transient
{ {
public: public:
#if (_MSC_VER < 1400) #if defined(WNT) && (_MSC_VER >= 1400)
enum DrawType {
#else
enum DrawType : unsigned int { enum DrawType : unsigned int {
#else
enum DrawType {
#endif #endif
Draw_Normal = 0, Draw_Normal = 0,
Draw_Transparent = 1, Draw_Top = 1,
Draw_Hilighted = 2, Draw_Transparent = 2,
Draw_DynHilighted = 3 Draw_Hilighted = 3,
Draw_DynHilighted = 4
}; };
public: public:
@ -52,7 +122,12 @@ class NIS_Drawer : public Standard_Transient
/** /**
* Empty constructor. * Empty constructor.
*/ */
inline NIS_Drawer () : myCtx (0L) {} inline NIS_Drawer ()
: myTransparency (0.f),
myIniId (0),
myObjPerDrawer (1024),
myCtx (0L)
{}
/** /**
* Destructor. * Destructor.
@ -91,6 +166,11 @@ class NIS_Drawer : public Standard_Transient
const DrawType theType2, const DrawType theType2,
const DrawType theType3) const; const DrawType theType3) const;
Standard_EXPORT void SetUpdated (const DrawType theType1,
const DrawType theType2,
const DrawType theType3,
const DrawType theType4) const;
/** /**
* Switch on/off the dynamic hilight of the given object in the * Switch on/off the dynamic hilight of the given object in the
* given view. * given view.
@ -126,7 +206,20 @@ class NIS_Drawer : public Standard_Transient
ObjectIterator () const ObjectIterator () const
{ return TColStd_MapIteratorOfPackedMapOfInteger (myMapID); } { return TColStd_MapIteratorOfPackedMapOfInteger (myMapID); }
/**
* Query associated draw lists.
*/
inline NCollection_List<NIS_DrawList *>
GetLists() const
{ return myLists; }
protected: protected:
/**
* Called to add draw list IDs to ex-list Ids of view. These draw lists are
* eventually released in the callback function, before anything is displayed
*/
Standard_EXPORT void UpdateExListId (const Handle_NIS_View& theView) const;
// ---------- PROTECTED METHODS ---------- // ---------- PROTECTED METHODS ----------
/** /**
@ -154,6 +247,7 @@ protected:
const Handle_NIS_View& theView); const Handle_NIS_View& theView);
Standard_EXPORT void addObject (const NIS_InteractiveObject * theObj, Standard_EXPORT void addObject (const NIS_InteractiveObject * theObj,
const Standard_Boolean isShareList,
const Standard_Boolean isUpVws); const Standard_Boolean isUpVws);
Standard_EXPORT void removeObject (const NIS_InteractiveObject * theObj, Standard_EXPORT void removeObject (const NIS_InteractiveObject * theObj,
@ -162,6 +256,11 @@ protected:
Standard_EXPORT virtual NIS_DrawList* Standard_EXPORT virtual NIS_DrawList*
createDefaultList (const Handle_NIS_View&) const; createDefaultList (const Handle_NIS_View&) const;
protected:
//! Get the number of interactive objects in this drawer
inline Standard_Integer NObjects() const
{ return myMapID.Extent(); }
private: private:
// ---------- PRIVATE (PROHIBITED) METHODS ---------- // ---------- PRIVATE (PROHIBITED) METHODS ----------
@ -170,11 +269,20 @@ protected:
// ---------- PRIVATE METHODS ---------- // ---------- PRIVATE METHODS ----------
void prepareList (const NIS_Drawer::DrawType theType, void prepareList (const NIS_Drawer::DrawType theType,
const NIS_DrawList& theDrawLst); const NIS_DrawList& theDrawLst,
const TColStd_PackedMapOfInteger& mapObj);
protected: protected:
// ---------- PROTECTED FIELDS ---------- // ---------- PROTECTED FIELDS ----------
NCollection_List<NIS_DrawList*> myLists; NCollection_List<NIS_DrawList*> myLists;
Standard_ShortReal myTransparency;
//! ID of the initializing InteractiveObject. It is never changed, can be
//! used to compute hash code of the Drawer instance.
Standard_Integer myIniId;
//! Maximal range of IDs of objects in one drawer. Limits the size of
//! draw lists. Can be initialized only in constructor (default 1024). It is
//! strictly prohibited to change this value outside the constructor.
Standard_Integer myObjPerDrawer;
private: private:
// ---------- PRIVATE FIELDS ---------- // ---------- PRIVATE FIELDS ----------
@ -185,6 +293,7 @@ protected:
friend class NIS_InteractiveContext; friend class NIS_InteractiveContext;
friend class NIS_InteractiveObject; friend class NIS_InteractiveObject;
friend class NIS_View;
public: public:
// Declaration of CASCADE RTTI // Declaration of CASCADE RTTI

View File

@ -8,16 +8,12 @@
#include <NIS_View.hxx> #include <NIS_View.hxx>
#include <TColStd_MapIteratorOfPackedMapOfInteger.hxx> #include <TColStd_MapIteratorOfPackedMapOfInteger.hxx>
#include <Standard_NoSuchObject.hxx> #include <Standard_NoSuchObject.hxx>
#include <Bnd_B2f.hxx>
IMPLEMENT_STANDARD_HANDLE (NIS_InteractiveContext, Standard_Transient) IMPLEMENT_STANDARD_HANDLE (NIS_InteractiveContext, Standard_Transient)
IMPLEMENT_STANDARD_RTTIEXT (NIS_InteractiveContext, Standard_Transient) IMPLEMENT_STANDARD_RTTIEXT (NIS_InteractiveContext, Standard_Transient)
static void deselectObj (const Handle(NIS_InteractiveObject)&, static void markAllDrawersUpdated (const NCollection_Map<Handle_NIS_Drawer>&);
const Standard_Integer,
TColStd_PackedMapOfInteger *);
static void selectObj (const Handle(NIS_InteractiveObject)&,
const Standard_Integer,
TColStd_PackedMapOfInteger *);
//======================================================================= //=======================================================================
//function : NIS_InteractiveContext() //function : NIS_InteractiveContext()
@ -25,8 +21,10 @@ static void selectObj (const Handle(NIS_InteractiveObject)&,
//======================================================================= //=======================================================================
NIS_InteractiveContext::NIS_InteractiveContext () NIS_InteractiveContext::NIS_InteractiveContext ()
: mySelectionMode (Mode_NoSelection), : myAllocator (new NIS_Allocator(1024*100)),
myAllocator (new NCollection_IncAllocator) // myDrawers (101, myAllocator),
mySelectionMode (Mode_NoSelection),
myIsShareDrawList (Standard_True)
{ {
// ID == 0 is invalid so we reserve this item from subsequent allocation. // ID == 0 is invalid so we reserve this item from subsequent allocation.
myObjects.Append (NULL); myObjects.Append (NULL);
@ -143,42 +141,42 @@ void NIS_InteractiveContext::GetBox (Bnd_B3f& theBox,
//======================================================================= //=======================================================================
void NIS_InteractiveContext::Display void NIS_InteractiveContext::Display
(const Handle_NIS_InteractiveObject& theObj, (Handle_NIS_InteractiveObject& theObj,
const Handle_NIS_Drawer& theDrawer, const Handle_NIS_Drawer& theDrawer,
const Standard_Boolean isUpdateViews) const Standard_Boolean isUpdateViews)
{ {
if (theObj.IsNull()) if (theObj.IsNull())
return; return;
Standard_Integer anID = theObj->ID(); objectForDisplay(theObj, theObj->DrawType());
Handle(NIS_Drawer) aDrawer = theDrawer; const Handle(NIS_Drawer)& aDrawer = drawerForDisplay(theObj, theDrawer);
if (aDrawer.IsNull() == Standard_False) { // Display Object as Normal or Transparent if it has been hidden
if (aDrawer->myCtx != this) if (theObj->IsHidden())
Standard_NoSuchObject::Raise ("NIS_InteractiveContext::Display (0)"); theObj->myIsHidden = Standard_False;
} else {
aDrawer = theObj->GetDrawer(); // Set Update flag in the Drawer
if (aDrawer.IsNull()) { if (isUpdateViews)
aDrawer = theObj->DefaultDrawer(); aDrawer->SetUpdated (theObj->DrawType());
aDrawer->myCtx = this; }
}
} //=======================================================================
if (anID == 0) { //function : DisplayOnTop
// Create a new ID for this object //purpose :
theObj->myID = myObjects.Length(); //=======================================================================
myObjects.Append (theObj);
myMapObjects[NIS_Drawer::Draw_Normal].Add(theObj->myID); void NIS_InteractiveContext::DisplayOnTop
} (Handle_NIS_InteractiveObject& theObj,
aDrawer = theObj->SetDrawer (aDrawer); const Handle_NIS_Drawer& theDrawer,
const Standard_Boolean isUpdateViews)
{
if (theObj.IsNull())
return;
objectForDisplay(theObj, NIS_Drawer::Draw_Top);
const Handle(NIS_Drawer)& aDrawer = drawerForDisplay(theObj, theDrawer);
// Display Object as Normal or Transparent if it has been hidden // Display Object as Normal or Transparent if it has been hidden
if (theObj->IsHidden()) if (theObj->IsHidden())
theObj->myIsHidden = Standard_False; theObj->myIsHidden = Standard_False;
// if (theObj->IsTransparent()) {
// myMapObjects[NIS_Drawer::Draw_Transparent].Add(anID);
// theObj->myDrawType = NIS_Drawer::Draw_Transparent;
// } else {
// myMapObjects[NIS_Drawer::Draw_Normal].Add(anID);
// theObj->myDrawType = NIS_Drawer::Draw_Normal;
// }
// Set Update flag in the Drawer // Set Update flag in the Drawer
if (isUpdateViews) if (isUpdateViews)
@ -221,6 +219,8 @@ void NIS_InteractiveContext::Remove (const Handle_NIS_InteractiveObject& theObj,
{ {
if (theObj.IsNull() == Standard_False) { if (theObj.IsNull() == Standard_False) {
const Handle(NIS_Drawer)& aDrawer = theObj->GetDrawer(); const Handle(NIS_Drawer)& aDrawer = theObj->GetDrawer();
if ( aDrawer.IsNull() )
return;
if (aDrawer->myCtx == this) { if (aDrawer->myCtx == this) {
// Remove the hilighting if the object has been hilighted // Remove the hilighting if the object has been hilighted
if (theObj->IsDynHilighted()) { if (theObj->IsDynHilighted()) {
@ -229,10 +229,10 @@ void NIS_InteractiveContext::Remove (const Handle_NIS_InteractiveObject& theObj,
if (anIterV.Value().IsNull() == Standard_False) if (anIterV.Value().IsNull() == Standard_False)
anIterV.Value()->DynamicUnhilight (theObj); anIterV.Value()->DynamicUnhilight (theObj);
} }
// Remove the obejct from the context // Remove the object from the context
const Standard_Integer anID = theObj->ID(); const Standard_Integer anID = theObj->ID();
const NIS_Drawer::DrawType aDrawType (theObj->DrawType()); const NIS_Drawer::DrawType aDrawType (theObj->DrawType());
if (myMapObjects[Standard_Integer(aDrawType)&0x3].Remove(anID)) if (myMapObjects[Standard_Integer(aDrawType)].Remove(anID))
aDrawer->removeObject(theObj.operator->(), isUpdateViews); aDrawer->removeObject(theObj.operator->(), isUpdateViews);
theObj->myID = 0; theObj->myID = 0;
theObj->myDrawer.Nullify(); theObj->myDrawer.Nullify();
@ -246,7 +246,7 @@ void NIS_InteractiveContext::Remove (const Handle_NIS_InteractiveObject& theObj,
//purpose : //purpose :
//======================================================================= //=======================================================================
void NIS_InteractiveContext::DisplayAll (const Standard_Boolean isUpdateViews) void NIS_InteractiveContext::DisplayAll ()
{ {
// UnHide all objects in the Context // UnHide all objects in the Context
NCollection_Vector <Handle_NIS_InteractiveObject>::Iterator anIter(myObjects); NCollection_Vector <Handle_NIS_InteractiveObject>::Iterator anIter(myObjects);
@ -258,17 +258,16 @@ void NIS_InteractiveContext::DisplayAll (const Standard_Boolean isUpdateViews)
} }
// Update status of objects in Drawers (particularly cancel dyn. hilighting) // Update status of objects in Drawers (particularly cancel dyn. hilighting)
if (isUpdateViews) {
NCollection_Map<Handle_NIS_Drawer>::Iterator anIterD (myDrawers); NCollection_Map<Handle_NIS_Drawer>::Iterator anIterD (myDrawers);
for (; anIterD.More(); anIterD.Next()) { for (; anIterD.More(); anIterD.Next()) {
const Handle(NIS_Drawer)& aDrawer = anIterD.Value(); const Handle(NIS_Drawer)& aDrawer = anIterD.Value();
if (aDrawer.IsNull() == Standard_False) { if (aDrawer.IsNull() == Standard_False) {
aDrawer->SetUpdated (NIS_Drawer::Draw_Normal, aDrawer->SetUpdated (NIS_Drawer::Draw_Normal,
NIS_Drawer::Draw_Top,
NIS_Drawer::Draw_Transparent, NIS_Drawer::Draw_Transparent,
NIS_Drawer::Draw_Hilighted); NIS_Drawer::Draw_Hilighted);
} }
} }
}
} }
//======================================================================= //=======================================================================
@ -276,7 +275,7 @@ void NIS_InteractiveContext::DisplayAll (const Standard_Boolean isUpdateViews)
//purpose : //purpose :
//======================================================================= //=======================================================================
void NIS_InteractiveContext::EraseAll (const Standard_Boolean isUpdateViews) void NIS_InteractiveContext::EraseAll ()
{ {
// Hide all objects in the Context // Hide all objects in the Context
NCollection_Vector <Handle_NIS_InteractiveObject>::Iterator anIter(myObjects); NCollection_Vector <Handle_NIS_InteractiveObject>::Iterator anIter(myObjects);
@ -299,14 +298,15 @@ void NIS_InteractiveContext::EraseAll (const Standard_Boolean isUpdateViews)
for (; anIterD.More(); anIterD.Next()) { for (; anIterD.More(); anIterD.Next()) {
const Handle(NIS_Drawer)& aDrawer = anIterD.Value(); const Handle(NIS_Drawer)& aDrawer = anIterD.Value();
if (aDrawer.IsNull() == Standard_False) { if (aDrawer.IsNull() == Standard_False) {
if (isUpdateViews)
aDrawer->SetUpdated (NIS_Drawer::Draw_Normal, aDrawer->SetUpdated (NIS_Drawer::Draw_Normal,
NIS_Drawer::Draw_Top,
NIS_Drawer::Draw_Transparent, NIS_Drawer::Draw_Transparent,
NIS_Drawer::Draw_Hilighted); NIS_Drawer::Draw_Hilighted);
// if (aList.myDynHilighted.IsEmpty() == Standard_False) { // if (aList.myDynHilighted.IsEmpty() == Standard_False) {
// aList.myIsUpdated[NIS_Drawer::Draw_DynHilighted]= Standard_True; // aList.myIsUpdated[NIS_Drawer::Draw_DynHilighted]= Standard_True;
// aList.myDynHilighted.Clear(); // aList.myDynHilighted.Clear();
// } // }
} }
} }
} }
@ -316,7 +316,7 @@ void NIS_InteractiveContext::EraseAll (const Standard_Boolean isUpdateViews)
//purpose : //purpose :
//======================================================================= //=======================================================================
void NIS_InteractiveContext::RemoveAll (const Standard_Boolean isUpdateViews) void NIS_InteractiveContext::RemoveAll ()
{ {
// Remove objects from the Context // Remove objects from the Context
NCollection_Vector <Handle_NIS_InteractiveObject>::Iterator anIter(myObjects); NCollection_Vector <Handle_NIS_InteractiveObject>::Iterator anIter(myObjects);
@ -335,43 +335,71 @@ void NIS_InteractiveContext::RemoveAll (const Standard_Boolean isUpdateViews)
} }
} }
// Remove objects from Drawers (particularly cancel dynamic hilighting) // Mark all draw lists to be removed in the view callback
NCollection_Map<Handle_NIS_Drawer>::Iterator anIterD (myDrawers); NCollection_Map<Handle_NIS_Drawer>::Iterator anIterD (myDrawers);
for (; anIterD.More(); anIterD.Next()) { for (; anIterD.More(); anIterD.Next()) {
const Handle(NIS_Drawer)& aDrawer = anIterD.Value(); const Handle(NIS_Drawer)& aDrawer = anIterD.Value();
if (aDrawer.IsNull() == Standard_False) { if (aDrawer.IsNull() == Standard_False) {
aDrawer->myMapID.Clear(); aDrawer->myMapID.Clear();
if (isUpdateViews) aDrawer->UpdateExListId(NULL);
aDrawer->SetUpdated (NIS_Drawer::Draw_Normal, aDrawer->myLists.Clear();
NIS_Drawer::Draw_Transparent,
NIS_Drawer::Draw_Hilighted);
// if (aList.myDynHilighted.IsEmpty() == Standard_False) {
// aList.myIsUpdated[NIS_Drawer::Draw_DynHilighted]= Standard_True;
// aList.myDynHilighted.Clear();
// }
} }
} }
// Remove Drawers
myDrawers.Clear();
// Release memory
myAllocator->Reset();
myAllocator->ResetCounters();
myDrawers.Clear();
// Remove objects from maps
myMapObjects[0].Clear();
myMapObjects[1].Clear();
myMapObjects[2].Clear();
myMapObjects[3].Clear();
myMapNonSelectableObjects.Clear();
}
//=======================================================================
//function : RebuildViews
//purpose :
//=======================================================================
void NIS_InteractiveContext::RebuildViews ()
{
const Handle_NIS_Allocator aNewAlloc = compactObjects();
// Recalculate all DrawLists in all drawers
markAllDrawersUpdated(myDrawers);
// It is time to destroy the old allocator, not before this line. Because
// the old allocator is needed to tidy up draw lists in SetUpdated() calls.
if (aNewAlloc.IsNull() == Standard_False)
myAllocator = aNewAlloc;
NCollection_List<Handle_NIS_View>::Iterator anIterV(myViews);
for (; anIterV.More(); anIterV.Next()) {
const Handle(NIS_View)& aView = anIterV.Value();
if (aView.IsNull() == Standard_False)
aView->Redraw();
}
} }
//======================================================================= //=======================================================================
//function : UpdateViews //function : UpdateViews
//purpose : //purpose : Only repaint the views refreshing their presentations only for
// those drawers that have been marked as updated.
//======================================================================= //=======================================================================
void NIS_InteractiveContext::UpdateViews () void NIS_InteractiveContext::UpdateViews ()
{ {
NCollection_Map<Handle_NIS_Drawer>::Iterator anIterD (myDrawers); const Handle_NIS_Allocator aNewAlloc = compactObjects();
for (; anIterD.More(); anIterD.Next()) { if (aNewAlloc.IsNull() == Standard_False)
const Handle(NIS_Drawer)& aDrawer = anIterD.Value(); myAllocator = aNewAlloc;
if (aDrawer.IsNull() == Standard_False) {
aDrawer->SetUpdated (NIS_Drawer::Draw_Normal, NCollection_List<Handle_NIS_View>::Iterator anIterV(myViews);
NIS_Drawer::Draw_Transparent,
NIS_Drawer::Draw_Hilighted);
// aList.myIsUpdated[NIS_Drawer::Draw_DynHilighted] =
// (aList.myDynHilighted.IsEmpty() == Standard_False);
}
}
NCollection_List<Handle_NIS_View>::Iterator anIterV (myViews);
for (; anIterV.More(); anIterV.Next()) { for (; anIterV.More(); anIterV.Next()) {
const Handle(NIS_View)& aView = anIterV.Value(); const Handle(NIS_View)& aView = anIterV.Value();
if (aView.IsNull() == Standard_False) if (aView.IsNull() == Standard_False)
@ -393,13 +421,13 @@ Standard_Boolean NIS_InteractiveContext::SetSelected
const Standard_Integer anID = theObj->ID(); const Standard_Integer anID = theObj->ID();
if (isSelected == Standard_False) { if (isSelected == Standard_False) {
if (myMapObjects[NIS_Drawer::Draw_Hilighted].Remove(anID)) { if (myMapObjects[NIS_Drawer::Draw_Hilighted].Remove(anID)) {
deselectObj (theObj, anID, &myMapObjects[0]); deselectObj (theObj, anID);
aResult = Standard_True; aResult = Standard_True;
} }
} else { } else {
if (IsSelectable(anID) == Standard_True) { if (IsSelectable(anID) == Standard_True) {
if (myMapObjects[NIS_Drawer::Draw_Hilighted].Add(anID)) { if (myMapObjects[NIS_Drawer::Draw_Hilighted].Add(anID)) {
selectObj (theObj, anID, &myMapObjects[0]); selectObj (theObj, anID);
aResult = Standard_True; aResult = Standard_True;
} }
} }
@ -421,9 +449,14 @@ Standard_Boolean NIS_InteractiveContext::ProcessSelection
Standard_Integer anID (0); Standard_Integer anID (0);
Standard_Boolean wasSelected (Standard_False); Standard_Boolean wasSelected (Standard_False);
if (theObj.IsNull() == Standard_False) { if (theObj.IsNull() == Standard_False) {
const Handle(NIS_Drawer)& aDrawer = theObj->GetDrawer();
if (aDrawer.IsNull() == Standard_False) {
if (aDrawer->GetContext() == this) {
anID = theObj->ID(); anID = theObj->ID();
wasSelected = myMapObjects[NIS_Drawer::Draw_Hilighted].Contains (anID); wasSelected = myMapObjects[NIS_Drawer::Draw_Hilighted].Contains (anID);
} }
}
}
switch (mySelectionMode) { switch (mySelectionMode) {
case Mode_Normal: case Mode_Normal:
@ -433,20 +466,20 @@ Standard_Boolean NIS_InteractiveContext::ProcessSelection
aResult = Standard_True; aResult = Standard_True;
} else if (wasSelected && mySelectionMode == Mode_Normal) { } else if (wasSelected && mySelectionMode == Mode_Normal) {
myMapObjects[NIS_Drawer::Draw_Hilighted].Remove( anID ); myMapObjects[NIS_Drawer::Draw_Hilighted].Remove( anID );
deselectObj (theObj, anID, &myMapObjects[0]); deselectObj (theObj, anID);
aResult = Standard_True; aResult = Standard_True;
break; break;
} }
if (wasSelected == Standard_False && IsSelectable(anID) == Standard_True) { if (wasSelected == Standard_False && IsSelectable(anID) == Standard_True) {
myMapObjects[NIS_Drawer::Draw_Hilighted].Add( anID ); myMapObjects[NIS_Drawer::Draw_Hilighted].Add( anID );
selectObj (theObj, anID, &myMapObjects[0]); selectObj (theObj, anID);
aResult = Standard_True; aResult = Standard_True;
} }
break; break;
case Mode_Exclusive: case Mode_Exclusive:
if (wasSelected) { if (wasSelected) {
myMapObjects[NIS_Drawer::Draw_Hilighted].Remove( anID ); myMapObjects[NIS_Drawer::Draw_Hilighted].Remove( anID );
deselectObj (theObj, anID, &myMapObjects[0]); deselectObj (theObj, anID);
aResult = Standard_True; aResult = Standard_True;
} }
break; break;
@ -476,7 +509,7 @@ void NIS_InteractiveContext::ProcessSelection
myMapObjects[NIS_Drawer::Draw_Hilighted] = aMap; myMapObjects[NIS_Drawer::Draw_Hilighted] = aMap;
for (anIter.Initialize (aMap); anIter.More(); anIter.Next()) { for (anIter.Initialize (aMap); anIter.More(); anIter.Next()) {
const Standard_Integer anID = anIter.Key(); const Standard_Integer anID = anIter.Key();
selectObj (myObjects(anID), anID, &myMapObjects[0]); selectObj (myObjects(anID), anID);
} }
} else { } else {
TColStd_PackedMapOfInteger aMapSub; TColStd_PackedMapOfInteger aMapSub;
@ -486,11 +519,11 @@ void NIS_InteractiveContext::ProcessSelection
myMapObjects[NIS_Drawer::Draw_Hilighted].Subtract (aMapSub); myMapObjects[NIS_Drawer::Draw_Hilighted].Subtract (aMapSub);
for (anIter.Initialize (aMap); anIter.More(); anIter.Next()) { for (anIter.Initialize (aMap); anIter.More(); anIter.Next()) {
const Standard_Integer anID = anIter.Key(); const Standard_Integer anID = anIter.Key();
selectObj (myObjects(anID), anID, &myMapObjects[0]); selectObj (myObjects(anID), anID);
} }
for (anIter.Initialize (aMapSub); anIter.More(); anIter.Next()) { for (anIter.Initialize (aMapSub); anIter.More(); anIter.Next()) {
const Standard_Integer anID = anIter.Key(); const Standard_Integer anID = anIter.Key();
deselectObj (myObjects(anID), anID, &myMapObjects[0]); deselectObj (myObjects(anID), anID);
} }
} }
break; break;
@ -499,7 +532,7 @@ void NIS_InteractiveContext::ProcessSelection
myMapObjects[NIS_Drawer::Draw_Hilighted].Unite (aMap); myMapObjects[NIS_Drawer::Draw_Hilighted].Unite (aMap);
for (anIter.Initialize (aMap); anIter.More(); anIter.Next()) { for (anIter.Initialize (aMap); anIter.More(); anIter.Next()) {
const Standard_Integer anID = anIter.Key(); const Standard_Integer anID = anIter.Key();
selectObj (myObjects(anID), anID, &myMapObjects[0]); selectObj (myObjects(anID), anID);
} }
break; break;
case Mode_Exclusive: case Mode_Exclusive:
@ -507,7 +540,7 @@ void NIS_InteractiveContext::ProcessSelection
myMapObjects[NIS_Drawer::Draw_Hilighted].Subtract (aMap); myMapObjects[NIS_Drawer::Draw_Hilighted].Subtract (aMap);
for (anIter.Initialize (aMap); anIter.More(); anIter.Next()) { for (anIter.Initialize (aMap); anIter.More(); anIter.Next()) {
const Standard_Integer anID = anIter.Key(); const Standard_Integer anID = anIter.Key();
deselectObj (myObjects(anID), anID, &myMapObjects[0]); deselectObj (myObjects(anID), anID);
} }
break; break;
default: ; default: ;
@ -541,7 +574,7 @@ void NIS_InteractiveContext::ClearSelected ()
(myMapObjects[NIS_Drawer::Draw_Hilighted]); (myMapObjects[NIS_Drawer::Draw_Hilighted]);
for (; anIter.More(); anIter.Next()) { for (; anIter.More(); anIter.Next()) {
const Standard_Integer anID = anIter.Key(); const Standard_Integer anID = anIter.Key();
deselectObj (myObjects(anID), anID, &myMapObjects[0]); deselectObj (myObjects(anID), anID);
} }
myMapObjects[NIS_Drawer::Draw_Hilighted].Clear(); myMapObjects[NIS_Drawer::Draw_Hilighted].Clear();
} }
@ -569,7 +602,7 @@ void NIS_InteractiveContext::SetSelected
aMapSub.Subtraction (myMapObjects[NIS_Drawer::Draw_Hilighted], aMap); aMapSub.Subtraction (myMapObjects[NIS_Drawer::Draw_Hilighted], aMap);
for (anIter.Initialize(aMapSub); anIter.More(); anIter.Next()) { for (anIter.Initialize(aMapSub); anIter.More(); anIter.Next()) {
const Standard_Integer anID = anIter.Key(); const Standard_Integer anID = anIter.Key();
deselectObj (myObjects(anID), anID, &myMapObjects[0]); deselectObj (myObjects(anID), anID);
} }
myMapObjects[NIS_Drawer::Draw_Hilighted].Subtract(aMapSub); myMapObjects[NIS_Drawer::Draw_Hilighted].Subtract(aMapSub);
} }
@ -579,7 +612,7 @@ void NIS_InteractiveContext::SetSelected
// Select objects // Select objects
for (anIter.Initialize (aMap); anIter.More(); anIter.Next()) { for (anIter.Initialize (aMap); anIter.More(); anIter.Next()) {
const Standard_Integer anID = anIter.Key(); const Standard_Integer anID = anIter.Key();
selectObj (myObjects(anID), anID, &myMapObjects[0]); selectObj (myObjects(anID), anID);
} }
} }
} }
@ -591,13 +624,16 @@ void NIS_InteractiveContext::SetSelected
Standard_Real NIS_InteractiveContext::selectObject Standard_Real NIS_InteractiveContext::selectObject
(Handle_NIS_InteractiveObject& theSel, (Handle_NIS_InteractiveObject& theSel,
NCollection_List<DetectedEnt>& theDetected,
const gp_Ax1& theAxis, const gp_Ax1& theAxis,
const Standard_Real theOver, const Standard_Real theOver,
const Standard_Boolean isOnlySel) const const Standard_Boolean isOnlySel) const
{ {
Standard_Real aResult (0.5 * RealLast()); static const Standard_Real anInfiniteDist = 0.5 * RealLast();
Standard_Real aMinDist(anInfiniteDist);
if (mySelectionMode != Mode_NoSelection || isOnlySel == Standard_False) if (mySelectionMode != Mode_NoSelection || isOnlySel == Standard_False)
{ {
DetectedEnt anEnt;
NCollection_Vector <Handle_NIS_InteractiveObject>::Iterator NCollection_Vector <Handle_NIS_InteractiveObject>::Iterator
anIter(myObjects); anIter(myObjects);
for (; anIter.More(); anIter.Next()) { for (; anIter.More(); anIter.Next()) {
@ -615,16 +651,29 @@ Standard_Real NIS_InteractiveContext::selectObject
const Bnd_B3f& aBox = anObj->GetBox(); const Bnd_B3f& aBox = anObj->GetBox();
if (aBox.IsOut (theAxis, Standard_False, theOver) == Standard_False) if (aBox.IsOut (theAxis, Standard_False, theOver) == Standard_False)
{ {
const Standard_Real aDist = anObj->Intersect (theAxis, theOver); anEnt.Dist = anObj->Intersect (theAxis, theOver);
if (aDist < aResult) { if (anEnt.Dist < anInfiniteDist) {
aResult = aDist; anEnt.PObj = anObj.operator->();
// Insert the detected entity in the sorted list
NCollection_List<DetectedEnt>::Iterator anIterD(theDetected);
for (; anIterD.More(); anIterD.Next()) {
if (anEnt.Dist < anIterD.Value().Dist) {
theDetected.InsertBefore(anEnt, anIterD);
break;
}
}
if (anIterD.More() == Standard_False)
theDetected.Append(anEnt);
if (anEnt.Dist < aMinDist) {
aMinDist = anEnt.Dist;
theSel = anObj; theSel = anObj;
} }
} }
} }
} }
} }
return aResult; }
return aMinDist;
} }
//======================================================================= //=======================================================================
@ -646,7 +695,7 @@ void NIS_InteractiveContext::SetSelectable
anID = anIter.Key(); anID = anIter.Key();
if ( myMapObjects[NIS_Drawer::Draw_Hilighted].Contains(anID)) { if ( myMapObjects[NIS_Drawer::Draw_Hilighted].Contains(anID)) {
myMapObjects[NIS_Drawer::Draw_Hilighted].Remove(anID); myMapObjects[NIS_Drawer::Draw_Hilighted].Remove(anID);
deselectObj (myObjects(anID), anID, &myMapObjects[0]); deselectObj (myObjects(anID), anID);
} }
} }
myMapNonSelectableObjects.Unite(objIDs); myMapNonSelectableObjects.Unite(objIDs);
@ -694,25 +743,90 @@ Standard_Boolean NIS_InteractiveContext::selectObjects
return aResult; return aResult;
} }
//=======================================================================
//function : selectObjects
//purpose :
//=======================================================================
Standard_Boolean NIS_InteractiveContext::selectObjects
(TColStd_PackedMapOfInteger &mapObj,
const NCollection_List<gp_XY> &thePolygon,
const Bnd_B2f &thePolygonBox,
const gp_Trsf &theTrfInv,
const Standard_Boolean isFullyIn) const
{
Standard_Boolean aResult (Standard_False);
if (mySelectionMode != Mode_NoSelection) {
NCollection_Vector <Handle_NIS_InteractiveObject>::Iterator
anIter(myObjects);
for (; anIter.More(); anIter.Next()) {
const Handle(NIS_InteractiveObject)& anObj = anIter.Value();
if (anObj.IsNull() == Standard_False)
if (anObj->IsDisplayed()) {
// Pass the object through the SelectFilter if available
if (mySelectFilter.IsNull() == Standard_False)
if (mySelectFilter->IsOk (anObj.operator->()) == Standard_False)
continue;
// Comvert 3d box to 2d one
const Bnd_B3f &aBox = anObj->GetBox();
Bnd_B2f aB2d;
Standard_Real aX[2];
Standard_Real aY[2];
Standard_Real aZ[2];
gp_XYZ aBoxVtx;
Standard_Integer i;
aBox.CornerMin().Coord(aX[0], aY[0], aZ[0]);
aBox.CornerMax().Coord(aX[1], aY[1], aZ[1]);
for (i = 0; i < 8; i++) {
aBoxVtx.SetX(aX[(i & 1) ? 1 : 0]);
aBoxVtx.SetY(aY[(i & 2) ? 1 : 0]);
aBoxVtx.SetZ(aZ[(i & 4) ? 1 : 0]);
theTrfInv.Transforms(aBoxVtx);
aB2d.Add(gp_XY(aBoxVtx.X(), aBoxVtx.Y()));
}
// Check the intersection with the box
if (thePolygonBox.IsOut(aB2d) == Standard_False) {
if (anObj->Intersect(thePolygon, theTrfInv, isFullyIn)) {
mapObj.Add (anObj->ID());
aResult = Standard_True;
}
}
}
}
}
return aResult;
}
//======================================================================= //=======================================================================
//function : deselectObj //function : deselectObj
//purpose : //purpose :
//======================================================================= //=======================================================================
void deselectObj (const Handle(NIS_InteractiveObject)& theObj, void NIS_InteractiveContext::deselectObj
const Standard_Integer theID, (const Handle(NIS_InteractiveObject)& theObj,
TColStd_PackedMapOfInteger * mapObjects) const Standard_Integer theID)
{ {
if (theObj.IsNull() == Standard_False) { if (theObj.IsNull() == Standard_False) {
const Handle(NIS_Drawer)& aDrawer = theObj->GetDrawer(); const Handle(NIS_Drawer)& aDrawer = theObj->GetDrawer();
if (theObj->IsTransparent()) { if (theObj->IsTransparent()) {
mapObjects[NIS_Drawer::Draw_Transparent].Add(theID); myMapObjects[NIS_Drawer::Draw_Transparent].Add(theID);
aDrawer->SetUpdated(NIS_Drawer::Draw_Transparent); aDrawer->SetUpdated(NIS_Drawer::Draw_Transparent);
} else if (theObj->myBaseType == NIS_Drawer::Draw_Top) {
myMapObjects[NIS_Drawer::Draw_Top].Add(theID);
aDrawer->SetUpdated(NIS_Drawer::Draw_Top);
} else { } else {
mapObjects[NIS_Drawer::Draw_Normal].Add(theID); myMapObjects[NIS_Drawer::Draw_Normal].Add(theID);
aDrawer->SetUpdated(NIS_Drawer::Draw_Normal); aDrawer->SetUpdated(NIS_Drawer::Draw_Normal);
} }
aDrawer->SetUpdated(NIS_Drawer::Draw_Hilighted); aDrawer->SetUpdated(NIS_Drawer::Draw_Hilighted);
theObj->myDrawType = theObj->myBaseType;
} }
} }
@ -721,20 +835,129 @@ void deselectObj (const Handle(NIS_InteractiveObject)& theObj,
//purpose : //purpose :
//======================================================================= //=======================================================================
void selectObj (const Handle(NIS_InteractiveObject)& theObj, void NIS_InteractiveContext::selectObj
const Standard_Integer theID, (const Handle(NIS_InteractiveObject)& theObj,
TColStd_PackedMapOfInteger * mapObjects) const Standard_Integer theID)
{ {
if (theObj.IsNull() == Standard_False) { if (theObj.IsNull() == Standard_False) {
const Handle(NIS_Drawer)& aDrawer = theObj->GetDrawer(); const Handle(NIS_Drawer)& aDrawer = theObj->GetDrawer();
if (theObj->IsTransparent()) { if (theObj->IsTransparent()) {
mapObjects[NIS_Drawer::Draw_Transparent].Remove(theID); myMapObjects[NIS_Drawer::Draw_Transparent].Remove(theID);
aDrawer->SetUpdated(NIS_Drawer::Draw_Transparent); aDrawer->SetUpdated(NIS_Drawer::Draw_Transparent);
} else if (theObj->myDrawType == NIS_Drawer::Draw_Top) {
myMapObjects[NIS_Drawer::Draw_Top].Remove(theID);
aDrawer->SetUpdated(NIS_Drawer::Draw_Top);
} else { } else {
mapObjects[NIS_Drawer::Draw_Normal].Remove(theID); myMapObjects[NIS_Drawer::Draw_Normal].Remove(theID);
aDrawer->SetUpdated(NIS_Drawer::Draw_Normal); aDrawer->SetUpdated(NIS_Drawer::Draw_Normal);
} }
aDrawer->SetUpdated(NIS_Drawer::Draw_Hilighted); aDrawer->SetUpdated(NIS_Drawer::Draw_Hilighted);
theObj->myDrawType = NIS_Drawer::Draw_Hilighted;
} }
} }
//=======================================================================
//function : drawerForDisplay
//purpose :
//=======================================================================
const Handle_NIS_Drawer& NIS_InteractiveContext::drawerForDisplay
(const Handle_NIS_InteractiveObject& theObj,
const Handle_NIS_Drawer& theDrawer)
{
Handle(NIS_Drawer) aDrawer;
if (theDrawer.IsNull() == Standard_False) {
if (theDrawer->myCtx != this)
Standard_NoSuchObject::Raise ("NIS_InteractiveContext::Display (0)");
aDrawer = theDrawer;
} else {
const Handle(NIS_Drawer)& anObjDrawer = theObj->GetDrawer();
if (anObjDrawer.IsNull() == Standard_False)
return anObjDrawer;
aDrawer = theObj->DefaultDrawer(0L);
aDrawer->myCtx = this;
}
return theObj->SetDrawer (aDrawer, Standard_False);
}
//=======================================================================
//function : objectIdForDisplay
//purpose :
//=======================================================================
void NIS_InteractiveContext::objectForDisplay
(Handle_NIS_InteractiveObject& theObj,
const NIS_Drawer::DrawType theDrawType)
{
if (theObj->ID() == 0) {
// Create a new ID for this object
Handle(NIS_InteractiveObject) anObj;
theObj->Clone(myAllocator, anObj);
theObj = anObj;
anObj->myID = myObjects.Length();
myObjects.Append (anObj);
myMapObjects[theDrawType].Add(anObj->myID);
anObj->myDrawType = theDrawType;
}
}
//=======================================================================
//function : compactObjects
//purpose :
//=======================================================================
Handle_NIS_Allocator NIS_InteractiveContext::compactObjects()
{
Handle(NIS_Allocator) aNewAlloc;
NCollection_List<Handle_NIS_View>::Iterator anIterV;
// Check if the memory used by objects has to be compacted.
const Standard_Size nAllocated = myAllocator->NAllocated();
if (nAllocated > 1024*1024) {
const Standard_Size nFreed = myAllocator->NFreed();
if ((nFreed * 5) / 3 > nAllocated || nFreed > 20*1024*1024)
{
for (anIterV.Init(myViews); anIterV.More(); anIterV.Next()) {
const Handle(NIS_View)& aView = anIterV.Value();
if (aView.IsNull() == Standard_False) {
aView->myDynHilighted.Nullify();
aView->GetDetected().Clear();
}
}
// Compact the memory: clone all objects to a new allocator, release
// the old allocator instance.
aNewAlloc = new NIS_Allocator;
NCollection_Vector<Handle_NIS_InteractiveObject>::Iterator
anIter(myObjects);
for (; anIter.More(); anIter.Next()) {
if (anIter.Value().IsNull() == Standard_False) {
Handle(NIS_InteractiveObject)& aNewObj = anIter.ChangeValue();
const Handle(NIS_InteractiveObject) anObj = aNewObj;
aNewObj.Nullify();
anObj->CloneWithID(aNewAlloc, aNewObj);
}
}
}
}
return aNewAlloc;
}
//=======================================================================
//function : markAllDrawersUpdated
//purpose :
//=======================================================================
void markAllDrawersUpdated (const NCollection_Map<Handle_NIS_Drawer>& lstDrv)
{
NCollection_Map<Handle_NIS_Drawer>::Iterator anIterD (lstDrv);
for (; anIterD.More(); anIterD.Next()) {
const Handle(NIS_Drawer)& aDrawer = anIterD.Value();
if (aDrawer.IsNull() == Standard_False) {
aDrawer->SetUpdated (NIS_Drawer::Draw_Normal,
NIS_Drawer::Draw_Top,
NIS_Drawer::Draw_Transparent,
NIS_Drawer::Draw_Hilighted);
}
}
}

View File

@ -9,9 +9,9 @@
#include <Handle_NIS_InteractiveObject.hxx> #include <Handle_NIS_InteractiveObject.hxx>
#include <Handle_NIS_View.hxx> #include <Handle_NIS_View.hxx>
#include <NCollection_IncAllocator.hxx>
#include <NCollection_Map.hxx> #include <NCollection_Map.hxx>
#include <NCollection_Vector.hxx> #include <NCollection_Vector.hxx>
#include <NIS_Allocator.hxx>
#include <NIS_Drawer.hxx> #include <NIS_Drawer.hxx>
#include <NIS_SelectFilter.hxx> #include <NIS_SelectFilter.hxx>
@ -23,36 +23,42 @@
class NIS_View; class NIS_View;
class Bnd_B3f; class Bnd_B3f;
class Bnd_B2f;
/** /**
* InteractiveContext is the central NIS structure that stores and manages * InteractiveContext is the central NIS structure that stores and manages
* all InteractiveObject instances as well as the Drawers for their * all NIS_InteractiveObject instances as well as the Drawers for their
* visualisation. * visualisation.
* There may be one or more Views referred by an InteractiveContext instance. * There may be one or more Views referred by an InteractiveContext instance.
* Also there may be one or more InteractiveContext instances referring the same * Also there may be one or more InteractiveContext instances referring the same
* View. However the latter case is not typical (see NIS_View description).<br> * View. However the latter case is not typical (see NIS_View description).<br>
* To add or remove a View in a Context, use methods AttachView() and * To add or remove a View in a Context, use methods AttachView() and
* DetachView(). * DetachView().
* <p>The main purpose of class NIS_InteractiveContext is allocation and *
* @section nis_interactivecontext_mgtobjects Management of objects
* The main purpose of class NIS_InteractiveContext is allocation and
* management of NIS_InteractiveObject instances. * management of NIS_InteractiveObject instances.
* <p>An InteractiveObject should be added to the Context by a call to method * <p>An InteractiveObject should be added to the Context by a call to method
* Display(). After that (not before) it becomes possible to: * Display() or DisplayOnTop(). After that (not before) it becomes possible to:
* <ul> * <ul>
* <li>change the presentation of the InteractiveObject (e.g., modify the color) * <li>change the presentation of the InteractiveObject (e.g., modify the color)
* </li> * </li>
* <li>make the InteractiveObject visible or invisible;</li> * <li>make the InteractiveObject visible or invisible, selectable or
* unselectable;</li>
* <li>set Transparency;</li> * <li>set Transparency;</li>
* <li>select InteractiveObject interactively, including the hilighting and * <li>select InteractiveObject interactively, including the hilighting and
* the dynamic hilighting.</li> * the dynamic hilighting.</li>
* </ul> * </ul>
* All methods managing InteractiveObject instances have the optional parameter * Methods that add/remove/display/hide NIS_InteractiveObject instances have
* 'isUpdateViews'. When it is set to True (default), the modification of the * the optional parameter 'isUpdateViews'. When it is set to True (default),
* object brings about the immediate update of the presentation (the * the modification of the object brings about an immediate update of its
* corresponding Drawer is flagged to recompute presentations). However, for * presentation (the corresponding Drawer flagged to recompute presentations).
* block operations when many InteractiveObject instances are affected it is * Normally you do not have to worry about this parameter leaving it assigned to
* usually better to delay this recalculation till a definite moment in the end * the default value; use the alternative value 'Standard_False' only for
* of updates. Then you can set the optional parameter to False and in the end - * very special purposes, like animation -- when many updates should be
* call the method UpdateViews of the NIS_InteractiveContext. * synchronized in time. For other methods like changing the transparency or
* color definition there is no parameter 'isUpdateViews', all changes mark
* the corresponding drawers immediately.
* <p>Typical scheme of usage: * <p>Typical scheme of usage:
* @code * @code
* const Handle(NIS_InteractiveContext) aContext = new NIS_InteractiveContext; * const Handle(NIS_InteractiveContext) aContext = new NIS_InteractiveContext;
@ -60,26 +66,53 @@ class Bnd_B3f;
* aContext->AttachView (aView); * aContext->AttachView (aView);
* .... * ....
* for (; ;) { * for (; ;) {
* const Handle(NIS_InteractiveObject) anObject = new ... * const Handle(MyIOClass) anObject = new MyIOClass();
* aContext->Display (anObject, NULL, Standard_False); * aContext->Display (anObject);
* anObject->SetColor(...); // method of class MyIOClass
* ... * ...
* } * }
* aContext->UpdateViews();
* @endcode * @endcode
* Additional services provided by InteractiveContext: * @section nis_interactivecontext_display Method Display()
* This method performs three important tasks, when called the first time for
* an object:
* <ul> * <ul>
* <li>Every instance of this class maintains a distinct * <li>Copy its argument to the memory pool that is managed by the internal
* NCollection_IncAllocator that can be used by contained * Allocator of NIS_InteractiveContext. Then <b>the new instance of
* NIS_InteractiveObject and NIS_Drawer instances. For example, each Object * object</b> is returned back in the same argument (in-out parameter);</li>
* may be assigned a name using the method SetAttribute, like: * <li>Store the copied instance in the internal vector of objects, so that
* @code * the displayed object receives its ID (sequential address in the vector);
* Standard_Size aLen = strlen(theName)+1; * </li>
* char * aName = (char *) myContext->Allocator()->Allocate(aLen); * <li>Create a Drawer instance if necessary; attach the displayed interactive
* memcpy (aName, theName, aLen); * object to this instance (or to a relevant and already existing Drawer)
* myObject->SetAttribute(aName);
* @endcode
* </li> * </li>
* </ul> * </ul>
* Thus any methods dealing with Drawer-related properties like color, line
* width, polygon offset, etc. can only be called following the necessary call
* of method Display().
* <p>
* Subsequent calls to Display() just revert previous calls of Erase() without
* any re-initialization of interactive object or its drawer.
*
* @section nis_interactivecontext_memory Using the memory
* As described in the sections above, all interactive objects should completely
* reside in the special memory pool managed by the InteractiveContext instance.
* This is a fast memory (NCollection_IncAllocator is used) but it has the
* drawback: when you destroy an object using method Remove() it is detached
* from NIS_InteractiveContext and its presentation is removed from all Views.
* But the memory allocated for that removed object is not released and it
* cannot be reused by new interactive objects. In time there may appear too
* many "dead" objects to hinder or even crash the application.
* <p>
* This problem is resolved by automatic keeping the record of the total size
* of both used and unused memory, in the instance of NIS_Allocator. When the
* amount of unused memory becomes too big then the method compactObjects()
* creates a new NIS_Allocator instance and copies there all interactive
* objects that are 'alive' then releasing the previous memory pool. All
* object IDs and their drawers remain intact, so nothing is changed except
* the greater amount of available memory in the system.
* <p>
* This mechanism works when either UpdateViews() or RebuildViews() is called
* from time to time, only these two methods can call compactObjects().
*/ */
class NIS_InteractiveContext : public Standard_Transient class NIS_InteractiveContext : public Standard_Transient
@ -135,7 +168,7 @@ class NIS_InteractiveContext : public Standard_Transient
NbObjects () NbObjects ()
// { return myObjects.Length()-1; } // { return myObjects.Length()-1; }
{ return (myMapObjects[0].Extent() + myMapObjects[1].Extent() + { return (myMapObjects[0].Extent() + myMapObjects[1].Extent() +
myMapObjects[2].Extent()); } myMapObjects[2].Extent()) + myMapObjects[3].Extent(); }
/** /**
* Query the total number of Drawers instances. * Query the total number of Drawers instances.
@ -145,11 +178,12 @@ class NIS_InteractiveContext : public Standard_Transient
{ return myDrawers.Size(); } { return myDrawers.Size(); }
/** /**
* Query the memory allocator associated with InteractiveContext instance. * Access to Drawers, can be used for specific operations where it is not
* desirale to iterate InteractiveObjects.
*/ */
inline const Handle_NCollection_IncAllocator& inline NCollection_Map<Handle_NIS_Drawer>::Iterator
Allocator () const GetDrawers () const
{ return myAllocator; } { return NCollection_Map<Handle_NIS_Drawer>::Iterator(myDrawers); }
// ================ BEGIN Mangement of Objects ================ // ================ BEGIN Mangement of Objects ================
///@name Management of Objects ///@name Management of Objects
@ -161,6 +195,31 @@ class NIS_InteractiveContext : public Standard_Transient
* this method should follow the creation of an InteractiveObject instance * this method should follow the creation of an InteractiveObject instance
* before it can be displayed. * before it can be displayed.
* @param theObj * @param theObj
* <tt>[in/out]</tt>Interactive object instance. If the object is displayed
* for the first time then the output value will be a new (cloned) object.
* @param theDrawer
* If this parameter is NULL, the default drawer is used for theObj, defined
* by the object type. Otherwise the given Drawer (must be present in this
* context) is used for theObj. Use the parameter to change the presentation
* of theObj.
* @param isUpdateViews
* If True, the drawer receives isUpdate flag, then it will recompute
* the presentations when Redraw event happens. You can leave the parameter
* to False if you have to make a number of similar calls, then you would
* call UpdateViews() in the end.
*/
Standard_EXPORT void Display (Handle_NIS_InteractiveObject& theObj,
const Handle_NIS_Drawer& theDrawer = NULL,
const Standard_Boolean isUpdateViews
= Standard_True);
/**
* Make the given interactive object visible on top of other objects in
* the current context.
* If the object is not yet added to this context, it is added. Therefore
* this method should follow the creation of an InteractiveObject instance
* before it can be displayed.
* @param theObj
* Interactive object instance. * Interactive object instance.
* @param theDrawer * @param theDrawer
* If this parameter is NULL, the default drawer is used for theObj, defined * If this parameter is NULL, the default drawer is used for theObj, defined
@ -173,7 +232,7 @@ class NIS_InteractiveContext : public Standard_Transient
* to False if you have to make a number of similar calls, then you would * to False if you have to make a number of similar calls, then you would
* call UpdateViews() in the end. * call UpdateViews() in the end.
*/ */
Standard_EXPORT void Display (const Handle_NIS_InteractiveObject& theObj, Standard_EXPORT void DisplayOnTop (Handle_NIS_InteractiveObject& theObj,
const Handle_NIS_Drawer& theDrawer = NULL, const Handle_NIS_Drawer& theDrawer = NULL,
const Standard_Boolean isUpdateViews const Standard_Boolean isUpdateViews
= Standard_True); = Standard_True);
@ -209,45 +268,33 @@ class NIS_InteractiveContext : public Standard_Transient
/** /**
* Make all stored InteractiveObject instances visible, equivalent to * Make all stored InteractiveObject instances visible, equivalent to
* calling method Display() for all contained objects. * calling method Display() for all contained objects.
* @param isUpdateViews
* If True, the drawer receives isUpdate flag, then it will recompute
* the presentations when Redraw event happens. You can leave the parameter
* to False if you have to make a number of similar calls, then you would
* call UpdateViews() in the end.
*/ */
Standard_EXPORT void DisplayAll (const Standard_Boolean isUpdateViews Standard_EXPORT void DisplayAll ();
= Standard_True);
/** /**
* Make all stored InteractiveObject instances invisible, equivalent to * Make all stored InteractiveObject instances invisible, equivalent to
* calling method Erase() for all contained objects. * calling method Erase() for all contained objects.
* @param isUpdateViews
* If True, the drawer receives isUpdate flag, then it will recompute
* the presentations when Redraw event happens. You can leave the parameter
* to False if you have to make a number of similar calls, then you would
* call UpdateViews() in the end.
*/ */
Standard_EXPORT void EraseAll (const Standard_Boolean isUpdateViews Standard_EXPORT void EraseAll ();
= Standard_True);
/** /**
* Clean the context of its contained objects. Drawers are not destroyed * Clean the context of its contained objects. Drawers are destroyed
* however all presentations should become empty. * and all presentations become empty.
* @param isUpdateViews
* If True, the drawer receives isUpdate flag, then it will recompute
* the presentations when Redraw event happens. You can leave the parameter
* to False if you have to make a number of similar calls, then you would
* call UpdateViews() in the end.
*/ */
Standard_EXPORT void RemoveAll (const Standard_Boolean isUpdateViews Standard_EXPORT void RemoveAll ();
= Standard_True);
/** /**
* This method signal that the presenation should be refreshed in all * This method signals that the presenation should be refreshed in all updated
* Drawers and in all Views. * Drawers and in all Views. Calls Redraw() of each view from inside.
*/ */
Standard_EXPORT void UpdateViews (); Standard_EXPORT void UpdateViews ();
/**
* Similar to UpdateViews but forces all presentations to be rebuilt whether
* the drawers are marked as updated or not.
*/
Standard_EXPORT void RebuildViews();
/** /**
* Find the bounding box of all Objects displayed (visible) in the given View. * Find the bounding box of all Objects displayed (visible) in the given View.
* @param theBox * @param theBox
@ -402,24 +449,35 @@ class NIS_InteractiveContext : public Standard_Transient
inline Standard_Boolean IsSelectable (const Standard_Integer objID) const inline Standard_Boolean IsSelectable (const Standard_Integer objID) const
{ return (myMapNonSelectableObjects.Contains( objID ) == Standard_False); } { return (myMapNonSelectableObjects.Contains( objID ) == Standard_False); }
/**
* Set or reset the flag that tells to NIS_Drawer to create shared DrawList.
* The default mode (in Constructor) is True.
*/
inline void SetShareDrawList (Standard_Boolean isShare)
{ myIsShareDrawList = isShare; }
//@} //@}
// ====== END Selection API ================ // ====== END Selection API ================
protected: protected:
//! Structure referencing one detected (picked) interactive entity.
struct DetectedEnt
{
Standard_Real Dist; //!< Distance on the view direction
NIS_InteractiveObject* PObj; //!< Pointer to interactive object
};
// ---------- PROTECTED METHODS ---------- // ---------- PROTECTED METHODS ----------
Standard_EXPORT void redraw (const Handle_NIS_View& theView, Standard_EXPORT void redraw (const Handle_NIS_View& theView,
const NIS_Drawer::DrawType theType); const NIS_Drawer::DrawType theType);
/*Standard_EXPORT void prepareList (const NIS_Drawer::DrawType theType,
const NIS_DrawList& theView,
NIS_Drawer * theDrawer);
*/
/** /**
* Detect the object selected by the given ray. * Detect the object selected by the given ray.
* @param theSel * @param theSel
* <tt>[out]</tt> The selected object that has the lowest ray distance. * <tt>[out]</tt> The selected object that has the lowest ray distance.
* @param theDet
* <tt>[out]</tt> Sorted list of all detected objects with ray distances
* @param theAxis * @param theAxis
* Selection ray * Selection ray
* @param theOver * @param theOver
@ -432,6 +490,7 @@ class NIS_InteractiveContext : public Standard_Transient
*/ */
Standard_EXPORT Standard_Real Standard_EXPORT Standard_Real
selectObject (Handle_NIS_InteractiveObject& theSel, selectObject (Handle_NIS_InteractiveObject& theSel,
NCollection_List<DetectedEnt>& theDet,
const gp_Ax1& theAxis, const gp_Ax1& theAxis,
const Standard_Real theOver, const Standard_Real theOver,
const Standard_Boolean isOnlySelectable const Standard_Boolean isOnlySelectable
@ -461,9 +520,58 @@ class NIS_InteractiveContext : public Standard_Transient
const gp_Trsf& theTrfInv, const gp_Trsf& theTrfInv,
const Standard_Boolean isFullyIn)const; const Standard_Boolean isFullyIn)const;
/**
* Build a list of objects that are inside or touched by a polygon.
* @param mapObj
* <tt>[out]</tt> Container of object IDs, updated by detected objects.
* @param thePolygon
* the list of vertices of a free-form closed polygon without
* self-intersections. The last point should not coincide with the first
* point of the list. Any two neighbor points should not be confused.
* @param thePolygonBox
* 2D box of selection polygon
* @param theTrfInv
* Inverted Position/Orientation of the plane where thePolygon is defined
* (for polygon-object intersections)
* @param isFullyIn
* True if only those objects are processed that are fully inside the
* selection polygon. False if objects fully or partially included in
* the polygon are processed.
* @return
* True if at least one object was selected.
*/
Standard_EXPORT Standard_Boolean
selectObjects (TColStd_PackedMapOfInteger &mapObj,
const NCollection_List<gp_XY> &thePolygon,
const Bnd_B2f &thePolygonBox,
const gp_Trsf &theTrfInv,
const Standard_Boolean isFullyIn) const;
private:
void deselectObj (const Handle_NIS_InteractiveObject&,
const Standard_Integer);
void selectObj (const Handle_NIS_InteractiveObject&,
const Standard_Integer);
const Handle_NIS_Drawer&
drawerForDisplay (const Handle_NIS_InteractiveObject&,
const Handle_NIS_Drawer&);
void objectForDisplay (Handle_NIS_InteractiveObject&,
const NIS_Drawer::DrawType);
Handle_NIS_Allocator
compactObjects ();
private: private:
// ---------- PRIVATE FIELDS ---------- // ---------- PRIVATE FIELDS ----------
/**
* Allocator for all data associated with objects.
*/
Handle_NIS_Allocator myAllocator;
/** /**
* Container of InteractiveObject instances. * Container of InteractiveObject instances.
*/ */
@ -483,11 +591,12 @@ class NIS_InteractiveContext : public Standard_Transient
/** /**
* Three maps indicating the state of contained objects: * Three maps indicating the state of contained objects:
* - #0 - normally presented objects * - #0 - normally presented objects
* - #1 - hilighted objects (i.e., selected) * - #1 - top objects
* - #2 - transparent objects * - #2 - hilighted objects (i.e., selected)
* - #3 - transparent objects
* <br>Each object can have only one entry in these maps. * <br>Each object can have only one entry in these maps.
*/ */
TColStd_PackedMapOfInteger myMapObjects[3]; TColStd_PackedMapOfInteger myMapObjects[4];
/** /**
* Objects contained in this map are ignored by SetSelected methods, * Objects contained in this map are ignored by SetSelected methods,
@ -500,20 +609,15 @@ class NIS_InteractiveContext : public Standard_Transient
*/ */
Handle_NIS_SelectFilter mySelectFilter; Handle_NIS_SelectFilter mySelectFilter;
/**
* Current selection.
*/
// TColStd_PackedMapOfInteger mySelection;
/** /**
* Current mode of selection. * Current mode of selection.
*/ */
SelectionMode mySelectionMode; SelectionMode mySelectionMode;
/** /**
* Allocator for arbitrary data associated with objects and drawers. * Flag that allows to use single draw list for all views.
*/ */
Handle_NCollection_IncAllocator myAllocator; Standard_Boolean myIsShareDrawList;
friend class NIS_View; friend class NIS_View;
friend class NIS_Drawer; friend class NIS_Drawer;

View File

@ -28,7 +28,8 @@ NIS_InteractiveObject::~NIS_InteractiveObject ( )
//======================================================================= //=======================================================================
const Handle_NIS_Drawer& NIS_InteractiveObject::SetDrawer const Handle_NIS_Drawer& NIS_InteractiveObject::SetDrawer
(const Handle(NIS_Drawer)& theDrawer) (const Handle(NIS_Drawer)& theDrawer,
const Standard_Boolean setUpdated)
{ {
NIS_InteractiveContext * aCtx = theDrawer->GetContext(); NIS_InteractiveContext * aCtx = theDrawer->GetContext();
if (myDrawer.IsNull() == Standard_False) if (myDrawer.IsNull() == Standard_False)
@ -47,6 +48,8 @@ const Handle_NIS_Drawer& NIS_InteractiveObject::SetDrawer
Standard_NullValue_Raise_if Standard_NullValue_Raise_if
(aCtx == 0L, "NIS_InteractiveObject::SetDrawer: NULL drawer context"); (aCtx == 0L, "NIS_InteractiveObject::SetDrawer: NULL drawer context");
// Add (if necessary) the new drawer to the Context // Add (if necessary) the new drawer to the Context
if (theDrawer->myIniId == 0)
theDrawer->myIniId = myID;
const Handle(NIS_Drawer)& aDrawer = aCtx->myDrawers.Added (theDrawer); const Handle(NIS_Drawer)& aDrawer = aCtx->myDrawers.Added (theDrawer);
if (myDrawer != aDrawer) if (myDrawer != aDrawer)
{ {
@ -55,8 +58,13 @@ const Handle_NIS_Drawer& NIS_InteractiveObject::SetDrawer
myDrawer->removeObject(this, Standard_True); myDrawer->removeObject(this, Standard_True);
myDrawer = aDrawer; myDrawer = aDrawer;
myDrawer->addObject(this, Standard_True); myDrawer->addObject(this, aCtx->myIsShareDrawList, Standard_True);
} }
if (setUpdated)
myDrawer->SetUpdated (NIS_Drawer::Draw_Normal,
NIS_Drawer::Draw_Top,
NIS_Drawer::Draw_Transparent,
NIS_Drawer::Draw_Hilighted);
return aDrawer; return aDrawer;
} }
@ -67,13 +75,23 @@ const Handle_NIS_Drawer& NIS_InteractiveObject::SetDrawer
void NIS_InteractiveObject::SetTransparency (const Standard_Real theValue) void NIS_InteractiveObject::SetTransparency (const Standard_Real theValue)
{ {
if (fabs(theValue - myTransparency) > 0.001) { Standard_Integer aValue =
if (theValue > 0.001) static_cast<Standard_Integer> (theValue * MaxTransparency);
myTransparency = static_cast<const Standard_ShortReal> (theValue); if (aValue != static_cast<Standard_Integer>(myTransparency))
{
if (aValue <= 0)
myTransparency = 0;
else if (aValue >= 1000)
myTransparency = 1000u;
else else
myTransparency = 0.f; myTransparency = static_cast<unsigned int> (aValue);
if (myDrawer.IsNull() == Standard_False && myID != 0) { if (myDrawer.IsNull() == Standard_False && myID != 0) {
const Handle(NIS_Drawer) aDrawer = DefaultDrawer(0L);
aDrawer->Assign (GetDrawer());
aDrawer->myTransparency = Transparency();
SetDrawer (aDrawer, Standard_False);
NIS_InteractiveContext * aCtx = myDrawer->GetContext(); NIS_InteractiveContext * aCtx = myDrawer->GetContext();
Standard_NullValue_Raise_if Standard_NullValue_Raise_if
(aCtx == 0L, "NIS_InteractiveObject::SetTransparency: " (aCtx == 0L, "NIS_InteractiveObject::SetTransparency: "
@ -113,6 +131,44 @@ const Bnd_B3f& NIS_InteractiveObject::GetBox ()
return myBox; return myBox;
} }
//=======================================================================
//function : Clone
//purpose :
//=======================================================================
void NIS_InteractiveObject::Clone (const Handle_NCollection_BaseAllocator&,
Handle_NIS_InteractiveObject& theDest) const
{
if (theDest.IsNull() == Standard_False)
{
theDest->myID = 0;
theDest->myDrawer = myDrawer;
theDest->myDrawType = myDrawType;
theDest->myBaseType = myBaseType;
theDest->myIsHidden = myIsHidden;
theDest->myIsDynHilighted = myIsDynHilighted;
theDest->myIsUpdateBox = myIsUpdateBox;
theDest->myTransparency = myTransparency;
if (myIsUpdateBox == Standard_False)
theDest->myBox = myBox;
theDest->myAttributePtr = myAttributePtr;
}
}
//=======================================================================
//function : CloneWithID
//purpose :
//=======================================================================
void NIS_InteractiveObject::CloneWithID
(const Handle_NCollection_BaseAllocator& theAlloc,
Handle_NIS_InteractiveObject& theDest)
{
Clone(theAlloc, theDest);
theDest->myID = myID;
myDrawer.Nullify();
}
//======================================================================= //=======================================================================
//function : Intersect //function : Intersect
//purpose : //purpose :
@ -125,6 +181,19 @@ Standard_Boolean NIS_InteractiveObject::Intersect (const Bnd_B3f&,
return Standard_True; return Standard_True;
} }
//=======================================================================
//function : Intersect
//purpose :
//=======================================================================
Standard_Boolean NIS_InteractiveObject::Intersect
(const NCollection_List<gp_XY> &thePolygon,
const gp_Trsf &theTrf,
const Standard_Boolean isFull) const
{
return Standard_True;
}
//======================================================================= //=======================================================================
//function : IsSelectable //function : IsSelectable
//purpose : Query if the Object is selectable. //purpose : Query if the Object is selectable.
@ -151,16 +220,10 @@ void NIS_InteractiveObject::SetSelectable (const Standard_Boolean isSel) const
aCtx->myMapNonSelectableObjects.Remove (myID); aCtx->myMapNonSelectableObjects.Remove (myID);
else { else {
aCtx->myMapNonSelectableObjects.Add (myID); aCtx->myMapNonSelectableObjects.Add (myID);
if (aCtx->myMapObjects[NIS_Drawer::Draw_Hilighted].Remove(myID)) if (myDrawType == NIS_Drawer::Draw_Hilighted)
{ {
if (IsTransparent()) { aCtx->myMapObjects[NIS_Drawer::Draw_Hilighted].Remove(myID);
aCtx->myMapObjects[NIS_Drawer::Draw_Transparent].Add(myID); aCtx->deselectObj (this, myID);
myDrawer->SetUpdated(NIS_Drawer::Draw_Transparent);
} else {
aCtx->myMapObjects[NIS_Drawer::Draw_Normal].Add(myID);
myDrawer->SetUpdated(NIS_Drawer::Draw_Normal);
}
myDrawer->SetUpdated(NIS_Drawer::Draw_Hilighted);
} }
} }
} }

View File

@ -16,22 +16,26 @@
* An InteractiveObject has the attributes: * An InteractiveObject has the attributes:
* <ul> * <ul>
* <li>Integer ID that is unique within the Interactive Context that hosts * <li>Integer ID that is unique within the Interactive Context that hosts
* this Object. Thsi ID is 0 if the Object is not yet attached to an * this Object. This ID is 0 if the Object is not yet attached to an
* InteractiveContext</li> * InteractiveContext</li>
* <li>3D Bounding box</li> * <li>3D Bounding box</li>
* <li>Presenatble state of the Object: Normal, Hilighted or Transparent.</li> * <li>Presentable state of the Object: Normal, Hilighted or Transparent.</li>
* <li>Visibility state (shown/hidden)</li> * <li>Visibility state (shown/hidden)</li>
* <li>Transparency level (0 to 1) - for transparent state</li> * <li>Selectability (selectable/non-selectable)</li>
* <li>Transparency level (0 to 1 in 1/1000 steps) - for transparent state</li>
* </ul> * </ul>
* Because the class is abstract, it does not define any color, material and * Because the class is abstract, it does not define any color, material and
* other visual aspect - all relevant aspects should be defined in derived * other visual aspect - all relevant aspects should be defined in derived
* classes.<br> * classes and their Drawers.
*
* @section nis_interactiveobject_drawer Drawers for NIS_InteractiveObject
* Every InteractiveObject type should have an associated NIS_Drawer type; a * Every InteractiveObject type should have an associated NIS_Drawer type; a
* new instance of this associated drawer is returned by the virtual method * new instance of this associated drawer must be returned by the virtual method
* DefaultDrawer(). The drawer is responsible for the correct calculation of * DefaultDrawer(). The drawer is responsible for the correct calculation of
* the presentation in every possible state (normal, hilighted, etc.); usually * the presentation in every possible state (normal, hilighted, etc.); usually
* the associated drawer instance contains all relevant visual aspects.<p> * the associated drawer instance contains all relevant visual aspects.
* Association with a Drawer instance is performed by method SetDrawer. This * <p>
* Association with a Drawer instance is performed by method SetDrawer(). This
* method should not be called by any custom code, it is used internally by * method should not be called by any custom code, it is used internally by
* NIS algorithms (in NIS_InteractiveContext::Display() for instance). If you * NIS algorithms (in NIS_InteractiveContext::Display() for instance). If you
* develop your own InteractiveObject type, you will need to call SetDrawer * develop your own InteractiveObject type, you will need to call SetDrawer
@ -39,17 +43,68 @@
* @code * @code
* void MyIOClass::SetColor (const Quantity_Color& theColor); * void MyIOClass::SetColor (const Quantity_Color& theColor);
* { * {
* Handle(MyIOClassDrawer) aDrawer = new MyIOClassDrawer; * const Handle(MyIOClassDrawer) aDrawer =
* static_cast<MyIOClassDrawer*>(DefaultDrawer(0L));
* // copy the current visual aspects and other attributes to the new Drawer * // copy the current visual aspects and other attributes to the new Drawer
* aDrawer->Assign (GetDrawer()); * aDrawer->Assign (GetDrawer());
* // replace the Drawer * // replace the Drawer
* aDrawer->myColor = theColor; * aDrawer->myColor = theColor;
* SetDrawer (aDrawer); * SetDrawer (aDrawer);
* // optional: redraws the changed InteractiveObject in the views
* GetDrawer()->GetContext()->UpdateViews();
* } * }
* @endcode * @endcode
* <p> * Please keep in mind that with this scheme you should not store the color in
* MyIOClass type, because it is already stored in its Drawer.
*
* @section nis_interactiveobject_selection Interactive selection
* Interactive selection is made in class NIS_InteractiveContext, methods
* selectObjects(). These methods call the virtual API of interactive object,
* that consists of 3 methods:
* <ul>
* <li>Intersect (theAxis, theOver) : find the intersection point with a 3D ray,
* the method returns the coordinate of intersection point on the ray.
* Parameter theOver provides the tolerance for intersection of thin
* geometries (lines, vertices)</li>
* <li>Intersect (theBox, theTrsf, isFullIn) : check if the interactive object
* intersects with a 3D box. Transformation 'theTrf' is the <b>inverse</b>
* box transformation, so it is applied to the interactive object rather
* than to the 3D box (3D box stays axis-aligned during intersection
* test). Parameter IsFullIn defines the condition for the result: if
* True then the whole interactive object must be contained inside the box,
* otherwise it is sufficient if only a portion (e.g., a point) is inside.
* This method is used for interactive rectangle selection.</li>
* <li>Intersect (thePolygon, theTrsf, isFullIn) : similar to the previous
* method, but using a polygonal prism instead of box, for selection by
* closed curve or polygon.</li>
* </ul>
*
* @section nis_interactiveobject_memory Memory management
* All data used in the scope of NIS_InteractiveObject subtype should be either
* its explicit fields or pointers to memory managed by a special NIS_Allocator
* instance that belongs to NIS_InteractiveContext. This is strictly required
* because NIS_InteractiveContext should completely manage all its objects,
* meaning that it destroys/reallocates them automatically. To support that,
* the virtual method Clone() should be correctly defined for every interactive
* object subtype. Supposing that MyIOClass inherits MyBaseIOBase :
* @code
* void MyIOCalss::Clone (const Handle_NCollection_BaseAllocator& theAlloc,
* Handle_NIS_InteractiveObject& theDest) const
* {
* Handle(MyIOClass) aNewObj;
* if (theDest.IsNull()) {
* aNewObj = new MyIOClass();
* theDest = aNewObj;
* } else {
* aNewObj = reinterpret_cast<MyIOClass*> (theDest.operator->());
* aNewObj->myAlloc = theAlloc;
* }
* MyIOBase::Clone(theAlloc, theDest);
* aNewObj->myDataField = myDataField;
* memcpy(myNewObj->myDataArray, myDataArray, nBytes);
* ...
* }
* @endcode
*
* @section nis_interactiveobject_attribute Attribute
* An instance of this class can have an associated value (Attribute) that is * An instance of this class can have an associated value (Attribute) that is
* stored as a pointer. It can accommodate an integer/float/boolean value or * stored as a pointer. It can accommodate an integer/float/boolean value or
* a pointer to some structure. This attribute is NOT automatically destroyed * a pointer to some structure. This attribute is NOT automatically destroyed
@ -68,10 +123,11 @@ class NIS_InteractiveObject : public Standard_Transient
inline NIS_InteractiveObject () inline NIS_InteractiveObject ()
: myID (0), : myID (0),
myDrawType (NIS_Drawer::Draw_Normal), myDrawType (NIS_Drawer::Draw_Normal),
myBaseType (NIS_Drawer::Draw_Normal),
myIsHidden (Standard_True), myIsHidden (Standard_True),
myIsDynHilighted (Standard_False), myIsDynHilighted (Standard_False),
myIsUpdateBox (Standard_True), myIsUpdateBox (Standard_True),
myTransparency (0.f), myTransparency (0),
myAttributePtr (0L) myAttributePtr (0L)
{} {}
@ -106,7 +162,9 @@ class NIS_InteractiveObject : public Standard_Transient
* the Context. * the Context.
*/ */
Standard_EXPORT const Handle_NIS_Drawer& Standard_EXPORT const Handle_NIS_Drawer&
SetDrawer (const Handle_NIS_Drawer& theDrawer); SetDrawer (const Handle_NIS_Drawer& theDrawer,
const Standard_Boolean setUpdated
= Standard_True);
/** /**
* Query the current drawer. * Query the current drawer.
@ -116,10 +174,14 @@ class NIS_InteractiveObject : public Standard_Transient
{ return myDrawer; } { return myDrawer; }
/** /**
* Create a default drawer instance. * Create a default drawer instance. In the upper-level call (in subclass)
* it is always called with NULL parameter. Then it should call the same
* method of the superclass (except for NIS_InteractiveObject superclass type)
* with the created Drawer instance as parameter.
* @see NIS_Triangulated as example.
*/ */
Standard_EXPORT virtual Handle_NIS_Drawer Standard_EXPORT virtual NIS_Drawer *
DefaultDrawer () const = 0; DefaultDrawer (NIS_Drawer * theDrv) const = 0;
/** /**
* Query a 3D bounding box of the object. * Query a 3D bounding box of the object.
@ -131,7 +193,7 @@ class NIS_InteractiveObject : public Standard_Transient
* Query the Transparent state. * Query the Transparent state.
*/ */
inline Standard_Boolean IsTransparent () const inline Standard_Boolean IsTransparent () const
{ return myTransparency > 0.001; } { return myTransparency > 0; }
/** /**
* Query the Hidden state * Query the Hidden state
@ -154,7 +216,7 @@ class NIS_InteractiveObject : public Standard_Transient
/** /**
* Query if the Object is selectable. * Query if the Object is selectable.
*/ */
Standard_EXPORT Standard_Boolean Standard_EXPORT virtual Standard_Boolean
IsSelectable () const; IsSelectable () const;
/** /**
@ -163,14 +225,15 @@ class NIS_InteractiveObject : public Standard_Transient
* True (default) - the Object will be selectable, False - it will be * True (default) - the Object will be selectable, False - it will be
* ignored by selection/hilighting algorithms. * ignored by selection/hilighting algorithms.
*/ */
Standard_EXPORT void SetSelectable (const Standard_Boolean isSel Standard_EXPORT virtual void
SetSelectable (const Standard_Boolean isSel
= Standard_True) const; = Standard_True) const;
/** /**
* Query the Transparency factor. * Query the Transparency factor.
*/ */
inline Standard_Real Transparency () const inline Standard_ShortReal Transparency () const
{ return myTransparency; } { return static_cast<Standard_ShortReal>(myTransparency) / MaxTransparency; }
/** /**
* Set the Transparency factor. * Set the Transparency factor.
@ -183,6 +246,23 @@ class NIS_InteractiveObject : public Standard_Transient
inline void UnsetTransparency () inline void UnsetTransparency ()
{ SetTransparency (0.); } { SetTransparency (0.); }
/**
* Create a copy of theObject except its ID.
* @param theAll
* Allocator where the Dest should store its private data.
* @param theDest
* <tt>[in-out]</tt> The target object where the data are copied.
*/
Standard_EXPORT virtual void
Clone (const Handle_NCollection_BaseAllocator& theAll,
Handle_NIS_InteractiveObject& theDest) const;
/**
* The same as Clone() but also copies the ID.
*/
Standard_EXPORT void CloneWithID (const Handle_NCollection_BaseAllocator&,
Handle_NIS_InteractiveObject&);
/** /**
* Intersect the InteractiveObject geometry with a line/ray. * Intersect the InteractiveObject geometry with a line/ray.
* @param theAxis * @param theAxis
@ -227,6 +307,32 @@ class NIS_InteractiveObject : public Standard_Transient
const gp_Trsf& theTrf, const gp_Trsf& theTrf,
const Standard_Boolean isFull) const; const Standard_Boolean isFull) const;
/**
* Intersect the InteractiveObject geometry with a selection polygon.
* The default implementation (in this abstract class) always returns True,
* signalling that every object pre-selected by its bounding box is
* automatically selected. The specializations should define a more correct
* behaviour.<br>
* The algorithm should transform the InteractiveObject geometry using the
* parameter theTrf and then reject it with polygon.
* @param thePolygon
* the list of vertices of a free-form closed polygon without
* self-intersections. The last point should not coincide with the first
* point of the list. Any two neighbor points should not be confused.
* @param theTrf
* Position/Orientation of the polygon. It coincides with theTrfInv that is
* passed to NIS_InteractiveContext::selectObjects().
* @param isFull
* True if full inclusion is required (full inside the tested box) for
* the positive result, False - if only partial inclusion give a result.
* @return
* True if the InteractiveObject geometry intersects the polygon or is inside it
*/
Standard_EXPORT virtual Standard_Boolean
Intersect (const NCollection_List<gp_XY> &thePolygon,
const gp_Trsf &theTrf,
const Standard_Boolean isFull) const;
/** /**
* Set the pointer to custom (arbitrary) data associated with the Object. * Set the pointer to custom (arbitrary) data associated with the Object.
*/ */
@ -267,18 +373,21 @@ class NIS_InteractiveObject : public Standard_Transient
// ---------- PRIVATE FIELDS ---------- // ---------- PRIVATE FIELDS ----------
Handle_NIS_Drawer myDrawer; Handle_NIS_Drawer myDrawer;
Standard_Size myID : 26; Standard_Size myID;
NIS_Drawer::DrawType myDrawType : 2; NIS_Drawer::DrawType myDrawType : 3;
NIS_Drawer::DrawType myBaseType : 3;
Standard_Boolean myIsHidden : 1; Standard_Boolean myIsHidden : 1;
Standard_Boolean myIsDynHilighted: 1; Standard_Boolean myIsDynHilighted: 1;
Standard_Boolean myIsUpdateBox : 1; Standard_Boolean myIsUpdateBox : 1;
Standard_ShortReal myTransparency; unsigned int myTransparency : 10;
static const unsigned int MaxTransparency = 1000;
protected: protected:
Bnd_B3f myBox; Bnd_B3f myBox;
void * myAttributePtr; void * myAttributePtr;
friend class NIS_InteractiveContext; friend class NIS_InteractiveContext;
friend class NIS_Drawer; friend class NIS_Drawer;

View File

@ -34,3 +34,16 @@ void NIS_ObjectsIterator::Next ()
if (myIter.Value().IsNull() == Standard_False) if (myIter.Value().IsNull() == Standard_False)
break; break;
} }
//=======================================================================
//function : Value
//purpose :
//=======================================================================
const Handle(NIS_InteractiveObject)& NIS_ObjectsIterator::Value() const
{
if (More())
return myIter.Value();
static const Handle(NIS_InteractiveObject) aNullObj;
return aNullObj;
}

View File

@ -69,9 +69,8 @@ class NIS_ObjectsIterator
* Returns the current object at the iteration pointer. If the iteration is * Returns the current object at the iteration pointer. If the iteration is
* over (More() == False) this method returns NULL Handle. * over (More() == False) this method returns NULL Handle.
*/ */
inline Handle(NIS_InteractiveObject) Standard_EXPORT const Handle_NIS_InteractiveObject&
Value () const Value () const;
{ if (More()) return myIter.Value(); return NULL; }
/** /**
* Step forward to the next valid InteractiveObject instance. * Step forward to the next valid InteractiveObject instance.

View File

@ -6,31 +6,39 @@
#include <NIS_Surface.hxx> #include <NIS_Surface.hxx>
#include <NIS_SurfaceDrawer.hxx> #include <NIS_SurfaceDrawer.hxx>
#include <NIS_Triangulated.hxx> #include <NIS_Triangulated.hxx>
#include <BRepMesh_IncrementalMesh.hxx>
#include <BRep_ListIteratorOfListOfCurveRepresentation.hxx>
#include <BRep_PolygonOnTriangulation.hxx>
#include <BRep_TEdge.hxx>
#include <BRep_Tool.hxx> #include <BRep_Tool.hxx>
#include <Geom_Surface.hxx> #include <Geom_Surface.hxx>
#include <NCollection_Map.hxx>
#include <Poly_PolygonOnTriangulation.hxx>
#include <Poly_Triangulation.hxx> #include <Poly_Triangulation.hxx>
#include <Precision.hxx> #include <Precision.hxx>
#include <TColgp_Array1OfPnt2d.hxx> #include <TColgp_Array1OfPnt2d.hxx>
#include <TopExp.hxx>
#include <TopExp_Explorer.hxx> #include <TopExp_Explorer.hxx>
#include <TopLoc_Location.hxx> #include <TopLoc_Location.hxx>
#include <TopTools_MapOfShape.hxx>
#include <TopoDS.hxx> #include <TopoDS.hxx>
#include <TopoDS_Face.hxx> #include <TopoDS_Face.hxx>
#include <TopoDS_Edge.hxx>
#include <TShort_Array1OfShortReal.hxx>
#include <gp_Ax1.hxx> #include <gp_Ax1.hxx>
IMPLEMENT_STANDARD_HANDLE (NIS_Surface, NIS_InteractiveObject) IMPLEMENT_STANDARD_HANDLE (NIS_Surface, NIS_InteractiveObject)
IMPLEMENT_STANDARD_RTTIEXT(NIS_Surface, NIS_InteractiveObject) IMPLEMENT_STANDARD_RTTIEXT(NIS_Surface, NIS_InteractiveObject)
//======================================================================= //=======================================================================
//function : defaultDrawer //function : IsEqual
//purpose : internal method (static) //purpose : Compare two triangulations, for NCollection_Map interface.
//======================================================================= //=======================================================================
inline Handle(NIS_SurfaceDrawer) defaultDrawer() inline Standard_Boolean IsEqual(const Handle_Poly_Triangulation& theT0,
const Handle_Poly_Triangulation& theT1)
{ {
const Handle(NIS_SurfaceDrawer) aDrawer = return (theT0 == theT1);
new NIS_SurfaceDrawer(Quantity_NOC_SLATEBLUE4);
aDrawer->SetBackColor (Quantity_NOC_DARKGREEN);
return aDrawer;
} }
//======================================================================= //=======================================================================
@ -38,14 +46,36 @@ inline Handle(NIS_SurfaceDrawer) defaultDrawer()
//purpose : //purpose :
//======================================================================= //=======================================================================
NIS_Surface::NIS_Surface NIS_Surface::NIS_Surface(const Handle_NCollection_BaseAllocator& theAlloc)
(const Handle(Poly_Triangulation)& theTri, : myAlloc (theAlloc),
const Handle_NCollection_BaseAllocator& theAlloc) mypNodes (NULL),
: mypNodes (NULL),
mypNormals (NULL), mypNormals (NULL),
mypTriangles (NULL),
mypEdges (NULL),
myNNodes (0), myNNodes (0),
myNTriangles (0), myNTriangles (0),
myAlloc (theAlloc) myNEdges (0),
myIsWireframe(0)
{
if (myAlloc.IsNull())
myAlloc = NCollection_BaseAllocator::CommonBaseAllocator();
}
//=======================================================================
//function : NIS_Surface
//purpose :
//=======================================================================
NIS_Surface::NIS_Surface (const Handle(Poly_Triangulation)& theTri,
const Handle_NCollection_BaseAllocator& theAlloc)
: myAlloc (theAlloc),
mypNodes (NULL),
mypNormals (NULL),
mypEdges (NULL),
myNNodes (0),
myNTriangles (0),
myNEdges (0),
myIsWireframe(0)
{ {
if (myAlloc.IsNull()) if (myAlloc.IsNull())
myAlloc = NCollection_BaseAllocator::CommonBaseAllocator(); myAlloc = NCollection_BaseAllocator::CommonBaseAllocator();
@ -107,47 +137,75 @@ NIS_Surface::NIS_Surface
//purpose : Constructor //purpose : Constructor
//======================================================================= //=======================================================================
NIS_Surface::NIS_Surface NIS_Surface::NIS_Surface (const TopoDS_Shape& theShape,
(const TopoDS_Shape& theShape, const Standard_Real theDeflection,
// const Standard_Real theDeflection,
const Handle_NCollection_BaseAllocator& theAlloc) const Handle_NCollection_BaseAllocator& theAlloc)
: mypNodes (NULL), : myAlloc (theAlloc),
mypNodes (NULL),
mypNormals (NULL), mypNormals (NULL),
mypTriangles (NULL), mypTriangles (NULL),
mypEdges (NULL),
myNNodes (0), myNNodes (0),
myNTriangles (0), myNTriangles (0),
myAlloc (theAlloc) myNEdges (0),
myIsWireframe (0)
{ {
if (myAlloc.IsNull()) if (myAlloc.IsNull())
myAlloc = NCollection_BaseAllocator::CommonBaseAllocator(); myAlloc = NCollection_BaseAllocator::CommonBaseAllocator();
Init (theShape, theDeflection);
}
//=======================================================================
//function : Init
//purpose : Initialize the instance with a TopoDS_Shape.
//=======================================================================
void NIS_Surface::Init (const TopoDS_Shape& theShape,
const Standard_Real theDeflection)
{
TopLoc_Location aLoc, aLocSurf; TopLoc_Location aLoc, aLocSurf;
// Count the nodes and triangles in faces // Count the nodes and triangles in faces
NCollection_Map<Handle_Poly_Triangulation> mapTri;
TopExp_Explorer fexp (theShape, TopAbs_FACE); TopExp_Explorer fexp (theShape, TopAbs_FACE);
for ( ; fexp.More(); fexp.Next() ) for (; fexp.More(); fexp.Next())
{ {
TopoDS_Face aFace = TopoDS::Face(fexp.Current()); const TopoDS_Face& aFace = TopoDS::Face(fexp.Current());
const Handle(Poly_Triangulation)& aTriangulation const Handle(Poly_Triangulation)& aTriangulation
= BRep_Tool::Triangulation (aFace, aLoc); = BRep_Tool::Triangulation (aFace, aLoc);
const Handle(Geom_Surface)& aSurf = BRep_Tool::Surface(aFace, aLoc);
if (aTriangulation.IsNull() == Standard_False && if (aTriangulation.IsNull())
aSurf.IsNull() == Standard_False) BRepMesh_IncrementalMesh aMeshTool(aFace, theDeflection);
if (aTriangulation.IsNull() == Standard_False)
{ {
myNNodes += aTriangulation->NbNodes(); myNNodes += aTriangulation->NbNodes();
myNTriangles += aTriangulation->NbTriangles(); myNTriangles += aTriangulation->NbTriangles();
mapTri.Add(aTriangulation);
} }
} }
// Alocate arrays of entities // Create map of edges, to build wireframe for all edges.
TopTools_MapOfShape mapEdges;
TopExp_Explorer eexp (theShape, TopAbs_EDGE);
for (; eexp.More(); eexp.Next())
{
const TopoDS_Shape& anEdge = eexp.Current();
mapEdges.Add(anEdge);
}
// Allocate arrays of entities
if (myNNodes && myNTriangles) { if (myNNodes && myNTriangles) {
mypNodes = static_cast<Standard_ShortReal*> mypNodes = static_cast<Standard_ShortReal *>
(myAlloc->Allocate(sizeof(Standard_ShortReal) * 3 * myNNodes)); (myAlloc->Allocate(sizeof(Standard_ShortReal) * 3 * myNNodes));
mypNormals = static_cast<Standard_ShortReal *> mypNormals = static_cast<Standard_ShortReal *>
(myAlloc->Allocate(sizeof(Standard_ShortReal) * 3 * myNNodes)); (myAlloc->Allocate(sizeof(Standard_ShortReal) * 3 * myNNodes));
mypTriangles = static_cast<Standard_Integer*> mypTriangles = static_cast<Standard_Integer *>
(myAlloc->Allocate(sizeof(Standard_Integer) * 3 * myNTriangles)); (myAlloc->Allocate(sizeof(Standard_Integer) * 3 * myNTriangles));
mypEdges = static_cast<Standard_Integer **>
(myAlloc->Allocate(sizeof(Standard_Integer *) * mapEdges.Extent()));
myNEdges = 0;
// The second loop: copy all nodes and triangles face-by-face // The second loop: copy all nodes and triangles face-by-face
const Standard_Real eps2 = Precision::Confusion()*Precision::Confusion(); const Standard_Real eps2 = Precision::Confusion()*Precision::Confusion();
@ -158,8 +216,7 @@ NIS_Surface::NIS_Surface
const Handle(Geom_Surface)& aSurf = BRep_Tool::Surface(aFace, aLocSurf); const Handle(Geom_Surface)& aSurf = BRep_Tool::Surface(aFace, aLocSurf);
const Handle(Poly_Triangulation)& aTriangulation = const Handle(Poly_Triangulation)& aTriangulation =
BRep_Tool::Triangulation(aFace, aLoc); BRep_Tool::Triangulation(aFace, aLoc);
if (aTriangulation.IsNull() == Standard_False && if (aTriangulation.IsNull() == Standard_False)
aSurf.IsNull() == Standard_False)
{ {
// Prepare transformation // Prepare transformation
Standard_Integer i, aNodeInd(nNodes)/*, aNTriangles = 0*/; Standard_Integer i, aNodeInd(nNodes)/*, aNTriangles = 0*/;
@ -181,10 +238,20 @@ NIS_Surface::NIS_Surface
gp_Vec aD1U, aD1V; gp_Vec aD1U, aD1V;
gp_Pnt aP; gp_Pnt aP;
gp_XYZ aNorm(0., 0., 0.);
if (aTriangulation->HasNormals()) {
// Retrieve the normal direction from the triangulation
aNorm.SetCoord(aTriangulation->Normals().Value(3*i-2),
aTriangulation->Normals().Value(3*i-1),
aTriangulation->Normals().Value(3*i-0));
} else if (aSurf.IsNull() == Standard_False)
{
// Compute the surface normal at the Node. // Compute the surface normal at the Node.
aSurf->D1(tabUV(i).X(), tabUV(i).Y(), aP, aD1U, aD1V); aSurf->D1(tabUV(i).X(), tabUV(i).Y(), aP, aD1U, aD1V);
gp_XYZ aNorm = (aD1U.Crossed(aD1V)).XYZ(); aNorm = (aD1U.Crossed(aD1V)).XYZ();
}
if (isReverse) if (isReverse)
aNorm.Reverse(); aNorm.Reverse();
const Standard_Real aMod = aNorm.SquareModulus(); const Standard_Real aMod = aNorm.SquareModulus();
@ -203,36 +270,85 @@ NIS_Surface::NIS_Surface
aNodeInd++; aNodeInd++;
} }
const Standard_Integer nNodes1 = nNodes - 1;
// Store all triangles of the current face in the data model // Store all triangles of the current face in the data model
const Poly_Array1OfTriangle& tabTri = aTriangulation->Triangles(); const Poly_Array1OfTriangle& tabTri = aTriangulation->Triangles();
for (i = tabTri.Lower(); i <= tabTri.Upper(); i++) for (i = tabTri.Lower(); i <= tabTri.Upper(); i++)
{ {
Standard_Integer aN[3]; Standard_Integer aN[3];
tabTri(i).Get (aN[0], aN[1], aN[2]); tabTri(i).Get (aN[0], aN[1], aN[2]);
if (((tabNode(aN[2]).XYZ() - Standard_Integer * pTriangle = &mypTriangles[nTriangles*3];
tabNode(aN[0]).XYZ()) ^ pTriangle[0] = aN[0] + nNodes1;
(tabNode(aN[1]).XYZ() -
tabNode(aN[0]).XYZ())).SquareModulus() > eps2)
{
aN[0] += (nNodes - 1);
aN[1] += (nNodes - 1);
aN[2] += (nNodes - 1);
mypTriangles[nTriangles*3 + 0] = aN[0];
if (isReverse) { if (isReverse) {
mypTriangles[nTriangles*3 + 1] = aN[2]; pTriangle[1] = aN[2] + nNodes1;
mypTriangles[nTriangles*3 + 2] = aN[1]; pTriangle[2] = aN[1] + nNodes1;
} else { } else {
mypTriangles[nTriangles*3 + 1] = aN[1]; pTriangle[1] = aN[1] + nNodes1;
mypTriangles[nTriangles*3 + 2] = aN[2]; pTriangle[2] = aN[2] + nNodes1;
} }
const Standard_ShortReal aVec0[3] = {
mypNodes[3*pTriangle[1]+0] - mypNodes[3*pTriangle[0]+0],
mypNodes[3*pTriangle[1]+1] - mypNodes[3*pTriangle[0]+1],
mypNodes[3*pTriangle[1]+2] - mypNodes[3*pTriangle[0]+2]
};
const Standard_ShortReal aVec1[3] = {
mypNodes[3*pTriangle[2]+0] - mypNodes[3*pTriangle[0]+0],
mypNodes[3*pTriangle[2]+1] - mypNodes[3*pTriangle[0]+1],
mypNodes[3*pTriangle[2]+2] - mypNodes[3*pTriangle[0]+2]
};
const Standard_ShortReal aVecP[3] = {
aVec0[1] * aVec1[2] - aVec0[2] * aVec1[1],
aVec0[2] * aVec1[0] - aVec0[0] * aVec1[2],
aVec0[0] * aVec1[1] - aVec0[1] * aVec1[0]
};
if (aVecP[0]*aVecP[0] + aVecP[1]*aVecP[1] + aVecP[2]*aVecP[2] > eps2)
nTriangles++; nTriangles++;
} }
// Store all edge polygons on the current face.
for (eexp.Init(aFace, TopAbs_EDGE); eexp.More(); eexp.Next())
{
const TopoDS_Edge& anEdge = TopoDS::Edge(eexp.Current());
if (mapEdges.Remove(anEdge)) {
const Handle(Poly_PolygonOnTriangulation)& aPolygon =
BRep_Tool::PolygonOnTriangulation(anEdge, aTriangulation, aLoc);
if (aPolygon.IsNull() == Standard_False) {
const TColStd_Array1OfInteger& arrNode = aPolygon->Nodes();
// Allocate memory to store the current polygon indices.
Standard_Integer aLen = arrNode.Length();
Standard_Integer * pEdge = static_cast<Standard_Integer *>
(myAlloc->Allocate(sizeof(Standard_Integer) * (aLen + 1)));
const gp_Pnt* pLast = &tabNode(arrNode(arrNode.Lower()));
pEdge[1] = arrNode(arrNode.Lower()) + nNodes1;
Standard_Integer iPNode(arrNode.Lower() + 1), iENode(1);
for (; iPNode <= arrNode.Upper(); iPNode++)
{
const Standard_Integer aN(arrNode(iPNode));
if (pLast->SquareDistance(tabNode(aN)) < eps2)
{
aLen--;
} else {
pLast = &tabNode(aN);
pEdge[++iENode] = aN + nNodes1;
}
}
// Do not save very short polygons
if (aLen > 1) {
pEdge[0] = aLen;
mypEdges[myNEdges++] = pEdge;
}
}
}
} }
nNodes += tabNode.Length(); nNodes += tabNode.Length();
} }
} }
myNTriangles = nTriangles; myNTriangles = nTriangles;
} }
if (GetDrawer().IsNull() == Standard_False)
{
setDrawerUpdate();
}
setIsUpdateBox(Standard_True);
} }
//======================================================================= //=======================================================================
@ -241,6 +357,16 @@ NIS_Surface::NIS_Surface
//======================================================================= //=======================================================================
NIS_Surface::~NIS_Surface () NIS_Surface::~NIS_Surface ()
{
Clear();
}
//=======================================================================
//function : Clear
//purpose :
//=======================================================================
void NIS_Surface::Clear ()
{ {
if (myNNodes) { if (myNNodes) {
myNNodes = 0; myNNodes = 0;
@ -251,6 +377,20 @@ NIS_Surface::~NIS_Surface ()
myNTriangles = 0; myNTriangles = 0;
myAlloc->Free(mypTriangles); myAlloc->Free(mypTriangles);
} }
if (mypEdges) {
for (Standard_Integer i = 0; i < myNEdges; i++) {
myAlloc->Free(mypEdges[i]);
}
myNEdges = 0;
myAlloc->Free(mypEdges);
}
if (GetDrawer().IsNull() == Standard_False) {
GetDrawer()->SetUpdated(NIS_Drawer::Draw_Normal,
NIS_Drawer::Draw_Top,
NIS_Drawer::Draw_Transparent,
NIS_Drawer::Draw_Hilighted);
}
myBox.Clear();
} }
//======================================================================= //=======================================================================
@ -258,9 +398,14 @@ NIS_Surface::~NIS_Surface ()
//purpose : //purpose :
//======================================================================= //=======================================================================
Handle(NIS_Drawer) NIS_Surface::DefaultDrawer () const NIS_Drawer * NIS_Surface::DefaultDrawer (NIS_Drawer * theDrawer) const
{ {
return defaultDrawer(); NIS_SurfaceDrawer * aDrawer =
theDrawer ? static_cast<NIS_SurfaceDrawer *>(theDrawer)
: new NIS_SurfaceDrawer (Quantity_NOC_SLATEBLUE4);
aDrawer->SetBackColor (Quantity_NOC_DARKGREEN);
aDrawer->myIsWireframe = myIsWireframe;
return aDrawer;
} }
//======================================================================= //=======================================================================
@ -270,9 +415,11 @@ Handle(NIS_Drawer) NIS_Surface::DefaultDrawer () const
void NIS_Surface::SetColor (const Quantity_Color& theColor) void NIS_Surface::SetColor (const Quantity_Color& theColor)
{ {
Handle(NIS_SurfaceDrawer) aDrawer = defaultDrawer(); const Handle(NIS_SurfaceDrawer) aDrawer =
static_cast<NIS_SurfaceDrawer *>(DefaultDrawer(0L));
aDrawer->Assign (GetDrawer()); aDrawer->Assign (GetDrawer());
aDrawer->myColor[NIS_Drawer::Draw_Normal] = theColor; aDrawer->myColor[NIS_Drawer::Draw_Normal] = theColor;
aDrawer->myColor[NIS_Drawer::Draw_Top] = theColor;
aDrawer->myColor[NIS_Drawer::Draw_Transparent] = theColor; aDrawer->myColor[NIS_Drawer::Draw_Transparent] = theColor;
SetDrawer (aDrawer); SetDrawer (aDrawer);
} }
@ -284,7 +431,8 @@ void NIS_Surface::SetColor (const Quantity_Color& theColor)
void NIS_Surface::SetBackColor (const Quantity_Color& theColor) void NIS_Surface::SetBackColor (const Quantity_Color& theColor)
{ {
Handle(NIS_SurfaceDrawer) aDrawer = defaultDrawer(); const Handle(NIS_SurfaceDrawer) aDrawer =
static_cast<NIS_SurfaceDrawer *>(DefaultDrawer(0L));
aDrawer->Assign (GetDrawer()); aDrawer->Assign (GetDrawer());
aDrawer->myBackColor = theColor; aDrawer->myBackColor = theColor;
SetDrawer (aDrawer); SetDrawer (aDrawer);
@ -297,23 +445,96 @@ void NIS_Surface::SetBackColor (const Quantity_Color& theColor)
void NIS_Surface::SetPolygonOffset (const Standard_Real theValue) void NIS_Surface::SetPolygonOffset (const Standard_Real theValue)
{ {
Handle(NIS_SurfaceDrawer) aDrawer = defaultDrawer(); const Handle(NIS_SurfaceDrawer) aDrawer =
static_cast<NIS_SurfaceDrawer *>(DefaultDrawer(0L));
aDrawer->Assign (GetDrawer()); aDrawer->Assign (GetDrawer());
aDrawer->myPolygonOffset = theValue; aDrawer->myPolygonOffset = static_cast<Standard_ShortReal>(theValue);
SetDrawer (aDrawer); SetDrawer (aDrawer);
} }
//======================================================================= //=======================================================================
//function : SetTransparency //function : SetDisplayMode
//purpose : Set the display mode: Shading or Wireframe.
//=======================================================================
void NIS_Surface::SetDisplayMode (const NIS_Surface::DisplayMode theMode)
{
Standard_Boolean isUpdate(Standard_False);
if (myIsWireframe) {
if (theMode != Wireframe) {
myIsWireframe = Standard_False;
isUpdate = Standard_True;
}
} else {
if (theMode == Wireframe) {
myIsWireframe = Standard_True;
isUpdate = Standard_True;
}
}
if (isUpdate && GetDrawer()) {
const Handle(NIS_SurfaceDrawer) aDrawer =
static_cast<NIS_SurfaceDrawer *>(DefaultDrawer(0L));
aDrawer->Assign (GetDrawer());
aDrawer->myIsWireframe = myIsWireframe;
SetDrawer(aDrawer);
}
}
//=======================================================================
//function : GetDisplayMode
//purpose : Query the current display mode: Shading or Wireframe.
//=======================================================================
NIS_Surface::DisplayMode NIS_Surface::GetDisplayMode () const
{
return myIsWireframe ? Wireframe : Shading;
}
//=======================================================================
//function : Clone
//purpose : //purpose :
//======================================================================= //=======================================================================
void NIS_Surface::SetTransparency (const Standard_Real theValue) void NIS_Surface::Clone (const Handle_NCollection_BaseAllocator& theAlloc,
Handle_NIS_InteractiveObject& theDest) const
{ {
Handle(NIS_SurfaceDrawer) aDrawer = defaultDrawer(); Handle(NIS_Surface) aNewObj;
aDrawer->Assign (GetDrawer()); if (theDest.IsNull()) {
aDrawer->myTransparency = theValue; aNewObj = new NIS_Surface(theAlloc);
SetDrawer (aDrawer); theDest = aNewObj;
} else {
aNewObj = reinterpret_cast<NIS_Surface*> (theDest.operator->());
aNewObj->myAlloc = theAlloc;
}
NIS_InteractiveObject::Clone(theAlloc, theDest);
aNewObj->myNNodes = myNNodes;
if (myNNodes > 0) {
// copy nodes and normals
const Standard_Size nBytes = myNNodes*3*sizeof(Standard_ShortReal);
aNewObj->mypNodes = (Standard_ShortReal *)theAlloc->Allocate(nBytes);
aNewObj->mypNormals = (Standard_ShortReal *)theAlloc->Allocate(nBytes);
memcpy(aNewObj->mypNodes, mypNodes, nBytes);
memcpy(aNewObj->mypNormals, mypNormals, nBytes);
}
aNewObj->myNTriangles = myNTriangles;
if (myNTriangles > 0) {
const Standard_Size nBytes = sizeof(Standard_Integer) * 3 * myNTriangles;
aNewObj->mypTriangles = (Standard_Integer *)theAlloc->Allocate(nBytes);
memcpy(aNewObj->mypTriangles, mypTriangles, nBytes);
}
aNewObj->myNEdges = myNEdges;
if (myNEdges > 0) {
aNewObj->mypEdges = static_cast<Standard_Integer **>
(theAlloc->Allocate(sizeof(Standard_Integer *) * myNEdges));
for (Standard_Integer i = 0; i < myNEdges; i++) {
const Standard_Integer * pEdge = mypEdges[i];
const Standard_Size nBytes = sizeof(Standard_Integer) * (pEdge[0] + 1);
aNewObj->mypEdges[i] =
static_cast<Standard_Integer *> (theAlloc->Allocate(nBytes));
memcpy(aNewObj->mypEdges[i], pEdge, nBytes);
}
}
aNewObj->myIsWireframe = myIsWireframe;
} }
//======================================================================= //=======================================================================
@ -322,7 +543,7 @@ void NIS_Surface::SetTransparency (const Standard_Real theValue)
//======================================================================= //=======================================================================
Standard_Real NIS_Surface::Intersect (const gp_Ax1& theAxis, Standard_Real NIS_Surface::Intersect (const gp_Ax1& theAxis,
const Standard_Real /*over*/) const const Standard_Real theOver) const
{ {
Standard_Real aResult (RealLast()); Standard_Real aResult (RealLast());
Standard_Real start[3], dir[3]; Standard_Real start[3], dir[3];
@ -330,6 +551,7 @@ Standard_Real NIS_Surface::Intersect (const gp_Ax1& theAxis,
theAxis.Direction().Coord(dir[0], dir[1], dir[2]); theAxis.Direction().Coord(dir[0], dir[1], dir[2]);
double anInter; double anInter;
if (myIsWireframe == Standard_False)
for (Standard_Integer i = 0; i < myNTriangles; i++) { for (Standard_Integer i = 0; i < myNTriangles; i++) {
const Standard_Integer * pTri = &mypTriangles[3*i]; const Standard_Integer * pTri = &mypTriangles[3*i];
if (NIS_Triangulated::tri_line_intersect (start, dir, if (NIS_Triangulated::tri_line_intersect (start, dir,
@ -340,6 +562,24 @@ Standard_Real NIS_Surface::Intersect (const gp_Ax1& theAxis,
if (anInter < aResult) if (anInter < aResult)
aResult = anInter; aResult = anInter;
} }
else {
const Standard_Real anOver2 = theOver*theOver;
for (Standard_Integer iEdge = 0; iEdge < myNEdges; iEdge++) {
const Standard_Integer * anEdge = mypEdges[iEdge];
const Standard_Integer nNodes = anEdge[0];
for (Standard_Integer i = 1; i < nNodes; i++) {
// Node index is incremented for the head of polygon indice array
if (NIS_Triangulated::seg_line_intersect (theAxis.Location().XYZ(),
theAxis.Direction().XYZ(),
anOver2,
&mypNodes[3*anEdge[i+0]],
&mypNodes[3*anEdge[i+1]],
&anInter))
if (anInter < aResult)
aResult = anInter;
}
}
}
return aResult; return aResult;
} }
@ -349,13 +589,13 @@ Standard_Real NIS_Surface::Intersect (const gp_Ax1& theAxis,
//purpose : //purpose :
//======================================================================= //=======================================================================
Standard_Boolean NIS_Surface::Intersect Standard_Boolean NIS_Surface::Intersect (const Bnd_B3f& theBox,
(const Bnd_B3f& theBox,
const gp_Trsf& theTrf, const gp_Trsf& theTrf,
const Standard_Boolean isFullIn) const const Standard_Boolean isFullIn) const
{ {
Standard_Boolean aResult (isFullIn); Standard_Boolean aResult (isFullIn);
if (myIsWireframe == Standard_False) {
if (myNTriangles > 0) { if (myNTriangles > 0) {
for (Standard_Integer iNode = 0; iNode < myNNodes*3; iNode+=3) { for (Standard_Integer iNode = 0; iNode < myNNodes*3; iNode+=3) {
gp_XYZ aPnt (static_cast<Standard_Real>(mypNodes[iNode+0]), gp_XYZ aPnt (static_cast<Standard_Real>(mypNodes[iNode+0]),
@ -368,6 +608,105 @@ Standard_Boolean NIS_Surface::Intersect
} }
} }
} }
} else {
for (Standard_Integer iEdge = 0; iEdge < myNEdges; iEdge++) {
const Standard_Integer * anEdge = mypEdges[iEdge];
const Standard_Integer nNodes = anEdge[0];
for (Standard_Integer i = 1; i < nNodes; i++) {
// index is incremented by 1 for the head number in the array
gp_Pnt aPnt[2] = {
gp_Pnt(static_cast<Standard_Real>(mypNodes[3*anEdge[i+0]+0]),
static_cast<Standard_Real>(mypNodes[3*anEdge[i+0]+1]),
static_cast<Standard_Real>(mypNodes[3*anEdge[i+0]+2])),
gp_Pnt(static_cast<Standard_Real>(mypNodes[3*anEdge[i+1]+0]),
static_cast<Standard_Real>(mypNodes[3*anEdge[i+1]+1]),
static_cast<Standard_Real>(mypNodes[3*anEdge[i+1]+2]))
};
aPnt[0].Transform(theTrf);
aPnt[1].Transform(theTrf);
if (isFullIn) {
if (NIS_Triangulated::seg_box_included (theBox, aPnt) == 0) {
aResult = Standard_False;
break;
}
} else {
if (NIS_Triangulated::seg_box_intersect (theBox, aPnt)) {
aResult = Standard_True;
break;
}
}
}
}
}
return aResult;
}
//=======================================================================
//function : Intersect
//purpose : Selection by polygon
//=======================================================================
Standard_Boolean NIS_Surface::Intersect
(const NCollection_List<gp_XY> &thePolygon,
const gp_Trsf &theTrf,
const Standard_Boolean isFullIn) const
{
Standard_Boolean aResult (isFullIn);
if (myIsWireframe == Standard_False) {
if (myNTriangles > 0) {
for (Standard_Integer iNode = 0; iNode < myNNodes*3; iNode+=3) {
gp_XYZ aPnt (static_cast<Standard_Real>(mypNodes[iNode+0]),
static_cast<Standard_Real>(mypNodes[iNode+1]),
static_cast<Standard_Real>(mypNodes[iNode+2]));
theTrf.Transforms(aPnt);
gp_XY aP2d(aPnt.X(), aPnt.Y());
if (!NIS_Triangulated::IsIn(thePolygon, aP2d)) {
if (isFullIn) {
aResult = Standard_False;
break;
}
} else {
if (isFullIn == Standard_False) {
aResult = Standard_True;
break;
}
}
}
}
} else {
for (Standard_Integer iEdge = 0; iEdge < myNEdges; iEdge++) {
const Standard_Integer * anEdge = mypEdges[iEdge];
const Standard_Integer nNodes = anEdge[0];
for (Standard_Integer i = 1; i < nNodes; i++) {
// index is incremented by 1 for the head number in the array
gp_Pnt aPnt[2] = {
gp_Pnt(static_cast<Standard_Real>(mypNodes[3*anEdge[i+0]+0]),
static_cast<Standard_Real>(mypNodes[3*anEdge[i+0]+1]),
static_cast<Standard_Real>(mypNodes[3*anEdge[i+0]+2])),
gp_Pnt(static_cast<Standard_Real>(mypNodes[3*anEdge[i+1]+0]),
static_cast<Standard_Real>(mypNodes[3*anEdge[i+1]+1]),
static_cast<Standard_Real>(mypNodes[3*anEdge[i+1]+2]))
};
aPnt[0].Transform(theTrf);
aPnt[1].Transform(theTrf);
const gp_XY aP2d[2] = { gp_XY(aPnt[0].X(), aPnt[0].Y()),
gp_XY(aPnt[1].X(), aPnt[1].Y()) };
if (isFullIn) {
if (NIS_Triangulated::seg_polygon_included (thePolygon, aP2d) == 0) {
aResult = Standard_False;
break;
}
} else {
if (NIS_Triangulated::seg_polygon_intersect (thePolygon, aP2d)) {
aResult = Standard_True;
break;
}
}
}
}
}
return aResult; return aResult;
} }
@ -378,7 +717,7 @@ Standard_Boolean NIS_Surface::Intersect
void NIS_Surface::computeBox () void NIS_Surface::computeBox ()
{ {
NIS_Triangulated::ComputeBox(myBox, myNNodes, mypNodes); NIS_Triangulated::ComputeBox(myBox, myNNodes, mypNodes, 3);
const Handle(NIS_SurfaceDrawer)& aDrawer = const Handle(NIS_SurfaceDrawer)& aDrawer =
static_cast<const Handle(NIS_SurfaceDrawer)&> (GetDrawer()); static_cast<const Handle(NIS_SurfaceDrawer)&> (GetDrawer());

View File

@ -15,12 +15,30 @@ class Handle_Poly_Triangulation;
class TopoDS_Shape; class TopoDS_Shape;
/** /**
* This class describes a presentation of a meshed surface. * Presentation of a meshed surface.
* Consists of 4 arrays: Nodes, Triangles, Normals and Edges. Normals are
* defined in nodes, so the number of stored normals is strictly the number of
* nodes. Edges is an array of pointers: each pointer starts an array of
* node indices that define a single edge (i.e., a polygon that can be closed or
* open, no matter). The first number in the edge is the number of nodes in it.
* <p>
* Instances of this class can be initialized either atomically (setting every
* node and triangle and edge) or from a TopoDS_Shape object. In side the
* TopoDS_Shape only triangulations in faces are used; edges are taken from
* PolygonOnTriangulation also belonging to faces.
* <p>
* This class is conceived as replacement of AIS_Shape; both wireframe and
* shading modes are available for dynamic switching.
*/ */
class NIS_Surface : public NIS_InteractiveObject class NIS_Surface : public NIS_InteractiveObject
{ {
public: public:
enum DisplayMode {
Shading,
Wireframe
};
/** /**
* Constructor * Constructor
*/ */
@ -29,21 +47,34 @@ public:
theAlloc =0L); theAlloc =0L);
/** /**
* Constructor. Creates the presentation of all faces in 'theShape' object. * Constructor. Creates the presentation of all faces in 'theShape' object.
* @aparm theShape * @param theShape
* Source geometry. It should contain triangulations inside. * Source geometry. It should contain triangulations inside.
* @param theAlloc * @param theDeflection
* Absolute deflection for meshing 'theShape' if such meshing is needed.
* @param theAl
* Allocator used for nodes and triangles in this presentation. * Allocator used for nodes and triangles in this presentation.
*/ */
Standard_EXPORT NIS_Surface(const TopoDS_Shape& theShape, Standard_EXPORT NIS_Surface(const TopoDS_Shape& theShape,
// const Standard_Real theDeflection, const Standard_Real theDeflection,
const Handle_NCollection_BaseAllocator& const Handle_NCollection_BaseAllocator& theAl=0L);
theAlloc = 0L);
/** /**
* Destructor * Destructor
*/ */
Standard_EXPORT virtual ~NIS_Surface (); Standard_EXPORT virtual ~NIS_Surface ();
/**
* Initialize the instance with a TopoDS_Shape. Used in constructor but can
* be called any time to redefine the geometry.
*/
Standard_EXPORT void Init (const TopoDS_Shape& theShape,
const Standard_Real theDefl);
/**
* Deallocate all internal data structures.
*/
Standard_EXPORT void Clear ();
/** /**
* Query the number of nodes. * Query the number of nodes.
*/ */
@ -54,6 +85,11 @@ public:
*/ */
inline Standard_Integer NTriangles () const { return myNTriangles;} inline Standard_Integer NTriangles () const { return myNTriangles;}
/**
* Query the number of edges for wireframe display.
*/
inline Standard_Integer NEdges () const { return myNEdges; }
/** /**
* Query the node by its index. * Query the node by its index.
* @return * @return
@ -76,6 +112,18 @@ public:
return &mypTriangles[theIndex * 3]; return &mypTriangles[theIndex * 3];
} }
/**
* Access to array of integers that represents an Edge.
* @return
* Pointer to array where the 0th element is the number of nodes in the edge
* and the elements starting from the 1st are node indices.
*/
inline const Standard_Integer*
Edge (const Standard_Integer theIndex) const
{
return mypEdges[theIndex];
}
/** /**
* Query the normal vector at the given triangulation node (by index) * Query the normal vector at the given triangulation node (by index)
* @return * @return
@ -90,8 +138,8 @@ public:
/** /**
* Create a default drawer instance. * Create a default drawer instance.
*/ */
Standard_EXPORT virtual Handle_NIS_Drawer Standard_EXPORT virtual NIS_Drawer *
DefaultDrawer () const; DefaultDrawer (NIS_Drawer *) const;
/** /**
* Set the normal color for presentation. * Set the normal color for presentation.
@ -115,15 +163,31 @@ public:
Standard_EXPORT void SetPolygonOffset (const Standard_Real theValue); Standard_EXPORT void SetPolygonOffset (const Standard_Real theValue);
/** /**
* Set the transparency factor. * Set the display mode: Shading or Wireframe.
* @param theValue * The default mode is Shading.
* 1.0 means full transparency, 0.0 means opaque. Valid quantities are in
* this interval.
*/ */
Standard_EXPORT void SetTransparency (const Standard_Real theValue); Standard_EXPORT void SetDisplayMode (const DisplayMode theMode);
/** /**
* Intersect the InteractiveObject geometry with a line/ray. * Query the current display mode: Shading or Wireframe.
*/
Standard_EXPORT DisplayMode
GetDisplayMode () const;
/**
* Create a copy of theObject except its ID.
* @param theAll
* Allocator where the Dest should store its private data.
* @param theDest
* <tt>[in-out]</tt> The target object where the data are copied. If
* passed NULL then the target should be created.
*/
Standard_EXPORT virtual void
Clone (const Handle_NCollection_BaseAllocator& theAll,
Handle_NIS_InteractiveObject& theDest) const;
/**
* Intersect the surface shading/wireframe geometry with a line/ray.
* @param theAxis * @param theAxis
* The line or ray in 3D space. * The line or ray in 3D space.
* @param theOver * @param theOver
@ -138,7 +202,7 @@ public:
const Standard_Real theOver) const; const Standard_Real theOver) const;
/** /**
* Intersect the InteractiveObject geometry with an oriented box. * Intersect the surface shading/wireframe geometry with an oriented box.
* @param theBox * @param theBox
* 3D box of selection * 3D box of selection
* @param theTrf * @param theTrf
@ -153,8 +217,32 @@ public:
const gp_Trsf& theTrf, const gp_Trsf& theTrf,
const Standard_Boolean isFull)const; const Standard_Boolean isFull)const;
/**
* Intersect the surface shading/wireframe geometry with a selection polygon.
* @param thePolygon
* the list of vertices of a free-form closed polygon without
* self-intersections. The last point should not coincide with the first
* point of the list. Any two neighbor points should not be confused.
* @param theTrf
* Position/Orientation of the polygon.
* @param isFullIn
* True if full inclusion is required, False - if partial.
* @return
* True if the InteractiveObject geometry intersects the polygon or is
* inside it
*/
Standard_EXPORT virtual Standard_Boolean Intersect
(const NCollection_List<gp_XY> &thePolygon,
const gp_Trsf &theTrf,
const Standard_Boolean isFullIn) const;
protected: protected:
/**
* Allocator for method Clone().
*/
Standard_EXPORT NIS_Surface (const Handle_NCollection_BaseAllocator& theAl);
/** /**
* Create a 3D bounding box of the object. * Create a 3D bounding box of the object.
*/ */
@ -168,15 +256,20 @@ protected:
gp_XYZ& theNormal) const; gp_XYZ& theNormal) const;
private: private:
Handle_NCollection_BaseAllocator myAlloc;
//! Array of nodes in triangles //! Array of nodes in triangles
Standard_ShortReal * mypNodes; Standard_ShortReal * mypNodes;
//! Array of normals (TriNodes) //! Array of normals (TriNodes)
Standard_ShortReal * mypNormals; Standard_ShortReal * mypNormals;
//! Array of triangles (node indices)
Standard_Integer * mypTriangles; Standard_Integer * mypTriangles;
//! Array of edges, each edge is an array of indices prefixed by N nodes
Standard_Integer ** mypEdges;
//! Number of nodes in triangles //! Number of nodes in triangles
Standard_Integer myNNodes; Standard_Integer myNNodes;
Standard_Integer myNTriangles; Standard_Integer myNTriangles;
Handle_NCollection_BaseAllocator myAlloc; Standard_Integer myNEdges;
Standard_Boolean myIsWireframe;
public: public:
// Declaration of CASCADE RTTI // Declaration of CASCADE RTTI

View File

@ -13,6 +13,11 @@
#endif #endif
#include <GL/gl.h> #include <GL/gl.h>
static void setColor(GLenum theFace,
Quantity_Parameter * theAmbient,
const Standard_Real theSpecularity,
GLint theShininess);
IMPLEMENT_STANDARD_HANDLE (NIS_SurfaceDrawer, NIS_Drawer) IMPLEMENT_STANDARD_HANDLE (NIS_SurfaceDrawer, NIS_Drawer)
IMPLEMENT_STANDARD_RTTIEXT (NIS_SurfaceDrawer, NIS_Drawer) IMPLEMENT_STANDARD_RTTIEXT (NIS_SurfaceDrawer, NIS_Drawer)
@ -26,10 +31,11 @@ NIS_SurfaceDrawer::NIS_SurfaceDrawer
const Quantity_Color &theHilight, const Quantity_Color &theHilight,
const Quantity_Color &theDynHilight) const Quantity_Color &theDynHilight)
: myBackColor (theNormal), : myBackColor (theNormal),
myTransparency (0.0), myPolygonOffset (0.f),
myPolygonOffset (0.f) myIsWireframe (Standard_False)
{ {
myColor[Draw_Normal] = theNormal; myColor[Draw_Normal] = theNormal;
myColor[Draw_Top] = theNormal;
myColor[Draw_Transparent] = theNormal; myColor[Draw_Transparent] = theNormal;
myColor[Draw_Hilighted] = theHilight; myColor[Draw_Hilighted] = theHilight;
myColor[Draw_DynHilighted] = theDynHilight; myColor[Draw_DynHilighted] = theDynHilight;
@ -40,12 +46,11 @@ NIS_SurfaceDrawer::NIS_SurfaceDrawer
//purpose : //purpose :
//======================================================================= //=======================================================================
void NIS_SurfaceDrawer::SetColor(const Quantity_Color &theColor, void NIS_SurfaceDrawer::SetColor(const Quantity_Color &theColor)
const Standard_Real theTransparency)
{ {
myColor[Draw_Normal] = theColor; myColor[Draw_Normal] = theColor;
myColor[Draw_Top] = theColor;
myColor[Draw_Transparent] = theColor; myColor[Draw_Transparent] = theColor;
myTransparency = theTransparency;
} }
//======================================================================= //=======================================================================
@ -60,10 +65,13 @@ void NIS_SurfaceDrawer::Assign (const Handle_NIS_Drawer& theOther)
const Handle(NIS_SurfaceDrawer)& anOther = const Handle(NIS_SurfaceDrawer)& anOther =
static_cast <const Handle(NIS_SurfaceDrawer)&> (theOther); static_cast <const Handle(NIS_SurfaceDrawer)&> (theOther);
myColor[Draw_Normal] = anOther->myColor[Draw_Normal]; myColor[Draw_Normal] = anOther->myColor[Draw_Normal];
myColor[Draw_Top] = anOther->myColor[Draw_Top];
myColor[Draw_Transparent] = anOther->myColor[Draw_Transparent]; myColor[Draw_Transparent] = anOther->myColor[Draw_Transparent];
myColor[Draw_Hilighted] = anOther->myColor[Draw_Hilighted]; myColor[Draw_Hilighted] = anOther->myColor[Draw_Hilighted];
myColor[Draw_DynHilighted] = anOther->myColor[Draw_DynHilighted]; myColor[Draw_DynHilighted] = anOther->myColor[Draw_DynHilighted];
myBackColor = anOther->myBackColor; myBackColor = anOther->myBackColor;
myPolygonOffset = anOther->myPolygonOffset;
myIsWireframe = anOther->myIsWireframe;
} }
} }
@ -88,8 +96,7 @@ Standard_Boolean NIS_SurfaceDrawer::IsEqual
.SquareDistance (myColor[Draw_DynHilighted]) < anEpsilon2 && .SquareDistance (myColor[Draw_DynHilighted]) < anEpsilon2 &&
anOther->myBackColor.SquareDistance(myBackColor) < anEpsilon2 && anOther->myBackColor.SquareDistance(myBackColor) < anEpsilon2 &&
fabs(anOther->myPolygonOffset - myPolygonOffset) < 0.999 && fabs(anOther->myPolygonOffset - myPolygonOffset) < 0.999 &&
(anOther->myTransparency - myTransparency) * myIsWireframe == anOther->myIsWireframe);
(anOther->myTransparency - myTransparency) < 0.01);
if (aResult) { if (aResult) {
// Arbitrary point for test // Arbitrary point for test
gp_XYZ aPnt[2] = { gp_XYZ aPnt[2] = {
@ -138,81 +145,63 @@ void NIS_SurfaceDrawer::BeforeDraw (const DrawType theType,
const NIS_DrawList&) const NIS_DrawList&)
{ {
glEnable(GL_LIGHTING); glEnable(GL_LIGHTING);
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 1); // glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 1);
glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
glEnableClientState (GL_VERTEX_ARRAY); glEnableClientState (GL_VERTEX_ARRAY);
glEnable(GL_COLOR_MATERIAL); if (myIsWireframe == Standard_False) {
glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
glEnable(GL_POLYGON_OFFSET_FILL);
glShadeModel(GL_SMOOTH);
}
Quantity_Parameter aValueCol[3]; Quantity_Parameter aValueCol[4] = {0., 0., 0., 1.};
Quantity_TypeOfColor bidTC (Quantity_TOC_RGB); Quantity_TypeOfColor bidTC (Quantity_TOC_RGB);
GLfloat aLineWidth (1.f); GLfloat aLineWidth (1.f);
GLfloat anOffset = myPolygonOffset; GLfloat anOffset = myPolygonOffset;
static const GLfloat gColorN[4] = {0.f, 0.f, 0.f, 1.f};
switch (theType) { switch (theType) {
case Draw_DynHilighted: case Draw_DynHilighted:
aLineWidth = 3.f; aLineWidth = 3.f;
myColor[theType].Values (aValueCol[0], aValueCol[1], aValueCol[2], bidTC); myColor[theType].Values (aValueCol[0], aValueCol[1], aValueCol[2], bidTC);
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); setColor(GL_FRONT_AND_BACK, &aValueCol[0], 0.1, 5);
glColor3d (aValueCol[0], aValueCol[1], aValueCol[2]); glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, &gColorN[0]);
glLineWidth (aLineWidth); glLineWidth (aLineWidth);
// glEnable(GL_POLYGON_OFFSET_LINE); if (myIsWireframe == Standard_False)
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(1.f, -(anOffset + 11.f)); glPolygonOffset(1.f, -(anOffset + 11.f));
return; return;
case Draw_Hilighted: case Draw_Hilighted:
anOffset += 10.f; anOffset += 10.f;
case Draw_Normal: case Draw_Normal:
case Draw_Top:
case Draw_Transparent: case Draw_Transparent:
glEnable(GL_POLYGON_OFFSET_FILL); if (myIsWireframe == Standard_False) {
glPolygonOffset(1.f, -anOffset); glPolygonOffset(1.f, -anOffset);
glEnableClientState (GL_NORMAL_ARRAY); glEnableClientState (GL_NORMAL_ARRAY);
}
myColor[theType].Values (aValueCol[0], aValueCol[1], aValueCol[2], bidTC); myColor[theType].Values (aValueCol[0], aValueCol[1], aValueCol[2], bidTC);
aValueCol[3] = 1. - myTransparency; aValueCol[3] = 1. - myTransparency;
if (theType == Draw_Transparent) {
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// don't write triangles into depth test
glDepthMask(GL_FALSE);
}
break; break;
default: default:
return; return;
} }
// glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 0); // glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 0);
static const GLfloat gColorN[4] = {0.f, 0.f, 0.f, 1.f};
GLfloat gColorS[4] = {
0.5f * static_cast<GLfloat> (1. + aValueCol[0]),
0.5f * static_cast<GLfloat> (1. + aValueCol[1]),
0.5f * static_cast<GLfloat> (1. + aValueCol[2]),
1.f
};
if (theType == Draw_Hilighted || if (theType == Draw_Hilighted ||
myBackColor.SquareDistance(myColor[Draw_Normal]) < 1.e-7) myBackColor.SquareDistance(myColor[Draw_Normal]) < 1.e-7)
{ {
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); setColor(GL_FRONT_AND_BACK, &aValueCol[0], 0.5, 10);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColor4d (aValueCol[0], aValueCol[1], aValueCol[2], aValueCol[3]);
// glColor3d (aValueCol[0], aValueCol[1], aValueCol[2]);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &gColorS[0]);
glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 10);
} else { } else {
glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); setColor(GL_FRONT, &aValueCol[0], 0.4, 10);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColor4d (aValueCol[0], aValueCol[1], aValueCol[2], aValueCol[3]);
// glColor3d (aValueCol[0], aValueCol[1], aValueCol[2]);
glMaterialfv(GL_FRONT, GL_SPECULAR, &gColorS[0]);
myBackColor.Values (aValueCol[0], aValueCol[1], aValueCol[2], bidTC); myBackColor.Values (aValueCol[0], aValueCol[1], aValueCol[2], bidTC);
glColorMaterial(GL_BACK, GL_AMBIENT_AND_DIFFUSE); setColor(GL_BACK, &aValueCol[0], 0.8, 5);
glColor3d (aValueCol[0], aValueCol[1], aValueCol[2]);
glMateriali(GL_FRONT, GL_SHININESS, 10);
gColorS[0] = 0.9f * static_cast<GLfloat> (aValueCol[0]) + 0.1f;
gColorS[1] = 0.9f * static_cast<GLfloat> (aValueCol[1]) + 0.1f;
gColorS[2] = 0.9f * static_cast<GLfloat> (aValueCol[2]) + 0.1f;
glMaterialfv(GL_BACK, GL_SPECULAR, &gColorS[0]);
glMateriali(GL_BACK, GL_SHININESS, 5);
} }
glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, &gColorN[0]); glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, &gColorN[0]);
if (theType == Draw_Hilighted)
glColor3d(0.9, 0.9, 0.9); // for the polygon presentation
glLineWidth (aLineWidth); glLineWidth (aLineWidth);
glShadeModel(GL_SMOOTH);
} }
//======================================================================= //=======================================================================
@ -223,23 +212,21 @@ void NIS_SurfaceDrawer::BeforeDraw (const DrawType theType,
void NIS_SurfaceDrawer::AfterDraw (const DrawType theType, void NIS_SurfaceDrawer::AfterDraw (const DrawType theType,
const NIS_DrawList&) const NIS_DrawList&)
{ {
// Reset transformation matrix.
// glPopMatrix();
glDisable(GL_COLOR_MATERIAL);
glDisable(GL_LIGHTING); glDisable(GL_LIGHTING);
glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_VERTEX_ARRAY);
switch (theType) { switch (theType) {
case Draw_DynHilighted: case Draw_Transparent:
// glDisable(GL_POLYGON_OFFSET_LINE); glDisable(GL_BLEND);
break; glDepthMask(GL_TRUE);
case Draw_Hilighted: case Draw_Hilighted:
case Draw_Normal: case Draw_Normal:
case Draw_Transparent: case Draw_Top:
glDisable(GL_POLYGON_OFFSET_FILL); if (myIsWireframe == Standard_False)
glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_NORMAL_ARRAY);
default:; default:;
} }
if (myIsWireframe == Standard_False)
glDisable(GL_POLYGON_OFFSET_FILL);
} }
//======================================================================= //=======================================================================
@ -255,16 +242,57 @@ void NIS_SurfaceDrawer::Draw (const Handle_NIS_InteractiveObject& theObj,
#ifdef _DEBUG #ifdef _DEBUG
static const Handle(Standard_Type) ThisType = STANDARD_TYPE(NIS_Surface); static const Handle(Standard_Type) ThisType = STANDARD_TYPE(NIS_Surface);
Standard_ProgramError_Raise_if (theObj->IsKind(ThisType) == Standard_False, Standard_ProgramError_Raise_if (theObj->IsKind(ThisType) == Standard_False,
"NIS_Surface::Draw: " "NIS_Surface::Draw: irrelevant object type");
"irrelevant object type");
#endif #endif
const NIS_Surface * pObject = const NIS_Surface * pObject =
static_cast <const NIS_Surface *> (theObj.operator->()); static_cast <const NIS_Surface *> (theObj.operator->());
if (pObject->NTriangles())
{
glVertexPointer (3, GL_FLOAT, 0, pObject->Node(0)); glVertexPointer (3, GL_FLOAT, 0, pObject->Node(0));
// In Highlited mode the shape must be shown as wireframe
Standard_Boolean isWireframe(myIsWireframe);
if (isWireframe == Standard_False && theType == Draw_DynHilighted)
if (pObject->NEdges() > 0)
isWireframe = Standard_True;
if (isWireframe)
{
for (Standard_Integer i = 0; i < pObject->NEdges(); i++) {
const GLint * pEdge = static_cast<const GLint *> (pObject->Edge(i));
glDrawElements (GL_LINE_STRIP, pEdge[0], GL_UNSIGNED_INT, &pEdge[1]);
}
} else {
if (pObject->NTriangles()) {
if (theType != Draw_DynHilighted)
glNormalPointer (GL_FLOAT, 0, pObject->Normal(0)); glNormalPointer (GL_FLOAT, 0, pObject->Normal(0));
glDrawElements (GL_TRIANGLES, pObject->NTriangles()*3, glDrawElements (GL_TRIANGLES, pObject->NTriangles()*3,
GL_UNSIGNED_INT, pObject->Triangle(0)); GL_UNSIGNED_INT, pObject->Triangle(0));
} }
}
} }
//=======================================================================
//function : setColor
//purpose :
//=======================================================================
void setColor(GLenum theFace,
Quantity_Parameter * theAmbient,
const Standard_Real theSpecularity,
GLint theShininess)
{
GLfloat aSpec = static_cast<GLfloat>(theSpecularity);
GLfloat aValueCol[4] = {
GLfloat(theAmbient[0]),
GLfloat(theAmbient[1]),
GLfloat(theAmbient[2]),
GLfloat(theAmbient[3])
};
glMaterialfv(theFace, GL_AMBIENT_AND_DIFFUSE, &aValueCol[0]);
aValueCol[0] = aSpec * (aValueCol[0] - 1.f) + 1.f;
aValueCol[1] = aSpec * (aValueCol[1] - 1.f) + 1.f;
aValueCol[2] = aSpec * (aValueCol[2] - 1.f) + 1.f;
aValueCol[3] = 1.f;
glMaterialfv(theFace, GL_SPECULAR, &aValueCol[0]);
glMateriali(theFace, GL_SHININESS, theShininess);
}

View File

@ -26,15 +26,14 @@ class NIS_SurfaceDrawer : public NIS_Drawer
*/ */
Standard_EXPORT NIS_SurfaceDrawer(const Quantity_Color &theNormal, Standard_EXPORT NIS_SurfaceDrawer(const Quantity_Color &theNormal,
const Quantity_Color &theHilight const Quantity_Color &theHilight
= Quantity_NOC_GRAY80, = Quantity_NOC_GRAY65,
const Quantity_Color &theDynHilight const Quantity_Color &theDynHilight
= Quantity_NOC_CYAN1); = Quantity_NOC_CYAN1);
/** /**
* Sets the color and transparency of the drawer. * Sets the color of the drawer.
*/ */
Standard_EXPORT void SetColor (const Quantity_Color &theColor, Standard_EXPORT void SetColor (const Quantity_Color &theColor);
const Standard_Real theTransparency);
/** /**
* Define the color used for the back side of rendered triangles. * Define the color used for the back side of rendered triangles.
@ -66,7 +65,7 @@ class NIS_SurfaceDrawer : public NIS_Drawer
*/ */
inline void SetPolygonOffset (const Standard_Real theOffset) inline void SetPolygonOffset (const Standard_Real theOffset)
{ {
myPolygonOffset = static_cast<const Standard_ShortReal>(theOffset); myPolygonOffset = static_cast<Standard_ShortReal>(theOffset);
} }
/** /**
@ -74,10 +73,9 @@ class NIS_SurfaceDrawer : public NIS_Drawer
*/ */
inline Standard_Real GetPolygonOffset () const inline Standard_Real GetPolygonOffset () const
{ {
return static_cast<const Standard_Real>(myPolygonOffset); return static_cast<Standard_Real>(myPolygonOffset);
} }
/** /**
* Copy the relevant information from another instance of Drawer. * Copy the relevant information from another instance of Drawer.
* raises exception if theOther has incompatible type (test IsKind). * raises exception if theOther has incompatible type (test IsKind).
@ -115,11 +113,11 @@ class NIS_SurfaceDrawer : public NIS_Drawer
private: private:
Quantity_Color myColor[4]; Quantity_Color myColor[5];
Quantity_Color myBackColor; Quantity_Color myBackColor;
gp_Trsf myTrsf; gp_Trsf myTrsf;
Standard_Real myTransparency;
Standard_ShortReal myPolygonOffset; Standard_ShortReal myPolygonOffset;
Standard_Boolean myIsWireframe;
friend class NIS_Surface; friend class NIS_Surface;

File diff suppressed because it is too large Load Diff

View File

@ -10,29 +10,67 @@
#include <NIS_InteractiveObject.hxx> #include <NIS_InteractiveObject.hxx>
#include <Quantity_Color.hxx> #include <Quantity_Color.hxx>
#ifdef WNT
// Disable the warning "operator new unmatched by delete"
#pragma warning (push)
#pragma warning (disable:4291)
#endif
class Handle_NIS_TriangulatedDrawer; class Handle_NIS_TriangulatedDrawer;
class NCollection_BaseAllocator; class NCollection_BaseAllocator;
class Handle_NCollection_BaseAllocator; class Handle_NCollection_BaseAllocator;
class NIS_TriangulatedDrawer;
/** /**
* Block of comments describing class NIS_Triangulated * Interactive object that consists of triangles, lines and polygons without
* normals. Particularly can be used to render planar 2D shapes.
*
* @par 2D and 3D model
* Vertices are stored in an array of float numbers, 2 or 3 numbers per vertex.
* The number of dimensions is defined in the constructor, see the parameter
* 'is2D'. When 2D is defined then for all vertices the Z coordinate is 0.
* To display planar objects in a plane different from XOY you should subclass
* this type together with the correponding Drawer and store the transformation
* parameters. In Drawer subclass either in method BeforeDraw() or in method
* Draw() you would call glTranslate() or glMultMatrix() so that all vertices
* should be located in their proper positions.
*
* @par Compressed storage
* For efficient memory utilization, indice (triangles, segments, polygons) are
* 8-bit, 16-bit or 32-bit numbers. The width of this numeric representation is
* chosen automatically when the total number of nodes is passed in the
* constructor or in any Set* method. For example, if this number of nodes is
* smaller than 256 then 8-bit representation is selected. The choice is stored
* in 'myIndexType' data member.
*/ */
class NIS_Triangulated : public NIS_InteractiveObject class NIS_Triangulated : public NIS_InteractiveObject
{ {
protected: protected:
// Constants defining the mode (type) of presentation. They allow mixed type, /**
// e.g., Triangulation+Line. Line and Segments are not mixable, their mix is * Constants defining the mode (type) of presentation. They allow mixed type,
// treated as Line only. * e.g., Triangulation+Line. Line and Segments are not mixable, their mix is
* treated as Line only.
*/
enum { enum {
Type_None = 0, Type_None = 0,
Type_Loop = 1, // modifier to Line Type_Loop = 1, //!< modifier to Line
Type_Line = 2, Type_Line = 2,
Type_Segments = 4, Type_Segments = 4,
Type_Triangulation = 8, Type_Triangulation = 8,
Type_Polygons = 16 Type_Polygons = 16
}; };
public:
/**
* Enumerated type of polygon rendering.
*/
enum PolygonType {
Polygon_Default = 0, //!< Polygon as LINE, Triangulation as FILL
Polygon_Line = 1, //!< Both Polygon and Triangulation as LINE
Polygon_Fill = 2 //!< Both Polygon and Triangulation as FILL
};
public: public:
// ---------- PUBLIC METHODS ---------- // ---------- PUBLIC METHODS ----------
@ -42,9 +80,17 @@ class NIS_Triangulated : public NIS_InteractiveObject
* (this number may be defined later in methods Set*Prs) as well as the * (this number may be defined later in methods Set*Prs) as well as the
* memory allocator where the nodes, lines and triangles will be stored by * memory allocator where the nodes, lines and triangles will be stored by
* this instance. * this instance.
* @param nNodes
* Total number of nodes that will be initialized for this object
* @param is2D
* If true then the nodes will be 2D in plane Z=0, otherwise normal 3D.
* @param theAlloc
* Allocator for internal data
*/ */
Standard_EXPORT NIS_Triangulated(const Standard_Integer nNodes = 0, Standard_EXPORT NIS_Triangulated(const Standard_Integer nNodes = 0,
const Handle_NCollection_BaseAllocator& =0L); const Standard_Boolean is2D = Standard_False,
const Handle_NCollection_BaseAllocator&
theAlloc = 0L);
/** /**
* Define the polygonal presentration. * Define the polygonal presentration.
@ -137,9 +183,8 @@ class NIS_Triangulated : public NIS_InteractiveObject
/** /**
* Create a default drawer instance. * Create a default drawer instance.
*/ */
Standard_EXPORT virtual Handle_NIS_Drawer Standard_EXPORT virtual NIS_Drawer *
DefaultDrawer () const; DefaultDrawer (NIS_Drawer *) const;
/** /**
* Define the coordinates of node [ind]. * Define the coordinates of node [ind].
@ -163,16 +208,14 @@ class NIS_Triangulated : public NIS_InteractiveObject
/** /**
* Allocate a single polygon, should be called for each polygon following * Allocate a single polygon, should be called for each polygon following
* the call SetPolygonsPrs(). * the call SetPolygonsPrs(). The polygon can be filled by node indices using
* the method SetPolygonNode().
* @param ind * @param ind
* Index of the polygon, should be [0..Npolygons-1] * Index of the polygon, should be [0..Npolygons-1]
* @param theSz * @param theSz
* Number of points (segments) in the polygon. * Number of points (segments) in the polygon.
* @return
* Pointer to the allocated buffer where you should store the indices
* of all polygon nodes in order, total "theSz" integers.
*/ */
Standard_EXPORT Standard_Integer* SetPolygon (const Standard_Integer ind, Standard_EXPORT void SetPolygon (const Standard_Integer ind,
const Standard_Integer theSz); const Standard_Integer theSz);
/** /**
@ -203,48 +246,43 @@ class NIS_Triangulated : public NIS_InteractiveObject
* Query the number of polygons. * Query the number of polygons.
*/ */
inline Standard_Integer NPolygons () const inline Standard_Integer NPolygons () const
{ return myNPolygons; } { return static_cast<Standard_Integer>(myNPolygons); }
/** /**
* Query the node by its index. * Query the node by its index.
* @return * @return
* pointer to array of 3 Standard_ShortReal values (X,Y,Z coordinates) * pointer to array of 2 or 3 Standard_ShortReal values {X,Y(,Z) coord}
*/ */
inline const Standard_ShortReal * Node (const Standard_Integer ind) const inline const Standard_ShortReal * Node (const Standard_Integer ind) const
{ return &mypNodes[ind*3]; } { return &mypNodes[ind * myNodeCoord]; }
/** /**
* Query the triangle by its index. * Define the node of a polygon by index.
* @return * @param indPoly
* pointer to array of 3 Standard_Integer values (nodes 0, 1, 2) * Index of the Polygon, should be less than the number of polygons that is
*/ * defined in SetPolygonsPrs() and can be returned by NPOlygons().
inline const Standard_Integer * Triangle (const Standard_Integer ind) const
{ return &mypTriangles[ind*3]; }
/**
* Query the node of line or segments by index in the array of node indices.
* This method does not make distinction of the presentation type
* (field myType), so the correct definition of ind is to be done by the
* caller.
* @return
* pointer to the Integer value representing the index of the node.
*/
inline const Standard_Integer * LineNode (const Standard_Integer ind) const
{ return &mypLines[ind]; }
/**
* Query the polygon.
* @param ind * @param ind
* rank of the polygon [0 .. N-1] * Index of the node in the Polygon. Should be less than the parameter theSz
* @param outInd * in the corresponding previous SetPolygon() call.
* <tt>[out]</tt> array of vertex indice * @param iNode
* @return * Index of the node in the given position of the Polygon.
* number of vertice in the polygon - the dimension of outInd array
*/ */
inline const Standard_Integer Polygon (const Standard_Integer ind, Standard_EXPORT void SetPolygonNode
Standard_Integer* & outInd) const (const Standard_Integer indPoly,
{ return * (outInd = mypPolygons[ind])++; } const Standard_Integer ind,
const Standard_Integer iNode);
/**
* Get the node with index 'ind' from the polygon number 'indPoly'.
*/
Standard_EXPORT Standard_Integer PolygonNode(const Standard_Integer indPoly,
const Standard_Integer ind)const;
/**
* Get the number of nodes for the polygon number 'indPoly'.
*/
Standard_EXPORT Standard_Integer NPolygonNodes
(const Standard_Integer indPoly)const;
/** /**
* Set the boolean flag defining if the polygons or the triangulation * Set the boolean flag defining if the polygons or the triangulation
@ -252,24 +290,22 @@ class NIS_Triangulated : public NIS_InteractiveObject
* Line/Segments. * Line/Segments.
* @param isDrawPolygons * @param isDrawPolygons
* True defines that no triangulation is drawn, only polygons are. False * True defines that no triangulation is drawn, only polygons are. False
* defines that only triangulation is draw, no polygons. * defines that only triangulation is drawn, no polygons.
* @param isUpdateV
* True if all views should be updated, otherwise wait till the next update
*/ */
Standard_EXPORT void SetDrawPolygons Standard_EXPORT void SetDrawPolygons
(const Standard_Boolean isDrawPolygons, (const Standard_Boolean isDrawPolygons);
const Standard_Boolean isUpdateViews /**
= Standard_True); * Set the type of polygon rendering.
*/
Standard_EXPORT void SetPolygonType
(const PolygonType theType);
/** /**
* Set the normal color for presentation. * Set the normal color for presentation.
* @param theColor * @param theColor
* New color to use for the presentation. * New color to use for the presentation.
* @param isUpdateV
* True if all views should be updated, otherwise wait till the next update
*/ */
Standard_EXPORT void SetColor (const Quantity_Color& theColor, Standard_EXPORT void SetColor (const Quantity_Color& theColor);
const Standard_Boolean isUpdateV
= Standard_True);
/** /**
* Get Normal, Transparent or Hilighted color of the presentation. * Get Normal, Transparent or Hilighted color of the presentation.
@ -283,34 +319,34 @@ class NIS_Triangulated : public NIS_InteractiveObject
* Set the color for hilighted presentation. * Set the color for hilighted presentation.
* @param theColor * @param theColor
* New color to use for the presentation. * New color to use for the presentation.
* @param isUpdateV
* True if all views should be updated, otherwise wait till the next update
*/ */
Standard_EXPORT void SetHilightColor (const Quantity_Color& theColor, Standard_EXPORT void SetHilightColor (const Quantity_Color& theColor);
const Standard_Boolean isUpdateV
= Standard_True);
/** /**
* Set the color for dynamic hilight presentation. * Set the color for dynamic hilight presentation.
* @param theColor * @param theColor
* New color to use for the presentation. * New color to use for the presentation.
* @param isUpdateV
* True if all views should be updated, otherwise wait till the next update
*/ */
Standard_EXPORT void SetDynHilightColor(const Quantity_Color& theColor, Standard_EXPORT void SetDynHilightColor(const Quantity_Color& theColor);
const Standard_Boolean isUpdateV
= Standard_True);
/** /**
* Set the width of line presentations in pixels. * Set the width of line presentations in pixels.
* @param theWidth * @param theWidth
* New line width to use for the presentation. * New line width to use for the presentation.
* @param isUpdateV
* True if all views should be updated, otherwise wait till the next update
*/ */
Standard_EXPORT void SetLineWidth (const Standard_Real theWidth, Standard_EXPORT void SetLineWidth (const Standard_Real theWidth);
const Standard_Boolean isUpdateV
= Standard_True); /**
* Create a copy of theObject except its ID.
* @param theAll
* Allocator where the Dest should store its private data.
* @param theDest
* <tt>[in-out]</tt> The target object where the data are copied. If
* passed NULL then the target should be created.
*/
Standard_EXPORT virtual void
Clone (const Handle_NCollection_BaseAllocator& theAll,
Handle_NIS_InteractiveObject& theDest) const;
/** /**
* Intersect the InteractiveObject geometry with a line/ray. * Intersect the InteractiveObject geometry with a line/ray.
@ -323,7 +359,7 @@ class NIS_Triangulated : public NIS_InteractiveObject
* detected. Otherwise returns the coordinate of thePnt on the ray. May be * detected. Otherwise returns the coordinate of thePnt on the ray. May be
* negative. * negative.
*/ */
Standard_EXPORT Standard_Real Standard_EXPORT virtual Standard_Real
Intersect (const gp_Ax1& theAxis, Intersect (const gp_Ax1& theAxis,
const Standard_Real theOver) const; const Standard_Real theOver) const;
@ -343,6 +379,25 @@ class NIS_Triangulated : public NIS_InteractiveObject
const gp_Trsf& theTrf, const gp_Trsf& theTrf,
const Standard_Boolean isFull)const; const Standard_Boolean isFull)const;
/**
* Intersect the InteractiveObject geometry with a selection polygon.
* @param thePolygon
* the list of vertices of a free-form closed polygon without
* self-intersections. The last point should not coincide with the first
* point of the list. Any two neighbor points should not be confused.
* @param theTrf
* Position/Orientation of the polygon.
* @param isFullIn
* True if full inclusion is required, False - if partial.
* @return
* True if the InteractiveObject geometry intersects the polygon or is
* inside it
*/
Standard_EXPORT virtual Standard_Boolean Intersect
(const NCollection_List<gp_XY> &thePolygon,
const gp_Trsf &theTrf,
const Standard_Boolean isFullIn) const;
Standard_EXPORT static int tri_line_intersect (const double start[3], Standard_EXPORT static int tri_line_intersect (const double start[3],
const double dir[3], const double dir[3],
const float V0[3], const float V0[3],
@ -350,6 +405,13 @@ class NIS_Triangulated : public NIS_InteractiveObject
const float V2[3], const float V2[3],
double * tInter); double * tInter);
Standard_EXPORT static int tri2d_line_intersect(const double start[3],
const double dir[3],
const float V0[2],
const float V1[2],
const float V2[2],
double * tInter);
Standard_EXPORT static int seg_line_intersect (const gp_XYZ& aStart, Standard_EXPORT static int seg_line_intersect (const gp_XYZ& aStart,
const gp_XYZ& aDir, const gp_XYZ& aDir,
const double over2, const double over2,
@ -357,18 +419,71 @@ class NIS_Triangulated : public NIS_InteractiveObject
const float V1[3], const float V1[3],
double * tInter); double * tInter);
Standard_EXPORT static int seg2d_line_intersect(const gp_XYZ& aStart,
const gp_XYZ& aDir,
const double over2,
const float V0[2],
const float V1[2],
double * tInter);
Standard_EXPORT static int seg_box_intersect (const Bnd_B3f& theBox, Standard_EXPORT static int seg_box_intersect (const Bnd_B3f& theBox,
const gp_Pnt thePnt[2]); const gp_Pnt thePnt[2]);
Standard_EXPORT static int seg_box_included (const Bnd_B3f& theBox, Standard_EXPORT static int seg_box_included (const Bnd_B3f& theBox,
const gp_Pnt thePnt[2]); const gp_Pnt thePnt[2]);
Standard_EXPORT static int seg_polygon_intersect
(const NCollection_List<gp_XY> &thePolygon,
const gp_XY thePnt[2]);
Standard_EXPORT static int seg_polygon_included
(const NCollection_List<gp_XY> &thePolygon,
const gp_XY thePnt[2]);
Standard_EXPORT static void ComputeBox (Bnd_B3f& theBox, Standard_EXPORT static void ComputeBox (Bnd_B3f& theBox,
const Standard_Integer nNodes, const Standard_Integer nNodes,
const Standard_ShortReal* pNodes); const Standard_ShortReal* pNodes,
const Standard_Integer nCoord);
/**
* Classification of thePoint with respect to thePolygon.
* @param thePolygon
* the list of vertices of a free-form closed polygon without
* self-intersections. The last point should not coincide with the first
* point of the list. Any two neighbor points should not be confused.
* @param thePoint
* the point to be classified.
* @return
* Standard_True if thePoint in inside thePolygon or lies on its boundary.
*/
Standard_EXPORT static Standard_Boolean
IsIn (const NCollection_List<gp_XY> &thePolygon,
const gp_XY &thePoint);
/**
* Implements deallocation of the object instance
*/
Standard_EXPORT virtual void Delete () const;
/**
* Operator new for memory allocation uses Open CASCADE memory manager
*/
void* operator new (size_t size)
{
return Standard::Allocate(size);
}
protected: protected:
/**
* Allocator-based operator new for dynamic allocations in method Clone()
*/
void* operator new (Standard_Size theSz,
const Handle(NCollection_BaseAllocator)& theAllocator)
{
return theAllocator->Allocate(theSz);
}
/** /**
* Create a 3D bounding box of the object. * Create a 3D bounding box of the object.
*/ */
@ -380,30 +495,49 @@ class NIS_Triangulated : public NIS_InteractiveObject
*/ */
Standard_EXPORT void allocateNodes (const Standard_Integer nNodes); Standard_EXPORT void allocateNodes (const Standard_Integer nNodes);
/**
* Get the node pointed by the i-th index in the array.
*/
Standard_EXPORT gp_Pnt nodeAtInd (const Standard_Integer * theArr,
const Standard_Integer i) const;
/**
* Get the node pointed by the i-th index in the array.
*/
Standard_EXPORT float* nodeArrAtInd (const Standard_Integer * theArr,
const Standard_Integer i) const;
protected: protected:
// ---------- PROTECTED FIELDS ---------- // ---------- PROTECTED FIELDS ----------
/** NCollection_BaseAllocator * myAlloc; //!< Usually from InteractiveContext
* Combination of Type_* constants Standard_Integer myType; //!< Combination of Type_* constants
*/
Standard_Integer myType;
Standard_ShortReal * mypNodes; Standard_ShortReal * mypNodes;
Standard_Integer * mypTriangles; Standard_Integer * mypTriangles;
Standard_Integer * mypLines; Standard_Integer * mypLines;
Standard_Integer ** mypPolygons; Standard_Integer ** mypPolygons;
Standard_Integer myNNodes; Standard_Integer myNNodes;
Standard_Integer myNTriangles; Standard_Integer myNTriangles;
Standard_Integer myNPolygons;
Standard_Integer myNLineNodes; Standard_Integer myNLineNodes;
NCollection_BaseAllocator * myAlloc; unsigned int myNPolygons : 24;
Standard_Boolean myIsDrawPolygons; Standard_Boolean myIsDrawPolygons : 1;
Standard_Boolean myIsCloned : 1; //!< How it is allocated
unsigned int myIndexType : 2; //!< 0:8bit, 1:16bit, 2:32bit
unsigned int myNodeCoord : 2; //!< 2 or 3 coordinates
unsigned int myPolygonType : 2;
public: public:
// Declaration of CASCADE RTTI // Declaration of CASCADE RTTI
DEFINE_STANDARD_RTTI (NIS_Triangulated) DEFINE_STANDARD_RTTI (NIS_Triangulated)
friend class NIS_TriangulatedDrawer;
}; };
// Definition of HANDLE object using Standard_DefineHandle.hxx // Definition of HANDLE object using Standard_DefineHandle.hxx
DEFINE_STANDARD_HANDLE (NIS_Triangulated, NIS_InteractiveObject) DEFINE_STANDARD_HANDLE (NIS_Triangulated, NIS_InteractiveObject)
#ifdef WNT
#pragma warning (pop)
#endif
#endif #endif

View File

@ -37,9 +37,12 @@ NIS_TriangulatedDrawer::NIS_TriangulatedDrawer
const Quantity_Color theHilight, const Quantity_Color theHilight,
const Quantity_Color theDynHilight) const Quantity_Color theDynHilight)
: myLineWidth (1.f), : myLineWidth (1.f),
myIsDrawPolygons (Standard_False) myIsDrawPolygons (Standard_False),
myPolygonType (NIS_Triangulated::Polygon_Default),
myPolygonAsLineLoop (Standard_False)
{ {
myColor[Draw_Normal] = theNormal; myColor[Draw_Normal] = theNormal;
myColor[Draw_Top] = theNormal;
myColor[Draw_Transparent] = theNormal; myColor[Draw_Transparent] = theNormal;
myColor[Draw_Hilighted] = theHilight; myColor[Draw_Hilighted] = theHilight;
myColor[Draw_DynHilighted] = theDynHilight; myColor[Draw_DynHilighted] = theDynHilight;
@ -57,14 +60,18 @@ void NIS_TriangulatedDrawer::Assign (const Handle_NIS_Drawer& theOther)
const Handle(NIS_TriangulatedDrawer)& anOther = const Handle(NIS_TriangulatedDrawer)& anOther =
static_cast <const Handle(NIS_TriangulatedDrawer)&> (theOther); static_cast <const Handle(NIS_TriangulatedDrawer)&> (theOther);
myColor[Draw_Normal] = anOther->myColor[Draw_Normal]; myColor[Draw_Normal] = anOther->myColor[Draw_Normal];
myColor[Draw_Top] = anOther->myColor[Draw_Top];
myColor[Draw_Transparent] = anOther->myColor[Draw_Transparent]; myColor[Draw_Transparent] = anOther->myColor[Draw_Transparent];
myColor[Draw_Hilighted] = anOther->myColor[Draw_Hilighted]; myColor[Draw_Hilighted] = anOther->myColor[Draw_Hilighted];
myColor[Draw_DynHilighted] = anOther->myColor[Draw_DynHilighted]; myColor[Draw_DynHilighted] = anOther->myColor[Draw_DynHilighted];
myLineWidth = anOther->myLineWidth; myLineWidth = anOther->myLineWidth;
myIsDrawPolygons = anOther->myIsDrawPolygons; myIsDrawPolygons = anOther->myIsDrawPolygons;
myPolygonType = anOther->myPolygonType;
} }
} }
static const Standard_Integer nObjPerDrawer = 64;
//======================================================================= //=======================================================================
//function : IsEqual //function : IsEqual
//purpose : Comparison of two Drawers (for Map impementation) //purpose : Comparison of two Drawers (for Map impementation)
@ -86,7 +93,8 @@ Standard_Boolean NIS_TriangulatedDrawer::IsEqual
.SquareDistance (myColor[Draw_DynHilighted]) < anEpsilon2 && .SquareDistance (myColor[Draw_DynHilighted]) < anEpsilon2 &&
(anOther->myLineWidth - myLineWidth) * (anOther->myLineWidth - myLineWidth) *
(anOther->myLineWidth - myLineWidth) < 0.01 && (anOther->myLineWidth - myLineWidth) < 0.01 &&
anOther->myIsDrawPolygons == myIsDrawPolygons); anOther->myIsDrawPolygons == myIsDrawPolygons &&
anOther->myPolygonType == myPolygonType);
return aResult; return aResult;
} }
@ -98,7 +106,7 @@ Standard_Boolean NIS_TriangulatedDrawer::IsEqual
void NIS_TriangulatedDrawer::BeforeDraw (const DrawType theType, void NIS_TriangulatedDrawer::BeforeDraw (const DrawType theType,
const NIS_DrawList&) const NIS_DrawList&)
{ {
Quantity_Parameter aValue[3]; Quantity_Parameter aValue[4];
Quantity_TypeOfColor bidTC (Quantity_TOC_RGB); Quantity_TypeOfColor bidTC (Quantity_TOC_RGB);
GLfloat aLineWidth (myLineWidth); GLfloat aLineWidth (myLineWidth);
Standard_Integer anOffsetHilighted = 0; Standard_Integer anOffsetHilighted = 0;
@ -109,10 +117,17 @@ void NIS_TriangulatedDrawer::BeforeDraw (const DrawType theType,
anOffsetHilighted = -11; anOffsetHilighted = -11;
#endif #endif
case Draw_Hilighted: case Draw_Hilighted:
if (myIsDrawPolygons) switch (myPolygonType) {
default:
case NIS_Triangulated::Polygon_Default:
if (myIsDrawPolygons) {
case NIS_Triangulated::Polygon_Line:
glEnable(GL_POLYGON_OFFSET_LINE); glEnable(GL_POLYGON_OFFSET_LINE);
else } else {
case NIS_Triangulated::Polygon_Fill:
glEnable(GL_POLYGON_OFFSET_FILL); glEnable(GL_POLYGON_OFFSET_FILL);
}
}
if (theType == Draw_Hilighted) if (theType == Draw_Hilighted)
{ {
#ifdef NEGATIVE_POFFSET #ifdef NEGATIVE_POFFSET
@ -121,12 +136,22 @@ void NIS_TriangulatedDrawer::BeforeDraw (const DrawType theType,
anOffsetHilighted = 1; anOffsetHilighted = 1;
#endif #endif
} }
myColor[theType].Values (aValue[0], aValue[1], aValue[2], bidTC);
glColor3d (aValue[0], aValue[1], aValue[2]);
break; break;
case Draw_Normal: case Draw_Normal:
case Draw_Top:
case Draw_Transparent: case Draw_Transparent:
#ifndef NEGATIVE_POFFSET #ifndef NEGATIVE_POFFSET
anOffsetHilighted = 11; anOffsetHilighted = 11;
#endif #endif
myColor[theType].Values (aValue[0], aValue[1], aValue[2], bidTC);
aValue[3] = 1. - myTransparency;
if (myTransparency > 0.01) {
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
glColor4d (aValue[0], aValue[1], aValue[2], aValue[3]);
break; break;
default: default:
return; return;
@ -134,12 +159,19 @@ void NIS_TriangulatedDrawer::BeforeDraw (const DrawType theType,
if (anOffsetHilighted) if (anOffsetHilighted)
glPolygonOffset(1.f, static_cast<GLfloat>(anOffsetHilighted)); glPolygonOffset(1.f, static_cast<GLfloat>(anOffsetHilighted));
myColor[theType].Values (aValue[0], aValue[1], aValue[2], bidTC); // myColor[theType].Values (aValue[0], aValue[1], aValue[2], bidTC);
glColor3d (aValue[0], aValue[1], aValue[2]); // glColor3d (aValue[0], aValue[1], aValue[2]);
if (myIsDrawPolygons) switch (myPolygonType) {
default:
case NIS_Triangulated::Polygon_Default:
if (myIsDrawPolygons) {
case NIS_Triangulated::Polygon_Line:
glPolygonMode (GL_FRONT_AND_BACK, GL_LINE); glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
else } else {
case NIS_Triangulated::Polygon_Fill:
glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
}
}
glEnableClientState (GL_VERTEX_ARRAY); glEnableClientState (GL_VERTEX_ARRAY);
glLineWidth (aLineWidth); glLineWidth (aLineWidth);
glShadeModel(GL_FLAT); glShadeModel(GL_FLAT);
@ -157,16 +189,27 @@ void NIS_TriangulatedDrawer::AfterDraw (const DrawType theType,
switch (theType) { switch (theType) {
case Draw_Hilighted: case Draw_Hilighted:
case Draw_DynHilighted: case Draw_DynHilighted:
if (myIsDrawPolygons) switch (myPolygonType) {
default:
case NIS_Triangulated::Polygon_Default:
if (myIsDrawPolygons) {
case NIS_Triangulated::Polygon_Line:
glDisable(GL_POLYGON_OFFSET_LINE); glDisable(GL_POLYGON_OFFSET_LINE);
else } else {
case NIS_Triangulated::Polygon_Fill:
glDisable(GL_POLYGON_OFFSET_FILL); glDisable(GL_POLYGON_OFFSET_FILL);
}
}
case Draw_Normal: case Draw_Normal:
case Draw_Top:
case Draw_Transparent: case Draw_Transparent:
glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_VERTEX_ARRAY);
if (myTransparency > 0.01)
glDisable(GL_BLEND);
default:; default:;
} }
if (myIsDrawPolygons) if (myPolygonType == NIS_Triangulated::Polygon_Line ||
(myPolygonType == NIS_Triangulated::Polygon_Default && myIsDrawPolygons))
glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
} }
@ -188,35 +231,57 @@ void NIS_TriangulatedDrawer::Draw (const Handle_NIS_InteractiveObject& theObj,
#endif #endif
const NIS_Triangulated * pObject = const NIS_Triangulated * pObject =
static_cast <const NIS_Triangulated *> (theObj.operator->()); static_cast <const NIS_Triangulated *> (theObj.operator->());
glVertexPointer (3, GL_FLOAT, 0, pObject->Node(0)); glVertexPointer (pObject->myNodeCoord, GL_FLOAT, 0, pObject->Node(0));
GLenum aType = GL_UNSIGNED_INT;
if (pObject->myIndexType == 0)
aType = GL_UNSIGNED_BYTE;
else if (pObject->myIndexType == 1)
aType = GL_UNSIGNED_SHORT;
if (myIsDrawPolygons == Standard_False) { if (myIsDrawPolygons == Standard_False) {
if (pObject->IsTriangulation()) if (pObject->IsTriangulation()) {
glDrawElements (GL_TRIANGLES, pObject->NTriangles()*3, glDrawElements (GL_TRIANGLES, pObject->NTriangles()*3,
GL_UNSIGNED_INT, pObject->Triangle(0)); aType, pObject->mypTriangles);
}
} else { } else {
if (pObject->IsPolygons()) { if (pObject->IsPolygons()) {
GLenum aMode = GL_POLYGON;
if (myPolygonAsLineLoop &&
(myPolygonType == NIS_Triangulated::Polygon_Line ||
(myPolygonType == NIS_Triangulated::Polygon_Default &&
myIsDrawPolygons)))
aMode = GL_LINE_LOOP;
const Standard_Integer nPoly = pObject->NPolygons(); const Standard_Integer nPoly = pObject->NPolygons();
for (Standard_Integer i = 0; i < nPoly; i++) { for (Standard_Integer i = 0; i < nPoly; i++) {
Standard_Integer * arrNodes; const Standard_Integer nSize = pObject->NPolygonNodes(i);
const Standard_Integer nSize = pObject->Polygon (i, arrNodes); void* anArray;
glDrawElements (GL_LINE_LOOP, nSize, GL_UNSIGNED_INT, arrNodes); if (pObject->myIndexType == 0)
anArray = reinterpret_cast<unsigned char *>(pObject->mypPolygons[i]) + 1;
else if (pObject->myIndexType == 1)
anArray = reinterpret_cast<unsigned short *>(pObject->mypPolygons[i]) + 1;
else
anArray = pObject->mypPolygons[i] + 1;
glDrawElements (aMode, nSize, aType, anArray);
} }
} }
} }
if (pObject->IsSegments()) if (pObject->IsSegments())
glDrawElements (GL_LINES, pObject->NLineNodes(), glDrawElements (GL_LINES, pObject->NLineNodes(),
GL_UNSIGNED_INT, pObject->LineNode(0)); aType, pObject->mypLines);
else { else {
Standard_Boolean isLoop; Standard_Boolean isLoop;
if (pObject->IsLine(isLoop)) if (pObject->IsLine(isLoop))
if (isLoop) { if (isLoop) {
glPolygonMode (GL_FRONT_AND_BACK, GL_LINE); // glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
glDrawElements (GL_LINE_LOOP, pObject->NLineNodes(), glDrawElements (GL_LINE_LOOP, pObject->NLineNodes(),
GL_UNSIGNED_INT, pObject->LineNode(0)); aType, pObject->mypLines);
glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); // glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
} else { } else {
glDrawElements (GL_LINE_STRIP, pObject->NLineNodes(), glDrawElements (GL_LINE_STRIP, pObject->NLineNodes(),
GL_UNSIGNED_INT, pObject->LineNode(0)); aType, pObject->mypLines);
} }
} }
} }

View File

@ -60,10 +60,20 @@ class NIS_TriangulatedDrawer : public NIS_Drawer
*/ */
Standard_EXPORT virtual Standard_Boolean Standard_EXPORT virtual Standard_Boolean
IsEqual (const Handle_NIS_Drawer& theOth)const; IsEqual (const Handle_NIS_Drawer& theOth)const;
private:
Quantity_Color myColor[4]; protected:
/**
* If myPolygonAsLineLoop is true then draw polygons of the object
* in the mode GL_LINE_LOOP instead of GL_POLYGON in the case if no filling
* was requested. This will eliminate the bug with Intel integrated graphic
* cards (e.g. 945G Express) for the sake of polygon offset functionality.
*/
Standard_Boolean myPolygonAsLineLoop;
Quantity_Color myColor[5];
Standard_ShortReal myLineWidth; Standard_ShortReal myLineWidth;
Standard_Boolean myIsDrawPolygons; Standard_Boolean myIsDrawPolygons;
unsigned int myPolygonType;
friend class NIS_Triangulated; friend class NIS_Triangulated;

View File

@ -8,6 +8,8 @@
#include <NIS_InteractiveObject.hxx> #include <NIS_InteractiveObject.hxx>
#include <gp_Ax1.hxx> #include <gp_Ax1.hxx>
#include <Visual3d_View.hxx> #include <Visual3d_View.hxx>
#include <Bnd_B2f.hxx>
#include <TColStd_MapIteratorOfPackedMapOfInteger.hxx>
#ifdef WNT #ifdef WNT
#include <Windows.h> #include <Windows.h>
#endif #endif
@ -23,12 +25,12 @@ IMPLEMENT_STANDARD_RTTIEXT (NIS_View, V3d_OrthographicView)
NIS_View::NIS_View (const Handle(V3d_Viewer)& theViewer, NIS_View::NIS_View (const Handle(V3d_Viewer)& theViewer,
const Handle(Aspect_Window)& theWindow) const Handle(Aspect_Window)& theWindow)
: V3d_OrthographicView (theViewer) : V3d_OrthographicView (theViewer),
myIsTopHilight(Standard_False),
myDoHilightSelected(Standard_True)
{ {
if (!theWindow.IsNull()) { if (!theWindow.IsNull())
const Aspect_GraphicCallbackProc aCallback = &MyCallback; V3d_View::SetWindow (theWindow, NULL, &MyCallback, this);
V3d_View::SetWindow (theWindow, NULL, aCallback, this);
}
} }
//======================================================================= //=======================================================================
@ -38,8 +40,7 @@ NIS_View::NIS_View (const Handle(V3d_Viewer)& theViewer,
void NIS_View::SetWindow(const Handle(Aspect_Window) &theWindow) void NIS_View::SetWindow(const Handle(Aspect_Window) &theWindow)
{ {
const Aspect_GraphicCallbackProc aCallback = &MyCallback; V3d_View::SetWindow (theWindow, NULL, &MyCallback, this);
V3d_View::SetWindow (theWindow, NULL, aCallback, this);
} }
// //======================================================================= // //=======================================================================
@ -80,6 +81,14 @@ void NIS_View::RemoveContext (NIS_InteractiveContext * theCtx)
myContexts.Remove (anIter); myContexts.Remove (anIter);
break; break;
} }
NCollection_Map<Handle_NIS_Drawer>::Iterator anIterD (theCtx->GetDrawers ());
for (; anIterD.More(); anIterD.Next()) {
const Handle(NIS_Drawer)& aDrawer = anIterD.Value();
if (aDrawer.IsNull() == Standard_False) {
aDrawer->UpdateExListId(this);
}
}
} }
//======================================================================= //=======================================================================
@ -87,7 +96,93 @@ void NIS_View::RemoveContext (NIS_InteractiveContext * theCtx)
//purpose : //purpose :
//======================================================================= //=======================================================================
void NIS_View::FitAll3d () Standard_Boolean NIS_View::FitAll3d (const Quantity_Coefficient theCoef)
{
Standard_Boolean aResult(Standard_False);
/*
Standard_Integer aLimp[4] = { 1000000, -1000000, 1000000, -1000000 };
GetBndBox( aLimp[0], aLimp[1], aLimp[2], aLimp[3] );
if (aLimp[1] > -1000000 && aLimp[3] > -1000000 &&
aLimp[0] < aLimp[1] && aLimp[2] < aLimp[3])
{
// Scale the view
WindowFit (aLimp[0], aLimp[2], aLimp[1], aLimp[3]);
aResult = Standard_True;
}
*/
Bnd_B3f aBox = GetBndBox();
// Check that the box is not empty
if (aBox.IsVoid() == Standard_False && MyView->IsDefined() == Standard_True) {
// Convert the 3D box to 2D representation in view coordinates
Standard_Real Umin,Umax,Vmin,Vmax,U,V,W;
gp_XYZ aCoord;
const gp_XYZ aCorner[2] = { aBox.CornerMin(), aBox.CornerMax() };
Standard_Boolean doFit = Standard_True;
while (doFit) {
for (Standard_Integer i = 0; i < 8; i++) {
if (i & 0x1) aCoord.SetX (aCorner[0].X());
else aCoord.SetX (aCorner[1].X());
if (i & 0x2) aCoord.SetY (aCorner[0].Y());
else aCoord.SetY (aCorner[1].Y());
if (i & 0x4) aCoord.SetZ (aCorner[0].Z());
else aCoord.SetZ (aCorner[1].Z());
MyView->Projects(aCoord.X(), aCoord.Y(), aCoord.Z(), U, V, W);
if (i) {
Umin = Min(Umin, U); Umax = Max(Umax, U);
Vmin = Min(Vmin, V); Vmax = Max(Vmax, V);
}
else {
Umin = Umax = U;
Vmin = Vmax = V;
}
}
if ( (Umax > Umin) && (Vmax > Vmin) ) {
Standard_Real OldUmin,OldUmax,OldVmin,OldVmax;
MyViewMapping.WindowLimit(OldUmin, OldVmin, OldUmax, OldVmax);
Standard_Real DxvOld = Abs(OldUmax - OldUmin);
// make a margin
Standard_Real Xrp, Yrp, DxvNew, DyvNew;
DxvNew = Abs(Umax - Umin); DyvNew = Abs(Vmax - Vmin);
DxvNew *= (1. + theCoef);
DyvNew *= (1. + theCoef);
Standard_Real aRatio = DxvNew / DxvOld;
Xrp = (Umin + Umax)/2. ; Yrp = (Vmin + Vmax)/2. ;
Umin = Xrp - DxvNew/2. ; Umax = Xrp + DxvNew/2. ;
Vmin = Yrp - DyvNew/2. ; Vmax = Yrp + DyvNew/2. ;
// fit view
FitAll(Umin, Vmin, Umax, Vmax);
// ratio 1e+6 often gives calculation error(s), reduce it
// if (aRatio < 1e+6) doFit = Standard_False;
if (aRatio < 100) doFit = Standard_False;
aResult = Standard_True;
}
else doFit = Standard_False;
}
}
return aResult;
}
//=======================================================================
//function : GetBndBox
//purpose :
//=======================================================================
Bnd_B3f NIS_View::GetBndBox() const
{ {
// Calculate the 3D bounding box of visible objects // Calculate the 3D bounding box of visible objects
// in all interactive contexts // in all interactive contexts
@ -103,12 +198,6 @@ void NIS_View::FitAll3d ()
} }
} }
if (aBox.IsVoid()) {
// No NIS objects displays, run the compatible method of V3d_View
FitAll();
return;
}
// Take the bounding box of AIS objects displayed in the view // Take the bounding box of AIS objects displayed in the view
Standard_Real aVal[6]; Standard_Real aVal[6];
View()->MinMaxValues(aVal[0], aVal[1], aVal[2], aVal[3], aVal[4], aVal[5]); View()->MinMaxValues(aVal[0], aVal[1], aVal[2], aVal[3], aVal[4], aVal[5]);
@ -117,6 +206,22 @@ void NIS_View::FitAll3d ()
aBox.Add (gp_XYZ (aVal[3], aVal[4], aVal[5])); aBox.Add (gp_XYZ (aVal[3], aVal[4], aVal[5]));
} }
return aBox;
}
//=======================================================================
//function : GetBndBox
//purpose :
//=======================================================================
void NIS_View::GetBndBox( Standard_Integer& theXMin, Standard_Integer& theXMax,
Standard_Integer& theYMin, Standard_Integer& theYMax ) const
{
theXMin = theYMin = 0;
theXMax = theYMax = -1;
Bnd_B3f aBox = GetBndBox();
// Check that the box is not empty // Check that the box is not empty
if (aBox.IsVoid() == Standard_False) { if (aBox.IsVoid() == Standard_False) {
// Convert the 3D box to 2D representation in pixel coordinates // Convert the 3D box to 2D representation in pixel coordinates
@ -140,8 +245,11 @@ void NIS_View::FitAll3d ()
if (aLimp[0] < aLimp[1] && aLimp[2] < aLimp[3]) if (aLimp[0] < aLimp[1] && aLimp[2] < aLimp[3])
{ {
// Scale the view // Scale the view
WindowFit (aLimp[0], aLimp[2], aLimp[1], aLimp[3]); // WindowFit (aLimp[0], aLimp[2], aLimp[1], aLimp[3]);
return; theXMin = aLimp[0];
theXMax = aLimp[1];
theYMin = aLimp[2];
theYMax = aLimp[3];
} }
} }
} }
@ -200,7 +308,6 @@ int NIS_View::MyCallback (Aspect_Drawable /* Window ID */,
} }
#endif //IS_DISABLED #endif //IS_DISABLED
// glEnable(GL_COLOR_MATERIAL);
GLboolean isDepthWriteMask, isDepthTest; GLboolean isDepthWriteMask, isDepthTest;
glGetBooleanv(GL_DEPTH_WRITEMASK,&isDepthWriteMask); glGetBooleanv(GL_DEPTH_WRITEMASK,&isDepthWriteMask);
glGetBooleanv(GL_DEPTH_TEST,&isDepthTest); glGetBooleanv(GL_DEPTH_TEST,&isDepthTest);
@ -217,14 +324,40 @@ int NIS_View::MyCallback (Aspect_Drawable /* Window ID */,
glClear(GL_DEPTH_BUFFER_BIT); glClear(GL_DEPTH_BUFFER_BIT);
} }
TColStd_MapIteratorOfPackedMapOfInteger anIterM(thisView->myExListId);
for (; anIterM.More(); anIterM.Next())
if (anIterM.Key() != 0) {
#ifdef ARRAY_LISTS
glDeleteLists (anIterM.Key(), 5);
#else
glDeleteLists (anIterM.Key(), 1);
}
#endif
thisView->myExListId.Clear();
for (anIter = thisView->myContexts; anIter.More(); anIter.Next()) for (anIter = thisView->myContexts; anIter.More(); anIter.Next())
anIter.Value()->redraw (thisView, NIS_Drawer::Draw_Normal); anIter.Value()->redraw (thisView, NIS_Drawer::Draw_Normal);
for (anIter = thisView->myContexts; anIter.More(); anIter.Next())
anIter.Value()->redraw (thisView, NIS_Drawer::Draw_Transparent); // #818151 - selected object is hidden by covered unselected one
// display hilighted objects always above the rest ones
if (thisView->myIsTopHilight == Standard_True) {
glDepthFunc(GL_ALWAYS);
}
for (anIter = thisView->myContexts; anIter.More(); anIter.Next()) for (anIter = thisView->myContexts; anIter.More(); anIter.Next())
anIter.Value()->redraw (thisView, NIS_Drawer::Draw_Hilighted); anIter.Value()->redraw (thisView, NIS_Drawer::Draw_Hilighted);
for (anIter = thisView->myContexts; anIter.More(); anIter.Next()) for (anIter = thisView->myContexts; anIter.More(); anIter.Next())
anIter.Value()->redraw (thisView, NIS_Drawer::Draw_DynHilighted); anIter.Value()->redraw (thisView, NIS_Drawer::Draw_DynHilighted);
for (anIter = thisView->myContexts; anIter.More(); anIter.Next())
anIter.Value()->redraw (thisView, NIS_Drawer::Draw_Transparent);
// draw top objects always above
if (thisView->myIsTopHilight == Standard_False) {
glDepthFunc(GL_ALWAYS);
}
for (anIter = thisView->myContexts; anIter.More(); anIter.Next())
anIter.Value()->redraw (thisView, NIS_Drawer::Draw_Top);
return 0; return 0;
} }
@ -237,6 +370,7 @@ int NIS_View::MyCallback (Aspect_Drawable /* Window ID */,
void NIS_View::DynamicHilight (const Standard_Integer theX, void NIS_View::DynamicHilight (const Standard_Integer theX,
const Standard_Integer theY) const Standard_Integer theY)
{ {
myDetected.Clear();
const Handle(NIS_InteractiveObject) aSelected = Pick (theX, theY); const Handle(NIS_InteractiveObject) aSelected = Pick (theX, theY);
// ASV: if at least one Context returns IsSelectable()==False, // ASV: if at least one Context returns IsSelectable()==False,
@ -248,10 +382,17 @@ void NIS_View::DynamicHilight (const Standard_Integer theX,
if (aSelected != myDynHilighted) { if (aSelected != myDynHilighted) {
const Handle(NIS_View) aView (this); const Handle(NIS_View) aView (this);
if (myDynHilighted.IsNull() == Standard_False) if (myDynHilighted.IsNull() == Standard_False)
myDynHilighted->GetDrawer()->SetDynamicHilighted (Standard_False, if (myDynHilighted->GetDrawer().IsNull() == Standard_False)
myDynHilighted->GetDrawer()->SetDynamicHilighted(Standard_False,
myDynHilighted, aView); myDynHilighted, aView);
if (aSelected.IsNull())
// 30.07.10 - NKV - synchronize behaviour with AIS interactive context (if need)
if (aSelected.IsNull() ||
(myDoHilightSelected == Standard_False &&
aSelected->GetDrawer()->GetContext()->IsSelected(aSelected)))
{
myDynHilighted.Nullify(); myDynHilighted.Nullify();
}
else { else {
aSelected->GetDrawer()->SetDynamicHilighted (Standard_True, aSelected->GetDrawer()->SetDynamicHilighted (Standard_True,
aSelected, aView); aSelected, aView);
@ -270,6 +411,7 @@ void NIS_View::DynamicUnhilight(const Handle_NIS_InteractiveObject& theObj)
{ {
if (theObj == myDynHilighted && theObj.IsNull() == Standard_False) { if (theObj == myDynHilighted && theObj.IsNull() == Standard_False) {
const Handle(NIS_View) aView (this); const Handle(NIS_View) aView (this);
if (myDynHilighted->GetDrawer().IsNull() == Standard_False)
myDynHilighted->GetDrawer()->SetDynamicHilighted (Standard_False, myDynHilighted->GetDrawer()->SetDynamicHilighted (Standard_False,
myDynHilighted, aView); myDynHilighted, aView);
myDynHilighted.Nullify(); myDynHilighted.Nullify();
@ -284,8 +426,10 @@ void NIS_View::DynamicUnhilight(const Handle_NIS_InteractiveObject& theObj)
void NIS_View::Select (const Standard_Integer theX, void NIS_View::Select (const Standard_Integer theX,
const Standard_Integer theY, const Standard_Integer theY,
const Standard_Boolean isForceMultiple) const Standard_Boolean isForceMultiple,
const Standard_Boolean theRedraw)
{ {
myDetected.Clear();
const Handle(NIS_InteractiveObject) aSelected = Pick (theX, theY); const Handle(NIS_InteractiveObject) aSelected = Pick (theX, theY);
NCollection_List<NIS_InteractiveContext *>::Iterator anIter (myContexts); NCollection_List<NIS_InteractiveContext *>::Iterator anIter (myContexts);
for (; anIter.More(); anIter.Next()) for (; anIter.More(); anIter.Next())
@ -296,7 +440,7 @@ void NIS_View::Select (const Standard_Integer theX,
const Handle(NIS_Drawer)& aDrawer = aSelected->GetDrawer(); const Handle(NIS_Drawer)& aDrawer = aSelected->GetDrawer();
aDrawer->SetDynamicHilighted (Standard_False, aSelected, this); aDrawer->SetDynamicHilighted (Standard_False, aSelected, this);
} }
Redraw(); if (theRedraw) Redraw();
} }
//======================================================================= //=======================================================================
@ -309,8 +453,10 @@ void NIS_View::Select (const Standard_Integer theXmin,
const Standard_Integer theXmax, const Standard_Integer theXmax,
const Standard_Integer theYmax, const Standard_Integer theYmax,
const Standard_Boolean isForceMult, const Standard_Boolean isForceMult,
const Standard_Boolean isFullyIncluded) const Standard_Boolean isFullyIncluded,
const Standard_Boolean theRedraw)
{ {
myDetected.Clear();
Standard_Real anX, anY, aZ; Standard_Real anX, anY, aZ;
if (theXmin == theXmax || theYmin == theYmax) if (theXmin == theXmax || theYmin == theYmax)
return; return;
@ -346,18 +492,85 @@ void NIS_View::Select (const Standard_Integer theXmin,
pCtx->selectObjects (mapSelected, aBoxSel, aTrfInv, aTrf, isFullyIncluded); pCtx->selectObjects (mapSelected, aBoxSel, aTrfInv, aTrf, isFullyIncluded);
pCtx->ProcessSelection (mapSelected, isForceMult); pCtx->ProcessSelection (mapSelected, isForceMult);
} }
Redraw(); if (theRedraw) Redraw();
} }
//=======================================================================
//function : Select
//purpose : Selection by polygon
//=======================================================================
void NIS_View::Select (const NCollection_List<gp_XY> &thePolygon,
const Standard_Boolean isForceMult,
const Standard_Boolean isFullyIncluded,
const Standard_Boolean theRedraw)
{
myDetected.Clear();
if (thePolygon.IsEmpty())
return;
Standard_Real anX, anY, aZ;
//Transformed box corresponding to the selected rectangle
Proj (anX, anY, aZ); // vector orthogonal to the view plane
const gp_Dir aProj (anX, anY, aZ);
const gp_XY &aPf = thePolygon.First();
// 3D point for the 3D coordinates
Convert((Standard_Integer) aPf.X(), (Standard_Integer) aPf.Y(), anX, anY, aZ);
const gp_Pnt anEye (anX, anY, aZ);
// 3D point for the 3D coordinates
const gp_XY &aPl = thePolygon.Last();
Convert((Standard_Integer) aPl.X(), (Standard_Integer) aPl.Y(), anX, anY, aZ);
// Compute transformation.
const gp_XYZ anXdir (gp_XYZ(anX, anY, aZ) - anEye.XYZ());
const gp_Ax3 anAx3 (anEye, aProj, anXdir);
gp_Trsf aTrf;
aTrf.SetTransformation (anAx3);
const gp_Trsf aTrfInv = aTrf.Inverted();
// Prepare list of 2d points of selection polygon.
NCollection_List<gp_XY> aPoints;
NCollection_List<gp_XY>::Iterator anIter(thePolygon);
Bnd_B2f aPolyBox;
for (; anIter.More(); anIter.Next()) {
const gp_XY &aP = anIter.Value();
Convert((Standard_Integer) aP.X(), (Standard_Integer) aP.Y(), anX, anY, aZ);
gp_XYZ aP3d(anX, anY, aZ);
aTrf.Transforms(aP3d);
gp_XY aP2d(aP3d.X(), aP3d.Y());
aPoints.Append(aP2d);
aPolyBox.Add(aP2d);
}
TColStd_PackedMapOfInteger mapSelected;
NCollection_List<NIS_InteractiveContext *>::Iterator anIterC(myContexts);
for (; anIterC.More(); anIterC.Next()) {
NIS_InteractiveContext * pCtx = anIterC.Value();
mapSelected.Clear();
pCtx->selectObjects (mapSelected, aPoints, aPolyBox, aTrf, isFullyIncluded);
pCtx->ProcessSelection (mapSelected, isForceMult);
}
if (theRedraw) Redraw();
}
//======================================================================= //=======================================================================
//function : Pick //function : Pick
//purpose : //purpose :
//======================================================================= //=======================================================================
Handle_NIS_InteractiveObject NIS_View::Pick Handle_NIS_InteractiveObject NIS_View::Pick (const Standard_Integer theX,
(const Standard_Integer theX, const Standard_Integer theY)
const Standard_Integer theY) const
{ {
// Find the ray passing through the clicked point in the view window. // Find the ray passing through the clicked point in the view window.
Standard_Real anX, anY, aZ, anOver; Standard_Real anX, anY, aZ, anOver;
@ -381,20 +594,30 @@ Handle_NIS_InteractiveObject NIS_View::Pick
Handle_NIS_InteractiveObject NIS_View::Pick Handle_NIS_InteractiveObject NIS_View::Pick
(const gp_Ax1& theAxis, (const gp_Ax1& theAxis,
const Standard_Real theOver, const Standard_Real theOver,
const Standard_Boolean isOnlySelectable) const const Standard_Boolean isOnlySelectable)
{ {
typedef NCollection_List<NIS_InteractiveContext::DetectedEnt> LstDetected;
Standard_Real aDistance (0.1 * RealLast()); Standard_Real aDistance (0.1 * RealLast());
Handle(NIS_InteractiveObject) aSelected, aTmpSel; Handle(NIS_InteractiveObject) aSelected, aTmpSel;
LstDetected aDetected;
NCollection_List<NIS_InteractiveContext *>::Iterator anIterC (myContexts); NCollection_List<NIS_InteractiveContext *>::Iterator anIterC (myContexts);
for (; anIterC.More(); anIterC.Next()) { for (; anIterC.More(); anIterC.Next()) {
const Standard_Real aDist = const Standard_Real aDist =
anIterC.Value()->selectObject (aTmpSel, theAxis, theOver, anIterC.Value()->selectObject (aTmpSel, aDetected, theAxis, theOver,
isOnlySelectable); isOnlySelectable);
if (aDist < aDistance) { if (aDist < aDistance) {
aDistance = aDist; aDistance = aDist;
aSelected = aTmpSel; aSelected = aTmpSel;
} }
} }
// simple iterating is enough to create list of detected objects
// in the order of increasing distance
myDetected.Clear();
for (LstDetected::Iterator anIt(aDetected); anIt.More(); anIt.Next())
myDetected.Append(anIt.Value().PObj);
return aSelected; return aSelected;
} }

View File

@ -11,6 +11,10 @@
#include <V3d_OrthographicView.hxx> #include <V3d_OrthographicView.hxx>
#include <Standard_DefineHandle.hxx> #include <Standard_DefineHandle.hxx>
#include <NCollection_List.hxx> #include <NCollection_List.hxx>
#include <NCollection_Vector.hxx>
#include <Bnd_B3f.hxx>
#include <TColStd_PackedMapOfInteger.hxx>
#include <gp_XY.hxx>
class NIS_InteractiveContext; class NIS_InteractiveContext;
class gp_Ax1; class gp_Ax1;
@ -58,9 +62,49 @@ class NIS_View : public V3d_OrthographicView
Standard_EXPORT void SetWindow(const Handle_Aspect_Window &theWindow); Standard_EXPORT void SetWindow(const Handle_Aspect_Window &theWindow);
/** /**
* Zoom the view to fit to visible objects size and positions. * Indicate whether to draw hilighted objects on top of all other ones
*/ */
Standard_EXPORT void FitAll3d (); inline void SetHilightOnTop(const Standard_Boolean theTop = Standard_True)
{ myIsTopHilight = theTop; }
/**
* Indicate whether to hilight selected object dynamically
* By default dynamic hilight works on all objects independently on its
* selected/non-selected state.
* This behaviour differs from the behaviour of AIS interactive context,
* that doesn't hilight dynamically (on mouse movements) selected objects.
* In the case both context are used in the same view the behaviour of both
* context can be made consistent by setting this flag to False
*/
inline void SetDynHilightSelected (const Standard_Boolean
theHilight = Standard_True)
{ myDoHilightSelected = theHilight; }
/**
* Zoom the view to fit to visible objects size and positions.
* @param theCoef
* Relative margin in both X and Y dimensions. For example, value 1.0
* will fit to twice the actual size.
* @return
* True if operation performed, False if failed (most likely because of
* very big actual scale)
*/
Standard_EXPORT Standard_Boolean FitAll3d (const Quantity_Coefficient theCoef
= 0.01);
/**
* Gets bounding box covering objects displayed in viewer.
*/
Standard_EXPORT Bnd_B3f GetBndBox() const;
/**
* Gets bounding box covering objects displayed in viewer.
* If operation is fails when Xmax < Xmin abd Ymax < Ymin
*/
Standard_EXPORT void GetBndBox(Standard_Integer& theXMin,
Standard_Integer& theXMax,
Standard_Integer& theYMin,
Standard_Integer& theYMax ) const;
// /** // /**
// * Destructor. // * Destructor.
@ -80,21 +124,30 @@ class NIS_View : public V3d_OrthographicView
*/ */
Standard_EXPORT void DynamicUnhilight(const Handle_NIS_InteractiveObject&); Standard_EXPORT void DynamicUnhilight(const Handle_NIS_InteractiveObject&);
/**
* Unhilights the currently hilighted object.
*/
inline void DynamicUnhilight() { DynamicUnhilight(myDynHilighted); }
/** /**
* Set or unset the selected (hilighted) state of the object that is under * Set or unset the selected (hilighted) state of the object that is under
* the coordinates theX, theY. * the coordinates theX, theY.
* @param theX * @param theX
* X coordinate of the view window * X coordinate of the view window
* @param theX * @param theY
* X coordinate of the view window * X coordinate of the view window
* @param isForceMult * @param isForceMult
* True if the effect of multi-Selection should be forced (e.g., when Shift * True if the effect of multi-Selection should be forced (e.g., when Shift
* is pressed). * is pressed).
* @param theRedraw
* True to redraw view automatically (default value).
*/ */
Standard_EXPORT void Select (const Standard_Integer theX, Standard_EXPORT void Select (const Standard_Integer theX,
const Standard_Integer theY, const Standard_Integer theY,
const Standard_Boolean isForceMult const Standard_Boolean isForceMult
= Standard_False); = Standard_False,
const Standard_Boolean theRedraw
= Standard_True);
/** /**
* Set or unset the selected (hilighted) state of the objects that are * Set or unset the selected (hilighted) state of the objects that are
@ -114,6 +167,8 @@ class NIS_View : public V3d_OrthographicView
* True if only those objects are processed that are fully inside the * True if only those objects are processed that are fully inside the
* selection rectangle. False if objects fully or partially included in * selection rectangle. False if objects fully or partially included in
* the rectangle are processed. * the rectangle are processed.
* @param theRedraw
* True to redraw view automatically (default value).
*/ */
Standard_EXPORT void Select (const Standard_Integer theXmin, Standard_EXPORT void Select (const Standard_Integer theXmin,
const Standard_Integer theYmin, const Standard_Integer theYmin,
@ -122,7 +177,35 @@ class NIS_View : public V3d_OrthographicView
const Standard_Boolean isForceMult const Standard_Boolean isForceMult
= Standard_False, = Standard_False,
const Standard_Boolean isFullyIncluded const Standard_Boolean isFullyIncluded
= Standard_False); = Standard_False,
const Standard_Boolean theRedraw
= Standard_True);
/**
* Set or unset the selected (hilighted) state of the objects that are
* intersected by 2D polygon in the view
* @param thePolygon
* defines the vertices of a free-form closed polygon without
* self-intersections. The last point should not coincide with the first
* point of the list. Points are interpreted as X and Y integer coordinates
* of the view window. Any two neighbor points should not be confused.
* @param isForceMult
* True if the effect of multi-Selection should be forced (e.g., when Shift
* is pressed).
* @param isFullyIncluded
* True if only those objects are processed that are fully inside the
* selection rectangle. False if objects fully or partially included in
* the rectangle are processed.
* @param theRedraw
* True to redraw view automatically (default value).
*/
Standard_EXPORT void Select (const NCollection_List<gp_XY> &thePolygon,
const Standard_Boolean isForceMult
= Standard_False,
const Standard_Boolean isFullyIncluded
= Standard_False,
const Standard_Boolean theRedraw
= Standard_True);
/** /**
* Interactive selection by mouse click. Selection itself is performed in each * Interactive selection by mouse click. Selection itself is performed in each
@ -138,7 +221,7 @@ class NIS_View : public V3d_OrthographicView
*/ */
Standard_EXPORT Handle_NIS_InteractiveObject Standard_EXPORT Handle_NIS_InteractiveObject
Pick (const Standard_Integer theX, Pick (const Standard_Integer theX,
const Standard_Integer theY) const; const Standard_Integer theY);
/** /**
* Interactive selection by mouse click. Selection itself is performed in each * Interactive selection by mouse click. Selection itself is performed in each
@ -148,7 +231,7 @@ class NIS_View : public V3d_OrthographicView
* 3D axis for objects selection * 3D axis for objects selection
* @param theOver * @param theOver
* Overlap for the selecting axis * Overlap for the selecting axis
* @param isOnlySelectable * @param isOnlySel
* If False, any displayed object can be picked, otherwise only selectable * If False, any displayed object can be picked, otherwise only selectable
* ones. * ones.
* @return * @return
@ -158,7 +241,19 @@ class NIS_View : public V3d_OrthographicView
Standard_EXPORT Handle_NIS_InteractiveObject Standard_EXPORT Handle_NIS_InteractiveObject
Pick (const gp_Ax1& theAxis, Pick (const gp_Ax1& theAxis,
const Standard_Real theOver, const Standard_Real theOver,
const Standard_Boolean isOnlySelectable) const; const Standard_Boolean isOnlySel);
/**
* Gets all objects detected by last call of Pick() method
*/
inline NCollection_Vector<NIS_InteractiveObject *> GetDetected() const
{ return myDetected; }
/**
* Obtain the IDs of ex-lists.
*/
inline TColStd_PackedMapOfInteger& GetExListId ()
{ return myExListId; }
protected: protected:
// ---------- PROTECTED METHODS ---------- // ---------- PROTECTED METHODS ----------
@ -182,6 +277,10 @@ class NIS_View : public V3d_OrthographicView
NCollection_List<NIS_InteractiveContext *> myContexts; NCollection_List<NIS_InteractiveContext *> myContexts;
Handle_NIS_InteractiveObject myDynHilighted; Handle_NIS_InteractiveObject myDynHilighted;
Standard_Boolean myIsTopHilight : 1;
Standard_Boolean myDoHilightSelected : 1;
NCollection_Vector<NIS_InteractiveObject *> myDetected;
TColStd_PackedMapOfInteger myExListId;
friend class NIS_InteractiveContext; friend class NIS_InteractiveContext;

View File

@ -438,12 +438,12 @@ void ViewerTest::Clear()
} else if (it.Key1()->IsKind(STANDARD_TYPE(NIS_InteractiveObject))) { } else if (it.Key1()->IsKind(STANDARD_TYPE(NIS_InteractiveObject))) {
const Handle(NIS_InteractiveObject) anObj = const Handle(NIS_InteractiveObject) anObj =
Handle(NIS_InteractiveObject)::DownCast (it.Key1()); Handle(NIS_InteractiveObject)::DownCast (it.Key1());
TheNISContext()->Remove(anObj,Standard_False); TheNISContext()->Remove(anObj);
} }
it.Next(); it.Next();
} }
TheAISContext()->UpdateCurrentViewer(); TheAISContext()->UpdateCurrentViewer();
TheNISContext()->UpdateViews(); // TheNISContext()->UpdateViews();
GetMapOfAIS().Clear(); GetMapOfAIS().Clear();
} }
} }
@ -1391,7 +1391,7 @@ static int VDonly2(Draw_Interpretor& , Standard_Integer argc, const char** argv)
} else if (it.Key1()->IsKind(STANDARD_TYPE(NIS_InteractiveObject))) { } else if (it.Key1()->IsKind(STANDARD_TYPE(NIS_InteractiveObject))) {
const Handle(NIS_InteractiveObject) aShape = const Handle(NIS_InteractiveObject) aShape =
Handle(NIS_InteractiveObject)::DownCast(it.Key1()); Handle(NIS_InteractiveObject)::DownCast(it.Key1());
TheNISContext()->Erase(aShape,Standard_False); TheNISContext()->Erase(aShape);
} }
it.Next(); it.Next();
} }
@ -1407,14 +1407,14 @@ static int VDonly2(Draw_Interpretor& , Standard_Integer argc, const char** argv)
Handle(AIS_InteractiveObject)::DownCast (anObj); Handle(AIS_InteractiveObject)::DownCast (anObj);
TheAISContext()->Display(aShape, Standard_False); TheAISContext()->Display(aShape, Standard_False);
} else if (anObj->IsKind(STANDARD_TYPE(NIS_InteractiveObject))) { } else if (anObj->IsKind(STANDARD_TYPE(NIS_InteractiveObject))) {
const Handle(NIS_InteractiveObject) aShape = Handle(NIS_InteractiveObject) aShape =
Handle(NIS_InteractiveObject)::DownCast (anObj); Handle(NIS_InteractiveObject)::DownCast (anObj);
TheNISContext()->Display(aShape, 0L, Standard_False); TheNISContext()->Display(aShape);
} }
} }
} }
TheAISContext() ->UpdateCurrentViewer(); TheAISContext() ->UpdateCurrentViewer();
TheNISContext() ->UpdateViews(); // TheNISContext() ->UpdateViews();
} }
return 0; return 0;
} }
@ -1473,12 +1473,12 @@ static int VErase2(Draw_Interpretor& , Standard_Integer argc, const char** arg
} else if (it.Key1()->IsKind(STANDARD_TYPE(NIS_InteractiveObject))) { } else if (it.Key1()->IsKind(STANDARD_TYPE(NIS_InteractiveObject))) {
const Handle(NIS_InteractiveObject) aShape = const Handle(NIS_InteractiveObject) aShape =
Handle(NIS_InteractiveObject)::DownCast(it.Key1()); Handle(NIS_InteractiveObject)::DownCast(it.Key1());
TheNISContext()->Erase(aShape,Standard_False); TheNISContext()->Erase(aShape);
} }
it.Next(); it.Next();
} }
TheAISContext() ->UpdateCurrentViewer(); TheAISContext() ->UpdateCurrentViewer();
TheNISContext()->UpdateViews(); // TheNISContext()->UpdateViews();
} }
//=============================================================== //===============================================================
@ -1497,12 +1497,12 @@ static int VErase2(Draw_Interpretor& , Standard_Integer argc, const char** arg
} else if (anObj->IsKind(STANDARD_TYPE(NIS_InteractiveObject))) { } else if (anObj->IsKind(STANDARD_TYPE(NIS_InteractiveObject))) {
const Handle(NIS_InteractiveObject) aShape = const Handle(NIS_InteractiveObject) aShape =
Handle(NIS_InteractiveObject)::DownCast (anObj); Handle(NIS_InteractiveObject)::DownCast (anObj);
TheNISContext()->Erase(aShape,Standard_False); TheNISContext()->Erase(aShape);
} }
} }
} }
TheAISContext() ->UpdateCurrentViewer(); TheAISContext() ->UpdateCurrentViewer();
TheNISContext() ->UpdateViews(); // TheNISContext() ->UpdateViews();
} }
return 0; return 0;
} }
@ -1530,12 +1530,12 @@ static int VEraseAll(Draw_Interpretor& di, Standard_Integer argc, const char** a
} else if (it.Key1()->IsKind(STANDARD_TYPE(NIS_InteractiveObject))) { } else if (it.Key1()->IsKind(STANDARD_TYPE(NIS_InteractiveObject))) {
const Handle(NIS_InteractiveObject) aShape = const Handle(NIS_InteractiveObject) aShape =
Handle(NIS_InteractiveObject)::DownCast(it.Key1()); Handle(NIS_InteractiveObject)::DownCast(it.Key1());
TheNISContext()->Erase(aShape,Standard_False); TheNISContext()->Erase(aShape);
} }
it.Next(); it.Next();
} }
TheAISContext() ->UpdateCurrentViewer(); TheAISContext() ->UpdateCurrentViewer();
TheNISContext() ->UpdateViews(); // TheNISContext() ->UpdateViews();
return 0; return 0;
} }
@ -1563,7 +1563,7 @@ static int VDisplayAll( Draw_Interpretor& di, Standard_Integer argc, const char*
} else if (it.Key1()->IsKind(STANDARD_TYPE(NIS_InteractiveObject))) { } else if (it.Key1()->IsKind(STANDARD_TYPE(NIS_InteractiveObject))) {
const Handle(NIS_InteractiveObject) aShape = const Handle(NIS_InteractiveObject) aShape =
Handle(NIS_InteractiveObject)::DownCast(it.Key1()); Handle(NIS_InteractiveObject)::DownCast(it.Key1());
TheNISContext()->Erase(aShape,Standard_False); TheNISContext()->Erase(aShape);
} }
it.Next(); it.Next();
} }
@ -1574,14 +1574,14 @@ static int VDisplayAll( Draw_Interpretor& di, Standard_Integer argc, const char*
Handle(AIS_InteractiveObject)::DownCast(it.Key1()); Handle(AIS_InteractiveObject)::DownCast(it.Key1());
TheAISContext()->Display(aShape, Standard_False); TheAISContext()->Display(aShape, Standard_False);
} else if (it.Key1()->IsKind(STANDARD_TYPE(NIS_InteractiveObject))) { } else if (it.Key1()->IsKind(STANDARD_TYPE(NIS_InteractiveObject))) {
const Handle(NIS_InteractiveObject) aShape = Handle(NIS_InteractiveObject) aShape =
Handle(NIS_InteractiveObject)::DownCast(it.Key1()); Handle(NIS_InteractiveObject)::DownCast(it.Key1());
TheNISContext()->Display(aShape, 0L, Standard_False); TheNISContext()->Display(aShape);
} }
it.Next(); it.Next();
} }
TheAISContext() ->UpdateCurrentViewer(); TheAISContext() ->UpdateCurrentViewer();
TheNISContext() ->UpdateViews(); // TheNISContext() ->UpdateViews();
} }
return 0; return 0;
} }
@ -1865,7 +1865,7 @@ static int VDisplay2 (Draw_Interpretor& di, Standard_Integer argc, const char**
} else if (anObj->IsKind(STANDARD_TYPE(NIS_InteractiveObject))) { } else if (anObj->IsKind(STANDARD_TYPE(NIS_InteractiveObject))) {
Handle(NIS_InteractiveObject) aShape = Handle(NIS_InteractiveObject) aShape =
Handle(NIS_InteractiveObject)::DownCast(anObj); Handle(NIS_InteractiveObject)::DownCast(anObj);
TheNISContext()->Display(aShape, 0L, Standard_False); TheNISContext()->Display(aShape);
} }
} }
else { // Create the AIS_Shape from a name else { // Create the AIS_Shape from a name
@ -1879,7 +1879,7 @@ static int VDisplay2 (Draw_Interpretor& di, Standard_Integer argc, const char**
} }
// Upadate the screen and redraw the view // Upadate the screen and redraw the view
TheAISContext()->UpdateCurrentViewer(); TheAISContext()->UpdateCurrentViewer();
TheNISContext()->UpdateViews(); // TheNISContext()->UpdateViews();
return 0; return 0;
} }