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
FILES
NIS_Allocator.cxx
NIS_Allocator.hxx
NIS_Drawer.cxx
NIS_Drawer.hxx
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
#include <NIS_Drawer.hxx>
#include <NIS_View.hxx>
#ifdef WNT
#include <windows.h>
@ -16,12 +17,21 @@
//=======================================================================
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[1] = Standard_True;
myIsUpdated[2] = 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)
: myView (theView),
myListID (0)
: myView (theView)
{
#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[1] = Standard_True;
myIsUpdated[2] = 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 ()
{
if (myListID != 0)
glDeleteLists (myListID, 4);
//if (myListID != 0)
//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)
{
#ifdef ARRAY_LISTS
if (myListID == 0)
myListID = glGenLists(4);
glNewList (GetListID (theType), GL_COMPILE);
myListID = glGenLists(5);
#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)
{
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,
const Standard_Boolean theFlag)
{
if ( theFlag )
SetUpdated( theType );
if (theFlag)
SetUpdated(theType);
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>
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
@ -43,8 +52,26 @@ class NIS_DrawList
* @param theType
* Integer value coinciding with the enumerated NIS_Drawer:DrawType.
*/
inline Standard_Integer GetListID (const Standard_Integer theType)
{ return myListID + (theType&0x3); }
inline Standard_Integer GetListID (const Standard_Integer theType) const
#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
@ -74,14 +101,13 @@ class NIS_DrawList
* @param theType
* Integer value coinciding with the enumerated NIS_Drawer::DrawType.
*/
inline Standard_Boolean IsUpdated (const Standard_Integer theType)
{ return myIsUpdated [theType&0x3]; }
inline Standard_Boolean IsUpdated (const Standard_Integer theType) const
{ return myIsUpdated [theType]; }
/**
* Set the flag indicating that the List should be updated (rebuilt).
*/
inline void SetUpdated (const Standard_Integer theType)
{ myIsUpdated [theType&0x3] = Standard_True; }
Standard_EXPORT void SetUpdated (const Standard_Integer theType);
/**
* 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,
const Standard_Boolean);
#ifdef ARRAY_LISTS
inline void SetListID (const Standard_Integer theID)
{ myListID = theID; }
#endif
private:
// ---------- PRIVATE METHODS (PROHIBITED) ----------
@ -122,8 +148,12 @@ class NIS_DrawList
// ---------- PRIVATE FIELDS ----------
Handle_NIS_View myView;
#ifdef ARRAY_LISTS
Standard_Integer myListID;
Standard_Boolean myIsUpdated[4];
#else
Standard_Integer myListID[5];
#endif
Standard_Boolean myIsUpdated[5];
NCollection_List<Handle_NIS_InteractiveObject> myDynHilighted;
};

View File

@ -4,6 +4,7 @@
// Copyright: Open Cascade 2007
#include <NIS_Drawer.hxx>
#include <NIS_View.hxx>
#include <NIS_InteractiveContext.hxx>
#include <NIS_InteractiveObject.hxx>
#include <TColStd_MapIteratorOfPackedMapOfInteger.hxx>
@ -34,6 +35,9 @@ void NIS_Drawer::Assign (const Handle_NIS_Drawer& theOther)
{
if (theOther->IsKind(DynamicType()) == Standard_False)
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
{
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);
if (theOther.IsNull() == Standard_False)
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;
}
@ -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
//purpose :
@ -93,13 +135,25 @@ void NIS_Drawer::redraw (const DrawType theType,
NCollection_List<NIS_DrawList*>::Iterator anIter (myLists);
for (; anIter.More(); anIter.Next()) {
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)) {
// 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);
prepareList (theType, aDrawList);
prepareList (theType, aDrawList, mapObj);
aDrawList.EndPrepare(theType);
}
aDrawList.Call(theType);
if (aDrawList.GetListID(theType) > 0)
aDrawList.Call(theType);
break;
}
}
@ -158,6 +212,28 @@ void NIS_Drawer::SetUpdated (const DrawType theType1,
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
//purpose :
@ -180,7 +256,8 @@ void NIS_Drawer::SetDynamicHilighted
} else
for (; anIter.More(); anIter.Next()) {
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);
theObj->myIsDynHilighted = isHilighted;
aDrawList.SetUpdated (Draw_DynHilighted);
@ -195,15 +272,18 @@ void NIS_Drawer::SetDynamicHilighted
//=======================================================================
void NIS_Drawer::removeObject (const NIS_InteractiveObject * theObj,
const Standard_Boolean isUpdateViews)
const Standard_Boolean isUpdateViews)
{
const Standard_Integer anID = theObj->ID();
myMapID.Remove (anID);
// Stop dynamic hilighting if it has been activated
if (theObj->IsDynHilighted())
SetDynamicHilighted (Standard_False, theObj);
if (myMapID.IsEmpty()) {
UpdateExListId(NULL);
}
// Set Updated for the draw type.
if (theObj->IsHidden() == Standard_False && isUpdateViews)
else if (theObj->IsHidden() == Standard_False && isUpdateViews)
SetUpdated (theObj->DrawType());
}
@ -213,6 +293,7 @@ void NIS_Drawer::removeObject (const NIS_InteractiveObject * theObj,
//=======================================================================
void NIS_Drawer::addObject (const NIS_InteractiveObject * theObj,
const Standard_Boolean isShareList,
const Standard_Boolean isUpdateViews)
{
myMapID.Add (theObj->ID());
@ -220,9 +301,13 @@ void NIS_Drawer::addObject (const NIS_InteractiveObject * theObj,
// Fill the drawer (if new) with DrawList instances for available Views.
if ( myLists.IsEmpty())
{
NCollection_List<Handle_NIS_View>::Iterator anIter (GetContext()->myViews);
for (; anIter.More(); anIter.Next())
myLists.Append (createDefaultList(anIter.Value()));
if (isShareList)
myLists.Append (createDefaultList(NULL));
else {
NCollection_List<Handle_NIS_View>::Iterator anIter(GetContext()->myViews);
for (; anIter.More(); anIter.Next())
myLists.Append (createDefaultList(anIter.Value()));
}
}
if (theObj->IsHidden() == Standard_False && isUpdateViews)
@ -245,7 +330,8 @@ const Bnd_B3f& NIS_Drawer::GetBox (const NIS_View * pView) const
NCollection_List<NIS_DrawList*>::Iterator anIterL (myLists);
for (; anIterL.More(); anIterL.Next()) {
NIS_DrawList& aDrawList = * anIterL.ChangeValue();
if (aDrawList.GetView().operator->() == pView)
const Handle(NIS_View)& aView = aDrawList.GetView();
if (aView.IsNull() || aView.operator->() == pView)
break;
}
if (anIterL.More())
@ -269,8 +355,9 @@ const Bnd_B3f& NIS_Drawer::GetBox (const NIS_View * pView) const
//function : prepareList
//purpose :
//=======================================================================
void NIS_Drawer::prepareList( const NIS_Drawer::DrawType theType,
const NIS_DrawList& theDrawList )
void NIS_Drawer::prepareList(const NIS_Drawer::DrawType theType,
const NIS_DrawList& theDrawList,
const TColStd_PackedMapOfInteger& mapObj)
{
if (!myCtx)
return;
@ -280,17 +367,15 @@ void NIS_Drawer::prepareList( const NIS_Drawer::DrawType theType,
if (theType == NIS_Drawer::Draw_DynHilighted) {
NCollection_List<Handle_NIS_InteractiveObject>::Iterator
anIter (theDrawList.DynHilightedList());
for (; anIter.More(); anIter.Next())
{
if (anIter.More()) {
BeforeDraw (theType, theDrawList);
Draw (anIter.Value(), NIS_Drawer::Draw_DynHilighted, theDrawList);
for (; anIter.More(); anIter.Next())
Draw (anIter.Value(), NIS_Drawer::Draw_DynHilighted, theDrawList);
AfterDraw (theType, theDrawList);
}
} else {
// The common part of two maps (objects for this draw type & objects in
// the current Drawer) is used for updating the presentation.
TColStd_PackedMapOfInteger mapObj;
mapObj.Intersection (myCtx->myMapObjects[theType&0x3], myMapID);
TColStd_MapIteratorOfPackedMapOfInteger anIter (mapObj);
if (anIter.More()) {
BeforeDraw (theType, theDrawList);
@ -313,5 +398,5 @@ void NIS_Drawer::prepareList( const NIS_Drawer::DrawType theType,
NIS_DrawList* NIS_Drawer::createDefaultList
(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;
/**
* 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
{
public:
#if (_MSC_VER < 1400)
enum DrawType {
#if defined(WNT) && (_MSC_VER >= 1400)
enum DrawType : unsigned int {
#else
enum DrawType : unsigned int {
enum DrawType {
#endif
Draw_Normal = 0,
Draw_Transparent = 1,
Draw_Hilighted = 2,
Draw_DynHilighted = 3
Draw_Top = 1,
Draw_Transparent = 2,
Draw_Hilighted = 3,
Draw_DynHilighted = 4
};
public:
@ -52,7 +122,12 @@ class NIS_Drawer : public Standard_Transient
/**
* Empty constructor.
*/
inline NIS_Drawer () : myCtx (0L) {}
inline NIS_Drawer ()
: myTransparency (0.f),
myIniId (0),
myObjPerDrawer (1024),
myCtx (0L)
{}
/**
* Destructor.
@ -91,6 +166,11 @@ class NIS_Drawer : public Standard_Transient
const DrawType theType2,
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
* given view.
@ -126,7 +206,20 @@ class NIS_Drawer : public Standard_Transient
ObjectIterator () const
{ return TColStd_MapIteratorOfPackedMapOfInteger (myMapID); }
/**
* Query associated draw lists.
*/
inline NCollection_List<NIS_DrawList *>
GetLists() const
{ return myLists; }
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 ----------
/**
@ -154,7 +247,8 @@ protected:
const Handle_NIS_View& theView);
Standard_EXPORT void addObject (const NIS_InteractiveObject * theObj,
const Standard_Boolean isUpVws);
const Standard_Boolean isShareList,
const Standard_Boolean isUpVws);
Standard_EXPORT void removeObject (const NIS_InteractiveObject * theObj,
const Standard_Boolean isUpVws);
@ -162,6 +256,11 @@ protected:
Standard_EXPORT virtual NIS_DrawList*
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 (PROHIBITED) METHODS ----------
@ -169,12 +268,21 @@ protected:
NIS_Drawer& operator = (const NIS_Drawer& theOther);
// ---------- PRIVATE METHODS ----------
void prepareList (const NIS_Drawer::DrawType theType,
const NIS_DrawList& theDrawLst);
void prepareList (const NIS_Drawer::DrawType theType,
const NIS_DrawList& theDrawLst,
const TColStd_PackedMapOfInteger& mapObj);
protected:
// ---------- PROTECTED FIELDS ----------
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 FIELDS ----------
@ -185,6 +293,7 @@ protected:
friend class NIS_InteractiveContext;
friend class NIS_InteractiveObject;
friend class NIS_View;
public:
// Declaration of CASCADE RTTI

View File

@ -8,16 +8,12 @@
#include <NIS_View.hxx>
#include <TColStd_MapIteratorOfPackedMapOfInteger.hxx>
#include <Standard_NoSuchObject.hxx>
#include <Bnd_B2f.hxx>
IMPLEMENT_STANDARD_HANDLE (NIS_InteractiveContext, Standard_Transient)
IMPLEMENT_STANDARD_RTTIEXT (NIS_InteractiveContext, Standard_Transient)
static void deselectObj (const Handle(NIS_InteractiveObject)&,
const Standard_Integer,
TColStd_PackedMapOfInteger *);
static void selectObj (const Handle(NIS_InteractiveObject)&,
const Standard_Integer,
TColStd_PackedMapOfInteger *);
static void markAllDrawersUpdated (const NCollection_Map<Handle_NIS_Drawer>&);
//=======================================================================
//function : NIS_InteractiveContext()
@ -25,8 +21,10 @@ static void selectObj (const Handle(NIS_InteractiveObject)&,
//=======================================================================
NIS_InteractiveContext::NIS_InteractiveContext ()
: mySelectionMode (Mode_NoSelection),
myAllocator (new NCollection_IncAllocator)
: myAllocator (new NIS_Allocator(1024*100)),
// myDrawers (101, myAllocator),
mySelectionMode (Mode_NoSelection),
myIsShareDrawList (Standard_True)
{
// ID == 0 is invalid so we reserve this item from subsequent allocation.
myObjects.Append (NULL);
@ -143,42 +141,42 @@ void NIS_InteractiveContext::GetBox (Bnd_B3f& theBox,
//=======================================================================
void NIS_InteractiveContext::Display
(const Handle_NIS_InteractiveObject& theObj,
const Handle_NIS_Drawer& theDrawer,
const Standard_Boolean isUpdateViews)
(Handle_NIS_InteractiveObject& theObj,
const Handle_NIS_Drawer& theDrawer,
const Standard_Boolean isUpdateViews)
{
if (theObj.IsNull())
return;
Standard_Integer anID = theObj->ID();
Handle(NIS_Drawer) aDrawer = theDrawer;
if (aDrawer.IsNull() == Standard_False) {
if (aDrawer->myCtx != this)
Standard_NoSuchObject::Raise ("NIS_InteractiveContext::Display (0)");
} else {
aDrawer = theObj->GetDrawer();
if (aDrawer.IsNull()) {
aDrawer = theObj->DefaultDrawer();
aDrawer->myCtx = this;
}
}
if (anID == 0) {
// Create a new ID for this object
theObj->myID = myObjects.Length();
myObjects.Append (theObj);
myMapObjects[NIS_Drawer::Draw_Normal].Add(theObj->myID);
}
aDrawer = theObj->SetDrawer (aDrawer);
// Display Object as Normal or Transparent if it has been hidden
objectForDisplay(theObj, theObj->DrawType());
const Handle(NIS_Drawer)& aDrawer = drawerForDisplay(theObj, theDrawer);
// Display Object as Normal or Transparent if it has been hidden
if (theObj->IsHidden())
theObj->myIsHidden = Standard_False;
// Set Update flag in the Drawer
if (isUpdateViews)
aDrawer->SetUpdated (theObj->DrawType());
}
//=======================================================================
//function : DisplayOnTop
//purpose :
//=======================================================================
void NIS_InteractiveContext::DisplayOnTop
(Handle_NIS_InteractiveObject& theObj,
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
if (theObj->IsHidden())
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
if (isUpdateViews)
@ -221,6 +219,8 @@ void NIS_InteractiveContext::Remove (const Handle_NIS_InteractiveObject& theObj,
{
if (theObj.IsNull() == Standard_False) {
const Handle(NIS_Drawer)& aDrawer = theObj->GetDrawer();
if ( aDrawer.IsNull() )
return;
if (aDrawer->myCtx == this) {
// Remove the hilighting if the object has been hilighted
if (theObj->IsDynHilighted()) {
@ -229,10 +229,10 @@ void NIS_InteractiveContext::Remove (const Handle_NIS_InteractiveObject& theObj,
if (anIterV.Value().IsNull() == Standard_False)
anIterV.Value()->DynamicUnhilight (theObj);
}
// Remove the obejct from the context
// Remove the object from the context
const Standard_Integer anID = theObj->ID();
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);
theObj->myID = 0;
theObj->myDrawer.Nullify();
@ -246,7 +246,7 @@ void NIS_InteractiveContext::Remove (const Handle_NIS_InteractiveObject& theObj,
//purpose :
//=======================================================================
void NIS_InteractiveContext::DisplayAll (const Standard_Boolean isUpdateViews)
void NIS_InteractiveContext::DisplayAll ()
{
// UnHide all objects in the Context
NCollection_Vector <Handle_NIS_InteractiveObject>::Iterator anIter(myObjects);
@ -258,15 +258,14 @@ void NIS_InteractiveContext::DisplayAll (const Standard_Boolean isUpdateViews)
}
// Update status of objects in Drawers (particularly cancel dyn. hilighting)
if (isUpdateViews) {
NCollection_Map<Handle_NIS_Drawer>::Iterator anIterD (myDrawers);
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_Transparent,
NIS_Drawer::Draw_Hilighted);
}
NCollection_Map<Handle_NIS_Drawer>::Iterator anIterD (myDrawers);
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);
}
}
}
@ -276,7 +275,7 @@ void NIS_InteractiveContext::DisplayAll (const Standard_Boolean isUpdateViews)
//purpose :
//=======================================================================
void NIS_InteractiveContext::EraseAll (const Standard_Boolean isUpdateViews)
void NIS_InteractiveContext::EraseAll ()
{
// Hide all objects in the Context
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()) {
const Handle(NIS_Drawer)& aDrawer = anIterD.Value();
if (aDrawer.IsNull() == Standard_False) {
if (isUpdateViews)
aDrawer->SetUpdated (NIS_Drawer::Draw_Normal,
NIS_Drawer::Draw_Transparent,
NIS_Drawer::Draw_Hilighted);
aDrawer->SetUpdated (NIS_Drawer::Draw_Normal,
NIS_Drawer::Draw_Top,
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();
// }
}
}
}
@ -316,7 +316,7 @@ void NIS_InteractiveContext::EraseAll (const Standard_Boolean isUpdateViews)
//purpose :
//=======================================================================
void NIS_InteractiveContext::RemoveAll (const Standard_Boolean isUpdateViews)
void NIS_InteractiveContext::RemoveAll ()
{
// Remove objects from the Context
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);
for (; anIterD.More(); anIterD.Next()) {
const Handle(NIS_Drawer)& aDrawer = anIterD.Value();
if (aDrawer.IsNull() == Standard_False) {
aDrawer->myMapID.Clear();
if (isUpdateViews)
aDrawer->SetUpdated (NIS_Drawer::Draw_Normal,
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();
// }
aDrawer->UpdateExListId(NULL);
aDrawer->myLists.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
//purpose :
//purpose : Only repaint the views refreshing their presentations only for
// those drawers that have been marked as updated.
//=======================================================================
void NIS_InteractiveContext::UpdateViews ()
{
NCollection_Map<Handle_NIS_Drawer>::Iterator anIterD (myDrawers);
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_Transparent,
NIS_Drawer::Draw_Hilighted);
// aList.myIsUpdated[NIS_Drawer::Draw_DynHilighted] =
// (aList.myDynHilighted.IsEmpty() == Standard_False);
}
}
NCollection_List<Handle_NIS_View>::Iterator anIterV (myViews);
const Handle_NIS_Allocator aNewAlloc = compactObjects();
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)
@ -393,13 +421,13 @@ Standard_Boolean NIS_InteractiveContext::SetSelected
const Standard_Integer anID = theObj->ID();
if (isSelected == Standard_False) {
if (myMapObjects[NIS_Drawer::Draw_Hilighted].Remove(anID)) {
deselectObj (theObj, anID, &myMapObjects[0]);
deselectObj (theObj, anID);
aResult = Standard_True;
}
} else {
if (IsSelectable(anID) == Standard_True) {
if (myMapObjects[NIS_Drawer::Draw_Hilighted].Add(anID)) {
selectObj (theObj, anID, &myMapObjects[0]);
selectObj (theObj, anID);
aResult = Standard_True;
}
}
@ -421,8 +449,13 @@ Standard_Boolean NIS_InteractiveContext::ProcessSelection
Standard_Integer anID (0);
Standard_Boolean wasSelected (Standard_False);
if (theObj.IsNull() == Standard_False) {
anID = theObj->ID();
wasSelected = myMapObjects[NIS_Drawer::Draw_Hilighted].Contains (anID);
const Handle(NIS_Drawer)& aDrawer = theObj->GetDrawer();
if (aDrawer.IsNull() == Standard_False) {
if (aDrawer->GetContext() == this) {
anID = theObj->ID();
wasSelected = myMapObjects[NIS_Drawer::Draw_Hilighted].Contains (anID);
}
}
}
switch (mySelectionMode) {
@ -433,20 +466,20 @@ Standard_Boolean NIS_InteractiveContext::ProcessSelection
aResult = Standard_True;
} else if (wasSelected && mySelectionMode == Mode_Normal) {
myMapObjects[NIS_Drawer::Draw_Hilighted].Remove( anID );
deselectObj (theObj, anID, &myMapObjects[0]);
deselectObj (theObj, anID);
aResult = Standard_True;
break;
}
if (wasSelected == Standard_False && IsSelectable(anID) == Standard_True) {
myMapObjects[NIS_Drawer::Draw_Hilighted].Add( anID );
selectObj (theObj, anID, &myMapObjects[0]);
selectObj (theObj, anID);
aResult = Standard_True;
}
break;
case Mode_Exclusive:
if (wasSelected) {
myMapObjects[NIS_Drawer::Draw_Hilighted].Remove( anID );
deselectObj (theObj, anID, &myMapObjects[0]);
deselectObj (theObj, anID);
aResult = Standard_True;
}
break;
@ -476,7 +509,7 @@ void NIS_InteractiveContext::ProcessSelection
myMapObjects[NIS_Drawer::Draw_Hilighted] = aMap;
for (anIter.Initialize (aMap); anIter.More(); anIter.Next()) {
const Standard_Integer anID = anIter.Key();
selectObj (myObjects(anID), anID, &myMapObjects[0]);
selectObj (myObjects(anID), anID);
}
} else {
TColStd_PackedMapOfInteger aMapSub;
@ -486,11 +519,11 @@ void NIS_InteractiveContext::ProcessSelection
myMapObjects[NIS_Drawer::Draw_Hilighted].Subtract (aMapSub);
for (anIter.Initialize (aMap); anIter.More(); anIter.Next()) {
const Standard_Integer anID = anIter.Key();
selectObj (myObjects(anID), anID, &myMapObjects[0]);
selectObj (myObjects(anID), anID);
}
for (anIter.Initialize (aMapSub); anIter.More(); anIter.Next()) {
const Standard_Integer anID = anIter.Key();
deselectObj (myObjects(anID), anID, &myMapObjects[0]);
deselectObj (myObjects(anID), anID);
}
}
break;
@ -499,7 +532,7 @@ void NIS_InteractiveContext::ProcessSelection
myMapObjects[NIS_Drawer::Draw_Hilighted].Unite (aMap);
for (anIter.Initialize (aMap); anIter.More(); anIter.Next()) {
const Standard_Integer anID = anIter.Key();
selectObj (myObjects(anID), anID, &myMapObjects[0]);
selectObj (myObjects(anID), anID);
}
break;
case Mode_Exclusive:
@ -507,7 +540,7 @@ void NIS_InteractiveContext::ProcessSelection
myMapObjects[NIS_Drawer::Draw_Hilighted].Subtract (aMap);
for (anIter.Initialize (aMap); anIter.More(); anIter.Next()) {
const Standard_Integer anID = anIter.Key();
deselectObj (myObjects(anID), anID, &myMapObjects[0]);
deselectObj (myObjects(anID), anID);
}
break;
default: ;
@ -541,7 +574,7 @@ void NIS_InteractiveContext::ClearSelected ()
(myMapObjects[NIS_Drawer::Draw_Hilighted]);
for (; anIter.More(); anIter.Next()) {
const Standard_Integer anID = anIter.Key();
deselectObj (myObjects(anID), anID, &myMapObjects[0]);
deselectObj (myObjects(anID), anID);
}
myMapObjects[NIS_Drawer::Draw_Hilighted].Clear();
}
@ -569,7 +602,7 @@ void NIS_InteractiveContext::SetSelected
aMapSub.Subtraction (myMapObjects[NIS_Drawer::Draw_Hilighted], aMap);
for (anIter.Initialize(aMapSub); anIter.More(); anIter.Next()) {
const Standard_Integer anID = anIter.Key();
deselectObj (myObjects(anID), anID, &myMapObjects[0]);
deselectObj (myObjects(anID), anID);
}
myMapObjects[NIS_Drawer::Draw_Hilighted].Subtract(aMapSub);
}
@ -579,7 +612,7 @@ void NIS_InteractiveContext::SetSelected
// Select objects
for (anIter.Initialize (aMap); anIter.More(); anIter.Next()) {
const Standard_Integer anID = anIter.Key();
selectObj (myObjects(anID), anID, &myMapObjects[0]);
selectObj (myObjects(anID), anID);
}
}
}
@ -590,14 +623,17 @@ void NIS_InteractiveContext::SetSelected
//=======================================================================
Standard_Real NIS_InteractiveContext::selectObject
(Handle_NIS_InteractiveObject& theSel,
const gp_Ax1& theAxis,
const Standard_Real theOver,
const Standard_Boolean isOnlySel) const
(Handle_NIS_InteractiveObject& theSel,
NCollection_List<DetectedEnt>& theDetected,
const gp_Ax1& theAxis,
const Standard_Real theOver,
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)
{
DetectedEnt anEnt;
NCollection_Vector <Handle_NIS_InteractiveObject>::Iterator
anIter(myObjects);
for (; anIter.More(); anIter.Next()) {
@ -615,16 +651,29 @@ Standard_Real NIS_InteractiveContext::selectObject
const Bnd_B3f& aBox = anObj->GetBox();
if (aBox.IsOut (theAxis, Standard_False, theOver) == Standard_False)
{
const Standard_Real aDist = anObj->Intersect (theAxis, theOver);
if (aDist < aResult) {
aResult = aDist;
theSel = anObj;
anEnt.Dist = anObj->Intersect (theAxis, theOver);
if (anEnt.Dist < anInfiniteDist) {
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;
}
}
}
}
}
}
return aResult;
return aMinDist;
}
//=======================================================================
@ -646,7 +695,7 @@ void NIS_InteractiveContext::SetSelectable
anID = anIter.Key();
if ( myMapObjects[NIS_Drawer::Draw_Hilighted].Contains(anID)) {
myMapObjects[NIS_Drawer::Draw_Hilighted].Remove(anID);
deselectObj (myObjects(anID), anID, &myMapObjects[0]);
deselectObj (myObjects(anID), anID);
}
}
myMapNonSelectableObjects.Unite(objIDs);
@ -694,25 +743,90 @@ Standard_Boolean NIS_InteractiveContext::selectObjects
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
//purpose :
//=======================================================================
void deselectObj (const Handle(NIS_InteractiveObject)& theObj,
const Standard_Integer theID,
TColStd_PackedMapOfInteger * mapObjects)
void NIS_InteractiveContext::deselectObj
(const Handle(NIS_InteractiveObject)& theObj,
const Standard_Integer theID)
{
if (theObj.IsNull() == Standard_False) {
const Handle(NIS_Drawer)& aDrawer = theObj->GetDrawer();
if (theObj->IsTransparent()) {
mapObjects[NIS_Drawer::Draw_Transparent].Add(theID);
myMapObjects[NIS_Drawer::Draw_Transparent].Add(theID);
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 {
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_Hilighted);
theObj->myDrawType = theObj->myBaseType;
}
}
@ -721,20 +835,129 @@ void deselectObj (const Handle(NIS_InteractiveObject)& theObj,
//purpose :
//=======================================================================
void selectObj (const Handle(NIS_InteractiveObject)& theObj,
const Standard_Integer theID,
TColStd_PackedMapOfInteger * mapObjects)
void NIS_InteractiveContext::selectObj
(const Handle(NIS_InteractiveObject)& theObj,
const Standard_Integer theID)
{
if (theObj.IsNull() == Standard_False) {
const Handle(NIS_Drawer)& aDrawer = theObj->GetDrawer();
if (theObj->IsTransparent()) {
mapObjects[NIS_Drawer::Draw_Transparent].Remove(theID);
myMapObjects[NIS_Drawer::Draw_Transparent].Remove(theID);
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 {
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_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_View.hxx>
#include <NCollection_IncAllocator.hxx>
#include <NCollection_Map.hxx>
#include <NCollection_Vector.hxx>
#include <NIS_Allocator.hxx>
#include <NIS_Drawer.hxx>
#include <NIS_SelectFilter.hxx>
@ -23,36 +23,42 @@
class NIS_View;
class Bnd_B3f;
class Bnd_B2f;
/**
* 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.
* There may be one or more Views referred by an InteractiveContext instance.
* 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>
* To add or remove a View in a Context, use methods AttachView() and
* 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.
* <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>
* <li>change the presentation of the InteractiveObject (e.g., modify the color)
* </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>select InteractiveObject interactively, including the hilighting and
* the dynamic hilighting.</li>
* </ul>
* All methods managing InteractiveObject instances have the optional parameter
* 'isUpdateViews'. When it is set to True (default), the modification of the
* object brings about the immediate update of the presentation (the
* corresponding Drawer is flagged to recompute presentations). However, for
* block operations when many InteractiveObject instances are affected it is
* usually better to delay this recalculation till a definite moment in the end
* of updates. Then you can set the optional parameter to False and in the end -
* call the method UpdateViews of the NIS_InteractiveContext.
* Methods that add/remove/display/hide NIS_InteractiveObject instances have
* the optional parameter 'isUpdateViews'. When it is set to True (default),
* the modification of the object brings about an immediate update of its
* presentation (the corresponding Drawer flagged to recompute presentations).
* Normally you do not have to worry about this parameter leaving it assigned to
* the default value; use the alternative value 'Standard_False' only for
* very special purposes, like animation -- when many updates should be
* 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:
* @code
* const Handle(NIS_InteractiveContext) aContext = new NIS_InteractiveContext;
@ -60,26 +66,53 @@ class Bnd_B3f;
* aContext->AttachView (aView);
* ....
* for (; ;) {
* const Handle(NIS_InteractiveObject) anObject = new ...
* aContext->Display (anObject, NULL, Standard_False);
* const Handle(MyIOClass) anObject = new MyIOClass();
* aContext->Display (anObject);
* anObject->SetColor(...); // method of class MyIOClass
* ...
* }
* aContext->UpdateViews();
* @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>
* <li>Every instance of this class maintains a distinct
* NCollection_IncAllocator that can be used by contained
* NIS_InteractiveObject and NIS_Drawer instances. For example, each Object
* may be assigned a name using the method SetAttribute, like:
* @code
* Standard_Size aLen = strlen(theName)+1;
* char * aName = (char *) myContext->Allocator()->Allocate(aLen);
* memcpy (aName, theName, aLen);
* myObject->SetAttribute(aName);
* @endcode
* </li>
* <li>Copy its argument to the memory pool that is managed by the internal
* Allocator of NIS_InteractiveContext. Then <b>the new instance of
* object</b> is returned back in the same argument (in-out parameter);</li>
* <li>Store the copied instance in the internal vector of objects, so that
* the displayed object receives its ID (sequential address in the vector);
* </li>
* <li>Create a Drawer instance if necessary; attach the displayed interactive
* object to this instance (or to a relevant and already existing Drawer)
* </li>
* </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
@ -135,7 +168,7 @@ class NIS_InteractiveContext : public Standard_Transient
NbObjects ()
// { return myObjects.Length()-1; }
{ return (myMapObjects[0].Extent() + myMapObjects[1].Extent() +
myMapObjects[2].Extent()); }
myMapObjects[2].Extent()) + myMapObjects[3].Extent(); }
/**
* Query the total number of Drawers instances.
@ -145,11 +178,12 @@ class NIS_InteractiveContext : public Standard_Transient
{ return myDrawers.Size(); }
/**
* Query the memory allocator associated with InteractiveContext instance.
*/
inline const Handle_NCollection_IncAllocator&
Allocator () const
{ return myAllocator; }
* Access to Drawers, can be used for specific operations where it is not
* desirale to iterate InteractiveObjects.
*/
inline NCollection_Map<Handle_NIS_Drawer>::Iterator
GetDrawers () const
{ return NCollection_Map<Handle_NIS_Drawer>::Iterator(myDrawers); }
// ================ BEGIN Mangement 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
* before it can be displayed.
* @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.
* @param theDrawer
* If this parameter is NULL, the default drawer is used for theObj, defined
@ -173,10 +232,10 @@ class NIS_InteractiveContext : public Standard_Transient
* to False if you have to make a number of similar calls, then you would
* call UpdateViews() in the end.
*/
Standard_EXPORT void Display (const Handle_NIS_InteractiveObject& theObj,
const Handle_NIS_Drawer& theDrawer = NULL,
const Standard_Boolean isUpdateViews
= Standard_True);
Standard_EXPORT void DisplayOnTop (Handle_NIS_InteractiveObject& theObj,
const Handle_NIS_Drawer& theDrawer = NULL,
const Standard_Boolean isUpdateViews
= Standard_True);
/**
* Make the given object invisible in the current InteractiveContext.
@ -209,45 +268,33 @@ class NIS_InteractiveContext : public Standard_Transient
/**
* Make all stored InteractiveObject instances visible, equivalent to
* 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_True);
Standard_EXPORT void DisplayAll ();
/**
* Make all stored InteractiveObject instances invisible, equivalent to
* 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_True);
Standard_EXPORT void EraseAll ();
/**
* Clean the context of its contained objects. Drawers are not destroyed
* however all presentations should 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.
* Clean the context of its contained objects. Drawers are destroyed
* and all presentations become empty.
*/
Standard_EXPORT void RemoveAll (const Standard_Boolean isUpdateViews
= Standard_True);
Standard_EXPORT void RemoveAll ();
/**
* This method signal that the presenation should be refreshed in all
* Drawers and in all Views.
* This method signals that the presenation should be refreshed in all updated
* Drawers and in all Views. Calls Redraw() of each view from inside.
*/
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.
* @param theBox
@ -402,24 +449,35 @@ class NIS_InteractiveContext : public Standard_Transient
inline Standard_Boolean IsSelectable (const Standard_Integer objID) const
{ 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 ================
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 ----------
Standard_EXPORT void redraw (const Handle_NIS_View& theView,
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.
* @param theSel
* <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
* Selection ray
* @param theOver
@ -432,6 +490,7 @@ class NIS_InteractiveContext : public Standard_Transient
*/
Standard_EXPORT Standard_Real
selectObject (Handle_NIS_InteractiveObject& theSel,
NCollection_List<DetectedEnt>& theDet,
const gp_Ax1& theAxis,
const Standard_Real theOver,
const Standard_Boolean isOnlySelectable
@ -461,9 +520,58 @@ class NIS_InteractiveContext : public Standard_Transient
const gp_Trsf& theTrfInv,
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 FIELDS ----------
/**
* Allocator for all data associated with objects.
*/
Handle_NIS_Allocator myAllocator;
/**
* Container of InteractiveObject instances.
*/
@ -483,11 +591,12 @@ class NIS_InteractiveContext : public Standard_Transient
/**
* Three maps indicating the state of contained objects:
* - #0 - normally presented objects
* - #1 - hilighted objects (i.e., selected)
* - #2 - transparent objects
* - #1 - top objects
* - #2 - hilighted objects (i.e., selected)
* - #3 - transparent objects
* <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,
@ -500,20 +609,15 @@ class NIS_InteractiveContext : public Standard_Transient
*/
Handle_NIS_SelectFilter mySelectFilter;
/**
* Current selection.
*/
// TColStd_PackedMapOfInteger mySelection;
/**
* Current mode of selection.
*/
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_Drawer;

View File

@ -28,7 +28,8 @@ NIS_InteractiveObject::~NIS_InteractiveObject ( )
//=======================================================================
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();
if (myDrawer.IsNull() == Standard_False)
@ -47,6 +48,8 @@ const Handle_NIS_Drawer& NIS_InteractiveObject::SetDrawer
Standard_NullValue_Raise_if
(aCtx == 0L, "NIS_InteractiveObject::SetDrawer: NULL drawer 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);
if (myDrawer != aDrawer)
{
@ -55,8 +58,13 @@ const Handle_NIS_Drawer& NIS_InteractiveObject::SetDrawer
myDrawer->removeObject(this, Standard_True);
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;
}
@ -67,13 +75,23 @@ const Handle_NIS_Drawer& NIS_InteractiveObject::SetDrawer
void NIS_InteractiveObject::SetTransparency (const Standard_Real theValue)
{
if (fabs(theValue - myTransparency) > 0.001) {
if (theValue > 0.001)
myTransparency = static_cast<const Standard_ShortReal> (theValue);
Standard_Integer aValue =
static_cast<Standard_Integer> (theValue * MaxTransparency);
if (aValue != static_cast<Standard_Integer>(myTransparency))
{
if (aValue <= 0)
myTransparency = 0;
else if (aValue >= 1000)
myTransparency = 1000u;
else
myTransparency = 0.f;
myTransparency = static_cast<unsigned int> (aValue);
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();
Standard_NullValue_Raise_if
(aCtx == 0L, "NIS_InteractiveObject::SetTransparency: "
@ -113,6 +131,44 @@ const Bnd_B3f& NIS_InteractiveObject::GetBox ()
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
//purpose :
@ -125,6 +181,19 @@ Standard_Boolean NIS_InteractiveObject::Intersect (const Bnd_B3f&,
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
//purpose : Query if the Object is selectable.
@ -151,16 +220,10 @@ void NIS_InteractiveObject::SetSelectable (const Standard_Boolean isSel) const
aCtx->myMapNonSelectableObjects.Remove (myID);
else {
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_Transparent].Add(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);
aCtx->myMapObjects[NIS_Drawer::Draw_Hilighted].Remove(myID);
aCtx->deselectObj (this, myID);
}
}
}

View File

@ -16,22 +16,26 @@
* An InteractiveObject has the attributes:
* <ul>
* <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>
* <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>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>
* Because the class is abstract, it does not define any color, material and
* 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
* 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
* the presentation in every possible state (normal, hilighted, etc.); usually
* the associated drawer instance contains all relevant visual aspects.<p>
* Association with a Drawer instance is performed by method SetDrawer. This
* the associated drawer instance contains all relevant visual aspects.
* <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
* NIS algorithms (in NIS_InteractiveContext::Display() for instance). If you
* develop your own InteractiveObject type, you will need to call SetDrawer
@ -39,17 +43,68 @@
* @code
* 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
* aDrawer->Assign (GetDrawer());
* // replace the Drawer
* aDrawer->myColor = theColor;
* SetDrawer (aDrawer);
* // optional: redraws the changed InteractiveObject in the views
* GetDrawer()->GetContext()->UpdateViews();
* }
* @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
* stored as a pointer. It can accommodate an integer/float/boolean value or
* a pointer to some structure. This attribute is NOT automatically destroyed
@ -68,10 +123,11 @@ class NIS_InteractiveObject : public Standard_Transient
inline NIS_InteractiveObject ()
: myID (0),
myDrawType (NIS_Drawer::Draw_Normal),
myBaseType (NIS_Drawer::Draw_Normal),
myIsHidden (Standard_True),
myIsDynHilighted (Standard_False),
myIsUpdateBox (Standard_True),
myTransparency (0.f),
myTransparency (0),
myAttributePtr (0L)
{}
@ -106,7 +162,9 @@ class NIS_InteractiveObject : public Standard_Transient
* the Context.
*/
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.
@ -116,10 +174,14 @@ class NIS_InteractiveObject : public Standard_Transient
{ 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
DefaultDrawer () const = 0;
Standard_EXPORT virtual NIS_Drawer *
DefaultDrawer (NIS_Drawer * theDrv) const = 0;
/**
* Query a 3D bounding box of the object.
@ -131,7 +193,7 @@ class NIS_InteractiveObject : public Standard_Transient
* Query the Transparent state.
*/
inline Standard_Boolean IsTransparent () const
{ return myTransparency > 0.001; }
{ return myTransparency > 0; }
/**
* Query the Hidden state
@ -154,7 +216,7 @@ class NIS_InteractiveObject : public Standard_Transient
/**
* Query if the Object is selectable.
*/
Standard_EXPORT Standard_Boolean
Standard_EXPORT virtual Standard_Boolean
IsSelectable () const;
/**
@ -163,14 +225,15 @@ class NIS_InteractiveObject : public Standard_Transient
* True (default) - the Object will be selectable, False - it will be
* 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;
/**
* Query the Transparency factor.
*/
inline Standard_Real Transparency () const
{ return myTransparency; }
inline Standard_ShortReal Transparency () const
{ return static_cast<Standard_ShortReal>(myTransparency) / MaxTransparency; }
/**
* Set the Transparency factor.
@ -183,6 +246,23 @@ class NIS_InteractiveObject : public Standard_Transient
inline void UnsetTransparency ()
{ 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.
* @param theAxis
@ -227,6 +307,32 @@ class NIS_InteractiveObject : public Standard_Transient
const gp_Trsf& theTrf,
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.
*/
@ -267,18 +373,21 @@ class NIS_InteractiveObject : public Standard_Transient
// ---------- PRIVATE FIELDS ----------
Handle_NIS_Drawer myDrawer;
Standard_Size myID : 26;
NIS_Drawer::DrawType myDrawType : 2;
Standard_Size myID;
NIS_Drawer::DrawType myDrawType : 3;
NIS_Drawer::DrawType myBaseType : 3;
Standard_Boolean myIsHidden : 1;
Standard_Boolean myIsDynHilighted: 1;
Standard_Boolean myIsUpdateBox : 1;
Standard_ShortReal myTransparency;
unsigned int myTransparency : 10;
static const unsigned int MaxTransparency = 1000;
protected:
Bnd_B3f myBox;
void * myAttributePtr;
friend class NIS_InteractiveContext;
friend class NIS_Drawer;

View File

@ -34,3 +34,16 @@ void NIS_ObjectsIterator::Next ()
if (myIter.Value().IsNull() == Standard_False)
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
* over (More() == False) this method returns NULL Handle.
*/
inline Handle(NIS_InteractiveObject)
Value () const
{ if (More()) return myIter.Value(); return NULL; }
Standard_EXPORT const Handle_NIS_InteractiveObject&
Value () const;
/**
* Step forward to the next valid InteractiveObject instance.

View File

@ -6,31 +6,39 @@
#include <NIS_Surface.hxx>
#include <NIS_SurfaceDrawer.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 <Geom_Surface.hxx>
#include <NCollection_Map.hxx>
#include <Poly_PolygonOnTriangulation.hxx>
#include <Poly_Triangulation.hxx>
#include <Precision.hxx>
#include <TColgp_Array1OfPnt2d.hxx>
#include <TopExp.hxx>
#include <TopExp_Explorer.hxx>
#include <TopLoc_Location.hxx>
#include <TopTools_MapOfShape.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Face.hxx>
#include <TopoDS_Edge.hxx>
#include <TShort_Array1OfShortReal.hxx>
#include <gp_Ax1.hxx>
IMPLEMENT_STANDARD_HANDLE (NIS_Surface, NIS_InteractiveObject)
IMPLEMENT_STANDARD_RTTIEXT(NIS_Surface, NIS_InteractiveObject)
//=======================================================================
//function : defaultDrawer
//purpose : internal method (static)
//function : IsEqual
//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 =
new NIS_SurfaceDrawer(Quantity_NOC_SLATEBLUE4);
aDrawer->SetBackColor (Quantity_NOC_DARKGREEN);
return aDrawer;
return (theT0 == theT1);
}
//=======================================================================
@ -38,14 +46,36 @@ inline Handle(NIS_SurfaceDrawer) defaultDrawer()
//purpose :
//=======================================================================
NIS_Surface::NIS_Surface
(const Handle(Poly_Triangulation)& theTri,
const Handle_NCollection_BaseAllocator& theAlloc)
: mypNodes (NULL),
mypNormals (NULL),
myNNodes (0),
myNTriangles (0),
myAlloc (theAlloc)
NIS_Surface::NIS_Surface(const Handle_NCollection_BaseAllocator& theAlloc)
: myAlloc (theAlloc),
mypNodes (NULL),
mypNormals (NULL),
mypTriangles (NULL),
mypEdges (NULL),
myNNodes (0),
myNTriangles (0),
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())
myAlloc = NCollection_BaseAllocator::CommonBaseAllocator();
@ -107,47 +137,75 @@ NIS_Surface::NIS_Surface
//purpose : Constructor
//=======================================================================
NIS_Surface::NIS_Surface
(const TopoDS_Shape& theShape,
// const Standard_Real theDeflection,
const Handle_NCollection_BaseAllocator& theAlloc)
: mypNodes (NULL),
NIS_Surface::NIS_Surface (const TopoDS_Shape& theShape,
const Standard_Real theDeflection,
const Handle_NCollection_BaseAllocator& theAlloc)
: myAlloc (theAlloc),
mypNodes (NULL),
mypNormals (NULL),
mypTriangles (NULL),
mypEdges (NULL),
myNNodes (0),
myNTriangles (0),
myAlloc (theAlloc)
myNEdges (0),
myIsWireframe (0)
{
if (myAlloc.IsNull())
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;
// Count the nodes and triangles in faces
NCollection_Map<Handle_Poly_Triangulation> mapTri;
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
= BRep_Tool::Triangulation (aFace, aLoc);
const Handle(Geom_Surface)& aSurf = BRep_Tool::Surface(aFace, aLoc);
if (aTriangulation.IsNull())
BRepMesh_IncrementalMesh aMeshTool(aFace, theDeflection);
if (aTriangulation.IsNull() == Standard_False &&
aSurf.IsNull() == Standard_False)
if (aTriangulation.IsNull() == Standard_False)
{
myNNodes += aTriangulation->NbNodes();
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) {
mypNodes = static_cast<Standard_ShortReal*>
mypNodes = static_cast<Standard_ShortReal *>
(myAlloc->Allocate(sizeof(Standard_ShortReal) * 3 * myNNodes));
mypNormals = static_cast<Standard_ShortReal *>
(myAlloc->Allocate(sizeof(Standard_ShortReal) * 3 * myNNodes));
mypTriangles = static_cast<Standard_Integer*>
mypTriangles = static_cast<Standard_Integer *>
(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
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(Poly_Triangulation)& aTriangulation =
BRep_Tool::Triangulation(aFace, aLoc);
if (aTriangulation.IsNull() == Standard_False &&
aSurf.IsNull() == Standard_False)
if (aTriangulation.IsNull() == Standard_False)
{
// Prepare transformation
Standard_Integer i, aNodeInd(nNodes)/*, aNTriangles = 0*/;
@ -181,10 +238,20 @@ NIS_Surface::NIS_Surface
gp_Vec aD1U, aD1V;
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.
aSurf->D1(tabUV(i).X(), tabUV(i).Y(), aP, aD1U, aD1V);
aNorm = (aD1U.Crossed(aD1V)).XYZ();
}
// Compute the surface normal at the Node.
aSurf->D1(tabUV(i).X(), tabUV(i).Y(), aP, aD1U, aD1V);
gp_XYZ aNorm = (aD1U.Crossed(aD1V)).XYZ();
if (isReverse)
aNorm.Reverse();
const Standard_Real aMod = aNorm.SquareModulus();
@ -203,29 +270,73 @@ NIS_Surface::NIS_Surface
aNodeInd++;
}
const Standard_Integer nNodes1 = nNodes - 1;
// Store all triangles of the current face in the data model
const Poly_Array1OfTriangle& tabTri = aTriangulation->Triangles();
for (i = tabTri.Lower(); i <= tabTri.Upper(); i++)
{
Standard_Integer aN[3];
tabTri(i).Get (aN[0], aN[1], aN[2]);
if (((tabNode(aN[2]).XYZ() -
tabNode(aN[0]).XYZ()) ^
(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) {
mypTriangles[nTriangles*3 + 1] = aN[2];
mypTriangles[nTriangles*3 + 2] = aN[1];
} else {
mypTriangles[nTriangles*3 + 1] = aN[1];
mypTriangles[nTriangles*3 + 2] = aN[2];
}
Standard_Integer * pTriangle = &mypTriangles[nTriangles*3];
pTriangle[0] = aN[0] + nNodes1;
if (isReverse) {
pTriangle[1] = aN[2] + nNodes1;
pTriangle[2] = aN[1] + nNodes1;
} else {
pTriangle[1] = aN[1] + nNodes1;
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++;
}
// 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();
@ -233,6 +344,11 @@ NIS_Surface::NIS_Surface
}
myNTriangles = nTriangles;
}
if (GetDrawer().IsNull() == Standard_False)
{
setDrawerUpdate();
}
setIsUpdateBox(Standard_True);
}
//=======================================================================
@ -241,6 +357,16 @@ NIS_Surface::NIS_Surface
//=======================================================================
NIS_Surface::~NIS_Surface ()
{
Clear();
}
//=======================================================================
//function : Clear
//purpose :
//=======================================================================
void NIS_Surface::Clear ()
{
if (myNNodes) {
myNNodes = 0;
@ -251,6 +377,20 @@ NIS_Surface::~NIS_Surface ()
myNTriangles = 0;
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 :
//=======================================================================
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)
{
Handle(NIS_SurfaceDrawer) aDrawer = defaultDrawer();
const Handle(NIS_SurfaceDrawer) aDrawer =
static_cast<NIS_SurfaceDrawer *>(DefaultDrawer(0L));
aDrawer->Assign (GetDrawer());
aDrawer->myColor[NIS_Drawer::Draw_Normal] = theColor;
aDrawer->myColor[NIS_Drawer::Draw_Top] = theColor;
aDrawer->myColor[NIS_Drawer::Draw_Transparent] = theColor;
SetDrawer (aDrawer);
}
@ -284,7 +431,8 @@ void NIS_Surface::SetColor (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->myBackColor = theColor;
SetDrawer (aDrawer);
@ -297,23 +445,96 @@ void NIS_Surface::SetBackColor (const Quantity_Color& theColor)
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->myPolygonOffset = theValue;
aDrawer->myPolygonOffset = static_cast<Standard_ShortReal>(theValue);
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 :
//=======================================================================
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();
aDrawer->Assign (GetDrawer());
aDrawer->myTransparency = theValue;
SetDrawer (aDrawer);
Handle(NIS_Surface) aNewObj;
if (theDest.IsNull()) {
aNewObj = new NIS_Surface(theAlloc);
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,
const Standard_Real /*over*/) const
const Standard_Real theOver) const
{
Standard_Real aResult (RealLast());
Standard_Real start[3], dir[3];
@ -330,15 +551,34 @@ Standard_Real NIS_Surface::Intersect (const gp_Ax1& theAxis,
theAxis.Direction().Coord(dir[0], dir[1], dir[2]);
double anInter;
for (Standard_Integer i = 0; i < myNTriangles; i++) {
const Standard_Integer * pTri = &mypTriangles[3*i];
if (NIS_Triangulated::tri_line_intersect (start, dir,
&mypNodes[3*pTri[0]],
&mypNodes[3*pTri[1]],
&mypNodes[3*pTri[2]],
&anInter))
if (anInter < aResult)
aResult = anInter;
if (myIsWireframe == Standard_False)
for (Standard_Integer i = 0; i < myNTriangles; i++) {
const Standard_Integer * pTri = &mypTriangles[3*i];
if (NIS_Triangulated::tri_line_intersect (start, dir,
&mypNodes[3*pTri[0]],
&mypNodes[3*pTri[1]],
&mypNodes[3*pTri[2]],
&anInter))
if (anInter < aResult)
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;
@ -349,22 +589,121 @@ Standard_Real NIS_Surface::Intersect (const gp_Ax1& theAxis,
//purpose :
//=======================================================================
Standard_Boolean NIS_Surface::Intersect
(const Bnd_B3f& theBox,
Standard_Boolean NIS_Surface::Intersect (const Bnd_B3f& theBox,
const gp_Trsf& theTrf,
const Standard_Boolean isFullIn) const
{
Standard_Boolean aResult (isFullIn);
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);
if (theBox.IsOut (aPnt) == isFullIn) {
aResult = !isFullIn;
break;
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);
if (theBox.IsOut (aPnt) == isFullIn) {
aResult = !isFullIn;
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);
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;
}
}
}
}
}
@ -378,7 +717,7 @@ Standard_Boolean NIS_Surface::Intersect
void NIS_Surface::computeBox ()
{
NIS_Triangulated::ComputeBox(myBox, myNNodes, mypNodes);
NIS_Triangulated::ComputeBox(myBox, myNNodes, mypNodes, 3);
const Handle(NIS_SurfaceDrawer)& aDrawer =
static_cast<const Handle(NIS_SurfaceDrawer)&> (GetDrawer());

View File

@ -15,35 +15,66 @@ class Handle_Poly_Triangulation;
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
{
public:
enum DisplayMode {
Shading,
Wireframe
};
/**
* Constructor
*/
Standard_EXPORT NIS_Surface(const Handle_Poly_Triangulation& theTri,
const Handle_NCollection_BaseAllocator&
const Handle_NCollection_BaseAllocator&
theAlloc =0L);
/**
* Constructor. Creates the presentation of all faces in 'theShape' object.
* @aparm theShape
* @param theShape
* 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.
*/
Standard_EXPORT NIS_Surface(const TopoDS_Shape& theShape,
// const Standard_Real theDeflection,
const Handle_NCollection_BaseAllocator&
theAlloc = 0L);
const Standard_Real theDeflection,
const Handle_NCollection_BaseAllocator& theAl=0L);
/**
* Destructor
*/
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.
*/
@ -54,6 +85,11 @@ public:
*/
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.
* @return
@ -76,6 +112,18 @@ public:
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)
* @return
@ -90,8 +138,8 @@ public:
/**
* Create a default drawer instance.
*/
Standard_EXPORT virtual Handle_NIS_Drawer
DefaultDrawer () const;
Standard_EXPORT virtual NIS_Drawer *
DefaultDrawer (NIS_Drawer *) const;
/**
* Set the normal color for presentation.
@ -115,15 +163,31 @@ public:
Standard_EXPORT void SetPolygonOffset (const Standard_Real theValue);
/**
* Set the transparency factor.
* @param theValue
* 1.0 means full transparency, 0.0 means opaque. Valid quantities are in
* this interval.
* Set the display mode: Shading or Wireframe.
* The default mode is Shading.
*/
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
* The line or ray in 3D space.
* @param theOver
@ -134,11 +198,11 @@ public:
* on the ray. May be negative.
*/
Standard_EXPORT virtual Standard_Real
Intersect (const gp_Ax1& theAxis,
Intersect (const gp_Ax1& theAxis,
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
* 3D box of selection
* @param theTrf
@ -153,8 +217,32 @@ public:
const gp_Trsf& theTrf,
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:
/**
* Allocator for method Clone().
*/
Standard_EXPORT NIS_Surface (const Handle_NCollection_BaseAllocator& theAl);
/**
* Create a 3D bounding box of the object.
*/
@ -168,15 +256,20 @@ protected:
gp_XYZ& theNormal) const;
private:
Handle_NCollection_BaseAllocator myAlloc;
//! Array of nodes in triangles
Standard_ShortReal * mypNodes;
//! Array of normals (TriNodes)
Standard_ShortReal * mypNormals;
//! Array of triangles (node indices)
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
Standard_Integer myNNodes;
Standard_Integer myNTriangles;
Handle_NCollection_BaseAllocator myAlloc;
Standard_Integer myNEdges;
Standard_Boolean myIsWireframe;
public:
// Declaration of CASCADE RTTI

View File

@ -13,6 +13,11 @@
#endif
#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_RTTIEXT (NIS_SurfaceDrawer, NIS_Drawer)
@ -26,10 +31,11 @@ NIS_SurfaceDrawer::NIS_SurfaceDrawer
const Quantity_Color &theHilight,
const Quantity_Color &theDynHilight)
: myBackColor (theNormal),
myTransparency (0.0),
myPolygonOffset (0.f)
myPolygonOffset (0.f),
myIsWireframe (Standard_False)
{
myColor[Draw_Normal] = theNormal;
myColor[Draw_Top] = theNormal;
myColor[Draw_Transparent] = theNormal;
myColor[Draw_Hilighted] = theHilight;
myColor[Draw_DynHilighted] = theDynHilight;
@ -40,12 +46,11 @@ NIS_SurfaceDrawer::NIS_SurfaceDrawer
//purpose :
//=======================================================================
void NIS_SurfaceDrawer::SetColor(const Quantity_Color &theColor,
const Standard_Real theTransparency)
void NIS_SurfaceDrawer::SetColor(const Quantity_Color &theColor)
{
myColor[Draw_Normal] = theColor;
myColor[Draw_Top] = 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 =
static_cast <const Handle(NIS_SurfaceDrawer)&> (theOther);
myColor[Draw_Normal] = anOther->myColor[Draw_Normal];
myColor[Draw_Top] = anOther->myColor[Draw_Top];
myColor[Draw_Transparent] = anOther->myColor[Draw_Transparent];
myColor[Draw_Hilighted] = anOther->myColor[Draw_Hilighted];
myColor[Draw_DynHilighted] = anOther->myColor[Draw_DynHilighted];
myBackColor = anOther->myBackColor;
myPolygonOffset = anOther->myPolygonOffset;
myIsWireframe = anOther->myIsWireframe;
}
}
@ -88,8 +96,7 @@ Standard_Boolean NIS_SurfaceDrawer::IsEqual
.SquareDistance (myColor[Draw_DynHilighted]) < anEpsilon2 &&
anOther->myBackColor.SquareDistance(myBackColor) < anEpsilon2 &&
fabs(anOther->myPolygonOffset - myPolygonOffset) < 0.999 &&
(anOther->myTransparency - myTransparency) *
(anOther->myTransparency - myTransparency) < 0.01);
myIsWireframe == anOther->myIsWireframe);
if (aResult) {
// Arbitrary point for test
gp_XYZ aPnt[2] = {
@ -110,7 +117,7 @@ Standard_Boolean NIS_SurfaceDrawer::IsEqual
//=======================================================================
void NIS_SurfaceDrawer::redraw (const DrawType theType,
const Handle_NIS_View& theView)
const Handle_NIS_View& theView)
{
glMatrixMode( GL_MODELVIEW );
glPushMatrix();
@ -135,84 +142,66 @@ void NIS_SurfaceDrawer::redraw (const DrawType theType,
//=======================================================================
void NIS_SurfaceDrawer::BeforeDraw (const DrawType theType,
const NIS_DrawList&)
const NIS_DrawList&)
{
glEnable(GL_LIGHTING);
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 1);
glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
// glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 1);
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);
GLfloat aLineWidth (1.f);
GLfloat anOffset = myPolygonOffset;
static const GLfloat gColorN[4] = {0.f, 0.f, 0.f, 1.f};
switch (theType) {
case Draw_DynHilighted:
aLineWidth = 3.f;
myColor[theType].Values (aValueCol[0], aValueCol[1], aValueCol[2], bidTC);
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
glColor3d (aValueCol[0], aValueCol[1], aValueCol[2]);
setColor(GL_FRONT_AND_BACK, &aValueCol[0], 0.1, 5);
glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, &gColorN[0]);
glLineWidth (aLineWidth);
// glEnable(GL_POLYGON_OFFSET_LINE);
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(1.f, -(anOffset + 11.f));
if (myIsWireframe == Standard_False)
glPolygonOffset(1.f, -(anOffset + 11.f));
return;
case Draw_Hilighted:
anOffset += 10.f;
case Draw_Normal:
case Draw_Top:
case Draw_Transparent:
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(1.f, -anOffset);
glEnableClientState (GL_NORMAL_ARRAY);
if (myIsWireframe == Standard_False) {
glPolygonOffset(1.f, -anOffset);
glEnableClientState (GL_NORMAL_ARRAY);
}
myColor[theType].Values (aValueCol[0], aValueCol[1], aValueCol[2], bidTC);
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;
default:
return;
}
// 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
};
// glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 0);
if (theType == Draw_Hilighted ||
myBackColor.SquareDistance(myColor[Draw_Normal]) < 1.e-7)
{
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
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);
setColor(GL_FRONT_AND_BACK, &aValueCol[0], 0.5, 10);
} else {
glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
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]);
setColor(GL_FRONT, &aValueCol[0], 0.4, 10);
myBackColor.Values (aValueCol[0], aValueCol[1], aValueCol[2], bidTC);
glColorMaterial(GL_BACK, GL_AMBIENT_AND_DIFFUSE);
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);
setColor(GL_BACK, &aValueCol[0], 0.8, 5);
}
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);
glShadeModel(GL_SMOOTH);
}
//=======================================================================
@ -221,25 +210,23 @@ void NIS_SurfaceDrawer::BeforeDraw (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);
glDisableClientState(GL_VERTEX_ARRAY);
switch (theType) {
case Draw_DynHilighted:
// glDisable(GL_POLYGON_OFFSET_LINE);
break;
case Draw_Transparent:
glDisable(GL_BLEND);
glDepthMask(GL_TRUE);
case Draw_Hilighted:
case Draw_Normal:
case Draw_Transparent:
glDisable(GL_POLYGON_OFFSET_FILL);
glDisableClientState(GL_NORMAL_ARRAY);
case Draw_Top:
if (myIsWireframe == Standard_False)
glDisableClientState(GL_NORMAL_ARRAY);
default:;
}
if (myIsWireframe == Standard_False)
glDisable(GL_POLYGON_OFFSET_FILL);
}
//=======================================================================
@ -248,23 +235,64 @@ void NIS_SurfaceDrawer::AfterDraw (const DrawType theType,
//=======================================================================
void NIS_SurfaceDrawer::Draw (const Handle_NIS_InteractiveObject& theObj,
const DrawType theType,
const NIS_DrawList&)
const DrawType theType,
const NIS_DrawList&)
{
// Assertion for the type of the drawn object
#ifdef _DEBUG
static const Handle(Standard_Type) ThisType = STANDARD_TYPE(NIS_Surface);
Standard_ProgramError_Raise_if (theObj->IsKind(ThisType) == Standard_False,
"NIS_Surface::Draw: "
"irrelevant object type");
"NIS_Surface::Draw: irrelevant object type");
#endif
const NIS_Surface * pObject =
static_cast <const NIS_Surface *> (theObj.operator->());
if (pObject->NTriangles())
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)
{
glVertexPointer (3, GL_FLOAT, 0, pObject->Node(0));
glNormalPointer (GL_FLOAT, 0, pObject->Normal(0));
glDrawElements (GL_TRIANGLES, pObject->NTriangles()*3,
GL_UNSIGNED_INT, pObject->Triangle(0));
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));
glDrawElements (GL_TRIANGLES, pObject->NTriangles()*3,
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,
const Quantity_Color &theHilight
= Quantity_NOC_GRAY80,
= Quantity_NOC_GRAY65,
const Quantity_Color &theDynHilight
= 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,
const Standard_Real theTransparency);
Standard_EXPORT void SetColor (const Quantity_Color &theColor);
/**
* 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)
{
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
{
return static_cast<const Standard_Real>(myPolygonOffset);
return static_cast<Standard_Real>(myPolygonOffset);
}
/**
* Copy the relevant information from another instance of Drawer.
* raises exception if theOther has incompatible type (test IsKind).
@ -115,11 +113,11 @@ class NIS_SurfaceDrawer : public NIS_Drawer
private:
Quantity_Color myColor[4];
Quantity_Color myColor[5];
Quantity_Color myBackColor;
gp_Trsf myTrsf;
Standard_Real myTransparency;
Standard_ShortReal myPolygonOffset;
Standard_Boolean myIsWireframe;
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 <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 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
{
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
// treated as Line only.
/**
* Constants defining the mode (type) of presentation. They allow mixed type,
* e.g., Triangulation+Line. Line and Segments are not mixable, their mix is
* treated as Line only.
*/
enum {
Type_None = 0,
Type_Loop = 1, // modifier to Line
Type_Loop = 1, //!< modifier to Line
Type_Line = 2,
Type_Segments = 4,
Type_Triangulation = 8,
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 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
* memory allocator where the nodes, lines and triangles will be stored by
* 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,
const Handle_NCollection_BaseAllocator& =0L);
const Standard_Boolean is2D = Standard_False,
const Handle_NCollection_BaseAllocator&
theAlloc = 0L);
/**
* Define the polygonal presentration.
@ -137,9 +183,8 @@ class NIS_Triangulated : public NIS_InteractiveObject
/**
* Create a default drawer instance.
*/
Standard_EXPORT virtual Handle_NIS_Drawer
DefaultDrawer () const;
Standard_EXPORT virtual NIS_Drawer *
DefaultDrawer (NIS_Drawer *) const;
/**
* 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
* the call SetPolygonsPrs().
* the call SetPolygonsPrs(). The polygon can be filled by node indices using
* the method SetPolygonNode().
* @param ind
* Index of the polygon, should be [0..Npolygons-1]
* @param theSz
* 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);
/**
@ -203,48 +246,43 @@ class NIS_Triangulated : public NIS_InteractiveObject
* Query the number of polygons.
*/
inline Standard_Integer NPolygons () const
{ return myNPolygons; }
{ return static_cast<Standard_Integer>(myNPolygons); }
/**
* Query the node by its index.
* @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
{ return &mypNodes[ind*3]; }
{ return &mypNodes[ind * myNodeCoord]; }
/**
* Query the triangle by its index.
* @return
* pointer to array of 3 Standard_Integer values (nodes 0, 1, 2)
*/
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.
* Define the node of a polygon by index.
* @param indPoly
* Index of the Polygon, should be less than the number of polygons that is
* defined in SetPolygonsPrs() and can be returned by NPOlygons().
* @param ind
* rank of the polygon [0 .. N-1]
* @param outInd
* <tt>[out]</tt> array of vertex indice
* @return
* number of vertice in the polygon - the dimension of outInd array
* Index of the node in the Polygon. Should be less than the parameter theSz
* in the corresponding previous SetPolygon() call.
* @param iNode
* Index of the node in the given position of the Polygon.
*/
inline const Standard_Integer Polygon (const Standard_Integer ind,
Standard_Integer* & outInd) const
{ return * (outInd = mypPolygons[ind])++; }
Standard_EXPORT void SetPolygonNode
(const Standard_Integer indPoly,
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
@ -252,24 +290,22 @@ class NIS_Triangulated : public NIS_InteractiveObject
* Line/Segments.
* @param isDrawPolygons
* True defines that no triangulation is drawn, only polygons are. False
* defines that only triangulation is draw, no polygons.
* @param isUpdateV
* True if all views should be updated, otherwise wait till the next update
* defines that only triangulation is drawn, no polygons.
*/
Standard_EXPORT void SetDrawPolygons
(const Standard_Boolean isDrawPolygons,
const Standard_Boolean isUpdateViews
= Standard_True);
(const Standard_Boolean isDrawPolygons);
/**
* Set the type of polygon rendering.
*/
Standard_EXPORT void SetPolygonType
(const PolygonType theType);
/**
* Set the normal color for presentation.
* @param theColor
* 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,
const Standard_Boolean isUpdateV
= Standard_True);
Standard_EXPORT void SetColor (const Quantity_Color& theColor);
/**
* 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.
* @param theColor
* 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,
const Standard_Boolean isUpdateV
= Standard_True);
Standard_EXPORT void SetHilightColor (const Quantity_Color& theColor);
/**
* Set the color for dynamic hilight presentation.
* @param theColor
* 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,
const Standard_Boolean isUpdateV
= Standard_True);
Standard_EXPORT void SetDynHilightColor(const Quantity_Color& theColor);
/**
* Set the width of line presentations in pixels.
* @param theWidth
* 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,
const Standard_Boolean isUpdateV
= Standard_True);
Standard_EXPORT void SetLineWidth (const Standard_Real theWidth);
/**
* 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.
@ -323,7 +359,7 @@ class NIS_Triangulated : public NIS_InteractiveObject
* detected. Otherwise returns the coordinate of thePnt on the ray. May be
* negative.
*/
Standard_EXPORT Standard_Real
Standard_EXPORT virtual Standard_Real
Intersect (const gp_Ax1& theAxis,
const Standard_Real theOver) const;
@ -343,19 +379,52 @@ class NIS_Triangulated : public NIS_InteractiveObject
const gp_Trsf& theTrf,
const Standard_Boolean isFull)const;
Standard_EXPORT static int tri_line_intersect (const double start[3],
const double dir[3],
const float V0[3],
const float V1[3],
const float V2[3],
double * tInter);
/**
* 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 seg_line_intersect (const gp_XYZ& aStart,
const gp_XYZ& aDir,
const double over2,
const float V0[3],
const float V1[3],
double * tInter);
Standard_EXPORT static int tri_line_intersect (const double start[3],
const double dir[3],
const float V0[3],
const float V1[3],
const float V2[3],
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,
const gp_XYZ& aDir,
const double over2,
const float V0[3],
const float V1[3],
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,
const gp_Pnt thePnt[2]);
@ -363,12 +432,58 @@ class NIS_Triangulated : public NIS_InteractiveObject
Standard_EXPORT static int seg_box_included (const Bnd_B3f& theBox,
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,
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:
/**
* 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.
*/
@ -380,30 +495,49 @@ class NIS_Triangulated : public NIS_InteractiveObject
*/
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 FIELDS ----------
/**
* Combination of Type_* constants
*/
Standard_Integer myType;
Standard_ShortReal * mypNodes;
Standard_Integer * mypTriangles;
Standard_Integer * mypLines;
Standard_Integer ** mypPolygons;
Standard_Integer myNNodes;
Standard_Integer myNTriangles;
Standard_Integer myNPolygons;
Standard_Integer myNLineNodes;
NCollection_BaseAllocator * myAlloc;
Standard_Boolean myIsDrawPolygons;
NCollection_BaseAllocator * myAlloc; //!< Usually from InteractiveContext
Standard_Integer myType; //!< Combination of Type_* constants
Standard_ShortReal * mypNodes;
Standard_Integer * mypTriangles;
Standard_Integer * mypLines;
Standard_Integer ** mypPolygons;
Standard_Integer myNNodes;
Standard_Integer myNTriangles;
Standard_Integer myNLineNodes;
unsigned int myNPolygons : 24;
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:
// Declaration of CASCADE RTTI
DEFINE_STANDARD_RTTI (NIS_Triangulated)
friend class NIS_TriangulatedDrawer;
};
// Definition of HANDLE object using Standard_DefineHandle.hxx
DEFINE_STANDARD_HANDLE (NIS_Triangulated, NIS_InteractiveObject)
#ifdef WNT
#pragma warning (pop)
#endif
#endif

View File

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

View File

@ -8,6 +8,8 @@
#include <NIS_InteractiveObject.hxx>
#include <gp_Ax1.hxx>
#include <Visual3d_View.hxx>
#include <Bnd_B2f.hxx>
#include <TColStd_MapIteratorOfPackedMapOfInteger.hxx>
#ifdef WNT
#include <Windows.h>
#endif
@ -23,12 +25,12 @@ IMPLEMENT_STANDARD_RTTIEXT (NIS_View, V3d_OrthographicView)
NIS_View::NIS_View (const Handle(V3d_Viewer)& theViewer,
const Handle(Aspect_Window)& theWindow)
: V3d_OrthographicView (theViewer)
: V3d_OrthographicView (theViewer),
myIsTopHilight(Standard_False),
myDoHilightSelected(Standard_True)
{
if (!theWindow.IsNull()) {
const Aspect_GraphicCallbackProc aCallback = &MyCallback;
V3d_View::SetWindow (theWindow, NULL, aCallback, this);
}
if (!theWindow.IsNull())
V3d_View::SetWindow (theWindow, NULL, &MyCallback, this);
}
//=======================================================================
@ -38,8 +40,7 @@ NIS_View::NIS_View (const Handle(V3d_Viewer)& theViewer,
void NIS_View::SetWindow(const Handle(Aspect_Window) &theWindow)
{
const Aspect_GraphicCallbackProc aCallback = &MyCallback;
V3d_View::SetWindow (theWindow, NULL, aCallback, this);
V3d_View::SetWindow (theWindow, NULL, &MyCallback, this);
}
// //=======================================================================
@ -80,6 +81,14 @@ void NIS_View::RemoveContext (NIS_InteractiveContext * theCtx)
myContexts.Remove (anIter);
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 :
//=======================================================================
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
// 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
Standard_Real aVal[6];
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]));
}
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
if (aBox.IsVoid() == Standard_False) {
// 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])
{
// Scale the view
WindowFit (aLimp[0], aLimp[2], aLimp[1], aLimp[3]);
return;
// WindowFit (aLimp[0], aLimp[2], aLimp[1], aLimp[3]);
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
// glEnable(GL_COLOR_MATERIAL);
GLboolean isDepthWriteMask, isDepthTest;
glGetBooleanv(GL_DEPTH_WRITEMASK,&isDepthWriteMask);
glGetBooleanv(GL_DEPTH_TEST,&isDepthTest);
@ -217,14 +324,40 @@ int NIS_View::MyCallback (Aspect_Drawable /* Window ID */,
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())
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())
anIter.Value()->redraw (thisView, NIS_Drawer::Draw_Hilighted);
for (anIter = thisView->myContexts; anIter.More(); anIter.Next())
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;
}
@ -237,6 +370,7 @@ int NIS_View::MyCallback (Aspect_Drawable /* Window ID */,
void NIS_View::DynamicHilight (const Standard_Integer theX,
const Standard_Integer theY)
{
myDetected.Clear();
const Handle(NIS_InteractiveObject) aSelected = Pick (theX, theY);
// ASV: if at least one Context returns IsSelectable()==False,
@ -248,10 +382,17 @@ void NIS_View::DynamicHilight (const Standard_Integer theX,
if (aSelected != myDynHilighted) {
const Handle(NIS_View) aView (this);
if (myDynHilighted.IsNull() == Standard_False)
myDynHilighted->GetDrawer()->SetDynamicHilighted (Standard_False,
myDynHilighted, aView);
if (aSelected.IsNull())
if (myDynHilighted->GetDrawer().IsNull() == Standard_False)
myDynHilighted->GetDrawer()->SetDynamicHilighted(Standard_False,
myDynHilighted, aView);
// 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();
}
else {
aSelected->GetDrawer()->SetDynamicHilighted (Standard_True,
aSelected, aView);
@ -270,8 +411,9 @@ void NIS_View::DynamicUnhilight(const Handle_NIS_InteractiveObject& theObj)
{
if (theObj == myDynHilighted && theObj.IsNull() == Standard_False) {
const Handle(NIS_View) aView (this);
myDynHilighted->GetDrawer()->SetDynamicHilighted (Standard_False,
myDynHilighted, aView);
if (myDynHilighted->GetDrawer().IsNull() == Standard_False)
myDynHilighted->GetDrawer()->SetDynamicHilighted (Standard_False,
myDynHilighted, aView);
myDynHilighted.Nullify();
Redraw();
}
@ -284,8 +426,10 @@ void NIS_View::DynamicUnhilight(const Handle_NIS_InteractiveObject& theObj)
void NIS_View::Select (const Standard_Integer theX,
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);
NCollection_List<NIS_InteractiveContext *>::Iterator anIter (myContexts);
for (; anIter.More(); anIter.Next())
@ -296,7 +440,7 @@ void NIS_View::Select (const Standard_Integer theX,
const Handle(NIS_Drawer)& aDrawer = aSelected->GetDrawer();
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 theYmax,
const Standard_Boolean isForceMult,
const Standard_Boolean isFullyIncluded)
const Standard_Boolean isFullyIncluded,
const Standard_Boolean theRedraw)
{
myDetected.Clear();
Standard_Real anX, anY, aZ;
if (theXmin == theXmax || theYmin == theYmax)
return;
@ -346,18 +492,85 @@ void NIS_View::Select (const Standard_Integer theXmin,
pCtx->selectObjects (mapSelected, aBoxSel, aTrfInv, aTrf, isFullyIncluded);
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
//purpose :
//=======================================================================
Handle_NIS_InteractiveObject NIS_View::Pick
(const Standard_Integer theX,
const Standard_Integer theY) const
Handle_NIS_InteractiveObject NIS_View::Pick (const Standard_Integer theX,
const Standard_Integer theY)
{
// Find the ray passing through the clicked point in the view window.
Standard_Real anX, anY, aZ, anOver;
@ -381,20 +594,30 @@ Handle_NIS_InteractiveObject NIS_View::Pick
Handle_NIS_InteractiveObject NIS_View::Pick
(const gp_Ax1& theAxis,
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());
Handle(NIS_InteractiveObject) aSelected, aTmpSel;
LstDetected aDetected;
NCollection_List<NIS_InteractiveContext *>::Iterator anIterC (myContexts);
for (; anIterC.More(); anIterC.Next()) {
const Standard_Real aDist =
anIterC.Value()->selectObject (aTmpSel, theAxis, theOver,
anIterC.Value()->selectObject (aTmpSel, aDetected, theAxis, theOver,
isOnlySelectable);
if (aDist < aDistance) {
aDistance = aDist;
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;
}

View File

@ -11,6 +11,10 @@
#include <V3d_OrthographicView.hxx>
#include <Standard_DefineHandle.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 gp_Ax1;
@ -58,9 +62,49 @@ class NIS_View : public V3d_OrthographicView
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.
@ -80,21 +124,30 @@ class NIS_View : public V3d_OrthographicView
*/
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
* the coordinates theX, theY.
* @param theX
* X coordinate of the view window
* @param theX
* @param theY
* X coordinate of the view window
* @param isForceMult
* True if the effect of multi-Selection should be forced (e.g., when Shift
* is pressed).
* @param theRedraw
* True to redraw view automatically (default value).
*/
Standard_EXPORT void Select (const Standard_Integer theX,
const Standard_Integer theY,
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
@ -114,6 +167,8 @@ class NIS_View : public V3d_OrthographicView
* 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 Standard_Integer theXmin,
const Standard_Integer theYmin,
@ -122,7 +177,35 @@ class NIS_View : public V3d_OrthographicView
const Standard_Boolean isForceMult
= Standard_False,
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
@ -138,7 +221,7 @@ class NIS_View : public V3d_OrthographicView
*/
Standard_EXPORT Handle_NIS_InteractiveObject
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
@ -148,7 +231,7 @@ class NIS_View : public V3d_OrthographicView
* 3D axis for objects selection
* @param theOver
* Overlap for the selecting axis
* @param isOnlySelectable
* @param isOnlySel
* If False, any displayed object can be picked, otherwise only selectable
* ones.
* @return
@ -156,9 +239,21 @@ class NIS_View : public V3d_OrthographicView
* all contexts attached to this View.
*/
Standard_EXPORT Handle_NIS_InteractiveObject
Pick (const gp_Ax1& theAxis,
const Standard_Real theOver,
const Standard_Boolean isOnlySelectable) const;
Pick (const gp_Ax1& theAxis,
const Standard_Real theOver,
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 METHODS ----------
@ -182,6 +277,10 @@ class NIS_View : public V3d_OrthographicView
NCollection_List<NIS_InteractiveContext *> myContexts;
Handle_NIS_InteractiveObject myDynHilighted;
Standard_Boolean myIsTopHilight : 1;
Standard_Boolean myDoHilightSelected : 1;
NCollection_Vector<NIS_InteractiveObject *> myDetected;
TColStd_PackedMapOfInteger myExListId;
friend class NIS_InteractiveContext;

View File

@ -438,12 +438,12 @@ void ViewerTest::Clear()
} else if (it.Key1()->IsKind(STANDARD_TYPE(NIS_InteractiveObject))) {
const Handle(NIS_InteractiveObject) anObj =
Handle(NIS_InteractiveObject)::DownCast (it.Key1());
TheNISContext()->Remove(anObj,Standard_False);
TheNISContext()->Remove(anObj);
}
it.Next();
}
TheAISContext()->UpdateCurrentViewer();
TheNISContext()->UpdateViews();
// TheNISContext()->UpdateViews();
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))) {
const Handle(NIS_InteractiveObject) aShape =
Handle(NIS_InteractiveObject)::DownCast(it.Key1());
TheNISContext()->Erase(aShape,Standard_False);
TheNISContext()->Erase(aShape);
}
it.Next();
}
@ -1407,14 +1407,14 @@ static int VDonly2(Draw_Interpretor& , Standard_Integer argc, const char** argv)
Handle(AIS_InteractiveObject)::DownCast (anObj);
TheAISContext()->Display(aShape, Standard_False);
} else if (anObj->IsKind(STANDARD_TYPE(NIS_InteractiveObject))) {
const Handle(NIS_InteractiveObject) aShape =
Handle(NIS_InteractiveObject) aShape =
Handle(NIS_InteractiveObject)::DownCast (anObj);
TheNISContext()->Display(aShape, 0L, Standard_False);
TheNISContext()->Display(aShape);
}
}
}
TheAISContext() ->UpdateCurrentViewer();
TheNISContext() ->UpdateViews();
// TheNISContext() ->UpdateViews();
}
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))) {
const Handle(NIS_InteractiveObject) aShape =
Handle(NIS_InteractiveObject)::DownCast(it.Key1());
TheNISContext()->Erase(aShape,Standard_False);
TheNISContext()->Erase(aShape);
}
it.Next();
}
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))) {
const Handle(NIS_InteractiveObject) aShape =
Handle(NIS_InteractiveObject)::DownCast (anObj);
TheNISContext()->Erase(aShape,Standard_False);
TheNISContext()->Erase(aShape);
}
}
}
TheAISContext() ->UpdateCurrentViewer();
TheNISContext() ->UpdateViews();
// TheNISContext() ->UpdateViews();
}
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))) {
const Handle(NIS_InteractiveObject) aShape =
Handle(NIS_InteractiveObject)::DownCast(it.Key1());
TheNISContext()->Erase(aShape,Standard_False);
TheNISContext()->Erase(aShape);
}
it.Next();
}
TheAISContext() ->UpdateCurrentViewer();
TheNISContext() ->UpdateViews();
// TheNISContext() ->UpdateViews();
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))) {
const Handle(NIS_InteractiveObject) aShape =
Handle(NIS_InteractiveObject)::DownCast(it.Key1());
TheNISContext()->Erase(aShape,Standard_False);
TheNISContext()->Erase(aShape);
}
it.Next();
}
@ -1574,14 +1574,14 @@ static int VDisplayAll( Draw_Interpretor& di, Standard_Integer argc, const char*
Handle(AIS_InteractiveObject)::DownCast(it.Key1());
TheAISContext()->Display(aShape, Standard_False);
} else if (it.Key1()->IsKind(STANDARD_TYPE(NIS_InteractiveObject))) {
const Handle(NIS_InteractiveObject) aShape =
Handle(NIS_InteractiveObject) aShape =
Handle(NIS_InteractiveObject)::DownCast(it.Key1());
TheNISContext()->Display(aShape, 0L, Standard_False);
TheNISContext()->Display(aShape);
}
it.Next();
}
TheAISContext() ->UpdateCurrentViewer();
TheNISContext() ->UpdateViews();
// TheNISContext() ->UpdateViews();
}
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))) {
Handle(NIS_InteractiveObject) aShape =
Handle(NIS_InteractiveObject)::DownCast(anObj);
TheNISContext()->Display(aShape, 0L, Standard_False);
TheNISContext()->Display(aShape);
}
}
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
TheAISContext()->UpdateCurrentViewer();
TheNISContext()->UpdateViews();
// TheNISContext()->UpdateViews();
return 0;
}