diff --git a/src/NIS/FILES b/src/NIS/FILES index 74ede22261..1bad545df1 100755 --- a/src/NIS/FILES +++ b/src/NIS/FILES @@ -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 index 0000000000..0f7cb0c48a --- /dev/null +++ b/src/NIS/NIS_Allocator.cxx @@ -0,0 +1,59 @@ +// File: NIS_Allocator.cpp +// Created: 22.10.10 17:35 +// Author: Alexander GRIGORIEV +// Copyright: Open Cascade 2010 + +#include + +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 + (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(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 index 0000000000..927be4bf4c --- /dev/null +++ b/src/NIS/NIS_Allocator.hxx @@ -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 + +/** + * 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 diff --git a/src/NIS/NIS_DrawList.cxx b/src/NIS/NIS_DrawList.cxx index 9123971acd..dd098730d0 100755 --- a/src/NIS/NIS_DrawList.cxx +++ b/src/NIS/NIS_DrawList.cxx @@ -4,6 +4,7 @@ // Copyright: Open Cascade 2007 #include +#include #ifdef WNT #include @@ -16,12 +17,21 @@ //======================================================================= NIS_DrawList::NIS_DrawList () - : myListID (0) { +#ifdef ARRAY_LISTS + myListID = 0; +#else + myListID[0] = 0; + myListID[1] = 0; + myListID[2] = 0; + myListID[3] = 0; + myListID[4] = 0; +#endif myIsUpdated[0] = Standard_True; myIsUpdated[1] = Standard_True; myIsUpdated[2] = Standard_True; myIsUpdated[3] = Standard_True; + myIsUpdated[4] = Standard_True; } //======================================================================= @@ -30,13 +40,22 @@ NIS_DrawList::NIS_DrawList () //======================================================================= NIS_DrawList::NIS_DrawList (const Handle_NIS_View& theView) - : myView (theView), - myListID (0) + : myView (theView) { +#ifdef ARRAY_LISTS + myListID = 0; +#else + myListID[0] = 0; + myListID[1] = 0; + myListID[2] = 0; + myListID[3] = 0; + myListID[4] = 0; +#endif myIsUpdated[0] = Standard_True; myIsUpdated[1] = Standard_True; myIsUpdated[2] = Standard_True; myIsUpdated[3] = Standard_True; + myIsUpdated[4] = Standard_True; } //======================================================================= @@ -46,8 +65,67 @@ NIS_DrawList::NIS_DrawList (const Handle_NIS_View& theView) NIS_DrawList::~NIS_DrawList () { - if (myListID != 0) - glDeleteLists (myListID, 4); + //if (myListID != 0) + //glDeleteLists (myListID, 5); +} + +//======================================================================= +//function : ClearListID +//purpose : Set myListID to 0. +//======================================================================= + +void NIS_DrawList::ClearListID (const Standard_Integer theType) +{ +#ifndef ARRAY_LISTS + if (theType >= 0) { + // To be called only in Callback context (i.e. when GL context is active) + if (myListID[theType] > 0) { + glDeleteLists(myListID[theType], 1); + myListID[theType] = 0; + } + myIsUpdated[theType] = Standard_False; + } +#endif +} + +//======================================================================= +//function : ClearListID +//purpose : Set myListID to 0. +//======================================================================= + +void NIS_DrawList::ClearListID (const Handle_NIS_View& theView) +{ +#ifdef ARRAY_LISTS + if (myListID > 0) + myView->GetExListId().Add(myListID); + myListID = 0; +#else + NIS_View * pView = (myView.IsNull()) ? + theView.operator->() : myView.operator->(); + if (pView) { + if (myListID[0] > 0) + pView->GetExListId().Add(myListID[0]); + myListID[0] = 0; + if (myListID[1] > 0) + pView->GetExListId().Add(myListID[1]); + myListID[1] = 0; + if (myListID[2] > 0) + pView->GetExListId().Add(myListID[2]); + myListID[2] = 0; + if (myListID[3] > 0) + pView->GetExListId().Add(myListID[3]); + myListID[3] = 0; + if (myListID[4] > 0) + pView->GetExListId().Add(myListID[4]); + myListID[4] = 0; + } + +#endif + myIsUpdated[0] = Standard_False; + myIsUpdated[1] = Standard_False; + myIsUpdated[2] = Standard_False; + myIsUpdated[3] = Standard_False; + myIsUpdated[4] = Standard_False; } //======================================================================= @@ -57,9 +135,14 @@ NIS_DrawList::~NIS_DrawList () void NIS_DrawList::BeginPrepare (const Standard_Integer theType) { +#ifdef ARRAY_LISTS if (myListID == 0) - myListID = glGenLists(4); - glNewList (GetListID (theType), GL_COMPILE); + myListID = glGenLists(5); +#else + if (GetListID(theType) == 0) + myListID[theType] = glGenLists(1); +#endif + glNewList (GetListID(theType), GL_COMPILE); } //======================================================================= @@ -70,7 +153,7 @@ void NIS_DrawList::BeginPrepare (const Standard_Integer theType) void NIS_DrawList::EndPrepare (const Standard_Integer theType) { glEndList (); - myIsUpdated[theType&0x3] = Standard_False; + myIsUpdated[theType] = Standard_False; } //======================================================================= @@ -120,9 +203,20 @@ Standard_Boolean NIS_DrawList::SetDynHilighted void NIS_DrawList::SetUpdated (const Standard_Integer theType, const Standard_Boolean theFlag) { - if ( theFlag ) - SetUpdated( theType ); + if (theFlag) + SetUpdated(theType); else - myIsUpdated [theType&0x3] = Standard_False; + myIsUpdated [theType] = Standard_False; } +//======================================================================= +//function : SetUpdated +//purpose : +//======================================================================= + +void NIS_DrawList::SetUpdated (const Standard_Integer theType) +{ + myIsUpdated [theType] = Standard_True; + if (theType == NIS_Drawer::Draw_Hilighted) + myDynHilighted.Clear(); +} diff --git a/src/NIS/NIS_DrawList.hxx b/src/NIS/NIS_DrawList.hxx index 77468b835c..5d978a66a8 100755 --- a/src/NIS/NIS_DrawList.hxx +++ b/src/NIS/NIS_DrawList.hxx @@ -12,9 +12,18 @@ #include 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 myDynHilighted; }; diff --git a/src/NIS/NIS_Drawer.cxx b/src/NIS/NIS_Drawer.cxx index c861c3ddf2..e1d793c273 100755 --- a/src/NIS/NIS_Drawer.cxx +++ b/src/NIS/NIS_Drawer.cxx @@ -4,6 +4,7 @@ // Copyright: Open Cascade 2007 #include +#include #include #include #include @@ -34,6 +35,9 @@ void NIS_Drawer::Assign (const Handle_NIS_Drawer& theOther) { if (theOther->IsKind(DynamicType()) == Standard_False) Standard_TypeMismatch::Raise ("NIS_Drawer::Assign"); + myIniId = theOther->myIniId; + myObjPerDrawer = theOther->myObjPerDrawer; + myTransparency = theOther->myTransparency; } //======================================================================= @@ -43,7 +47,9 @@ void NIS_Drawer::Assign (const Handle_NIS_Drawer& theOther) Standard_Integer NIS_Drawer::HashCode(const Standard_Integer theN) const { - return ::HashCode (DynamicType(), theN); + Standard_Integer aKey = ::HashCode (DynamicType(), theN); + aKey += (myIniId / myObjPerDrawer); + return ((aKey & 0x7fffffff) % theN) + 1; } //======================================================================= @@ -56,7 +62,13 @@ Standard_Boolean NIS_Drawer::IsEqual (const Handle_NIS_Drawer& theOther) const Standard_Boolean aResult (Standard_False); if (theOther.IsNull() == Standard_False) if (DynamicType() == theOther->DynamicType()) - aResult = (myMapID.Extent() < 2048); + if (theOther->myIniId/theOther->myObjPerDrawer == myIniId/myObjPerDrawer) + aResult = Standard_True; + + if (aResult) + if (fabs(myTransparency - theOther->myTransparency) > 0.01) + aResult = Standard_False; + return aResult; } @@ -78,6 +90,36 @@ void NIS_Drawer::AfterDraw (const DrawType, const NIS_DrawList&) { } +//======================================================================= +//function : UpdateExListId +//purpose : +//======================================================================= + +void NIS_Drawer::UpdateExListId (const Handle_NIS_View& theView) const +{ + if (theView.IsNull()) { + if (myCtx) { + if (myCtx->myViews.IsEmpty() == Standard_False) { + const Handle(NIS_View)& aView = myCtx->myViews.First(); + NCollection_List::Iterator anIterL(myLists); + for (; anIterL.More(); anIterL.Next()) { + NIS_DrawList * const pList = anIterL.Value(); + pList->ClearListID(aView); + } + } + } + } else { + NCollection_List::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::Iterator anIter (myLists); for (; anIter.More(); anIter.Next()) { NIS_DrawList& aDrawList = * anIter.ChangeValue(); - if (aDrawList.GetView() == theView) { + const Handle_NIS_View& aView = aDrawList.GetView(); + if (aView == theView || aView.IsNull()) { if (aDrawList.IsUpdated(theType)) { + // Get the IDs of objects concerned + TColStd_PackedMapOfInteger mapObj; + mapObj.Intersection (myCtx->myMapObjects[theType], myMapID); +#ifndef ARRAY_LISTS + // Release the list that is no more in use + if (mapObj.IsEmpty() && theType != Draw_DynHilighted) { + aDrawList.ClearListID(theType); + break; + } +#endif aDrawList.BeginPrepare(theType); - prepareList (theType, aDrawList); + prepareList (theType, aDrawList, mapObj); aDrawList.EndPrepare(theType); } - aDrawList.Call(theType); + if (aDrawList.GetListID(theType) > 0) + aDrawList.Call(theType); break; } } @@ -158,6 +212,28 @@ void NIS_Drawer::SetUpdated (const DrawType theType1, const_cast(myBox).Clear(); } +//======================================================================= +//function : SetUpdated +//purpose : +//======================================================================= + + +void NIS_Drawer::SetUpdated (const DrawType theType1, + const DrawType theType2, + const DrawType theType3, + const DrawType theType4) const +{ + NCollection_List::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(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::Iterator anIter (GetContext()->myViews); - for (; anIter.More(); anIter.Next()) - myLists.Append (createDefaultList(anIter.Value())); + if (isShareList) + myLists.Append (createDefaultList(NULL)); + else { + NCollection_List::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::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::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); } diff --git a/src/NIS/NIS_Drawer.hxx b/src/NIS/NIS_Drawer.hxx index 0639ae5a49..81d8f18ae2 100755 --- a/src/NIS/NIS_Drawer.hxx +++ b/src/NIS/NIS_Drawer.hxx @@ -28,21 +28,91 @@ class NIS_View; template 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()). + *
    + *
  • BeforeDraw() : 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
  • + *
  • Draw() : all OpenGL commands that are specific to a given + * interactive object, usually definition of vertices, triangles, lines, + * or their arrays.
  • + *
  • AfterDraw() : 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.
  • + *
+ * 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. + *

+ * 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. Two instances of Drawer are equal if they + * have the same set of visual properties that are implemented in BeforeDraw(). + * 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. + *

+ * 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. + *

+ * @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 + 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 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 diff --git a/src/NIS/NIS_InteractiveContext.cxx b/src/NIS/NIS_InteractiveContext.cxx index d58ad6e110..828dfcd21f 100755 --- a/src/NIS/NIS_InteractiveContext.cxx +++ b/src/NIS/NIS_InteractiveContext.cxx @@ -8,16 +8,12 @@ #include #include #include +#include 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&); //======================================================================= //function : NIS_InteractiveContext() @@ -25,8 +21,10 @@ static void selectObj (const Handle(NIS_InteractiveObject)&, //======================================================================= NIS_InteractiveContext::NIS_InteractiveContext () - : mySelectionMode (Mode_NoSelection), - myAllocator (new NCollection_IncAllocator) + : myAllocator (new NIS_Allocator(1024*100)), +// myDrawers (101, myAllocator), + mySelectionMode (Mode_NoSelection), + myIsShareDrawList (Standard_True) { // ID == 0 is invalid so we reserve this item from subsequent allocation. myObjects.Append (NULL); @@ -143,42 +141,42 @@ void NIS_InteractiveContext::GetBox (Bnd_B3f& theBox, //======================================================================= void NIS_InteractiveContext::Display - (const Handle_NIS_InteractiveObject& theObj, - const Handle_NIS_Drawer& theDrawer, - const Standard_Boolean isUpdateViews) + (Handle_NIS_InteractiveObject& theObj, + const Handle_NIS_Drawer& theDrawer, + const Standard_Boolean isUpdateViews) { if (theObj.IsNull()) return; - Standard_Integer anID = theObj->ID(); - Handle(NIS_Drawer) aDrawer = theDrawer; - if (aDrawer.IsNull() == Standard_False) { - if (aDrawer->myCtx != this) - Standard_NoSuchObject::Raise ("NIS_InteractiveContext::Display (0)"); - } else { - aDrawer = theObj->GetDrawer(); - if (aDrawer.IsNull()) { - aDrawer = theObj->DefaultDrawer(); - aDrawer->myCtx = this; - } - } - if (anID == 0) { - // Create a new ID for this object - theObj->myID = myObjects.Length(); - myObjects.Append (theObj); - myMapObjects[NIS_Drawer::Draw_Normal].Add(theObj->myID); - } - aDrawer = theObj->SetDrawer (aDrawer); - - // Display Object as Normal or Transparent if it has been hidden + objectForDisplay(theObj, theObj->DrawType()); + const Handle(NIS_Drawer)& aDrawer = drawerForDisplay(theObj, theDrawer); + // Display Object as Normal or Transparent if it has been hidden + if (theObj->IsHidden()) + theObj->myIsHidden = Standard_False; + + // Set Update flag in the Drawer + if (isUpdateViews) + aDrawer->SetUpdated (theObj->DrawType()); +} + +//======================================================================= +//function : DisplayOnTop +//purpose : +//======================================================================= + +void NIS_InteractiveContext::DisplayOnTop + (Handle_NIS_InteractiveObject& theObj, + const Handle_NIS_Drawer& theDrawer, + const Standard_Boolean isUpdateViews) +{ + if (theObj.IsNull()) + return; + + objectForDisplay(theObj, NIS_Drawer::Draw_Top); + const Handle(NIS_Drawer)& aDrawer = drawerForDisplay(theObj, theDrawer); + + // Display Object as Normal or Transparent if it has been hidden if (theObj->IsHidden()) theObj->myIsHidden = Standard_False; -// if (theObj->IsTransparent()) { -// myMapObjects[NIS_Drawer::Draw_Transparent].Add(anID); -// theObj->myDrawType = NIS_Drawer::Draw_Transparent; -// } else { -// myMapObjects[NIS_Drawer::Draw_Normal].Add(anID); -// theObj->myDrawType = NIS_Drawer::Draw_Normal; -// } // Set Update flag in the Drawer if (isUpdateViews) @@ -221,6 +219,8 @@ void NIS_InteractiveContext::Remove (const Handle_NIS_InteractiveObject& theObj, { if (theObj.IsNull() == Standard_False) { const Handle(NIS_Drawer)& aDrawer = theObj->GetDrawer(); + if ( aDrawer.IsNull() ) + return; if (aDrawer->myCtx == this) { // Remove the hilighting if the object has been hilighted if (theObj->IsDynHilighted()) { @@ -229,10 +229,10 @@ void NIS_InteractiveContext::Remove (const Handle_NIS_InteractiveObject& theObj, if (anIterV.Value().IsNull() == Standard_False) anIterV.Value()->DynamicUnhilight (theObj); } - // Remove the obejct from the context + // Remove the object from the context const Standard_Integer anID = theObj->ID(); const NIS_Drawer::DrawType aDrawType (theObj->DrawType()); - if (myMapObjects[Standard_Integer(aDrawType)&0x3].Remove(anID)) + if (myMapObjects[Standard_Integer(aDrawType)].Remove(anID)) aDrawer->removeObject(theObj.operator->(), isUpdateViews); theObj->myID = 0; theObj->myDrawer.Nullify(); @@ -246,7 +246,7 @@ void NIS_InteractiveContext::Remove (const Handle_NIS_InteractiveObject& theObj, //purpose : //======================================================================= -void NIS_InteractiveContext::DisplayAll (const Standard_Boolean isUpdateViews) +void NIS_InteractiveContext::DisplayAll () { // UnHide all objects in the Context NCollection_Vector ::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::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::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 ::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 ::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::Iterator anIterD (myDrawers); for (; anIterD.More(); anIterD.Next()) { const Handle(NIS_Drawer)& aDrawer = anIterD.Value(); if (aDrawer.IsNull() == Standard_False) { aDrawer->myMapID.Clear(); - if (isUpdateViews) - aDrawer->SetUpdated (NIS_Drawer::Draw_Normal, - NIS_Drawer::Draw_Transparent, - NIS_Drawer::Draw_Hilighted); -// if (aList.myDynHilighted.IsEmpty() == Standard_False) { -// aList.myIsUpdated[NIS_Drawer::Draw_DynHilighted]= Standard_True; -// aList.myDynHilighted.Clear(); -// } + aDrawer->UpdateExListId(NULL); + aDrawer->myLists.Clear(); } } + // Remove Drawers + myDrawers.Clear(); + + // Release memory + myAllocator->Reset(); + myAllocator->ResetCounters(); + + myDrawers.Clear(); + + // Remove objects from maps + myMapObjects[0].Clear(); + myMapObjects[1].Clear(); + myMapObjects[2].Clear(); + myMapObjects[3].Clear(); + myMapNonSelectableObjects.Clear(); +} + +//======================================================================= +//function : RebuildViews +//purpose : +//======================================================================= + +void NIS_InteractiveContext::RebuildViews () +{ + const Handle_NIS_Allocator aNewAlloc = compactObjects(); + + // Recalculate all DrawLists in all drawers + markAllDrawersUpdated(myDrawers); + + // It is time to destroy the old allocator, not before this line. Because + // the old allocator is needed to tidy up draw lists in SetUpdated() calls. + if (aNewAlloc.IsNull() == Standard_False) + myAllocator = aNewAlloc; + + NCollection_List::Iterator anIterV(myViews); + for (; anIterV.More(); anIterV.Next()) { + const Handle(NIS_View)& aView = anIterV.Value(); + if (aView.IsNull() == Standard_False) + aView->Redraw(); + } } //======================================================================= //function : UpdateViews -//purpose : +//purpose : Only repaint the views refreshing their presentations only for +// those drawers that have been marked as updated. //======================================================================= void NIS_InteractiveContext::UpdateViews () { - NCollection_Map::Iterator anIterD (myDrawers); - for (; anIterD.More(); anIterD.Next()) { - const Handle(NIS_Drawer)& aDrawer = anIterD.Value(); - if (aDrawer.IsNull() == Standard_False) { - aDrawer->SetUpdated (NIS_Drawer::Draw_Normal, - NIS_Drawer::Draw_Transparent, - NIS_Drawer::Draw_Hilighted); -// aList.myIsUpdated[NIS_Drawer::Draw_DynHilighted] = -// (aList.myDynHilighted.IsEmpty() == Standard_False); - } - } - NCollection_List::Iterator anIterV (myViews); + const Handle_NIS_Allocator aNewAlloc = compactObjects(); + if (aNewAlloc.IsNull() == Standard_False) + myAllocator = aNewAlloc; + + NCollection_List::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& 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 ::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::Iterator anIterD(theDetected); + for (; anIterD.More(); anIterD.Next()) { + if (anEnt.Dist < anIterD.Value().Dist) { + theDetected.InsertBefore(anEnt, anIterD); + break; + } + } + if (anIterD.More() == Standard_False) + theDetected.Append(anEnt); + if (anEnt.Dist < aMinDist) { + aMinDist = anEnt.Dist; + theSel = anObj; + } } } } } } - return aResult; + return aMinDist; } //======================================================================= @@ -646,7 +695,7 @@ void NIS_InteractiveContext::SetSelectable anID = anIter.Key(); if ( myMapObjects[NIS_Drawer::Draw_Hilighted].Contains(anID)) { myMapObjects[NIS_Drawer::Draw_Hilighted].Remove(anID); - deselectObj (myObjects(anID), anID, &myMapObjects[0]); + deselectObj (myObjects(anID), anID); } } myMapNonSelectableObjects.Unite(objIDs); @@ -694,25 +743,90 @@ Standard_Boolean NIS_InteractiveContext::selectObjects return aResult; } +//======================================================================= +//function : selectObjects +//purpose : +//======================================================================= + +Standard_Boolean NIS_InteractiveContext::selectObjects + (TColStd_PackedMapOfInteger &mapObj, + const NCollection_List &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 ::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::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::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& lstDrv) +{ + NCollection_Map::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); + } + } +} diff --git a/src/NIS/NIS_InteractiveContext.hxx b/src/NIS/NIS_InteractiveContext.hxx index da4b3a263f..29b8360d3b 100755 --- a/src/NIS/NIS_InteractiveContext.hxx +++ b/src/NIS/NIS_InteractiveContext.hxx @@ -9,9 +9,9 @@ #include #include -#include #include #include +#include #include #include @@ -23,36 +23,42 @@ class NIS_View; class Bnd_B3f; +class Bnd_B2f; /** * InteractiveContext is the central NIS structure that stores and manages - * all InteractiveObject instances as well as the Drawers for their + * all NIS_InteractiveObject instances as well as the Drawers for their * visualisation. * There may be one or more Views referred by an InteractiveContext instance. * Also there may be one or more InteractiveContext instances referring the same * View. However the latter case is not typical (see NIS_View description).
* To add or remove a View in a Context, use methods AttachView() and * DetachView(). - *

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. *

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: *

    *
  • change the presentation of the InteractiveObject (e.g., modify the color) *
  • - *
  • make the InteractiveObject visible or invisible;
  • + *
  • make the InteractiveObject visible or invisible, selectable or + * unselectable;
  • *
  • set Transparency;
  • *
  • select InteractiveObject interactively, including the hilighting and * the dynamic hilighting.
  • *
- * 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. *

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: *

    - *
  • 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 - *
  • + *
  • Copy its argument to the memory pool that is managed by the internal + * Allocator of NIS_InteractiveContext. Then the new instance of + * object is returned back in the same argument (in-out parameter);
  • + *
  • Store the copied instance in the internal vector of objects, so that + * the displayed object receives its ID (sequential address in the vector); + *
  • + *
  • Create a Drawer instance if necessary; attach the displayed interactive + * object to this instance (or to a relevant and already existing Drawer) + *
  • *
+ * 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(). + *

+ * 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. + *

+ * 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. + *

+ * 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::Iterator + GetDrawers () const + { return NCollection_Map::Iterator(myDrawers); } // ================ BEGIN Mangement of Objects ================ ///@name Management of Objects @@ -161,6 +195,31 @@ class NIS_InteractiveContext : public Standard_Transient * this method should follow the creation of an InteractiveObject instance * before it can be displayed. * @param theObj + * [in/out]Interactive object instance. If the object is displayed + * for the first time then the output value will be a new (cloned) object. + * @param theDrawer + * If this parameter is NULL, the default drawer is used for theObj, defined + * by the object type. Otherwise the given Drawer (must be present in this + * context) is used for theObj. Use the parameter to change the presentation + * of theObj. + * @param isUpdateViews + * If True, the drawer receives isUpdate flag, then it will recompute + * the presentations when Redraw event happens. You can leave the parameter + * to False if you have to make a number of similar calls, then you would + * call UpdateViews() in the end. + */ + Standard_EXPORT void Display (Handle_NIS_InteractiveObject& theObj, + const Handle_NIS_Drawer& theDrawer = NULL, + const Standard_Boolean isUpdateViews + = Standard_True); + + /** + * Make the given interactive object visible on top of other objects in + * the current context. + * If the object is not yet added to this context, it is added. Therefore + * this method should follow the creation of an InteractiveObject instance + * before it can be displayed. + * @param theObj * Interactive object instance. * @param theDrawer * If this parameter is NULL, the default drawer is used for theObj, defined @@ -173,10 +232,10 @@ class NIS_InteractiveContext : public Standard_Transient * to False if you have to make a number of similar calls, then you would * call UpdateViews() in the end. */ - Standard_EXPORT void Display (const Handle_NIS_InteractiveObject& theObj, - const Handle_NIS_Drawer& theDrawer = NULL, - const Standard_Boolean isUpdateViews - = Standard_True); + Standard_EXPORT void DisplayOnTop (Handle_NIS_InteractiveObject& theObj, + const Handle_NIS_Drawer& theDrawer = NULL, + const Standard_Boolean isUpdateViews + = Standard_True); /** * Make the given object invisible in the current InteractiveContext. @@ -209,45 +268,33 @@ class NIS_InteractiveContext : public Standard_Transient /** * Make all stored InteractiveObject instances visible, equivalent to * calling method Display() for all contained objects. - * @param isUpdateViews - * If True, the drawer receives isUpdate flag, then it will recompute - * the presentations when Redraw event happens. You can leave the parameter - * to False if you have to make a number of similar calls, then you would - * call UpdateViews() in the end. */ - Standard_EXPORT void DisplayAll (const Standard_Boolean isUpdateViews - = Standard_True); + Standard_EXPORT void DisplayAll (); /** * Make all stored InteractiveObject instances invisible, equivalent to * calling method Erase() for all contained objects. - * @param isUpdateViews - * If True, the drawer receives isUpdate flag, then it will recompute - * the presentations when Redraw event happens. You can leave the parameter - * to False if you have to make a number of similar calls, then you would - * call UpdateViews() in the end. */ - Standard_EXPORT void EraseAll (const Standard_Boolean isUpdateViews - = Standard_True); + Standard_EXPORT void EraseAll (); /** - * Clean the context of its contained objects. Drawers are not destroyed - * however all presentations should become empty. - * @param isUpdateViews - * If True, the drawer receives isUpdate flag, then it will recompute - * the presentations when Redraw event happens. You can leave the parameter - * to False if you have to make a number of similar calls, then you would - * call UpdateViews() in the end. + * Clean the context of its contained objects. Drawers are destroyed + * and all presentations become empty. */ - Standard_EXPORT void RemoveAll (const Standard_Boolean isUpdateViews - = Standard_True); + Standard_EXPORT void RemoveAll (); /** - * This method signal that the presenation should be refreshed in all - * Drawers and in all Views. + * This method signals that the presenation should be refreshed in all updated + * Drawers and in all Views. Calls Redraw() of each view from inside. */ Standard_EXPORT void UpdateViews (); + /** + * Similar to UpdateViews but forces all presentations to be rebuilt whether + * the drawers are marked as updated or not. + */ + Standard_EXPORT void RebuildViews(); + /** * Find the bounding box of all Objects displayed (visible) in the given View. * @param theBox @@ -402,24 +449,35 @@ class NIS_InteractiveContext : public Standard_Transient inline Standard_Boolean IsSelectable (const Standard_Integer objID) const { return (myMapNonSelectableObjects.Contains( objID ) == Standard_False); } + /** + * Set or reset the flag that tells to NIS_Drawer to create shared DrawList. + * The default mode (in Constructor) is True. + */ + inline void SetShareDrawList (Standard_Boolean isShare) + { myIsShareDrawList = isShare; } //@} // ====== END Selection API ================ protected: + //! Structure referencing one detected (picked) interactive entity. + struct DetectedEnt + { + Standard_Real Dist; //!< Distance on the view direction + NIS_InteractiveObject* PObj; //!< Pointer to interactive object + }; + // ---------- PROTECTED METHODS ---------- Standard_EXPORT void redraw (const Handle_NIS_View& theView, const NIS_Drawer::DrawType theType); - /*Standard_EXPORT void prepareList (const NIS_Drawer::DrawType theType, - const NIS_DrawList& theView, - NIS_Drawer * theDrawer); - */ /** * Detect the object selected by the given ray. * @param theSel * [out] The selected object that has the lowest ray distance. + * @param theDet + * [out] 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& theDet, const gp_Ax1& theAxis, const Standard_Real theOver, const Standard_Boolean isOnlySelectable @@ -461,9 +520,58 @@ class NIS_InteractiveContext : public Standard_Transient const gp_Trsf& theTrfInv, const Standard_Boolean isFullyIn)const; + /** + * Build a list of objects that are inside or touched by a polygon. + * @param mapObj + * [out] 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 &thePolygon, + const Bnd_B2f &thePolygonBox, + const gp_Trsf &theTrfInv, + const Standard_Boolean isFullyIn) const; + +private: + void deselectObj (const Handle_NIS_InteractiveObject&, + const Standard_Integer); + + void selectObj (const Handle_NIS_InteractiveObject&, + const Standard_Integer); + + const Handle_NIS_Drawer& + drawerForDisplay (const Handle_NIS_InteractiveObject&, + const Handle_NIS_Drawer&); + + void objectForDisplay (Handle_NIS_InteractiveObject&, + const NIS_Drawer::DrawType); + + Handle_NIS_Allocator + compactObjects (); + private: // ---------- PRIVATE FIELDS ---------- + /** + * Allocator for all data associated with objects. + */ + Handle_NIS_Allocator myAllocator; + /** * Container of InteractiveObject instances. */ @@ -483,11 +591,12 @@ class NIS_InteractiveContext : public Standard_Transient /** * Three maps indicating the state of contained objects: * - #0 - normally presented objects - * - #1 - hilighted objects (i.e., selected) - * - #2 - transparent objects + * - #1 - top objects + * - #2 - hilighted objects (i.e., selected) + * - #3 - transparent objects *
Each object can have only one entry in these maps. */ - TColStd_PackedMapOfInteger myMapObjects[3]; + TColStd_PackedMapOfInteger myMapObjects[4]; /** * Objects contained in this map are ignored by SetSelected methods, @@ -500,20 +609,15 @@ class NIS_InteractiveContext : public Standard_Transient */ Handle_NIS_SelectFilter mySelectFilter; - /** - * Current selection. - */ - // TColStd_PackedMapOfInteger mySelection; - /** * Current mode of selection. */ SelectionMode mySelectionMode; /** - * Allocator for arbitrary data associated with objects and drawers. + * Flag that allows to use single draw list for all views. */ - Handle_NCollection_IncAllocator myAllocator; + Standard_Boolean myIsShareDrawList; friend class NIS_View; friend class NIS_Drawer; diff --git a/src/NIS/NIS_InteractiveObject.cxx b/src/NIS/NIS_InteractiveObject.cxx index 0d093ae9e7..8a980fe549 100755 --- a/src/NIS/NIS_InteractiveObject.cxx +++ b/src/NIS/NIS_InteractiveObject.cxx @@ -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 (theValue); + Standard_Integer aValue = + static_cast (theValue * MaxTransparency); + if (aValue != static_cast(myTransparency)) + { + if (aValue <= 0) + myTransparency = 0; + else if (aValue >= 1000) + myTransparency = 1000u; else - myTransparency = 0.f; + myTransparency = static_cast (aValue); if (myDrawer.IsNull() == Standard_False && myID != 0) { + const Handle(NIS_Drawer) aDrawer = DefaultDrawer(0L); + aDrawer->Assign (GetDrawer()); + aDrawer->myTransparency = Transparency(); + SetDrawer (aDrawer, Standard_False); + NIS_InteractiveContext * aCtx = myDrawer->GetContext(); Standard_NullValue_Raise_if (aCtx == 0L, "NIS_InteractiveObject::SetTransparency: " @@ -113,6 +131,44 @@ const Bnd_B3f& NIS_InteractiveObject::GetBox () return myBox; } +//======================================================================= +//function : Clone +//purpose : +//======================================================================= + +void NIS_InteractiveObject::Clone (const Handle_NCollection_BaseAllocator&, + Handle_NIS_InteractiveObject& theDest) const +{ + if (theDest.IsNull() == Standard_False) + { + theDest->myID = 0; + theDest->myDrawer = myDrawer; + theDest->myDrawType = myDrawType; + theDest->myBaseType = myBaseType; + theDest->myIsHidden = myIsHidden; + theDest->myIsDynHilighted = myIsDynHilighted; + theDest->myIsUpdateBox = myIsUpdateBox; + theDest->myTransparency = myTransparency; + if (myIsUpdateBox == Standard_False) + theDest->myBox = myBox; + theDest->myAttributePtr = myAttributePtr; + } +} + +//======================================================================= +//function : CloneWithID +//purpose : +//======================================================================= + +void NIS_InteractiveObject::CloneWithID + (const Handle_NCollection_BaseAllocator& theAlloc, + Handle_NIS_InteractiveObject& theDest) +{ + Clone(theAlloc, theDest); + theDest->myID = myID; + myDrawer.Nullify(); +} + //======================================================================= //function : Intersect //purpose : @@ -125,6 +181,19 @@ Standard_Boolean NIS_InteractiveObject::Intersect (const Bnd_B3f&, return Standard_True; } +//======================================================================= +//function : Intersect +//purpose : +//======================================================================= + +Standard_Boolean NIS_InteractiveObject::Intersect + (const NCollection_List &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); } } } diff --git a/src/NIS/NIS_InteractiveObject.hxx b/src/NIS/NIS_InteractiveObject.hxx index 192d2027a5..806c82af77 100755 --- a/src/NIS/NIS_InteractiveObject.hxx +++ b/src/NIS/NIS_InteractiveObject.hxx @@ -16,22 +16,26 @@ * An InteractiveObject has the attributes: *

    *
  • 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
  • *
  • 3D Bounding box
  • - *
  • Presenatble state of the Object: Normal, Hilighted or Transparent.
  • + *
  • Presentable state of the Object: Normal, Hilighted or Transparent.
  • *
  • Visibility state (shown/hidden)
  • - *
  • Transparency level (0 to 1) - for transparent state
  • + *
  • Selectability (selectable/non-selectable)
  • + *
  • Transparency level (0 to 1 in 1/1000 steps) - for transparent state
  • *
* 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.
+ * 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.

- * Association with a Drawer instance is performed by method SetDrawer. This + * the associated drawer instance contains all relevant visual aspects. + *

+ * Association with a Drawer instance is performed by method SetDrawer(). This * method should not be called by any custom code, it is used internally by * NIS algorithms (in NIS_InteractiveContext::Display() for instance). If you * develop your own InteractiveObject type, you will need to call SetDrawer @@ -39,17 +43,68 @@ * @code * void MyIOClass::SetColor (const Quantity_Color& theColor); * { - * Handle(MyIOClassDrawer) aDrawer = new MyIOClassDrawer; + * const Handle(MyIOClassDrawer) aDrawer = + * static_cast(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 - *

+ * 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: + *

    + *
  • 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)
  • + *
  • Intersect (theBox, theTrsf, isFullIn) : check if the interactive object + * intersects with a 3D box. Transformation 'theTrf' is the inverse + * 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.
  • + *
  • Intersect (thePolygon, theTrsf, isFullIn) : similar to the previous + * method, but using a polygonal prism instead of box, for selection by + * closed curve or polygon.
  • + *
+ * + * @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 (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(myTransparency) / MaxTransparency; } /** * Set the Transparency factor. @@ -183,6 +246,23 @@ class NIS_InteractiveObject : public Standard_Transient inline void UnsetTransparency () { SetTransparency (0.); } + /** + * Create a copy of theObject except its ID. + * @param theAll + * Allocator where the Dest should store its private data. + * @param theDest + * [in-out] The target object where the data are copied. + */ + Standard_EXPORT virtual void + Clone (const Handle_NCollection_BaseAllocator& theAll, + Handle_NIS_InteractiveObject& theDest) const; + + /** + * The same as Clone() but also copies the ID. + */ + Standard_EXPORT void CloneWithID (const Handle_NCollection_BaseAllocator&, + Handle_NIS_InteractiveObject&); + /** * Intersect the InteractiveObject geometry with a line/ray. * @param theAxis @@ -227,6 +307,32 @@ class NIS_InteractiveObject : public Standard_Transient const gp_Trsf& theTrf, const Standard_Boolean isFull) const; + /** + * Intersect the InteractiveObject geometry with a selection polygon. + * The default implementation (in this abstract class) always returns True, + * signalling that every object pre-selected by its bounding box is + * automatically selected. The specializations should define a more correct + * behaviour.
+ * 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 &thePolygon, + const gp_Trsf &theTrf, + const Standard_Boolean isFull) const; + /** * Set the pointer to custom (arbitrary) data associated with the Object. */ @@ -267,18 +373,21 @@ class NIS_InteractiveObject : public Standard_Transient // ---------- PRIVATE FIELDS ---------- Handle_NIS_Drawer myDrawer; - Standard_Size myID : 26; - NIS_Drawer::DrawType myDrawType : 2; + Standard_Size myID; + NIS_Drawer::DrawType myDrawType : 3; + NIS_Drawer::DrawType myBaseType : 3; Standard_Boolean myIsHidden : 1; Standard_Boolean myIsDynHilighted: 1; Standard_Boolean myIsUpdateBox : 1; - Standard_ShortReal myTransparency; + unsigned int myTransparency : 10; + static const unsigned int MaxTransparency = 1000; protected: Bnd_B3f myBox; void * myAttributePtr; + friend class NIS_InteractiveContext; friend class NIS_Drawer; diff --git a/src/NIS/NIS_ObjectsIterator.cxx b/src/NIS/NIS_ObjectsIterator.cxx index fbeec2bbd7..b78527ce81 100755 --- a/src/NIS/NIS_ObjectsIterator.cxx +++ b/src/NIS/NIS_ObjectsIterator.cxx @@ -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; +} diff --git a/src/NIS/NIS_ObjectsIterator.hxx b/src/NIS/NIS_ObjectsIterator.hxx index d58f92621f..58421de3d8 100755 --- a/src/NIS/NIS_ObjectsIterator.hxx +++ b/src/NIS/NIS_ObjectsIterator.hxx @@ -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. diff --git a/src/NIS/NIS_Surface.cxx b/src/NIS/NIS_Surface.cxx index abb15a8616..943bcbc520 100755 --- a/src/NIS/NIS_Surface.cxx +++ b/src/NIS/NIS_Surface.cxx @@ -6,31 +6,39 @@ #include #include #include +#include +#include +#include +#include #include #include +#include +#include #include #include #include +#include #include #include +#include #include #include +#include +#include #include IMPLEMENT_STANDARD_HANDLE (NIS_Surface, NIS_InteractiveObject) IMPLEMENT_STANDARD_RTTIEXT(NIS_Surface, NIS_InteractiveObject) //======================================================================= -//function : defaultDrawer -//purpose : internal method (static) +//function : IsEqual +//purpose : Compare two triangulations, for NCollection_Map interface. //======================================================================= -inline Handle(NIS_SurfaceDrawer) defaultDrawer() +inline Standard_Boolean IsEqual(const Handle_Poly_Triangulation& theT0, + const Handle_Poly_Triangulation& theT1) { - const Handle(NIS_SurfaceDrawer) aDrawer = - new NIS_SurfaceDrawer(Quantity_NOC_SLATEBLUE4); - aDrawer->SetBackColor (Quantity_NOC_DARKGREEN); - return aDrawer; + return (theT0 == theT1); } //======================================================================= @@ -38,14 +46,36 @@ inline Handle(NIS_SurfaceDrawer) defaultDrawer() //purpose : //======================================================================= -NIS_Surface::NIS_Surface - (const Handle(Poly_Triangulation)& theTri, - const Handle_NCollection_BaseAllocator& theAlloc) -: mypNodes (NULL), - mypNormals (NULL), - myNNodes (0), - myNTriangles (0), - myAlloc (theAlloc) +NIS_Surface::NIS_Surface(const Handle_NCollection_BaseAllocator& theAlloc) + : myAlloc (theAlloc), + mypNodes (NULL), + mypNormals (NULL), + mypTriangles (NULL), + mypEdges (NULL), + myNNodes (0), + myNTriangles (0), + myNEdges (0), + myIsWireframe(0) +{ + if (myAlloc.IsNull()) + myAlloc = NCollection_BaseAllocator::CommonBaseAllocator(); +} + +//======================================================================= +//function : NIS_Surface +//purpose : +//======================================================================= + +NIS_Surface::NIS_Surface (const Handle(Poly_Triangulation)& theTri, + const Handle_NCollection_BaseAllocator& theAlloc) + : myAlloc (theAlloc), + mypNodes (NULL), + mypNormals (NULL), + mypEdges (NULL), + myNNodes (0), + myNTriangles (0), + myNEdges (0), + myIsWireframe(0) { if (myAlloc.IsNull()) myAlloc = NCollection_BaseAllocator::CommonBaseAllocator(); @@ -107,47 +137,75 @@ NIS_Surface::NIS_Surface //purpose : Constructor //======================================================================= -NIS_Surface::NIS_Surface - (const TopoDS_Shape& theShape, -// const Standard_Real theDeflection, - const Handle_NCollection_BaseAllocator& theAlloc) - : mypNodes (NULL), +NIS_Surface::NIS_Surface (const TopoDS_Shape& theShape, + const Standard_Real theDeflection, + const Handle_NCollection_BaseAllocator& theAlloc) + : myAlloc (theAlloc), + mypNodes (NULL), mypNormals (NULL), mypTriangles (NULL), + mypEdges (NULL), myNNodes (0), myNTriangles (0), - myAlloc (theAlloc) + myNEdges (0), + myIsWireframe (0) { if (myAlloc.IsNull()) myAlloc = NCollection_BaseAllocator::CommonBaseAllocator(); + Init (theShape, theDeflection); +} + +//======================================================================= +//function : Init +//purpose : Initialize the instance with a TopoDS_Shape. +//======================================================================= + +void NIS_Surface::Init (const TopoDS_Shape& theShape, + const Standard_Real theDeflection) +{ TopLoc_Location aLoc, aLocSurf; // Count the nodes and triangles in faces + NCollection_Map 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 + mypNodes = static_cast (myAlloc->Allocate(sizeof(Standard_ShortReal) * 3 * myNNodes)); mypNormals = static_cast (myAlloc->Allocate(sizeof(Standard_ShortReal) * 3 * myNNodes)); - mypTriangles = static_cast + mypTriangles = static_cast (myAlloc->Allocate(sizeof(Standard_Integer) * 3 * myNTriangles)); + mypEdges = static_cast + (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 + (myAlloc->Allocate(sizeof(Standard_Integer) * (aLen + 1))); + const gp_Pnt* pLast = &tabNode(arrNode(arrNode.Lower())); + pEdge[1] = arrNode(arrNode.Lower()) + nNodes1; + Standard_Integer iPNode(arrNode.Lower() + 1), iENode(1); + for (; iPNode <= arrNode.Upper(); iPNode++) + { + const Standard_Integer aN(arrNode(iPNode)); + if (pLast->SquareDistance(tabNode(aN)) < eps2) + { + aLen--; + } else { + pLast = &tabNode(aN); + pEdge[++iENode] = aN + nNodes1; + } + } + // Do not save very short polygons + if (aLen > 1) { + pEdge[0] = aLen; + mypEdges[myNEdges++] = pEdge; + } + } } } nNodes += tabNode.Length(); @@ -233,6 +344,11 @@ NIS_Surface::NIS_Surface } myNTriangles = nTriangles; } + if (GetDrawer().IsNull() == Standard_False) + { + setDrawerUpdate(); + } + setIsUpdateBox(Standard_True); } //======================================================================= @@ -241,6 +357,16 @@ NIS_Surface::NIS_Surface //======================================================================= NIS_Surface::~NIS_Surface () +{ + Clear(); +} + +//======================================================================= +//function : Clear +//purpose : +//======================================================================= + +void NIS_Surface::Clear () { if (myNNodes) { myNNodes = 0; @@ -251,6 +377,20 @@ NIS_Surface::~NIS_Surface () myNTriangles = 0; myAlloc->Free(mypTriangles); } + if (mypEdges) { + for (Standard_Integer i = 0; i < myNEdges; i++) { + myAlloc->Free(mypEdges[i]); + } + myNEdges = 0; + myAlloc->Free(mypEdges); + } + if (GetDrawer().IsNull() == Standard_False) { + GetDrawer()->SetUpdated(NIS_Drawer::Draw_Normal, + NIS_Drawer::Draw_Top, + NIS_Drawer::Draw_Transparent, + NIS_Drawer::Draw_Hilighted); + } + myBox.Clear(); } //======================================================================= @@ -258,9 +398,14 @@ NIS_Surface::~NIS_Surface () //purpose : //======================================================================= -Handle(NIS_Drawer) NIS_Surface::DefaultDrawer () const +NIS_Drawer * NIS_Surface::DefaultDrawer (NIS_Drawer * theDrawer) const { - return defaultDrawer(); + NIS_SurfaceDrawer * aDrawer = + theDrawer ? static_cast(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(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(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(DefaultDrawer(0L)); aDrawer->Assign (GetDrawer()); - aDrawer->myPolygonOffset = theValue; + aDrawer->myPolygonOffset = static_cast(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(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 (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 + (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 (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(mypNodes[iNode+0]), - static_cast(mypNodes[iNode+1]), - static_cast(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(mypNodes[iNode+0]), + static_cast(mypNodes[iNode+1]), + static_cast(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(mypNodes[3*anEdge[i+0]+0]), + static_cast(mypNodes[3*anEdge[i+0]+1]), + static_cast(mypNodes[3*anEdge[i+0]+2])), + gp_Pnt(static_cast(mypNodes[3*anEdge[i+1]+0]), + static_cast(mypNodes[3*anEdge[i+1]+1]), + static_cast(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 &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(mypNodes[iNode+0]), + static_cast(mypNodes[iNode+1]), + static_cast(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(mypNodes[3*anEdge[i+0]+0]), + static_cast(mypNodes[3*anEdge[i+0]+1]), + static_cast(mypNodes[3*anEdge[i+0]+2])), + gp_Pnt(static_cast(mypNodes[3*anEdge[i+1]+0]), + static_cast(mypNodes[3*anEdge[i+1]+1]), + static_cast(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 (GetDrawer()); diff --git a/src/NIS/NIS_Surface.hxx b/src/NIS/NIS_Surface.hxx index 68821159ea..01d16e47d3 100755 --- a/src/NIS/NIS_Surface.hxx +++ b/src/NIS/NIS_Surface.hxx @@ -15,35 +15,66 @@ class Handle_Poly_Triangulation; class TopoDS_Shape; /** - * This class describes a presentation of a meshed surface. + * Presentation of a meshed surface. + * Consists of 4 arrays: Nodes, Triangles, Normals and Edges. Normals are + * defined in nodes, so the number of stored normals is strictly the number of + * nodes. Edges is an array of pointers: each pointer starts an array of + * node indices that define a single edge (i.e., a polygon that can be closed or + * open, no matter). The first number in the edge is the number of nodes in it. + *

+ * 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. + *

+ * This class is conceived as replacement of AIS_Shape; both wireframe and + * shading modes are available for dynamic switching. */ class NIS_Surface : public NIS_InteractiveObject { public: + enum DisplayMode { + Shading, + Wireframe + }; + /** * Constructor */ Standard_EXPORT NIS_Surface(const Handle_Poly_Triangulation& theTri, - const Handle_NCollection_BaseAllocator& + const Handle_NCollection_BaseAllocator& theAlloc =0L); /** * Constructor. Creates the presentation of all faces in 'theShape' object. - * @aparm theShape + * @param theShape * Source geometry. It should contain triangulations inside. - * @param theAlloc + * @param theDeflection + * Absolute deflection for meshing 'theShape' if such meshing is needed. + * @param theAl * Allocator used for nodes and triangles in this presentation. */ Standard_EXPORT NIS_Surface(const TopoDS_Shape& theShape, -// const Standard_Real theDeflection, - const Handle_NCollection_BaseAllocator& - theAlloc = 0L); + const Standard_Real theDeflection, + const Handle_NCollection_BaseAllocator& theAl=0L); /** * Destructor */ Standard_EXPORT virtual ~NIS_Surface (); + /** + * Initialize the instance with a TopoDS_Shape. Used in constructor but can + * be called any time to redefine the geometry. + */ + Standard_EXPORT void Init (const TopoDS_Shape& theShape, + const Standard_Real theDefl); + + /** + * Deallocate all internal data structures. + */ + Standard_EXPORT void Clear (); + /** * Query the number of nodes. */ @@ -54,6 +85,11 @@ public: */ inline Standard_Integer NTriangles () const { return myNTriangles;} + /** + * Query the number of edges for wireframe display. + */ + inline Standard_Integer NEdges () const { return myNEdges; } + /** * Query the node by its index. * @return @@ -76,6 +112,18 @@ public: return &mypTriangles[theIndex * 3]; } + /** + * Access to array of integers that represents an Edge. + * @return + * Pointer to array where the 0th element is the number of nodes in the edge + * and the elements starting from the 1st are node indices. + */ + inline const Standard_Integer* + Edge (const Standard_Integer theIndex) const + { + return mypEdges[theIndex]; + } + /** * Query the normal vector at the given triangulation node (by index) * @return @@ -90,8 +138,8 @@ public: /** * Create a default drawer instance. */ - Standard_EXPORT virtual Handle_NIS_Drawer - DefaultDrawer () const; + Standard_EXPORT virtual NIS_Drawer * + DefaultDrawer (NIS_Drawer *) const; /** * Set the normal color for presentation. @@ -115,15 +163,31 @@ public: Standard_EXPORT void SetPolygonOffset (const Standard_Real theValue); /** - * Set the transparency factor. - * @param theValue - * 1.0 means full transparency, 0.0 means opaque. Valid quantities are in - * this interval. + * Set the display mode: Shading or Wireframe. + * The default mode is Shading. */ - Standard_EXPORT void SetTransparency (const Standard_Real theValue); + Standard_EXPORT void SetDisplayMode (const DisplayMode theMode); /** - * Intersect the InteractiveObject geometry with a line/ray. + * Query the current display mode: Shading or Wireframe. + */ + Standard_EXPORT DisplayMode + GetDisplayMode () const; + + /** + * Create a copy of theObject except its ID. + * @param theAll + * Allocator where the Dest should store its private data. + * @param theDest + * [in-out] The target object where the data are copied. If + * passed NULL then the target should be created. + */ + Standard_EXPORT virtual void + Clone (const Handle_NCollection_BaseAllocator& theAll, + Handle_NIS_InteractiveObject& theDest) const; + + /** + * Intersect the surface shading/wireframe geometry with a line/ray. * @param theAxis * The line or ray in 3D space. * @param theOver @@ -134,11 +198,11 @@ public: * on the ray. May be negative. */ Standard_EXPORT virtual Standard_Real - Intersect (const gp_Ax1& theAxis, + Intersect (const gp_Ax1& theAxis, const Standard_Real theOver) const; /** - * Intersect the InteractiveObject geometry with an oriented box. + * Intersect the surface shading/wireframe geometry with an oriented box. * @param theBox * 3D box of selection * @param theTrf @@ -153,8 +217,32 @@ public: const gp_Trsf& theTrf, const Standard_Boolean isFull)const; + /** + * Intersect the surface shading/wireframe geometry with a selection polygon. + * @param thePolygon + * the list of vertices of a free-form closed polygon without + * self-intersections. The last point should not coincide with the first + * point of the list. Any two neighbor points should not be confused. + * @param theTrf + * Position/Orientation of the polygon. + * @param isFullIn + * True if full inclusion is required, False - if partial. + * @return + * True if the InteractiveObject geometry intersects the polygon or is + * inside it + */ + Standard_EXPORT virtual Standard_Boolean Intersect + (const NCollection_List &thePolygon, + const gp_Trsf &theTrf, + const Standard_Boolean isFullIn) const; + protected: + /** + * Allocator for method Clone(). + */ + Standard_EXPORT NIS_Surface (const Handle_NCollection_BaseAllocator& theAl); + /** * Create a 3D bounding box of the object. */ @@ -168,15 +256,20 @@ protected: gp_XYZ& theNormal) const; private: + Handle_NCollection_BaseAllocator myAlloc; //! Array of nodes in triangles Standard_ShortReal * mypNodes; //! Array of normals (TriNodes) Standard_ShortReal * mypNormals; + //! Array of triangles (node indices) Standard_Integer * mypTriangles; + //! Array of edges, each edge is an array of indices prefixed by N nodes + Standard_Integer ** mypEdges; //! Number of nodes in triangles Standard_Integer myNNodes; Standard_Integer myNTriangles; - Handle_NCollection_BaseAllocator myAlloc; + Standard_Integer myNEdges; + Standard_Boolean myIsWireframe; public: // Declaration of CASCADE RTTI diff --git a/src/NIS/NIS_SurfaceDrawer.cxx b/src/NIS/NIS_SurfaceDrawer.cxx index dc9dba450e..8c69245304 100755 --- a/src/NIS/NIS_SurfaceDrawer.cxx +++ b/src/NIS/NIS_SurfaceDrawer.cxx @@ -13,6 +13,11 @@ #endif #include +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 (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 (1. + aValueCol[0]), - 0.5f * static_cast (1. + aValueCol[1]), - 0.5f * static_cast (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 (aValueCol[0]) + 0.1f; - gColorS[1] = 0.9f * static_cast (aValueCol[1]) + 0.1f; - gColorS[2] = 0.9f * static_cast (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 (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 (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(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); +} + diff --git a/src/NIS/NIS_SurfaceDrawer.hxx b/src/NIS/NIS_SurfaceDrawer.hxx index e815118323..a43e9a81cf 100755 --- a/src/NIS/NIS_SurfaceDrawer.hxx +++ b/src/NIS/NIS_SurfaceDrawer.hxx @@ -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(theOffset); + myPolygonOffset = static_cast(theOffset); } /** @@ -74,10 +73,9 @@ class NIS_SurfaceDrawer : public NIS_Drawer */ inline Standard_Real GetPolygonOffset () const { - return static_cast(myPolygonOffset); + return static_cast(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; diff --git a/src/NIS/NIS_Triangulated.cxx b/src/NIS/NIS_Triangulated.cxx index 8c7c677f67..67c1641120 100755 --- a/src/NIS/NIS_Triangulated.cxx +++ b/src/NIS/NIS_Triangulated.cxx @@ -13,9 +13,29 @@ 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(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(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(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(nPolygons); mypPolygons = static_cast (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 - (myAlloc->Allocate(sizeof(Standard_Integer)*3*nTri)); allocateNodes (nNodes); + + myNTriangles = nTri; + const Standard_Size nBytes = NBytesInd(3 * nTri, myIndexType); + mypTriangles = static_cast (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 - (myAlloc->Allocate(sizeof(Standard_Integer)*nPoints)); allocateNodes (nNodes); + + myNLineNodes = nPoints; + const Standard_Size nBytes = NBytesInd(nPoints, myIndexType); + mypLines = static_cast (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 - (myAlloc->Allocate(sizeof(Standard_Integer)*myNLineNodes)); allocateNodes (nNodes); + + myNLineNodes = nSegments*2; + const Standard_Size nBytes = NBytesInd(myNLineNodes, myIndexType); + mypLines = static_cast (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(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(mypTriangles) + (3 * ind); + pTri[0] = static_cast(iNode0); + pTri[1] = static_cast(iNode1); + pTri[2] = static_cast(iNode2); + } + break; + case 1: // 16bit + { + unsigned short * pTri = + reinterpret_cast(mypTriangles) + (3 * ind); + pTri[0] = static_cast(iNode0); + pTri[1] = static_cast(iNode1); + pTri[2] = static_cast(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(mypLines) + ind; + pInd[0] = static_cast(iNode); + } + break; + case 1: // 16bit + { + unsigned short * pInd = + reinterpret_cast(mypLines) + ind; + pInd[0] = static_cast(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(myNPolygons)) + Standard_OutOfRange::Raise ("NIS_Triangulated::SetPolygonNode"); + + Standard_Integer * aPoly = mypPolygons[indPoly]; + switch (myIndexType) { + case 0: // 8bit + { + unsigned char aNNode = * (reinterpret_cast(aPoly)); + if (static_cast(ind) >= aNNode) + Standard_OutOfRange::Raise ("NIS_Triangulated::SetPolygonNode"); + + unsigned char * pInd = + reinterpret_cast(aPoly) + ind + 1; + pInd[0] = static_cast(iNode); + } + break; + case 1: // 16bit + { + unsigned short aNNode = * (reinterpret_cast(aPoly)); + if (static_cast(ind) >= aNNode) + Standard_OutOfRange::Raise ("NIS_Triangulated::SetPolygonNode"); + + unsigned short * pInd = + reinterpret_cast(aPoly) + ind + 1; + pInd[0] = static_cast(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(myNPolygons)) + Standard_OutOfRange::Raise ("NIS_Triangulated::PolygonNode"); + Standard_Integer * aPoly = mypPolygons[indPoly]; + switch (myIndexType) { + case 0: // 8bit + { + unsigned char aNNode = * (reinterpret_cast(aPoly)); + aResult = static_cast(aNNode); + } + break; + case 1: // 16bit + { + unsigned short aNNode = * (reinterpret_cast(aPoly)); + aResult = static_cast(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(myNPolygons)) + Standard_OutOfRange::Raise ("NIS_Triangulated::PolygonNode"); + const Standard_Integer * aPoly = mypPolygons[indPoly]; + switch (myIndexType) { + case 0: // 8bit + { + const unsigned char * pInd = + reinterpret_cast(aPoly); + if (static_cast(ind) >= pInd[0]) + Standard_OutOfRange::Raise ("NIS_Triangulated::PolygonNode"); + + aResult = static_cast(pInd[ind + 1]); + } + break; + case 1: // 16bit + { + const unsigned short * pInd = + reinterpret_cast(aPoly); + if (static_cast(ind) >= pInd[0]) + Standard_OutOfRange::Raise ("NIS_Triangulated::PolygonNode"); + + aResult = static_cast(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(myNPolygons)) Standard_OutOfRange::Raise ("NIS_Triangulated::SetPolygon"); - Standard_Integer * anArray = static_cast - (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 + (myAlloc->Allocate (sizeof(unsigned char) * (theSz+1))); + mypPolygons[ind] = reinterpret_cast (anArray); + anArray[0] = static_cast(theSz); + } + break; + case 1: // 16bit + { + unsigned short * anArray = static_cast + (myAlloc->Allocate (sizeof(unsigned short) * (theSz+1))); + mypPolygons[ind] = reinterpret_cast (anArray); + anArray[0] = static_cast(theSz); + } + break; + default: // 32bit + { + Standard_Integer * anArray = static_cast + (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(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(theType); + else { + if (myPolygonType != static_cast(theType)) { + const Handle(NIS_TriangulatedDrawer) aDrawer = + static_cast(DefaultDrawer(0L)); + aDrawer->Assign (GetDrawer()); + aDrawer->myPolygonType = theType; + SetDrawer (aDrawer); + myPolygonType = static_cast(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(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(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(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(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 (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 + (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 + (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 + (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 + (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(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(mypNodes[iNode+0]), + static_cast(mypNodes[iNode+1]), 0.); + if (myNodeCoord > 2) + aPnt.SetZ (static_cast(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(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(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; - } - } 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; - } - - 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++) { + Standard_Integer i = 0; + if (myNodeCoord > 2) + for (; i < myNLineNodes; i+=2) { if (seg_line_intersect (theAxis.Location().XYZ(), theAxis.Direction().XYZ(), anOver2, - &mypNodes[3*arrNodes[i-1]], - &mypNodes[3*arrNodes[i-0]], + nodeArrAtInd(mypLines, i+0), + nodeArrAtInd(mypLines, i+1), &anInter)) if (anInter < aResult) aResult = anInter; } - 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; + 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) { + 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 (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, + 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 &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(mypNodes[iNode+0]), + static_cast(mypNodes[iNode+1]), 0.); + if (myNodeCoord > 2) + aPnt.SetZ (static_cast(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; + } + } + } + } + } + return aResult; +} /* ===================================================================== Function : determinant @@ -718,6 +1266,68 @@ int NIS_Triangulated::tri_line_intersect (const double start[3], return res; } +/* ===================================================================== +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(V1[0]-V0[0]), static_cast(V1[1]-V0[1]) }, + { static_cast(V2[0]-V0[0]), static_cast(V2[1]-V0[1]) }, + { static_cast(p2d[0]-V0[0]), static_cast(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 @@ -725,8 +1335,8 @@ 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 : @@ -830,6 +1513,207 @@ int NIS_Triangulated::seg_box_included (const Bnd_B3f& theBox, return aResult; } +//======================================================================= +//function : seg_polygon_intersect +//purpose : +//======================================================================= + +int NIS_Triangulated::seg_polygon_intersect + (const NCollection_List &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::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 &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 &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::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 - (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(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(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(theArray); + pResult = &mypNodes[myNodeCoord * pInd[theInd]]; + } + else if (myIndexType == 1) { + const unsigned short * pInd = + reinterpret_cast(theArray); + pResult = &mypNodes[myNodeCoord * pInd[theInd]]; + } + else { + pResult = &mypNodes[myNodeCoord * theArray[theInd]]; + } + return pResult; +} diff --git a/src/NIS/NIS_Triangulated.hxx b/src/NIS/NIS_Triangulated.hxx index 7bd0eccbdc..02bc9b2975 100755 --- a/src/NIS/NIS_Triangulated.hxx +++ b/src/NIS/NIS_Triangulated.hxx @@ -10,29 +10,67 @@ #include #include +#ifdef WNT +// Disable the warning "operator new unmatched by delete" +#pragma warning (push) +#pragma warning (disable:4291) +#endif + class Handle_NIS_TriangulatedDrawer; class NCollection_BaseAllocator; class Handle_NCollection_BaseAllocator; +class NIS_TriangulatedDrawer; /** - * Block of comments describing class NIS_Triangulated + * Interactive object that consists of triangles, lines and polygons without + * normals. Particularly can be used to render planar 2D shapes. + * + * @par 2D and 3D model + * Vertices are stored in an array of float numbers, 2 or 3 numbers per vertex. + * The number of dimensions is defined in the constructor, see the parameter + * 'is2D'. When 2D is defined then for all vertices the Z coordinate is 0. + * To display planar objects in a plane different from XOY you should subclass + * this type together with the correponding Drawer and store the transformation + * parameters. In Drawer subclass either in method BeforeDraw() or in method + * Draw() you would call glTranslate() or glMultMatrix() so that all vertices + * should be located in their proper positions. + * + * @par Compressed storage + * For efficient memory utilization, indice (triangles, segments, polygons) are + * 8-bit, 16-bit or 32-bit numbers. The width of this numeric representation is + * chosen automatically when the total number of nodes is passed in the + * constructor or in any Set* method. For example, if this number of nodes is + * smaller than 256 then 8-bit representation is selected. The choice is stored + * in 'myIndexType' data member. */ class NIS_Triangulated : public NIS_InteractiveObject { protected: - // Constants defining the mode (type) of presentation. They allow mixed type, - // e.g., Triangulation+Line. Line and Segments are not mixable, their mix is - // treated as Line only. + /** + * Constants defining the mode (type) of presentation. They allow mixed type, + * e.g., Triangulation+Line. Line and Segments are not mixable, their mix is + * treated as Line only. + */ enum { Type_None = 0, - Type_Loop = 1, // modifier to Line + Type_Loop = 1, //!< modifier to Line Type_Line = 2, Type_Segments = 4, Type_Triangulation = 8, Type_Polygons = 16 }; + public: + /** + * Enumerated type of polygon rendering. + */ + enum PolygonType { + Polygon_Default = 0, //!< Polygon as LINE, Triangulation as FILL + Polygon_Line = 1, //!< Both Polygon and Triangulation as LINE + Polygon_Fill = 2 //!< Both Polygon and Triangulation as FILL + }; + public: // ---------- PUBLIC METHODS ---------- @@ -42,9 +80,17 @@ class NIS_Triangulated : public NIS_InteractiveObject * (this number may be defined later in methods Set*Prs) as well as the * memory allocator where the nodes, lines and triangles will be stored by * this instance. + * @param nNodes + * Total number of nodes that will be initialized for this object + * @param is2D + * If true then the nodes will be 2D in plane Z=0, otherwise normal 3D. + * @param theAlloc + * Allocator for internal data */ Standard_EXPORT NIS_Triangulated(const Standard_Integer nNodes = 0, - const Handle_NCollection_BaseAllocator& =0L); + const Standard_Boolean is2D = Standard_False, + const Handle_NCollection_BaseAllocator& + theAlloc = 0L); /** * Define the polygonal presentration. @@ -137,9 +183,8 @@ class NIS_Triangulated : public NIS_InteractiveObject /** * Create a default drawer instance. */ - Standard_EXPORT virtual Handle_NIS_Drawer - DefaultDrawer () const; - + Standard_EXPORT virtual NIS_Drawer * + DefaultDrawer (NIS_Drawer *) const; /** * Define the coordinates of node [ind]. @@ -163,16 +208,14 @@ class NIS_Triangulated : public NIS_InteractiveObject /** * Allocate a single polygon, should be called for each polygon following - * the call SetPolygonsPrs(). + * the call SetPolygonsPrs(). The polygon can be filled by node indices using + * the method SetPolygonNode(). * @param ind * Index of the polygon, should be [0..Npolygons-1] * @param theSz * Number of points (segments) in the polygon. - * @return - * Pointer to the allocated buffer where you should store the indices - * of all polygon nodes in order, total "theSz" integers. */ - Standard_EXPORT Standard_Integer* SetPolygon (const Standard_Integer ind, + Standard_EXPORT void SetPolygon (const Standard_Integer ind, const Standard_Integer theSz); /** @@ -203,48 +246,43 @@ class NIS_Triangulated : public NIS_InteractiveObject * Query the number of polygons. */ inline Standard_Integer NPolygons () const - { return myNPolygons; } + { return static_cast(myNPolygons); } /** * Query the node by its index. * @return - * pointer to array of 3 Standard_ShortReal values (X,Y,Z coordinates) + * pointer to array of 2 or 3 Standard_ShortReal values {X,Y(,Z) coord} */ inline const Standard_ShortReal * Node (const Standard_Integer ind) const - { return &mypNodes[ind*3]; } + { return &mypNodes[ind * myNodeCoord]; } /** - * Query the triangle by its index. - * @return - * pointer to array of 3 Standard_Integer values (nodes 0, 1, 2) - */ - inline const Standard_Integer * Triangle (const Standard_Integer ind) const - { return &mypTriangles[ind*3]; } - - /** - * Query the node of line or segments by index in the array of node indices. - * This method does not make distinction of the presentation type - * (field myType), so the correct definition of ind is to be done by the - * caller. - * @return - * pointer to the Integer value representing the index of the node. - */ - inline const Standard_Integer * LineNode (const Standard_Integer ind) const - { return &mypLines[ind]; } - - - /** - * Query the polygon. + * Define the node of a polygon by index. + * @param indPoly + * Index of the Polygon, should be less than the number of polygons that is + * defined in SetPolygonsPrs() and can be returned by NPOlygons(). * @param ind - * rank of the polygon [0 .. N-1] - * @param outInd - * [out] array of vertex indice - * @return - * number of vertice in the polygon - the dimension of outInd array + * Index of the node in the Polygon. Should be less than the parameter theSz + * in the corresponding previous SetPolygon() call. + * @param iNode + * Index of the node in the given position of the Polygon. */ - inline const Standard_Integer Polygon (const Standard_Integer ind, - Standard_Integer* & outInd) const - { return * (outInd = mypPolygons[ind])++; } + Standard_EXPORT void SetPolygonNode + (const Standard_Integer indPoly, + const Standard_Integer ind, + const Standard_Integer iNode); + + /** + * Get the node with index 'ind' from the polygon number 'indPoly'. + */ + Standard_EXPORT Standard_Integer PolygonNode(const Standard_Integer indPoly, + const Standard_Integer ind)const; + + /** + * Get the number of nodes for the polygon number 'indPoly'. + */ + Standard_EXPORT Standard_Integer NPolygonNodes + (const Standard_Integer indPoly)const; /** * Set the boolean flag defining if the polygons or the triangulation @@ -252,24 +290,22 @@ class NIS_Triangulated : public NIS_InteractiveObject * Line/Segments. * @param isDrawPolygons * True defines that no triangulation is drawn, only polygons are. False - * defines that only triangulation is draw, no polygons. - * @param isUpdateV - * True if all views should be updated, otherwise wait till the next update + * defines that only triangulation is drawn, no polygons. */ Standard_EXPORT void SetDrawPolygons - (const Standard_Boolean isDrawPolygons, - const Standard_Boolean isUpdateViews - = Standard_True); + (const Standard_Boolean isDrawPolygons); + /** + * Set the type of polygon rendering. + */ + Standard_EXPORT void SetPolygonType + (const PolygonType theType); + /** * Set the normal color for presentation. * @param theColor * New color to use for the presentation. - * @param isUpdateV - * True if all views should be updated, otherwise wait till the next update */ - Standard_EXPORT void SetColor (const Quantity_Color& theColor, - const Standard_Boolean isUpdateV - = Standard_True); + Standard_EXPORT void SetColor (const Quantity_Color& theColor); /** * Get Normal, Transparent or Hilighted color of the presentation. @@ -283,34 +319,34 @@ class NIS_Triangulated : public NIS_InteractiveObject * Set the color for hilighted presentation. * @param theColor * New color to use for the presentation. - * @param isUpdateV - * True if all views should be updated, otherwise wait till the next update */ - Standard_EXPORT void SetHilightColor (const Quantity_Color& theColor, - const Standard_Boolean isUpdateV - = Standard_True); + Standard_EXPORT void SetHilightColor (const Quantity_Color& theColor); /** * Set the color for dynamic hilight presentation. * @param theColor * New color to use for the presentation. - * @param isUpdateV - * True if all views should be updated, otherwise wait till the next update */ - Standard_EXPORT void SetDynHilightColor(const Quantity_Color& theColor, - const Standard_Boolean isUpdateV - = Standard_True); + Standard_EXPORT void SetDynHilightColor(const Quantity_Color& theColor); /** * Set the width of line presentations in pixels. * @param theWidth * New line width to use for the presentation. - * @param isUpdateV - * True if all views should be updated, otherwise wait till the next update */ - Standard_EXPORT void SetLineWidth (const Standard_Real theWidth, - const Standard_Boolean isUpdateV - = Standard_True); + Standard_EXPORT void SetLineWidth (const Standard_Real theWidth); + + /** + * Create a copy of theObject except its ID. + * @param theAll + * Allocator where the Dest should store its private data. + * @param theDest + * [in-out] The target object where the data are copied. If + * passed NULL then the target should be created. + */ + Standard_EXPORT virtual void + Clone (const Handle_NCollection_BaseAllocator& theAll, + Handle_NIS_InteractiveObject& theDest) const; /** * Intersect the InteractiveObject geometry with a line/ray. @@ -323,7 +359,7 @@ class NIS_Triangulated : public NIS_InteractiveObject * detected. Otherwise returns the coordinate of thePnt on the ray. May be * negative. */ - Standard_EXPORT Standard_Real + Standard_EXPORT virtual Standard_Real Intersect (const gp_Ax1& theAxis, const Standard_Real theOver) const; @@ -343,19 +379,52 @@ class NIS_Triangulated : public NIS_InteractiveObject const gp_Trsf& theTrf, const Standard_Boolean isFull)const; - Standard_EXPORT static int tri_line_intersect (const double start[3], - const double dir[3], - const float V0[3], - const float V1[3], - const float V2[3], - double * tInter); + /** + * Intersect the InteractiveObject geometry with a selection polygon. + * @param thePolygon + * the list of vertices of a free-form closed polygon without + * self-intersections. The last point should not coincide with the first + * point of the list. Any two neighbor points should not be confused. + * @param theTrf + * Position/Orientation of the polygon. + * @param isFullIn + * True if full inclusion is required, False - if partial. + * @return + * True if the InteractiveObject geometry intersects the polygon or is + * inside it + */ + Standard_EXPORT virtual Standard_Boolean Intersect + (const NCollection_List &thePolygon, + const gp_Trsf &theTrf, + const Standard_Boolean isFullIn) const; - Standard_EXPORT static int seg_line_intersect (const gp_XYZ& aStart, - const gp_XYZ& aDir, - const double over2, - const float V0[3], - const float V1[3], - double * tInter); + Standard_EXPORT static int tri_line_intersect (const double start[3], + const double dir[3], + const float V0[3], + const float V1[3], + const float V2[3], + double * tInter); + + Standard_EXPORT static int tri2d_line_intersect(const double start[3], + const double dir[3], + const float V0[2], + const float V1[2], + const float V2[2], + double * tInter); + + Standard_EXPORT static int seg_line_intersect (const gp_XYZ& aStart, + const gp_XYZ& aDir, + const double over2, + const float V0[3], + const float V1[3], + double * tInter); + + Standard_EXPORT static int seg2d_line_intersect(const gp_XYZ& aStart, + const gp_XYZ& aDir, + const double over2, + const float V0[2], + const float V1[2], + double * tInter); Standard_EXPORT static int seg_box_intersect (const Bnd_B3f& theBox, const gp_Pnt thePnt[2]); @@ -363,12 +432,58 @@ class NIS_Triangulated : public NIS_InteractiveObject Standard_EXPORT static int seg_box_included (const Bnd_B3f& theBox, const gp_Pnt thePnt[2]); + Standard_EXPORT static int seg_polygon_intersect + (const NCollection_List &thePolygon, + const gp_XY thePnt[2]); + + Standard_EXPORT static int seg_polygon_included + (const NCollection_List &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 &thePolygon, + const gp_XY &thePoint); + + /** + * Implements deallocation of the object instance + */ + Standard_EXPORT virtual void Delete () const; + + /** + * Operator new for memory allocation uses Open CASCADE memory manager + */ + void* operator new (size_t size) + { + return Standard::Allocate(size); + } protected: + /** + * Allocator-based operator new for dynamic allocations in method Clone() + */ + void* operator new (Standard_Size theSz, + const Handle(NCollection_BaseAllocator)& theAllocator) + { + return theAllocator->Allocate(theSz); + } + /** * Create a 3D bounding box of the object. */ @@ -380,30 +495,49 @@ class NIS_Triangulated : public NIS_InteractiveObject */ Standard_EXPORT void allocateNodes (const Standard_Integer nNodes); + /** + * Get the node pointed by the i-th index in the array. + */ + Standard_EXPORT gp_Pnt nodeAtInd (const Standard_Integer * theArr, + const Standard_Integer i) const; + + /** + * Get the node pointed by the i-th index in the array. + */ + Standard_EXPORT float* nodeArrAtInd (const Standard_Integer * theArr, + const Standard_Integer i) const; + protected: // ---------- PROTECTED FIELDS ---------- - /** - * Combination of Type_* constants - */ - Standard_Integer myType; - Standard_ShortReal * mypNodes; - Standard_Integer * mypTriangles; - Standard_Integer * mypLines; - Standard_Integer ** mypPolygons; - Standard_Integer myNNodes; - Standard_Integer myNTriangles; - Standard_Integer myNPolygons; - Standard_Integer myNLineNodes; - NCollection_BaseAllocator * myAlloc; - Standard_Boolean myIsDrawPolygons; + NCollection_BaseAllocator * myAlloc; //!< Usually from InteractiveContext + Standard_Integer myType; //!< Combination of Type_* constants + Standard_ShortReal * mypNodes; + Standard_Integer * mypTriangles; + Standard_Integer * mypLines; + Standard_Integer ** mypPolygons; + Standard_Integer myNNodes; + Standard_Integer myNTriangles; + Standard_Integer myNLineNodes; + unsigned int myNPolygons : 24; + Standard_Boolean myIsDrawPolygons : 1; + Standard_Boolean myIsCloned : 1; //!< How it is allocated + unsigned int myIndexType : 2; //!< 0:8bit, 1:16bit, 2:32bit + unsigned int myNodeCoord : 2; //!< 2 or 3 coordinates + unsigned int myPolygonType : 2; public: // Declaration of CASCADE RTTI DEFINE_STANDARD_RTTI (NIS_Triangulated) + + friend class NIS_TriangulatedDrawer; }; // Definition of HANDLE object using Standard_DefineHandle.hxx DEFINE_STANDARD_HANDLE (NIS_Triangulated, NIS_InteractiveObject) +#ifdef WNT +#pragma warning (pop) +#endif + #endif diff --git a/src/NIS/NIS_TriangulatedDrawer.cxx b/src/NIS/NIS_TriangulatedDrawer.cxx index f2d09c8087..4940e21e45 100755 --- a/src/NIS/NIS_TriangulatedDrawer.cxx +++ b/src/NIS/NIS_TriangulatedDrawer.cxx @@ -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 (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(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 (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(pObject->mypPolygons[i]) + 1; + else if (pObject->myIndexType == 1) + anArray = reinterpret_cast(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); } } + } + diff --git a/src/NIS/NIS_TriangulatedDrawer.hxx b/src/NIS/NIS_TriangulatedDrawer.hxx index 38dc094b72..70d8c41dd9 100755 --- a/src/NIS/NIS_TriangulatedDrawer.hxx +++ b/src/NIS/NIS_TriangulatedDrawer.hxx @@ -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; diff --git a/src/NIS/NIS_View.cxx b/src/NIS/NIS_View.cxx index 334835bc9f..d5d1db976d 100755 --- a/src/NIS/NIS_View.cxx +++ b/src/NIS/NIS_View.cxx @@ -8,6 +8,8 @@ #include #include #include +#include +#include #ifdef WNT #include #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::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::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 &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 aPoints; + NCollection_List::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::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 LstDetected; Standard_Real aDistance (0.1 * RealLast()); Handle(NIS_InteractiveObject) aSelected, aTmpSel; + LstDetected aDetected; NCollection_List::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; } + diff --git a/src/NIS/NIS_View.hxx b/src/NIS/NIS_View.hxx index 4f90f77505..fe55cf9128 100755 --- a/src/NIS/NIS_View.hxx +++ b/src/NIS/NIS_View.hxx @@ -11,6 +11,10 @@ #include #include #include +#include +#include +#include +#include class NIS_InteractiveContext; class gp_Ax1; @@ -58,9 +62,49 @@ class NIS_View : public V3d_OrthographicView Standard_EXPORT void SetWindow(const Handle_Aspect_Window &theWindow); /** - * Zoom the view to fit to visible objects size and positions. + * Indicate whether to draw hilighted objects on top of all other ones */ - Standard_EXPORT void FitAll3d (); + inline void SetHilightOnTop(const Standard_Boolean theTop = Standard_True) + { myIsTopHilight = theTop; } + + /** + * Indicate whether to hilight selected object dynamically + * By default dynamic hilight works on all objects independently on its + * selected/non-selected state. + * This behaviour differs from the behaviour of AIS interactive context, + * that doesn't hilight dynamically (on mouse movements) selected objects. + * In the case both context are used in the same view the behaviour of both + * context can be made consistent by setting this flag to False + */ + inline void SetDynHilightSelected (const Standard_Boolean + theHilight = Standard_True) + { myDoHilightSelected = theHilight; } + + /** + * Zoom the view to fit to visible objects size and positions. + * @param theCoef + * Relative margin in both X and Y dimensions. For example, value 1.0 + * will fit to twice the actual size. + * @return + * True if operation performed, False if failed (most likely because of + * very big actual scale) + */ + Standard_EXPORT Standard_Boolean FitAll3d (const Quantity_Coefficient theCoef + = 0.01); + + /** + * Gets bounding box covering objects displayed in viewer. + */ + Standard_EXPORT Bnd_B3f GetBndBox() const; + + /** + * Gets bounding box covering objects displayed in viewer. + * If operation is fails when Xmax < Xmin abd Ymax < Ymin + */ + Standard_EXPORT void GetBndBox(Standard_Integer& theXMin, + Standard_Integer& theXMax, + Standard_Integer& theYMin, + Standard_Integer& theYMax ) const; // /** // * Destructor. @@ -80,21 +124,30 @@ class NIS_View : public V3d_OrthographicView */ Standard_EXPORT void DynamicUnhilight(const Handle_NIS_InteractiveObject&); + /** + * Unhilights the currently hilighted object. + */ + inline void DynamicUnhilight() { DynamicUnhilight(myDynHilighted); } + /** * Set or unset the selected (hilighted) state of the object that is under * the coordinates theX, theY. * @param theX * X coordinate of the view window - * @param theX + * @param theY * X coordinate of the view window * @param isForceMult * True if the effect of multi-Selection should be forced (e.g., when Shift * is pressed). + * @param theRedraw + * True to redraw view automatically (default value). */ Standard_EXPORT void Select (const Standard_Integer theX, const Standard_Integer theY, const Standard_Boolean isForceMult - = Standard_False); + = Standard_False, + const Standard_Boolean theRedraw + = Standard_True); /** * Set or unset the selected (hilighted) state of the objects that are @@ -114,6 +167,8 @@ class NIS_View : public V3d_OrthographicView * True if only those objects are processed that are fully inside the * selection rectangle. False if objects fully or partially included in * the rectangle are processed. + * @param theRedraw + * True to redraw view automatically (default value). */ Standard_EXPORT void Select (const Standard_Integer theXmin, const Standard_Integer theYmin, @@ -122,7 +177,35 @@ class NIS_View : public V3d_OrthographicView const Standard_Boolean isForceMult = Standard_False, const Standard_Boolean isFullyIncluded - = Standard_False); + = Standard_False, + const Standard_Boolean theRedraw + = Standard_True); + + /** + * Set or unset the selected (hilighted) state of the objects that are + * intersected by 2D polygon in the view + * @param thePolygon + * defines the vertices of a free-form closed polygon without + * self-intersections. The last point should not coincide with the first + * point of the list. Points are interpreted as X and Y integer coordinates + * of the view window. Any two neighbor points should not be confused. + * @param isForceMult + * True if the effect of multi-Selection should be forced (e.g., when Shift + * is pressed). + * @param isFullyIncluded + * True if only those objects are processed that are fully inside the + * selection rectangle. False if objects fully or partially included in + * the rectangle are processed. + * @param theRedraw + * True to redraw view automatically (default value). + */ + Standard_EXPORT void Select (const NCollection_List &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 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 myContexts; Handle_NIS_InteractiveObject myDynHilighted; + Standard_Boolean myIsTopHilight : 1; + Standard_Boolean myDoHilightSelected : 1; + NCollection_Vector myDetected; + TColStd_PackedMapOfInteger myExListId; friend class NIS_InteractiveContext; diff --git a/src/ViewerTest/ViewerTest.cxx b/src/ViewerTest/ViewerTest.cxx index ad190b9903..4f9f8b6a96 100755 --- a/src/ViewerTest/ViewerTest.cxx +++ b/src/ViewerTest/ViewerTest.cxx @@ -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; }