From 990d0fce78e8ec1dc0ed1cad185eca21aa8d0815 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Mon, 8 May 2017 16:42:49 +0200 Subject: [PATCH] GUI support from Python Enables experimental support for starting the Netgen GUI from Python directly. To use it, just import the gui module: > import netgen.gui --- libsrc/meshing/global.cpp | 4 +- ng/CMakeLists.txt | 6 ++ ng/gui.cpp | 222 ++++++++++++++++++++++++++++++++++++++ ng/ngappinit.cpp | 2 + 4 files changed, 233 insertions(+), 1 deletion(-) create mode 100644 ng/gui.cpp diff --git a/libsrc/meshing/global.cpp b/libsrc/meshing/global.cpp index 4a6237c3..dd3e14bd 100644 --- a/libsrc/meshing/global.cpp +++ b/libsrc/meshing/global.cpp @@ -27,7 +27,9 @@ namespace netgen global_mesh = m; } - + // true if netgen was started using the netgen executable + // false if netgen.gui was imported from python + DLL_HEADER bool netgen_executable_started = false; // Flags parameters; int silentflag = 0; diff --git a/ng/CMakeLists.txt b/ng/CMakeLists.txt index 0f36f434..10db4536 100644 --- a/ng/CMakeLists.txt +++ b/ng/CMakeLists.txt @@ -11,11 +11,17 @@ if(USE_GUI) add_executable(netgen ${netgen_sources}) target_link_libraries( netgen nglib ${ZLIB_LIBRARIES} ${LIBTOGL} ${TK_LIBRARY} ${TCL_LIBRARY} ${JPEG_LIBRARIES} ${FFMPEG_LIBRARIES} ${X11_X11_LIB} ${OCC_LIBRARIES}) + add_library(gui SHARED ${netgen_sources} gui.cpp) + target_link_libraries( gui nglib ${ZLIB_LIBRARIES} ${LIBTOGL} ${TK_LIBRARY} ${TCL_LIBRARY} ${JPEG_LIBRARIES} ${FFMPEG_LIBRARIES} ${X11_X11_LIB} ${OCC_LIBRARIES}) if(NOT WIN32) target_link_libraries( netgen mesh stlvis stl geom2dvis interface geom2d csg stl visual csgvis ) + target_link_libraries( gui mesh stlvis stl geom2dvis interface geom2d csg stl visual csgvis ) endif(NOT WIN32) install(TARGETS netgen ${ng_install_dir}) + install(TARGETS gui DESTINATION ${PYTHON_PACKAGES_INSTALL_DIR}/netgen) + set_target_properties( gui PROPERTIES PREFIX "") # name output file gui.so instead of libgui.so + if(APPLE) set_target_properties(netgen PROPERTIES OUTPUT_NAME netgen) endif(APPLE) diff --git a/ng/gui.cpp b/ng/gui.cpp new file mode 100644 index 00000000..ab7bcfab --- /dev/null +++ b/ng/gui.cpp @@ -0,0 +1,222 @@ +#include +#include +#include + +#include "../libsrc/interface/writeuser.hpp" +#include + +namespace netgen +{ + DLL_HEADER extern Flags parameters; + DLL_HEADER extern bool netgen_executable_started; + DLL_HEADER extern int printmessage_importance; +} + +using netgen::parameters; +using netgen::ngdir; +using netgen::verbose; +using netgen::Array; +using netgen::RegisterUserFormats; + +extern "C" int Ng_ServerSocketManagerInit (int port); +extern "C" int Ng_ServerSocketManagerRun (void); + +int Tcl_AppInit(Tcl_Interp * interp); + +extern bool nodisplay; +extern bool shellmode; + +void main_gui() +{ + if(netgen::netgen_executable_started) + return; + + if ( netgen::id == 0 ) + { + cout << "NETGEN-" << PACKAGE_VERSION << endl; + + cout << "Developed by Joachim Schoeberl at" << endl + << "2010-xxxx Vienna University of Technology" << endl + << "2006-2010 RWTH Aachen University" << endl + << "1996-2006 Johannes Kepler University Linz" << endl; + +#ifdef OCCGEOMETRY + cout << "Including OpenCascade geometry kernel" << endl; +#endif + +#ifdef ACIS + cout << "Including ACIS geometry kernel" << endl; +#endif + +#ifdef DEBUG + cout << "You are running the debug version !" << endl; +#endif + + + } + +// netgen::h_argc = argc; +// netgen::h_argv = argv; + + if (getenv ("NETGENDIR") && strlen (getenv ("NETGENDIR"))) + ngdir = getenv ("NETGENDIR"); + else + ngdir = "."; + + verbose = parameters.GetDefineFlag ("V"); + + if (verbose) + cout << "NETGENDIR = " << ngdir << endl; + + + if ( netgen::id == 0 ) + { + if (parameters.StringFlagDefined ("testout")) + netgen::testout = new ofstream (parameters.GetStringFlag ("testout", "test.out")); + + + if(parameters.GetDefineFlag("batchmode")) + nodisplay = true; + + + if(parameters.GetDefineFlag("shellmode")) + { + nodisplay = true; + shellmode = true; + } + + Tcl_FindExecutable(NULL); + + // initialize application + Tcl_Interp * myinterp = Tcl_CreateInterp (); + if (Tcl_AppInit (myinterp) == TCL_ERROR) + { + cerr << "Exit Netgen due to initialization problem" << endl; + exit (1); + } + + + + // parse tcl-script + int errcode; + + bool internaltcl = false; + if (shellmode) + internaltcl = false; + + if (verbose) + { + cout << "Tcl header version = " << TCL_PATCH_LEVEL << endl; + Tcl_Eval (myinterp, "puts \"Tcl runtime version = [info patchlevel] \";"); + } + + if (parameters.GetDefineFlag ("internaltcl")) + internaltcl=true; + if (parameters.GetDefineFlag ("externaltcl")) + internaltcl=false; + + + + if (internaltcl) + { + if (verbose) + cout << "using internal Tcl-script" << endl; + + // connect to one string + extern const char * ngscript[]; + const char ** hcp = ngscript; + int len = 0; + while (*hcp) + len += strlen (*hcp++); + + char * tr1 = new char[len+1]; + *tr1 = 0; + hcp = ngscript; + + char * tt1 = tr1; + while (*hcp) + { + strcat (tt1, *hcp); + tt1 += strlen (*hcp++); + } + + errcode = Tcl_Eval (myinterp, tr1); + delete [] tr1; + } + + else + + { + string startfile = ngdir + "/ng.tcl"; + + if (verbose) + cout << "Load Tcl-script from " << startfile << endl; + + errcode = Tcl_EvalFile (myinterp, (char*)startfile.c_str()); + } + + if (errcode) + { + cout << "Error in Tcl-Script:" << endl; + // cout << "result = " << myinterp->result << endl; + cout << "result = " << Tcl_GetStringResult (myinterp) << endl; + // cout << "in line " << myinterp->errorLine << endl; + + cout << "\nMake sure to set environment variable NETGENDIR to directory containing ng.tcl" << endl; + exit (1); + } + + + // lookup user file formats and insert into format list: + Array userformats; + Array extensions; + RegisterUserFormats (userformats, extensions); + + ostringstream fstr; + + tcl_const char * exportft = Tcl_GetVar (myinterp, "exportfiletype", 0); + for (int i = 1; i <= userformats.Size(); i++) + { + fstr << ".ngmenu.file.filetype add radio -label \"" + << userformats.Get(i) << "\" -variable exportfiletype\n"; + fstr << "lappend meshexportformats { {" << userformats.Get(i) << "} {" << extensions.Get(i) << "} }\n"; + } + + Tcl_Eval (myinterp, (char*)fstr.str().c_str()); + Tcl_SetVar (myinterp, "exportfiletype", exportft, 0); + + + // start event-loop + Tk_MainLoop(); + Tcl_DeleteInterp (myinterp); +// Tcl_Exit(0); + } +} + + + +extern "C" int Ng_Init (Tcl_Interp * interp); +extern "C" int Ng_Vis_Init (Tcl_Interp * interp); + +extern "C" void Ng_TclCmd(string); + +struct GuiThread { + std::thread t; + ~GuiThread() { + Ng_TclCmd(".ngmenu.file invoke \"Quit\";"); + if(netgen::printmessage_importance>2) + cout << "waiting for GUI to finish..." << endl; + t.join(); + } +}; + +static GuiThread gui_thread; + +PYBIND11_PLUGIN(gui) { + pybind11::module m("gui", "pybind gui"); + gui_thread.t = std::thread([]() + { + main_gui(); + }); + return m.ptr(); +} diff --git a/ng/ngappinit.cpp b/ng/ngappinit.cpp index cf2f25bd..69623bc4 100644 --- a/ng/ngappinit.cpp +++ b/ng/ngappinit.cpp @@ -34,6 +34,7 @@ namespace netgen namespace netgen { Flags parameters; + DLL_HEADER extern bool netgen_executable_started; } @@ -70,6 +71,7 @@ bool shellmode = false; int main(int argc, char ** argv) { + netgen::netgen_executable_started = true; #ifdef PARALLEL int mpi_required = MPI_THREAD_MULTIPLE;