Playing with NIS (New Interactive Services)

Hi, I tried to display something with NIS (NIS_View and NIS_InteractiveContext) but can't have something represented (just a trihedron with V3d_View::TriedronDisplay()).

I create a V3d_Viewer as normal, pass it to NIS_View, then create a NIS_InteractiveContext and call AttachView().

I load an IGES file and create a NIS_Surface and a NIS_SurfaceDrawer for each topological face (triangulated).

My code is :

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

// Create the V3d viewer
Handle_Aspect_GraphicDevice graphicDevice;
#ifdef WNT
graphicDevice = new Graphic3d_WNTGraphicDevice;
#else
graphicDevice = new Graphic3d_GraphicDevice(std::getenv("DISPLAY"));
#endif // WNT
// Create the named OCC 3d viewer.
Handle_V3d_Viewer v3dViewer = new V3d_Viewer(graphicDevice,
(short*)("Viewer3d"));
// Configure the OCC 3d viewer.
v3dViewer->SetDefaultViewSize(1000.0);
v3dViewer->SetDefaultViewProj(V3d_XposYnegZpos);
v3dViewer->SetDefaultBackgroundColor(Quantity_NOC_BLACK);
v3dViewer->SetDefaultVisualization(V3d_ZBUFFER);
v3dViewer->SetDefaultShadingModel(V3d_GOURAUD);
v3dViewer->SetUpdateMode(V3d_WAIT);
v3dViewer->SetDefaultSurfaceDetail(V3d_TEX_NONE);
// Initialize the OCC 3d viewer.
v3dViewer->Init();
v3dViewer->SetDefaultLights();
v3dViewer->SetLightOn();
// Create the OCC interactive context.
Handle_NIS_InteractiveContext nisCxt = new NIS_InteractiveContext;
// Build the GUI.
// ...
Handle_NIS_View nisView = new NIS_View(v3dViewer);
nisCxt->AttachView(nisView);
// ...
// Load an IGES shape
TopoDS_Shape shape = ...
if (!shape.IsNull())
{
for (TopExp_Explorer exp(shape, TopAbs_FACE); exp.More(); exp.Next())
{
const TopoDS_Face& face = TopoDS::Face(exp.Current());
BRepMesh::Mesh(exp.Current(), 0.1);
TopLoc_Location location;
Handle_Poly_Triangulation triangulation =
BRep_Tool::Triangulation(face, location);
if (!triangulation.IsNull())
{
Handle_NIS_Surface surface = new NIS_Surface(triangulation);
Handle_NIS_SurfaceDrawer surfaceDrawer =
new NIS_SurfaceDrawer(Quantity_NOC_RED);
nisCxt->Display(surface);
}
}
}
nisCxt->UpdateViews();

What is wrong with this code ? NIS seem very promising.

Alexander Grigoriev's picture

Dear Hugues,

You should create a window (e.g., on Windows you would construct an instance of Handle_WNT_Window). This window instance should be passed to the constructor of NIS_View (2nd parameter), or it can be delivered in a separate call of the method NIS_View::SetWindow(). This will likely solve the problem.

Normally you should not create or use a NIS_Drawer instance, it is maintained internally by NIS context and interactive object. In order to set the color, the methods NIS_Surface::SetColor and NIS_Surface::SetBackColor should be used.

Also, you can initialize NIS_Surface with a triangulation but the location will be ignored. As the result there may be displayed a collection of surface patches in arbitrary places that will not resemble the original IGES shape. I suggest you to use the other constructor of NIS_Surface that takes a TopoDS_Shape object (using directly the faces from your explorer loop).

Hope my remarks are helpful.

Hugues Delorme's picture

Alexander,

I already initialized the NIS_View like you said (I skipped that part from my previous post) :

nisView = new NIS_View(v3dViewer);
int windowHandle = (int)(widget->winId());
short hi = static_cast(windowHandle >> 16);
short lo = static_cast(windowHandle);
Handle_Aspect_GraphicDevice device = v3dViewer->Device();
#ifdef WNT
Handle_WNT_Window hWnd =
new WNT_Window(Handle_Graphic3d_WNTGraphicDevice::DownCast(device),
static_cast(hi),
static_cast(lo));
hWnd->SetFlags(WDF_NOERASEBKGRND);
#else
Handle_Xw_Window hWnd =
new Xw_Window(Handle(Graphic3d_GraphicDevice)::DownCast(device),
static_cast(hi),
static_cast(lo),
Xw_WQ_SAMEQUALITY);
#endif // WNT
nisView->SetWindow(hWnd);
if (!hWnd->IsMapped())
hWnd->Map();

nisView->TriedronDisplay(Aspect_TOTP_LEFT_LOWER,
Quantity_NOC_WHITE,
0.1, V3d_ZBUFFER);
nisView->MustBeResized();

Note that I am on KUbuntu 8.04.

Now I create NIS_Surface like you advised, but I can't see the shapes in the NIS_View, nothing is displayed apart the bottom-left trihedron :

TopoDS_Shape shape = // Load an IGES shape.
if (!shape.IsNull())
{
for (TopExp_Explorer exp(shape, TopAbs_FACE); exp.More(); exp.Next())
{
const TopoDS_Face& face = TopoDS::Face(exp.Current());
BRepMesh::Mesh(face, 0.1);
Handle_NIS_Surface surface = new NIS_Surface(face);
nisCxt->Display(surface);
}
nisCxt->UpdateViews();
}

What am I missing ? I can't see what's wrong with that code.

Alexander Grigoriev's picture

Hugues,

It is better to provide hWnd in the constructor of NIS_View.

Your code after the view initialization seems to be OK. I do not have access to KUbuntu, instead I use WNT. The following code executes well in DRAW environment that should be available on your platform. You can add this function to ViewerTest package, add the TCL command to ViewerTest::Commands() then start DRAWEXE and issue the commands in TCL prompt:
pload
pload AISV
vinit
auxNIS
the last command starts the code. If it works on your box you can check and compare how it is done in ViewerTest.
=============================
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

Standard_Integer auxNIS (Draw_Interpretor& dout, Standard_Integer n, char** a)
{
// using the NIS view previously created by the command "vinit"
const Handle(V3d_View) aView = ViewerTest::CurrentView();
aView->TriedronDisplay(Aspect_TOTP_LEFT_LOWER,
Quantity_NOC_WHITE,
0.1, V3d_ZBUFFER);
aView->MustBeResized();

// Create the cylindrical shape (shell of 3 faces)
BRepPrim_Cylinder aCyl(gp_Ax2(gp_Pnt(0., 0., 0.), gp_Dir(0., 0., 1.)),
10., 20.);
TopoDS_Shape shape = aCyl.Shell();
for (TopExp_Explorer exp(shape, TopAbs_FACE); exp.More(); exp.Next())
{
const TopoDS_Face& face = TopoDS::Face(exp.Current());
BRepMesh::Mesh(face, 0.1);
Handle_NIS_Surface surface = new NIS_Surface(face);
TheNISContext()->Display(surface);
}
TheNISContext()->UpdateViews();

return 0;
}
=============================

Hugues Delorme's picture

Alexander,

I tried to give the hWnd to the constructor of NIS_View instead of calling V3d_View::SetWindow(), but had no success. Anyway the NIS_View seems good as I can display a triehdron and do rotations, pannings and zoom.

I think the problem is NIS_SurfaceDrawer or NIS_InteraciveContext. I also tried to create and display with NIS your testing cylinder but still no success, even on Windows XP.

I have no idea how to add DRAW extensions to ViewerTest, this is too tricky for me.

I really would like to use NIS, what is the problem ? There is no problem with this code in AIS, maybe NIS is not mature enough.

Hugues Delorme's picture

OK I finally managed to add auxNIS() to the ViewerCommands list, and recompiled TKViewerTest. I tried the command with DRAWEXE, it displayed the testing cylinder (but nearly half of the cylinder is hidden). NIS seems to work inside DRAWEXE.

I took a look at the source code in ViewerTest_ViewerCommands.cxx and I figured out that the main difference with my code is how the Window is created.
In ViewerTest_ViewerCommands.cxx (line 178 to 186) :

if ( GetG3dDevice().IsNull() ) GetG3dDevice() =
new Graphic3d_GraphicDevice(getenv("DISPLAY"),Xw_TOM_READONLY);
if ( VT_GetWindow().IsNull() ) {
VT_GetWindow() = new Xw_Window(GetG3dDevice(),
"Test3d",
0.,0.60,0.40,0.40,
Xw_WQ_3DQUALITY,
Quantity_NOC_BLACK);

In my source code :

Handle_Aspect_GraphicDevice graphicDevice = new Graphic3d_GraphicDevice(std::getenv("DISPLAY"));
Handle_Xw_Window hWnd =
new Xw_Window(Handle_Graphic3d_GraphicDevice::DownCast(graphicDevice), this->winId());

"this->winId()" is the window system identifier of a QGLWidget where the view will be displayed.

I added also those lines :

nisView->SetDegenerateModeOn();
nisView->SetZClippingDepth(0.5);
nisView->SetZClippingWidth(1.0 / 2.0);

#ifndef WNT
Handle(Graphic3d_GraphicDevice) g3dDevice =
Handle_Graphic3d_GraphicDevice::DownCast(graphicDevice);
Standard_Address theDisplay = g3dDevice->XDisplay();
Display *display = (Display*)theDisplay;
XSynchronize(display, 1);
XSynchronize(display, 0);
#endif // WNT

But this still has no effect. Now I don't see what is the clear difference apart from parameters about the creation of V3d_Viewer. This is really annoying.
Have anyone here already tried NIS with Qt ? Alexander, Pete Dolbey ! Help !!!

P Dolbey's picture

If you've got a simple example that demonstrates the problem I can try it out, but I'm running Vista not Kubutu. You can email me at [pdolbey at users dot sourceforge dot net] to discuss.

Pete

p.s. did you try a FitAll() or ZFitAll().

Alexander Grigoriev's picture

Dealing with NIS_View it is better to call its method FitAll3d:
- FitAll fits to only AIS objects
- FitAll3d fits to all AIS and NIS objects

Also you can check the Qt application located in samples/standard/qt that is included in the standard distribution. It implements a V3d_View inside a Qt widget, and it can be easily modified to accommodate NIS_View & NIS_InteractiveContext. I checked, this can show the cylinder as NIS_Surface object, under Win32.

Note that in the sample the window is defined as a special Qt widget (class View, inheriting QWidget) rather than QGLWidget.

Hugues Delorme's picture

Hi Alexander,

Can you send me the code you modified to make the Qt standard sample based on NIS ?
My email is : delorme.hugues AT gmail DOT com.
Thanks a bunch !

Hugues Delorme's picture

Thanks to Pete Dolbey (again thank you Pete) I have a working example of a small NIS-based viewer.

I am displaying NIS surfaces from an IGES model. I can see them (note I had to call V3d_View::SetDepth() on the NIS view to fully see the surfaces), but the "interior" of the surfaces is not drawn, only the "exterior".
This is strange. I tried to call NIS_Surface::SetColor() and NIS_Surface::SetBackColor() but with no success. What could be the problem ?

I also create NIS_Triangulated objects to display the edges of my IGES model. I use a Line presentation (calling NIS_Triangulated::SetLinePrs() and ::SetNode() and setLineNode()). Actually I translate the Poly_Polygon3D I get from BRep_Tool::Polygon3D() for each edge.
This works, also selection behaves far far better than AIS when lots of faces and edges are displayed. I just would mind if it easily possible to have a bigger line width for dynamic highlighting because for now hilighted edges are difficult to see.

A last question how would you display points with NIS ? Maybe by using AIS ?

Hugues Delorme's picture

EDIT

I have tested under Windows, the "interior / exterior" problem does not appear, so this is at least a bug for the Linux version of NIS_Surface and/or NIS_SurfaceDrawer.

I'm not an expert in OpenGL but I will give a look at the source code of NIS_Surface* classes.

Alexander, can you test one of your sample under Linux ?
I remember well that with the auxNIS command in DRAWEXE I have had the same display problem for the cylinder example.

Hugues Delorme's picture

OK I looked at NIS_SurfaceDrawer.cxx.
I suspect this is a blending issue. See ligns 186 to 189 (or 194 to 197) :
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]);

If normalColor == backColor then the NIS_Surface displayed is almost invisible : I just see a very very tranparent surface.
Some OpenGl doc (http://www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/...) says that :

"Transparency is best implemented using blend function (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) with primitives sorted from farthest to nearest"

Is this the case ? Are the primitives of a NIS_Surface sorted from farthest to nearest ? I can't figure this out from the source code of NIS_Surface.cxx.

Now if I uncomment the lign 189 (ie we want a normal call to glColor3d()) then there is no problem but blending is not taken into account.

Svetlozar Kostadinov's picture

I had probably the same difficulties with the transparency. If you change the blending function to...

glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA);

...the result is better.

Hugues Delorme's picture

I changed the blending function as you suggested, I get plain black surfaces. Have you tried on Linux ?

Svetlozar Kostadinov's picture

:( Strange, on XP works perfectly! Try different combinations, one should be OK.

Carlos's picture

Hi,

¿Have you solved the problems with transparency?.

In my case if I set transparency to NIS_Surfaces, it works but the result it is not OK as it appears some green surfaces, the ones are in the rear.

I also tried to use SetTransparency with NIS_Triangulated objects but in this case it does not work at all, even if the transparency is stated to 1.

Another question.

I only use basic primitives (BRepPrimAPI_MakeBox, BRepPrimAPI_MakeCylinder and Lines) so I do not have experienced with the Mesh package. In order to create a NIS_Surface I use

TopoDS_Shape S1 =BRepPrimAPI_MakeCylinder (gp_Ax2(gp_Pnt(cx,cy,cz), gp_Dir(dirx,diry,dirz)),radio,altura);

BRepMesh::Mesh(S1, d);
Handle_NIS_Surface surface = new NIS_Surface(S1);

I have played with different values of d, and I understand that this values is related with the quality of the mesh. I have made some trials and although this parameter it does not affect to the display of the cylinder, it takes less time with greater values of d.

In my case, for the value of 0.1, it takes the same time to display the cylinder that with the standard AIS_Context. If the d value is increased to 50, the time is reduced by 1/3.

As the mesh quality apparently does not affect to the display quality, is there another possibility to create simpler meshes of these objects.?

Regards,

Pawel's picture

Hi Hugues,

would you mind sharing the initialization code for the NIS viewer or a small code sample? I was experimenting with NIS and I'm facing the same issues you described in your posts.

Thanks in advance
Pawel

Hugues Delorme's picture

Hi Pawel,

What you could first try is to attach the NIS view to the NIS context before building the GUI that holds the NIS view :

// ...
// Create the OCC interactive context and attach the view.
Handle_NIS_InteractiveContext nisCxt = new NIS_InteractiveContext;
Handle_NIS_View nisView = new NIS_View(v3dViewer);
nisCxt->AttachView(nisView);
// Build the GUI ...

More precisely, as Pete Dolbey said in private discussion, the NIS view must be initialized before any paint event of the GUI.

If it does not solve the problem, I can send you a small but complete working example. Just give here you email address.

Svetlozar Kostadinov's picture

Hey, Sasha, for the first time I see a guy from the development team in this forum :)