OCC22144 NIS performance and memory usage update
authorAGV <>
Thu, 19 May 2011 10:30:28 +0000 (10:30 +0000)
committerbugmaster <bugmaster@opencascade.com>
Mon, 5 Mar 2012 15:28:38 +0000 (19:28 +0400)
24 files changed:
src/NIS/FILES
src/NIS/NIS_Allocator.cxx [new file with mode: 0644]
src/NIS/NIS_Allocator.hxx [new file with mode: 0644]
src/NIS/NIS_DrawList.cxx
src/NIS/NIS_DrawList.hxx
src/NIS/NIS_Drawer.cxx
src/NIS/NIS_Drawer.hxx
src/NIS/NIS_InteractiveContext.cxx
src/NIS/NIS_InteractiveContext.hxx
src/NIS/NIS_InteractiveObject.cxx
src/NIS/NIS_InteractiveObject.hxx
src/NIS/NIS_ObjectsIterator.cxx
src/NIS/NIS_ObjectsIterator.hxx
src/NIS/NIS_Surface.cxx
src/NIS/NIS_Surface.hxx
src/NIS/NIS_SurfaceDrawer.cxx
src/NIS/NIS_SurfaceDrawer.hxx
src/NIS/NIS_Triangulated.cxx
src/NIS/NIS_Triangulated.hxx
src/NIS/NIS_TriangulatedDrawer.cxx
src/NIS/NIS_TriangulatedDrawer.hxx
src/NIS/NIS_View.cxx
src/NIS/NIS_View.hxx
src/ViewerTest/ViewerTest.cxx

index 74ede22..1bad545 100755 (executable)
@@ -1,5 +1,7 @@
 EXTERNLIB
 FILES
+NIS_Allocator.cxx
+NIS_Allocator.hxx
 NIS_Drawer.cxx
 NIS_Drawer.hxx
 NIS_DrawList.cxx
diff --git a/src/NIS/NIS_Allocator.cxx b/src/NIS/NIS_Allocator.cxx
new file mode 100644 (file)
index 0000000..0f7cb0c
--- /dev/null
@@ -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);
+  }
+}
diff --git a/src/NIS/NIS_Allocator.hxx b/src/NIS/NIS_Allocator.hxx
new file mode 100644 (file)
index 0000000..927be4b
--- /dev/null
@@ -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
index 9123971..dd09873 100755 (executable)
@@ -4,6 +4,7 @@
 // Copyright: Open Cascade 2007
 
 #include <NIS_Drawer.hxx>
+#include <NIS_View.hxx>
 
 #ifdef WNT
 #include <windows.h>
 //=======================================================================
 
 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();
+}
index 77468b8..5d978a6 100755 (executable)
 #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;
 };
 
index c861c3d..e1d793c 100755 (executable)
@@ -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;
 }
 
@@ -79,6 +91,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;
       }
     }
@@ -159,6 +213,28 @@ void NIS_Drawer::SetUpdated (const DrawType theType1,
 }
 
 //=======================================================================
+//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);
 }
index 0639ae5..81d8f18 100755 (executable)
@@ -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
index d58ad6e..828dfcd 100755 (executable)
@@ -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);
+  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;
 
-    // Display Object as Normal or Transparent if it has been hidden
+  // 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 : UpdateViews
+//function : RebuildViews
 //purpose  : 
 //=======================================================================
 
-void NIS_InteractiveContext::UpdateViews ()
+void NIS_InteractiveContext::RebuildViews ()
 {
-  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);
-    }
+  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();
   }
-  NCollection_List<Handle_NIS_View>::Iterator anIterV (myViews);
+}
+
+//=======================================================================
+//function : UpdateViews
+//purpose  : Only repaint the views refreshing their presentations only for
+//           those drawers that have been marked as updated.
+//=======================================================================
+
+void NIS_InteractiveContext::UpdateViews ()
+{
+  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);
@@ -695,24 +744,89 @@ Standard_Boolean NIS_InteractiveContext::selectObjects
 }
 
 //=======================================================================
+//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);
+    }
+  }
+}
index da4b3a2..29b8360 100755 (executable)
@@ -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>
 
 
 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,7 +195,8 @@ class NIS_InteractiveContext : public Standard_Transient
    * this method should follow the creation of an InteractiveObject instance
    * before it can be displayed.
    * @param theObj
-   *   Interactive object instance.
+   *   <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
@@ -173,12 +208,36 @@ 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,
+  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
+   *   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 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.
    * @param theObj
    *   Interactive object instance. Must be already added to this context.
@@ -209,46 +268,34 @@ 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
    *   <tt>[out]</tt> Bounding box, updated (not reinitialized!) by the object
@@ -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,10 +520,59 @@ 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.
    */ 
   NCollection_Vector <Handle_NIS_InteractiveObject> myObjects;
@@ -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,
@@ -501,19 +610,14 @@ 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;
index 0d093ae..8a980fe 100755 (executable)
@@ -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: "
@@ -114,6 +132,44 @@ const Bnd_B3f& NIS_InteractiveObject::GetBox ()
 }
 
 //=======================================================================
+//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  : 
 //=======================================================================
@@ -126,6 +182,19 @@ Standard_Boolean NIS_InteractiveObject::Intersect (const Bnd_B3f&,
 }
 
 //=======================================================================
+//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);
       }
     }
   }
index 192d202..806c82a 100755 (executable)
  * 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
  * @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.
@@ -184,6 +247,23 @@ class NIS_InteractiveObject : public Standard_Transient
   { 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
    *   The line or ray in 3D space.
@@ -228,6 +308,32 @@ class NIS_InteractiveObject : public Standard_Transient
                                          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.
    */
   inline void             SetAttribute  (void * theAttributePtr)
@@ -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;
 
index fbeec2b..b78527c 100755 (executable)
@@ -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;
+}
index d58f926..58421de 100755 (executable)
@@ -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.
index abb15a8..943bcbc 100755 (executable)
@@ -6,31 +6,59 @@
 #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);
+}
+
+//=======================================================================
+//function : NIS_Surface
+//purpose  : 
+//=======================================================================
+
+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();  
 }
 
 //=======================================================================
@@ -38,14 +66,16 @@ 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(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);  
 }
 
 //=======================================================================
@@ -242,6 +358,16 @@ NIS_Surface::NIS_Surface
 
 NIS_Surface::~NIS_Surface ()
 {
+  Clear();
+}
+
+//=======================================================================
+//function : Clear
+//purpose  : 
+//=======================================================================
+
+void NIS_Surface::Clear ()
+{
   if (myNNodes) {
     myNNodes = 0;
     myAlloc->Free(mypNodes);
@@ -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());
index 6882115..01d16e4 100755 (executable)
@@ -15,29 +15,48 @@ 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
@@ -45,6 +64,18 @@ public:
   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.
    */
   inline Standard_Integer           NNodes      () const { return myNNodes; }
@@ -55,6 +86,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
    *   pointer to array of 3 Standard_ShortReal values (X,Y,Z coordinates)
@@ -77,6 +113,18 @@ public:
   }
 
   /**
+   * 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
    *   pointer to array of 3 Standard_ShortReal values (X,Y,Z coordinates)
@@ -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,9 +217,33 @@ 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.
    */
   Standard_EXPORT virtual void computeBox     ();
@@ -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
index dc9dba4..8c69245 100755 (executable)
 #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);
+}
+
index e815118..a43e9a8 100755 (executable)
@@ -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;
 
index 8c7c677..67c1641 100755 (executable)
 IMPLEMENT_STANDARD_HANDLE  (NIS_Triangulated, NIS_InteractiveObject)
 IMPLEMENT_STANDARD_RTTIEXT (NIS_Triangulated, NIS_InteractiveObject)
 
-inline Handle(NIS_TriangulatedDrawer) defaultDrawer ()
+static Standard_Real aTolConf = Precision::Confusion() * 0.0001;
+
+/**
+ * Checking the given value if it is considerably greater than zero.
+ */
+static inline Standard_Boolean IsPositive (const Standard_Real theVal)
 {
-  return new NIS_TriangulatedDrawer (Quantity_NOC_RED);
+  return (theVal > aTolConf);
+}
+
+/**
+ * Compute the size in bytes of an index array.
+ */ 
+static inline Standard_Size    NBytesInd  (const Standard_Integer nInd,
+                                           const unsigned int     theIndType)
+{
+  Standard_Size nBytes = static_cast<Standard_Size>(nInd);
+  if (theIndType) {
+    nBytes *= 2;
+    if (theIndType > 1u)
+      nBytes *= 2;
+  }
+  return nBytes;
 }
 
 //=======================================================================
@@ -25,18 +45,23 @@ inline Handle(NIS_TriangulatedDrawer) defaultDrawer ()
 
 NIS_Triangulated::NIS_Triangulated
                         (const Standard_Integer                   nNodes,
+                         const Standard_Boolean                   is2D,
                          const Handle(NCollection_BaseAllocator)& theAlloc)
-  : myType              (Type_None),
+  : myAlloc             (0L),
+    myType              (Type_None),
     mypNodes            (0L),
     mypTriangles        (0L),
     mypLines            (0L),
     mypPolygons         (0L),
     myNNodes            (0),
     myNTriangles        (0),
-    myNPolygons         (0),
     myNLineNodes        (0),
-    myAlloc             (0L),
-    myIsDrawPolygons    (Standard_False)
+    myNPolygons         (0u),
+    myIsDrawPolygons    (Standard_False),
+    myIsCloned          (Standard_False),
+    myIndexType         (2u),
+    myNodeCoord         (is2D ? 2 : 3),
+    myPolygonType       (static_cast<unsigned int>(Polygon_Default))
 {
   
   if (theAlloc.IsNull())
@@ -69,14 +94,21 @@ void NIS_Triangulated::Clear ()
     mypLines = 0L;
   }
   if (myNPolygons) {
-    for (Standard_Integer i = 0; i < myNPolygons; i++)
+    for (unsigned int i = 0; i < myNPolygons; i++)
       myAlloc->Free(mypPolygons[i]);
     myAlloc->Free(mypPolygons);
-    myNPolygons = 0;
+    myNPolygons = 0u;
     mypPolygons = 0L;
   }
   myType = Type_None;
   myIsDrawPolygons = Standard_False;
+  myPolygonType = static_cast<unsigned int>(Polygon_Default);
+  if (GetDrawer().IsNull() == Standard_False) {
+    GetDrawer()->SetUpdated(NIS_Drawer::Draw_Normal,
+                            NIS_Drawer::Draw_Top,
+                            NIS_Drawer::Draw_Transparent,
+                            NIS_Drawer::Draw_Hilighted);
+  }
 }
 
 //=======================================================================
@@ -92,11 +124,11 @@ void NIS_Triangulated::SetPolygonsPrs (const Standard_Integer nPolygons,
   else {
     myType |= Type_Polygons;
     if (myNPolygons) {
-      for (Standard_Integer i = 0; i < myNPolygons; i++)
+      for (unsigned int i = 0; i < myNPolygons; i++)
         myAlloc->Free(mypPolygons[i]);
       myAlloc->Free(mypPolygons);
     }
-    myNPolygons = nPolygons;
+    myNPolygons = static_cast<unsigned int>(nPolygons);
     mypPolygons = static_cast<Standard_Integer **>
       (myAlloc->Allocate(sizeof(Standard_Integer *)*nPolygons));
     allocateNodes (nNodes);
@@ -117,10 +149,11 @@ void NIS_Triangulated::SetTriangulationPrs (const Standard_Integer nTri,
     myType |= Type_Triangulation;
     if (myNTriangles)
       myAlloc->Free(mypTriangles);
-    myNTriangles = nTri;
-    mypTriangles = static_cast<Standard_Integer *>
-      (myAlloc->Allocate(sizeof(Standard_Integer)*3*nTri));
     allocateNodes (nNodes);
+
+    myNTriangles = nTri;
+    const Standard_Size nBytes = NBytesInd(3 * nTri, myIndexType);
+    mypTriangles = static_cast<Standard_Integer *> (myAlloc->Allocate(nBytes));
   }
 }
 
@@ -142,10 +175,11 @@ void NIS_Triangulated::SetLinePrs (const Standard_Integer nPoints,
     if (myNLineNodes)
       myAlloc->Free(mypLines);
     myType &= ~Type_Segments;
-    myNLineNodes = nPoints;
-    mypLines = static_cast<Standard_Integer *>
-      (myAlloc->Allocate(sizeof(Standard_Integer)*nPoints));
     allocateNodes (nNodes);
+
+    myNLineNodes = nPoints;
+    const Standard_Size nBytes = NBytesInd(nPoints, myIndexType);
+    mypLines = static_cast<Standard_Integer *> (myAlloc->Allocate(nBytes));
   }
 }
 
@@ -164,10 +198,11 @@ void NIS_Triangulated::SetSegmentPrs (const Standard_Integer nSegments,
     if (myNLineNodes)
       myAlloc->Free(mypLines);
     myType &= ~(Type_Line | Type_Loop);
-    myNLineNodes = nSegments*2;
-    mypLines = static_cast<Standard_Integer *>
-      (myAlloc->Allocate(sizeof(Standard_Integer)*myNLineNodes));
     allocateNodes (nNodes);
+
+    myNLineNodes = nSegments*2;
+    const Standard_Size nBytes = NBytesInd(myNLineNodes, myIndexType);
+    mypLines = static_cast<Standard_Integer *> (myAlloc->Allocate(nBytes));
   }
 }
 
@@ -186,9 +221,14 @@ NIS_Triangulated::~NIS_Triangulated ()
 //purpose  : 
 //=======================================================================
 
-Handle(NIS_Drawer) NIS_Triangulated::DefaultDrawer () const
+NIS_Drawer * NIS_Triangulated::DefaultDrawer (NIS_Drawer * theDrawer) const
 {
-  return defaultDrawer();
+  NIS_TriangulatedDrawer * aDrawer =
+    theDrawer ? static_cast<NIS_TriangulatedDrawer *>(theDrawer)
+              : new NIS_TriangulatedDrawer (Quantity_NOC_RED);
+  aDrawer->myIsDrawPolygons = myIsDrawPolygons;
+  aDrawer->myPolygonType = myPolygonType;
+  return aDrawer;
 }
 
 //=======================================================================
@@ -198,16 +238,21 @@ Handle(NIS_Drawer) NIS_Triangulated::DefaultDrawer () const
 
 void NIS_Triangulated::ComputeBox (Bnd_B3f&                  theBox,
                                    const Standard_Integer    nNodes,
-                                   const Standard_ShortReal* pNodes)
+                                   const Standard_ShortReal* pNodes,
+                                   const Standard_Integer    nCoord)
 {
   theBox.Clear();
   if (nNodes > 0) {
     Standard_ShortReal aBox[6] = {
-      pNodes[0], pNodes[1], pNodes[2],
-      pNodes[0], pNodes[1], pNodes[2]
+      pNodes[0], pNodes[1], 0.,
+      pNodes[0], pNodes[1], 0.
     };
+    if (nCoord > 2) {
+      aBox[2] = pNodes[2];
+      aBox[5] = pNodes[2];
+    }
     for (Standard_Integer i = 1; i < nNodes; i++) {
-      const Standard_ShortReal * pNode = &pNodes[i*3];
+      const Standard_ShortReal * pNode = &pNodes[i * nCoord];
       if (aBox[0] > pNode[0])
         aBox[0] = pNode[0];
       else if (aBox[3] < pNode[0])
@@ -216,10 +261,12 @@ void NIS_Triangulated::ComputeBox (Bnd_B3f&                  theBox,
         aBox[1] = pNode[1];
       else if (aBox[4] < pNode[1])
         aBox[4] = pNode[1];
-      if (aBox[2] > pNode[2])
-        aBox[2] = pNode[2];
-      else if (aBox[5] < pNode[2])
-        aBox[5] = pNode[2];
+      if (nCoord > 2) {
+        if (aBox[2] > pNode[2])
+          aBox[2] = pNode[2];
+        else if (aBox[5] < pNode[2])
+          aBox[5] = pNode[2];
+      }
     }
     theBox.Add (gp_XYZ (Standard_Real(aBox[0]),
                         Standard_Real(aBox[1]),
@@ -237,7 +284,7 @@ void NIS_Triangulated::ComputeBox (Bnd_B3f&                  theBox,
 
 void NIS_Triangulated::computeBox ()
 {
-  ComputeBox (myBox, myNNodes, mypNodes);
+  ComputeBox (myBox, myNNodes, mypNodes, myNodeCoord);
 }
 
 //=======================================================================
@@ -250,10 +297,12 @@ void NIS_Triangulated::SetNode       (const Standard_Integer  ind,
 {
   if (ind >= myNNodes)
     Standard_OutOfRange::Raise ("NIS_Triangulated::SetNode");
-  Standard_ShortReal * pNode = &mypNodes[3*ind];
+  Standard_ShortReal * pNode = &mypNodes[myNodeCoord * ind];
   pNode[0] = Standard_ShortReal(thePnt.X());
   pNode[1] = Standard_ShortReal(thePnt.Y());
-  pNode[2] = Standard_ShortReal(thePnt.Z());
+  if (myNodeCoord > 2)
+    pNode[2] = Standard_ShortReal(thePnt.Z());
+  setIsUpdateBox(Standard_True);
 }
 
 //=======================================================================
@@ -266,10 +315,12 @@ void NIS_Triangulated::SetNode       (const Standard_Integer  ind,
 {
   if (ind >= myNNodes)
     Standard_OutOfRange::Raise ("NIS_Triangulated::SetNode");
-  Standard_ShortReal * pNode = &mypNodes[3*ind];
+  Standard_ShortReal * pNode = &mypNodes[myNodeCoord * ind];
   pNode[0] = Standard_ShortReal(thePnt.X());
   pNode[1] = Standard_ShortReal(thePnt.Y());
-  pNode[2] = 0.f;
+  if (myNodeCoord > 2)
+    pNode[2] = 0.f;
+  setIsUpdateBox(Standard_True);
 }
 
 //=======================================================================
@@ -284,10 +335,33 @@ void NIS_Triangulated::SetTriangle   (const Standard_Integer  ind,
 {
   if (ind >= myNTriangles)
     Standard_OutOfRange::Raise ("NIS_Triangulated::SetTriangle");
-  Standard_Integer * pTri = &mypTriangles[3*ind];
-  pTri[0] = iNode0;
-  pTri[1] = iNode1;
-  pTri[2] = iNode2;
+  switch (myIndexType) {
+    case 0: // 8bit
+    {
+      unsigned char * pTri =
+        reinterpret_cast<unsigned char *>(mypTriangles) + (3 * ind);
+      pTri[0] = static_cast<unsigned char>(iNode0);
+      pTri[1] = static_cast<unsigned char>(iNode1);
+      pTri[2] = static_cast<unsigned char>(iNode2);
+    }
+    break;
+    case 1: // 16bit
+    {
+      unsigned short * pTri =
+        reinterpret_cast<unsigned short *>(mypTriangles) + (3 * ind);
+      pTri[0] = static_cast<unsigned short>(iNode0);
+      pTri[1] = static_cast<unsigned short>(iNode1);
+      pTri[2] = static_cast<unsigned short>(iNode2);
+    }
+    break;
+    default: // 32bit
+    {
+      Standard_Integer * pTri = &mypTriangles[3*ind];
+      pTri[0] = iNode0;
+      pTri[1] = iNode1;
+      pTri[2] = iNode2;
+    }
+  }
 }
 
 //=======================================================================
@@ -300,7 +374,143 @@ void NIS_Triangulated::SetLineNode      (const Standard_Integer ind,
 {
   if (ind >= myNLineNodes)
     Standard_OutOfRange::Raise ("NIS_Triangulated::SetTriangle");
-  mypLines[ind] = iNode;
+  switch (myIndexType) {
+    case 0: // 8bit
+    {
+      unsigned char * pInd =
+        reinterpret_cast<unsigned char *>(mypLines) + ind;
+      pInd[0] = static_cast<unsigned char>(iNode);
+    }
+    break;
+    case 1: // 16bit
+    {
+      unsigned short * pInd =
+        reinterpret_cast<unsigned short *>(mypLines) + ind;
+      pInd[0] = static_cast<unsigned short>(iNode);
+    }
+    break;
+    default: // 32bit
+      mypLines[ind] = iNode;
+  }
+}
+
+//=======================================================================
+//function : SetPolygonNode
+//purpose  : 
+//=======================================================================
+
+void NIS_Triangulated::SetPolygonNode         (const Standard_Integer indPoly,
+                                               const Standard_Integer ind,
+                                               const Standard_Integer iNode)
+{
+  if (indPoly >= static_cast<Standard_Integer>(myNPolygons))
+    Standard_OutOfRange::Raise ("NIS_Triangulated::SetPolygonNode");
+    
+  Standard_Integer * aPoly  = mypPolygons[indPoly];
+  switch (myIndexType) {
+  case 0: // 8bit
+  {
+    unsigned char aNNode =  * (reinterpret_cast<unsigned char *>(aPoly));
+    if (static_cast<unsigned char>(ind) >= aNNode)
+      Standard_OutOfRange::Raise ("NIS_Triangulated::SetPolygonNode");
+
+    unsigned char * pInd =
+      reinterpret_cast<unsigned char *>(aPoly) + ind + 1;
+    pInd[0] = static_cast<unsigned char>(iNode);   
+  }
+  break;
+  case 1: // 16bit
+  {
+    unsigned short aNNode =  * (reinterpret_cast<unsigned short *>(aPoly));
+    if (static_cast<unsigned short>(ind) >= aNNode)
+      Standard_OutOfRange::Raise ("NIS_Triangulated::SetPolygonNode");
+
+    unsigned short * pInd =
+      reinterpret_cast<unsigned short *>(aPoly) + ind + 1;
+    pInd[0] = static_cast<unsigned short>(iNode);
+  }
+  break;
+  default: // 32bit
+    if (ind >= aPoly[0])
+      Standard_OutOfRange::Raise ("NIS_Triangulated::SetPolygonNode");
+    aPoly[ind + 1] = iNode;
+  }
+}
+
+//=======================================================================
+//function : NPolygonNodes
+//purpose  : 
+//=======================================================================
+Standard_Integer NIS_Triangulated::NPolygonNodes
+                                         (const Standard_Integer indPoly)const
+{
+  Standard_Integer aResult(0);
+  if (indPoly >= static_cast<Standard_Integer>(myNPolygons))
+    Standard_OutOfRange::Raise ("NIS_Triangulated::PolygonNode");
+  Standard_Integer * aPoly  = mypPolygons[indPoly];
+  switch (myIndexType) {
+    case 0: // 8bit
+    {
+      unsigned char aNNode =  * (reinterpret_cast<unsigned char *>(aPoly));
+      aResult = static_cast<Standard_Integer>(aNNode);
+    }
+    break;
+    case 1: // 16bit
+    {
+      unsigned short aNNode =  * (reinterpret_cast<unsigned short *>(aPoly));
+      aResult = static_cast<Standard_Integer>(aNNode);
+    }
+    break;
+    default: // 32bit
+    {
+      aResult = aPoly[0];
+    }
+  }
+  return aResult;
+}
+
+//=======================================================================
+//function : PolygonNode
+//purpose  : 
+//=======================================================================
+
+Standard_Integer NIS_Triangulated::PolygonNode 
+                                            (const Standard_Integer indPoly,
+                                             const Standard_Integer ind)const
+{
+  Standard_Integer aResult(-1);
+  if (indPoly >= static_cast<Standard_Integer>(myNPolygons))
+    Standard_OutOfRange::Raise ("NIS_Triangulated::PolygonNode");
+  const Standard_Integer * aPoly  = mypPolygons[indPoly];
+  switch (myIndexType) {
+    case 0: // 8bit
+    {
+      const unsigned char * pInd =
+        reinterpret_cast<const unsigned char *>(aPoly);
+      if (static_cast<unsigned char>(ind) >= pInd[0])
+        Standard_OutOfRange::Raise ("NIS_Triangulated::PolygonNode");
+
+      aResult = static_cast<Standard_Integer>(pInd[ind + 1]);
+    }
+    break;
+    case 1: // 16bit
+    {
+      const unsigned short * pInd =
+        reinterpret_cast<const unsigned short *>(aPoly);
+      if (static_cast<unsigned short>(ind) >= pInd[0])
+        Standard_OutOfRange::Raise ("NIS_Triangulated::PolygonNode");
+
+      aResult = static_cast<Standard_Integer>(pInd[ind + 1]);
+    }
+    break;
+    default: // 32bit
+    {
+      if (ind >= aPoly[0])
+        Standard_OutOfRange::Raise ("NIS_Triangulated::PolygonNode");
+      aResult = aPoly[ind + 1];
+    }
+  }
+  return aResult;
 }
 
 //=======================================================================
@@ -308,16 +518,36 @@ void NIS_Triangulated::SetLineNode      (const Standard_Integer ind,
 //purpose  : 
 //=======================================================================
 
-Standard_Integer* NIS_Triangulated::SetPolygon (const Standard_Integer  ind,
-                                                const Standard_Integer  theSz)
+void NIS_Triangulated::SetPolygon (const Standard_Integer  ind,
+                                   const Standard_Integer  theSz)
 {
-  if (ind >= myNPolygons)
+  if (ind >= static_cast<Standard_Integer>(myNPolygons))
     Standard_OutOfRange::Raise ("NIS_Triangulated::SetPolygon");
-  Standard_Integer * anArray  = static_cast <Standard_Integer *>
-    (myAlloc->Allocate (sizeof(Standard_Integer) * (theSz+1)));
-  mypPolygons[ind] = anArray;
-  anArray[0] = theSz;
-  return &anArray[1];
+  switch (myIndexType) {
+    case 0: // 8bit
+    {
+      unsigned char * anArray  = static_cast <unsigned char *>
+        (myAlloc->Allocate (sizeof(unsigned char) * (theSz+1)));
+      mypPolygons[ind] = reinterpret_cast<Standard_Integer *> (anArray);
+      anArray[0] = static_cast<unsigned char>(theSz);
+    }
+    break;
+    case 1: // 16bit
+    {
+      unsigned short * anArray  = static_cast <unsigned short *>
+        (myAlloc->Allocate (sizeof(unsigned short) * (theSz+1)));
+      mypPolygons[ind] = reinterpret_cast<Standard_Integer *> (anArray);
+      anArray[0] = static_cast<unsigned short>(theSz);
+    }
+    break;
+    default: // 32bit
+    {
+      Standard_Integer * anArray  = static_cast <Standard_Integer *>
+        (myAlloc->Allocate (sizeof(Standard_Integer) * (theSz+1)));
+      mypPolygons[ind] = anArray;
+      anArray[0] = theSz;
+    }
+  } 
 }
 
 //=======================================================================
@@ -325,18 +555,42 @@ Standard_Integer* NIS_Triangulated::SetPolygon (const Standard_Integer  ind,
 //purpose  : 
 //=======================================================================
 
-void NIS_Triangulated::SetDrawPolygons (const Standard_Boolean isDrawPolygons,
-                                        const Standard_Boolean isUpdateViews)
+void NIS_Triangulated::SetDrawPolygons (const Standard_Boolean isDrawPolygons)
 {
-  if (myIsDrawPolygons != isDrawPolygons) {
-    Handle(NIS_TriangulatedDrawer) aDrawer = defaultDrawer();
-    aDrawer->Assign (GetDrawer());
-    aDrawer->myIsDrawPolygons = isDrawPolygons;
-    SetDrawer (aDrawer);
+  if (GetDrawer().IsNull())
     myIsDrawPolygons = isDrawPolygons;
+  else {
+    if (myIsDrawPolygons != isDrawPolygons) {
+      const Handle(NIS_TriangulatedDrawer) aDrawer =
+        static_cast<NIS_TriangulatedDrawer *>(DefaultDrawer(0L));
+      aDrawer->Assign (GetDrawer());
+      aDrawer->myIsDrawPolygons = isDrawPolygons;
+      SetDrawer (aDrawer);
+      myIsDrawPolygons = isDrawPolygons;
+    }
+  }
+}
+
+//=======================================================================
+//function : SetPolygonType
+//purpose  : Set the type of polygon rendering
+//=======================================================================
+
+void NIS_Triangulated::SetPolygonType
+                                (const NIS_Triangulated::PolygonType theType)
+{
+  if (GetDrawer().IsNull())
+    myPolygonType = static_cast<unsigned int>(theType);
+  else {
+    if (myPolygonType != static_cast<unsigned int>(theType)) {
+      const Handle(NIS_TriangulatedDrawer) aDrawer =
+        static_cast<NIS_TriangulatedDrawer *>(DefaultDrawer(0L));
+      aDrawer->Assign (GetDrawer());
+      aDrawer->myPolygonType = theType;
+      SetDrawer (aDrawer);
+      myPolygonType = static_cast<unsigned int>(theType);
+    }
   }
-  if (isUpdateViews)
-    GetDrawer()->GetContext()->UpdateViews();
 }
 
 //=======================================================================
@@ -344,16 +598,15 @@ void NIS_Triangulated::SetDrawPolygons (const Standard_Boolean isDrawPolygons,
 //purpose  : Set the normal color for presentation.
 //=======================================================================
 
-void NIS_Triangulated::SetColor (const Quantity_Color&  theColor,
-                                 const Standard_Boolean isUpdateViews)
+void NIS_Triangulated::SetColor (const Quantity_Color&  theColor)
 {
-  Handle(NIS_TriangulatedDrawer) aDrawer = defaultDrawer();
+  const Handle(NIS_TriangulatedDrawer) aDrawer =
+    static_cast<NIS_TriangulatedDrawer *>(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);
-  if (isUpdateViews)
-    GetDrawer()->GetContext()->UpdateViews();
 }
 
 //=======================================================================
@@ -361,15 +614,16 @@ void NIS_Triangulated::SetColor (const Quantity_Color&  theColor,
 //purpose  : Get Normal, Transparent or Hilighted color of the presentation.
 //=======================================================================
 
-Quantity_Color NIS_Triangulated::GetColor (const NIS_Drawer::DrawType theDrawType) const
+Quantity_Color NIS_Triangulated::GetColor
+                        (const NIS_Drawer::DrawType theDrawType) const
 {
-    Handle(NIS_TriangulatedDrawer) aDrawer = 
-        Handle(NIS_TriangulatedDrawer)::DownCast( GetDrawer() );
-    if (aDrawer.IsNull() == Standard_False)
-    {
-        return aDrawer->myColor[theDrawType];
-    }
-    return Quantity_Color(); // return null color object
+  Handle(NIS_TriangulatedDrawer) aDrawer = 
+    Handle(NIS_TriangulatedDrawer)::DownCast( GetDrawer() );
+  if (aDrawer.IsNull() == Standard_False)
+  {
+    return aDrawer->myColor[theDrawType];
+  }
+  return Quantity_Color(); // return null color object
 }
 
 //=======================================================================
@@ -377,15 +631,13 @@ Quantity_Color NIS_Triangulated::GetColor (const NIS_Drawer::DrawType theDrawTyp
 //purpose  : Set the color for hilighted presentation.
 //=======================================================================
 
-void NIS_Triangulated::SetHilightColor (const Quantity_Color&  theColor,
-                                        const Standard_Boolean isUpdateViews)
+void NIS_Triangulated::SetHilightColor (const Quantity_Color&  theColor)
 {
-  Handle(NIS_TriangulatedDrawer) aDrawer = defaultDrawer();
+  const Handle(NIS_TriangulatedDrawer) aDrawer =
+    static_cast<NIS_TriangulatedDrawer *>(DefaultDrawer(0L));
   aDrawer->Assign (GetDrawer());
   aDrawer->myColor[NIS_Drawer::Draw_Hilighted] = theColor;
   SetDrawer (aDrawer);
-  if (isUpdateViews)
-    GetDrawer()->GetContext()->UpdateViews();
 }
 
 //=======================================================================
@@ -393,15 +645,13 @@ void NIS_Triangulated::SetHilightColor (const Quantity_Color&  theColor,
 //purpose  : Set the color for dynamic hilight presentation.
 //=======================================================================
 
-void NIS_Triangulated::SetDynHilightColor(const Quantity_Color&  theColor,
-                                          const Standard_Boolean isUpdateViews)
+void NIS_Triangulated::SetDynHilightColor(const Quantity_Color&  theColor)
 {
-  Handle(NIS_TriangulatedDrawer) aDrawer = defaultDrawer();
+  const Handle(NIS_TriangulatedDrawer) aDrawer =
+    static_cast<NIS_TriangulatedDrawer *>(DefaultDrawer(0L));
   aDrawer->Assign (GetDrawer());
   aDrawer->myColor[NIS_Drawer::Draw_DynHilighted] = theColor;
   SetDrawer (aDrawer);
-  if (isUpdateViews)
-    GetDrawer()->GetContext()->UpdateViews();
 }
 
 //=======================================================================
@@ -409,15 +659,95 @@ void NIS_Triangulated::SetDynHilightColor(const Quantity_Color&  theColor,
 //purpose  : Set the width of line presentations in pixels.
 //=======================================================================
 
-void NIS_Triangulated::SetLineWidth (const Standard_Real    theWidth,
-                                     const Standard_Boolean isUpdateViews)
+void NIS_Triangulated::SetLineWidth (const Standard_Real    theWidth)
 {
-  Handle(NIS_TriangulatedDrawer) aDrawer = defaultDrawer();
+  const Handle(NIS_TriangulatedDrawer) aDrawer =
+    static_cast<NIS_TriangulatedDrawer *>(DefaultDrawer(0L));
   aDrawer->Assign (GetDrawer());
   aDrawer->myLineWidth = (Standard_ShortReal) theWidth;
   SetDrawer (aDrawer);
-  if (isUpdateViews)
-    GetDrawer()->GetContext()->UpdateViews();
+}
+
+//=======================================================================
+//function : Clone
+//purpose  : 
+//=======================================================================
+
+void NIS_Triangulated::Clone (const Handle_NCollection_BaseAllocator& theAlloc,
+                              Handle_NIS_InteractiveObject& theDest) const
+{
+  Handle(NIS_Triangulated) aNewObj;
+  if (theDest.IsNull()) {
+    aNewObj = new (theAlloc) NIS_Triangulated(myNNodes, myNodeCoord == 2,
+                                              theAlloc);
+    aNewObj->myIsCloned = Standard_True;
+    theDest = aNewObj;
+  } else {
+    aNewObj = reinterpret_cast<NIS_Triangulated*> (theDest.operator->());
+    aNewObj->myAlloc = theAlloc.operator->();
+    aNewObj->myNNodes = 0;
+    aNewObj->allocateNodes(myNNodes);
+  }
+  NIS_InteractiveObject::Clone(theAlloc, theDest);
+  if (myNNodes > 0)
+  {
+    // copy nodes
+    memcpy(aNewObj->mypNodes, mypNodes,
+           myNNodes * myNodeCoord * sizeof(Standard_ShortReal));
+    // copy triangles
+    aNewObj->myNTriangles = myNTriangles;
+    if (myNTriangles) {
+      const Standard_Size nBytes = NBytesInd(3 * myNTriangles, myIndexType);
+      aNewObj->mypTriangles = static_cast<Standard_Integer *>
+        (theAlloc->Allocate(nBytes));
+      memcpy(aNewObj->mypTriangles, mypTriangles, nBytes);
+    }
+    // copy lines/segments
+    aNewObj->myNLineNodes = myNLineNodes;
+    if (myNLineNodes) {
+      const Standard_Size nBytes = NBytesInd(myNLineNodes, myIndexType);
+      aNewObj->mypLines = static_cast<Standard_Integer *>
+        (theAlloc->Allocate(nBytes));
+      memcpy(aNewObj->mypLines, mypLines, nBytes);
+    }
+    // copy polygons
+    aNewObj->myNPolygons = myNPolygons;
+    if (myNPolygons) {
+      const Standard_Size nBytes = sizeof(Standard_Integer *)*myNPolygons;
+      aNewObj->mypPolygons = static_cast<Standard_Integer **>
+        (theAlloc->Allocate(nBytes));
+      for (unsigned int i = 0; i < myNPolygons; i++) {
+        const Standard_Integer nNodes = NPolygonNodes(i);
+        const Standard_Size nBytes = NBytesInd(nNodes+1, myIndexType);
+        aNewObj->mypPolygons[i] = static_cast <Standard_Integer *>
+          (theAlloc->Allocate (nBytes));
+        memcpy(aNewObj->mypPolygons[i], mypPolygons[i], nBytes);
+      }
+    }
+  }
+  aNewObj->myType = myType;
+  aNewObj->myIsDrawPolygons = myIsDrawPolygons;
+  aNewObj->myIndexType = myIndexType;
+  aNewObj->myPolygonType = myPolygonType;
+}
+
+//=======================================================================
+//function : Delete
+//purpose  : 
+//=======================================================================
+
+void NIS_Triangulated::Delete () const
+{
+  if (myIsCloned == Standard_False)
+    Standard_Transient::Delete();
+  else {
+    // Call the destructor and then release the memory occupied by the instance.
+    // This is required when the NIS_Triangulated instance is allocated in
+    // the same allocator as its internal arrays.
+    NIS_Triangulated* pThis = const_cast<NIS_Triangulated*>(this);
+    pThis->~NIS_Triangulated();
+    myAlloc->Free(pThis);
+  }
 }
 
 //=======================================================================
@@ -432,12 +762,15 @@ Standard_Boolean NIS_Triangulated::Intersect
 {
   Standard_Boolean aResult (isFullIn);
 
-  if ((myType & Type_Triangulation) && myIsDrawPolygons == Standard_False)
-    for (Standard_Integer iNode = 0; iNode < myNNodes*3; iNode+=3) {
-      gp_XYZ aPnt ((Standard_Real)mypNodes[iNode+0],
-                   (Standard_Real)mypNodes[iNode+1],
-                   (Standard_Real)mypNodes[iNode+2]);
-      theTrf.Transforms(aPnt);
+  if ((myType & Type_Triangulation) && myIsDrawPolygons == Standard_False) {
+    unsigned int iNode = 0;
+    for (; iNode < myNNodes * myNodeCoord; iNode += myNodeCoord)
+    {
+      gp_XYZ aPnt (static_cast<Standard_Real>(mypNodes[iNode+0]),
+                   static_cast<Standard_Real>(mypNodes[iNode+1]), 0.);
+      if (myNodeCoord > 2)
+        aPnt.SetZ (static_cast<Standard_Real>(mypNodes[iNode+2]));
+      theTrf.Transforms (aPnt);
       if (theBox.IsOut (aPnt)) {
         if (isFullIn) {
           aResult = Standard_False;
@@ -450,16 +783,13 @@ Standard_Boolean NIS_Triangulated::Intersect
         }
       }
     }
+  }
   if (aResult == isFullIn) {
     if (myType & Type_Segments) {
       for (Standard_Integer i = 0; i < myNLineNodes; i+=2) {
         const gp_Pnt aPnt[2] = {
-          gp_Pnt (mypNodes[3*mypLines[i+0]+0],
-                  mypNodes[3*mypLines[i+0]+1],
-                  mypNodes[3*mypLines[i+0]+2]).Transformed(theTrf),
-          gp_Pnt (mypNodes[3*mypLines[i+1]+0],
-                  mypNodes[3*mypLines[i+1]+1],
-                  mypNodes[3*mypLines[i+1]+2]).Transformed(theTrf)
+          nodeAtInd(mypLines, i+0).Transformed(theTrf),
+          nodeAtInd(mypLines, i+1).Transformed(theTrf)
         };
         if (isFullIn) {
           if (seg_box_included (theBox, aPnt) == 0) {
@@ -476,12 +806,8 @@ Standard_Boolean NIS_Triangulated::Intersect
     } else if (myType & Type_Line) {
       for (Standard_Integer i = 1; i < myNLineNodes; i++) {
         const gp_Pnt aPnt[2] = {
-          gp_Pnt (mypNodes[3*mypLines[i-1]+0],
-                  mypNodes[3*mypLines[i-1]+1],
-                  mypNodes[3*mypLines[i-1]+2]).Transformed(theTrf),
-          gp_Pnt (mypNodes[3*mypLines[i+0]+0],
-                  mypNodes[3*mypLines[i+0]+1],
-                  mypNodes[3*mypLines[i+0]+2]).Transformed(theTrf)
+          nodeAtInd(mypLines, i-1).Transformed(theTrf),
+          nodeAtInd(mypLines, i+0).Transformed(theTrf)
         };
         if (isFullIn) {
           if (seg_box_included (theBox, aPnt) == 0) {
@@ -497,12 +823,8 @@ Standard_Boolean NIS_Triangulated::Intersect
       }
       if (aResult == isFullIn && (myType & Type_Loop)) {
         const gp_Pnt aPntLast[2] = {
-          gp_Pnt (mypNodes[3*mypLines[myNLineNodes-1]+0],
-                  mypNodes[3*mypLines[myNLineNodes-1]+1],
-                  mypNodes[3*mypLines[myNLineNodes-1]+2]).Transformed(theTrf),
-          gp_Pnt (mypNodes[3*mypLines[0]+0],
-                  mypNodes[3*mypLines[0]+1],
-                  mypNodes[3*mypLines[0]+2]).Transformed(theTrf)
+          nodeAtInd(mypLines, myNLineNodes-1).Transformed(theTrf),
+          nodeAtInd(mypLines, 0).Transformed(theTrf)
         };
         if (isFullIn) {
           if (seg_box_included (theBox, aPntLast) == 0)
@@ -513,17 +835,14 @@ Standard_Boolean NIS_Triangulated::Intersect
         }
       }
     } else if ((myType & Type_Polygons) && myIsDrawPolygons) {
-      for (Standard_Integer iPoly = 0; iPoly < myNPolygons; iPoly++) {
-        const Standard_Integer nNodes = * mypPolygons[iPoly];
-        const Standard_Integer * arrNodes = mypPolygons[iPoly] + 1;
+      for (unsigned int iPoly = 0; iPoly < myNPolygons; iPoly++) {
+        const Standard_Integer * aPoly = mypPolygons[iPoly];
+        const Standard_Integer nNodes = NPolygonNodes(iPoly);
         for (Standard_Integer i = 1; i < nNodes; i++) {
+          // index is incremented by 1 for the head number in the array
           const gp_Pnt aPnt[2] = {
-            gp_Pnt (mypNodes[3*arrNodes[i-1]+0],
-                    mypNodes[3*arrNodes[i-1]+1],
-                    mypNodes[3*arrNodes[i-1]+2]).Transformed(theTrf),
-            gp_Pnt (mypNodes[3*arrNodes[i+0]+0],
-                    mypNodes[3*arrNodes[i+0]+1],
-                    mypNodes[3*arrNodes[i+0]+2]).Transformed(theTrf)
+            nodeAtInd(aPoly, i+0).Transformed(theTrf),
+            nodeAtInd(aPoly, i+1).Transformed(theTrf)
           };
           if (isFullIn) {
             if (seg_box_included (theBox, aPnt) == 0) {
@@ -539,12 +858,8 @@ Standard_Boolean NIS_Triangulated::Intersect
         }
         if (aResult == isFullIn) {
           const gp_Pnt aPntLast[2] = {
-            gp_Pnt (mypNodes[3*arrNodes[nNodes-1]+0],
-                    mypNodes[3*arrNodes[nNodes-1]+1],
-                    mypNodes[3*arrNodes[nNodes-1]+2]).Transformed(theTrf),
-            gp_Pnt (mypNodes[3*arrNodes[0]+0],
-                    mypNodes[3*arrNodes[0]+1],
-                    mypNodes[3*arrNodes[0]+2]).Transformed(theTrf)
+            nodeAtInd(aPoly, nNodes).Transformed(theTrf),
+            nodeAtInd(aPoly, 1).Transformed(theTrf)
           };
           if (isFullIn) {
             if (seg_box_included (theBox, aPntLast) == 0)
@@ -576,71 +891,304 @@ Standard_Real NIS_Triangulated::Intersect (const gp_Ax1&       theAxis,
 
   if ((myType & Type_Triangulation) && (myIsDrawPolygons == Standard_False))
     for (Standard_Integer i = 0; i < myNTriangles; i++) {
-      const Standard_Integer * pTri = &mypTriangles[3*i];
-      if (tri_line_intersect (start, dir,
-                              &mypNodes[3*pTri[0]],
-                              &mypNodes[3*pTri[1]],
-                              &mypNodes[3*pTri[2]],
-                              &anInter))
-        if (anInter < aResult)
-          aResult = anInter;
+      Standard_Boolean isIntersect(Standard_False);
+      if (myIndexType == 0) {
+        const unsigned char * pTri =
+          reinterpret_cast<unsigned char *>(mypTriangles) + (3 * i);
+        if (myNodeCoord > 2)
+          isIntersect = tri_line_intersect (start, dir,
+                                            &mypNodes[myNodeCoord * pTri[0]],
+                                            &mypNodes[myNodeCoord * pTri[1]],
+                                            &mypNodes[myNodeCoord * pTri[2]],
+                                            &anInter);
+        else
+          isIntersect = tri2d_line_intersect (start, dir,
+                                              &mypNodes[myNodeCoord * pTri[0]],
+                                              &mypNodes[myNodeCoord * pTri[1]],
+                                              &mypNodes[myNodeCoord * pTri[2]],
+                                              &anInter);
+      } else if (myIndexType == 1) {
+        const unsigned short * pTri =
+          reinterpret_cast<unsigned short *>(mypTriangles) + (3 * i);
+        if (myNodeCoord > 2)
+          isIntersect = tri_line_intersect (start, dir,
+                                            &mypNodes[myNodeCoord * pTri[0]],
+                                            &mypNodes[myNodeCoord * pTri[1]],
+                                            &mypNodes[myNodeCoord * pTri[2]],
+                                            &anInter);
+        else
+          isIntersect = tri2d_line_intersect (start, dir,
+                                              &mypNodes[myNodeCoord * pTri[0]],
+                                              &mypNodes[myNodeCoord * pTri[1]],
+                                              &mypNodes[myNodeCoord * pTri[2]],
+                                              &anInter);
+      } else {
+        const Standard_Integer * pTri = &mypTriangles[3 * i];
+        if (myNodeCoord > 2)
+          isIntersect = tri_line_intersect (start, dir,
+                                            &mypNodes[myNodeCoord * pTri[0]],
+                                            &mypNodes[myNodeCoord * pTri[1]],
+                                            &mypNodes[myNodeCoord * pTri[2]],
+                                            &anInter);
+        else
+          isIntersect = tri2d_line_intersect (start, dir,
+                                              &mypNodes[myNodeCoord * pTri[0]],
+                                              &mypNodes[myNodeCoord * pTri[1]],
+                                              &mypNodes[myNodeCoord * pTri[2]],
+                                              &anInter);
+      }
+      if (isIntersect && anInter < aResult)
+        aResult = anInter;
     }
 
   const Standard_Real anOver2 = theOver*theOver;
   if (myType & Type_Segments) {
-    for (Standard_Integer i = 0; i < myNLineNodes; i+=2) {
-      if (seg_line_intersect (theAxis.Location().XYZ(),
-                              theAxis.Direction().XYZ(), anOver2,
-                              &mypNodes[3*mypLines[i+0]],
-                              &mypNodes[3*mypLines[i+1]],
-                              &anInter))
-        if (anInter < aResult)
-          aResult = anInter;
-    }
+    Standard_Integer i = 0;
+    if (myNodeCoord > 2)
+      for (; i < myNLineNodes; i+=2) {
+        if (seg_line_intersect (theAxis.Location().XYZ(),
+                                theAxis.Direction().XYZ(), anOver2,
+                                nodeArrAtInd(mypLines, i+0),
+                                nodeArrAtInd(mypLines, i+1),
+                                &anInter))
+          if (anInter < aResult)
+            aResult = anInter;
+      }
+    else
+      for (; i < myNLineNodes; i+=2) {
+        if (seg2d_line_intersect (theAxis.Location().XYZ(),
+                                  theAxis.Direction().XYZ(), anOver2,
+                                  nodeArrAtInd(mypLines, i+0),
+                                  nodeArrAtInd(mypLines, i+1),
+                                  &anInter))
+          if (anInter < aResult)
+            aResult = anInter;
+      }
   } else if (myType & Type_Line) {
-    for (Standard_Integer i = 1; i < myNLineNodes; i++) {
-      if (seg_line_intersect (theAxis.Location().XYZ(),
-                              theAxis.Direction().XYZ(), anOver2,
-                              &mypNodes[3*mypLines[i-1]],
-                              &mypNodes[3*mypLines[i-0]],
-                              &anInter))
-        if (anInter < aResult)
-          aResult = anInter;
-    }
-    if (myType & Type_Loop)
-      if (seg_line_intersect (theAxis.Location().XYZ(),
-                              theAxis.Direction().XYZ(), anOver2,
-                              &mypNodes[3*mypLines[myNLineNodes-1]],
-                              &mypNodes[3*mypLines[0]],
-                              &anInter))
-        if (anInter < aResult)
-          aResult = anInter;
+    Standard_Integer i = 1;
+    if (myNodeCoord > 2) {
+      for (; i < myNLineNodes; i++) {
+        if (seg_line_intersect (theAxis.Location().XYZ(),
+                                theAxis.Direction().XYZ(), anOver2,
+                                nodeArrAtInd(mypLines, i-1),
+                                nodeArrAtInd(mypLines, i-0),
+                                &anInter))
+          if (anInter < aResult)
+            aResult = anInter;
+      }
+      if (myType & Type_Loop)
+        if (seg_line_intersect (theAxis.Location().XYZ(),
+                                theAxis.Direction().XYZ(), anOver2,
+                                nodeArrAtInd(mypLines, myNLineNodes-1),
+                                nodeArrAtInd(mypLines, 0),
+                                &anInter))
+          if (anInter < aResult)
+            aResult = anInter;
+    } else {
+      for (; i < myNLineNodes; i++) {
+        if (seg2d_line_intersect (theAxis.Location().XYZ(),
+                                  theAxis.Direction().XYZ(), anOver2,
+                                  nodeArrAtInd(mypLines, i-1),
+                                  nodeArrAtInd(mypLines, i-0),
+                                  &anInter))
+          if (anInter < aResult)
+            aResult = anInter;
+      }
+      if (myType & Type_Loop)
+        if (seg2d_line_intersect (theAxis.Location().XYZ(),
+                                  theAxis.Direction().XYZ(), anOver2,
+                                  nodeArrAtInd(mypLines, myNLineNodes-1),
+                                  nodeArrAtInd(mypLines, 0),
+                                  &anInter))
+          if (anInter < aResult)
+            aResult = anInter;
+    }
   }
 
   if ((myType & Type_Polygons) && myIsDrawPolygons) {
-    for (Standard_Integer iPoly = 0; iPoly < myNPolygons; iPoly++) {
-      const Standard_Integer nNodes = * mypPolygons[iPoly];
-      const Standard_Integer * arrNodes = mypPolygons[iPoly] + 1;
-      for (Standard_Integer i = 1; i < nNodes; i++) {
+    for (unsigned int iPoly = 0; iPoly < myNPolygons; iPoly++) {
+      const Standard_Integer * aPoly = mypPolygons[iPoly];
+      const Standard_Integer nNodes = NPolygonNodes(iPoly);
+      Standard_Integer i = 1;
+      if (myNodeCoord > 2) {
+        for (; i < nNodes; i++) {
+          // Node index is incremented for the head of polygon indice array
+          if (seg_line_intersect (theAxis.Location().XYZ(),
+                                  theAxis.Direction().XYZ(), anOver2,
+                                  nodeArrAtInd(aPoly, i+0),
+                                  nodeArrAtInd(aPoly, i+1),
+                                  &anInter))
+            if (anInter < aResult)
+              aResult = anInter;
+        }
         if (seg_line_intersect (theAxis.Location().XYZ(),
                                 theAxis.Direction().XYZ(), anOver2,
-                                &mypNodes[3*arrNodes[i-1]],
-                                &mypNodes[3*arrNodes[i-0]],
+                                nodeArrAtInd(aPoly, nNodes),
+                                nodeArrAtInd(aPoly, 1),
                                 &anInter))
           if (anInter < aResult)
             aResult = anInter;
+      } else {
+        for (; i < nNodes; i++) {
+          // Node index is incremented for the head of polygon indice array
+          if (seg2d_line_intersect (theAxis.Location().XYZ(),
+                                    theAxis.Direction().XYZ(), anOver2,
+                                    nodeArrAtInd(aPoly, i+0),
+                                    nodeArrAtInd(aPoly, i+1),
+                                    &anInter))
+            if (anInter < aResult)
+              aResult = anInter;
+        }
+        if (seg2d_line_intersect (theAxis.Location().XYZ(),
+                                  theAxis.Direction().XYZ(), anOver2,
+                                  nodeArrAtInd(aPoly, nNodes),
+                                  nodeArrAtInd(aPoly, 1),
+                                  &anInter))
+          if (anInter < aResult)
+            aResult = anInter;
+      }
+    }
+  }
+  return aResult;
+}
+
+//=======================================================================
+//function : Intersect
+//purpose  : 
+//=======================================================================
+Standard_Boolean NIS_Triangulated::Intersect
+                    (const NCollection_List<gp_XY> &thePolygon,
+                     const gp_Trsf                 &theTrf,
+                     const Standard_Boolean         isFullIn) const
+{
+  Standard_Boolean aResult (isFullIn);
+
+  if ((myType & Type_Triangulation) && myIsDrawPolygons == Standard_False) {
+    unsigned int iNode = 0;
+    for (; iNode < myNNodes * myNodeCoord; iNode += myNodeCoord)
+    {
+      gp_XYZ aPnt (static_cast<Standard_Real>(mypNodes[iNode+0]),
+                   static_cast<Standard_Real>(mypNodes[iNode+1]), 0.);
+      if (myNodeCoord > 2)
+        aPnt.SetZ (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;
+        }
+      }
+    }
+  }
+  if (aResult == isFullIn) {
+    if (myType & Type_Segments) {
+      for (Standard_Integer i = 0; i < myNLineNodes; i+=2) {
+        const gp_Pnt aPnt[2] = {
+          nodeAtInd(mypLines, i+0).Transformed(theTrf),
+          nodeAtInd(mypLines, i+1).Transformed(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 (seg_polygon_included (thePolygon, aP2d) == 0) {
+            aResult = Standard_False;
+            break;
+          }
+        } else {
+          if (seg_polygon_intersect (thePolygon, aP2d)) {
+            aResult = Standard_True;
+            break;
+          }
+        }
+      }
+    } else if (myType & Type_Line) {
+      for (Standard_Integer i = 1; i < myNLineNodes; i++) {
+        const gp_Pnt aPnt[2] = {
+          nodeAtInd(mypLines, i-1).Transformed(theTrf),
+          nodeAtInd(mypLines, i+0).Transformed(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 (seg_polygon_included (thePolygon, aP2d) == 0) {
+            aResult = Standard_False;
+            break;
+          }
+        } else {
+          if (seg_polygon_intersect (thePolygon, aP2d)) {
+            aResult = Standard_True;
+            break;
+          }
+        }
+      }
+      if (aResult == isFullIn && (myType & Type_Loop)) {
+        const gp_Pnt aPntLast[2] = {
+          nodeAtInd(mypLines, myNLineNodes-1).Transformed(theTrf),
+          nodeAtInd(mypLines, 0).Transformed(theTrf)
+        };
+        const gp_XY aP2dLast[2] = { gp_XY(aPntLast[0].X(), aPntLast[0].Y()),
+                                    gp_XY(aPntLast[1].X(), aPntLast[1].Y()) };
+
+        if (isFullIn) {
+          if (seg_polygon_included (thePolygon, aP2dLast) == 0)
+            aResult = Standard_False;
+        } else {
+          if (seg_polygon_intersect (thePolygon, aP2dLast))
+            aResult = Standard_True;
+        }
+      }
+    } else if ((myType & Type_Polygons) && myIsDrawPolygons) {
+      for (unsigned int iPoly = 0; iPoly < myNPolygons; iPoly++) {
+        const Standard_Integer * aPoly = mypPolygons[iPoly];
+        const Standard_Integer nNodes = NPolygonNodes(iPoly);
+        for (Standard_Integer i = 1; i < nNodes; i++) {
+          const gp_Pnt aPnt[2] = {
+            nodeAtInd(aPoly, i+0).Transformed(theTrf),
+            nodeAtInd(aPoly, i+1).Transformed(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 (seg_polygon_included (thePolygon, aP2d) == 0) {
+              aResult = Standard_False;
+              break;
+            }
+          } else {
+            if (seg_polygon_intersect (thePolygon, aP2d)) {
+              aResult = Standard_True;
+              break;
+            }
+          }
+        }
+        if (aResult == isFullIn) {
+          const gp_Pnt aPntLast[2] = {
+            nodeAtInd(aPoly, nNodes).Transformed(theTrf),
+            nodeAtInd(aPoly, 1).Transformed(theTrf)
+          };
+          const gp_XY aP2dLast[2] = { gp_XY(aPntLast[0].X(), aPntLast[0].Y()),
+                                      gp_XY(aPntLast[1].X(), aPntLast[1].Y()) };
+          if (isFullIn) {
+            if (seg_polygon_included (thePolygon, aP2dLast) == 0)
+              aResult = Standard_False;
+          } else {
+            if (seg_polygon_intersect (thePolygon, aP2dLast))
+              aResult = Standard_True;
+          }
+        }
       }
-      if (seg_line_intersect (theAxis.Location().XYZ(),
-                              theAxis.Direction().XYZ(), anOver2,
-                              &mypNodes[3*arrNodes[nNodes-1]],
-                              &mypNodes[3*arrNodes[0]],
-                              &anInter))
-        if (anInter < aResult)
-          aResult = anInter;
     }
   }
   return aResult;
-};
+}
 
 /* =====================================================================
 Function   : determinant
@@ -719,14 +1267,76 @@ int NIS_Triangulated::tri_line_intersect (const double      start[3],
 }
 
 /* =====================================================================
+Function   : tri2d_line_intersect
+Purpose    : Intersect a 2D triangle with a 3D line. Z coordinate of triangle
+           : is zero
+Parameters : start  - coordinates of the origin of the line
+             dir    - coordinates of the direction of the line (normalized)
+             V0     - first vertex of the triangle
+             V1     - second vertex of the triangle
+             V2     - third vertex of the triangle
+             tInter - output value, contains the parameter of the intersection
+                      point on the line (if found). May be NULL pointer
+Returns    : int = 1 if intersection found, 0 otherwise
+======================================================================== */
+
+int NIS_Triangulated::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)
+{
+  int res = 0;
+  const double conf = 1E-15;
+
+  // Parallel case is excluded
+  if (dir[2] * dir[2] > conf)
+  {
+    // Find the 2d intersection of (start, dir) with the plane Z = 0.
+    const double p2d[2] = {
+      start[0] - dir[0] * start[2] / dir[2],
+      start[1] - dir[1] * start[2] / dir[2]
+    };
+
+    // Classify the 2d intersection using barycentric coordinates
+    // (http://www.blackpawn.com/texts/pointinpoly/)
+    const double v[][2] = {
+      { static_cast<double>(V1[0]-V0[0]), static_cast<double>(V1[1]-V0[1]) },
+      { static_cast<double>(V2[0]-V0[0]), static_cast<double>(V2[1]-V0[1]) },
+      { static_cast<double>(p2d[0]-V0[0]), static_cast<double>(p2d[1]-V0[1]) }
+    };
+    const double dot00 = v[0][0]*v[0][0] + v[0][1]*v[0][1];
+    const double dot01 = v[0][0]*v[1][0] + v[0][1]*v[1][1];
+    const double dot02 = v[0][0]*v[2][0] + v[0][1]*v[2][1];
+    const double dot11 = v[1][0]*v[1][0] + v[1][1]*v[1][1];
+    const double dot12 = v[1][0]*v[2][0] + v[1][1]*v[2][1];
+    const double denom = (dot00 * dot11 - dot01 * dot01);
+    if (denom * denom < conf) {
+      // Point on the 1st side of the triangle
+      res = (dot01 > -conf && dot00 < dot11 + conf);
+    } else {
+      // Barycentric coordinates of the point
+      const double u = (dot11 * dot02 - dot01 * dot12) / denom;
+      const double v = (dot00 * dot12 - dot01 * dot02) / denom;
+      res = (u > -conf) && (v > -conf) && (u + v < 1. + conf);
+    }
+  }
+  if (res && tInter)
+    *tInter = -start[2] / dir[2];
+
+  return res;
+}
+
+/* =====================================================================
 Function   : seg_line_intersect
 Purpose    : Intersect a segment with a line
 Parameters : start  - coordinates of the origin of the line
              dir    - coordinates of the direction of the line (normalized)
              over2  - maximal square distance between the line and the segment
                       for intersection state
-             V0     - first vertex of the triangle
-             V1     - second vertex of the triangle
+             V0     - first vertex of the segment
+             V1     - second vertex of the segment
              tInter - output value, contains the parameter of the intersection
                       point on the line (if found). May be NULL pointer
 Returns    : int = 1 if intersection found, 0 otherwise
@@ -791,6 +1401,79 @@ int NIS_Triangulated::seg_line_intersect (const gp_XYZ&     aStart,
   return res;
 }
 
+/* =====================================================================
+Function   : seg2d_line_intersect
+Purpose    : Intersect a 2D segment with a 3D line
+Parameters : start  - coordinates of the origin of the line
+             dir    - coordinates of the direction of the line (normalized)
+             over2  - maximal square distance between the line and the segment
+                      for intersection state
+             V0     - first vertex of the segment
+             V1     - second vertex of the segment
+             tInter - output value, contains the parameter of the intersection
+                      point on the line (if found). May be NULL pointer
+Returns    : int = 1 if intersection found, 0 otherwise
+======================================================================== */
+
+int NIS_Triangulated::seg2d_line_intersect (const gp_XYZ&     aStart,
+                                            const gp_XYZ&     aDir,
+                                            const double      over2,
+                                            const float       V0[2],
+                                            const float       V1[2],
+                                            double            * tInter)
+{
+  int res = 0;
+  const gp_XYZ aDirSeg (V1[0]-V0[0], V1[1]-V0[1], 0.);
+  gp_XYZ aDirN = aDirSeg ^ aDir;
+  Standard_Real aMod2 = aDirN.SquareModulus();
+  if (aMod2 < Precision::Confusion() * 0.001) {
+    const gp_XYZ aDelta0 (V0[0]-aStart.X(), V0[1]-aStart.Y(), -aStart.Z());
+    if ((aDelta0 ^ aDir).SquareModulus() < over2) {
+      res = 1;
+      const gp_XYZ aDelta1 (V1[0]-aStart.X(), V1[1]-aStart.Y(), -aStart.Z());
+      if (tInter)
+        * tInter = Min (aDelta0 * aDir, aDelta1 * aDir);
+    }
+  } else {
+    // distance between two unlimited lines
+    const gp_XYZ aPnt0 (V0[0], V0[1], 0.);
+    const Standard_Real aDistL = (aDirN * aPnt0) - aDirN * aStart;
+    if (aDistL*aDistL < over2 * aMod2) {
+      const gp_XYZ aPnt1 (V1[0], V1[1], 0.);
+      Standard_Real aDist[3] = {
+        ((aPnt0 - aStart) ^ aDir).Modulus(),
+        ((aPnt1 - aStart) ^ aDir).Modulus(),
+        0.
+      };
+      // Find the intermediate point by interpolation using the distances from
+      // the end points.
+      const gp_XYZ aPntI =
+        (aPnt0 * aDist[1] + aPnt1 * aDist[0]) / (aDist[0] + aDist[1]);
+      aDist[2] = ((aPntI - aStart) ^ aDir).Modulus();
+      if (aDist[2] < aDist[0] && aDist[2] < aDist[1]) {
+        if (aDist[2]*aDist[2] < over2) {
+          res = 1;
+          if (tInter)
+            * tInter = (aPntI - aStart) * aDir;
+        }
+      } else if (aDist[0] < aDist[1]) {
+        if (aDist[0] * aDist[0] < over2) {
+          res = 1;
+          if (tInter)
+            * tInter = (aPnt0 - aStart) * aDir;
+        }
+      } else {
+        if (aDist[1] * aDist[1] < over2) {
+          res = 1;
+          if (tInter)
+            * tInter = (aPnt1 - aStart) * aDir;
+        }
+      }
+    }
+  }
+  return res;
+}
+
 //=======================================================================
 //function : seg_box_intersect
 //purpose  : 
@@ -831,6 +1514,207 @@ int NIS_Triangulated::seg_box_included  (const Bnd_B3f& theBox,
 }
 
 //=======================================================================
+//function : seg_polygon_intersect
+//purpose  : 
+//=======================================================================
+
+int NIS_Triangulated::seg_polygon_intersect
+                      (const NCollection_List<gp_XY> &thePolygon,
+                       const gp_XY                    thePnt[2])
+{
+  Standard_Integer aResult = 0;
+
+  if (thePolygon.IsEmpty())
+    return aResult;
+
+  gp_XY            aDir(thePnt[1] - thePnt[0]);
+  Standard_Real    aDist   = aDir.SquareModulus();
+
+  if (aDist > aTolConf) {
+    aDist = Sqrt(aDist);
+    aDir.Divide(aDist); // Normalize direction.
+
+    // Intersect the line passed through thePnt[0] and thePnt[1] with thePolygon
+    // Line is presented in form Ax + By + C = 0
+    Standard_Real aA =  aDir.Y();
+    Standard_Real aB = -aDir.X();
+    Standard_Real aC = -(aA*thePnt[0].X() + aB*thePnt[0].Y());
+    gp_XY         aSegment[2];
+    Standard_Real aSignedD[2];
+    Standard_Real aDelta = 0.01;
+
+    aSegment[0] = thePolygon.Last();
+    aSignedD[0] = aA*aSegment[0].X() + aB*aSegment[0].Y() + aC;
+
+    NCollection_List<gp_XY>::Iterator anIter(thePolygon);
+
+    for (; anIter.More(); anIter.Next()) {
+      aSegment[1] = anIter.Value();
+      aSignedD[1] = aA*aSegment[1].X() + aB*aSegment[1].Y() + aC;
+
+      // Check if there is an intersection.
+      if (Abs(aSignedD[0]) <= aTolConf || Abs(aSignedD[1]) <= aTolConf) {
+        Standard_Integer anIndexVtx = 
+                              (Abs(aSignedD[0]) > aTolConf) ? 1 :
+                              (Abs(aSignedD[1]) > aTolConf) ? 0 : -1;
+        if (anIndexVtx != -1) {
+          // Check if the point aSegment[1] is inside the segment.
+          gp_XY         aDP(aSegment[anIndexVtx] - thePnt[0]);
+          Standard_Real aParam = aDP.Dot(aDir);
+
+          if (aParam >= -aTolConf && aParam <= aDist + aTolConf) {
+            // Classify a point on the line that is close to aSegment[1] with
+            // respect to the polygon.
+            gp_XY aPShift;
+
+            if (aParam - aDelta >= 0.) {
+              aPShift = thePnt[0] + aDir.Multiplied(aParam - aDelta);
+              if (!IsIn(thePolygon, aPShift))
+                aResult = 1;
+            }
+
+            // Try to shift on another direction.
+            if (!aResult) {
+              if (aParam + aDelta <= aDist) {
+                aPShift = thePnt[0] + aDir.Multiplied(aParam + aDelta);
+                if (!IsIn(thePolygon, aPShift))
+                  aResult = 1;
+              }
+            }
+          }
+        }
+      } else if (aSignedD[0]*aSignedD[1] < 0.) {
+        // Compute intersection of the segment with the line.
+        gp_XY         aDSeg(aSegment[1] - aSegment[0]);
+        Standard_Real aSegLen     = aDSeg.Modulus();
+        Standard_Real aParamOnSeg = aSegLen/(1 + Abs(aSignedD[1]/aSignedD[0]));
+        gp_XY         aPOnLine
+                         (aSegment[0] + aDSeg.Multiplied(aParamOnSeg/aSegLen));
+
+        // Check if aPOnLine inside the segment thePnt[1] - thePnt[0]
+        gp_XY         aDP(aPOnLine - thePnt[0]);
+        Standard_Real aParam = aDP.Dot(aDir);
+
+        if (aParam >= -aTolConf && aParam <= aDist + aTolConf) {
+          gp_XY aPShift;
+
+          if (aParam - aDelta >= 0.) {
+            aPShift = thePnt[0] + aDir.Multiplied(aParam - aDelta);
+
+            if (!IsIn(thePolygon, aPShift))
+              aResult = 1;
+          }
+
+          // Try to shift on another direction.
+          if (!aResult) {
+            if (aParam + aDelta <= aDist) {
+              aPShift = thePnt[0] + aDir.Multiplied(aParam + aDelta);
+
+              if (!IsIn(thePolygon, aPShift))
+                aResult = 1;
+            }
+          }
+        }
+      }
+
+      if (aResult != 0)
+        break;
+
+      aSegment[0] = aSegment[1];
+      aSignedD[0] = aSignedD[1];
+    }
+  }
+
+  return aResult;
+}
+
+//=======================================================================
+//function : seg_polygon_included
+//purpose  : 
+//=======================================================================
+
+int NIS_Triangulated::seg_polygon_included
+                      (const NCollection_List<gp_XY> &thePolygon,
+                       const gp_XY                    thePnt[2])
+{
+  int aResult     = 0;
+  int anIntersect = seg_polygon_intersect(thePolygon, thePnt);
+
+  if (anIntersect == 0) {
+    if (IsIn(thePolygon, thePnt[0]) && IsIn(thePolygon, thePnt[1]))
+      aResult = 1;
+  }
+
+  return aResult;
+}
+
+//=======================================================================
+//function : IsIn
+//purpose  : 
+//=======================================================================
+
+Standard_Boolean NIS_Triangulated::IsIn
+                      (const NCollection_List<gp_XY> &thePolygon,
+                       const gp_XY                   &thePoint)
+{
+  if (thePolygon.IsEmpty())
+    return Standard_False;
+
+  Standard_Integer aCounter = 0; // intersections counter
+  gp_XY            aSegment[2];
+
+  aSegment[0] = thePolygon.Last();
+
+  NCollection_List<gp_XY>::Iterator anIter(thePolygon);
+
+  for (; anIter.More(); anIter.Next()) {
+    aSegment[1] = anIter.Value();
+
+    // Compute projection of the point onto the segment.
+    Standard_Real       aParam = 0.;
+    const gp_XY         aDelta = aSegment[1] - aSegment[0];
+    const gp_XY         aDPP0  = thePoint - aSegment[0];
+    const Standard_Real aLen2  = aDelta.SquareModulus();
+
+    if (IsPositive(aLen2)) {
+      aParam = (aDelta*aDPP0)/aLen2;
+
+      if (aParam < 0.)
+        aParam = 0.;
+      else if (aParam > 1.)
+        aParam = 1.;
+    }
+    // Check if the point lies on the segment
+    gp_XY         aPOnSeg  = aSegment[0]*(1. - aParam) + aSegment[1]*aParam;
+    Standard_Real aSqrDist = (thePoint - aPOnSeg).SquareModulus();
+
+    if (aSqrDist < aTolConf) {
+      // The point is on the contour.
+      return Standard_True;
+    }
+
+    // Compute intersection.
+    const Standard_Real aProd(aDPP0 ^ aDelta);
+
+    if (IsPositive(thePoint.X() - aSegment[0].X())) {
+      if (!IsPositive(thePoint.X() - aSegment[1].X())) {
+        if (aProd > 0.)
+          aCounter++;
+      }
+    } else {
+      if (IsPositive(thePoint.X() - aSegment[1].X())) {
+        if (aProd < 0.)
+          aCounter++;
+      }
+    }
+
+    aSegment[0] = aSegment[1];
+  }
+
+  return (aCounter & 0x1);
+}
+
+//=======================================================================
 //function : allocateNodes
 //purpose  : 
 //=======================================================================
@@ -842,6 +1726,67 @@ void NIS_Triangulated::allocateNodes (const Standard_Integer nNodes)
       myAlloc->Free(mypNodes);
     myNNodes = nNodes;
     mypNodes = static_cast<Standard_ShortReal*>
-      (myAlloc->Allocate(sizeof(Standard_ShortReal)*3*nNodes));
+      (myAlloc->Allocate(sizeof(Standard_ShortReal) * myNodeCoord * nNodes));
+    if (nNodes < 256)
+      myIndexType = 0;
+    else if (nNodes < 65536)
+      myIndexType = 1;
+    else
+      myIndexType = 2;
+  }
+}
+
+//=======================================================================
+//function : NodeAtInd
+//purpose  : Get the node pointed by the i-th index in the array.
+//=======================================================================
+
+gp_Pnt NIS_Triangulated::nodeAtInd  (const Standard_Integer * theArray,
+                                     const Standard_Integer theInd) const
+{
+  if (myIndexType == 0) {
+    const unsigned char * pInd =
+      reinterpret_cast<const unsigned char *>(theArray);
+    return gp_Pnt (mypNodes[myNodeCoord * pInd[theInd] + 0],
+                   mypNodes[myNodeCoord * pInd[theInd] + 1],
+                   myNodeCoord < 3 ? 0. :
+                   mypNodes[myNodeCoord * pInd[theInd] + 2]);
+  }
+  if (myIndexType == 1) {
+    const unsigned short * pInd =
+      reinterpret_cast<const unsigned short *>(theArray);
+    return gp_Pnt (mypNodes[myNodeCoord * pInd[theInd] + 0],
+                   mypNodes[myNodeCoord * pInd[theInd] + 1],
+                   myNodeCoord < 3 ? 0. :
+                   mypNodes[myNodeCoord * pInd[theInd] + 2]);
+  }
+  return gp_Pnt (mypNodes[myNodeCoord * theArray[theInd] + 0],
+                 mypNodes[myNodeCoord * theArray[theInd] + 1],
+                 myNodeCoord < 3 ? 0. :
+                 mypNodes[myNodeCoord * theArray[theInd] + 2]);
+}
+  
+//=======================================================================
+//function : nodeArrAtInd
+//purpose  : Get the node pointed by the i-th index in the array.
+//=======================================================================
+
+float* NIS_Triangulated::nodeArrAtInd (const Standard_Integer * theArray,
+                                       const Standard_Integer theInd) const
+{
+  float* pResult = 0L; 
+  if (myIndexType == 0) {
+    const unsigned char * pInd =
+      reinterpret_cast<const unsigned char *>(theArray);
+    pResult = &mypNodes[myNodeCoord * pInd[theInd]];
+  }
+  else if (myIndexType == 1) {
+    const unsigned short * pInd =
+      reinterpret_cast<const unsigned short *>(theArray);
+    pResult = &mypNodes[myNodeCoord * pInd[theInd]];
+  }
+  else {
+    pResult = &mypNodes[myNodeCoord * theArray[theInd]];
   }
+  return pResult;
 }
index 7bd0ecc..02bc9b2 100755 (executable)
 #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,
@@ -34,6 +62,16 @@ class NIS_Triangulated : public NIS_InteractiveObject
   };
 
  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)
+   * 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
+   *   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 *   Triangle  (const Standard_Integer ind) const
-  { return &mypTriangles[ind*3]; }
+  Standard_EXPORT void              SetPolygonNode
+                                              (const Standard_Integer indPoly,
+                                               const Standard_Integer ind,
+                                               const Standard_Integer iNode);
 
   /**
-   * 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.
+   * Get the node with index 'ind' from the polygon number 'indPoly'.
    */
-  inline const Standard_Integer *   LineNode  (const Standard_Integer ind) const
-  { return &mypLines[ind]; }
-
+  Standard_EXPORT Standard_Integer PolygonNode(const Standard_Integer indPoly,
+                                               const Standard_Integer ind)const;
 
   /**
-   * Query the polygon.
-   * @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
+   * Get the number of nodes for the polygon number 'indPoly'.
    */
-  inline const Standard_Integer     Polygon   (const Standard_Integer ind,
-                                               Standard_Integer* & outInd) const
-  { return * (outInd = mypPolygons[ind])++; }
+  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);
-
-  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);
+  /**
+   * Intersect the InteractiveObject geometry with a selection polygon.
+   * @param thePolygon
+   *   the list of vertices of a free-form closed polygon without
+   *   self-intersections. The last point should not coincide with the first
+   *   point of the list. Any two neighbor points should not be confused.
+   * @param theTrf
+   *   Position/Orientation of the polygon.
+   * @param isFullIn
+   *   True if full inclusion is required, False - if partial.
+   * @return
+   *   True if the InteractiveObject geometry intersects the polygon or is
+   *   inside it
+   */
+  Standard_EXPORT virtual Standard_Boolean Intersect
+                    (const NCollection_List<gp_XY> &thePolygon,
+                     const gp_Trsf                 &theTrf,
+                     const Standard_Boolean         isFullIn) const;
+
+  Standard_EXPORT static int tri_line_intersect  (const double      start[3],
+                                                  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,13 +432,59 @@ 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.
    */
   Standard_EXPORT virtual void computeBox     ();
@@ -380,30 +495,49 @@ class NIS_Triangulated : public NIS_InteractiveObject
    */
   Standard_EXPORT void         allocateNodes  (const Standard_Integer nNodes);
 
- protected:
-  // ---------- PROTECTED FIELDS ----------
+  /**
+   * 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;
 
   /**
-   * Combination of Type_* constants
+   * Get the node pointed by the i-th index in the array.
    */
-  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;
+  Standard_EXPORT float*       nodeArrAtInd   (const Standard_Integer * theArr,
+                                               const Standard_Integer i) const;
+
+ protected:
+  // ---------- PROTECTED FIELDS ----------
+
+  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
index f2d09c8..4940e21 100755 (executable)
@@ -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);
       }
   }
+
 }
+
index 38dc094..70d8c41 100755 (executable)
@@ -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;
 
index 334835b..d5d1db9 100755 (executable)
@@ -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;
 }
+
index 4f90f77..fe55cf9 100755 (executable)
 #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);
 
   /**
+   * Indicate whether to draw hilighted objects on top of all other ones
+   */
+  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 void FitAll3d ();
+  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.
@@ -81,20 +125,29 @@ 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;
 
index ad190b9..4f9f8b6 100755 (executable)
@@ -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;
 }