[mathgl] 01/04: Imported Upstream version 2.2

Dimitrios Eftaxiopoulos eftaxiop-guest at moszumanska.debian.org
Mon Dec 30 15:55:17 UTC 2013


This is an automated email from the git hooks/post-receive script.

eftaxiop-guest pushed a commit to branch master
in repository mathgl.

commit 9beecfbfae4fc384f3901a140b6d30d21cb23bd2
Author: Dimitrios Eftaxiopoulos <eftaxi12 at otenet.gr>
Date:   Sat Dec 28 16:19:13 2013 +0200

    Imported Upstream version 2.2
---
 CMakeLists.txt                     |  172 ++-
 ChangeLog.txt                      |   32 +
 brush.ods                          |  Bin 10909 -> 19306 bytes
 examples/full_test.cpp             |  118 +-
 examples/glut_example.cpp          |    1 +
 examples/mpi_test.cpp              |   39 +
 examples/qt_example.cpp            |   10 +-
 examples/samples.cpp               |  497 +++++--
 examples/wnd_samples.cpp           |   50 +-
 examples/wx_example.cpp            |  105 +-
 include/CMakeLists.txt             |    1 +
 include/config.h.in                |   31 +-
 include/mgl2/abstract.h            |  105 ++
 include/mgl2/addon.h               |    4 +-
 include/mgl2/base.h                |  207 ++-
 include/mgl2/base_cf.h             |   26 +-
 include/mgl2/canvas.h              |  161 ++-
 include/mgl2/canvas_cf.h           |    9 +-
 include/mgl2/canvas_wnd.h          |    2 +-
 include/mgl2/cont.h                |    6 +-
 include/mgl2/data.h                |   56 +-
 include/mgl2/data_cf.h             |   56 +-
 include/mgl2/datac.h               |   27 +-
 include/mgl2/datac_cf.h            |   18 +-
 include/mgl2/define.h              |  109 +-
 include/mgl2/eval.h                |    2 +-
 include/mgl2/evalc.h               |    2 +-
 include/mgl2/fit.h                 |    2 +-
 include/mgl2/fltk.h                |   18 +-
 include/mgl2/font.h                |   31 +-
 include/mgl2/glut.h                |    2 +-
 include/mgl2/mgl.h                 |   82 +-
 include/mgl2/mpi.h                 |    3 +-
 include/mgl2/opengl.h              |   23 +-
 include/mgl2/other.h               |    7 +-
 include/mgl2/parser.h              |   28 +-
 include/mgl2/pde.h                 |   56 +
 include/mgl2/plot.h                |   17 +-
 include/mgl2/prim.h                |    2 +-
 include/mgl2/qmathgl.h             |   19 +-
 include/mgl2/qt.h                  |    4 +-
 include/mgl2/surf.h                |    2 +-
 include/mgl2/thread.h              |   86 ++
 include/mgl2/type.h                |    8 +-
 include/mgl2/vect.h                |    2 +-
 include/mgl2/volume.h              |    2 +-
 include/mgl2/window.h              |    7 +-
 include/mgl2/wnd.h                 |    5 +-
 include/mgl2/wx.h                  |   40 +-
 json/main.js                       |   38 +-
 json/mathgl.Graph.js               |  859 ++++++------
 json/mathgl.WebkitBackend.js       |   18 +-
 lang/CMakeLists.txt                |   13 +-
 include/mgl2/data.h => lang/data.i |  976 +++++++------
 lang/mathgl.i                      |   18 +-
 include/mgl2/mgl.h => lang/mgl.i   | 2638 ++++++++++++++++++------------------
 lang/sed_rules                     |   13 +
 include/mgl2/type.h => lang/type.i |   68 +-
 mathgl-2x.cbp                      |   19 +-
 mgllab/editor.cpp                  |    3 +-
 src/CMakeLists.txt                 |   19 +-
 src/addon.cpp                      |   67 +-
 src/axis.cpp                       |  320 +++--
 src/base.cpp                       |  443 +++---
 src/base_cf.cpp                    |   48 +-
 src/canvas.cpp                     |  547 ++++----
 src/canvas_cf.cpp                  |    4 +
 src/complex.cpp                    |  611 ++++++---
 src/complex_io.cpp                 |  217 ++-
 src/cont.cpp                       |  309 +++--
 src/crust.cpp                      |  235 ++--
 src/data.cpp                       | 1411 +++++++++++--------
 src/{data_new.cpp => data_ex.cpp}  |  471 +++----
 src/data_gr.cpp                    |  177 +++
 src/data_io.cpp                    |  319 ++---
 src/data_png.cpp                   |   99 +-
 src/eval.cpp                       |   64 +-
 src/evalc.cpp                      |   25 +-
 src/evalp.cpp                      |  577 ++++----
 src/exec.cpp                       |   80 +-
 src/export.cpp                     |   74 +-
 src/export_2d.cpp                  |  129 +-
 src/export_3d.cpp                  |  302 +++--
 src/fft.cpp                        | 1141 +++++++++++-----
 src/fit.cpp                        |  280 ++--
 src/font.cpp                       |  324 +++--
 src/interp.hpp                     |  384 ++++++
 src/mpi.cpp                        |   12 +-
 src/obj.cpp                        |    4 -
 src/opengl.cpp                     |  170 ++-
 src/other.cpp                      |  163 ++-
 src/parser.cpp                     |  482 +++----
 src/pde.cpp                        |  380 +++---
 src/pixel.cpp                      | 1341 ++++++++++++++----
 src/plot.cpp                       |  762 ++++++-----
 src/prc/writePRC.h                 |    7 -
 src/prim.cpp                       |  218 +--
 src/surf.cpp                       |  305 +++--
 src/vect.cpp                       |  525 +++----
 src/volume.cpp                     |   79 +-
 src/window.cpp                     |    1 +
 texinfo/CMakeLists.txt             |  194 +--
 texinfo/appendix_en.texi           |    2 +
 texinfo/appendix_ru.texi           |    2 +
 texinfo/concept_en.texi            |   46 +-
 texinfo/concept_ru.texi            |   89 +-
 texinfo/core_en.texi               |  288 ++--
 texinfo/core_ru.texi               |  320 +++--
 texinfo/data_en.texi               |  130 +-
 texinfo/data_ru.texi               |  235 ++--
 texinfo/doc_en.texi                |  126 +-
 texinfo/doc_ru.texi                |  124 +-
 texinfo/ex_mgl_en.texi             |  405 ++++--
 texinfo/ex_mgl_ru.texi             |  419 ++++--
 texinfo/example_en.texi            |  481 +++++--
 texinfo/example_ru.texi            |  529 +++++---
 texinfo/formats_en.texi            |    7 +-
 texinfo/formats_ru.texi            |    7 +-
 texinfo/index.html                 |   23 +-
 texinfo/json.html                  |    2 +-
 texinfo/mathgl.js                  |   74 +-
 texinfo/mathgl_en.texi             |   75 +-
 texinfo/mathgl_ru.texi             |   78 +-
 texinfo/mgl_en.texi                |   29 +-
 texinfo/mgl_ru.texi                |   31 +-
 texinfo/other_en.texi              |    6 +-
 texinfo/other_ru.texi              |    6 +-
 texinfo/overview_en.texi           |   10 +
 texinfo/overview_ru.texi           |   11 +
 texinfo/parse_en.texi              |   26 +-
 texinfo/parse_ru.texi              |  242 ++--
 texinfo/surf_cont_fog_g.png        |  Bin 30517 -> 0 bytes
 texinfo/symbols_en.texi            |   64 +-
 texinfo/symbols_ru.texi            |   68 +-
 texinfo/time.texi                  |  112 ++
 texinfo/time_big.texi              |  112 ++
 texinfo/title.html                 |   10 -
 texinfo/toc_en.html                |   44 -
 texinfo/toc_fr.html                |   45 -
 texinfo/toc_ru.html                |   54 -
 texinfo/udav_en.texi               |    6 +
 texinfo/udav_ru.texi               |    6 +
 texinfo/version.texi               |    2 +
 texinfo/web_en.texi                |   80 +-
 texinfo/web_fr.texi                |    4 +-
 texinfo/web_ru.texi                |   80 +-
 texinfo/widget_en.texi             |  178 ++-
 texinfo/widget_ru.texi             |  184 ++-
 todo.txt                           |   55 +-
 udav/dat_pnl.cpp                   |   15 +-
 udav/info_dlg.cpp                  |    2 +-
 udav/plot_pnl.cpp                  |   16 +-
 udav/udav_wnd.cpp                  |    5 +-
 widgets/CMakeLists.txt             |   15 +-
 widgets/fltk.cpp                   |   20 +-
 widgets/glut.cpp                   |   42 +-
 widgets/qt.cpp                     |   39 +-
 widgets/wx.cpp                     |  303 +----
 158 files changed, 15468 insertions(+), 10191 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3364973..8a06dd3 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -3,13 +3,14 @@ cmake_minimum_required(VERSION 2.8.6)
 project( MathGL )
 
 if(NOT CMAKE_BUILD_TYPE)
-	set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build, options are: 
+	set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build, options are:
 		None(CMAKE_CXX_FLAGS or CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel." FORCE)
 endif(NOT CMAKE_BUILD_TYPE)
 
 set(CMAKE_VERBOSE_MAKEFILE ON)
 set(MathGL_VERSION_MAJOR 2)
-set(MathGL_VERSION_MINOR 1.3)
+set(MathGL_VERSION_MINOR 2.0)
+set(MathGL_SOVERSION 7.1.0)
 
 
 MACRO(MGL_DEPENDENT_OPTION option doc default depends1 force1 depends2 force2)
@@ -60,14 +61,26 @@ set(MGL_LIB_INSTALL_DIR "lib" CACHE STRING "Set library install directory")
 option(enable-double "Enable double precision in MathGL library" ON)
 option(enable-simple "Slightly increase drawing speed but disable mglDataA class")
 option(enable-mpi "Enable mpi")
-option(enable-doc "Enable documentation building")
+option(enable-opengl "Enable OpenGL support" ON)
+option(enable-all-docs "Enable all documentation building")
+#option(enable-doc "Enable documentation building")
 option(enable-all "Enable all core features")
 option(enable-all-widgets "Enable all Widgets")
 option(enable-all-swig "Enable all SWIG based interfaces")
-option(enable-pthread "Enable POSIX threads support" ON)
+option(enable-pthread "Enable POSIX threads support" OFF)
+option(enable-openmp "Enable POSIX threads support" ON)
 option(enable-lgpl "Enable only LGPL part of MathGL")
 option(enable-mgl2 "Use names 'libmgl2-*' instead of 'libmgl-*'")
 #option(enable-ltdl "Enable loading modules support")
+CMAKE_DEPENDENT_OPTION(enable-doc-site "Enable HTML documentation for website" OFF "NOT enable-all-docs" ON)
+CMAKE_DEPENDENT_OPTION(enable-doc-html "Enable HTML documentation" OFF "NOT enable-all-docs" ON)
+CMAKE_DEPENDENT_OPTION(enable-doc-info "Enable INFO documentation" OFF "NOT enable-all-docs" ON)
+CMAKE_DEPENDENT_OPTION(enable-doc-pdf-ru "Enable Russian PDF documentation" OFF "NOT enable-all-docs" ON)
+CMAKE_DEPENDENT_OPTION(enable-doc-pdf-en "Enable English PDF documentation" OFF "NOT enable-all-docs" ON)
+CMAKE_DEPENDENT_OPTION(enable-doc-prc "Enable PDF samples for HTML docs" OFF "NOT enable-all-docs" ON)
+CMAKE_DEPENDENT_OPTION(enable-doc-json "Enable JSON samples for HTML docs" OFF "NOT enable-all-docs" ON)
+option(enable-texi2html "Use texi2html (obsolete package) instead of texi2any" OFF)
+
 CMAKE_DEPENDENT_OPTION(enable-zlib "Enable zlib support" ON "NOT enable-all" ON)
 CMAKE_DEPENDENT_OPTION(enable-png "Enable png support" ON "NOT enable-all" ON)
 CMAKE_DEPENDENT_OPTION(enable-jpeg "Enable jpeg support" OFF "NOT enable-all" ON)
@@ -76,12 +89,12 @@ MGL_DEPENDENT_OPTION(enable-hdf4 "Enable hdf4 support" OFF "NOT enable-lgpl" ON
 MGL_DEPENDENT_OPTION(enable-hdf5 "Enable hdf5 support" OFF "NOT enable-lgpl" ON "NOT enable-all" ON)
 CMAKE_DEPENDENT_OPTION(enable-pdf "Enable pdf support" OFF "NOT enable-all" ON)
 CMAKE_DEPENDENT_OPTION(enable-gif "Enable gif support" OFF "NOT enable-all" ON)
-CMAKE_DEPENDENT_OPTION(enable-opengl "Enable OpenGL support" ON "NOT enable-mpi" OFF)
-MGL_DEPENDENT_OPTION(enable-glut "Enable glut support" OFF "NOT enable-lgpl;NOT enable-mpi" ON "NOT enable-all-widgets" ON)
-MGL_DEPENDENT_OPTION(enable-fltk "Enable fltk widget" OFF "NOT enable-lgpl;NOT enable-mpi" ON "NOT enable-all-widgets" ON)
-CMAKE_DEPENDENT_OPTION(enable-wx "Enable wxWidget widget" OFF "NOT enable-lgpl;NOT enable-mpi" OFF)
-MGL_DEPENDENT_OPTION(enable-qt "Enable Qt4 widget" OFF "NOT enable-lgpl;NOT enable-mpi" ON "NOT enable-all-widgets" ON)
+MGL_DEPENDENT_OPTION(enable-glut "Enable glut support" OFF "NOT enable-lgpl" ON "NOT enable-all-widgets" ON)
+MGL_DEPENDENT_OPTION(enable-fltk "Enable fltk widget" OFF "NOT enable-lgpl" ON "NOT enable-all-widgets" ON)
+CMAKE_DEPENDENT_OPTION(enable-wx "Enable wxWidget widget" OFF "NOT enable-lgpl" OFF)
+MGL_DEPENDENT_OPTION(enable-qt "Enable Qt4 widget" OFF "NOT enable-lgpl" ON "NOT enable-all-widgets" ON)
 MGL_DEPENDENT_OPTION(enable-python "Enable python interface" OFF "NOT enable-lgpl" ON "NOT enable-all-swig" ON)
+MGL_DEPENDENT_OPTION(enable-lua "Enable Lua (v.5.1) interface" OFF "NOT enable-lgpl" ON "NOT enable-all-swig" ON)
 MGL_DEPENDENT_OPTION(enable-octave "Enable octave interface" OFF "NOT enable-lgpl" ON "NOT enable-all-swig" ON)
 MGL_DEPENDENT_OPTION(enable-octave-install "Octave interface will install for all users" ON "NOT enable-lgpl" ON "NOT enable-all-swig" ON)
 
@@ -103,7 +116,15 @@ endif(NOT WIN32)
 
 include(CheckFunctionExists)
 include(CMakePushCheckState)
+include(TestBigEndian)
+
+TEST_BIG_ENDIAN(WORDS_BIGENDIAN)
+if(WORDS_BIGENDIAN)
+	ADD_DEFINITIONS("-DWORDS_BIGENDIAN")
+endif(WORDS_BIGENDIAN)
+
 CHECK_FUNCTION_EXISTS(sin MGL_SIN)
+CHECK_FUNCTION_EXISTS(memrchr HAVE_MEMRCHR)
 if(NOT MGL_SIN)
         cmake_push_check_state()
         set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} m)
@@ -115,6 +136,9 @@ if(NOT MGL_SIN)
                 message(SEND_ERROR "Math library not found")
         endif(MGL_SIN_M)
 endif(NOT MGL_SIN)
+if(HAVE_MEMRCHR)
+	ADD_DEFINITIONS("-DHAVE_MEMRCHR")
+endif(HAVE_MEMRCHR)
 
 if(enable-double)
 	set(MGL_USE_DOUBLE 1)
@@ -129,6 +153,20 @@ else(enable-simple)
 	set(MGL_NO_DATA_A 0)
 endif(enable-simple)
 
+if(enable-openmp)
+	find_package(OpenMP)
+	if(OPENMP_FOUND)
+		set(MGL_HAVE_OMP 1)
+		set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
+		set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
+	else(OPENMP_FOUND)
+		message(SEND_ERROR "Couldn't find OpenMP. You can enable POSIX threads instead.")
+		set(MGL_HAVE_OMP 0)
+	endif(OPENMP_FOUND)
+else(enable-openmp)
+	set(MGL_HAVE_OMP 0)
+endif(enable-openmp)
+
 if(enable-mpi)
 	set(MGL_HAVE_MPI 1)
 	find_package(MPI REQUIRED)
@@ -193,7 +231,6 @@ else(enable-hdf4)
 endif(enable-hdf4)
 
 if(enable-hdf5)
-#	message(STATUS "enable hdf5")
 	set(MGL_HAVE_HDF5 1)
 	include(FindHDF5)
 	if(NOT HDF5_FOUND)
@@ -251,8 +288,6 @@ if(enable-pdf)
 	if(NOT HPDF_INCLUDE_DIR)
 		message(SEND_ERROR "Couldn't find headers of 3d-enabled version of libhpdf.")
 	endif(NOT HPDF_INCLUDE_DIR)
-#	message(STATUS "Found libHaru library at: ${HPDF_LIB}")
-#	message(STATUS "Found libHaru headers: ${HPDF_INCLUDE_DIR}")
 else(enable-pdf)
 	set(MGL_HAVE_PDF 0)
 endif(enable-pdf)
@@ -300,17 +335,14 @@ else(enable-fltk)
 	set(MGL_HAVE_FLTK 0)
 endif(enable-fltk)
 
-#if((enable-all-widgets OR enable-wx) AND (NOT enable-lgpl) )
 if(enable-wx)
 	set(MGL_HAVE_WX 1)
 	FIND_PACKAGE(wxWidgets COMPONENTS base core gl)
 	if(NOT wxWidgets_FOUND)
 		message(SEND_ERROR "Couldn't find wxWidgets library.")
 	endif(NOT wxWidgets_FOUND)
-#else((enable-all-widgets OR enable-wx) AND (NOT enable-lgpl) )
 else(enable-wx)
 	set(MGL_HAVE_WX 0)
-#endif((enable-all-widgets OR enable-wx) AND (NOT enable-lgpl) )
 endif(enable-wx)
 
 if(enable-qt)
@@ -324,6 +356,7 @@ else(enable-qt)
 endif(enable-qt)
 
 if(enable-python)
+	set(MGL_HAVE_SWIG 1)
 	set(MGL_HAVE_PYTHON 1)
 	FIND_PACKAGE(PythonInterp)
 	if(NOT PYTHONINTERP_FOUND)
@@ -346,7 +379,20 @@ else(enable-python)
 	set(MGL_HAVE_PYTHON 0)
 endif(enable-python)
 
+if(enable-lua)
+	set(MGL_HAVE_SWIG 1)
+	set(MGL_HAVE_LUA 1)
+	INCLUDE(FindLua51)
+	if(NOT LUA51_FOUND)
+		message(SEND_ERROR "Couldn't find Lua 5.1 library.")
+	endif(NOT LUA51_FOUND)
+else(enable-lua)
+	set(MGL_HAVE_LUA 0)
+endif(enable-lua)
+
+
 if(enable-octave)
+	set(MGL_HAVE_SWIG 1)
 	set(MGL_HAVE_OCTAVE 1)
 	find_program(oct_prog octave-config)
 	if(NOT oct_prog)
@@ -368,37 +414,95 @@ else(enable-octave)
 	set(MGL_HAVE_OCTAVE 0)
 endif(enable-octave)
 
-if(enable-doc)
-	set(MGL_HAVE_DOC 1)
+if(enable-doc-info)
+	set(MGL_HAVE_DOC_INFO 1)
 	find_program(findmi makeinfo)
 	if(NOT findmi)
 		message(SEND_ERROR "Couldn't find makeinfo needed for documentation building.")
 	endif(NOT findmi)
-	find_program(findth texi2html)
-	if(NOT findth)
-		message(SEND_ERROR "Couldn't find texi2html needed for documentation building.")
-	endif(NOT findth)
+else(enable-doc-info)
+	set(MGL_HAVE_DOC_INFO 0)
+endif(enable-doc-info)
+
+if(enable-doc-html OR enable-doc-site)
+	if(enable-texi2html)
+		find_program(findth texi2html)
+		if(NOT findth)
+			message(SEND_ERROR "Couldn't find texi2html needed for documentation building.")
+		endif(NOT findth)
+	else(enable-texi2html)
+		find_program(findth texi2any)
+		if(NOT findth)
+			message(SEND_ERROR "Couldn't find texi2any needed for documentation building.")
+		endif(NOT findth)
+	endif(enable-texi2html)
+endif(enable-doc-html OR enable-doc-site)
+
+if(enable-texi2html)
+	set(site_en ${CMAKE_BINARY_DIR}/texinfo/doc_en/doc_en.html)
+	set(site_ru ${CMAKE_BINARY_DIR}/texinfo/doc_ru/doc_ru.html)
+	set(th_opt )
+else(enable-texi2html)
+	set(th_opt --html)
+	set(site_en ${CMAKE_BINARY_DIR}/texinfo/doc_en/index.html)
+	set(site_ru ${CMAKE_BINARY_DIR}/texinfo/doc_ru/index.html)
+endif(enable-texi2html)
+
+if(enable-doc-html)
+	set(MGL_HAVE_DOC_HTML 1)
+else(enable-doc-html)
+	set(MGL_HAVE_DOC_HTML 0)
+endif(enable-doc-html)
+
+
+if(enable-doc-site)
+	set(MGL_HAVE_DOC_SITE 1)
+else(enable-doc-site)
+	set(MGL_HAVE_DOC_SITE 0)
+endif(enable-doc-site)
+
+if(enable-doc-pdf-ru)
+	set(MGL_HAVE_DOC_PDF_RU 1)
 	find_program(findtp texi2pdf)
 	if(NOT findtp)
 		message(SEND_ERROR "Couldn't find texi2pdf needed for documentation building.")
 	endif(NOT findtp)
-else(enable-doc)
-	set(MGL_HAVE_DOC 0)
-endif(enable-doc)
+else(enable-doc-pdf-ru)
+	set(MGL_HAVE_DOC_PDF_RU 0)
+endif(enable-doc-pdf-ru)
 
-if(MGL_HAVE_PYTHON OR MGL_HAVE_OCTAVE)
+if(enable-doc-pdf-en)
+	set(MGL_HAVE_DOC_PDF_EN 1)
+	find_program(findtp texi2pdf)
+	if(NOT findtp)
+		message(SEND_ERROR "Couldn't find texi2pdf needed for documentation building.")
+	endif(NOT findtp)
+else(enable-doc-pdf-en)
+	set(MGL_HAVE_DOC_PDF_EN 0)
+endif(enable-doc-pdf-en)
+
+if(enable-doc-json)
+	set(MGL_HAVE_DOC_JSON 1)
+else(enable-doc-json)
+	set(MGL_HAVE_DOC_JSON 0)
+endif(enable-doc-json)
+
+if(enable-doc-prc)
+	set(MGL_HAVE_DOC_PRC 1)
+	if(NOT enable-pdf)
+		message(SEND_ERROR "You need to enable pdf support for MathGL.")
+	endif(NOT enable-pdf)
+else(enable-doc-prc)
+	set(MGL_HAVE_DOC_PRC 0)
+endif(enable-doc-prc)
+
+if(MGL_HAVE_SWIG)
 	FIND_PACKAGE(SWIG)
 	if(NOT SWIG_FOUND)
 		message(SEND_ERROR "Couldn't find swig needed for interfaces compiling.")
 	endif(NOT SWIG_FOUND)
 	INCLUDE(${SWIG_USE_FILE})
-endif(MGL_HAVE_PYTHON OR MGL_HAVE_OCTAVE)
-
-#execute_process(
-#	COMMAND ${oct_prog} -q --eval \'strcat\(octave_config_info\("canonical_host_type"\), "-", octave_config_info\("api_version"\)\)'|sed -e 's/ans = //'
-#	OUTPUT_VARIABLE OCTAVE_ARCH
-#	)
-#message(SEND_ERROR "${OCTAVE_ARCH}")
+endif(MGL_HAVE_SWIG)
 
 if(UNIX)
 	add_definitions(-DNO_COLOR_ARRAY)
@@ -418,5 +522,9 @@ add_subdirectory( lang )
 if(NOT MSVC AND NOT BORLAND)
 add_subdirectory( utils )
 add_subdirectory( examples )
+
+if(MGL_HAVE_DOC_HTML OR MGL_HAVE_DOC_SITE OR MGL_HAVE_DOC_INFO OR MGL_HAVE_DOC_PDF_RU OR MGL_HAVE_DOC_PDF_EN )
 add_subdirectory( texinfo )
+endif(MGL_HAVE_DOC_HTML OR MGL_HAVE_DOC_SITE OR MGL_HAVE_DOC_INFO OR MGL_HAVE_DOC_PDF_RU OR MGL_HAVE_DOC_PDF_EN )
+
 endif(NOT MSVC AND NOT BORLAND)
diff --git a/ChangeLog.txt b/ChangeLog.txt
index 9d2da36..6520551 100644
--- a/ChangeLog.txt
+++ b/ChangeLog.txt
@@ -1,3 +1,35 @@
+2.2 Release 11 November 2013
+
+* Add OpenMP calls mostly everywhere (can work as replacement of pthreads - a bit faster since more loops is parallelized).
+* Greatly speed up consequent FFT and Hankel transforms. Add mgl_clear_fft() function for manual clearing of saved FFT/Hankel data.
+* Add OHLC() plot for drawing Open-High-Low-Close diagram
+* Add wxMathGL widget.
+* Add interface for Lua v.5.1.
+* Add mask for face drawing if one of symbols "-+=;oOsS~<>jdD*^" is specified in color scheme. This work only for export in bitmap images.
+* Add Quality=8 for dots drawing (extremely fast).
+* Add styles '4','6','8' for Cone() and Cones() to produce square, hex-, octo-prism.
+* Add style 't' for Cones() to produce tubes (cylinders).
+* Add style '^' for Legend() to left/right align legend if its coordinates are right/left from the center
+* Add style '<', '^', '>' for aligning/centering boxes in Bars(), Barh(), BoxPlot(), Cones(). Also this plots become centered by default if nx sizes are the same for all data.
+* Add Dots() function which set independently both color and alpha of dots
+* Improve automatic axis position. Add style '^' for inverse automatic axis position.
+* Improve tick labeling. Add style TuneTicks&4 for zero filling of tick labels.
+* Add mglData::Refill() for filling by interpolation of parametrically dependent data
+* Add transparency for Area() and Region() plots.
+* Add mgl_clf_chr() function and extend 'clf' command.
+* Fourier now perform true inverse Fourier transform (instead of backward one).
+* Improve/change lighting from local sources. Add SetDiffuse() function.
+* C functions now return NULL if HMDT data cannot be created for given input argument(s).
+* Enable line width for Mesh() and Fall() plots.
+* Replace +INF and -INF by NAN in textual formula output.
+* Add manual compression of JSON.
+* Define WORDS_BIGENDIAN and HAVE_MEMRCHR (thanks to Dinar Valeev).
+* Bugfix for cleaning unused points.
+* Fix 'setsize' command at UDAV starting.
+* Rewrite MGL parsing by using std::wstring for avoiding possible bugs of wcs*() functions.
+* Minor bugfixes.
+* Update docs.
+
 2.1.3.1 Released 8 May 2013
 
 * Compatibility changes for MS VS.
diff --git a/brush.ods b/brush.ods
index 9b0be4e..ae9110c 100644
Binary files a/brush.ods and b/brush.ods differ
diff --git a/examples/full_test.cpp b/examples/full_test.cpp
index c050a0b..cf8b599 100644
--- a/examples/full_test.cpp
+++ b/examples/full_test.cpp
@@ -49,11 +49,11 @@ int type = 0;
 int dotest  = 0;
 int width  = 800;
 int height = 600;
-int mini = 0;
 int big  = 0;
 int srnd = 0;
 int use_mgl = 0;
 int verbose = 0;
+int quality  = MGL_DRAW_NORM;
 //-----------------------------------------------------------------------------
 void mgls_prepare1d(mglData *y, mglData *y1=0, mglData *y2=0, mglData *x1=0, mglData *x2=0);
 void mgls_prepare2d(mglData *a, mglData *b=0, mglData *v=0);
@@ -64,23 +64,21 @@ void mgls_prepare3v(mglData *ex, mglData *ey, mglData *ez);
 void save(mglGraph *gr,const char *name,const char *suf);
 void smgl_stfa(mglGraph *gr);	// STFA sample
 void smgl_text(mglGraph *gr);	// text drawing
+void smgl_surf(mglGraph *gr);
 void test(mglGraph *gr)
 {
-	smgl_text(gr);	return;
-	
 	mglParse par;
-	par.AllowSetSize(true);
 	setlocale(LC_CTYPE, "");
-	par.Execute(gr,"xrange 1362565462 1365935062:ticktime 'x' 7*86400 '%d/%m/%y':axis");
-//	FILE *fp=fopen("/home/balakin/progr/mathgl-code/mathgl-2x/build/test.mgl","r");
-//	par.Execute(gr,fp,true);
-//	fclose(fp);
+//	par.Execute(gr,"axis");
+	par.Execute(gr,"axis 'lg(x)' '' '':axis:box:fplot 'x^2'");
 }
 //-----------------------------------------------------------------------------
 #if !defined(_MSC_VER) && !defined(__BORLANDC__)
 static struct option longopts[] =
 {
+	{ "mini",	no_argument,	&big,	3 },
 	{ "big",	no_argument,	&big,		1 },
+	{ "web",	no_argument,	&big,		2 },
 	{ "bps",	no_argument,	&type,		8 },
 	{ "help",	no_argument,	NULL,		'?' },
 	{ "height",	required_argument,	NULL,	'h' },
@@ -91,7 +89,6 @@ static struct option longopts[] =
 	{ "kind",	required_argument,	NULL,	'k' },
 	{ "list",	no_argument,	NULL,		'l' },
 	{ "mgl",	no_argument,	&use_mgl,	1 },
-	{ "mini",	no_argument,	&mini,		1 },
 	{ "none",	no_argument,	&type,		7 },
 	{ "obj",	no_argument,	&type,		11 },
 	{ "obj_old",no_argument,	&type,		10 },
@@ -107,9 +104,11 @@ static struct option longopts[] =
 	{ "jsonz",	no_argument,	&type,		16 },
 	{ "test",	no_argument,	&dotest,	1 },
 	{ "font",	no_argument,	&dotest,	2 },
+	{ "time",	no_argument,	&dotest,	3 },
 	{ "thread",	required_argument,	NULL,	't' },
 	{ "verbose",no_argument,	&verbose,	1 },
 	{ "width",	required_argument,	NULL,	'w' },
+	{ "quality",required_argument,	NULL,	'q' },
 	{ NULL,		0,				NULL,		0 }
 };
 //-----------------------------------------------------------------------------
@@ -121,10 +120,11 @@ void usage()
 		"--height=num	- png picture height\n"
 		"--mini		- png picture is 200x150\n"
 		"--big		- png picture is 1920x1440\n"
+		"--web		- png picture is 640x480\n"
 		"--prc		- output prc\n"
 		"--pdf		- output pdf\n"
 		"--eps		- output EPS\n"
-		"--eps		- output LaTeX\n"
+		"--tex		- output LaTeX\n"
 		"--jpeg		- output JPEG\n"
 		"--json		- output JSON\n"
 		"--jsonz		- output JSONz\n"
@@ -140,8 +140,10 @@ void usage()
 		"--kind=name	- produce only this sample\n"
 		"--thread=num	- number of threads used\n"
 		"--mgl		- use MGL scripts for samples\n"
-		"--test		- perform test\n"
+		"--test		- run in test mode\n"
+		"--time		- measure execution time for all samples\n"
 		"--font		- write current font as C++ file\n"
+		"--quality=val	- use specified quality for plot(s)\n"
 	);
 }
 #endif
@@ -150,7 +152,6 @@ void save(mglGraph *gr,const char *name,const char *suf="")
 {
 	//	return;
 	char buf[128];
-	printf("%s ",name);	fflush(stdout);
 	switch(type)
 	{
 		case 1:	// EPS
@@ -172,7 +173,7 @@ void save(mglGraph *gr,const char *name,const char *suf="")
 		case 6:	// GIF
 			snprintf(buf,128,"%s%s.gif",name,suf);
 			gr->WriteGIF(buf);	break;
-		case 7:	// none
+		case 7:	gr->Finish();	// none
 			break;
 		case 8:	// EPS to PNG
 			snprintf(buf,128,"%s%s.png",name,suf);
@@ -201,7 +202,7 @@ void save(mglGraph *gr,const char *name,const char *suf="")
 			gr->WriteJSON(buf);	break;
 		case 16:	// JSON
 			snprintf(buf,128,"%s%s.jsonz",name,suf);
-			gr->WriteJSON(buf);	break;
+			gr->WriteJSON(buf,"",true);	break;
 		default:// PNG (no alpha)
 #if MGL_HAVE_PNG
 			snprintf(buf,128,"%s%s.png",name,suf);
@@ -228,6 +229,7 @@ int main(int argc,char **argv)
 			case 0:		break;
 			case 'w':	width =atoi(optarg);	break;
 			case 'h':	height=atoi(optarg);	break;
+			case 'q':	quality =atoi(optarg);	break;
 			case 'k':	strncpy(name, optarg,256);
 						tmp=strchr(name,'.');	if(tmp)	*tmp=0;
 						tmp=strchr(name,'-');	if(tmp)	*tmp=0;
@@ -242,12 +244,16 @@ int main(int argc,char **argv)
 #endif
 
 	if(dotest==1)	printf("Global (before):%s\n",mglGlobalMess.c_str());
-	gr = new mglGraph;	//gr->SetQuality(0);
+	gr = new mglGraph;
 	if(	type==11|| type==12|| type==5 || type==9)	width=height;
-	if(mini)		{	gr->SetSize(190,145);	suf = "-sm";	}
-	else if(big)
-	{	gr->SetSize(1920,1440);	suf = "-lg";	}
-	else	gr->SetSize(width,height);
+	switch(big)
+	{
+	case 1:	gr->SetSize(1920,1440);	suf = "-lg";	break;
+	case 2:	gr->SetSize(640,480);	break;
+	case 3:	gr->SetSize(192,144);	suf = "-sm";	break;
+	default:	gr->SetSize(width,height);
+	}
+	gr->SetQuality(quality);
 
 	if(dotest==1)
 	{
@@ -262,29 +268,68 @@ int main(int argc,char **argv)
 	else if(dotest==2)
 	{	mgl_create_cpp_font(gr->Self(), L"!-~,¡-ÿ,̀-̏,Α-ω,ϑ,ϕ,ϖ,ϰ,ϱ,ϵ,А-я,ℏ,ℑ,ℓ,ℜ,←-↙,∀-∯,≠-≯,⟂");
 		delete gr;	return 0;	}
+	else if(dotest==3)
+	{
+		int qual[7]={0,1,2,4,5,6,8};
+		size_t ll=strlen(mmgl_dat_prepare)+1;
+		mglParse par;
+		par.AllowSetSize(true);	setlocale(LC_CTYPE, "");
+		FILE *fp = fopen(big?"time_big.texi":"time.texi","w");
+		fprintf(fp,"@multitable @columnfractions .16 .12 .12 .12 .12 .12 .12 .12\n");
+		fprintf(fp,"@headitem Name");
+		for(int i=0;i<7;i++)	fprintf(fp," @tab q=%d",qual[i]);
+		clock_t beg,end;
+		while(s->name[0])	// all samples
+		{
+			char *buf = new char[strlen(s->mgl)+ll];
+			strcpy(buf,s->mgl);	strcat(buf,mmgl_dat_prepare);
+			fprintf(fp,"\n at item %s",s->name);
+
+			printf("%s",s->name);
+			for(int i=0;i<7;i++)
+			{
+				gr->DefaultPlotParam();
+				gr->SetQuality(qual[i]);	gr->Clf();
+				beg = clock();
+				if(!use_mgl)	s->func(gr);
+				else 	par.Execute(gr,buf);
+				gr->Finish();
+				end = clock();
+				fprintf(fp," @tab %.3g",double(end-beg)/CLOCKS_PER_SEC);
+				printf("\t%d->%g",qual[i],double(end-beg)/CLOCKS_PER_SEC);
+				fflush(fp);	fflush(stdout);
+			}
+			printf("\n");	delete []buf;	s++;
+		}
+		fprintf(fp,"\n at end multitable\n");	fclose(fp);
+	}
+
+	if(type==15 || type==16)	big=3;	// save mini version for json
 
-	if(type==15 || type==16)	mini=1;	// save mini version for json
-	
 	if(srnd)	mgl_srnd(1);
 	gr->VertexColor(false);	gr->Compression(false);
-	if(name[0]==0)	while(s->name[0])	// all samples
+	if(name[0]==0)
 	{
-		gr->DefaultPlotParam();	gr->Clf();
-		if(use_mgl)
+		while(s->name[0])	// all samples
 		{
-			mglParse par;
-			par.AllowSetSize(true);
-			setlocale(LC_CTYPE, "");
-			char *buf = new char[strlen(s->mgl)+strlen(mmgl_dat_prepare)+1];
-			strcpy(buf,s->mgl);		strcat(buf,mmgl_dat_prepare);
-			printf("\n-------\n%s\n-------\n",verbose?buf:s->mgl);
-			par.Execute(gr,buf);	delete []buf;
-			const char *mess = gr->Message();
-			if(*mess)	printf("Warnings: %s\n-------\n",mess);
+			gr->DefaultPlotParam();	gr->Clf();
+			if(use_mgl)
+			{
+				mglParse par;
+				par.AllowSetSize(true);
+				setlocale(LC_CTYPE, "");
+				char *buf = new char[strlen(s->mgl)+strlen(mmgl_dat_prepare)+1];
+				strcpy(buf,s->mgl);		strcat(buf,mmgl_dat_prepare);
+				printf("\n-------\n%s\n-------\n",verbose?buf:s->mgl);
+				par.Execute(gr,buf);	delete []buf;
+				const char *mess = gr->Message();
+				if(*mess)	printf("Warnings: %s\n-------\n",mess);
+			}
+			else	s->func(gr);
+			save(gr, s->name, suf);
+			printf("%s ",s->name);	fflush(stdout);	s++;
 		}
-		else	s->func(gr);
-		save(gr, s->name, suf);
-		fflush(stdout);	s++;
+		printf("\n");
 	}
 	else	// manual sample
 	{
@@ -312,7 +357,6 @@ int main(int argc,char **argv)
 		}
 		else	printf("no sample %s\n",name);
 	}
-	printf("\n");
 	delete gr;	return 0;
 }
 //-----------------------------------------------------------------------------
diff --git a/examples/glut_example.cpp b/examples/glut_example.cpp
index 419bb74..e88678c 100644
--- a/examples/glut_example.cpp
+++ b/examples/glut_example.cpp
@@ -21,6 +21,7 @@
 //-----------------------------------------------------------------------------
 int test_wnd(mglGraph *gr);
 int sample(mglGraph *gr);
+int sample_m(mglGraph *gr);
 int sample_1(mglGraph *gr);
 int sample_2(mglGraph *gr);
 int sample_3(mglGraph *gr);
diff --git a/examples/mpi_test.cpp b/examples/mpi_test.cpp
new file mode 100644
index 0000000..7d32780
--- /dev/null
+++ b/examples/mpi_test.cpp
@@ -0,0 +1,39 @@
+#include <stdio.h>
+#include <mgl2/mpi.h>
+#include <mpi.h>
+#define MCW		MPI_COMM_WORLD
+
+int main(int argc, char *argv[])
+{
+	// initialize MPI
+	int rank=0, numproc=1;
+	MPI_Init(&argc, &argv);
+	MPI_Comm_size(MPI_COMM_WORLD,&numproc);
+	MPI_Comm_rank(MPI_COMM_WORLD,&rank);
+	if(rank==0)	printf("Use %d processes.\n", numproc);
+
+	// initialize data similarly for all ranks
+	mglData a(128,128);
+	mglGraphMPI gr;
+	// do the same plot for its own range
+	char buf[64];
+	sprintf(buf,"xrange %g %g",2.*rank/numproc-1,2.*(rank+1)/numproc-1);
+	gr.Fill(a,"sin(2*pi*x)",buf);
+	// plot data in each rank
+	gr.Rotate(40,60);
+	gr.Surf(a,"",buf);
+	// collect information
+	if(rank!=0)	gr.MPI_Send(0);
+	else	for(int i=1;i<numproc;i++)	gr.MPI_Recv(i);
+
+	if(rank==0)
+	{
+		gr.Box();	gr.Axis();		// some post processing
+		gr.WritePNG("test.png");	// save result
+	}
+	sprintf(buf,"test%d.png",rank);
+	gr.WritePNG(buf);
+
+	MPI_Finalize();
+	return 0;
+}
diff --git a/examples/qt_example.cpp b/examples/qt_example.cpp
index c6f0ef5..944d471 100644
--- a/examples/qt_example.cpp
+++ b/examples/qt_example.cpp
@@ -32,9 +32,6 @@ int sample_3(mglGraph *gr);
 int sample_d(mglGraph *gr);
 //-----------------------------------------------------------------------------
 //#define PTHREAD_SAMPLE
-#ifdef PTHREAD_SAMPLE
-#include <pthread.h>
-#endif
 mglPoint pnt;  // some global variable for changeable data
 void *mgl_qt_tmp(void *);
 //-----------------------------------------------------------------------------
@@ -45,7 +42,7 @@ public:
 	mglWnd *Gr;  // graphics to be updated
 	int Draw(mglGraph *gr);
 	void Calc();
-} foo;
+};
 //-----------------------------------------------------
 void Foo::Calc()
 {
@@ -71,8 +68,9 @@ int Foo::Draw(mglGraph *gr)
 int main(int argc,char **argv)
 {
 #ifdef PTHREAD_SAMPLE
-	mglQT gr(&foo,"MathGL examples");
-	foo.Gr = &gr;   foo.Run();
+	Foo *foo = new Foo;
+	mglQT gr(foo,"MathGL examples");
+	foo->Gr = &gr;   foo->Run();
 	return gr.Run();
 #else
 	mglQT *gr;
diff --git a/examples/samples.cpp b/examples/samples.cpp
index 2c64bb6..fb6831e 100644
--- a/examples/samples.cpp
+++ b/examples/samples.cpp
@@ -24,7 +24,7 @@ void mgls_prepare2d(mglData *a, mglData *b=0, mglData *v=0);
 void mgls_prepare3d(mglData *a, mglData *b=0);
 void mgls_prepare2v(mglData *a, mglData *b);
 void mgls_prepare3v(mglData *ex, mglData *ey, mglData *ez);
-extern int mini;
+extern int big;
 //-----------------------------------------------------------------------------
 struct mglSample	/// Structure for list of samples
 {
@@ -73,12 +73,12 @@ void smgl_fexport(mglGraph *gr)	// test file export
 	gr->Line(mglPoint(x0,1-5*d),mglPoint(x1,1-5*d),"ki");	gr->Puts(mglPoint(x2,y-5*d),"Small dash-dot 'i'",":rL");
 	gr->Line(mglPoint(x0,1-6*d),mglPoint(x1,1-6*d),"k:");	gr->Puts(mglPoint(x2,y-6*d),"Dots ':'",":rL");
 	gr->Line(mglPoint(x0,1-7*d),mglPoint(x1,1-7*d),"k ");	gr->Puts(mglPoint(x2,y-7*d),"None ' '",":rL");
-	
+
 	d=0.25; x1=-1; x0=-0.8;	y = -0.05;
-	gr->Mark(mglPoint(x1,5*d),"k.");		gr->Puts(mglPoint(x0,y+5*d),"'.'",":rL");
-	gr->Mark(mglPoint(x1,4*d),"k+");		gr->Puts(mglPoint(x0,y+4*d),"'+'",":rL");
-	gr->Mark(mglPoint(x1,3*d),"kx");		gr->Puts(mglPoint(x0,y+3*d),"'x'",":rL");
-	gr->Mark(mglPoint(x1,2*d),"k*");		gr->Puts(mglPoint(x0,y+2*d),"'*'",":rL");
+	gr->Mark(mglPoint(x1,5*d),"k.");	gr->Puts(mglPoint(x0,y+5*d),"'.'",":rL");
+	gr->Mark(mglPoint(x1,4*d),"k+");	gr->Puts(mglPoint(x0,y+4*d),"'+'",":rL");
+	gr->Mark(mglPoint(x1,3*d),"kx");	gr->Puts(mglPoint(x0,y+3*d),"'x'",":rL");
+	gr->Mark(mglPoint(x1,2*d),"k*");	gr->Puts(mglPoint(x0,y+2*d),"'*'",":rL");
 	gr->Mark(mglPoint(x1,d),"ks");		gr->Puts(mglPoint(x0,y+d),"'s'",":rL");
 	gr->Mark(mglPoint(x1,0),"kd");		gr->Puts(mglPoint(x0,y),"'d'",":rL");
 	gr->Mark(mglPoint(x1,-d,0),"ko");	gr->Puts(mglPoint(x0,y-d),"'o'",":rL");
@@ -86,7 +86,7 @@ void smgl_fexport(mglGraph *gr)	// test file export
 	gr->Mark(mglPoint(x1,-3*d,0),"kv");	gr->Puts(mglPoint(x0,y-3*d),"'v'",":rL");
 	gr->Mark(mglPoint(x1,-4*d,0),"k<");	gr->Puts(mglPoint(x0,y-4*d),"'<'",":rL");
 	gr->Mark(mglPoint(x1,-5*d,0),"k>");	gr->Puts(mglPoint(x0,y-5*d),"'>'",":rL");
-	
+
 	d=0.25; x1=-0.5; x0=-0.3;	y = -0.05;
 	gr->Mark(mglPoint(x1,5*d),"k#.");	gr->Puts(mglPoint(x0,y+5*d),"'\\#.'",":rL");
 	gr->Mark(mglPoint(x1,4*d),"k#+");	gr->Puts(mglPoint(x0,y+4*d),"'\\#+'",":rL");
@@ -99,7 +99,7 @@ void smgl_fexport(mglGraph *gr)	// test file export
 	gr->Mark(mglPoint(x1,-3*d,0),"k#v");	gr->Puts(mglPoint(x0,y-3*d),"'\\#v'",":rL");
 	gr->Mark(mglPoint(x1,-4*d,0),"k#<");	gr->Puts(mglPoint(x0,y-4*d),"'\\#<'",":rL");
 	gr->Mark(mglPoint(x1,-5*d,0),"k#>");	gr->Puts(mglPoint(x0,y-5*d),"'\\#>'",":rL");
-	
+
 	gr->SubPlot(3,2,1);
 	double a=0.1,b=0.4,c=0.5;
 	gr->Line(mglPoint(a,1),mglPoint(b,1),"k-A");		gr->Puts(mglPoint(c,1),"Style 'A' or 'A\\_'",":rL");
@@ -113,7 +113,7 @@ void smgl_fexport(mglGraph *gr)	// test file export
 	gr->Line(mglPoint(a,-0.6),mglPoint(b,-0.6),"k-_");	gr->Puts(mglPoint(c,-0.6),"Style '\\_' or none",":rL");
 	gr->Line(mglPoint(a,-0.8),mglPoint(b,-0.8),"k-AS");	gr->Puts(mglPoint(c,-0.8),"Style 'AS'",":rL");
 	gr->Line(mglPoint(a,-1),mglPoint(b,-1),"k-_A");		gr->Puts(mglPoint(c,-1),"Style '\\_A'",":rL");
-	
+
 	a=-1;	b=-0.7;	c=-0.6;
 	gr->Line(mglPoint(a,1),mglPoint(b,1),"kAA");		gr->Puts(mglPoint(c,1),"Style 'AA'",":rL");
 	gr->Line(mglPoint(a,0.8),mglPoint(b,0.8),"kVV");	gr->Puts(mglPoint(c,0.8),"Style 'VV'",":rL");
@@ -126,7 +126,7 @@ void smgl_fexport(mglGraph *gr)	// test file export
 	gr->Line(mglPoint(a,-0.6),mglPoint(b,-0.6),"k-__");	gr->Puts(mglPoint(c,-0.6),"Style '\\_\\_'",":rL");
 	gr->Line(mglPoint(a,-0.8),mglPoint(b,-0.8),"k-VA");	gr->Puts(mglPoint(c,-0.8),"Style 'VA'",":rL");
 	gr->Line(mglPoint(a,-1),mglPoint(b,-1),"k-AV");		gr->Puts(mglPoint(c,-1),"Style 'AV'",":rL");
-	
+
 	gr->SubPlot(3,2,2);
 	//#LENUQ
 	gr->FaceZ(mglPoint(-1,	-1), 0.4, 0.3, "L#");	gr->Puts(mglPoint(-0.8,-0.9), "L", "w:C", -1.4);
@@ -173,7 +173,7 @@ void smgl_fexport(mglGraph *gr)	// test file export
 	// HEX
 	gr->FaceZ(mglPoint(-1, -1.3), 1, 0.3, "{xff9966}#");	gr->Puts(mglPoint(-0.5,-1.2), "\\{xff9966\\}", "k:C", -1.4);
 	gr->FaceZ(mglPoint(0,  -1.3), 1, 0.3, "{x83CAFF}#");	gr->Puts(mglPoint( 0.5,-1.2), "\\{x83CAFF\\}", "k:C", -1.4);
-	
+
 	gr->SubPlot(3,2,3);
 	char stl[3]="r1", txt[4]="'1'";
 	for(int i=0;i<10;i++)
@@ -182,20 +182,20 @@ void smgl_fexport(mglGraph *gr)	// test file export
 		gr->Line(mglPoint(-1,0.2*i-1),mglPoint(1,0.2*i-1),stl);
 		gr->Puts(mglPoint(1.05,0.2*i-1),txt,":L");
 	}
-	
+
 	gr->SubPlot(3,2,4);	gr->Title("TriPlot sample");	gr->Rotate(50,60);
 	double t[] = {0,1,2, 0,1,3, 0,2,3, 1,2,3};
 	double xt[] = {-1,1,0,0}, yt[] = {-1,-1,1,0}, zt[] = {-1,-1,-1,1};
 	mglData tt(4,3,t), uu(4,xt), vv(4,yt), ww(4,zt);
 	gr->TriPlot(tt,uu,vv,ww,"b");
 	gr->TriPlot(tt,uu,vv,ww,"k#");
-	
+
 	gr->SubPlot(3,2,5);
 	mglData r(4);	r.Fill(1,4);
 	gr->SetRanges(1,4,1,4);	gr->Axis();
 	gr->Mark(r,r,"s");
 	gr->Plot(r,"b");
-	
+
 	gr->WriteJPEG("fexport.jpg");
 	gr->WritePNG("fexport.png");
 	gr->WriteBMP("fexport.bmp");
@@ -203,7 +203,7 @@ void smgl_fexport(mglGraph *gr)	// test file export
 	gr->WriteEPS("fexport.eps");
 	gr->WriteSVG("fexport.svg");
 	gr->WriteGIF("fexport.gif");
-	
+
 	gr->WriteXYZ("fexport.xyz");
 	gr->WriteSTL("fexport.stl");
 	gr->WriteOFF("fexport.off");
@@ -212,6 +212,102 @@ void smgl_fexport(mglGraph *gr)	// test file export
 	gr->WritePRC("fexport.prc");
 }
 //-----------------------------------------------------------------------------
+const char *mmgl_refill="new x 10 '0.5+rnd':cumsum x 'x':norm x -1 1\n"
+"copy y sin(pi*x)/2\nbox:axis:plot x y 'o '\n"
+"new r 100:refill r x y\nplot r 'r'\nfplot 'sin(pi*x)/2' 'B:'";
+void smgl_refill(mglGraph *gr)
+{
+	mglData x(10), y(10), r(100);
+	x.Modify("0.5+rnd");	x.CumSum("x");	x.Norm(-1,1);
+	y.Modify("sin(pi*v)/2",x);
+	gr->Axis();	gr->Box();	gr->Plot(x,y,"o ");
+	gr->Refill(r,x,y);	// or you can use r.Refill(x,y,-1,1);
+	gr->Plot(r,"r");	gr->FPlot("sin(pi*x)/2","B:");
+}
+//-----------------------------------------------------------------------------
+const char *mmgl_correl="new a 100 'exp(-10*x^2)'\n"
+"new b 100 'exp(-10*(x+0.5)^2)'\n"
+"yrange 0 1\nsubplot 1 2 0 '_':title 'Input fields'\n"
+"plot a:plot b:box:axis\n"
+"correl r a b 'x'\nnorm r 0 1:swap r 'x' # make it human readable\n"
+"subplot 1 2 1 '_':title 'Correlation of a and b'\n"
+"plot r 'r':axis:box\nline 0.5 0 0.5 1 'B|'\n";
+void smgl_correl(mglGraph *gr)
+{
+	mglData a(100),b(100);
+	gr->Fill(a,"exp(-10*x^2)");	gr->Fill(b,"exp(-10*(x+0.5)^2)");
+	gr->SetRange('y',0,1);
+	gr->SubPlot(1,2,0,"_");	gr->Title("Input fields");
+	gr->Plot(a);	gr->Plot(b);	gr->Axis();	gr->Box();
+	mglData r = a.Correl(b,"x");
+	r.Norm(0,1);	r.Swap("x");	// make it human readable
+	gr->SubPlot(1,2,1,"_");	gr->Title("Correlation of a and b");
+	gr->Plot(r,"r");	gr->Axis();	gr->Box();
+	gr->Line(mglPoint(0.5,0),mglPoint(0.5,1),"B|");
+}
+//-----------------------------------------------------------------------------
+const char *mmgl_mask="new a 10 10 'x'\n"
+"subplot 5 4 0 '':title '\"-\" mask':dens a '3-'\n"
+"subplot 5 4 1 '':title '\"+\" mask':dens a '3+'\n"
+"subplot 5 4 2 '':title '\"=\" mask':dens a '3='\n"
+"subplot 5 4 3 '':title '\";\" mask':dens a '3;'\n"
+"subplot 5 4 4 '':title '\";I\" mask':dens a '3;I'\n"
+"subplot 5 4 5 '':title '\"o\" mask':dens a '3o'\n"
+"subplot 5 4 6 '':title '\"O\" mask':dens a '3O'\n"
+"subplot 5 4 7 '':title '\"s\" mask':dens a '3s'\n"
+"subplot 5 4 8 '':title '\"S\" mask':dens a '3S'\n"
+"subplot 5 4 9 '':title '\";/\" mask':dens a '3;/'\n"
+"subplot 5 4 10 '':title '\"~\" mask':dens a '3~'\n"
+"subplot 5 4 11 '':title '\"<\" mask':dens a '3<'\n"
+"subplot 5 4 12 '':title '\">\" mask':dens a '3>'\n"
+"subplot 5 4 13 '':title '\"j\" mask':dens a '3j'\n"
+"subplot 5 4 14 '':title '\"-;\\\" mask':dens a '3;\\ '\n"
+"subplot 5 4 15 '':title '\"d\" mask':dens a '3d'\n"
+"subplot 5 4 16 '':title '\"D\" mask':dens a '3D'\n"
+"subplot 5 4 17 '':title '\"*\" mask':dens a '3*'\n"
+"subplot 5 4 18 '':title '\"^\" mask':dens a '3^'\n"
+"subplot 5 4 19 '':title 'manual mask'\n"
+"mask '+' 'ff00182424f80000':dens a '3+'";
+void smgl_mask(mglGraph *gr)
+{
+	mglData a(10,10);	a.Fill(-1,1);
+	gr->SubPlot(5,4,0,"");	gr->Title("'-' mask");	gr->Dens(a,"3-");
+	gr->SubPlot(5,4,1,"");	gr->Title("'+' mask");	gr->Dens(a,"3+");
+	gr->SubPlot(5,4,2,"");	gr->Title("'=' mask");	gr->Dens(a,"3=");
+	gr->SubPlot(5,4,3,"");	gr->Title("';' mask");	gr->Dens(a,"3;");
+	gr->SubPlot(5,4,4,"");	gr->Title("';I' mask");	gr->Dens(a,"3;I");
+	gr->SubPlot(5,4,5,"");	gr->Title("'o' mask");	gr->Dens(a,"3o");
+	gr->SubPlot(5,4,6,"");	gr->Title("'O' mask");	gr->Dens(a,"3O");
+	gr->SubPlot(5,4,7,"");	gr->Title("'s' mask");	gr->Dens(a,"3s");
+	gr->SubPlot(5,4,8,"");	gr->Title("'S' mask");	gr->Dens(a,"3S");
+	gr->SubPlot(5,4,9,"");	gr->Title("';/' mask");	gr->Dens(a,"3;/");
+	gr->SubPlot(5,4,10,"");	gr->Title("'~' mask");	gr->Dens(a,"3~");
+	gr->SubPlot(5,4,11,"");	gr->Title("'<' mask");	gr->Dens(a,"3<");
+	gr->SubPlot(5,4,12,"");	gr->Title("'>' mask");	gr->Dens(a,"3>");
+	gr->SubPlot(5,4,13,"");	gr->Title("'j' mask");	gr->Dens(a,"3j");
+	gr->SubPlot(5,4,14,"");	gr->Title("';\\\\' mask");	gr->Dens(a,"3;\\");
+	gr->SubPlot(5,4,15,"");	gr->Title("'d' mask");	gr->Dens(a,"3d");
+	gr->SubPlot(5,4,16,"");	gr->Title("'D' mask");	gr->Dens(a,"3D");
+	gr->SubPlot(5,4,17,"");	gr->Title("'*' mask");	gr->Dens(a,"3*");
+	gr->SubPlot(5,4,18,"");	gr->Title("'^' mask");	gr->Dens(a,"3^");
+	gr->SubPlot(5,4,19,"");	gr->Title("manual mask");
+	gr->SetMask('+', "ff00182424f80000");	gr->Dens(a,"3+");
+}
+//-----------------------------------------------------------------------------
+const char *mmgl_export="new a 100 100 'x^2*y':new b 100 100\n"
+"export a 'test_data.png' 'BbcyrR' -1 1\n"
+"import b 'test_data.png' 'BbcyrR' -1 1\n"
+"subplot 2 1 0 '':title 'initial':box:dens a\n"
+"subplot 2 1 1 '':title 'imported':box:dens b";
+void smgl_export(mglGraph *gr)	// basic data operations
+{
+	mglData a(100,100), b; gr->Fill(a,"x^2*y");
+	a.Export("test_data.png","BbcyrR");
+	b.Import("test_data.png","BbcyrR",-1,1);
+	gr->SubPlot(2,1,0,"");	gr->Title("initial");	gr->Box();	gr->Dens(a);
+	gr->SubPlot(2,1,1,"");	gr->Title("imported");	gr->Box();	gr->Dens(b);
+}
+//-----------------------------------------------------------------------------
 const char *mmgl_data1="new a 40 50 60 'exp(-x^2-4*y^2-16*z^2)'\n"
 "light on:alpha on\n"
 "copy b a:diff b 'x':subplot 5 3 0:call 'splot'\n"
@@ -321,7 +417,7 @@ void smgl_param1(mglGraph *gr)	// 1d parametric plots
 	gr->SubPlot(4,3,2);	gr->Rotate(40,60);	gr->Box();	gr->Tens(x,y,z,c);
 	gr->SubPlot(4,3,3);	gr->Rotate(40,60);	gr->Box();	gr->Bars(x,y,z);
 	gr->SubPlot(4,3,4);	gr->Rotate(40,60);	gr->Box();	gr->Stem(x,y,z);
-	gr->SubPlot(4,3,5);	gr->Rotate(40,60);	gr->Box();	gr->TextMark(x,y,z,"\\alpha");
+	gr->SubPlot(4,3,5);	gr->Rotate(40,60);	gr->Box();	gr->TextMark(x,y,z,c*2,"\\alpha");
 	gr->SubPlot(4,3,6);	gr->Rotate(40,60);	gr->Box();	gr->Tube(x,y,z,c/10,"","light on");
 	gr->SubPlot(4,3,7);	gr->Rotate(40,60);	gr->Box();	gr->Mark(x,y,z,c,"s");
 	gr->SubPlot(4,3,8);	gr->Rotate(40,60);	gr->Box();	gr->Error(x,y,z/10,c/10);
@@ -355,7 +451,7 @@ void smgl_param2(mglGraph *gr)	// 2d parametric plots
 	mglData x(100,100), y(100,100), z(100,100), c(100,100);
 	gr->Fill(x,"sin(pi*(x+y)/2)*cos(pi*y/2)");	gr->Fill(y,"cos(pi*(x+y)/2)*cos(pi*y/2)");
 	gr->Fill(z,"sin(pi*y/2)");	gr->Fill(c,"cos(pi*x)");
-	
+
 	gr->SubPlot(4,4,0);	gr->Rotate(40,60);	gr->Box();	gr->Surf(x,y,z);
 	gr->SubPlot(4,4,1);	gr->Rotate(40,60);	gr->Box();	gr->SurfC(x,y,z,c);
 	gr->SubPlot(4,4,2);	gr->Rotate(40,60);	gr->Box();	gr->SurfA(x,y,z,c,"","alpha 1");
@@ -443,7 +539,7 @@ void smgl_paramv(mglGraph *gr)	// parametric plots for vector field
 	gr->SubPlot(3,3,4);	gr->Rotate(40,60);	gr->Box();	gr->Vect(x,y,z,ex,ey,ez);
 	gr->SubPlot(3,3,5);	gr->Rotate(40,60);	gr->Box();
 	gr->Vect3(x,y,z,ex,ey,ez);	gr->Vect3(x,y,z,ex,ey,ez,"x");	gr->Vect3(x,y,z,ex,ey,ez,"z");
-	gr->Grid3(x,y,z,z,"{r9}");	gr->Grid3(x,y,z,z,"{r9}x");		gr->Grid3(x,y,z,z,"{r9}z");
+	gr->Grid3(x,y,z,z,"{r9}");	gr->Grid3(x,y,z,z,"{g9}x");		gr->Grid3(x,y,z,z,"{b9}z");
 	gr->SubPlot(3,3,6);	gr->Rotate(40,60);	gr->Box();	gr->Flow(x,y,z,ex,ey,ez);
 	gr->SubPlot(3,3,7);	gr->Rotate(40,60);	gr->Box();	gr->Pipe(x,y,z,ex,ey,ez);
 }
@@ -512,8 +608,8 @@ void smgl_triangulation(mglGraph *gr)	// surface triangulation
 	mglData x(100), y(100), z(100);
 	gr->Fill(x,"2*rnd-1");	gr->Fill(y,"2*rnd-1");	gr->Fill(z,"v^2-w^2",x,y);
 	mglData d = mglTriangulation(x,y), g(30,30);
-	
-	if(!mini)	gr->Title("Triangulation");
+
+	if(big!=3)	gr->Title("Triangulation");
 	gr->Rotate(40,60);	gr->Box();	gr->Light(true);
 	gr->TriPlot(d,x,y,z);	gr->TriPlot(d,x,y,z,"#k");
 
@@ -542,8 +638,8 @@ const char *mmgl_schemes="call 'sch' 0 'kw'\ncall 'sch' 1 'wk'\ncall 'sch' 2 'kH
 "call 'sch' 8 'GgwmM'\ncall 'sch' 9 'UuwqR'\ncall 'sch' 10 'QqwcC'\ncall 'sch' 11 'CcwyY'\n"
 "call 'sch' 12 'bcwyr'\ncall 'sch' 13 'bwr'\ncall 'sch' 14 'BbcyrR'\ncall 'sch' 15 'UbcyqR'\n"
 "call 'sch' 16 'BbcwyrR'\ncall 'sch' 17 'bgr'\ncall 'sch' 18 'BbcyrR|'\ncall 'sch' 19 'b\\{g,0.3\\}r'\n"
-"stop\nfunc 'sch' 2\nsubplot 2 10 $1 '<>_^' 0.2 0:fsurf 'x' '$2'\n"
-"text 0.07+0.5*mod($1,2) 0.92-0.1*int($1/2) '$2' 'A'\nreturn\n";
+"stop\nfunc 'sch' 2\nsubplot 2 10 $1 '<>_^' 0.2 0:fsurf 'x' $2\n"
+"text 0.07+0.5*mod($1,2) 0.92-0.1*int($1/2) $2 'A'\nreturn\n";
 void smgl_schemes(mglGraph *gr)	// Color table
 {
 	mglData a(256,2);	a.Fill(-1,1);
@@ -736,7 +832,7 @@ const char *mmgl_text="call 'prepare1d'\nsubplot 2 2 0 ''\ntext 0 1 'Text can be
 "line -1 -1 1 1 'rA':text 0 0 1 1 'At angle' '@'\nline -1 -1 -1 1 'rA':text -1 0 -1 1 'Vertical'\n";
 void smgl_text(mglGraph *gr)	// text drawing
 {
-	if(!mini)	gr->SubPlot(2,2,0,"");
+	if(big!=3)	gr->SubPlot(2,2,0,"");
 	gr->Putsw(mglPoint(0,1),L"Text can be in ASCII and in Unicode");
 	gr->Puts(mglPoint(0,0.6),"It can be \\wire{wire}, \\big{big} or #r{colored}");
 	gr->Puts(mglPoint(0,0.2),"One can change style in string: "
@@ -746,7 +842,7 @@ void smgl_text(mglGraph *gr)	// text drawing
 	gr->Puts(mglPoint(0,-0.6),"Easy to change indexes ^{up} _{down} @{center}");
 	gr->Puts(mglPoint(0,-1),"It parse TeX: \\int \\alpha \\cdot "
 	"\\sqrt3{sin(\\pi x)^2 + \\gamma_{i_k}} dx");
-	if(mini)	return;
+	if(big==3)	return;
 
 	gr->SubPlot(2,2,1,"");
 	gr->Puts(mglPoint(0,0.5), "\\sqrt{\\frac{\\alpha^{\\gamma^2}+\\overset 1{\\big\\infty}}{\\sqrt3{2+b}}}", "@", -2);
@@ -764,6 +860,30 @@ void smgl_text(mglGraph *gr)	// text drawing
 	gr->Line(mglPoint(-1,-1),mglPoint(-1,1),"rA");	gr->Puts(mglPoint(-1,0),mglPoint(-1,1),"Vertical");
 }
 //-----------------------------------------------------------------------------
+const char *mmgl_text2="call 'prepare1d'\n"
+"subplot 1 3 0 '':box:plot y(:,0)\ntext y 'This is very very long string drawn along a curve' 'k'\ntext y 'Another string drawn above a curve' 'Tr'\n"
+"subplot 1 3 1 '':box:plot y(:,0)\ntext y 'This is very very long string drawn along a curve' 'k:C'\ntext y 'Another string drawn above a curve' 'Tr:C'\n"
+"subplot 1 3 2 '':box:plot y(:,0)\ntext y 'This is very very long string drawn along a curve' 'k:R'\ntext y 'Another string drawn above a curve' 'Tr:R'\n";
+void smgl_text2(mglGraph *gr)	// text drawing
+{
+	mglData y;	mgls_prepare1d(&y);
+	if(big!=3)	gr->SubPlot(1,3,0,"");
+	gr->Box();	gr->Plot(y.SubData(-1,0));
+	gr->Text(y,"This is very very long string drawn along a curve","k");
+	gr->Text(y,"Another string drawn above a curve","Tr");
+	if(big==3)	return;
+
+	gr->SubPlot(1,3,1,"");
+	gr->Box();	gr->Plot(y.SubData(-1,0));
+	gr->Text(y,"This is very very long string drawn along a curve","k:C");
+	gr->Text(y,"Another string drawn above a curve","Tr:C");
+
+	gr->SubPlot(1,3,2,"");
+	gr->Box();	gr->Plot(y.SubData(-1,0));
+	gr->Text(y,"This is very very long string drawn along a curve","k:R");
+	gr->Text(y,"Another string drawn above a curve","Tr:R");
+}
+//-----------------------------------------------------------------------------
 const char *mmgl_fonts="define d 0.25\nloadfont 'STIX':text 0 1.1 'default font (STIX)'\nloadfont 'adventor':text 0 1.1-d 'adventor font'\n"
 "loadfont 'bonum':text 0 1.1-2*d 'bonum font'\nloadfont 'chorus':text 0 1.1-3*d 'chorus font'\nloadfont 'cursor':text 0 1.1-4*d 'cursor font'\n"
 "loadfont 'heros':text 0 1.1-5*d 'heros font'\nloadfont 'heroscn':text 0 1.1-6*d 'heroscn font'\nloadfont 'pagella':text 0 1.1-7*d 'pagella font'\n"
@@ -793,9 +913,9 @@ void smgl_bars(mglGraph *gr)
 {
 	mglData ys(10,3);	ys.Modify("0.8*sin(pi*(2*x+y/2))+0.2*rnd");
 	gr->SetOrigin(0,0,0);
-	if(!mini)	{	gr->SubPlot(3,2,0,"");	gr->Title("Bars plot (default)");	}
+	if(big!=3)	{	gr->SubPlot(3,2,0,"");	gr->Title("Bars plot (default)");	}
 	gr->Box();	gr->Bars(ys);
-	if(mini)	return;
+	if(big==3)	return;
 	gr->SubPlot(3,2,1,"");	gr->Title("2 colors");	gr->Box();	gr->Bars(ys,"cbgGyr");
 	gr->SubPlot(3,2,4,"");	gr->Title("'\\#' style");	gr->Box();	gr->Bars(ys,"#");
 	gr->SubPlot(3,2,5);	gr->Title("3d variant");	gr->Rotate(50,60);	gr->Box();
@@ -814,9 +934,9 @@ void smgl_barh(mglGraph *gr)
 {
 	mglData ys(10,3);	ys.Modify("0.8*sin(pi*(2*x+y/2))+0.2*rnd");
 	gr->SetOrigin(0,0,0);
-	if(!mini)	{	gr->SubPlot(2,2,0,"");	gr->Title("Barh plot (default)");	}
+	if(big!=3)	{	gr->SubPlot(2,2,0,"");	gr->Title("Barh plot (default)");	}
 	gr->Box();	gr->Barh(ys);
-	if(mini)	return;
+	if(big==3)	return;
 	gr->SubPlot(2,2,1,"");	gr->Title("2 colors");	gr->Box();	gr->Barh(ys,"cbgGyr");
 	gr->SetRanges(-3,3,-1,1);	// increase range since summation can exceed [-1,1]
 	gr->SubPlot(2,2,2,"");	gr->Title("'a' style");	gr->Box();	gr->Barh(ys,"a");
@@ -830,9 +950,9 @@ const char *mmgl_area="call 'prepare1d'\norigin 0 0 0\nsubplot 2 2 0 '':title 'A
 void smgl_area(mglGraph *gr)
 {
 	mglData y;	mgls_prepare1d(&y);	gr->SetOrigin(0,0,0);
-	if(!mini)	{	gr->SubPlot(2,2,0,"");	gr->Title("Area plot (default)");	}
+	if(big!=3)	{	gr->SubPlot(2,2,0,"");	gr->Title("Area plot (default)");	}
 	gr->Box();	gr->Area(y);
-	if(mini)	return;
+	if(big==3)	return;
 	gr->SubPlot(2,2,1,"");	gr->Title("2 colors");	gr->Box();	gr->Area(y,"cbgGyr");
 	gr->SubPlot(2,2,2,"");	gr->Title("'!' style");	gr->Box();	gr->Area(y,"!");
 	gr->SubPlot(2,2,3);	gr->Title("3d variant");	gr->Rotate(50,60);	gr->Box();
@@ -848,9 +968,9 @@ const char *mmgl_plot="call 'prepare1d'\nsubplot 2 2 0 '':title 'Plot plot (defa
 void smgl_plot(mglGraph *gr)
 {
 	mglData y;	mgls_prepare1d(&y);	gr->SetOrigin(0,0,0);
-	if(!mini)	{	gr->SubPlot(2,2,0,"");	gr->Title("Plot plot (default)");	}
+	if(big!=3)	{	gr->SubPlot(2,2,0,"");	gr->Title("Plot plot (default)");	}
 	gr->Box();	gr->Plot(y);
-	if(mini)	return;
+	if(big==3)	return;
 	gr->SubPlot(2,2,2,"");	gr->Title("'!' style; 'rgb' palette");	gr->Box();	gr->Plot(y,"o!rgb");
 	gr->SubPlot(2,2,3,"");	gr->Title("just markers");	gr->Box();	gr->Plot(y," +");
 	gr->SubPlot(2,2,1);	gr->Title("3d variant");	gr->Rotate(50,60);	gr->Box();
@@ -860,15 +980,15 @@ void smgl_plot(mglGraph *gr)
 }
 //-----------------------------------------------------------------------------
 const char *mmgl_tens="call 'prepare1d'\nsubplot 2 2 0 '':title 'Tens plot (default)':box:tens y(:,0) y(:,1)\n"
-"subplot 2 2 2 '':title '" " style':box:tens y(:,0) y(:,1) 'o '\n"
+"subplot 2 2 2 '':title '\" \" style':box:tens y(:,0) y(:,1) 'o '\n"
 "new yc 30 'sin(pi*x)':new xc 30 'cos(pi*x)':new z 30 'x'\n"
 "subplot 2 2 1:title '3d variant':rotate 50 60:box:tens xc yc z z 's'\n";
 void smgl_tens(mglGraph *gr)
 {
 	mglData y;	mgls_prepare1d(&y);	gr->SetOrigin(0,0,0);
-	if(!mini)	{	gr->SubPlot(2,2,0,"");	gr->Title("Tens plot (default)");	}
+	if(big!=3)	{	gr->SubPlot(2,2,0,"");	gr->Title("Tens plot (default)");	}
 	gr->Box();	gr->Tens(y.SubData(-1,0), y.SubData(-1,1));
-	if(mini)	return;
+	if(big==3)	return;
 	gr->SubPlot(2,2,2,"");	gr->Title("' ' style");	gr->Box();	gr->Tens(y.SubData(-1,0), y.SubData(-1,1),"o ");
 	gr->SubPlot(2,2,1);	gr->Title("3d variant");	gr->Rotate(50,60);	gr->Box();
 	mglData yc(30), xc(30), z(30);	z.Modify("2*x-1");
@@ -885,9 +1005,9 @@ void smgl_region(mglGraph *gr)
 {
 	mglData y;	mgls_prepare1d(&y);
 	mglData y1 = y.SubData(-1,1), y2 = y.SubData(-1,2);	gr->SetOrigin(0,0,0);
-	if(!mini)	{	gr->SubPlot(2,2,0,"");	gr->Title("Region plot (default)");	}
+	if(big!=3)	{	gr->SubPlot(2,2,0,"");	gr->Title("Region plot (default)");	}
 	gr->Box();	gr->Region(y1,y2);	gr->Plot(y1,"k2");	gr->Plot(y2,"k2");
-	if(mini)	return;
+	if(big==3)	return;
 	gr->SubPlot(2,2,1,"");	gr->Title("2 colors");	gr->Box();	gr->Region(y1,y2,"yr");	gr->Plot(y1,"k2");	gr->Plot(y2,"k2");
 	gr->SubPlot(2,2,2,"");	gr->Title("'!' style");	gr->Box();	gr->Region(y1,y2,"!");	gr->Plot(y1,"k2");	gr->Plot(y2,"k2");
 	gr->SubPlot(2,2,3,"");	gr->Title("'i' style");	gr->Box();	gr->Region(y1,y2,"ir");	gr->Plot(y1,"k2");	gr->Plot(y2,"k2");
@@ -901,9 +1021,9 @@ void smgl_stem(mglGraph *gr)
 	mglData y;	mgls_prepare1d(&y);	gr->SetOrigin(0,0,0);
 	mglData yc(30), xc(30), z(30);	z.Modify("2*x-1");
 	yc.Modify("sin(pi*(2*x-1))");	xc.Modify("cos(pi*2*x-pi)");
-	if(!mini)	{	gr->SubPlot(2,2,0,"");	gr->Title("Stem plot (default)");	}
+	if(big!=3)	{	gr->SubPlot(2,2,0,"");	gr->Title("Stem plot (default)");	}
 	gr->Box();	gr->Stem(y);
-	if(mini)	return;
+	if(big==3)	return;
 	gr->SubPlot(2,2,1);	gr->Title("3d variant");	gr->Rotate(50,60);
 	gr->Box();	gr->Stem(xc,yc,z,"rx");
 	gr->SubPlot(2,2,2,"");	gr->Title("'!' style");	gr->Box();	gr->Stem(y,"o!rgb");
@@ -917,22 +1037,34 @@ void smgl_step(mglGraph *gr)
 	mglData y;	mgls_prepare1d(&y);	gr->SetOrigin(0,0,0);
 	mglData yc(30), xc(30), z(30);	z.Modify("2*x-1");
 	yc.Modify("sin(pi*(2*x-1))");	xc.Modify("cos(pi*2*x-pi)");
-	if(!mini)	{	gr->SubPlot(2,2,0,"");	gr->Title("Step plot (default)");	}
+	if(big!=3)	{	gr->SubPlot(2,2,0,"");	gr->Title("Step plot (default)");	}
 	gr->Box();	gr->Step(y);
-	if(mini)	return;
+	if(big==3)	return;
 	gr->SubPlot(2,2,1);	gr->Title("3d variant");	gr->Rotate(50,60);
 	gr->Box();	gr->Step(xc,yc,z,"r");
 	gr->SubPlot(2,2,2,"");	gr->Title("'!' style");	gr->Box();	gr->Step(y,"s!rgb");
 }
 //-----------------------------------------------------------------------------
-const char *mmgl_boxplot="new a 10 7 '(2*rnd-1)^3/2'\nsubplot 1 1 0 '':title 'Boxplot plot':box:boxplot a";
+const char *mmgl_boxplot="new a 10 7 '(2*rnd-1)^3/2'\nsubplot 1 1 0 '':title 'Boxplot plot':box:boxplot a\n";
 void smgl_boxplot(mglGraph *gr)	// flow threads and density plot
 {
 	mglData a(10,7);	a.Modify("(2*rnd-1)^3/2");
-	if(!mini)	{	gr->SubPlot(1,1,0,"");	gr->Title("Boxplot plot");	}
+	if(big!=3)	{	gr->SubPlot(1,1,0,"");	gr->Title("Boxplot plot");	}
 	gr->Box();	gr->BoxPlot(a);
 }
 //-----------------------------------------------------------------------------
+const char *mmgl_ohlc="new o 10 '0.5*sin(pi*x)'\nnew c 10 '0.5*sin(pi*(x+2/9))'\n"
+"new l 10 '0.3*rnd-0.8'\nnew h 10 '0.3*rnd+0.5'\n"
+"subplot 1 1 0 '':title 'OHLC plot':box:ohlc o h l c\n";
+void smgl_ohlc(mglGraph *gr)	// flow threads and density plot
+{
+	mglData o(10), h(10), l(10), c(10);
+	gr->Fill(o,"0.5*sin(pi*x)");	gr->Fill(c,"0.5*sin(pi*(x+2/9))");
+	gr->Fill(l,"0.3*rnd-0.8");		gr->Fill(h,"0.3*rnd+0.5");
+	if(big!=3)	{	gr->SubPlot(1,1,0,"");	gr->Title("OHLC plot");	}
+	gr->Box();	gr->OHLC(o,h,l,c);
+}
+//-----------------------------------------------------------------------------
 const char *mmgl_type0="call 'prepare2d'\nalpha on:light on:transptype 0:clf\nsubplot 2 2 0:rotate 50 60:surf a:box\n"
 "subplot 2 2 1:rotate 50 60:dens a:box\nsubplot 2 2 2:rotate 50 60:cont a:box\n"
 "subplot 2 2 3:rotate 50 60:axial a:box";
@@ -1055,6 +1187,39 @@ void smgl_molecule(mglGraph *gr)	// example of moleculas
 	gr->DoubleSided( true ); // put back
 }
 //-----------------------------------------------------------------------------
+const char *mmgl_error2="new x0 10 'rnd':new ex 10 '0.1'\nnew y0 10 'rnd':new ey 10 '0.1'\nranges 0 1 0 1\n"
+"subplot 4 3 0 '':box:error x0 y0 ex ey '#+@'\n"
+"subplot 4 3 1 '':box:error x0 y0 ex ey '#x@'\n"
+"subplot 4 3 2 '':box:error x0 y0 ex ey '#s@'; alpha 0.5\n"
+"subplot 4 3 3 '':box:error x0 y0 ex ey 's@'\n"
+"subplot 4 3 4 '':box:error x0 y0 ex ey 'd@'\n"
+"subplot 4 3 5 '':box:error x0 y0 ex ey '#d@'; alpha 0.5\n"
+"subplot 4 3 6 '':box:error x0 y0 ex ey '+@'\n"
+"subplot 4 3 7 '':box:error x0 y0 ex ey 'x@'\n"
+"subplot 4 3 8 '':box:error x0 y0 ex ey 'o@'\n"
+"subplot 4 3 9 '':box:error x0 y0 ex ey '#o@'; alpha 0.5\n"
+"subplot 4 3 10 '':box:error x0 y0 ex ey '#.@'\n"
+"subplot 4 3 11 '':box:error x0 y0 ex ey; alpha 0.5\n";
+void smgl_error2(mglGraph *gr)
+{
+	mglData x0(10), y0(10), ex(10), ey(10);
+	for(int i=0;i<10;i++)
+	{	x0.a[i] = mgl_rnd();	y0.a[i] = mgl_rnd();	ey.a[i] = ex.a[i] = 0.1;	}
+	gr->SetRanges(0,1,0,1);	gr->Alpha(true);
+	gr->SubPlot(4,3,0,"");	gr->Box();	gr->Error(x0,y0,ex,ey,"#+@");
+	gr->SubPlot(4,3,1,"");	gr->Box();	gr->Error(x0,y0,ex,ey,"#x@");
+	gr->SubPlot(4,3,2,"");	gr->Box();	gr->Error(x0,y0,ex,ey,"#s@","alpha 0.5");
+	gr->SubPlot(4,3,3,"");	gr->Box();	gr->Error(x0,y0,ex,ey,"s@");
+	gr->SubPlot(4,3,4,"");	gr->Box();	gr->Error(x0,y0,ex,ey,"d@");
+	gr->SubPlot(4,3,5,"");	gr->Box();	gr->Error(x0,y0,ex,ey,"#d@","alpha 0.5");
+	gr->SubPlot(4,3,6,"");	gr->Box();	gr->Error(x0,y0,ex,ey,"+@");
+	gr->SubPlot(4,3,7,"");	gr->Box();	gr->Error(x0,y0,ex,ey,"x@");
+	gr->SubPlot(4,3,8,"");	gr->Box();	gr->Error(x0,y0,ex,ey,"o@");
+	gr->SubPlot(4,3,9,"");	gr->Box();	gr->Error(x0,y0,ex,ey,"#o@","alpha 0.5");
+	gr->SubPlot(4,3,10,"");	gr->Box();	gr->Error(x0,y0,ex,ey,"#.@");
+	gr->SubPlot(4,3,11,"");	gr->Box();	gr->Error(x0,y0,ex,ey);
+}
+//-----------------------------------------------------------------------------
 const char *mmgl_error="call 'prepare1d'\nnew y 50 '0.7*sin(pi*x-pi) + 0.5*cos(3*pi*(x+1)/2) + 0.2*sin(pi*(x+1)/2)'\n"
 "new x0 10 'x + 0.1*rnd-0.05':new ex 10 '0.1':new ey 10 '0.2'\n"
 "new y0 10 '0.7*sin(pi*x-pi) + 0.5*cos(3*pi*(x+1)/2) + 0.2*sin(pi*(x+1)/2) + 0.2*rnd-0.1'\n"
@@ -1075,9 +1240,9 @@ void smgl_error(mglGraph *gr)
 		y0.a[i] = 0.7*sin(2*M_PI*x)+0.5*cos(3*M_PI*x)+0.2*sin(M_PI*x)+0.2*mgl_rnd()-0.1;
 		ey0.a[i]=0.2;	ex0.a[i]=0.1;
 	}
-	if(!mini)	{	gr->SubPlot(2,2,0,"");	gr->Title("Error plot (default)");	}
+	if(big!=3)	{	gr->SubPlot(2,2,0,"");	gr->Title("Error plot (default)");	}
 	gr->Box();	gr->Plot(y.SubData(-1,0));	gr->Error(x0,y0,ex0,ey0,"ko");
-	if(mini)	return;
+	if(big==3)	return;
 	gr->SubPlot(2,2,1,"");	gr->Title("'!' style; no e_x");
 	gr->Box();	gr->Plot(y.SubData(-1,0));	gr->Error(x0,y0,ey0,"o!rgb");
 	gr->SubPlot(2,2,2,"");	gr->Title("'\\@' style");	gr->Alpha(true);
@@ -1098,9 +1263,9 @@ const char *mmgl_chart="new ch 7 2 'rnd+0.1':light on\n"
 void smgl_chart(mglGraph *gr)
 {
 	mglData ch(7,2);	for(int i=0;i<7*2;i++)	ch.a[i]=mgl_rnd()+0.1;
-	if(!mini)	{	gr->SubPlot(2,2,0);	gr->Title("Chart plot (default)");	}
+	if(big!=3)	{	gr->SubPlot(2,2,0);	gr->Title("Chart plot (default)");	}
 	gr->Light(true);	gr->Rotate(50,60);	gr->Box();	gr->Chart(ch);
-	if(mini)	return;
+	if(big==3)	return;
 	gr->SubPlot(2,2,1);	gr->Title("'\\#' style");
 	gr->Rotate(50,60);	gr->Box();	gr->Chart(ch,"#");
 	gr->SubPlot(2,2,2);	gr->Title("Pie chart; ' ' color");
@@ -1115,7 +1280,7 @@ const char *mmgl_mark="call 'prepare1d'\nsubplot 1 1 0 '':title 'Mark plot (defa
 void smgl_mark(mglGraph *gr)
 {
 	mglData y,y1;	mgls_prepare1d(&y,&y1);
-	if(!mini)	{	gr->SubPlot(1,1,0,"");	gr->Title("Mark plot (default)");	}
+	if(big!=3)	{	gr->SubPlot(1,1,0,"");	gr->Title("Mark plot (default)");	}
 	gr->Box();	gr->Mark(y,y1,"s");
 }
 //-----------------------------------------------------------------------------
@@ -1124,7 +1289,7 @@ const char *mmgl_radar="new yr 10 3 '0.4*sin(pi*(x+1.5+y/2)+0.1*rnd)'\n"
 void smgl_radar(mglGraph *gr)
 {
 	mglData yr(10,3);	yr.Modify("0.4*sin(pi*(2*x+y))+0.1*rnd");
-	if(!mini)	{	gr->SubPlot(1,1,0,"");	gr->Title("Radar plot (with grid, '\\#')");	}
+	if(big!=3)	{	gr->SubPlot(1,1,0,"");	gr->Title("Radar plot (with grid, '\\#')");	}
 	gr->Radar(yr,"#");
 }
 //-----------------------------------------------------------------------------
@@ -1135,7 +1300,7 @@ void smgl_candle(mglGraph *gr)
 	mglData y(30);	gr->Fill(y,"sin(pi*x/2)^2");
 	mglData y1(30);	gr->Fill(y1,"v/2",y);
 	mglData y2(30);	gr->Fill(y2,"(1+v)/2",y);
-	if(!mini)	{	gr->SubPlot(1,1,0,"");	gr->Title("Candle plot (default)");	}
+	if(big!=3)	{	gr->SubPlot(1,1,0,"");	gr->Title("Candle plot (default)");	}
 	gr->SetRange('y',0,1);	gr->Box();	gr->Candle(y,y1,y2);
 }
 //-----------------------------------------------------------------------------
@@ -1143,7 +1308,7 @@ const char *mmgl_textmark="call 'prepare1d'\nsubplot 1 1 0 '':title 'TextMark pl
 void smgl_textmark(mglGraph *gr)
 {
 	mglData y,y1;	mgls_prepare1d(&y,&y1);
-	if(!mini)	{	gr->SubPlot(1,1,0,"");	gr->Title("TextMark plot (default)");	}
+	if(big!=3)	{	gr->SubPlot(1,1,0,"");	gr->Title("TextMark plot (default)");	}
 	gr->Box();	gr->TextMark(y,y1,"\\gamma","r");
 }
 //-----------------------------------------------------------------------------
@@ -1156,9 +1321,9 @@ const char *mmgl_tube="call 'prepare1d'\nlight on\n"
 void smgl_tube(mglGraph *gr)
 {
 	mglData y,y1,y2;	mgls_prepare1d(&y,&y1,&y2);	y1/=20;
-	if(!mini)	{	gr->SubPlot(2,2,0,"");	gr->Title("Tube plot (default)");	}
+	if(big!=3)	{	gr->SubPlot(2,2,0,"");	gr->Title("Tube plot (default)");	}
 	gr->Light(true);	gr->Box();	gr->Tube(y,0.05);
-	if(mini)	return;
+	if(big==3)	return;
 	gr->SubPlot(2,2,1,"");	gr->Title("variable radius");	gr->Box();	gr->Tube(y,y1);
 	gr->SubPlot(2,2,2,"");	gr->Title("'\\#' style");	gr->Box();	gr->Tube(y,0.05,"#");
 	mglData yc(50), xc(50), z(50);	z.Modify("2*x-1");
@@ -1180,9 +1345,9 @@ void smgl_tape(mglGraph *gr)
 	mglData xc(50), yc(50), z(50);
 	yc.Modify("sin(pi*(2*x-1))");
 	xc.Modify("cos(pi*2*x-pi)");	z.Fill(-1,1);
-	if(!mini)	{	gr->SubPlot(2,2,0,"");	gr->Title("Tape plot (default)");	}
+	if(big!=3)	{	gr->SubPlot(2,2,0,"");	gr->Title("Tape plot (default)");	}
 	gr->Box();	gr->Tape(y);	gr->Plot(y,"k");
-	if(mini)	return;
+	if(big==3)	return;
 	gr->SubPlot(2,2,1);	gr->Title("3d variant, 2 colors");	gr->Rotate(50,60);	gr->Light(true);
 	gr->Box();	gr->Plot(xc,yc,z,"k");	gr->Tape(xc,yc,z,"rg");
 	gr->SubPlot(2,2,2);	gr->Title("3d variant, x only");	gr->Rotate(50,60);
@@ -1191,13 +1356,13 @@ void smgl_tape(mglGraph *gr)
 	gr->Box();	gr->Plot(xc,yc,z,"k");	gr->Tape(xc,yc,z,"zg");	gr->Tape(xc,yc,z,"zg#");
 }
 //-----------------------------------------------------------------------------
-const char *mmgl_fog="call 'prepare2d'\ntitle 'Fog sample':rotate 50 60:light on:fog 1\nbox:surf a\n";
+const char *mmgl_fog="call 'prepare2d'\ntitle 'Fog sample':rotate 50 60:light on:fog 1\nbox:surf a:cont a 'y'\n";
 void smgl_fog(mglGraph *gr)
 {
 	mglData a;	mgls_prepare2d(&a);
-	if(!mini)	gr->Title("Fog sample");
+	if(big!=3)	gr->Title("Fog sample");
 	gr->Light(true);	gr->Rotate(50,60);	gr->Fog(1);	gr->Box();
-	gr->Surf(a);
+	gr->Surf(a);	gr->Cont(a,"y");
 }
 //-----------------------------------------------------------------------------
 const char *mmgl_map="new a 50 40 'x':new b 50 40 'y':zrange -2 2:text 0 0 '\\to'\n"
@@ -1254,7 +1419,7 @@ void smgl_qo2d(mglGraph *gr)
 	mglData r, xx, yy, a, im(128), re(128);
 	const char *ham = "p^2+q^2-x-1+i*0.5*(y+x)*(y>-x)";
 	r = mglRay(ham, mglPoint(-0.7, -1), mglPoint(0, 0.5), 0.02, 2);
-	if(!mini)	{gr->SubPlot(1,1,0,"<_");	gr->Title("Beam and ray tracing");}
+	if(big!=3)	{gr->SubPlot(1,1,0,"<_");	gr->Title("Beam and ray tracing");}
 	gr->Plot(r.SubData(0), r.SubData(1), "k");
 	gr->Axis();	gr->Label('x', "\\i x");	gr->Label('y', "\\i y");
 	// now start beam tracing
@@ -1279,7 +1444,7 @@ void smgl_pde(mglGraph *gr)	// PDE sample
 	gr->Fill(re,"exp(-48*(x+0.7)^2)");
 	a = gr->PDE("p^2+q^2-x-1+i*0.5*(z+x)*(z>-x)", re, im, 0.01, 30);
 	a.Transpose("yxz");
-	if(!mini)	{gr->SubPlot(1,1,0,"<_");	gr->Title("PDE solver");	}
+	if(big!=3)	{gr->SubPlot(1,1,0,"<_");	gr->Title("PDE solver");	}
 	gr->SetRange('c',0,1);	gr->Dens(a,"wyrRk");
 	gr->Axis();	gr->Label('x', "\\i x");	gr->Label('y', "\\i z");
 	gr->FPlot("-x", "k|");
@@ -1290,7 +1455,7 @@ const char *mmgl_conta="call 'prepare3d'\ntitle 'Cont3 sample':rotate 50 60:box\
 void smgl_conta(mglGraph *gr)
 {
 	mglData c;	mgls_prepare3d(&c);
-	if(!mini)	gr->Title("Cont3 sample");
+	if(big!=3)	gr->Title("Cont3 sample");
 	gr->Rotate(50,60);	gr->Box();
 	gr->Cont3(c,"x");	gr->Cont3(c);	gr->Cont3(c,"z");
 }
@@ -1300,7 +1465,7 @@ const char *mmgl_contfa="call 'prepare3d'\ntitle 'Cont3 sample':rotate 50 60:box
 void smgl_contfa(mglGraph *gr)
 {
 	mglData c;	mgls_prepare3d(&c);
-	if(!mini)	gr->Title("ContF3 sample");
+	if(big!=3)	gr->Title("ContF3 sample");
 	gr->Rotate(50,60);	gr->Light(true);	gr->Box();
 	gr->ContF3(c,"x");	gr->ContF3(c);		gr->ContF3(c,"z");
 	gr->Cont3(c,"kx");	gr->Cont3(c,"k");	gr->Cont3(c,"kz");
@@ -1311,7 +1476,7 @@ const char *mmgl_densa="call 'prepare3d'\ntitle 'Dens3 sample':rotate 50 60:alph
 void smgl_densa(mglGraph *gr)
 {
 	mglData c;	mgls_prepare3d(&c);
-	if(!mini)	gr->Title("Dens3 sample");
+	if(big!=3)	gr->Title("Dens3 sample");
 	gr->Rotate(50,60);	gr->Alpha(true);	gr->SetAlphaDef(0.7);
 	gr->SetOrigin(0,0,0);	gr->Axis("_xyz");	gr->Box();
 	gr->Dens3(c,"x");	gr->Dens3(c);	gr->Dens3(c,"z");
@@ -1322,7 +1487,7 @@ const char *mmgl_dens_xyz="call 'prepare3d'\ntitle 'Dens[XYZ] sample':rotate 50
 void smgl_dens_xyz(mglGraph *gr)
 {
 	mglData c;	mgls_prepare3d(&c);
-	if(!mini)	gr->Title("Dens[XYZ] sample");
+	if(big!=3)	gr->Title("Dens[XYZ] sample");
 	gr->Rotate(50,60);	gr->Box();	gr->DensX(c.Sum("x"),0,-1);
 	gr->DensY(c.Sum("y"),0,1);		gr->DensZ(c.Sum("z"),0,-1);
 }
@@ -1332,7 +1497,7 @@ const char *mmgl_cont_xyz="call 'prepare3d'\ntitle 'Cont[XYZ] sample':rotate 50
 void smgl_cont_xyz(mglGraph *gr)
 {
 	mglData c;	mgls_prepare3d(&c);
-	if(!mini)	gr->Title("Cont[XYZ] sample");
+	if(big!=3)	gr->Title("Cont[XYZ] sample");
 	gr->Rotate(50,60);	gr->Box();	gr->ContX(c.Sum("x"),"",-1);
 	gr->ContY(c.Sum("y"),"",1);		gr->ContZ(c.Sum("z"),"",-1);
 }
@@ -1342,24 +1507,24 @@ const char *mmgl_contf_xyz="call 'prepare3d'\ntitle 'ContF[XYZ] sample':rotate 5
 void smgl_contf_xyz(mglGraph *gr)
 {
 	mglData c;	mgls_prepare3d(&c);
-	if(!mini)	gr->Title("ContF[XYZ] sample");
+	if(big!=3)	gr->Title("ContF[XYZ] sample");
 	gr->Rotate(50,60);	gr->Box();	gr->ContFX(c.Sum("x"),"",-1);
 	gr->ContFY(c.Sum("y"),"",1);	gr->ContFZ(c.Sum("z"),"",-1);
 }
 //-----------------------------------------------------------------------------
 const char *mmgl_cloud="call 'prepare3d'\nsubplot 2 2 0:title 'Cloud plot':rotate 50 60:alpha on:box:cloud c 'wyrRk'\n"
-"subplot 2 2 1:title '\"!\" style':rotate 50 60:box:cloud c '!wyrRk'\n"
+"subplot 2 2 1:title '\"i\" style':rotate 50 60:box:cloud c 'iwyrRk'\n"
 "subplot 2 2 2:title '\".\" style':rotate 50 60:box:cloud c '.wyrRk'\n"
 "subplot 2 2 3:title 'meshnum 10':rotate 50 60:box:cloud c 'wyrRk'; meshnum 10\n";
 void smgl_cloud(mglGraph *gr)
 {
 	mglData c;	mgls_prepare3d(&c);
-	if(!mini)	{	gr->SubPlot(2,2,0);	gr->Title("Cloud plot");	}
+	if(big!=3)	{	gr->SubPlot(2,2,0);	gr->Title("Cloud plot");	}
 	gr->Rotate(50,60);	gr->Alpha(true);
 	gr->Box();	gr->Cloud(c,"wyrRk");
-	if(mini)	return;
-	gr->SubPlot(2,2,1);	gr->Title("'!' style");
-	gr->Rotate(50,60);	gr->Box();	gr->Cloud(c,"!wyrRk");
+	if(big==3)	return;
+	gr->SubPlot(2,2,1);	gr->Title("'i' style");
+	gr->Rotate(50,60);	gr->Box();	gr->Cloud(c,"iwyrRk");
 	gr->SubPlot(2,2,2);	gr->Title("'.' style");
 	gr->Rotate(50,60);	gr->Box();	gr->Cloud(c,".wyrRk");
 	gr->SubPlot(2,2,3);	gr->Title("meshnum 10");
@@ -1373,9 +1538,9 @@ const char *mmgl_cont="call 'prepare2d'\nlist v -0.5 -0.15 0 0.15 0.5\nsubplot 2
 void smgl_cont(mglGraph *gr)
 {
 	mglData a,v(5);	mgls_prepare2d(&a);	v.a[0]=-0.5;	v.a[1]=-0.15;	v.a[2]=0;	v.a[3]=0.15;	v.a[4]=0.5;
-	if(!mini)	{	gr->SubPlot(2,2,0);	gr->Title("Cont plot (default)");	}
+	if(big!=3)	{	gr->SubPlot(2,2,0);	gr->Title("Cont plot (default)");	}
 	gr->Rotate(50,60);	gr->Box();	gr->Cont(a);
-	if(mini)	return;
+	if(big==3)	return;
 	gr->SubPlot(2,2,1);	gr->Title("manual levels");
 	gr->Rotate(50,60);	gr->Box();	gr->Cont(v,a);
 	gr->SubPlot(2,2,2);	gr->Title("'\\_' style");
@@ -1396,9 +1561,9 @@ void smgl_contf(mglGraph *gr)
 	v.a[1]=-0.15;	v.a[2]=0;	v.a[3]=0.15;	v.a[4]=0.5;
 	gr->Fill(a1,"0.6*sin(2*pi*x+pi*(z+1)/2)*sin(3*pi*y+pi*z) + 0.4*cos(3*pi*(x*y)+pi*(z+1)^2/2)");
 
-	if(!mini)	{	gr->SubPlot(2,2,0);	gr->Title("ContF plot (default)");	}
+	if(big!=3)	{	gr->SubPlot(2,2,0);	gr->Title("ContF plot (default)");	}
 	gr->Rotate(50,60);	gr->Box();	gr->ContF(a);
-	if(mini)	return;
+	if(big==3)	return;
 	gr->SubPlot(2,2,1);	gr->Title("manual levels");
 	gr->Rotate(50,60);	gr->Box();	gr->ContF(v,a);
 	gr->SubPlot(2,2,2);	gr->Title("'\\_' style");
@@ -1419,9 +1584,9 @@ void smgl_contd(mglGraph *gr)
 	v.a[1]=-0.15;	v.a[2]=0;	v.a[3]=0.15;	v.a[4]=0.5;
 	gr->Fill(a1,"0.6*sin(2*pi*x+pi*(z+1)/2)*sin(3*pi*y+pi*z) + 0.4*cos(3*pi*(x*y)+pi*(z+1)^2/2)");
 
-	if(!mini)	{	gr->SubPlot(2,2,0);	gr->Title("ContD plot (default)");	}
+	if(big!=3)	{	gr->SubPlot(2,2,0);	gr->Title("ContD plot (default)");	}
 	gr->Rotate(50,60);	gr->Box();	gr->ContD(a);
-	if(mini)	return;
+	if(big==3)	return;
 	gr->SubPlot(2,2,1);	gr->Title("manual levels");
 	gr->Rotate(50,60);	gr->Box();	gr->ContD(v,a);
 	gr->SubPlot(2,2,2);	gr->Title("'\\_' style");
@@ -1439,9 +1604,9 @@ void smgl_contv(mglGraph *gr)
 {
 	mglData a,v(5);	mgls_prepare2d(&a);	v.a[0]=-0.5;
 	v.a[1]=-0.15;	v.a[2]=0;	v.a[3]=0.15;	v.a[4]=0.5;
-	if(!mini)	{	gr->SubPlot(2,2,0);	gr->Title("ContV plot (default)");	}
+	if(big!=3)	{	gr->SubPlot(2,2,0);	gr->Title("ContV plot (default)");	}
 	gr->Rotate(50,60);	gr->Box();	gr->ContV(a);
-	if(mini)	return;
+	if(big==3)	return;
 	gr->SubPlot(2,2,1);	gr->Title("manual levels");
 	gr->Rotate(50,60);	gr->Box();	gr->ContV(v,a);
 	gr->SubPlot(2,2,2);	gr->Title("'\\_' style");
@@ -1458,9 +1623,9 @@ const char *mmgl_torus="call 'prepare1d'\nsubplot 2 2 0:title 'Torus plot (defau
 void smgl_torus(mglGraph *gr)
 {
 	mglData y1,y2;	mgls_prepare1d(0,&y1,&y2);
-	if(!mini)	{	gr->SubPlot(2,2,0);	gr->Title("Torus plot (default)");	}
+	if(big!=3)	{	gr->SubPlot(2,2,0);	gr->Title("Torus plot (default)");	}
 	gr->Light(true);	gr->Rotate(50,60);	gr->Box();	gr->Torus(y1,y2);
-	if(mini)	return;
+	if(big==3)	return;
 	gr->SubPlot(2,2,1);	gr->Title("'x' style");	gr->Rotate(50,60);	gr->Box();	gr->Torus(y1,y2,"x");
 	gr->SubPlot(2,2,2);	gr->Title("'z' style");	gr->Rotate(50,60);	gr->Box();	gr->Torus(y1,y2,"z");
 	gr->SubPlot(2,2,3);	gr->Title("'\\#' style");	gr->Rotate(50,60);	gr->Box();	gr->Torus(y1,y2,"#");
@@ -1473,9 +1638,9 @@ const char *mmgl_axial="call 'prepare2d'\nsubplot 2 2 0:title 'Axial plot (defau
 void smgl_axial(mglGraph *gr)
 {
 	mglData a;	mgls_prepare2d(&a);
-	if(!mini)	{	gr->SubPlot(2,2,0);	gr->Title("Axial plot (default)");	}
+	if(big!=3)	{	gr->SubPlot(2,2,0);	gr->Title("Axial plot (default)");	}
 	gr->Light(true);	gr->Alpha(true);	gr->Rotate(50,60);	gr->Box();	gr->Axial(a);
-	if(mini)	return;
+	if(big==3)	return;
 	gr->SubPlot(2,2,1);	gr->Title("'x' style; '.'style");	gr->Rotate(50,60);	gr->Box();	gr->Axial(a,"x.");
 	gr->SubPlot(2,2,2);	gr->Title("'z' style");	gr->Rotate(50,60);	gr->Box();	gr->Axial(a,"z");
 	gr->SubPlot(2,2,3);	gr->Title("'\\#' style");	gr->Rotate(50,60);	gr->Box();	gr->Axial(a,"#");
@@ -1486,12 +1651,43 @@ const char *mmgl_several_light="call 'prepare2d'\ntitle 'Several light sources':
 void smgl_several_light(mglGraph *gr)	// several light sources
 {
 	mglData a;	mgls_prepare2d(&a);
-	if(!mini)	gr->Title("Several light sources");
+	if(big!=3)	gr->Title("Several light sources");
 	gr->Rotate(50,60);	gr->Light(true);	gr->AddLight(1,mglPoint(0,1,0),'c');
 	gr->AddLight(2,mglPoint(1,0,0),'y');	gr->AddLight(3,mglPoint(0,-1,0),'m');
 	gr->Box();	gr->Surf(a,"h");
 }
 //-----------------------------------------------------------------------------
+const char *mmgl_light="light on:quality 6\ncall 'prepare2d'\n"
+"subplot 2 2 0:title 'Default':rotate 50 60:box:surf a\nline -1 -0.7 1.7 -1 -0.7 0.7 'BA'\n\n"
+"light 0 1 0 1 -2 -1 -1\nsubplot 2 2 1:title 'Local':rotate 50 60:box:surf a\n"
+"line 1 0 1 -1 -1 0 'BAO'\n\n"
+"diffuse 0\nsubplot 2 2 2:title 'no diffuse':rotate 50 60:box:surf a\n"
+"line 1 0 1 -1 -1 0 'BAO'\n\n"
+"diffuse 0.5:light 0 1 0 1 -2 -1 -1 'w' 0\n"
+"subplot 2 2 3:title 'diffusive only':rotate 50 60:box:surf a\n"
+"line 1 0 1 -1 -1 0 'BAO'\n";
+void smgl_light(mglGraph *gr)	// local light sources
+{
+	mglData a;	mgls_prepare2d(&a);
+	if(big==3)
+	{	gr->Light(true);	gr->Rotate(50,60);	gr->Box();	gr->Surf(a);	return;	}
+	int qual = gr->GetQuality();
+	gr->Light(true);	gr->SetQuality(6);
+	gr->SubPlot(2,2,0);	gr->Title("Default");	gr->Rotate(50,60);	gr->Box();	gr->Surf(a);
+	gr->Line(mglPoint(-1,-0.7,1.7),mglPoint(-1,-0.7,0.7),"BA");
+	gr->AddLight(0,mglPoint(1,0,1),mglPoint(-2,-1,-1));
+	gr->SubPlot(2,2,1);	gr->Title("Local");	gr->Rotate(50,60);	gr->Box();	gr->Surf(a);
+	gr->Line(mglPoint(1,0,1),mglPoint(-1,-1,0),"BAO");
+	gr->SetDiffuse(0);
+	gr->SubPlot(2,2,2);	gr->Title("no diffuse");	gr->Rotate(50,60);	gr->Box();	gr->Surf(a);
+	gr->Line(mglPoint(1,0,1),mglPoint(-1,-1,0),"BAO");
+	gr->SetDiffuse(0.5);
+	gr->AddLight(0,mglPoint(1,0,1),mglPoint(-2,-1,-1),'w',0);
+	gr->SubPlot(2,2,3);	gr->Title("diffusive only");	gr->Rotate(50,60);	gr->Box();	gr->Surf(a);
+	gr->Line(mglPoint(1,0,1),mglPoint(-1,-1,0),"BAO");
+	gr->SetQuality(qual);
+}
+//-----------------------------------------------------------------------------
 const char *mmgl_surf3="call 'prepare3d'\nlight on:alpha on\n"
 "subplot 2 2 0:title 'Surf3 plot (default)'\nrotate 50 60:box:surf3 c\n"
 "subplot 2 2 1:title '\"\\#\" style'\nrotate 50 60:box:surf3 c '#'\n"
@@ -1499,10 +1695,10 @@ const char *mmgl_surf3="call 'prepare3d'\nlight on:alpha on\n"
 void smgl_surf3(mglGraph *gr)
 {
 	mglData c;	mgls_prepare3d(&c);
-	if(!mini)	{	gr->SubPlot(2,2,0);	gr->Title("Surf3 plot (default)");	}
+	if(big!=3)	{	gr->SubPlot(2,2,0);	gr->Title("Surf3 plot (default)");	}
 	gr->Rotate(50,60);	gr->Light(true);	gr->Alpha(true);
 	gr->Box();	gr->Surf3(c);
-	if(mini)	return;
+	if(big==3)	return;
 	gr->SubPlot(2,2,1);	gr->Title("'\\#' style");
 	gr->Rotate(50,60);	gr->Box();	gr->Surf3(c,"#");
 	gr->SubPlot(2,2,2);	gr->Title("'.' style");
@@ -1513,7 +1709,7 @@ const char *mmgl_surf3a="call 'prepare3d'\ntitle 'Surf3A plot':rotate 50 60:ligh
 void smgl_surf3a(mglGraph *gr)
 {
 	mglData c,d;	mgls_prepare3d(&c,&d);
-	if(!mini)	gr->Title("Surf3A plot");
+	if(big!=3)	gr->Title("Surf3A plot");
 	gr->Rotate(50,60);	gr->Light(true);	gr->Alpha(true);
 	gr->Box();	gr->Surf3A(c,d);
 }
@@ -1522,7 +1718,7 @@ const char *mmgl_surf3c="call 'prepare3d'\ntitle 'Surf3C plot':rotate 50 60:ligh
 void smgl_surf3c(mglGraph *gr)
 {
 	mglData c,d;	mgls_prepare3d(&c,&d);
-	if(!mini)	gr->Title("Surf3C plot");
+	if(big!=3)	gr->Title("Surf3C plot");
 	gr->Rotate(50,60);	gr->Light(true);	gr->Alpha(true);
 	gr->Box();	gr->Surf3C(c,d);
 }
@@ -1551,7 +1747,7 @@ const char *mmgl_traj="call 'prepare1d'\nsubplot 1 1 0 '':title 'Traj plot':box:
 void smgl_traj(mglGraph *gr)
 {
 	mglData x,y,y1,y2;	mgls_prepare1d(&y,&y1,&y2,&x);
-	if(!mini)	{gr->SubPlot(1,1,0,"");	gr->Title("Traj plot");}
+	if(big!=3)	{gr->SubPlot(1,1,0,"");	gr->Title("Traj plot");}
 	gr->Box();	gr->Plot(x,y);	gr->Traj(x,y,y1,y2);
 }
 //-----------------------------------------------------------------------------
@@ -1559,7 +1755,7 @@ const char *mmgl_mesh="call 'prepare2d'\ntitle 'Mesh plot':rotate 50 60:box:mesh
 void smgl_mesh(mglGraph *gr)
 {
 	mglData a;	mgls_prepare2d(&a);
-	if(!mini)	gr->Title("Mesh plot");
+	if(big!=3)	gr->Title("Mesh plot");
 	gr->Rotate(50,60);	gr->Box();	gr->Mesh(a);
 }
 //-----------------------------------------------------------------------------
@@ -1567,7 +1763,7 @@ const char *mmgl_fall="call 'prepare2d'\ntitle 'Fall plot':rotate 50 60:box:fall
 void smgl_fall(mglGraph *gr)
 {
 	mglData a;	mgls_prepare2d(&a);
-	if(!mini)	gr->Title("Fall plot");
+	if(big!=3)	gr->Title("Fall plot");
 	gr->Rotate(50,60);	gr->Box();	gr->Fall(a);
 }
 //-----------------------------------------------------------------------------
@@ -1579,9 +1775,9 @@ const char *mmgl_surf="call 'prepare2d'\nsubplot 2 2 0:title 'Surf plot (default
 void smgl_surf(mglGraph *gr)
 {
 	mglData a;	mgls_prepare2d(&a);
-	if(!mini)	{	gr->SubPlot(2,2,0);	gr->Title("Surf plot (default)");	}
+	if(big!=3)	{	gr->SubPlot(2,2,0);	gr->Title("Surf plot (default)");	}
 	gr->Light(true);	gr->Rotate(50,60);	gr->Box();	gr->Surf(a);
-	if(mini)	return;
+	if(big==3)	return;
 	gr->SubPlot(2,2,1);	gr->Title("'\\#' style; meshnum 10");
 	gr->Rotate(50,60);	gr->Box();	gr->Surf(a,"#","meshnum 10");
 	gr->SubPlot(2,2,2);	gr->Title("'.' style");
@@ -1621,7 +1817,7 @@ const char *mmgl_belt="call 'prepare2d'\ntitle 'Belt plot':rotate 50 60:box:belt
 void smgl_belt(mglGraph *gr)
 {
 	mglData a;	mgls_prepare2d(&a);
-	if(!mini)	gr->Title("Belt plot");
+	if(big!=3)	gr->Title("Belt plot");
 	gr->Rotate(50,60);	gr->Box();	gr->Belt(a);
 }
 //-----------------------------------------------------------------------------
@@ -1634,9 +1830,9 @@ void smgl_dens(mglGraph *gr)
 {
 	mglData a,a1(30,40,3);	mgls_prepare2d(&a);
 	gr->Fill(a1,"0.6*sin(2*pi*x+pi*(z+1)/2)*sin(3*pi*y+pi*z) + 0.4*cos(3*pi*(x*y)+pi*(z+1)^2/2)");
-	if(!mini)	{gr->SubPlot(2,2,0,"");	gr->Title("Dens plot (default)");}
+	if(big!=3)	{gr->SubPlot(2,2,0,"");	gr->Title("Dens plot (default)");}
 	gr->Box();	gr->Dens(a);
-	if(mini)	return;
+	if(big==3)	return;
 	gr->SubPlot(2,2,1);	gr->Title("3d variant");
 	gr->Rotate(50,60);	gr->Box();	gr->Dens(a);
 	gr->SubPlot(2,2,2,"");	gr->Title("'\\#' style; meshnum 10");
@@ -1649,7 +1845,7 @@ const char *mmgl_surfc="call 'prepare2d'\ntitle 'SurfC plot':rotate 50 60:light
 void smgl_surfc(mglGraph *gr)
 {
 	mglData a,b;	mgls_prepare2d(&a,&b);
-	if(!mini)	gr->Title("SurfC plot");	gr->Rotate(50,60);
+	if(big!=3)	gr->Title("SurfC plot");	gr->Rotate(50,60);
 	gr->Light(true);	gr->Box();	gr->SurfC(a,b);
 }
 //-----------------------------------------------------------------------------
@@ -1657,7 +1853,7 @@ const char *mmgl_surfa="call 'prepare2d'\ntitle 'SurfA plot':rotate 50 60:light
 void smgl_surfa(mglGraph *gr)
 {
 	mglData a,b;	mgls_prepare2d(&a,&b);
-	if(!mini)	gr->Title("SurfA plot");	gr->Rotate(50,60);
+	if(big!=3)	gr->Title("SurfA plot");	gr->Rotate(50,60);
 	gr->Alpha(true);	gr->Light(true);	gr->Box();	gr->SurfA(a,b);
 }
 //-----------------------------------------------------------------------------
@@ -1665,7 +1861,7 @@ const char *mmgl_tile="call 'prepare2d'\ntitle 'Tile plot':rotate 50 60:box:tile
 void smgl_tile(mglGraph *gr)
 {
 	mglData a;	mgls_prepare2d(&a);
-	if(!mini)	gr->Title("Tile plot");
+	if(big!=3)	gr->Title("Tile plot");
 	gr->Rotate(40,60);	gr->Box();	gr->Tile(a);
 }
 //-----------------------------------------------------------------------------
@@ -1673,7 +1869,7 @@ const char *mmgl_tiles="call 'prepare2d'\nsubplot 1 1 0 '':title 'Tiles plot':bo
 void smgl_tiles(mglGraph *gr)
 {
 	mglData a,b;	mgls_prepare2d(&a,&b);
-	if(!mini)	{gr->SubPlot(1,1,0,"");	gr->Title("TileS plot");}
+	if(big!=3)	{gr->SubPlot(1,1,0,"");	gr->Title("TileS plot");}
 	gr->Box();	gr->TileS(a,b);
 }
 //-----------------------------------------------------------------------------
@@ -1685,9 +1881,9 @@ void smgl_boxs(mglGraph *gr)
 {
 	mglData a;	mgls_prepare2d(&a);
 	gr->SetOrigin(0,0,0);	gr->Light(true);
-	if(!mini)	{gr->SubPlot(2,2,0);	gr->Title("Boxs plot (default)");}
+	if(big!=3)	{gr->SubPlot(2,2,0);	gr->Title("Boxs plot (default)");}
 	gr->Rotate(40,60);	gr->Box();	gr->Boxs(a);
-	if(mini)	return;
+	if(big==3)	return;
 	gr->SubPlot(2,2,1);	gr->Title("'\\@' style");
 	gr->Rotate(50,60);	gr->Box();	gr->Boxs(a,"@");
 	gr->SubPlot(2,2,2);	gr->Title("'\\#' style");
@@ -1709,7 +1905,7 @@ void smgl_fit(mglGraph *gr)	// nonlinear fitting
 	double ini[3] = {1,1,3};
 	mglData Ini(3,ini);
 	res = gr->Fit(rnd, "a+b*sin(c*x)", "abc", Ini);
-	if(!mini)	gr->Title("Fitting sample");
+	if(big!=3)	gr->Title("Fitting sample");
 	gr->SetRange('y',-2,2);	gr->Box();	gr->Plot(rnd, ". ");
 	gr->Axis();		gr->Plot(res, "r");	gr->Plot(in, "b");
 	gr->Puts(mglPoint(-0.9, -1.3), "fitted:", "r:L");
@@ -1726,10 +1922,10 @@ const char *mmgl_vecta="call 'prepare3v'\nsubplot 2 1 0:title 'Vect3 sample':rot
 void smgl_vecta(mglGraph *gr)
 {
 	mglData ex,ey,ez;	mgls_prepare3v(&ex,&ey,&ez);
-	if(!mini)	{	gr->SubPlot(2,1,0);	gr->Title("Vect3 sample");	}
+	if(big!=3)	{	gr->SubPlot(2,1,0);	gr->Title("Vect3 sample");	}
 	gr->Rotate(50,60);	gr->SetOrigin(0,0,0);	gr->Axis("_xyz");	gr->Box();
 	gr->Vect3(ex,ey,ez,"x");	gr->Vect3(ex,ey,ez);	gr->Vect3(ex,ey,ez,"z");
-	if(mini)	return;
+	if(big==3)	return;
 	gr->SubPlot(2,1,1);	gr->Title("'f' style");
 	gr->Rotate(50,60);	gr->SetOrigin(0,0,0);	gr->Axis("_xyz");	gr->Box();
 	gr->Vect3(ex,ey,ez,"fx");	gr->Vect3(ex,ey,ez,"f");	gr->Vect3(ex,ey,ez,"fz");
@@ -1745,9 +1941,9 @@ const char *mmgl_vect="call 'prepare2v'\ncall 'prepare3v'\nsubplot 3 2 0 '':titl
 void smgl_vect(mglGraph *gr)
 {
 	mglData a,b;	mgls_prepare2v(&a,&b);
-	if(!mini)	{gr->SubPlot(3,2,0,"");	gr->Title("Vect plot (default)");}
+	if(big!=3)	{gr->SubPlot(3,2,0,"");	gr->Title("Vect plot (default)");}
 	gr->Box();	gr->Vect(a,b);
-	if(mini)	return;
+	if(big==3)	return;
 	gr->SubPlot(3,2,1,"");	gr->Title("'.' style; '=' style");	gr->Box();	gr->Vect(a,b,"=.");
 	gr->SubPlot(3,2,2,"");	gr->Title("'f' style");	gr->Box();	gr->Vect(a,b,"f");
 	gr->SubPlot(3,2,3,"");	gr->Title("'>' style");	gr->Box();	gr->Vect(a,b,">");
@@ -1764,9 +1960,9 @@ const char *mmgl_flow="call 'prepare2v'\ncall 'prepare3v'\nsubplot 2 2 0 '':titl
 void smgl_flow(mglGraph *gr)
 {
 	mglData a,b;	mgls_prepare2v(&a,&b);
-	if(!mini)	{gr->SubPlot(2,2,0,"");	gr->Title("Flow plot (default)");}
+	if(big!=3)	{gr->SubPlot(2,2,0,"");	gr->Title("Flow plot (default)");}
 	gr->Box();	gr->Flow(a,b);
-	if(mini)	return;
+	if(big==3)	return;
 	gr->SubPlot(2,2,1,"");	gr->Title("'v' style");	gr->Box();	gr->Flow(a,b,"v");
 	gr->SubPlot(2,2,2,"");	gr->Title("'\\#' style");	gr->Box();	gr->Flow(a,b,"#");
 	mglData ex,ey,ez;	mgls_prepare3v(&ex,&ey,&ez);
@@ -1781,9 +1977,9 @@ const char *mmgl_pipe="call 'prepare2v'\ncall 'prepare3v'\nsubplot 2 2 0 '':titl
 void smgl_pipe(mglGraph *gr)
 {
 	mglData a,b;	mgls_prepare2v(&a,&b);
-	if(!mini)	{gr->SubPlot(2,2,0,"");	gr->Title("Pipe plot (default)");}
+	if(big!=3)	{gr->SubPlot(2,2,0,"");	gr->Title("Pipe plot (default)");}
 	gr->Light(true);	gr->Box();	gr->Pipe(a,b);
-	if(mini)	return;
+	if(big==3)	return;
 	gr->SubPlot(2,2,1,"");	gr->Title("'i' style");	gr->Box();	gr->Pipe(a,b,"i");
 	gr->SubPlot(2,2,2,"");	gr->Title("'\\#' style");	gr->Box();	gr->Pipe(a,b,"#");
 	mglData ex,ey,ez;	mgls_prepare3v(&ex,&ey,&ez);
@@ -1795,7 +1991,7 @@ const char *mmgl_dew="call 'prepare2v'\nsubplot 1 1 0 '':title 'Dew plot':light
 void smgl_dew(mglGraph *gr)
 {
 	mglData a,b;	mgls_prepare2v(&a,&b);
-	if(!mini)	{gr->SubPlot(1,1,0,"");	gr->Title("Dew plot");}
+	if(big!=3)	{gr->SubPlot(1,1,0,"");	gr->Title("Dew plot");}
 	gr->Box();	gr->Light(true);	gr->Dew(a,b);
 }
 //-----------------------------------------------------------------------------
@@ -1803,29 +1999,35 @@ const char *mmgl_grad="call 'prepare2d'\nsubplot 1 1 0 '':title 'Grad plot':box:
 void smgl_grad(mglGraph *gr)
 {
 	mglData a;	mgls_prepare2d(&a);
-	if(!mini)	{gr->SubPlot(1,1,0,"");	gr->Title("Grad plot");}
+	if(big!=3)	{gr->SubPlot(1,1,0,"");	gr->Title("Grad plot");}
 	gr->Box();	gr->Grad(a);	gr->Dens(a,"{u8}w{q8}");
 }
 //-----------------------------------------------------------------------------
-const char *mmgl_cones="new ys 10 3 '0.8*sin(pi*(x+y/4+1.25))+0.2*rnd'\n"
-"subplot 2 2 0:title 'Cones plot':rotate 50 60:light on:origin 0 0 0:box:cones ys\n"
-"subplot 2 2 1:title '2 colors':rotate 50 60:light on:origin 0 0 0:box:cones ys 'cbgGyr'\n"
-"subplot 2 2 2:title '\"\\#\" style':rotate 50 60:light on:origin 0 0 0:box:cones ys '#'\n"
-"subplot 2 2 3:title '\"a\" style':rotate 50 60:zrange -2 2:light on:origin 0 0 0:box:cones ys 'a'\n";
+const char *mmgl_cones="new ys 10 3 '0.8*sin(pi*(x+y/4+1.25))+0.2*rnd'\nlight on:origin 0 0 0\n"
+"subplot 3 2 0:title 'Cones plot':rotate 50 60:box:cones ys\n"
+"subplot 3 2 1:title '2 colors':rotate 50 60:box:cones ys 'cbgGyr'\n"
+"subplot 3 2 2:title '\"\\#\" style':rotate 50 60:box:cones ys '#'\n"
+"subplot 3 2 3:title '\"a\" style':rotate 50 60:zrange -2 2:box:cones ys 'a'\n"
+"subplot 3 2 4:title '\"t\" style':rotate 50 60:box:cones ys 't'\n"
+"subplot 3 2 5:title '\"4\" style':rotate 50 60:box:cones ys '4'\n";
 void smgl_cones(mglGraph *gr)
 {
 	mglData ys(10,3);	ys.Modify("0.8*sin(pi*(2*x+y/2))+0.2*rnd");
 	gr->Light(true);	gr->SetOrigin(0,0,0);
-	if(!mini)	{	gr->SubPlot(2,2,0);	gr->Title("Cones plot");	}
+	if(big!=3)	{	gr->SubPlot(3,2,0);	gr->Title("Cones plot");	}
 	gr->Rotate(50,60);	gr->Box();	gr->Cones(ys);
-	if(mini)	return;
-	gr->SubPlot(2,2,1);	gr->Title("2 colors");
+	if(big==3)	return;
+	gr->SubPlot(3,2,1);	gr->Title("2 colors");
 	gr->Rotate(50,60);	gr->Box();	gr->Cones(ys,"cbgGyr");
-	gr->SubPlot(2,2,2);	gr->Title("'\\#' style");
+	gr->SubPlot(3,2,2);	gr->Title("'\\#' style");
 	gr->Rotate(50,60);	gr->Box();	gr->Cones(ys,"#");
-	gr->SubPlot(2,2,3);	gr->Title("'a' style");
+	gr->SubPlot(3,2,3);	gr->Title("'a' style");
 	gr->SetRange('z',-2,2);	// increase range since summation can exceed [-1,1]
 	gr->Rotate(50,60);	gr->Box();	gr->Cones(ys,"a");
+	gr->SubPlot(3,2,4);	gr->Title("'t' style");
+	gr->Rotate(50,60);	gr->Box();	gr->Cones(ys,"t");
+	gr->SubPlot(3,2,5);	gr->Title("'4' style");
+	gr->Rotate(50,60);	gr->Box();	gr->Cones(ys,"4");
 }
 //-----------------------------------------------------------------------------
 const char *mmgl_aspect="subplot 2 2 0:box:text -1 1.1 'Just box' ':L'\ninplot 0.2 0.5 0.7 1 off:box:text 0 1.2 'InPlot example'\n"
@@ -1994,12 +2196,13 @@ void smgl_loglog(mglGraph *gr)	// log-log axis
 }
 //-----------------------------------------------------------------------------
 const char *mmgl_venn="list x -0.3 0 0.3:list y 0.3 -0.3 0.3:list e 0.7 0.7 0.7\n"
-"subplot 1 1 0:title 'Venn-like diagram':alpha on:error x y e e '!rgb@#o'";
+"subplot 1 1 0:title 'Venn-like diagram'\ntransptype 1:alpha on:error x y e e '!rgb@#o'";
 void smgl_venn(mglGraph *gr)
 {
 	double xx[3]={-0.3,0,0.3}, yy[3]={0.3,-0.3,0.3}, ee[3]={0.7,0.7,0.7};
 	mglData x(3,xx), y(3,yy), e(3,ee);
-	gr->SubPlot(1,1,0);	gr->Title("Venn-like diagram");	gr->Alpha(true);	gr->Error(x,y,e,e,"!rgb@#o");
+	gr->SubPlot(1,1,0);	gr->Title("Venn-like diagram");
+	gr->SetTranspType(1);	gr->Alpha(true);	gr->Error(x,y,e,e,"!rgb@#o","alpha 0.1");
 }
 //-----------------------------------------------------------------------------
 const char *mmgl_stereo="call 'prepare2d'\nlight on\nsubplot 2 1 0:rotate 50 60+1:box:surf a\nsubplot 2 1 1:rotate 50 60-1:box:surf a\n";
@@ -2083,7 +2286,7 @@ void smgl_primitives(mglGraph *gr)	// flag #
 	gr->Puts(mglPoint(0.9,1),"sh=1");			gr->Ball(mglPoint(0.9,0,1),'k');
 	gr->Drop(mglPoint(0.9,0),mglPoint(0,1),0.5,"r",1);
 	gr->Line(mglPoint(-0.9,0,1),mglPoint(0.9,0,1),"b");
-	
+
 	gr->Puts(mglPoint(-0.9,-1.1),"asp=0.33");
 	gr->Drop(mglPoint(-0.9,-0.7),mglPoint(0,1),0.5,"b",0,0.33);
 	gr->Puts(mglPoint(-0.3,-1.1),"asp=0.67");
@@ -2103,9 +2306,9 @@ const char *mmgl_table="new ys 10 3 '0.8*sin(pi*(x+y/4+1.25))+0.2*rnd'\n"
 void smgl_table(mglGraph *gr)
 {
 	mglData ys(10,3);	ys.Modify("0.8*sin(pi*(2*x+y/2))+0.2*rnd");
-	if(!mini)	{	gr->SubPlot(2,2,0);	gr->Title("Table plot");	}
+	if(big!=3)	{	gr->SubPlot(2,2,0);	gr->Title("Table plot");	}
 	gr->Table(ys,"y_1\ny_2\ny_3");	gr->Box();
-	if(mini)	return;
+	if(big==3)	return;
 	gr->SubPlot(2,2,1);	gr->Title("no borders, colored");
 	gr->Table(ys,"y_1\ny_2\ny_3","r|");
 	gr->SubPlot(2,2,2);	gr->Title("no font decrease");
@@ -2119,7 +2322,7 @@ const char *mmgl_label="new ys 10 '0.2*rnd-0.8*sin(pi*x)'\n"
 void smgl_label(mglGraph *gr)
 {
 	mglData ys(10);	ys.Modify("0.8*sin(pi*2*x)+0.2*rnd");
-	if(!mini)	{	gr->SubPlot(1,1,0,"");	gr->Title("Label plot");	}
+	if(big!=3)	{	gr->SubPlot(1,1,0,"");	gr->Title("Label plot");	}
 	gr->Box();	gr->Plot(ys," *");	gr->Label(ys,"y=%y");
 }
 //-----------------------------------------------------------------------------
@@ -2143,12 +2346,12 @@ void smgl_colorbar(mglGraph *gr)
 	mglData a,v;	mgls_prepare2d(&a,0,&v);
 	gr->Box();	gr->ContD(v,a);
 	gr->Colorbar(v,"<");	gr->Colorbar(v,">");	gr->Colorbar(v,"_");	gr->Colorbar(v,"^");
-	
+
 	gr->SubPlot(2,2,3);	gr->Title(" ");
 	gr->Puts(mglPoint(-0.5,1.55),"Color positions",":C",-2);
 	gr->Colorbar("bwr>",0.25,0);	gr->Puts(mglPoint(-0.9,1.2),"Default");
 	gr->Colorbar("b{w,0.3}r>",0.5,0);	gr->Puts(mglPoint(-0.1,1.2),"Manual");
-	
+
 	gr->Puts(mglPoint(1,1.55),"log-scale",":C",-2);
 	gr->SetRange('c',0.01,1e3);
 	gr->Colorbar(">",0.75,0);	gr->Puts(mglPoint(0.65,1.2),"Normal scale");
@@ -2171,9 +2374,9 @@ void smgl_legend(mglGraph *gr)
 	gr->AddLegend("sin(\\pi \\sqrt{x})","rd");
 	gr->AddLegend("just text"," ");
 	gr->AddLegend("no indent for this","");
-	if(!mini)	{gr->SubPlot(2,2,0,"");	gr->Title("Legend (default)");}
+	if(big!=3)	{gr->SubPlot(2,2,0,"");	gr->Title("Legend (default)");}
 	gr->Box();	gr->Legend();
-	if(mini)	return;
+	if(big==3)	return;
 	gr->Legend(3,"A#");
 	gr->Puts(mglPoint(0.75,0.65),"Absolute position","A");
 	gr->SubPlot(2,2,2,"");	gr->Title("coloring");	gr->Box();
@@ -2314,8 +2517,8 @@ void smgl_projection(mglGraph *gr)	// flag #
 	y.Modify("0.25*(1+sin(2*pi*x))");
 	rx.Modify("rnd"); ry.Modify("(1-v)*rnd",rx);
 	z.Modify("x");
-	
-	if(!mini)	gr->Title("Projection sample");
+
+	if(big!=3)	gr->Title("Projection sample");
 	gr->Ternary(4);
 	gr->Rotate(50,60);		gr->Light(true);
 	gr->Plot(x,y,z,"r2");	gr->Surf(a,"#");
@@ -2337,8 +2540,8 @@ void smgl_projection5(mglGraph *gr)	// flag #
 	y.Modify("0.25*(1+sin(2*pi*x))");
 	rx.Modify("rnd"); ry.Modify("(1-v)*rnd",rx);
 	z.Modify("x");
-	
-	if(!mini)	gr->Title("Projection sample (ternary)");
+
+	if(big!=3)	gr->Title("Projection sample (ternary)");
 	gr->Ternary(5);
 	gr->Rotate(50,60);		gr->Light(true);
 	gr->Plot(x,y,z,"r2");	gr->Surf(a,"#");
@@ -2370,7 +2573,7 @@ void smgl_triplot(mglGraph *gr)
 	gr->SubPlot(2,2,2);	gr->Title("QuadPlot coloring");	gr->Rotate(50,60);
 	gr->QuadPlot(qq,xx,yy,zz,yy,"yr");
 	gr->QuadPlot(qq,xx,yy,zz,"k#");
-	
+
 	double t[] = {0,1,2, 0,1,3, 0,2,3, 1,2,3};
 	double xt[] = {-1,1,0,0}, yt[] = {-1,-1,1,0}, zt[] = {-1,-1,-1,1};
 	mglData tt(4,3,t), uu(4,xt), vv(4,yt), ww(4,zt);
@@ -2397,7 +2600,7 @@ void smgl_dots(mglGraph *gr)
 		y.a[i] = 0.9*cos(t)*sin(f);
 		z.a[i] = 0.6*sin(t);
 	}
-	if(!mini)	gr->Title("Dots sample");
+	if(big!=3)	gr->Title("Dots sample");
 	gr->Rotate(50,60);	gr->Box();	gr->Dots(x,y,z);
 }
 //-----------------------------------------------------------------------------
@@ -2422,12 +2625,12 @@ void smgl_mirror(mglGraph *gr)	// flag #
 {
 	mglData a(31,41);
 	gr->Fill(a,"-pi*x*exp(-(y+1)^2-4*x^2)");
-	
-	if(!mini)	{	gr->SubPlot(2,2,0);	gr->Title("Options for coordinates");	}
+
+	if(big!=3)	{	gr->SubPlot(2,2,0);	gr->Title("Options for coordinates");	}
 	gr->Alpha(true);	gr->Light(true);
 	gr->Rotate(40,60);	gr->Box();
 	gr->Surf(a,"r","yrange 0 1"); gr->Surf(a,"b","yrange 0 -1");
-	if(mini)	return;
+	if(big==3)	return;
 	gr->SubPlot(2,2,1);	gr->Title("Option 'meshnum'");
 	gr->Rotate(40,60);	gr->Box();
 	gr->Mesh(a,"r","yrange 0 1"); gr->Mesh(a,"b","yrange 0 -1; meshnum 5");
@@ -2465,6 +2668,7 @@ mglSample samp[] = {
 	{"contf_xyz", smgl_contf_xyz, mmgl_contf_xyz},
 	{"contfa", smgl_contfa, mmgl_contfa},
 	{"contv", smgl_contv, mmgl_contv},
+	{"correl", smgl_correl, mmgl_correl},
 //	{"crust", smgl_crust, mmgl_crust},	// TODO: open after triangulation
 	{"curvcoor", smgl_curvcoor, mmgl_curvcoor},
 	{"cut", smgl_cut, mmgl_cut},
@@ -2477,7 +2681,9 @@ mglSample samp[] = {
 	{"densa", smgl_densa, mmgl_densa},
 	{"dew", smgl_dew, mmgl_dew},
 	{"dots", smgl_dots, mmgl_dots},
-	{"error", smgl_error, mmgl_error },
+	{"error", smgl_error, mmgl_error},
+	{"error2", smgl_error2, mmgl_error2},
+	{"export", smgl_export, mmgl_export},
 	{"fall", smgl_fall, mmgl_fall},
 	{"fexport", smgl_fexport, mmgl_fexport},
 	{"fit", smgl_fit, mmgl_fit},
@@ -2489,12 +2695,15 @@ mglSample samp[] = {
 	{"inplot", smgl_inplot, mmgl_inplot},
 	{"label", smgl_label, mmgl_label},
 	{"legend", smgl_legend, mmgl_legend },
+	{"light", smgl_light, mmgl_light},
 	{"loglog", smgl_loglog, mmgl_loglog},
 	{"map", smgl_map, mmgl_map},
 	{"mark", smgl_mark, mmgl_mark},
+	{"mask", smgl_mask, mmgl_mask},
 	{"mesh", smgl_mesh, mmgl_mesh},
 	{"mirror", smgl_mirror, mmgl_mirror },
 	{"molecule", smgl_molecule, mmgl_molecule },
+	{"ohlc", smgl_ohlc, mmgl_ohlc},
 	{"param1", smgl_param1, mmgl_param1},
 	{"param2", smgl_param2, mmgl_param2},
 	{"param3", smgl_param3, mmgl_param3},
@@ -2508,6 +2717,7 @@ mglSample samp[] = {
 	{"projection5", smgl_projection5, mmgl_projection5 },
 	{"qo2d", smgl_qo2d, mmgl_qo2d},
 	{"radar", smgl_radar, mmgl_radar},
+	{"refill", smgl_refill, mmgl_refill},
 	{"region", smgl_region, mmgl_region},
 	{"schemes", smgl_schemes, mmgl_schemes },
 	{"several_light", smgl_several_light, mmgl_several_light },
@@ -2528,6 +2738,7 @@ mglSample samp[] = {
 	{"tens", smgl_tens, mmgl_tens},
 	{"ternary", smgl_ternary, mmgl_ternary },
 	{"text", smgl_text, mmgl_text},
+	{"text2", smgl_text2, mmgl_text2},
 	{"textmark", smgl_textmark, mmgl_textmark},
 	{"ticks", smgl_ticks, mmgl_ticks},
 	{"tile", smgl_tile, mmgl_tile},
diff --git a/examples/wnd_samples.cpp b/examples/wnd_samples.cpp
index 865875d..501a1f1 100644
--- a/examples/wnd_samples.cpp
+++ b/examples/wnd_samples.cpp
@@ -49,7 +49,7 @@ mgl_set_test_mode(true);
 	gr->ShowFrame(1);
 	gr->ShowFrame(2);
 	gr->ShowFrame(3);
-	//	gr->Puts(mglPoint(0,1),"1");
+//	gr->Puts(mglPoint(0,1),"1");
 	gr->Finish();
 	return 0;
 }
@@ -427,14 +427,14 @@ int sample_d(mglGraph *gr)
 //-----------------------------------------------------------------------------
 void mgls_prepare1d(mglData *y, mglData *y1, mglData *y2, mglData *x1, mglData *x2)
 {
-	register long i,n=50;
+	long n=50;
 	if(y)	y->Create(n,3);
 	if(x1)	x1->Create(n);		if(x2)	x2->Create(n);
 	if(y1)	y1->Create(n);		if(y2)	y2->Create(n);
-	double xx;
-	for(i=0;i<n;i++)
+#pragma omp parallel for
+	for(long i=0;i<n;i++)
 	{
-		xx = i/(n-1.);
+		double xx = i/(n-1.);
 		if(y)
 		{
 			y->a[i] = 0.7*sin(2*M_PI*xx) + 0.5*cos(3*M_PI*xx) + 0.2*sin(M_PI*xx);
@@ -450,13 +450,14 @@ void mgls_prepare1d(mglData *y, mglData *y1, mglData *y2, mglData *x1, mglData *
 //-----------------------------------------------------------------------------
 void mgls_prepare2d(mglData *a, mglData *b, mglData *v)
 {
-	register long i,j,n=50,m=40,i0;
+	long n=50,m=40;
 	if(a)	a->Create(n,m);		if(b)	b->Create(n,m);
 	if(v)	{	v->Create(9);	v->Fill(-1,1);	}
-	double x,y;
-	for(i=0;i<n;i++)	for(j=0;j<m;j++)
+#pragma omp parallel for collapse(2)
+	for(long j=0;j<m;j++)	for(long i=0;i<n;i++)
 	{
-		x = i/(n-1.);	y = j/(m-1.);	i0 = i+n*j;
+		double x = i/(n-1.), y = j/(m-1.);
+		register long i0 = i+n*j;
 		if(a)	a->a[i0] = 0.6*sin(2*M_PI*x)*sin(3*M_PI*y)+0.4*cos(3*M_PI*x*y);
 		if(b)	b->a[i0] = 0.6*cos(2*M_PI*x)*cos(3*M_PI*y)+0.4*cos(3*M_PI*x*y);
 	}
@@ -464,12 +465,13 @@ void mgls_prepare2d(mglData *a, mglData *b, mglData *v)
 //-----------------------------------------------------------------------------
 void mgls_prepare3d(mglData *a, mglData *b)
 {
-	register long i,j,k,n=61,m=50,l=40,i0;
+	long n=61,m=50,l=40;
 	if(a)	a->Create(n,m,l);		if(b)	b->Create(n,m,l);
-	double x,y,z;
-	for(i=0;i<n;i++)	for(j=0;j<m;j++)	for(k=0;k<l;k++)
+#pragma omp parallel for collapse(3)
+	for(long k=0;k<l;k++)	for(long j=0;j<m;j++)	for(long i=0;i<n;i++)
 	{
-		x=2*i/(n-1.)-1;	y=2*j/(m-1.)-1;	z=2*k/(l-1.)-1;	i0 = i+n*(j+m*k);
+		double x=2*i/(n-1.)-1, y=2*j/(m-1.)-1, z=2*k/(l-1.)-1;
+		register long i0 = i+n*(j+m*k);
 		if(a)	a->a[i0] = -2*(x*x + y*y + z*z*z*z - z*z - 0.1);
 		if(b)	b->a[i0] = 1-2*tanh((x+y)*(x+y));
 	}
@@ -477,12 +479,13 @@ void mgls_prepare3d(mglData *a, mglData *b)
 //-----------------------------------------------------------------------------
 void mgls_prepare2v(mglData *a, mglData *b)
 {
-	register long i,j,n=20,m=30,i0;
+	long n=20,m=30;
 	if(a)	a->Create(n,m);		if(b)	b->Create(n,m);
-	double x,y;
-	for(i=0;i<n;i++)	for(j=0;j<m;j++)
+#pragma omp parallel for collapse(2)
+	for(long j=0;j<m;j++)	for(long i=0;i<n;i++)
 	{
-		x=i/(n-1.);	y=j/(m-1.);	i0 = i+n*j;
+		double x=i/(n-1.), y=j/(m-1.);
+		register long i0 = i+n*j;
 		if(a)	a->a[i0] = 0.6*sin(2*M_PI*x)*sin(3*M_PI*y)+0.4*cos(3*M_PI*x*y);
 		if(b)	b->a[i0] = 0.6*cos(2*M_PI*x)*cos(3*M_PI*y)+0.4*cos(3*M_PI*x*y);
 	}
@@ -490,13 +493,14 @@ void mgls_prepare2v(mglData *a, mglData *b)
 //-----------------------------------------------------------------------------
 void mgls_prepare3v(mglData *ex, mglData *ey, mglData *ez)
 {
-	register long i,j,k,n=10,i0;
+	long n=10;
 	if(!ex || !ey || !ez)	return;
 	ex->Create(n,n,n);	ey->Create(n,n,n);	ez->Create(n,n,n);
-	double x,y,z, r1,r2;
-	for(i=0;i<n;i++)	for(j=0;j<n;j++)	for(k=0;k<n;k++)
+#pragma omp parallel for collapse(3)
+	for(long k=0;k<n;k++)	for(long j=0;j<n;j++)	for(long i=0;i<n;i++)
 	{
-		x=2*i/(n-1.)-1;	y=2*j/(n-1.)-1;	z=2*k/(n-1.)-1;	i0 = i+n*(j+k*n);
+		double x=2*i/(n-1.)-1, y=2*j/(n-1.)-1, z=2*k/(n-1.)-1;
+		register long i0 = i+n*(j+k*n);
 /* 		r1 = 1./(x*x+y*y+z*z+0.01);	r2=exp(-0.01/r1/r1)*r1;
  		ex->a[i0]=z*y*r2*r2;
  		ey->a[i0]=x*y*r2*r2+1;
@@ -504,8 +508,8 @@ void mgls_prepare3v(mglData *ex, mglData *ey, mglData *ez)
 /*		ex->a[i0]=3*z;
 		ey->a[i0]=1;
 		ez->a[i0]=-3*x;*/
-		r1 = pow(x*x+y*y+(z-0.3)*(z-0.3)+0.03,1.5);
-		r2 = pow(x*x+y*y+(z+0.3)*(z+0.3)+0.03,1.5);
+		double r1 = pow(x*x+y*y+(z-0.3)*(z-0.3)+0.03,1.5);
+		double r2 = pow(x*x+y*y+(z+0.3)*(z+0.3)+0.03,1.5);
 		ex->a[i0]=0.2*x/r1 - 0.2*x/r2;
 		ey->a[i0]=0.2*y/r1 - 0.2*y/r2;
 		ez->a[i0]=0.2*(z-0.3)/r1 - 0.2*(z+0.3)/r2;
diff --git a/examples/wx_example.cpp b/examples/wx_example.cpp
index c7a8685..e440b3b 100644
--- a/examples/wx_example.cpp
+++ b/examples/wx_example.cpp
@@ -17,61 +17,64 @@
  *   Free Software Foundation, Inc.,                                       *
  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
  ***************************************************************************/
+#include <wx/wx.h>
 #include "mgl2/wx.h"
 //-----------------------------------------------------------------------------
-#ifdef ENABLE_MGLGRAPHWX
-int test(mglGraph *gr, void *);
-int sample(mglGraph *gr, void *);
-int sample_1(mglGraph *gr, void *);
-int sample_2(mglGraph *gr, void *);
-int sample_3(mglGraph *gr, void *);
-int sample_d(mglGraph *gr, void *);
+int test_wnd(mglGraph *gr);
+int sample(mglGraph *gr);
+int sample_1(mglGraph *gr);
+int sample_2(mglGraph *gr);
+int sample_3(mglGraph *gr);
+int sample_d(mglGraph *gr);
 //-----------------------------------------------------------------------------
-//#define PTHREAD_SAMPLE
-#ifdef PTHREAD_SAMPLE
-#include <pthread.h>
-#endif
-mglPoint pnt;  // some global variable for changable data
-void *mgl_wx_tmp(void *)	{	mglWxRun();	return 0;	}
+class testApp : public wxApp
+{
+public:
+	virtual bool OnInit();
+};
+//-----------------------------------------------------------------------------
+class testFrame: public wxFrame
+{
+public:
+	testFrame(wxFrame *frame, const wxString& title);
+	~testFrame() {}
+private:
+	enum	{	idMenuQuit = 1000	};
+	void OnClose(wxCloseEvent& event)	{	Destroy();	}
+	void OnQuit(wxCommandEvent& event)	{	Destroy();	}
+
+	wxScrolledWindow *scroll;
+	wxMathGL *mgl;
+	DECLARE_EVENT_TABLE()
+};
+//-----------------------------------------------------------------------------
+IMPLEMENT_APP(testApp);
+//-----------------------------------------------------------------------------
+bool testApp::OnInit()
+{
+	testFrame* frame = new testFrame(0L, _("MathGL + wxWidgets sample"));
+	frame->Show();
+	return true;
+}
+//-----------------------------------------------------------------------------
+BEGIN_EVENT_TABLE(testFrame, wxFrame)
+	EVT_CLOSE(testFrame::OnClose)
+	EVT_MENU(idMenuQuit, testFrame::OnQuit)
+END_EVENT_TABLE()
 //-----------------------------------------------------------------------------
-int main(int argc,char **argv)
+testFrame::testFrame(wxFrame *frame, const wxString& title) : wxFrame(frame, -1, title)
 {
-#ifdef PTHREAD_SAMPLE
-	mglGraphWX gr;
-	gr.Window(argc,argv,NULL,"test",0,0);  // create window
-	gr.ClfOnUpdate = false;
-	static pthread_t tmp;
-	pthread_create(&tmp, 0, mgl_qt_tmp, 0);
-	pthread_detach(tmp);    // run window handling in the separate thread
-	for(int i=0;i<10;i++)   // do calculation
-	{
-		sleep(2);             // which can be very long
-		pnt = mglPoint(2*mgl_rnd()-1,2*mgl_rnd()-1);
-		gr.Clf();             // make new drawing
-		gr.Line(mglPoint(),pnt,"Ar2");
-		char str[10] = "i=0";	str[3] = '0'+i;
-		gr.Text(mglPoint(),"");
-		gr.Update();       // update window
-	}
-	return 0;   // finish calculations and close the window
-#else
-	mglGraphWX gr;
-	char key = 0;
-	if(argc>1 && argv[1][0]!='-')	key = argv[1][0];
-	else	printf("You may specify argument '1', '2', '3' or 'd' for viewing examples of 1d, 2d, 3d or dual plotting\n");
-	switch(key)
-	{
-	case '1':	gr.Window(argc,argv,sample_1,"1D plots");	break;
-	case '2':	gr.Window(argc,argv,sample_2,"2D plots");	break;
-	case '3':	gr.Window(argc,argv,sample_3,"3D plots");	break;
-	case 'd':	gr.Window(argc,argv,sample_d,"Dual plots");	break;
-	case 't':	gr.Window(argc,argv,test,"Testing");	break;
-	default:	gr.Window(argc,argv,sample,"Example of molecules");	break;
-	}
-	return mglWxRun();
-#endif
+	// create a menu bar
+	wxMenuBar* mbar = new wxMenuBar();
+	wxMenu* fileMenu = new wxMenu(_T(""));
+	fileMenu->Append(idMenuQuit, _("&Quit\tAlt-F4"), _("Quit the application"));
+	mbar->Append(fileMenu, _("&File"));
+	SetMenuBar(mbar);
+	SetSize(800,620);
+
+	scroll = new wxScrolledWindow(this);
+	mgl = new wxMathGL(scroll);
+	mgl->SetDraw(mgl_draw_graph,(void*)sample);
+	mgl->Update();
 }
 //-----------------------------------------------------------------------------
-#else
-int main(int argc,char **argv)	{	return 0;	}
-#endif
\ No newline at end of file
diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt
index b868776..cbde2e5 100644
--- a/include/CMakeLists.txt
+++ b/include/CMakeLists.txt
@@ -8,6 +8,7 @@ install(DIRECTORY mgl2/ DESTINATION ${MGL_INCLUDE_PATH}
                         PATTERN "qt.h" EXCLUDE
                         PATTERN "qmathgl.h" EXCLUDE
                         PATTERN "window.h" EXCLUDE
+                        PATTERN "*old.h" EXCLUDE
                         PATTERN "*~" EXCLUDE
                         PATTERN "*.fs"
                         PATTERN "*.pas"
diff --git a/include/config.h.in b/include/config.h.in
index 629342d..f5171a5 100644
--- a/include/config.h.in
+++ b/include/config.h.in
@@ -1,25 +1,24 @@
 #ifndef _MGL_CONFIG_H_
 #define _MGL_CONFIG_H_
 
-#define MGL_USE_DOUBLE ${MGL_USE_DOUBLE}
-#define MGL_NO_DATA_A ${MGL_NO_DATA_A}
+#define MGL_USE_DOUBLE	${MGL_USE_DOUBLE}
+#define MGL_NO_DATA_A	${MGL_NO_DATA_A}
 
-#define MGL_HAVE_GSL ${MGL_HAVE_GSL}
-#define MGL_HAVE_LTDL ${MGL_HAVE_LTDL}
 #if defined(_MSC_VER) || defined(__BORLANDC__)
-#define MGL_HAVE_PTHREAD 0
+#define MGL_HAVE_PTHREAD	0
 #else
-#define MGL_HAVE_PTHREAD ${MGL_HAVE_PTHREAD}
+#define MGL_HAVE_PTHREAD	${MGL_HAVE_PTHREAD}
 #endif
-#define MGL_HAVE_HDF4 ${MGL_HAVE_HDF4}
-#define MGL_HAVE_HDF5 ${MGL_HAVE_HDF5}
-#define MGL_HAVE_JPEG ${MGL_HAVE_JPEG}
-#define MGL_HAVE_PNG ${MGL_HAVE_PNG}
-#define MGL_HAVE_ZLIB ${MGL_HAVE_ZLIB}
-#define MGL_HAVE_PDF ${MGL_HAVE_PDF}
-#define MGL_HAVE_GIF ${MGL_HAVE_GIF}
-#define MGL_HAVE_OPENGL ${MGL_HAVE_OPENGL}
-#define MGL_HAVE_MPI ${MGL_HAVE_MPI}
-#define MGL_FONT_PATH "${MGL_FONT_PATH}"
+#define MGL_HAVE_ZLIB	${MGL_HAVE_ZLIB}
+#define MGL_HAVE_PNG		${MGL_HAVE_PNG}
+#define MGL_HAVE_GSL		${MGL_HAVE_GSL}
+#define MGL_HAVE_OPENGL	${MGL_HAVE_OPENGL}
+#define MGL_HAVE_OMP		${MGL_HAVE_OMP}
+#define MGL_HAVE_JPEG	${MGL_HAVE_JPEG}
+#define MGL_HAVE_GIF		${MGL_HAVE_GIF}
+#define MGL_HAVE_PDF		${MGL_HAVE_PDF}
+#define MGL_HAVE_HDF4	${MGL_HAVE_HDF4}
+#define MGL_HAVE_HDF5	${MGL_HAVE_HDF5}
+#define MGL_FONT_PATH	"${MGL_FONT_PATH}"
 
 #endif
diff --git a/include/mgl2/abstract.h b/include/mgl2/abstract.h
new file mode 100644
index 0000000..a076071
--- /dev/null
+++ b/include/mgl2/abstract.h
@@ -0,0 +1,105 @@
+/***************************************************************************
+ * thread.h is part of Math Graphic Library
+ * Copyright (C) 2007-2012 Alexey Balakin <mathgl.abalakin at gmail.ru>       *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU Library General Public License as       *
+ *   published by the Free Software Foundation; either version 3 of the    *
+ *   License, or (at your option) any later version.                       *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU Library General Public     *
+ *   License along with this program; if not, write to the                 *
+ *   Free Software Foundation, Inc.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+#ifndef _MGL_ABSTRACT_H_
+#define _MGL_ABSTRACT_H_
+
+#include "mgl2/define.h"
+//-----------------------------------------------------------------------------
+#ifdef __cplusplus
+#include <string>
+#include "mgl2/type.h"
+//-----------------------------------------------------------------------------
+class mglBase;
+class mglData;
+class mglParser;
+class mglFormula;
+class mglFormulaC;
+class mglFont;
+typedef mglBase* HMGL;
+typedef mglData* HMDT;
+typedef mglParser* HMPR;
+typedef mglFormula* HMEX;
+typedef mglFormulaC* HAEX;
+//-----------------------------------------------------------------------------
+#if MGL_NO_DATA_A
+#define mglDataA mglData
+typedef const mglData* HCDT;
+#include "mgl2/data.h"
+#else
+//-----------------------------------------------------------------------------
+/// Callback function for asking user a question. Result shouldn't exceed 1024.
+extern MGL_EXPORT void (*mgl_ask_func)(const wchar_t *quest, wchar_t *res);
+//-----------------------------------------------------------------------------
+/// Abstract class for data array
+class MGL_EXPORT mglDataA
+{
+public:
+	virtual ~mglDataA()	{}
+	virtual mreal v(long i,long j=0,long k=0) const = 0;
+	virtual mreal vthr(long i) const = 0;
+	virtual long GetNx() const = 0;
+	virtual long GetNy() const = 0;
+	virtual long GetNz() const = 0;
+	inline long GetNN() const {	return GetNx()*GetNy()*GetNz();	}
+	virtual mreal Maximal() const = 0;
+	virtual mreal Minimal() const = 0;
+	virtual mreal dvx(long i,long j=0,long k=0) const = 0;
+//	{	return i>0 ? (i<GetNx()-1 ? (v(i+1,j,k)-v(i-1,j,k))/2 : v(i,j,k)-v(i-1,j,k)) : v(1,j,k)-v(0,j,k);	}
+	virtual mreal dvy(long i,long j=0,long k=0) const = 0;
+//	{	return j>0 ? (j<GetNy()-1 ? (v(i,j+1,k)-v(i,j-1,k))/2 : v(i,j,k)-v(i,j-1,k)) : v(i,1,k)-v(i,0,k);	}
+	virtual mreal dvz(long i,long j=0,long k=0) const = 0;
+//	{	return k>0 ? (k<GetNz()-1 ? (v(i,j,k+1)-v(i,j,k-1))/2 : v(i,j,k)-v(i,j,k-1)) : v(i,j,1)-v(i,j,0);	}
+};
+#endif
+typedef const mglDataA* HCDT;
+//-----------------------------------------------------------------------------
+/// Structure for color ID
+struct MGL_EXPORT mglColorID
+{
+	char id;
+	mglColor col;
+};
+MGL_EXPORT extern mglColorID mglColorIds[31];
+MGL_EXPORT extern std::string mglGlobalMess;	///< Buffer for receiving global messages
+//-----------------------------------------------------------------------------
+/// Brushes for mask with symbol "-+=;oOsS~<>jdD*^" correspondingly
+extern uint64_t mgl_mask_val[16];
+#define MGL_MASK_ID		"-+=;oOsS~<>jdD*^"
+#define MGL_SOLID_MASK	0xffffffffffffffff
+//-----------------------------------------------------------------------------
+#else
+typedef void *HMGL;
+typedef void *HMDT;
+typedef void *HMEX;
+typedef void *HAEX;
+typedef void *HMPR;
+typedef const void *HCDT;
+#endif
+
+#if MGL_SRC
+#define _Da_(d)	(*((const mglDataA *)(d)))
+#define _DA_(a)	((const mglDataA *)*(a))
+#define _GR_	((mglBase *)(*gr))
+//#define _D_(d)	*((mglData *)*(d))
+#define _DM_(a)	((mglData *)*(a))
+#define _DT_	((mglData *)*d)
+#endif
+
+#endif
diff --git a/include/mgl2/addon.h b/include/mgl2/addon.h
index 37036d6..01272c7 100644
--- a/include/mgl2/addon.h
+++ b/include/mgl2/addon.h
@@ -47,7 +47,7 @@ double MGL_EXPORT mgl_ipow(double x,int n);
 /// Get random number with Gaussian distribution
 double MGL_EXPORT mgl_gauss_rnd();
 /// Fill frequencies for FFT
-void MGL_EXPORT mgl_fft_freq(double *freq,size_t nn);
+void MGL_EXPORT mgl_fft_freq(double *freq,long nn);
 
 /// Remove double spaces from the string
 void MGL_EXPORT mgl_strcls(char *str);
@@ -58,6 +58,8 @@ int MGL_EXPORT mgl_chrpos(const char *str,char fnd);
 
 /// Get uncommented string from file (NOTE: it is not thread safe!!!)
 MGL_EXPORT char *mgl_fgetstr(FILE *fp);
+/// Get parameters from uncommented strings of file (NOTE: it is not thread safe!!!)
+void MGL_EXPORT mgl_fgetpar(FILE *fp, const char *str, ...);
 /// Check if symbol denote true
 int MGL_EXPORT mgl_istrue(char ch);
 /// Print test message
diff --git a/include/mgl2/base.h b/include/mgl2/base.h
index 5f0d9df..c973d9a 100644
--- a/include/mgl2/base.h
+++ b/include/mgl2/base.h
@@ -19,62 +19,21 @@
  ***************************************************************************/
 #ifndef _MGL_BASE_H_
 #define _MGL_BASE_H_
-#if !defined(_MSC_VER) && !defined(__BORLANDC__)
-#include <stdint.h>
-#endif
-#if defined(__BORLANDC__)
-typedef unsigned uintptr_t;
-#endif
-#include "mgl2/define.h"
+//#if !defined(_MSC_VER) && !defined(__BORLANDC__)
+#include "mgl2/abstract.h"
 
 #ifdef __cplusplus
 #include <vector>
 #include <string>
-#include "mgl2/type.h"
-//-----------------------------------------------------------------------------
-class mglBase;
-class mglData;
-class mglParser;
-class mglFormula;
-class mglFormulaC;
-class mglFont;
-typedef mglBase* HMGL;
-typedef mglData* HMDT;
-typedef mglParser* HMPR;
-typedef mglFormula* HMEX;
-typedef mglFormulaC* HAEX;
-//-----------------------------------------------------------------------------
-#if MGL_NO_DATA_A
-#define mglDataA mglData
-typedef const mglData* HCDT;
-#include "mgl2/data.h"
+
+#if MGL_HAVE_PTHREAD
+#include <pthread.h>
+#define MGL_PUSH(a,v,m)		{pthread_mutex_lock(&m);	a.push_back(v);	pthread_mutex_unlock(&m);}
 #else
-//-----------------------------------------------------------------------------
-/// Callback function for asking user a question. Result shouldn't exceed 1024.
-extern MGL_EXPORT void (*mgl_ask_func)(const wchar_t *quest, wchar_t *res);
-//-----------------------------------------------------------------------------
-/// Abstract class for data array
-class mglDataA
-{
-public:
-	virtual ~mglDataA()	{}
-	virtual mreal v(long i,long j=0,long k=0) const = 0;
-	virtual mreal vthr(long i) const = 0;
-	virtual long GetNx() const = 0;
-	virtual long GetNy() const = 0;
-	virtual long GetNz() const = 0;
-	inline long GetNN() const {	return GetNx()*GetNy()*GetNz();	}
-	virtual mreal Maximal() const = 0;
-	virtual mreal Minimal() const = 0;
-	virtual mreal dvx(long i,long j=0,long k=0) const = 0;
-//	{	return i>0 ? (i<GetNx()-1 ? (v(i+1,j,k)-v(i-1,j,k))/2 : v(i,j,k)-v(i-1,j,k)) : v(1,j,k)-v(0,j,k);	}
-	virtual mreal dvy(long i,long j=0,long k=0) const = 0;
-//	{	return j>0 ? (j<GetNy()-1 ? (v(i,j+1,k)-v(i,j-1,k))/2 : v(i,j,k)-v(i,j-1,k)) : v(i,1,k)-v(i,0,k);	}
-	virtual mreal dvz(long i,long j=0,long k=0) const = 0;
-//	{	return k>0 ? (k<GetNz()-1 ? (v(i,j,k+1)-v(i,j,k-1))/2 : v(i,j,k)-v(i,j,k-1)) : v(i,j,1)-v(i,j,0);	}
-};
+#define MGL_PUSH(a,v,m)		a.push_back(v);
 #endif
-typedef const mglDataA* HCDT;
+
+#define MGL_TO_WCS(str,code)	if(str){size_t s=mbstowcs(0,str,0); wchar_t *wcs=new wchar_t[s+1]; mbstowcs(wcs,str,s); wcs[s]=0; code; delete []wcs;}
 //-----------------------------------------------------------------------------
 inline mreal mgl_d(mreal v,mreal v1,mreal v2) { return v2!=v1?(v-v1)/(v2-v1):NAN; }
 //-----------------------------------------------------------------------------
@@ -82,26 +41,50 @@ mglPoint GetX(HCDT x, int i, int j, int k=0);
 mglPoint GetY(HCDT y, int i, int j, int k=0);
 mglPoint GetZ(HCDT z, int i, int j, int k=0);
 //-----------------------------------------------------------------------------
+/// Structure for transformation matrix
+struct MGL_EXPORT mglMatrix
+{
+	mreal b[9];
+	mreal x,y,z,pf;
+	mglMatrix()	{	clear();	}
+	void Rotate(mreal tetz,mreal tetx,mreal tety);
+	void RotateN(mreal Tet,mreal x,mreal y,mreal z);
+	inline void clear()	{	x=y=z=0;	memset(b,0,9*sizeof(mreal));	b[0]=b[4]=b[8]=1;	}
+	inline mglMatrix &operator=(const mglMatrix &a)
+	{	x=a.x;	y=a.y;	z=a.z;	pf=a.pf;	memcpy(b,a.b,9*sizeof(mreal));	return *this;	}
+};
+inline bool operator==(const mglMatrix &a, const mglMatrix &b)
+{	return b.x==a.x&&b.y==a.y&&b.z==a.z&&b.pf==a.pf&&!memcmp(b.b,a.b,9*sizeof(mreal));}
+inline bool operator!=(const mglMatrix &a, const mglMatrix &b)
+{	return b.x!=a.x||b.y!=a.y||b.z!=a.z||b.pf!=a.pf||memcmp(b.b,a.b,9*sizeof(mreal));	}
+//-----------------------------------------------------------------------------
 /// Structure for simplest primitives
-struct mglPrim	// NOTE: use float for reducing memory size
+struct MGL_EXPORT mglPrim	// NOTE: use float for reducing memory size
 {
 	// NOTE: n4 is used as mark; n3 -- as pen style for type=0,1,4
 	// NOTE: n3 is used as position of txt,font in Ptxt for type=6
 	long n1,n2,n3,n4;	///< coordinates of corners
-	int type;	///< primitive type (0-point, 1-line, 2-trig, 3-quad, 4-glyph, 6-text)
+	short type;	///< primitive type (0-point, 1-line, 2-trig, 3-quad, 4-glyph, 6-text)
+	short angl;	///< rotation angle for mask
 	int id;		///< object id
-	float z;		///< z-position
-	float s;		///< size (if applicable) or fscl
-	float w;		///< width (if applicable) or ftet
-	float p;
-
-	mglPrim(int t=0)	{	n1=n2=n3=n4=id=0;	z=s=w=p=0;	type = t;	}
+	float z;	///< z-position
+	float w;	///< width (if applicable) or ftet
+	union
+	{
+		struct
+		{
+			float s;		///< size (if applicable) or fscl
+			float p;
+		};
+		uint64_t m;
+	};
+	mglPrim(int t=0)	{	n1=n2=n3=n4=id=0;	z=s=w=p=0;	type=t;	}
 };
 bool operator<(const mglPrim &a,const mglPrim &b);
 bool operator>(const mglPrim &a,const mglPrim &b);
 //-----------------------------------------------------------------------------
 /// Structure for group of primitives
-struct mglGroup
+struct MGL_EXPORT mglGroup
 {
 	std::vector<long> p;	///< list of primitives (not filled!!!)
 	int Id;				///< Current list of primitives
@@ -110,7 +93,7 @@ struct mglGroup
 };
 //-----------------------------------------------------------------------------
 /// Structure for text label
-struct mglText
+struct MGL_EXPORT mglText
 {
 	std::wstring text;
 	std::string stl;
@@ -120,7 +103,7 @@ struct mglText
 };
 //-----------------------------------------------------------------------------
 /// Structure for internal point representation
-struct mglPnt	// NOTE: use float for reducing memory size
+struct MGL_EXPORT mglPnt	// NOTE: use float for reducing memory size
 {
 	float xx,yy,zz;	// original coordinates
 	float x,y,z;	// coordinates
@@ -153,8 +136,8 @@ struct MGL_EXPORT mglGlyph
 	short *trig, *line;	///< vertexes of triangles and lines
 
 	mglGlyph()	{	nl=nt=0;	trig=line=0;	}
-	mglGlyph(const mglGlyph &a)	{	trig=line=0;	*this=a;	}
-	mglGlyph(long Nt, long Nl)		{	trig=line=0;	Create(Nt,Nl);	}
+	mglGlyph(const mglGlyph &a)	{	nl=nt=0;	trig=line=0;	*this=a;	}
+	mglGlyph(long Nt, long Nl)	{	nl=nt=0;	trig=line=0;	Create(Nt,Nl);	}
 	~mglGlyph()	{	if(trig)	delete []trig;	if(line)	delete []line;	}
 
 	void Create(long Nt, long Nl);
@@ -174,7 +157,7 @@ struct MGL_EXPORT mglTexture
 	char Sch[260];		///< Color scheme used
 	int Smooth;			///< Type of texture (smoothing and so on)
 	mreal Alpha;			///< Transparency
-	
+
 	mglTexture()	{	n=Smooth=0;	Alpha=1;	}
 	mglTexture(const char *cols, int smooth=0,mreal alpha=1)
 	{	n=0;	Set(cols,smooth,alpha);	}
@@ -195,17 +178,8 @@ const mglColor BC( 0, 0, 0);
 const mglColor WC( 1, 1, 1);
 const mglColor RC( 1, 0, 0);
 //-----------------------------------------------------------------------------
-/// Structure for color ID
-struct mglColorID
-{
-	char id;
-	mglColor col;
-};
-MGL_EXPORT extern mglColorID mglColorIds[31];
-MGL_EXPORT extern std::string mglGlobalMess;	///< Buffer for receiving global messages
-//-----------------------------------------------------------------------------
 /// Structure active points
-struct mglActivePos
+struct MGL_EXPORT mglActivePos
 {
 	int x,y;		///< coordinates of active point
 	int id;		///< object id for active point
@@ -233,16 +207,16 @@ public:
 	mreal CDef;			///< Default (current) color in texture
 	mreal AlphaDef;		///< Default value of alpha channel (transparency)
 	mreal BarWidth;		///< Relative width of rectangles in Bars().
-	int MeshNum;			///< Set approximate number of lines in Mesh and Grid. By default (=0) it draw all lines.
-	int FaceNum;			///< Set approximate number of visible faces and lines. By default (=0) it draw everything.
+	int MeshNum;		///< Set approximate number of lines in Mesh and Grid. By default (=0) it draw all lines.
+	int FaceNum;		///< Set approximate number of visible faces and lines. By default (=0) it draw everything.
 	char Arrow1, Arrow2;///< Style of arrows at end and at start of curve
 	long InUse;			///< Smart pointer (number of users)
-	long Flag;			///< Flags for controlling drawing
+	uint32_t Flag;			///< Flags for controlling drawing
 
-	inline bool get(long fl) const	{	return Flag&fl;	}
-	inline void set(long fl)	{	Flag |= fl;	}
-	inline void clr(long fl)	{	Flag &=~fl;	}
-	inline void set(bool v,long fl)	{	Flag = v ? Flag|fl : Flag&(~fl);	}
+	inline bool get(uint32_t fl) const	{	return Flag&fl;	}
+	inline void set(uint32_t fl)	{	Flag |= fl;	}
+	inline void clr(uint32_t fl)	{	Flag &=~fl;	}
+	inline void set(bool v,uint32_t fl)	{	Flag = v ? Flag|fl : Flag&(~fl);	}
 
 	/// Set axis range scaling -- simplified way to shift/zoom axis range -- need to replot whole image!
 	inline void ZoomAxis(mglPoint p1=mglPoint(0,0,0,0), mglPoint p2=mglPoint(1,1,1,1))	{	AMin = p1;	AMax = p2;	}
@@ -288,14 +262,20 @@ public:
 	inline void SetCutBox(mreal x1, mreal y1, mreal z1, mreal x2, mreal y2, mreal z2)
 	{	CutMin=mglPoint(x1,y1,z1);	CutMax=mglPoint(x2,y2,z2);	}
 	inline void SetCutBox(mglPoint v1, mglPoint v2)	{	CutMin=v1;	CutMax=v2;	}
+	/// Reset mask to solid state
+	inline void ResetMask()	{	mask = MGL_SOLID_MASK;	MaskAn = DefMaskAn;	}
+	/// Set default mask rotation angle
+	inline void SetMaskAngle(int angle)	{	DefMaskAn = angle;	}
 
 	/// Set the using of light on/off.
 	virtual bool Light(bool enable)
 	{	bool t=get(MGL_ENABLE_LIGHT);	set(enable,MGL_ENABLE_LIGHT);	return t;	}
 	/// Set ambient light brightness
 	virtual void SetAmbient(mreal bright=0.5);
+	/// Set diffusive light brightness
+	virtual void SetDiffuse(mreal bright=0.5);
 	/// Use diffusive light (only for local light sources)
-	inline void SetDifLight(bool dif)	{	set(dif,MGL_DIFFUSIVE);	}
+	inline void SetDifLight(bool dif)	{	SetDiffuse(dif?0.5:0);	}
 	/// Set the transparency on/off.
 	virtual bool Alpha(bool enable)
 	{	bool t=get(MGL_ENABLE_ALPHA);	set(enable,MGL_ENABLE_ALPHA);	return t;	}
@@ -354,7 +334,7 @@ public:
 	virtual mreal GetRatio() const;
 	virtual int GetWidth() const;
 	virtual int GetHeight() const;
-	
+
 	/// Set to use or not text rotation
 	inline void SetRotatedText(bool val)	{	set(val,MGL_ENABLE_RTEXT);	}
 	/// Set default font style and color
@@ -373,10 +353,13 @@ public:
 	/// Set plot quality
 	virtual void SetQuality(int qual=MGL_DRAW_NORM)	{	Quality=qual;	}
 	inline int GetQuality() const	{	return Quality;	}
+	inline void SetDrawReg(long nx=1, long ny=1, long m=0)	{	dr_x=nx;	dr_y=ny;	dr_p=m;	}
 
 	// ~~~~~~~~~~~~~~~~~~~~~~ Developer functions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 	/// Add point to the Pnt and return its position
-	long AddPnt(mglPoint p, mreal c=-1, mglPoint n=mglPoint(NAN), mreal a=-1, int scl=1);
+	inline long AddPnt(mglPoint p, mreal c=-1, mglPoint n=mglPoint(NAN), mreal a=-1, int scl=1)
+	{	return AddPnt(&B,p,c,n,a,scl);	}
+	long AddPnt(const mglMatrix *M, mglPoint p, mreal c=-1, mglPoint n=mglPoint(NAN), mreal a=-1, int scl=1);
 	long CopyNtoC(long k, mreal c);
 	long CopyProj(long from, mglPoint p, mglPoint n);
 	virtual void Reserve(long n);		///< Allocate n-cells for Pnt and return current position
@@ -388,7 +371,10 @@ public:
 	void AddActive(long k,int n=0);
 	/// Clear unused points and primitives
 	void ClearUnused();
-	
+
+	inline mreal GetPenWidth()	{	return PenWidth;	}
+
+	inline const mglMatrix *GetB()	const	{	return &B;	}
 	inline mglPoint GetPntP(long i) const
 	{	const mglPnt &p=Pnt[i];	return mglPoint(p.x,p.y,p.z);	}
 	inline mglPoint GetPntN(long i) const
@@ -407,11 +393,11 @@ public:
 	inline const mglTexture &GetTxt(long i) const	{	return Txt[i];	}
 	inline long GetTxtNum() const		{	return Txt.size();	}
 	/// Scale coordinates and cut off some points
-	virtual bool ScalePoint(mglPoint &p, mglPoint &n, bool use_nan=true) const;
+	virtual bool ScalePoint(const mglMatrix *M, mglPoint &p, mglPoint &n, bool use_nan=true) const;
 
-	virtual mreal GetOrgX(char dir) const=0;	///< Get Org.x (parse NAN value)
-	virtual mreal GetOrgY(char dir) const=0;	///< Get Org.y (parse NAN value)
-	virtual mreal GetOrgZ(char dir) const=0;	///< Get Org.z (parse NAN value)
+	virtual mreal GetOrgX(char dir, bool inv=false) const=0;	///< Get Org.x (parse NAN value)
+	virtual mreal GetOrgY(char dir, bool inv=false) const=0;	///< Get Org.y (parse NAN value)
+	virtual mreal GetOrgZ(char dir, bool inv=false) const=0;	///< Get Org.z (parse NAN value)
 
 	/// Get color depending on single variable z, which should be scaled if scale=true
 	inline mreal GetC(long s,mreal z,bool scale = true) const
@@ -419,14 +405,17 @@ public:
 	/// Get alpha value depending on single variable a
 	mreal GetA(mreal a) const;
 	/// Set pen/palette
-	char SetPenPal(const char *stl, long *id=0);
+	char SetPenPal(const char *stl, long *id=0, bool pal=true);
 	/// Add texture (like color scheme) and return the position of first color
 	long AddTexture(const char *cols, int smooth=0);
 //	inline mreal AddTexture(char col)	{	return AddTexture(mglColor(col));	}
 	mreal AddTexture(mglColor col);
 	inline void DefColor(mglColor col)	{	CDef = AddTexture(col);	}
+	/// Set mask for face coloring
+	void SetMask(const char *mask);
 	/// Set next color from palette
 	mreal NextColor(long &id);
+	mreal NextColor(long id, long sh);
 
 	virtual void mark_plot(long p, char type, mreal size=1)=0;
 	virtual void arrow_plot(long p1, long p2, char st)=0;
@@ -456,7 +445,7 @@ protected:
 	std::vector<mglPrim> Sub;	///< InPlot regions {n1=x1,n2=x2,n3=y1,n4=y2,id}
 	std::vector<mglText> Ptx;	///< Text labels for mglPrim
 	std::vector<mglText> Leg;	///< Text labels for legend
-	std::vector<mglGlyph> Glf;	///< Glyphs data 
+	std::vector<mglGlyph> Glf;	///< Glyphs data
 	std::vector<mglTexture> Txt;	///< Pointer to textures
 #if MGL_HAVE_PTHREAD
 	pthread_mutex_t mutexPnt, mutexTxt, mutexLeg, mutexGlf, mutexAct, mutexDrw;
@@ -469,6 +458,11 @@ protected:
 	mreal PenWidth;		///< Pen width for further line plotting (must be >0 !!!)
 //	long numT;			///< Number of textures
 	mreal AmbBr;		///< Default ambient light brightness
+	mreal DifBr;		///< Default diffusive light brightness
+
+	mglMatrix Bp;		///< Transformation matrix for View() and Zoom()
+	mglMatrix B;		///< Transformation matrix
+	mglMatrix B1;		///< Transformation matrix for colorbar
 
 	mglFont *fnt;		///< Class for printing vector text
 	mreal FontSize;		///< The size of font for tick and axis labels
@@ -486,8 +480,10 @@ protected:
 	mreal ArrowSize;	///< The size of arrows.
 	char last_style[64];///< Last pen style
 	mreal font_factor;	///< Font scaling factor
+	
+	long dr_x, dr_y, dr_p;	///< default drawing region for quality&4 mode
 
-	virtual void LightScale()=0;			///< Scale positions of light sources
+	virtual void LightScale(const mglMatrix *M)=0;			///< Scale positions of light sources
 
 	// block for SaveState()
 	mglPoint MinS;		///< Saved lower edge of bounding box for graphics.
@@ -498,14 +494,22 @@ protected:
 	bool saved;			///< State is saved
 	std::string leg_str;///< text to be save in legend
 
+	union
+	{
+		uint64_t mask;	///< Mask to be used for coloring
+		unsigned char mask_ch[8];
+	};
+	int MaskAn;		///< Mask rotation angle in degrees
+	int DefMaskAn;	///< Default mask rotation angle in degrees
+
 private:
 
 	mglPoint CutMin;	///< Lower edge of bounding box for cut off.
 	mglPoint CutMax;	///< Upper edge of bounding box for cut off.
 
-	void RecalcCRange();	///< Recalculate internal parameter for correct coloring.
+	bool RecalcCRange();	///< Recalculate internal parameter for correct coloring.
 	void RecalcBorder();	///< Recalculate internal parameter for correct transformation rules.
-	void SetFBord(mreal x,mreal y,mreal z);	///< Set internal boundng box depending on transformation formula
+	bool SetFBord(mreal x,mreal y,mreal z);	///< Set internal boundng box depending on transformation formula
 	void ClearEq();			///< Clear the used variables for axis transformation
 };
 //-----------------------------------------------------------------------------
@@ -517,20 +521,5 @@ bool MGL_EXPORT mgl_check_vec3(HMGL gr, HCDT x, HCDT y, HCDT z, HCDT ax, HCDT ay
 bool MGL_EXPORT mgl_check_trig(HMGL gr, HCDT nums, HCDT x, HCDT y, HCDT z, HCDT a, const char *name, int d=3);
 bool MGL_EXPORT mgl_isboth(HCDT x, HCDT y, HCDT z, HCDT a);
 //-----------------------------------------------------------------------------
-#define _Da_(d)	(*((const mglDataA *)(d)))
-#define _DA_(a)	((const mglDataA *)*(a))
-#define _GR_	((mglBase *)(*gr))
-//-----------------------------------------------------------------------------
-//#define _D_(d)	*((mglData *)*(d))
-#define _DM_(a)	((mglData *)*(a))
-#define _DT_	((mglData *)*d)
-//-----------------------------------------------------------------------------
-#else
-typedef void *HMGL;
-typedef void *HMDT;
-typedef void *HMEX;
-typedef void *HAEX;
-typedef void *HMPR;
-typedef const void *HCDT;
 #endif
 #endif
diff --git a/include/mgl2/base_cf.h b/include/mgl2/base_cf.h
index c0a5597..1f4024d 100644
--- a/include/mgl2/base_cf.h
+++ b/include/mgl2/base_cf.h
@@ -19,7 +19,7 @@
  ***************************************************************************/
 #ifndef _MGL_BASE_CF_H_
 #define _MGL_BASE_CF_H_
-#include "mgl2/base.h"
+#include "mgl2/abstract.h"
 //-----------------------------------------------------------------------------
 #ifdef __cplusplus
 extern "C" {
@@ -46,12 +46,18 @@ int MGL_EXPORT mgl_get_quality_(uintptr_t *gr);
 /// Set plot quality
 void MGL_EXPORT mgl_set_quality(HMGL gr, int qual);
 void MGL_EXPORT mgl_set_quality_(uintptr_t *gr, int *qual);
+/// Set drawing region for Quality&4
+void MGL_EXPORT mgl_set_draw_reg(HMGL gr, long nx, long ny, long m);
+void MGL_EXPORT mgl_set_draw_reg_(uintptr_t *gr, int *nx, int *ny, int *m);
+
 /// Is frames
 int MGL_EXPORT mgl_is_frames(HMGL gr);
 /// Get bit-value flag of HMGL state (for advanced users only)
-int MGL_EXPORT mgl_get_flag(HMGL gr, long flag);
+int MGL_EXPORT mgl_get_flag(HMGL gr, uint32_t flag);
+int MGL_EXPORT mgl_get_flag_(uintptr_t *gr, unsigned long *flag);
 /// Set bit-value flag of HMGL state (for advanced users only)
-void MGL_EXPORT mgl_set_flag(HMGL gr, int val, long flag);
+void MGL_EXPORT mgl_set_flag(HMGL gr, int val, uint32_t flag);
+void MGL_EXPORT mgl_set_flag_(uintptr_t *gr, int *val, unsigned long *flag);
 /// Change counter of HMGL uses (for advanced users only). Non-zero counter prevent automatic object removing.
 long MGL_EXPORT mgl_use_graph(HMGL gr, int inc);
 long MGL_EXPORT mgl_use_graph_(uintptr_t *gr, int *inc);
@@ -79,6 +85,15 @@ void MGL_EXPORT mgl_set_color_(char *id, mreal *r, mreal *g, mreal *b, int);
 /// Set default color scheme
 void MGL_EXPORT mgl_set_def_sch(HMGL gr, const char *sch);
 void MGL_EXPORT mgl_set_def_sch_(uintptr_t *gr, const char *sch,int);
+/// Set mask for face coloring as array of type 'unsigned char[8]'
+void MGL_EXPORT mgl_set_mask(char id, const char *mask);
+void MGL_EXPORT mgl_set_mask_(const char *id, const char *mask,int,int);
+/// Set mask for face coloring as unsigned long number
+void MGL_EXPORT mgl_set_mask_val(char id, uint64_t mask);
+void MGL_EXPORT mgl_set_mask_val_(const char *id, uint64_t *mask,int);
+/// Set default mask rotation angle
+void MGL_EXPORT mgl_set_mask_angle(HMGL gr, int angle);
+void MGL_EXPORT mgl_set_mask_angle_(uintptr_t *gr, int *angle);
 
 /// Set default value of alpha-channel
 void MGL_EXPORT mgl_set_alpha_default(HMGL gr, double alpha);
@@ -99,7 +114,10 @@ void MGL_EXPORT mgl_clear_unused_(uintptr_t *gr);
 /// Set ambient light brightness
 void MGL_EXPORT mgl_set_ambbr(HMGL gr, double i);
 void MGL_EXPORT mgl_set_ambbr_(uintptr_t *gr, mreal *i);
-/// Use diffusive light (only for local light sources)
+/// Set diffusive light brightness
+void MGL_EXPORT mgl_set_difbr(HMGL gr, double i);
+void MGL_EXPORT mgl_set_difbr_(uintptr_t *gr, mreal *i);
+/// Use diffusive light (only for local light sources) -- OBSOLETE
 void MGL_EXPORT mgl_set_light_dif(HMGL gr, int enable);
 void MGL_EXPORT mgl_set_light_dif_(uintptr_t *gr, int *enable);
 
diff --git a/include/mgl2/canvas.h b/include/mgl2/canvas.h
index 3b7f222..aeef0df 100644
--- a/include/mgl2/canvas.h
+++ b/include/mgl2/canvas.h
@@ -23,26 +23,15 @@
 //-----------------------------------------------------------------------------
 struct GifFileType;
 //-----------------------------------------------------------------------------
-/// Structure for transformation matrix
-struct mglMatrix
-{
-	mreal b[9];
-	mreal x,y,z,pf;
-	mglMatrix()	{	clear();	}
-	inline void clear()	{	x=y=z=0;	memset(b,0,9*sizeof(mreal));	b[0]=b[4]=b[8]=1;	}
-	inline mglMatrix &operator=(const mglMatrix &a)
-	{	x=a.x;	y=a.y;	z=a.z;	pf=a.pf;	memcpy(b,a.b,9*sizeof(mreal));	return *this;	}
-};
-//-----------------------------------------------------------------------------
 /// Structure for drawing axis and ticks
-struct mglAxis
+struct MGL_EXPORT mglAxis
 {
-	mglAxis()	{	dv=ds=d=v0=v1=v2=o=sh=0;	ns=f=ch=*t=0;	pos = 't';	}
+	mglAxis()	{	dv=ds=d=v0=v1=v2=o=sh=0;	ns=f=ch=0;	pos = 't';	inv=false;	}
 	mglAxis(const mglAxis &aa)
 	{	dv=aa.dv;	ds=aa.ds;	d=aa.d;		dir=aa.dir;	sh=aa.sh;
 		v0=aa.v0;	v1=aa.v1;	v2=aa.v2;	o=aa.o;		pos=aa.pos;
-		a = aa.a;	b = aa.b;	org=aa.org;	txt=aa.txt;
-		ns=aa.ns;	f=aa.f;		ch=aa.ch;	wcscpy(t,aa.t);	}
+		a = aa.a;	b = aa.b;	org=aa.org;	txt=aa.txt;	inv=aa.inv;
+		ns=aa.ns;	f=aa.f;		ch=aa.ch;	t=aa.t;	}
 	inline void AddLabel(const wchar_t *lbl, mreal v)
 	{	txt.push_back(mglText(lbl,"",v));	}
 	inline void AddLabel(const std::wstring &lbl, mreal v)
@@ -51,7 +40,7 @@ struct mglAxis
 	mreal dv,ds;		///< Actual step for ticks and subticks.
 	mreal d;			///< Step for axis ticks (if positive) or its number (if negative).
 	int ns;			///< Number of axis subticks.
-	wchar_t t[256];	///< Tick template (set "" to use default one ("%.2g" in simplest case))
+	std::wstring t;	///< Tick template (set "" to use default one ("%.2g" in simplest case))
 	mglPoint dir;	///< Axis direction
 	mglPoint a,b;	///< Directions of over axis
 	mglPoint org;
@@ -61,13 +50,14 @@ struct mglAxis
 	mreal o;			///< Point of starting ticks numbering (if NAN then Org is used).
 	int f;			///< Flag 0x1 - time, 0x2 - manual, 0x4 - fixed dv
 	std::vector<mglText> txt;	///< Axis labels
-	char ch;			///< Character of axis (like 'x','y','z','c')
+	char ch;		///< Character of axis (like 'x','y','z','c')
 	char pos;		///< Text position ('t' by default, or 'T' for opposite)
 	mreal sh;		///< Extra shift of ticks and axis labels
+	bool inv;		///< Inverse automatic origin position
 };
 //-----------------------------------------------------------------------------
 /// Structure for light source
-struct mglLight
+struct MGL_EXPORT mglLight
 {
 	mglLight()	{	n=false;	a=b=0;	}
 	bool n;			///< Availability of light sources
@@ -82,9 +72,14 @@ struct mglLight
 //-----------------------------------------------------------------------------
 class mglCanvas;
 /// Structure for light source
-struct mglDrawReg
+struct MGL_EXPORT mglDrawReg
 {
-	unsigned long PDef;
+	union
+	{
+		uint64_t PDef;
+		unsigned char m[8];
+	};
+	int angle;	///< mask rotation values in degrees
 	int ObjId;
 	mreal PenWidth, pPos;
 	int x1,x2,y1,y2;
@@ -92,7 +87,7 @@ struct mglDrawReg
 };
 //-----------------------------------------------------------------------------
 /// Structure contains everything for drawing
-struct mglDrawDat
+struct MGL_EXPORT mglDrawDat
 {
 	std::vector<mglPnt>  Pnt;	///< Internal points
 	std::vector<mglPrim> Prm;	///< Primitives (lines, triangles and so on) -- need for export
@@ -101,10 +96,13 @@ struct mglDrawDat
 	std::vector<mglTexture> Txt;	///< Pointer to textures
 };
 //-----------------------------------------------------------------------------
+union mglRGBA	{	uint32_t c; unsigned char r[4];	};
+//-----------------------------------------------------------------------------
 /// Class contains all functionality for creating different mathematical plots
 class MGL_EXPORT mglCanvas : public mglBase
 {
 friend struct mglPrim;
+friend struct mglDrawReg;
 public:
 using mglBase::Light;
 
@@ -123,8 +121,9 @@ using mglBase::Light;
 
 	/// Clear transformation matrix.
 	inline void Identity(bool rel=false)	{	InPlot(0,1,0,1,rel);	}
+	inline void Identity(mglMatrix &M, bool rel=false)	{	InPlot(M,0,1,0,1,rel);	}
 	/// Push transformation matrix into stack
-	inline void Push()	{	MGL_PUSH(stack,B,mutexStk);	}
+	void Push();
 	/// Set PlotFactor
 	inline void SetPlotFactor(mreal val)
 	{	if(val<=0)	{B.pf=1.55;	set(MGL_AUTO_FACTOR);}	else {B.pf=val;	clr(MGL_AUTO_FACTOR);}	}
@@ -133,13 +132,15 @@ using mglBase::Light;
 	/// Pop transformation matrix from stack
 	inline void Pop()	{	B = stack.back(); stack.pop_back();	}
 	/// Clear up the frame
-	virtual void Clf(mglColor back=WC);
+	virtual void Clf(mglColor back=NC);
 
 	/// Put further plotting in cell of stick rotated on angles tet, phi
 	void StickPlot(int num, int i, mreal tet, mreal phi);
 	/// Put further plotting in some region of whole frame surface.
-	void InPlot(mreal x1,mreal x2,mreal y1,mreal y2,bool rel=true);
+	inline void InPlot(mreal x1,mreal x2,mreal y1,mreal y2,bool rel=true)
+	{	InPlot(B,x1,x2,y1,y2,rel);	}
 	void InPlot(mreal x1,mreal x2,mreal y1,mreal y2, const char *style);
+	void InPlot(mglMatrix &M,mreal x1,mreal x2,mreal y1,mreal y2,bool rel=true);
 	/// Add title for current subplot/inplot
 	void Title(const char *title,const char *stl="#",mreal size=-2);
 	void Title(const wchar_t *title,const char *stl="#",mreal size=-2);
@@ -148,7 +149,7 @@ using mglBase::Light;
 	/// Rotate a further plotting.
 	void Rotate(mreal TetX,mreal TetZ,mreal TetY=0);
 	/// Rotate a further plotting around vector {x,y,z}.
-	void RotateN(mreal Tet,mreal x,mreal y,mreal z);
+	void RotateN(mreal Tet,mreal x,mreal y,mreal z)	;
 	/// Set perspective (in range [0,1)) for plot. Set to zero for switching off.
 	void Perspective(mreal a)	{	Bp.pf = fabs(a);	}
 
@@ -185,7 +186,7 @@ using mglBase::Light;
 	int GetSplId(long xs,long ys) const;
 	/// Check if there is active point or primitive (n=-1)
 	int IsActive(int xs, int ys,int &n);
-	
+
 	/// Create new frame.
 	virtual int NewFrame();
 	/// Finish frame drawing
@@ -202,19 +203,20 @@ using mglBase::Light;
 	virtual void SetFrame(long i);
 	/// Add drawing data from i-th frame to the current drawing
 	void ShowFrame(long i);
-	
+
 	/// Start write frames to cinema using GIF format
 	void StartGIF(const char *fname, int ms=100);
 	/// Stop writing cinema using GIF format
 	void CloseGIF();
 	/// Finish plotting. Normally this function is called internaly.
-	virtual void Finish(bool fast=true);
+	virtual void Finish();
 	/// Export points and primitives in file using MGLD format
 	bool ExportMGLD(const char *fname, const char *descr=0);
 	/// Import points and primitives from file using MGLD format
 	bool ImportMGLD(const char *fname, bool add=false);
 	/// Export in JSON format suitable for later drawing by JavaScript
-	bool WriteJSON(const char *fname);
+	bool WriteJSON(const char *fname, bool force_zlib=false);
+	std::string GetJSON();
 
 	/// Set the transparency type
 	inline void SetTranspType(int val)
@@ -288,8 +290,6 @@ using mglBase::Light;
 
 	void StartAutoGroup (const char *);
 	void EndGroup();
-	/// Retur color for primitive depending lighting
-	mglColor GetColor(const mglPrim &p);
 	/// Set extra shift for tick and axis labels
 	inline void SetTickShift(mglPoint p)
 	{	ax.sh = p.x;	ay.sh = p.y;	az.sh = p.z;	ac.sh = p.c;	}
@@ -302,7 +302,12 @@ using mglBase::Light;
 	int *OI;			///< ObjId arrays (size width*height)
 	/// Plot point p with color c
 	void pnt_plot(long x,long y,mreal z,const unsigned char c[4], int obj_id);
-	
+	void pnt_fast(long x,long y,mreal z,const unsigned char c[4], int obj_id);
+	/// preparing primitives for 2d export or bitmap drawing (0 default, 1 for 2d vector, 2 for 3d vector)
+	void PreparePrim(int fast);
+	inline uint32_t GetPntCol(long i)	{	return pnt_col[i];	}
+	inline uint32_t GetPrmCol(long i)	{	return prm_col[i];	}
+
 protected:
 	mreal Delay;		///< Delay for animation in seconds
 	// NOTE: Z should be float for reducing space and for compatibility reasons
@@ -326,9 +331,6 @@ protected:
 	int Width;			///< Width of the image
 	int Height;			///< Height of the image
 	int Depth;			///< Depth of the image
-	mglMatrix Bp;		///< Transformation matrix for View() and Zoom()
-	mglMatrix B;		///< Transformation matrix
-	mglMatrix B1;		///< Transformation matrix for colorbar
 	mreal inW, inH;		///< Width and height of last InPlot
 	mreal inX, inY;		///< Coordinates of last InPlot
 	mglLight light[10];	///< Light sources
@@ -352,14 +354,16 @@ protected:
 	/// Clear ZBuffer only
 	void ClfZB(bool force=false);
 	/// Scale coordinates and cut off some points
-	bool ScalePoint(mglPoint &p, mglPoint &n, bool use_nan=true) const;
-	void LightScale();	///< Additionally scale positions of light sources
+	bool ScalePoint(const mglMatrix *M, mglPoint &p, mglPoint &n, bool use_nan=true) const;
+	void LightScale(const mglMatrix *M);	///< Additionally scale positions of light sources
 	/// Push drawing data (for frames only). NOTE: can be VERY large
 	long PushDrwDat();
-	
-	mreal GetOrgX(char dir) const;	///< Get Org.x (parse NAN value)
-	mreal GetOrgY(char dir) const;	///< Get Org.y (parse NAN value)
-	mreal GetOrgZ(char dir) const;	///< Get Org.z (parse NAN value)
+	/// Retur color for primitive depending lighting
+	uint32_t GetColor(const mglPrim &p);
+
+	mreal GetOrgX(char dir, bool inv=false) const;	///< Get Org.x (parse NAN value)
+	mreal GetOrgY(char dir, bool inv=false) const;	///< Get Org.y (parse NAN value)
+	mreal GetOrgZ(char dir, bool inv=false) const;	///< Get Org.z (parse NAN value)
 
 	void mark_plot(long p, char type, mreal size=1);
 	void arrow_plot(long p1, long p2, char st);
@@ -370,12 +374,12 @@ protected:
 	mreal text_plot(long p,const wchar_t *text,const char *fnt,mreal size=-1,mreal sh=0,mreal  col=-('k'), bool rot=true);
 
 	void add_prim(mglPrim &a);	///< add primitive to list
-	void mark_draw(const mglPnt &p, char type, mreal size, mglDrawReg *d);
-	void arrow_draw(const mglPnt &p1, const mglPnt &p2, char st, mreal size, mglDrawReg *d);
-	virtual void line_draw(const mglPnt &p1, const mglPnt &p2, mglDrawReg *d);
-	virtual void trig_draw(const mglPnt &p1, const mglPnt &p2, const mglPnt &p3, bool anorm, mglDrawReg *d);
-	virtual void quad_draw(const mglPnt &p1, const mglPnt &p2, const mglPnt &p3, const mglPnt &p4, mglDrawReg *d);
-	virtual void pnt_draw(const mglPnt &p, mglDrawReg *d);
+	void arrow_draw(const mglPnt &p1, const mglPnt &p2, char st, mreal size, const mglDrawReg *d);
+	virtual void mark_draw(const mglPnt &p, char type, mreal size, mglDrawReg *d);
+	virtual void line_draw(const mglPnt &p1, const mglPnt &p2, const mglDrawReg *d);
+	virtual void trig_draw(const mglPnt &p1, const mglPnt &p2, const mglPnt &p3, bool anorm, const mglDrawReg *d);
+	virtual void quad_draw(const mglPnt &p1, const mglPnt &p2, const mglPnt &p3, const mglPnt &p4, const mglDrawReg *d);
+	virtual void pnt_draw(const mglPnt &p, const mglDrawReg *d);
 	void arrow_draw(long n1, long n2, char st, float ll);
 	void arrow_plot_3d(long n1, long n2, char st, float ll);
 	void glyph_draw(const mglPrim &P, mglDrawReg *d);
@@ -385,66 +389,83 @@ protected:
 	mglPoint RestorePnt(mglPoint ps, bool norm=false) const;
 
 	// functions for multi-threading
-	void PreparePrim(bool fast);
-	void pxl_combine(size_t id, size_t n, const void *);
-	void pxl_memcpy(size_t id, size_t n, const void *);
-	void pxl_backgr(size_t id, size_t n, const void *);
-	void pxl_primdr(size_t id, size_t n, const void *);
-	void pxl_transform(size_t id, size_t n, const void *);
-	void pxl_setz(size_t id, size_t n, const void *);
-	void pxl_setz_adv(size_t id, size_t n, const void *);
-	void pxl_other(size_t id, size_t n, const void *p);
+	void pxl_pntcol(long id, long n, const void *);
+	void pxl_prmcol(long id, long n, const void *);
+	void pxl_combine(long id, long n, const void *);
+	void pxl_memcpy(long id, long n, const void *);
+	void pxl_backgr(long id, long n, const void *);
+	void pxl_primdr(long id, long n, const void *);
+	void pxl_dotsdr(long id, long n, const void *);
+	void pxl_primpx(long id, long n, const void *);
+	void pxl_transform(long id, long n, const void *);
+	void pxl_setz(long id, long n, const void *);
+	void pxl_setz_adv(long id, long n, const void *);
+	void pxl_other(long id, long n, const void *p);
 	/// Put drawing from other mglCanvas (for multithreading, like subplots)
 	void PutDrawReg(mglDrawReg *d, const mglCanvas *gr);
-	
+
 private:
+	std::vector<uint32_t> pnt_col, prm_col;
 //	mreal _tetx,_tety,_tetz;		// extra angles
 	std::vector<mglMatrix> stack;	///< stack for transformation matrices
-	int dr_nx1, dr_nx2, dr_ny1, dr_ny2;	// Allowed drawing region
 	GifFileType *gif;
 	mreal fscl,ftet;	///< last scale and rotation for glyphs
 	long forg;		///< original point (for directions)
 	size_t grp_counter;	///< Counter for StartGroup(); EndGroup();
+	mglMatrix Bt;	///< temporary matrix for text
 
 	/// Draw generic colorbar
 	void colorbar(HCDT v, const mreal *s, int where, mreal x, mreal y, mreal w, mreal h);
 	/// Draw labels for ticks
-	void DrawLabels(mglAxis &aa);
+	void DrawLabels(mglAxis &aa, bool inv=false);
 	/// Get label style
 	char GetLabelPos(mreal c, long kk, mglAxis &aa);
 	/// Draw tick
-	void tick_draw(mglPoint o, mglPoint d1, mglPoint d2, int f, const char *stl);
+	void tick_draw(mglPoint o, mglPoint d1, mglPoint d2, int f);
 	mreal FindOptOrg(char dir, int ind) const;
 	/// Transform mreal color and alpha to bits format
 	unsigned char* col2int(const mglPnt &p, unsigned char *r, int obj_id);
 	/// Combine colors in 2 plane.
 	void combine(unsigned char *c1, const unsigned char *c2);
 	/// Fast drawing of line between 2 points
-	void fast_draw(const mglPnt &p1, const mglPnt &p2, mglDrawReg *d);
+	void fast_draw(const mglPnt &p1, const mglPnt &p2, const mglDrawReg *d);
 
 	/// Additionally scale points p for positioning in image
-	void PostScale(mglPoint &p) const;
+	void PostScale(const mglMatrix *M, mglPoint &p) const;
 	/// Scale points p for projection to the face number nface in image
 	long ProjScale(int nface, long p, bool text=false);
-	inline void PostScale(mglPoint *p,long n) const	{	for(long i=0;i<n;i++)	PostScale(p[i]);	}
 	/// Set coordinate and add the point, return its id
 	long setPp(mglPnt &q, const mglPoint &p);
-	
+
 	// functions for glyph drawing
-	void glyph_fill(const mglPnt &p, mreal f, const mglGlyph &g, mglDrawReg *d);
-	void glyph_wire(const mglPnt &p, mreal f, const mglGlyph &g, mglDrawReg *d);
-	void glyph_line(const mglPnt &p, mreal f, bool solid, mglDrawReg *d);
+	void glyph_fill(const mglMatrix *M, const mglPnt &p, mreal f, const mglGlyph &g, const mglDrawReg *d);
+	void glyph_wire(const mglMatrix *M, const mglPnt &p, mreal f, const mglGlyph &g, const mglDrawReg *d);
+	void glyph_line(const mglMatrix *M, const mglPnt &p, mreal f, bool solid, const mglDrawReg *d);
+
+	// fill pixel for given primitive
+	void mark_pix(long i,long j,const mglPnt &p, char type, mreal size, mglDrawReg *d);
+	void arrow_pix(long i,long j,const mglPnt &p1, const mglPnt &p2, char st, mreal size, const mglDrawReg *d);
+	void line_pix(long i,long j,const mglPnt &p1, const mglPnt &p2, const mglDrawReg *d);
+	void trig_pix(long i,long j,const mglPnt &p1, const mglPnt &p2, const mglPnt &p3, bool anorm, const mglDrawReg *d);
+	void quad_pix(long i,long j,const mglPnt &p1, const mglPnt &p2, const mglPnt &p3, const mglPnt &p4, const mglDrawReg *d);
+	void glyph_pix(long i,long j,const mglPrim &P, mglDrawReg *d);
+	void pnt_pix(long i,long j,const mglPnt &p, const mglDrawReg *d);
+	void glyph_fpix(long i,long j,const mglMatrix *M, const mglPnt &p, mreal f, const mglGlyph &g, const mglDrawReg *d);
+	void glyph_wpix(long i,long j,const mglMatrix *M, const mglPnt &p, mreal f, const mglGlyph &g, const mglDrawReg *d);
+	void glyph_lpix(long i,long j,const mglMatrix *M, const mglPnt &p, mreal f, bool solid, const mglDrawReg *d);
+
+
 };
 //-----------------------------------------------------------------------------
 struct mglThreadG
 {
 	mglCanvas *gr;		// grapher
-	void (mglCanvas::*f)(size_t i, size_t n, const void *);
+	void (mglCanvas::*f)(long i, long n, const void *);
 	unsigned id;		// thread id
-	size_t n;	// total number of iteration
+	long n;	// total number of iteration
 	const void *p;		// external parameter
 };
 /// Start several thread for the task
-void mglStartThread(void (mglCanvas::*func)(size_t i, size_t n), mglCanvas *gr, size_t n);
+void mglStartThread(void (mglCanvas::*func)(long i, long n), mglCanvas *gr, long n);
 //-----------------------------------------------------------------------------
 #endif
diff --git a/include/mgl2/canvas_cf.h b/include/mgl2/canvas_cf.h
index db02211..d088ece 100644
--- a/include/mgl2/canvas_cf.h
+++ b/include/mgl2/canvas_cf.h
@@ -19,7 +19,7 @@
  ***************************************************************************/
 #ifndef MGL_CANVAS_CF_H
 #define MGL_CANVAS_CF_H
-#include "mgl2/base.h"
+#include "mgl2/abstract.h"
 //-----------------------------------------------------------------------------
 #ifdef __cplusplus
 extern "C" {
@@ -203,6 +203,9 @@ void MGL_EXPORT mgl_import_mgld_(uintptr_t *gr, const char *fname, int *add, int
 /// Export in JSON format suitable for later drawing by JavaScript
 void MGL_EXPORT mgl_write_json(HMGL gr, const char *fname,const char *descr);
 void MGL_EXPORT mgl_write_json_(uintptr_t *gr, const char *fname,const char *descr,int,int);
+void MGL_EXPORT mgl_write_json_z(HMGL gr, const char *fname,const char *descr);
+void MGL_EXPORT mgl_write_json_z_(uintptr_t *gr, const char *fname,const char *descr,int,int);
+MGL_EXPORT const char *mgl_get_json(HMGL gr);
 
 /// Get RGB values of current bitmap
 MGL_EXPORT const unsigned char *mgl_get_rgb(HMGL gr);
@@ -299,6 +302,9 @@ void MGL_EXPORT mgl_clf_(uintptr_t *gr);
 /// Clear up the frame and fill background by specified color
 void MGL_EXPORT mgl_clf_rgb(HMGL gr, double r, double g, double b);
 void MGL_EXPORT mgl_clf_rgb_(uintptr_t *gr, mreal *r, mreal *g, mreal *b);
+/// Clear up the frame and fill background by specified color
+void MGL_EXPORT mgl_clf_chr(HMGL gr, char col);
+void MGL_EXPORT mgl_clf_chr_(uintptr_t *gr, const char *col, int);
 
 /// Put further plotting in some region of whole frame.
 void MGL_EXPORT mgl_subplot(HMGL gr, int nx,int ny,int m,const char *style);
@@ -506,4 +512,3 @@ double MGL_EXPORT mgl_expr_diff_v(HMEX ex, char dir, mreal *var);
 #endif
 //-----------------------------------------------------------------------------
 #endif
-
diff --git a/include/mgl2/canvas_wnd.h b/include/mgl2/canvas_wnd.h
index 5d5b19e..ede42b0 100644
--- a/include/mgl2/canvas_wnd.h
+++ b/include/mgl2/canvas_wnd.h
@@ -64,7 +64,7 @@ public:
 						const char *title, void *par=NULL,
 						void (*reload)(void *p)=NULL, bool maximize=false)=0;
 	void SetDrawFunc(int (*draw)(mglBase *gr, void *p), void *par=NULL, void (*reload)(void *p)=NULL);
-	
+
 private:
 	int CurFig;			///< Current figure in the list.
 
diff --git a/include/mgl2/cont.h b/include/mgl2/cont.h
index 39c7060..acfe093 100644
--- a/include/mgl2/cont.h
+++ b/include/mgl2/cont.h
@@ -19,7 +19,7 @@
  ***************************************************************************/
 #ifndef _MGL_CONT_H_
 #define _MGL_CONT_H_
-#include "mgl2/base.h"
+#include "mgl2/abstract.h"
 //-----------------------------------------------------------------------------
 #ifdef __cplusplus
 extern "C" {
@@ -40,8 +40,8 @@ void MGL_EXPORT mgl_textw_y(HMGL gr, HCDT y, const wchar_t *text, const char *fo
 
 void MGL_EXPORT mgl_cont_gen(HMGL gr, double val, HCDT a, HCDT x, HCDT y, HCDT z, const char *stl);
 void MGL_EXPORT mgl_contf_gen(HMGL gr, double v1, double v2, HCDT a, HCDT x, HCDT y, HCDT z, const char *stl);
-void MGL_EXPORT mgl_contv_gen(HMGL gr, double v1, double v2, HCDT a, HCDT x, HCDT y, HCDT z, const char *stl);
-void MGL_EXPORT mgl_axial_gen(HMGL gr, double v1, double v2, HCDT a, HCDT x, HCDT y, HCDT z, const char *stl);
+//void MGL_EXPORT mgl_contv_gen(HMGL gr, double v1, double v2, HCDT a, HCDT x, HCDT y, HCDT z, const char *stl);
+//void MGL_EXPORT mgl_axial_gen(HMGL gr, double v1, double v2, HCDT a, HCDT x, HCDT y, HCDT z, const char *stl);
 
 /// Draw manual contour lines for 2d data specified parametrically
 void MGL_EXPORT mgl_cont_xy_val(HMGL gr, HCDT v, HCDT x, HCDT y, HCDT z, const char *sch, const char *opt);
diff --git a/include/mgl2/data.h b/include/mgl2/data.h
index 7ff2725..8dedada 100644
--- a/include/mgl2/data.h
+++ b/include/mgl2/data.h
@@ -21,6 +21,7 @@
 #define _MGL_DATA_H_
 
 #include "mgl2/data_cf.h"
+#include "mgl2/pde.h"
 #ifdef __cplusplus
 //-----------------------------------------------------------------------------
 #include <vector>
@@ -28,9 +29,9 @@
 //-----------------------------------------------------------------------------
 /// Class for working with data array
 #if MGL_NO_DATA_A
-class mglData
+class MGL_EXPORT mglData
 #else
-class mglData : public mglDataA
+class MGL_EXPORT mglData : public mglDataA
 #endif
 {
 public:
@@ -88,16 +89,16 @@ public:
 	inline void Set(const double *A,long NX,long NY=1,long NZ=1)
 	{	mgl_data_set_double(this,A,NX,NY,NZ);	}
 	/// Allocate memory and copy the data from the (float **) array
-	inline void Set(const float **A,long N1,long N2)
+	inline void Set(float const * const *A,long N1,long N2)
 	{	mgl_data_set_float2(this,A,N1,N2);	}
 	/// Allocate memory and copy the data from the (double **) array
-	inline void Set(const double **A,long N1,long N2)
+	inline void Set(double const * const *A,long N1,long N2)
 	{	mgl_data_set_double2(this,A,N1,N2);	}
 	/// Allocate memory and copy the data from the (float ***) array
-	inline void Set(const float ***A,long N1,long N2,long N3)
+	inline void Set(float const * const * const *A,long N1,long N2,long N3)
 	{	mgl_data_set_float3(this,A,N1,N2,N3);	}
 	/// Allocate memory and copy the data from the (double ***) array
-	inline void Set(const double ***A,long N1,long N2,long N3)
+	inline void Set(double const * const * const *A,long N1,long N2,long N3)
 	{	mgl_data_set_double3(this,A,N1,N2,N3);	}
 	/// Allocate memory and scanf the data from the string
 	inline void Set(const char *str,long NX,long NY=1,long NZ=1)
@@ -146,7 +147,7 @@ public:
 	/// Join with another data array
 	inline void Join(const mglDataA &d)
 	{	mgl_data_join(this,&d);	}
-	
+
 	/// Modify the data by specified formula
 	inline void Modify(const char *eq,long dim=0)
 	{	mgl_data_modify(this, eq, dim);	}
@@ -166,9 +167,28 @@ public:
 	/// Equidistantly fill the data to range [x1,x2] in direction dir
 	inline void Fill(mreal x1,mreal x2=NaN,char dir='x')
 	{	return mgl_data_fill(this,x1,x2,dir);	}
-	/// Set the data by triangulated surface values assuming x,y,z in range [r1,r2]
+	/// Fill the data by interpolated values of vdat parametrically depended on xdat,ydat,zdat for x,y,z in range [p1,p2]
+	inline void Refill(const mglDataA &xdat, const mglDataA &vdat, mreal x1, mreal x2,long sl=-1)
+	{	mgl_data_refill_x(this,&xdat,&vdat,x1,x2,sl);	}
+	inline void Refill(const mglDataA &xdat, const mglDataA &vdat, mglPoint p1, mglPoint p2,long sl=-1)
+	{	mgl_data_refill_x(this,&xdat,&vdat,p1.x,p2.x,sl);	}
+	inline void Refill(const mglDataA &xdat, const mglDataA &ydat, const mglDataA &vdat, mglPoint p1, mglPoint p2,long sl=-1)
+	{	mgl_data_refill_xy(this,&xdat,&ydat,&vdat,p1.x,p2.x,p1.y,p2.y,sl);	}
+	inline void Refill(const mglDataA &xdat, const mglDataA &ydat, const mglDataA &zdat, const mglDataA &vdat, mglPoint p1, mglPoint p2)
+	{	mgl_data_refill_xyz(this,&xdat,&ydat,&zdat,&vdat,p1.x,p2.x,p1.y,p2.y,p1.z,p2.z);	}
+	/// Fill the data by interpolated values of vdat parametrically depended on xdat,ydat,zdat for x,y,z in axis range of gr
+	inline void Refill(mglBase *gr, const mglDataA &xdat, const mglDataA &vdat, long sl=-1, const char *opt="")
+	{	mgl_data_refill_gr(gr,this,&xdat,0,0,&vdat,sl,opt);	}
+	inline void Refill(mglBase *gr, const mglDataA &xdat, const mglDataA &ydat, const mglDataA &vdat, long sl=-1, const char *opt="")
+	{	mgl_data_refill_gr(gr,this,&xdat,&ydat,0,&vdat,sl,opt);	}
+	inline void Refill(mglBase *gr, const mglDataA &xdat, const mglDataA &ydat, const mglDataA &zdat, const mglDataA &vdat, const char *opt="")
+	{	mgl_data_refill_gr(gr,this,&xdat,&ydat,&zdat,&vdat,-1,opt);	}
+	/// Set the data by triangulated surface values assuming x,y,z in axis range of gr
 	inline void Grid(mglBase *gr, const mglDataA &x, const mglDataA &y, const mglDataA &z, const char *opt="")
 	{	mgl_data_grid(gr,this,&x,&y,&z,opt);	}
+	/// Set the data by triangulated surface values assuming x,y,z in range [p1, p2]
+	inline void Grid(const mglDataA &xdat, const mglDataA &ydat, const mglDataA &vdat, mglPoint p1, mglPoint p2)
+	{	mgl_data_grid_xy(this,&xdat,&ydat,&vdat,p1.x,p2.x,p1.y,p2.y);	}
 	/// Put value to data element(s)
 	inline void Put(mreal val, long i=-1, long j=-1, long k=-1)
 	{	mgl_data_put_val(this,val,i,j,k);	}
@@ -248,7 +268,7 @@ public:
 	inline mglData Combine(const mglDataA &dat) const
 	{	return mglData(true,mgl_data_combine(this,&dat));	}
 	/// Resize the data to new size of box [x1,x2]*[y1,y2]*[z1,z2]
-	inline mglData Resize(long mx,long my=1,long mz=1, mreal x1=0,mreal x2=1, mreal y1=0,mreal y2=1, mreal z1=0,mreal z2=1) const
+	inline mglData Resize(long mx,long my=0,long mz=0, mreal x1=0,mreal x2=1, mreal y1=0,mreal y2=1, mreal z1=0,mreal z2=1) const
 	{	return mglData(true,mgl_data_resize_box(this,mx,my,mz,x1,x2,y1,y2,z1,z2));	}
 	/// Get array which values is result of interpolation this for coordinates from other arrays
 	inline mglData Evaluate(const mglData &idat, bool norm=true) const
@@ -260,7 +280,13 @@ public:
 	/// Find roots for set of nonlinear equations defined by textual formula
 	inline mglData Roots(const char *func, char var='x') const
 	{	return mglData(true,mgl_data_roots(func, this, var));	}
-	
+	/// Find correlation with another data arrays
+	inline mglData Correl(const mglDataA &dat, const char *dir) const
+	{	return mglData(true,mgl_data_correl(this,&dat,dir));	}
+	/// Find auto correlation function
+	inline mglData AutoCorrel(const char *dir) const
+	{	return mglData(true,mgl_data_correl(this,this,dir));	}
+
 	/// Cumulative summation the data in given direction or directions
 	inline void CumSum(const char *dir)	{	mgl_data_cumsum(this,dir);	}
 	/// Integrate (cumulative summation) the data in given direction or directions
@@ -331,7 +357,7 @@ public:
 	{	return mglData(true,mgl_data_solve(this, val, dir, 0, norm));	}
 	inline mglData Solve(mreal val, char dir, const mglData &i0, bool norm=true) const
 	{	return mglData(true,mgl_data_solve(this, val, dir, &i0, norm));	}
-	
+
 	/// Interpolate by cubic spline the data and return its derivatives at given point x=[0...nx-1], y=[0...ny-1], z=[0...nz-1]
 	inline mreal Spline(mglPoint &dif, mreal x,mreal y=0,mreal z=0) const
 	{	return mgl_data_spline_ext(this, x,y,z, &(dif.x),&(dif.y), &(dif.z));	}
@@ -346,7 +372,7 @@ public:
 	inline mreal Linear1(mglPoint &dif, mreal x,mreal y=0,mreal z=0) const
 	{	mreal res=mgl_data_linear_ext(this,x*(nx-1),y*(ny-1),z*(nz-1), &(dif.x),&(dif.y), &(dif.z));
 		dif.x*=nx>1?nx-1:1;	dif.y*=ny>1?ny-1:1;	dif.z*=nz>1?nz-1:1;	return res;	}
-	
+
 	/// Get information about the data (sizes and momentum) to string
 	inline const char *PrintInfo() const	{	return mgl_data_info(this);	}
 	/// Print information about the data (sizes and momentum) to FILE (for example, stdout)
@@ -420,11 +446,11 @@ protected:
 #endif
 	/// Get the value in given cell of the data without border checking
 	inline mreal v(long i,long j=0,long k=0) const
-#ifdef DEBUG
+#ifndef DEBUG
+	{	return a[i+nx*(j+ny*k)];	}
+#else
 	{	if(i<0 || j<0 || k<0 || i>=nx || j>=ny || k>=nz)	printf("Wrong index in mglData");
 		return a[i+nx*(j+ny*k)];	}
-#else
-	{	return a[i+nx*(j+ny*k)];	}
 #endif
 	inline mreal vthr(long i) const {	return a[i];	}
 	// add for speeding up !!!
diff --git a/include/mgl2/data_cf.h b/include/mgl2/data_cf.h
index e827af3..964c330 100644
--- a/include/mgl2/data_cf.h
+++ b/include/mgl2/data_cf.h
@@ -20,7 +20,7 @@
 #ifndef _MGL_DATA_CF_H_
 #define _MGL_DATA_CF_H_
 //-----------------------------------------------------------------------------
-#include "mgl2/base.h"
+#include "mgl2/abstract.h"
 //-----------------------------------------------------------------------------
 #if MGL_HAVE_GSL
 #include <gsl/gsl_vector.h>
@@ -82,16 +82,16 @@ void MGL_EXPORT mgl_data_set_double(HMDT dat, const double *A,long mx,long my,lo
 void MGL_EXPORT mgl_data_set_double_(uintptr_t *dat, const double *A,int *NX,int *NY,int *NZ);
 void MGL_EXPORT mgl_data_set_double1_(uintptr_t *d, const double *A,int *N1);
 /// Allocate memory and copy the data from the (float **) array
-void MGL_EXPORT mgl_data_set_float2(HMDT d, const float **A,long N1,long N2);
+void MGL_EXPORT mgl_data_set_float2(HMDT d, float const * const *A,long N1,long N2);
 void MGL_EXPORT mgl_data_set_float2_(uintptr_t *d, const float *A,int *N1,int *N2);
 /// Allocate memory and copy the data from the (double **) array
-void MGL_EXPORT mgl_data_set_double2(HMDT d, const double **A,long N1,long N2);
+void MGL_EXPORT mgl_data_set_double2(HMDT d, double const * const *A,long N1,long N2);
 void MGL_EXPORT mgl_data_set_double2_(uintptr_t *d, const double *A,int *N1,int *N2);
 /// Allocate memory and copy the data from the (float ***) array
-void MGL_EXPORT mgl_data_set_float3(HMDT d, const float ***A,long N1,long N2,long N3);
+void MGL_EXPORT mgl_data_set_float3(HMDT d, float const * const * const *A,long N1,long N2,long N3);
 void MGL_EXPORT mgl_data_set_float3_(uintptr_t *d, const float *A,int *N1,int *N2,int *N3);
 /// Allocate memory and copy the data from the (double ***) array
-void MGL_EXPORT mgl_data_set_double3(HMDT d, const double ***A,long N1,long N2,long N3);
+void MGL_EXPORT mgl_data_set_double3(HMDT d, double const * const * const *A,long N1,long N2,long N3);
 void MGL_EXPORT mgl_data_set_double3_(uintptr_t *d, const double *A,int *N1,int *N2,int *N3);
 /// Import data from abstract type
 void MGL_EXPORT mgl_data_set(HMDT dat, HCDT a);
@@ -173,9 +173,24 @@ void MGL_EXPORT mgl_data_fill_(uintptr_t *dat, mreal *x1,mreal *x2,const char *d
 /// Modify the data by specified formula assuming x,y,z in range [r1,r2]
 void MGL_EXPORT mgl_data_fill_eq(HMGL gr, HMDT dat, const char *eq, HCDT vdat, HCDT wdat,const char *opt);
 void MGL_EXPORT mgl_data_fill_eq_(uintptr_t *gr, uintptr_t *dat, const char *eq, uintptr_t *vdat, uintptr_t *wdat,const char *opt, int, int);
+/// Fill dat by interpolated values of vdat parametrically depended on xdat for x in range [x1,x2]
+void MGL_EXPORT mgl_data_refill_x(HMDT dat, HCDT xdat, HCDT vdat, mreal x1, mreal x2, long sl);
+void MGL_EXPORT mgl_data_refill_x_(uintptr_t *dat, uintptr_t *xdat, uintptr_t *vdat, mreal *x1, mreal *x2, long *sl);
+/// Fill dat by interpolated values of vdat parametrically depended on xdat,ydat for x,y in range [x1,x2]*[y1,y2]
+void MGL_EXPORT mgl_data_refill_xy(HMDT dat, HCDT xdat, HCDT ydat, HCDT vdat, mreal x1, mreal x2, mreal y1, mreal y2, long sl);
+void MGL_EXPORT mgl_data_refill_xy_(uintptr_t *dat, uintptr_t *xdat, uintptr_t *ydat, uintptr_t *vdat, mreal *x1, mreal *x2, mreal *y1, mreal *y2, long *sl);
+/// Fill dat by interpolated values of vdat parametrically depended on xdat,ydat,zdat for x,y,z in range [x1,x2]*[y1,y2]*[z1,z2]
+void MGL_EXPORT mgl_data_refill_xyz(HMDT dat, HCDT xdat, HCDT ydat, HCDT zdat, HCDT vdat, mreal x1, mreal x2, mreal y1, mreal y2, mreal z1, mreal z2);
+void MGL_EXPORT mgl_data_refill_xyz_(uintptr_t *dat, uintptr_t *xdat, uintptr_t *ydat, uintptr_t *zdat, uintptr_t *vdat, mreal *x1, mreal *x2, mreal *y1, mreal *y2, mreal *z1, mreal *z2);
+/// Fill dat by interpolated values of vdat parametrically depended on xdat,ydat,zdat for x,y,z in axis range
+void MGL_EXPORT mgl_data_refill_gr(HMGL gr, HMDT dat, HCDT xdat, HCDT ydat, HCDT zdat, HCDT vdat, long sl, const char *opt);
+void MGL_EXPORT mgl_data_refill_gr_(uintptr_t *gr, uintptr_t *dat, uintptr_t *xdat, uintptr_t *ydat, uintptr_t *zdat, uintptr_t *vdat, long *sl, const char *opt,int);
 /// Set the data by triangulated surface values assuming x,y,z in range [r1,r2]
 void MGL_EXPORT mgl_data_grid(HMGL gr, HMDT d, HCDT xdat, HCDT ydat, HCDT zdat,const char *opt);
 void MGL_EXPORT mgl_data_grid_(uintptr_t *gr, uintptr_t *dat, uintptr_t *xdat, uintptr_t *ydat, uintptr_t *zdat, const char *opt,int);
+/// Set the data by triangulated surface values assuming x,y,z in range [x1,x2]*[y1,y2]
+void MGL_EXPORT mgl_data_grid_xy(HMDT d, HCDT xdat, HCDT ydat, HCDT zdat, mreal x1, mreal x2, mreal y1, mreal y2);
+void MGL_EXPORT mgl_data_grid_xy_(uintptr_t *dat, uintptr_t *xdat, uintptr_t *ydat, uintptr_t *zdat, mreal *x1, mreal *x2, mreal *y1, mreal *y2);
 /// Put value to data element(s)
 void MGL_EXPORT mgl_data_put_val(HMDT dat, mreal val, long i, long j, long k);
 void MGL_EXPORT mgl_data_put_val_(uintptr_t *dat, mreal *val, int *i, int *j, int *k);
@@ -309,13 +324,20 @@ void MGL_EXPORT mgl_data_cosfft_(uintptr_t *dat, const char *dir,int);
 /// Fill data by 'x'/'k' samples for Hankel ('h') or Fourier ('f') transform
 void MGL_EXPORT mgl_data_fill_sample(HMDT dat, const char *how);
 void MGL_EXPORT mgl_data_fill_sample_(uintptr_t *dat, const char *how,int);
+/// Find correlation between 2 data arrays
+HMDT MGL_EXPORT mgl_data_correl(HCDT dat1, HCDT dat2, const char *dir);
+uintptr_t MGL_EXPORT mgl_data_correl_(uintptr_t dat1, uintptr_t dat2, const char *dir,int);
 
 /// Allocate and prepare data for Fourier transform by nthr threads
 MGL_EXPORT void *mgl_fft_alloc(long n, void **space, long nthr);
+MGL_EXPORT void *mgl_fft_alloc_thr(long n);
 /// Free data for Fourier transform
 void MGL_EXPORT mgl_fft_free(void *wt, void **ws, long nthr);
+void MGL_EXPORT mgl_fft_free_thr(void *wt);
 /// Make Fourier transform of data x of size n and step s between points
-void MGL_EXPORT mgl_fft(double *x, long s, long n, const void *wt, void *ws, bool inv);
+void MGL_EXPORT mgl_fft(double *x, long s, long n, const void *wt, void *ws, int inv);
+/// Clear internal data for speeding up FFT and Hankel transforms
+void MGL_EXPORT mgl_clear_fft();
 
 /// Interpolate by cubic spline the data to given point x=[0...nx-1], y=[0...ny-1], z=[0...nz-1]
 mreal MGL_EXPORT mgl_data_spline(HCDT dat, mreal x,mreal y,mreal z);
@@ -395,28 +417,6 @@ void MGL_EXPORT mgl_data_add_num_(uintptr_t *dat, mreal *d);
 void MGL_EXPORT mgl_data_sub_num(HMDT dat, mreal d);
 void MGL_EXPORT mgl_data_sub_num_(uintptr_t *dat, mreal *d);
 
-/// Saves result of PDE solving (|u|^2) for "Hamiltonian" ham with initial conditions ini
-HMDT MGL_EXPORT mgl_pde_solve(HMGL gr, const char *ham, HCDT ini_re, HCDT ini_im, mreal dz, mreal k0,const char *opt);
-uintptr_t MGL_EXPORT mgl_pde_solve_(uintptr_t* gr, const char *ham, uintptr_t* ini_re, uintptr_t* ini_im, mreal *dz, mreal *k0,const char *opt,int,int);
-/// Saves result of PDE solving for "Hamiltonian" ham with initial conditions ini along a curve ray (must have nx>=7 - x,y,z,px,py,pz,tau or nx=5 - x,y,px,py,tau)
-HMDT MGL_EXPORT mgl_qo2d_solve(const char *ham, HCDT ini_re, HCDT ini_im, HCDT ray, mreal r, mreal k0, HMDT xx, HMDT yy);
-HMDT MGL_EXPORT mgl_qo2d_func(dual (*ham)(mreal u, mreal x, mreal y, mreal px, mreal py, void *par), void *par, HCDT ini_re, HCDT ini_im, HCDT ray, mreal r, mreal k0, HMDT xx, HMDT yy);
-uintptr_t MGL_EXPORT mgl_qo2d_solve_(const char *ham, uintptr_t* ini_re, uintptr_t* ini_im, uintptr_t* ray, mreal *r, mreal *k0, uintptr_t* xx, uintptr_t* yy, int);
-/// Saves result of PDE solving for "Hamiltonian" ham with initial conditions ini along a curve ray (must have nx>=7 - x,y,z,px,py,pz,tau or nx=5 - x,y,px,py,tau)
-HMDT MGL_EXPORT mgl_qo3d_solve(const char *ham, HCDT ini_re, HCDT ini_im, HCDT ray, mreal r, mreal k0, HMDT xx, HMDT yy, HMDT zz);
-HMDT MGL_EXPORT mgl_qo3d_func(dual (*ham)(mreal u, mreal x, mreal y, mreal z, mreal px, mreal py, mreal pz, void *par), void *par, HCDT ini_re, HCDT ini_im, HCDT ray, mreal r, mreal k0, HMDT xx, HMDT yy, HMDT zz);
-uintptr_t MGL_EXPORT mgl_qo3d_solve_(const char *ham, uintptr_t* ini_re, uintptr_t* ini_im, uintptr_t* ray, mreal *r, mreal *k0, uintptr_t* xx, uintptr_t* yy, uintptr_t* zz, int);
-/// Saves result of ODE solving of n equations with right part func and initial conditions x0 over time interval [0,tmax] with time step dt
-HMDT MGL_EXPORT mgl_ode_solve(void (*func)(const mreal *x, mreal *dx, void *par), int n, mreal *x0, mreal dt, mreal tmax, void *par);
-/// Finds ray with starting point r0, p0 (and prepares ray data for mgl_qo2d_solve)
-HMDT MGL_EXPORT mgl_ray_trace(const char *ham, mreal x0, mreal y0, mreal z0, mreal px, mreal py, mreal pz, mreal dt, mreal tmax);
-uintptr_t MGL_EXPORT mgl_ray_trace_(const char *ham, mreal *x0, mreal *y0, mreal *z0, mreal *px, mreal *py, mreal *pz, mreal *dt, mreal *tmax,int);
-/// Calculate Jacobian determinant for D{x(u,v), y(u,v)} = dx/du*dy/dv-dx/dv*dy/du
-HMDT MGL_EXPORT mgl_jacobian_2d(HCDT x, HCDT y);
-uintptr_t MGL_EXPORT mgl_jacobian_2d_(uintptr_t* x, uintptr_t* y);
-/// Calculate Jacobian determinant for D{x(u,v,w), y(u,v,w), z(u,v,w)}
-HMDT MGL_EXPORT mgl_jacobian_3d(HCDT x, HCDT y, HCDT z);
-uintptr_t MGL_EXPORT mgl_jacobian_3d_(uintptr_t* x, uintptr_t* y, uintptr_t* z);
 /// Integral data transformation (like Fourier 'f' or 'i', Hankel 'h' or None 'n') for amplitude and phase
 HMDT MGL_EXPORT mgl_transform_a(HCDT am, HCDT ph, const char *tr);
 uintptr_t MGL_EXPORT mgl_transform_a_(uintptr_t *am, uintptr_t *ph, const char *tr, int);
diff --git a/include/mgl2/datac.h b/include/mgl2/datac.h
index 5661e55..5d7e414 100644
--- a/include/mgl2/datac.h
+++ b/include/mgl2/datac.h
@@ -31,7 +31,7 @@
 #define mgl4 	mreal(4)
 //-----------------------------------------------------------------------------
 /// Class for working with data array
-class mglDataC : public mglDataA
+class MGL_EXPORT mglDataC : public mglDataA
 {
 public:
 
@@ -162,6 +162,13 @@ public:
 	inline void Fill(dual x1,dual x2=NaN,char dir='x')
 	{	return mgl_datac_fill(this,x1,x2,dir);	}
 
+		/// Put value to data element(s)
+	inline void Put(dual val, long i=-1, long j=-1, long k=-1)
+	{	mgl_datac_put_val(this,val,i,j,k);	}
+	/// Put array to data element(s)
+	inline void Put(const mglDataA &dat, long i=-1, long j=-1, long k=-1)
+	{	mgl_datac_put_dat(this,&dat,i,j,k);	}
+
 	/// Set names for columns (slices)
 	inline void SetColumnId(const char *ids)
 	{	mgl_datac_set_id(this,ids);	}
@@ -256,6 +263,13 @@ public:
 	inline mglData Evaluate(const mglData &idat, const mglData &jdat, const mglData &kdat, bool norm=true) const
 	{	return mglData(true,mgl_data_evaluate(this,&idat,&jdat,&kdat,norm));	}
 
+	/// Find correlation with another data arrays
+	inline mglDataC Correl(const mglData &dat, const char *dir) const
+	{	return mglDataC(true,mgl_datac_correl(this,&dat,dir));	}
+	/// Find auto correlation function
+	inline mglDataC AutoCorrel(const char *dir) const
+	{	return mglDataC(true,mgl_datac_correl(this,this,dir));	}
+
 	/// Cumulative summation the data in given direction or directions
 	inline void CumSum(const char *dir)	{	mgl_datac_cumsum(this,dir);	}
 	/// Integrate (cumulative summation) the data in given direction or directions
@@ -280,6 +294,12 @@ public:
 	/// Fourier transform
 	inline void FFT(const char *dir)	{	mgl_datac_fft(this,dir);	}
 
+	/// Interpolate by cubic spline the data to given point x=[0...nx-1], y=[0...ny-1], z=[0...nz-1]
+	inline dual Spline(mreal x,mreal y=0,mreal z=0) const
+	{	return mgl_datac_spline(this, x,y,z);	}
+	/// Interpolate by cubic spline the data to given point x,\a y,\a z which normalized in range [0, 1]
+	inline dual Spline1(mreal x,mreal y=0,mreal z=0) const
+	{	return mgl_datac_spline(this, x*(nx-1),y*(ny-1),z*(nz-1));	}
 	/// Interpolate by linear function the data to given point x=[0...nx-1], y=[0...ny-1], z=[0...nz-1]
 	inline dual Linear(mreal x,mreal y=0,mreal z=0)	const
 	{	return mgl_datac_linear(this,x,y,z);	}
@@ -371,6 +391,11 @@ protected:
 	return k>0? abs(k<nz-1? (a[i0+n]-a[i0-n])/mgl2:a[i0]-a[i0-n]) : abs(a[i0+n]-a[i0]);	}
 };
 //-----------------------------------------------------------------------------
+#ifndef SWIG
+dual mglLinearC(const dual *a, long nx, long ny, long nz, mreal x, mreal y, mreal z);
+dual mglSpline3C(const dual *a, long nx, long ny, long nz, mreal x, mreal y, mreal z,dual *dx=0, dual *dy=0, dual *dz=0);
+#endif
+//-----------------------------------------------------------------------------
 #define _DN_(a)	((mglDataC *)*(a))
 #define _DC_		((mglDataC *)*d)
 //-----------------------------------------------------------------------------
diff --git a/include/mgl2/datac_cf.h b/include/mgl2/datac_cf.h
index a6925d8..89490a1 100644
--- a/include/mgl2/datac_cf.h
+++ b/include/mgl2/datac_cf.h
@@ -20,7 +20,7 @@
 #ifndef _MGL_DATAC_CF_H_
 #define _MGL_DATAC_CF_H_
 //-----------------------------------------------------------------------------
-#include "mgl2/base.h"
+#include "mgl2/abstract.h"
 //-----------------------------------------------------------------------------
 #if MGL_HAVE_GSL
 #include <gsl/gsl_vector.h>
@@ -142,6 +142,13 @@ void MGL_EXPORT mgl_datac_modify_(uintptr_t *dat, const char *eq,int *dim,int);
 void MGL_EXPORT mgl_datac_modify_vw(HADT dat, const char *eq,HCDT vdat,HCDT wdat);
 void MGL_EXPORT mgl_datac_modify_vw_(uintptr_t *dat, const char *eq, uintptr_t *vdat, uintptr_t *wdat,int);
 
+/// Put value to data element(s)
+void MGL_EXPORT mgl_datac_put_val(HADT dat, dual val, long i, long j, long k);
+void MGL_EXPORT mgl_datac_put_val_(uintptr_t *dat, dual *val, int *i, int *j, int *k);
+/// Put array to data element(s)
+void MGL_EXPORT mgl_datac_put_dat(HADT dat, HCDT val, long i, long j, long k);
+void MGL_EXPORT mgl_datac_put_dat_(uintptr_t *dat, uintptr_t *val, int *i, int *j, int *k);
+
 /// Reduce size of the data
 void MGL_EXPORT mgl_datac_squeeze(HADT dat, long rx,long ry,long rz,long smooth);
 void MGL_EXPORT mgl_datac_squeeze_(uintptr_t *dat, int *rx,int *ry,int *rz,int *smooth);
@@ -192,6 +199,9 @@ void MGL_EXPORT mgl_datac_hankel_(uintptr_t *dat, const char *dir,int);
 /// Apply Fourier transform
 void MGL_EXPORT mgl_datac_fft(HADT dat, const char *dir);
 void MGL_EXPORT mgl_datac_fft_(uintptr_t *dat, const char *dir,int);
+/// Find correlation between 2 data arrays
+HADT MGL_EXPORT mgl_datac_correl(HCDT dat1, HCDT dat2, const char *dir);
+uintptr_t MGL_EXPORT mgl_datac_correl_(uintptr_t dat1, uintptr_t dat2, const char *dir,int);
 
 HMDT MGL_EXPORT mgl_datac_real(HCDT dat);
 uintptr_t MGL_EXPORT mgl_datac_real_(uintptr_t *dat);
@@ -208,6 +218,12 @@ dual MGL_EXPORT mgl_datac_linear_(uintptr_t *d, mreal *x,mreal *y,mreal *z);
 /// Interpolate by linear function the data and return its derivatives at given point x=[0...nx-1], y=[0...ny-1], z=[0...nz-1]
 dual MGL_EXPORT mgl_datac_linear_ext(HCDT d, mreal x,mreal y,mreal z, dual *dx,dual *dy,dual *dz);
 dual MGL_EXPORT mgl_datac_linear_ext_(uintptr_t *d, mreal *x,mreal *y,mreal *z, dual *dx,dual *dy,dual *dz);
+/// Interpolate by cubic spline the data to given point x=[0...nx-1], y=[0...ny-1], z=[0...nz-1]
+dual MGL_EXPORT mgl_datac_spline(HCDT dat, mreal x,mreal y,mreal z);
+dual MGL_EXPORT mgl_datac_spline_(uintptr_t *dat, mreal *x,mreal *y,mreal *z);
+/// Interpolate by cubic spline the data and return its derivatives at given point x=[0...nx-1], y=[0...ny-1], z=[0...nz-1]
+dual MGL_EXPORT mgl_datac_spline_ext(HCDT dat, mreal x,mreal y,mreal z, dual *dx,dual *dy,dual *dz);
+dual MGL_EXPORT mgl_datac_spline_ext_(uintptr_t *dat, mreal *x,mreal *y,mreal *z, dual *dx,dual *dy,dual *dz);
 
 #ifdef __cplusplus
 }
diff --git a/include/mgl2/define.h b/include/mgl2/define.h
index aa23043..55c6d58 100644
--- a/include/mgl2/define.h
+++ b/include/mgl2/define.h
@@ -21,9 +21,14 @@
 #define _MGL_DEFINE_H_
 //-----------------------------------------------------------------------------
 #include "mgl2/config.h"
+#ifndef SWIG
 #include "mgl2/dllexport.h"
+#if MGL_HAVE_OMP
+#include <omp.h>
+#endif
+#endif
 
-#define MGL_VER2 	1.3
+#define MGL_VER2 	2.0	// minor version of MathGL 2.* (like 1.3 for v.2.1.3)
 //-----------------------------------------------------------------------------
 #ifdef WIN32 //_MSC_VER needs this before math.h
 #define	_USE_MATH_DEFINES
@@ -46,6 +51,22 @@
 #endif
 #endif
 
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+typedef signed char int8_t;
+typedef signed short int16_t;
+typedef signed long int32_t;
+typedef signed long long int64_t;
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned long uint32_t;
+typedef unsigned long long uint64_t;
+#else
+#include <stdint.h>
+#endif
+#if defined(__BORLANDC__)
+typedef unsigned long uintptr_t;
+#endif
+
 #include <math.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -58,6 +79,8 @@
 #endif
 
 #if defined(_MSC_VER)
+#define collapse(a)	// MSVS don't support OpenMP 3.*
+#define strtoull _strtoui64
 #define hypot	_hypot
 #define getcwd	_getcwd
 #define chdir	_chdir // BORLAND has chdir
@@ -108,6 +131,10 @@ typedef float mreal;
 #define mgl_min(a,b)	(((a)>(b)) ? (b) : (a))
 #define mgl_max(a,b)	(((a)>(b)) ? (a) : (b))
 #define mgl_isnan(a)	((a)!=(a))
+//#define mgl_isnum(a)	((a)==(a) && 2*(a)!=(a))
+#define mgl_isnum(a)	((a)==(a))
+#define mgl_isfin(a)	((a)-(a)==0.)
+#define mgl_isbad(a)	((a)-(a)!=0.)
 //-----------------------------------------------------------------------------
 #define SMOOTH_NONE		0
 #define SMOOTH_LINE_3	1
@@ -141,6 +168,8 @@ enum{	// types of predefined curvelinear coordinate systems
 #define MGL_DRAW_FAST	1	// fast, no color interpolation
 #define MGL_DRAW_NORM	2	// high quality, slower
 #define MGL_DRAW_LMEM	4	// low memory usage (direct to pixel)
+#define MGL_DRAW_DOTS	8	// draw dots instead of primitives
+#define MGL_DRAW_NONE	9	// no ouput (for testing only)
 //-----------------------------------------------------------------------------
 enum{	// Codes for warnings/messages
 	mglWarnNone = 0,// Everything OK
@@ -160,6 +189,10 @@ enum{	// Codes for warnings/messages
 	mglWarnTern, 	// Axis ranges are incompatible
 	mglWarnNull, 	// Pointer is NULL
 	mglWarnSpc,		// Not enough space for plot
+	mglScrArg,		// Wrong argument(s) in MGL script
+	mglScrCmd,		// Wrong command in MGL script
+	mglScrLong,		// Too long line in MGL script
+	mglScrStr,		// Unbalanced ' in MGL script
 	mglWarnEnd		// Maximal number of warnings (must be last)
 };
 //-----------------------------------------------------------------------------
@@ -184,7 +217,7 @@ enum{	// Codes for warnings/messages
 #define MGL_SHOW_POS		0x001000 	///< Switch to show or not mouse click position
 #define MGL_CLF_ON_UPD		0x002000 	///< Clear plot before Update()
 #define MGL_NOSUBTICKS		0x004000 	///< Disable subticks drawing (for bounding box)
-#define MGL_DIFFUSIVE		0x008000 	///< Use diffusive light instead of specular
+//#define MGL_DIFFUSIVE		0x008000 	///< Use diffusive light instead of specular
 #define MGL_VECT_FRAME		0x010000 	///< Use DrwDat to remember all data of frames
 #define MGL_REDUCEACC		0x020000 	///< Reduce accuracy of points (to reduc size of output files)
 #define MGL_PREFERVC 		0x040000 	///< Prefer vertex color instead of texture if output format supports
@@ -193,66 +226,11 @@ enum{	// Codes for warnings/messages
 //-----------------------------------------------------------------------------
 #ifdef __cplusplus
 //-----------------------------------------------------------------------------
+extern float mgl_cos[360];	///< contain cosine with step 1 degree
+//-----------------------------------------------------------------------------
 #include <complex>
 typedef std::complex<mreal> dual;
 //-----------------------------------------------------------------------------
-struct mglThreadD
-{
-	mreal *a;		// float* array with parameters or results
-	const mreal *b,*c,*d,*e;	// float* arrays with parameters
-	const long *p;	// long* array with parameters
-	const void *v;	// pointer to data/grapher
-	int id;			// thread id
-	long n;			// total number of iteration
-	const char *s;
-};
-struct mglThreadC
-{
-	dual *a;		// dual* array with parameters or results
-	const dual *b,*c,*d,*e;	// dual* arrays with parameters
-	const long *p;	// long* array with parameters
-	const void *v;	// pointer to data/grapher
-	int id;			// thread id
-	long n;			// total number of iteration
-	const char *s;
-};
-struct mglThreadV
-{
-	mreal *a;		// float* array with parameters or results
-	dual *aa;		// dual* array with parameters or results
-	const void *b,*c;	// float* arrays with parameters
-	const mreal *d;	// float* arrays with parameters
-	const long *p;	// long* array with parameters
-	const void *v;	// pointer to data/grapher
-	int id;			// thread id
-	long n;			// total number of iteration
-};
-struct mglThreadT
-{
-	void *a; 		// dual* or mreal* array with input or results
-	double *b; 		// dual* array with input or results
-	const long *p;	// long* array with parameters
-	const void *v;	// pointer to table/parameter
-	void **w; 		// pointer to workspace
-	int id;			// thread id
-	long n;			// total number of iteration
-	const void *re,*im;
-};
-/// Start several thread for the task
-void MGL_EXPORT mglStartThread(void *(*func)(void *), void (*post)(mglThreadD *,mreal *), long n,
-					mreal *a=0, const mreal *b=0, const mreal *c=0, const long *p=0,
-					const void *v=0, const mreal *d=0, const mreal *e=0, const char *s=0);
-void MGL_EXPORT mglStartThreadV(void *(*func)(void *), long n, mreal *a, const void *b=0,
-					const void *c=0, const long *p=0, const void *v=0, const mreal *d=0);
-void MGL_EXPORT mglStartThreadV(void *(*func)(void *), long n, dual *a, const void *b=0,
-					const void *c=0, const long *p=0, const void *v=0, const mreal *d=0);
-void MGL_EXPORT mglStartThreadC(void *(*func)(void *), void (*post)(mglThreadC *,dual *), long n,
-					dual *a=0, const dual *b=0, const dual *c=0, const long *p=0,
-					const void *v=0, const dual *d=0, const dual *e=0, const char *s=0);
-void MGL_EXPORT mglStartThreadT(void *(*func)(void *), long n, void *a, double *b, const void *v=0,
-					void **w=0, const long *p=0, const void *re=0, const void *im=0);
-MGL_EXPORT extern int mglNumThr;		///< Number of thread for plotting and data handling
-//-----------------------------------------------------------------------------
 extern "C" {
 #else
 #include <complex.h>
@@ -262,12 +240,16 @@ typedef double _Complex dual;
 typedef float _Complex dual;
 #endif
 #endif
+/// Find length of wchar_t string (bypass standard wcslen bug)
+size_t MGL_EXPORT mgl_wcslen(const wchar_t *str);
 /// Get RGB values for given color id or fill by -1 if no one found
 void MGL_EXPORT mgl_chrrgb(char id, float rgb[3]);
 /// Check if string contain color id and return its number
 long MGL_EXPORT mgl_have_color(const char *stl);
 /// Find symbol in string excluding {} and return its position or NULL
 const char *mglchr(const char *str, char ch);
+/// Find any symbol from chr in string excluding {} and return its position or NULL
+const char *mglchrs(const char *str, const char *chr);
 /// Set number of thread for plotting and data handling
 void MGL_EXPORT mgl_set_num_thr(int n);
 void MGL_EXPORT mgl_test_txt(const char *str, ...);
@@ -280,16 +262,11 @@ void MGL_EXPORT mgl_strlwr(char *str);
 void MGL_EXPORT mgl_wcslwr(wchar_t *str);
 /// Convert wchar_t* string into char* one
 void MGL_EXPORT mgl_wcstombs(char *dst, const wchar_t *src, int size);
+/// Clear internal data for speeding up FFT and Hankel transforms
+void MGL_EXPORT mgl_clear_fft();
 #ifdef __cplusplus
 }
 #endif
-//#if MGL_HAVE_PTHREAD && defined(MGL_SRC)
-#if MGL_HAVE_PTHREAD
-#include <pthread.h>
-#define MGL_PUSH(a,v,m)		{pthread_mutex_lock(&m);	a.push_back(v);	pthread_mutex_unlock(&m);}
-#else
-#define MGL_PUSH(a,v,m)		a.push_back(v);
-#endif
 //-----------------------------------------------------------------------------
 #endif
 //-----------------------------------------------------------------------------
diff --git a/include/mgl2/eval.h b/include/mgl2/eval.h
index a8d780f..1f5cfc6 100644
--- a/include/mgl2/eval.h
+++ b/include/mgl2/eval.h
@@ -29,7 +29,7 @@
 const int MGL_VS = 'z'-'a'+1;
 //-----------------------------------------------------------------------------
 /// Class for evaluating formula specified by the string
-class mglFormula					// îáúåêò äëÿ ââîäà è âû÷èñëåíèÿ ôîðìóë
+class MGL_EXPORT mglFormula					// îáúåêò äëÿ ââîäà è âû÷èñëåíèÿ ôîðìóë
 {
 public:
 	/// Evaluates the formula for 'x','r'=\a x, 'y','n'=\a y, 'z','t'=\a z, 'u'=\a u
diff --git a/include/mgl2/evalc.h b/include/mgl2/evalc.h
index 3b0469b..800688b 100644
--- a/include/mgl2/evalc.h
+++ b/include/mgl2/evalc.h
@@ -23,7 +23,7 @@
 #include "mgl2/eval.h"
 //-----------------------------------------------------------------------------
 /// Class for evaluating formula specified by the string
-class mglFormulaC					// ������ ��� ����� � ���������� ������
+class MGL_EXPORT mglFormulaC					// ������ ��� ����� � ���������� ������
 {
 public:
 	/// Evaluates the formula for 'x','r'=\a x, 'y','n'=\a y, 'z','t'=\a z, 'u'=\a u
diff --git a/include/mgl2/fit.h b/include/mgl2/fit.h
index 8ab759a..26c7932 100644
--- a/include/mgl2/fit.h
+++ b/include/mgl2/fit.h
@@ -19,7 +19,7 @@
  ***************************************************************************/
 #ifndef _MGL_FIT_H_
 #define _MGL_FIT_H_
-#include "mgl2/base.h"
+#include "mgl2/abstract.h"
 //-----------------------------------------------------------------------------
 #ifdef __cplusplus
 extern "C" {
diff --git a/include/mgl2/fltk.h b/include/mgl2/fltk.h
index 75f45a5..bfc9813 100644
--- a/include/mgl2/fltk.h
+++ b/include/mgl2/fltk.h
@@ -21,7 +21,7 @@
 #ifndef _MGL_FLTK_H_
 #define _MGL_FLTK_H_
 
-#include <mgl2/base.h>
+#include <mgl2/abstract.h>
 //-----------------------------------------------------------------------------
 #ifdef __cplusplus
 extern "C" {
@@ -40,7 +40,7 @@ int MGL_EXPORT mgl_fltk_thr();
 #include <mgl2/wnd.h>
 //-----------------------------------------------------------------------------
 /// Wrapper class for windows displaying graphics
-class mglFLTK : public mglWnd
+class MGL_EXPORT mglFLTK : public mglWnd
 {
 public:
 	mglFLTK(const char *title="MathGL") : mglWnd()
@@ -69,7 +69,7 @@ public:
 class mglCanvas;
 //-----------------------------------------------------------------------------
 /// Class is FLTK widget which display MathGL graphics
-class Fl_MathGL : public Fl_Widget
+class MGL_EXPORT Fl_MathGL : public Fl_Widget
 {
 public:
 	Fl_Valuator	*tet_val;	///< pointer to external tet-angle validator
@@ -91,9 +91,9 @@ public:
 	/// Get pointer to grapher
 	inline HMGL get_graph()	{	return (HMGL)gr;	}
 	/// Set drawing functions and its parameter
-	inline void set_draw(int (*func)(mglBase *gr, void *par), void *par=0)
-	{	draw_func = func;	draw_par = par;	}
-	inline void set_draw(mglDraw *dr)	{	draw_cl = dr;	}
+	inline void set_draw(int (*func)(mglBase *gr, void *par), void *par)
+	{	if(draw_cl)	delete draw_cl;	draw_cl=0;	draw_func=func;	draw_par=par;	}
+	inline void set_draw(mglDraw *dr)	{	if(draw_cl)	delete draw_cl;	draw_cl=dr;	draw_func=0;	}
 	inline void set_draw(int (*dr)(mglGraph *gr))
 	{	set_draw(dr?mgl_draw_graph:0,(void*)dr);	}
 	void set_state(bool z, bool r)	{	zoom = z;	rotate = r;	}
@@ -108,7 +108,7 @@ public:
 	{	popup = pmenu;	wpar = wdg;	vpar = v;	}
 	inline void zoom_region(mreal xx1,mreal xx2,mreal yy1, mreal yy2)
 	{	x1=xx1;	y1=yy1;	x2=xx2;	y2=yy2;	}
-	
+
 protected:
 	mglCanvas *gr;		///< pointer to grapher
 	void *draw_par;		///< Parameters for drawing function mglCanvasWnd::DrawFunc.
@@ -133,7 +133,7 @@ protected:
 	void resize(int x, int y, int w, int h);	///< resize control
 };
 //-----------------------------------------------------------------------------
-class Fl_MGLView : public Fl_Window
+class MGL_EXPORT Fl_MGLView : public Fl_Window
 {
 public:
 	Fl_MathGL *FMGL;		///< Control which draw graphics
@@ -155,6 +155,8 @@ public:
 	void setoff_zoom()	{	setoff(zoom, zoom_bt);	}
 	void setoff_rotate(){	setoff(rotate, rotate_bt);	}
 	bool is_sshow()		{	return sshow;	}
+	void adjust()
+	{	mgl_set_size(FMGL->get_graph(),scroll->w(),scroll->h());	FMGL->size(scroll->w(),scroll->h());	update();	}
 
 	Fl_MGLView(int x, int y, int w, int h, const char *label=0);
 	~Fl_MGLView();
diff --git a/include/mgl2/font.h b/include/mgl2/font.h
index 1a6ab79..ab6bdbe 100644
--- a/include/mgl2/font.h
+++ b/include/mgl2/font.h
@@ -22,6 +22,7 @@
 #define _MGL_FONT_H_
 
 #include "mgl2/define.h"
+#include <vector>
 //-----------------------------------------------------------------------------
 #define MGL_FONT_BOLD		0x01000000	// This value is used binary
 #define MGL_FONT_ITAL		0x02000000	// This value is used binary
@@ -43,14 +44,14 @@
 #define MGL_DEF_FONT_NAME	"STIX"
 #endif
 //-----------------------------------------------------------------------------
-struct mglTeXsymb	{	unsigned kod;	const wchar_t *tex;	};
+struct MGL_EXPORT mglTeXsymb	{	unsigned kod;	const wchar_t *tex;	};
 const float mgl_fgen = 4*14;
 /// Get font color, style and align for internal parser
 char mglGetStyle(const char *how, int *font, int *align=0);
 class mglBase;
 //-----------------------------------------------------------------------------
 /// Class for font typeface and text plotting procedures
-class mglFont
+class MGL_EXPORT mglFont
 {
 public:
 	mglBase *gr;	///< mglBase class used for drawing characters
@@ -94,16 +95,16 @@ public:
 	inline short GetWidth(int s, long j) const	{	return width[s][j];	}
 	inline float GetFact(int s) const		{	return fact[s];	}
 protected:
-	wchar_t *id;		///< Unicode ID for glyph
-	unsigned *tr[4];	///< Shift of glyph description by triangles (for solid font)
-	unsigned *ln[4];	///< Shift of glyph description by lines (for wire font)
-	short *numt[4];		///< Number of triangles in glyph description (for solid font)
-	short *numl[4];		///< Number of lines in glyph description (for wire font)
-	short *width[4];	///< Width of glyph for wire font
-	float fact[4];		///< Divider for width of glyph
-	unsigned numg;		///< Number of glyphs
-	short *Buf;			///< Buffer for glyph descriptions
-	long numb;			///< Buffer size
+	wchar_t *id;	///< Unicode ID for glyph
+	int *tr[4];		///< Shift of glyph description by triangles (for solid font)
+	int *ln[4];		///< Shift of glyph description by lines (for wire font)
+	short *numt[4];	///< Number of triangles in glyph description (for solid font)
+	short *numl[4];	///< Number of lines in glyph description (for wire font)
+	short *width[4];///< Width of glyph for wire font
+	float fact[4];	///< Divider for width of glyph
+	unsigned numg;	///< Number of glyphs
+	short *Buf;		///< Buffer for glyph descriptions
+	long numb;		///< Buffer size
 
 	/// Print text string for font specified by integer constant
 	float Puts(const wchar_t *str,int font,int align, float col) const;
@@ -121,11 +122,11 @@ protected:
 	unsigned Symbol(char ch) const;
 private:
 	float get_ptr(long &i,unsigned *str, unsigned **b1, unsigned **b2,float &w1,float &w2, float f1, float f2, int st) const;
-	bool read_data(const char *fname, float *ff, short *wdt, short *numl, unsigned *posl, short *numt, unsigned *post, unsigned &cur);
+	bool read_data(const char *fname, float *ff, short *wdt, short *numl, int *posl, short *numt, int *post, std::vector<short> &buf);
 	void main_copy();
-	bool read_main(const char *fname, unsigned &cur);
+	bool read_main(const char *fname, std::vector<short> &buf);
 	void mem_alloc();
-	bool read_def(unsigned &cur);
+	bool read_def();
 	void draw_ouline(int st, float x, float y, float f, float g, float ww, float ccol) const;
 };
 //-----------------------------------------------------------------------------
diff --git a/include/mgl2/glut.h b/include/mgl2/glut.h
index 2a23ab1..baabcba 100644
--- a/include/mgl2/glut.h
+++ b/include/mgl2/glut.h
@@ -30,7 +30,7 @@ HMGL MGL_EXPORT mgl_create_graph_glut(int (*draw)(HMGL gr, void *p), const char
 #ifdef __cplusplus
 }
 //-----------------------------------------------------------------------------
-class mglGLUT: public mglGraph
+class MGL_EXPORT mglGLUT: public mglGraph
 {
 public:
 	mglGLUT(int (*draw)(HMGL gr, void *p), const char *title="MathGL", void *par=0, void (*load)(void *p)=0) : mglGraph(-1)
diff --git a/include/mgl2/mgl.h b/include/mgl2/mgl.h
index 713823f..2dfe4e6 100644
--- a/include/mgl2/mgl.h
+++ b/include/mgl2/mgl.h
@@ -21,11 +21,12 @@
 #define _MGL_H_
 
 #include "mgl2/mgl_cf.h"
+#ifdef __cplusplus
 #include "mgl2/data.h"
 #include "mgl2/datac.h"
 //-----------------------------------------------------------------------------
 /// Wrapper class for all graphics
-class mglGraph
+class MGL_EXPORT mglGraph
 {
 protected:
 	HMGL gr;
@@ -56,7 +57,7 @@ public:
 	inline void SetPlotId(const char *id)	{	mgl_set_plotid(gr,id);	}
 	/// Get name of plot for saving filename
 	inline const char *GetPlotId()	{	return mgl_get_plotid(gr);	}
-	
+
 	/// Set the transparency on/off.
 	inline void Alpha(bool enable)			{	mgl_set_alpha(gr, enable);	}
 	/// Set default value of alpha-channel
@@ -68,7 +69,7 @@ public:
 	inline void Light(bool enable)			{	mgl_set_light(gr, enable);	}
 	/// Switch on/off the specified light source.
 	inline void Light(int n,bool enable)	{	mgl_set_light_n(gr, n, enable);	}
-	/// Use diffusive light (only for local light sources)
+	/// Use diffusive light (only for local light sources) -- OBSOLETE
 	inline void SetDifLight(bool dif)		{	mgl_set_light_dif(gr, dif);	}
 	/// Add a light source.
 	inline void AddLight(int n, mglPoint p, char col='w', double bright=0.5, double ap=0)
@@ -77,6 +78,8 @@ public:
 	{	mgl_add_light_loc(gr, n, r.x, r.y, r.z, p.x, p.y, p.z, col, bright, ap);	}
 	/// Set ambient light brightness
 	inline void SetAmbient(double i)			{	mgl_set_ambbr(gr, i);	}
+	/// Set diffusive light brightness
+	inline void SetDiffuse(double i)			{	mgl_set_difbr(gr, i);	}
 	/// Set the fog distance or switch it off (if d=0).
 	inline void Fog(double d, double dz=0.25)	{	mgl_set_fog(gr, d, dz);		}
 
@@ -90,7 +93,7 @@ public:
 	inline void SetMeshNum(int num)			{	mgl_set_meshnum(gr, num);	}
 	/// Set number of visible faces (use 0 to draw all of them)
 	inline void SetFaceNum(int num)			{	mgl_set_facenum(gr, num);	}
-	
+
 	/// Set cutting for points outside of bounding box
 	inline void SetCut(bool cut)				{	mgl_set_cut(gr, cut);	}
 	/// Set additional cutting box
@@ -124,6 +127,15 @@ public:
 	/// Set default color scheme
 	inline void SetDefScheme(const char *sch)	{	mgl_set_def_sch(gr, sch);	}
 
+	/// Sets RGB values for color with given id
+	static inline void SetColor(char id, double r, double g, double b)	{	mgl_set_color(id, r, g, b);	}
+	/// Set mask for face coloring as array of type 'unsigned char[8]'
+	static inline void SetMask(char id, const char *mask)	{	mgl_set_mask(id, mask);	}
+	/// Set mask for face coloring as uint64_t number
+	static inline void SetMask(char id, uint64_t mask)	{	mgl_set_mask_val(id, mask);	}
+	/// Set default mask rotation angle
+	inline void SetMaskAngle(int angle)	{	mgl_set_mask_angle(gr, angle);	}
+
 	/// Get last warning code
 	inline int  GetWarn()	{	return mgl_get_warn(gr);}
 	/// Set warning code ant fill message
@@ -224,7 +236,7 @@ public:
 	/// Set to draw tick labels at axis origin
 	inline void SetOriginTick(bool enable=true)
 	{	mgl_set_flag(gr,!enable, MGL_NO_ORIGIN);	}
-	
+
 	/// Put further plotting in some region of whole frame.
 	inline void SubPlot(int nx,int ny,int m,const char *style="<>_^", double dx=0, double dy=0)
 	{	mgl_subplot_d(gr, nx, ny, m, style, dx, dy);	}
@@ -252,7 +264,7 @@ public:
 	inline void Push()	{	mgl_mat_push(gr);	}
 	/// Pop transformation matrix from stack
 	inline void Pop()	{	mgl_mat_pop(gr);	}
-	
+
 	/// Add title for current subplot/inplot
 	inline 	void Title(const char *title,const char *stl="",double size=-2)
 	{	mgl_title(gr,title,stl,size);	}
@@ -283,6 +295,8 @@ public:
 	inline void SetQuality(int qual=MGL_DRAW_NORM)	{	mgl_set_quality(gr, qual);	}
 	/// Get plot quality
 	inline int GetQuality()	{	return mgl_get_quality(gr);	}
+	/// Set drawing region for Quality&4
+	inline void SetDrawReg(long nx=1, long ny=1, long m=0)	{	mgl_set_draw_reg(gr,nx,ny,m);	}
 	/// Start group of objects
 	inline void StartGroup(const char *name)		{	mgl_start_group(gr, name);	}
 	/// End group of objects
@@ -347,8 +361,11 @@ public:
 	inline void WritePRC(const char *fname,const char *descr="",bool make_pdf=true)
 	{	mgl_write_prc(gr, fname, descr, make_pdf);	}
 	/// Export in JSON format suitable for later drawing by JavaScript
-	inline void WriteJSON(const char *fname,const char *descr="")
-	{	mgl_write_json(gr, fname, descr);	}
+	inline void WriteJSON(const char *fname,const char *descr="",bool force_z=false)
+	{	if(force_z)	mgl_write_json_z(gr, fname, descr);
+		else 	mgl_write_json(gr, fname, descr);	}
+	/// Return string of JSON data suitable for later drawing by JavaScript
+	inline const char *GetJSON()	{	return mgl_get_json(gr);	}
 
 	/// Force preparing the image. It can be useful for OpenGL mode mostly.
 	inline void Finish()			{	mgl_finish(gr);	}
@@ -368,7 +385,7 @@ public:
 	inline void SetFrame(int i)	{	mgl_set_frame(gr, i);	}
 	/// Append drawing data from i-th frame (work if MGL_VECT_FRAME is set on)
 	inline void ShowFrame(int i){	mgl_show_frame(gr, i);	}
-	
+
 	/// Start write frames to cinema using GIF format
 	inline void StartGIF(const char *fname, int ms=100)
 	{	mgl_start_gif(gr, fname,ms);	}
@@ -440,6 +457,7 @@ public:
 
 	/// Clear up the frame
 	inline void Clf(double r, double g, double b)	{	mgl_clf_rgb(gr, r, g, b);	}
+	inline void Clf(char col)	{	mgl_clf_chr(gr, col);	}
 	inline void Clf()	{	mgl_clf(gr);	}
 	/// Clear unused points and primitives. Useful only in combination with SetFaceNum().
 	inline void ClearUnused()	{	mgl_clear_unused(gr);	}
@@ -628,6 +646,13 @@ public:
 	/// Draw chart for data a
 	inline void Chart(const mglDataA &a, const char *colors="", const char *opt="")
 	{	mgl_chart(gr, &a, colors,opt);	}
+
+	/// Draw Open-High-Low-Close (OHLC) diagram
+	inline void OHLC(const mglDataA &x, const mglDataA &open, const mglDataA &high, const mglDataA &low, const mglDataA &close, const char *pen="", const char *opt="")
+	{	mgl_ohlc_x(gr, &x, &open,&high,&low,&close,pen,opt);	}
+	inline void OHLC(const mglDataA &open, const mglDataA &high, const mglDataA &low, const mglDataA &close, const char *pen="", const char *opt="")
+	{	mgl_ohlc(gr, &open,&high,&low,&close,pen,opt);	}
+
 	/// Draw box-plot (special 5-value plot used in statistic)
 	inline void BoxPlot(const mglDataA &x, const mglDataA &y, const char *pen="", const char *opt="")
 	{	mgl_boxplot_xy(gr, &x, &y, pen,opt);	}
@@ -708,7 +733,7 @@ public:
 	{	mgl_table(gr, x, y, &val, text, fnt, opt);	}
 	inline void Table(double x, double y, const mglDataA &val, const wchar_t *text, const char *fnt="#|", const char *opt="")
 	{	mgl_tablew(gr, x, y, &val, text, fnt, opt);	}
-	
+
 	/// Draw tube with radius r around curve {x,y,z}
 	inline void Tube(const mglDataA &x, const mglDataA &y, const mglDataA &z, const mglDataA &r, const char *pen="", const char *opt="")
 	{	mgl_tube_xyzr(gr, &x, &y, &z, &r, pen, opt);	}
@@ -1060,9 +1085,12 @@ public:
 	/// Draw dots in points {x,y,z}.
 	inline void Dots(const mglDataA &x, const mglDataA &y, const mglDataA &z, const char *sch="", const char *opt="")
 	{	mgl_dots(gr, &x, &y, &z, sch, opt);	}
-	/// Draw semitransparent dots in points {x,y,z} with alpha a.
+	/// Draw semitransparent dots in points {x,y,z} with specified alpha a.
 	inline void Dots(const mglDataA &x, const mglDataA &y, const mglDataA &z, const mglDataA &a, const char *sch="", const char *opt="")
 	{	mgl_dots_a(gr, &x, &y, &z, &a, sch, opt);	}
+	/// Draw semitransparent dots in points {x,y,z} with specified color c and alpha a.
+	inline void Dots(const mglDataA &x, const mglDataA &y, const mglDataA &z, const mglDataA &c, const mglDataA &a, const char *sch="", const char *opt="")
+	{	mgl_dots_ca(gr, &x, &y, &z, &c, &a, sch, opt);	}
 	/// Draw surface reconstructed for points in arrays {x,y,z}.
 	inline void Crust(const mglDataA &x, const mglDataA &y, const mglDataA &z, const char *sch="", const char *opt="")
 	{	mgl_crust(gr, &x, &y, &z, sch, opt);	}
@@ -1140,11 +1168,19 @@ public:
 	{	mgl_datac_fill_eq(gr, &u, eq, &v, 0, opt);	}
 	inline void Fill(mglDataC &u, const char *eq, const mglDataA &v, const mglDataA &w, const char *opt="")
 	{	mgl_datac_fill_eq(gr, &u, eq, &v, &w, opt);	}
-	
+
+	/// Fill dat by interpolated values of vdat parametrically depended on xdat,ydat,zdat for x,y,z in axis range
+	inline void Refill(mglData &dat, const mglDataA &xdat, const mglDataA &vdat, long sl=-1, const char *opt="")
+	{	mgl_data_refill_gr(gr,&dat,&xdat,0,0,&vdat,sl,opt);	}
+	inline void Refill(mglData &dat, const mglDataA &xdat, const mglDataA &ydat, const mglDataA &vdat, long sl=-1, const char *opt="")
+	{	mgl_data_refill_gr(gr,&dat,&xdat,&ydat,0,&vdat,sl,opt);	}
+	inline void Refill(mglData &dat, const mglDataA &xdat, const mglDataA &ydat, const mglDataA &zdat, const mglDataA &vdat, const char *opt="")
+	{	mgl_data_refill_gr(gr,&dat,&xdat,&ydat,&zdat,&vdat,-1,opt);	}
+
 	/// Set the data by triangulated surface values assuming x,y,z in range [Min, Max]
 	inline void DataGrid(mglData &d, const mglDataA &x, const mglDataA &y, const mglDataA &z, const char *opt="")
 	{	mgl_data_grid(gr,&d,&x,&y,&z,opt);	}
-	
+
 	/// Make histogram (distribution) of data. This function do not plot data.
 	inline mglData Hist(const mglDataA &x, const mglDataA &a, const char *opt="")
 	{	return mglData(true, mgl_hist_x(gr, &x, &a, opt));	}
@@ -1161,8 +1197,9 @@ public:
 //	inline void TextureColor(bool){}	// NOTE: Add later -- IDTF
 };
 //-----------------------------------------------------------------------------
+#ifndef SWIG
 /// Structure for handling named mglData (used by mglParse class).
-class mglVar : public mglData
+class MGL_EXPORT mglVar : public mglData
 {
 public:
 	std::wstring s;	///< Data name
@@ -1171,7 +1208,7 @@ public:
 	mglVar *prev;	///< Pointer to previous instance in list
 	bool temp;		///< This is temporary variable
 	void (*func)(void *);	///< Callback function for destroying
-	
+
 	mglVar():mglData()	{	o=0;	next=prev=0;	func=0;	temp=false;	}
 	virtual ~mglVar()
 	{
@@ -1194,9 +1231,10 @@ public:
 		if(next)	next->prev = this;
 	}
 };
+#endif
 //-----------------------------------------------------------------------------
 /// Wrapper class for MGL parsing
-class mglParse
+class MGL_EXPORT mglParse
 {
 	HMPR pr;
 public:
@@ -1259,7 +1297,7 @@ public:
 	{	return mglData(true,mgl_parser_calc(pr,formula)); 	}
 	inline mglData Calc(const wchar_t *formula)
 	{	return mglData(true,mgl_parser_calcw(pr,formula));	}
-	
+
 	/// Find variable with given name or add a new one
 	/// NOTE !!! You must not delete obtained data arrays !!!
 	inline mglVar *AddVar(const char *name)
@@ -1280,7 +1318,7 @@ public:
 };
 //-----------------------------------------------------------------------------
 /// Wrapper class expression evaluating
-class mglExpr
+class MGL_EXPORT mglExpr
 {
 	HMEX ex;
 public:
@@ -1302,8 +1340,9 @@ public:
 #endif
 };
 //-----------------------------------------------------------------------------
+#ifndef SWIG
 /// Wrapper class expression evaluating
-class mglExprC
+class MGL_EXPORT mglExprC
 {
 	HAEX ex;
 public:
@@ -1319,11 +1358,12 @@ public:
 		var['x'-'a']=x;	var['y'-'a']=y;	var['z'-'a']=z;
 		var['u'-'a']=u;	var['v'-'a']=v;	var['w'-'a']=w;
 		return mgl_cexpr_eval_v(ex,var);	}
-#ifndef SWIG
 	/// Return value of expression for given variables
 	inline dual Eval(dual var[26])
 	{	return mgl_cexpr_eval_v(ex,var);	}
-#endif
 };
+#endif
+//-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 #endif
+#endif
\ No newline at end of file
diff --git a/include/mgl2/mpi.h b/include/mgl2/mpi.h
index 4c456c9..f874594 100644
--- a/include/mgl2/mpi.h
+++ b/include/mgl2/mpi.h
@@ -37,8 +37,9 @@ void MGL_EXPORT mgl_mpi_recv_(uintptr_t *gr, int *id);
 #include "mgl2/mgl.h"
 //-----------------------------------------------------------------------------
 /// Wrapper class for all graphics
-class mglGraphMPI:public mglGraph
+class MGL_EXPORT mglGraphMPI:public mglGraph
 {
+public:
 	inline mglGraphMPI(int kind=0, int width=600, int height=400):mglGraph(kind,width,height){}
 	inline mglGraphMPI(const mglGraph &graph):mglGraph(graph){}
 	inline mglGraphMPI(HMGL graph):mglGraph(graph){}
diff --git a/include/mgl2/opengl.h b/include/mgl2/opengl.h
index 4b2c7ea..cd99788 100644
--- a/include/mgl2/opengl.h
+++ b/include/mgl2/opengl.h
@@ -29,20 +29,20 @@ public:
 	~mglCanvasGL();
 
 	void SetQuality(int =0)	{	Quality=2;	}
-	void Finish(bool fast=true);
+	void Finish();
 	void SetSize(int ,int )	{}
 	void View(mreal tetX,mreal tetY,mreal tetZ);
 	void Zoom(mreal x1, mreal y1, mreal x2, mreal y2);
-	int NewFrame();
+/*	int NewFrame();
 	void EndFrame();
-	void DelFrame(long ){}
-	
+	void DelFrame(long ){}*/
+
 	bool Alpha(bool enable);
 	void Fog(mreal d, mreal dz=0.25);
 	bool Light(bool enable);
 	void Light(int n, bool enable);
 	void AddLight(int n,mglPoint r,mglPoint d, char c='w', mreal bright=0.5, mreal ap=0);
-	void Clf(mglColor Back=WC);
+	void Clf(mglColor Back=NC);
 
 protected:
 	// provide fastest variant for usual points (not glyphs or marks)
@@ -50,14 +50,17 @@ protected:
 	void trig_draw(long n1, long n2, long n3);
 	void quad_draw(long n1, long n2, long n3, long n4);
 	// variant for glyphs or marks
-	void line_draw(const mglPnt &p1, const mglPnt &p2, mglDrawReg *d);
-	void trig_draw(const mglPnt &p1, const mglPnt &p2, const mglPnt &p3, bool anorm, mglDrawReg *d);
-	void quad_draw(const mglPnt &p1, const mglPnt &p2, const mglPnt &p3, const mglPnt &p4, mglDrawReg *d);
-	void pnt_draw(const mglPnt &p, mglDrawReg *d);
+	void line_draw(const mglPnt &p1, const mglPnt &p2, const mglDrawReg *d);
+	void trig_draw(const mglPnt &p1, const mglPnt &p2, const mglPnt &p3, bool anorm, const mglDrawReg *d);
+	void quad_draw(const mglPnt &p1, const mglPnt &p2, const mglPnt &p3, const mglPnt &p4, const mglDrawReg *d);
+	void pnt_draw(const mglPnt &p, const mglDrawReg *d);
+	void mark_draw(const mglPnt &q, char type, mreal size, mglDrawReg *d);
 
 	unsigned char **GetRGBLines(long &w, long &h, unsigned char *&f, bool solid=true);
-	void LightScale();
+	void LightScale(const mglMatrix *M);
 	void set_pen(unsigned style,mreal width);
+
+	void gl_clf(mglColor Back=WC);
 };
 //-----------------------------------------------------------------------------
 #endif
diff --git a/include/mgl2/other.h b/include/mgl2/other.h
index 7de2dfb..3582a86 100644
--- a/include/mgl2/other.h
+++ b/include/mgl2/other.h
@@ -19,7 +19,7 @@
  ***************************************************************************/
 #ifndef _MGL_OTHER_H_
 #define _MGL_OTHER_H_
-#include "mgl2/base.h"
+#include "mgl2/abstract.h"
 //-----------------------------------------------------------------------------
 #ifdef __cplusplus
 extern "C" {
@@ -61,9 +61,12 @@ void MGL_EXPORT mgl_tricont_xyc_(uintptr_t *gr, uintptr_t *nums, uintptr_t *x, u
 /// Draw dots in points {x,y,z}.
 void MGL_EXPORT mgl_dots(HMGL gr, HCDT x, HCDT y, HCDT z, const char *sch, const char *opt);
 void MGL_EXPORT mgl_dots_(uintptr_t *gr, uintptr_t *x, uintptr_t *y, uintptr_t *z, const char *sch, const char *opt,int,int);
-/// Draw semitransparent dots in points {x,y,z} with alpha a.
+/// Draw semitransparent dots in points {x,y,z} with specified alpha a.
 void MGL_EXPORT mgl_dots_a(HMGL gr, HCDT x, HCDT y, HCDT z, HCDT a, const char *sch, const char *opt);
 void MGL_EXPORT mgl_dots_a_(uintptr_t *gr, uintptr_t *x, uintptr_t *y, uintptr_t *z, uintptr_t *a, const char *sch, const char *opt,int,int);
+/// Draw semitransparent dots in points {x,y,z} with specified color c and alpha a.
+void MGL_EXPORT mgl_dots_ca(HMGL gr, HCDT x, HCDT y, HCDT z, HCDT c, HCDT a, const char *sch, const char *opt);
+void MGL_EXPORT mgl_dots_ca_(uintptr_t *gr, uintptr_t *x, uintptr_t *y, uintptr_t *z, uintptr_t *c, uintptr_t *a, const char *sch, const char *opt,int,int);
 
 /// Draw surface reconstructed for points in arrays {x,y,z}.
 void MGL_EXPORT mgl_crust(HMGL gr, HCDT x, HCDT y, HCDT z, const char *sch, const char *opt);
diff --git a/include/mgl2/parser.h b/include/mgl2/parser.h
index 2a451b5..3c8056e 100644
--- a/include/mgl2/parser.h
+++ b/include/mgl2/parser.h
@@ -69,11 +69,11 @@ struct mglFunc
 {
 	long pos;
 	int narg;
-//	std::wstring func;
-	wchar_t func[64];
+	std::wstring func;
+//	wchar_t func[64];
 	mglFunc(long p, const wchar_t *f);
 	mglFunc(const mglFunc &f);
-	mglFunc()	{	pos=narg=-1;	*func=0;	}
+	mglFunc()	{	pos=narg=-1;	}
 };
 //-----------------------------------------------------------------------------
 /// Structure for stack of functions and its arguments.
@@ -98,7 +98,6 @@ public:
 	bool AllowFileIO;	///< Allow reading/saving files
 	bool Stop;			///< Stop command was. Flag prevent further execution
 	mglCommand *Cmd;	///< Table of MGL commands (can be changed by user). It MUST be sorted by 'name'!!!
-	wchar_t *op1, *op2;	///< Buffer for options (are used if out!=NULL)
 	long InUse;			///< Smart pointer (number of users)
 
 	mglParser(bool setsize=false);
@@ -113,7 +112,7 @@ public:
 	/// Parse and execute the unicode string of MGL script
 	inline int Parse(HMGL gr, const wchar_t *str, long pos=0)
 	{	mglGraph GR(gr);	return Parse(&GR,str,pos);	}
-	int Parse(mglGraph *gr, const wchar_t *str, long pos=0);
+	int Parse(mglGraph *gr, std::wstring str, long pos=0);
 	/// Execute MGL script file fname
 	inline void Execute(HMGL gr, FILE *fp, bool print=false)
 	{	mglGraph GR(gr);	Execute(&GR,fp,print);	}
@@ -133,7 +132,7 @@ public:
 	/// Scan for functions (use NULL for reset)
 	void ScanFunc(const wchar_t *line);
 	/// Check if name is function and return its address (or 0 if no)
-	long IsFunc(const wchar_t *name, int *narg=0);
+	long IsFunc(const std::wstring &name, int *narg=0);
 	/// Find variable or return 0 if absent
 	mglVar *FindVar(const char *name);
 	mglVar *FindVar(const wchar_t *name);
@@ -176,21 +175,20 @@ private:
 	int for_addr;		///< Flag for saving address in variable (for_addr-1)
 	bool for_br;		///< Break is switched on (skip all comands until 'next')
 
-	/// Length of parameter strings
-	size_t GetParLen();
-	size_t GetParLen(const wchar_t *str);
 	/// Parse command
-	int Exec(mglGraph *gr, const wchar_t *com, long n, mglArg *a, const wchar_t *var, const wchar_t *opt);
+	int Exec(mglGraph *gr, const wchar_t *com, long n, mglArg *a, const std::wstring &var, const wchar_t *opt);
 	/// Fill arguments a from strings
-	void FillArg(mglGraph *gr, int n, wchar_t **arg, mglArg *a);
+	void FillArg(mglGraph *gr, int n, std::wstring *arg, mglArg *a);
 	/// PreExecute stage -- parse some commands and create variables
-	int PreExec(mglGraph *gr, long n, wchar_t **arg, mglArg *a);
+	int PreExec(mglGraph *gr, long n, std::wstring *arg, mglArg *a);
 	/// Execute program-flow control commands
-	int FlowExec(mglGraph *gr, const wchar_t *com, long n, mglArg *a);
+	int FlowExec(mglGraph *gr, const std::wstring &com, long n, mglArg *a);
 	/// Parse and execute the unicode string of MGL script
-	int ParseDat(mglGraph *gr, const wchar_t *str, mglData &res);
+	int ParseDat(mglGraph *gr, std::wstring str, mglData &res);
+	/// Define '$' parameters or start for loop
+	int ParseDef(std::wstring &str);
 	/// Parse $N arguments
-	void PutArg(const wchar_t *string, wchar_t *str, bool def);
+	void PutArg(std::wstring &str, bool def);
 	/// In skip mode
 	bool inline ifskip()	{	return (if_pos>0 && !(if_stack[if_pos-1]&1));	}
 	bool inline skip()		{	return (Skip || ifskip() || for_br);	}
diff --git a/include/mgl2/pde.h b/include/mgl2/pde.h
new file mode 100644
index 0000000..8c37983
--- /dev/null
+++ b/include/mgl2/pde.h
@@ -0,0 +1,56 @@
+/***************************************************************************
+ * data_cf.h is part of Math Graphic Library
+ * Copyright (C) 2007-2012 Alexey Balakin <mathgl.abalakin at gmail.ru>       *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU Library General Public License as       *
+ *   published by the Free Software Foundation; either version 3 of the    *
+ *   License, or (at your option) any later version.                       *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU Library General Public     *
+ *   License along with this program; if not, write to the                 *
+ *   Free Software Foundation, Inc.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+#ifndef _MGL_PDE_H_
+#define _MGL_PDE_H_
+//-----------------------------------------------------------------------------
+#include "mgl2/abstract.h"
+//-----------------------------------------------------------------------------
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/// Saves result of PDE solving (|u|^2) for "Hamiltonian" ham with initial conditions ini
+HMDT MGL_EXPORT mgl_pde_solve(HMGL gr, const char *ham, HCDT ini_re, HCDT ini_im, mreal dz, mreal k0,const char *opt);
+uintptr_t MGL_EXPORT mgl_pde_solve_(uintptr_t* gr, const char *ham, uintptr_t* ini_re, uintptr_t* ini_im, mreal *dz, mreal *k0,const char *opt,int,int);
+/// Saves result of PDE solving for "Hamiltonian" ham with initial conditions ini along a curve ray (must have nx>=7 - x,y,z,px,py,pz,tau or nx=5 - x,y,px,py,tau)
+HMDT MGL_EXPORT mgl_qo2d_solve(const char *ham, HCDT ini_re, HCDT ini_im, HCDT ray, mreal r, mreal k0, HMDT xx, HMDT yy);
+HMDT MGL_EXPORT mgl_qo2d_func(dual (*ham)(mreal u, mreal x, mreal y, mreal px, mreal py, void *par), void *par, HCDT ini_re, HCDT ini_im, HCDT ray, mreal r, mreal k0, HMDT xx, HMDT yy);
+uintptr_t MGL_EXPORT mgl_qo2d_solve_(const char *ham, uintptr_t* ini_re, uintptr_t* ini_im, uintptr_t* ray, mreal *r, mreal *k0, uintptr_t* xx, uintptr_t* yy, int);
+/// Saves result of PDE solving for "Hamiltonian" ham with initial conditions ini along a curve ray (must have nx>=7 - x,y,z,px,py,pz,tau or nx=5 - x,y,px,py,tau)
+HMDT MGL_EXPORT mgl_qo3d_solve(const char *ham, HCDT ini_re, HCDT ini_im, HCDT ray, mreal r, mreal k0, HMDT xx, HMDT yy, HMDT zz);
+HMDT MGL_EXPORT mgl_qo3d_func(dual (*ham)(mreal u, mreal x, mreal y, mreal z, mreal px, mreal py, mreal pz, void *par), void *par, HCDT ini_re, HCDT ini_im, HCDT ray, mreal r, mreal k0, HMDT xx, HMDT yy, HMDT zz);
+uintptr_t MGL_EXPORT mgl_qo3d_solve_(const char *ham, uintptr_t* ini_re, uintptr_t* ini_im, uintptr_t* ray, mreal *r, mreal *k0, uintptr_t* xx, uintptr_t* yy, uintptr_t* zz, int);
+/// Saves result of ODE solving of n equations with right part func and initial conditions x0 over time interval [0,tmax] with time step dt
+HMDT MGL_EXPORT mgl_ode_solve(void (*func)(const mreal *x, mreal *dx, void *par), int n, mreal *x0, mreal dt, mreal tmax, void *par);
+/// Finds ray with starting point r0, p0 (and prepares ray data for mgl_qo2d_solve)
+HMDT MGL_EXPORT mgl_ray_trace(const char *ham, mreal x0, mreal y0, mreal z0, mreal px, mreal py, mreal pz, mreal dt, mreal tmax);
+uintptr_t MGL_EXPORT mgl_ray_trace_(const char *ham, mreal *x0, mreal *y0, mreal *z0, mreal *px, mreal *py, mreal *pz, mreal *dt, mreal *tmax,int);
+/// Calculate Jacobian determinant for D{x(u,v), y(u,v)} = dx/du*dy/dv-dx/dv*dy/du
+HMDT MGL_EXPORT mgl_jacobian_2d(HCDT x, HCDT y);
+uintptr_t MGL_EXPORT mgl_jacobian_2d_(uintptr_t* x, uintptr_t* y);
+/// Calculate Jacobian determinant for D{x(u,v,w), y(u,v,w), z(u,v,w)}
+HMDT MGL_EXPORT mgl_jacobian_3d(HCDT x, HCDT y, HCDT z);
+uintptr_t MGL_EXPORT mgl_jacobian_3d_(uintptr_t* x, uintptr_t* y, uintptr_t* z);
+
+#ifdef __cplusplus
+}
+#endif
+//-----------------------------------------------------------------------------
+#endif
diff --git a/include/mgl2/plot.h b/include/mgl2/plot.h
index 8936917..c022493 100644
--- a/include/mgl2/plot.h
+++ b/include/mgl2/plot.h
@@ -19,7 +19,7 @@
  ***************************************************************************/
 #ifndef _MGL_1D_H_
 #define _MGL_1D_H_
-#include "mgl2/base.h"
+#include "mgl2/abstract.h"
 //-----------------------------------------------------------------------------
 #ifdef __cplusplus
 extern "C" {
@@ -98,7 +98,7 @@ void MGL_EXPORT mgl_stem_xy(HMGL graph, HCDT x, HCDT y, const char *pen, const c
 void MGL_EXPORT mgl_stem_xy_(uintptr_t *graph, uintptr_t *x, uintptr_t *y, const char *pen, const char *opt,int,int);
 /// Draw vertical lines from points {x,y} with x in x-axis range to axis plane
 void MGL_EXPORT mgl_stem(HMGL graph, HCDT y,	const char *pen, const char *opt);
-void MGL_EXPORT mgl_stem_(uintptr_t *graph, uintptr_t *y,	const char *pen, const char *opt,int,int);
+void MGL_EXPORT mgl_stem_(uintptr_t *graph, uintptr_t *y, const char *pen, const char *opt,int,int);
 
 /// Draw stairs for points in arrays {x,y,z}
 void MGL_EXPORT mgl_step_xyz(HMGL graph, HCDT x, HCDT y, HCDT z, const char *pen, const char *opt);
@@ -108,7 +108,7 @@ void MGL_EXPORT mgl_step_xy(HMGL graph, HCDT x, HCDT y, const char *pen, const c
 void MGL_EXPORT mgl_step_xy_(uintptr_t *graph, uintptr_t *x, uintptr_t *y, const char *pen, const char *opt,int,int);
 /// Draw stairs for points in arrays {x,y} with x in x-axis range
 void MGL_EXPORT mgl_step(HMGL graph, HCDT y,	const char *pen, const char *opt);
-void MGL_EXPORT mgl_step_(uintptr_t *graph, uintptr_t *y,	const char *pen, const char *opt,int,int);
+void MGL_EXPORT mgl_step_(uintptr_t *graph, uintptr_t *y, const char *pen, const char *opt,int,int);
 
 /// Draw vertical bars from points {x,y,z} to axis plane
 void MGL_EXPORT mgl_bars_xyz(HMGL graph, HCDT x, HCDT y, HCDT z, const char *pen, const char *opt);
@@ -118,14 +118,21 @@ void MGL_EXPORT mgl_bars_xy(HMGL graph, HCDT x, HCDT y, const char *pen, const c
 void MGL_EXPORT mgl_bars_xy_(uintptr_t *graph, uintptr_t *x, uintptr_t *y, const char *pen, const char *opt,int,int);
 /// Draw vertical bars from points {x,y} with x in x-axis range to axis plane
 void MGL_EXPORT mgl_bars(HMGL graph, HCDT y,	const char *pen, const char *opt);
-void MGL_EXPORT mgl_bars_(uintptr_t *graph, uintptr_t *y,	const char *pen, const char *opt,int,int);
+void MGL_EXPORT mgl_bars_(uintptr_t *graph, uintptr_t *y, const char *pen, const char *opt,int,int);
 
 /// Draw horizontal bars from points {v,y} to axis plane
 void MGL_EXPORT mgl_barh_yx(HMGL graph, HCDT y, HCDT v, const char *pen, const char *opt);
 void MGL_EXPORT mgl_barh_yx_(uintptr_t *graph, uintptr_t *y, uintptr_t *v, const char *pen, const char *opt,int,int);
 /// Draw horizontal bars from points {v,y} with y in y-axis range to axis plane
 void MGL_EXPORT mgl_barh(HMGL graph, HCDT v,	const char *pen, const char *opt);
-void MGL_EXPORT mgl_barh_(uintptr_t *graph, uintptr_t *v,	const char *pen, const char *opt,int,int);
+void MGL_EXPORT mgl_barh_(uintptr_t *graph, uintptr_t *v, const char *pen, const char *opt,int,int);
+
+/// Draw Open-High-Low-Close (OHLC) diagram
+void MGL_EXPORT mgl_ohlc_x(HMGL graph, HCDT x, HCDT open, HCDT high, HCDT low, HCDT close, const char *pen, const char *opt);
+void MGL_EXPORT mgl_ohlc_x_(uintptr_t *graph, uintptr_t *x, uintptr_t *open, uintptr_t *high, uintptr_t *low, uintptr_t *close, const char *pen, const char *opt,int,int);
+/// Draw Open-High-Low-Close (OHLC) diagram with x in x-axis range
+void MGL_EXPORT mgl_ohlc(HMGL graph, HCDT open, HCDT high, HCDT low, HCDT close, const char *pen, const char *opt);
+void MGL_EXPORT mgl_ohlc_(uintptr_t *graph, uintptr_t *open, uintptr_t *high, uintptr_t *low, uintptr_t *close, const char *pen, const char *opt,int,int);
 
 /// Draw chart for data a
 void MGL_EXPORT mgl_chart(HMGL graph, HCDT a, const char *col, const char *opt);
diff --git a/include/mgl2/prim.h b/include/mgl2/prim.h
index 68f5fc9..fc9dcb6 100644
--- a/include/mgl2/prim.h
+++ b/include/mgl2/prim.h
@@ -19,7 +19,7 @@
  ***************************************************************************/
 #ifndef _MGL_PRIM_H_
 #define _MGL_PRIM_H_
-#include "mgl2/base.h"
+#include "mgl2/abstract.h"
 //-----------------------------------------------------------------------------
 #ifdef __cplusplus
 extern "C" {
diff --git a/include/mgl2/qmathgl.h b/include/mgl2/qmathgl.h
index 9c9459e..531ccd7 100644
--- a/include/mgl2/qmathgl.h
+++ b/include/mgl2/qmathgl.h
@@ -55,12 +55,10 @@ public:
 	{	setGraph(GR->Self());	}
 	inline HMGL getGraph()	{	return (HMGL)gr;	}
 	/// Set drawing functions and its parameter
-	inline void setDraw(int (*func)(mglBase *gr, void *par), void *par=0)
-	{	draw_func = func;	draw_par = par;	emit usePrimChanged(draw_func || draw);	}
-	inline void setDraw(mglDraw *dr)
-	{	draw = dr;	emit usePrimChanged(draw_func || draw);	}
-	inline void setDraw(int (*draw)(mglGraph *gr))
-	{	setDraw(draw?mgl_draw_graph:0,(void*)draw);	}
+	void setDraw(int (*func)(mglBase *gr, void *par), void *par);
+	void setDraw(mglDraw *dr);
+	inline void setDraw(int (*func)(mglGraph *gr))
+	{	setDraw(func?mgl_draw_graph:0,(void*)func);	}
 	inline void zoomRegion(mreal xx1,mreal xx2,mreal yy1, mreal yy2)
 	{	x1=xx1;	y1=yy1;	x2=xx2;	y2=yy2;	}
 
@@ -90,6 +88,7 @@ public slots:
 	void imgSize(int w, int h);	///< Set image size
 	void setViewYZ(bool v);	///< Switch on/off rotation around Y and Z axis
 
+	void setCustZoom(bool a);	///< Switch on/off using custom zoom
 	void setZoom(bool z);	///< Switch on/off mouse zooming
 	void setRotate(bool r);	///< Switch on/off mouse rotation
 	void zoomIn();			///< Zoom in graphics
@@ -155,7 +154,9 @@ signals:
 	void objChanged(int objId);	///< User double-click to select object/line
 	void refreshData();
 	void doubleClick(int id);	///< Double mouse click by object with id
-	void askStyle(int id);	///< Update style
+	void askStyle(int id);		///< Update style
+	/// user can define its own zooming function
+	void customZoom(double x1, double y1, double x2, double y2, double tet, double phi, double per);
 
 protected:
 	void paintEvent(QPaintEvent *);
@@ -177,6 +178,7 @@ protected:
 	double per;			///< Value of perspective ( must be in [0,1) )
 	bool alpha;			///< Transparency state
 	bool light;			///< Lightning state
+	bool custZoom;		///< Use custom zoom instead of built in
 	bool zoom;			///< Mouse zoom state
 	bool grid;			///< Grid drawing state
 	bool rotate;			///< Mouse rotation state
@@ -193,8 +195,9 @@ private:
 };
 //-----------------------------------------------------------------------------
 /// Class for drawing the MGL script
-struct mglDrawScript : public mglDraw
+class MGL_EXPORT mglDrawScript : public mglDraw
 {
+public:
 	HMPR par;		///< Parser to be used
 	QString text;	///< Script to be drawn
 	long line;		///< Line which will be highlited
diff --git a/include/mgl2/qt.h b/include/mgl2/qt.h
index fb7f7c1..3f14d09 100644
--- a/include/mgl2/qt.h
+++ b/include/mgl2/qt.h
@@ -19,7 +19,7 @@
  ***************************************************************************/
 #ifndef _MGL_QT_H_
 #define _MGL_QT_H_
-#include <mgl2/base.h>
+#include <mgl2/abstract.h>
 //-----------------------------------------------------------------------------
 #ifdef __cplusplus
 extern "C" {
@@ -36,7 +36,7 @@ int MGL_EXPORT mgl_qt_run_();
 #include <mgl2/wnd.h>
 //-----------------------------------------------------------------------------
 /// Wrapper class for windows displaying graphics
-class mglQT : public mglWnd
+class MGL_EXPORT mglQT : public mglWnd
 {
 public:
 	mglQT(const char *title="MathGL") : mglWnd()
diff --git a/include/mgl2/surf.h b/include/mgl2/surf.h
index 59d668c..c6dc3c3 100644
--- a/include/mgl2/surf.h
+++ b/include/mgl2/surf.h
@@ -19,7 +19,7 @@
  ***************************************************************************/
 #ifndef _MGL_SURF_H_
 #define _MGL_SURF_H_
-#include "mgl2/base.h"
+#include "mgl2/abstract.h"
 //-----------------------------------------------------------------------------
 #ifdef __cplusplus
 extern "C" {
diff --git a/include/mgl2/thread.h b/include/mgl2/thread.h
new file mode 100644
index 0000000..618d04d
--- /dev/null
+++ b/include/mgl2/thread.h
@@ -0,0 +1,86 @@
+/***************************************************************************
+ * thread.h is part of Math Graphic Library
+ * Copyright (C) 2007-2012 Alexey Balakin <mathgl.abalakin at gmail.ru>       *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU Library General Public License as       *
+ *   published by the Free Software Foundation; either version 3 of the    *
+ *   License, or (at your option) any later version.                       *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU Library General Public     *
+ *   License along with this program; if not, write to the                 *
+ *   Free Software Foundation, Inc.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+#ifndef _MGL_THREAD_H_
+#define _MGL_THREAD_H_
+#include "mgl2/define.h"
+//-----------------------------------------------------------------------------
+#if MGL_HAVE_PTHREAD
+#include <pthread.h>
+#endif
+//-----------------------------------------------------------------------------
+struct mglThreadD
+{
+	mreal *a;		// float* array with parameters or results
+	const mreal *b,*c,*d,*e;	// float* arrays with parameters
+	const long *p;	// long* array with parameters
+	const void *v;	// pointer to data/grapher
+	int id;			// thread id
+	long n;			// total number of iteration
+	const char *s;
+};
+struct mglThreadC
+{
+	dual *a;		// dual* array with parameters or results
+	const dual *b,*c,*d,*e;	// dual* arrays with parameters
+	const long *p;	// long* array with parameters
+	const void *v;	// pointer to data/grapher
+	int id;			// thread id
+	long n;			// total number of iteration
+	const char *s;
+};
+struct mglThreadV
+{
+	mreal *a;		// float* array with parameters or results
+	dual *aa;		// dual* array with parameters or results
+	const void *b,*c;	// float* arrays with parameters
+	const mreal *d;	// float* arrays with parameters
+	const long *p;	// long* array with parameters
+	const void *v;	// pointer to data/grapher
+	int id;			// thread id
+	long n;			// total number of iteration
+};
+struct mglThreadT
+{
+	void *a; 		// dual* or mreal* array with input or results
+	double *b; 		// dual* array with input or results
+	const long *p;	// long* array with parameters
+	const void *v;	// pointer to table/parameter
+	void **w; 		// pointer to workspace
+	int id;			// thread id
+	long n;			// total number of iteration
+	const void *re,*im;
+};
+/// Start several thread for the task
+void MGL_EXPORT mglStartThread(void *(*func)(void *), void (*post)(mglThreadD *,mreal *), long n,
+					mreal *a=0, const mreal *b=0, const mreal *c=0, const long *p=0,
+					const void *v=0, const mreal *d=0, const mreal *e=0, const char *s=0);
+void MGL_EXPORT mglStartThreadV(void *(*func)(void *), long n, mreal *a, const void *b=0,
+					const void *c=0, const long *p=0, const void *v=0, const mreal *d=0);
+void MGL_EXPORT mglStartThreadV(void *(*func)(void *), long n, dual *a, const void *b=0,
+					const void *c=0, const long *p=0, const void *v=0, const mreal *d=0);
+void MGL_EXPORT mglStartThreadC(void *(*func)(void *), void (*post)(mglThreadC *,dual *), long n,
+					dual *a=0, const dual *b=0, const dual *c=0, const long *p=0,
+					const void *v=0, const dual *d=0, const dual *e=0, const char *s=0);
+void MGL_EXPORT mglStartThreadT(void *(*func)(void *), long n, void *a, double *b, const void *v=0,
+					void **w=0, const long *p=0, const void *re=0, const void *im=0);
+MGL_EXPORT extern int mglNumThr;		///< Number of thread for plotting and data handling
+//-----------------------------------------------------------------------------
+#endif
+//-----------------------------------------------------------------------------
diff --git a/include/mgl2/type.h b/include/mgl2/type.h
index fb803ed..d7c01de 100644
--- a/include/mgl2/type.h
+++ b/include/mgl2/type.h
@@ -19,9 +19,7 @@
  ***************************************************************************/
 #ifndef _MGL_TYPE_H_
 #define _MGL_TYPE_H_
-#if !defined(_MSC_VER) && !defined(__BORLANDC__)
-#include <stdint.h>
-#endif
+
 #include "mgl2/define.h"
 //-----------------------------------------------------------------------------
 const mreal Pi = M_PI;
@@ -34,7 +32,7 @@ const mreal mgl_min_a = 1./256;
 #define MGL_SET_RGB(p,rr,gg,bb)		{p.r=(rr);p.g=(gg);p.b=(bb);}
 //-----------------------------------------------------------------------------
 /// Class for point in 3D space
-struct mglPoint
+struct MGL_EXPORT mglPoint
 {
 	mreal x,y,z,c;
 	mglPoint(mreal X=0,mreal Y=0,mreal Z=0,mreal C=0){x=X;y=Y;z=Z;c=C;}
@@ -88,7 +86,7 @@ inline mreal mgl_norm(const mglPoint &p)
 #endif
 //-----------------------------------------------------------------------------
 /// Class for RGBA color
-struct mglColor
+struct MGL_EXPORT mglColor
 {
 	float r;	///< Red component of color
 	float g;	///< Green component of color
diff --git a/include/mgl2/vect.h b/include/mgl2/vect.h
index e45e4c2..fe61bc8 100644
--- a/include/mgl2/vect.h
+++ b/include/mgl2/vect.h
@@ -19,7 +19,7 @@
  ***************************************************************************/
 #ifndef _MGL_VECT_H_
 #define _MGL_VECT_H_
-#include "mgl2/base.h"
+#include "mgl2/abstract.h"
 //-----------------------------------------------------------------------------
 #ifdef __cplusplus
 extern "C" {
diff --git a/include/mgl2/volume.h b/include/mgl2/volume.h
index 7a9d248..a53e604 100644
--- a/include/mgl2/volume.h
+++ b/include/mgl2/volume.h
@@ -19,7 +19,7 @@
  ***************************************************************************/
 #ifndef _MGL_VOL_H_
 #define _MGL_VOL_H_
-#include "mgl2/base.h"
+#include "mgl2/abstract.h"
 //-----------------------------------------------------------------------------
 #ifdef __cplusplus
 extern "C" {
diff --git a/include/mgl2/window.h b/include/mgl2/window.h
index 7835efc..9c615b2 100644
--- a/include/mgl2/window.h
+++ b/include/mgl2/window.h
@@ -25,7 +25,7 @@
 #include "mgl2/wx.h"
 //-----------------------------------------------------------------------------
 /// Wrapper class for all windows displaying graphics
-class mglWindow : public mglWnd
+class MGL_EXPORT mglWindow : public mglWnd
 {
 	int wnd;	///< Type of window
 public:
@@ -35,26 +35,23 @@ public:
 	{
 		wnd=kind;
 		if(wnd==1)	gr = mgl_create_graph_qt(draw,title,par,load);
-		else if(wnd==2)	gr = mgl_create_graph_wx(draw,title,par,load);
 		else		gr = mgl_create_graph_fltk(draw,title,par,load);
 	}
 	mglWindow(int (*draw)(mglGraph *gr), const char *title="MathGL", int kind=0) : mglWnd()
 	{
 		wnd=kind;
 		if(wnd==1)	gr = mgl_create_graph_qt(draw?mgl_draw_graph:0,title,(void*)draw,0);
-		else if(wnd==2)	gr = mgl_create_graph_wx(draw?mgl_draw_graph:0,title,(void*)draw,0);
 		else		gr = mgl_create_graph_fltk(draw?mgl_draw_graph:0,title,(void*)draw,0);
 	}
 	mglWindow(mglDraw *draw, const char *title="MathGL", int kind=0) : mglWnd()
 	{
 		wnd=kind;
 		if(wnd==1)	gr = mgl_create_graph_qt(draw?mgl_draw_class:0,title,draw,mgl_reload_class);
-		else if(wnd==2)	gr = mgl_create_graph_wx(draw?mgl_draw_class:0,title,draw,mgl_reload_class);
 		else		gr = mgl_create_graph_fltk(draw?mgl_draw_class:0,title,draw,mgl_reload_class);
 		mgl_set_click_func(gr, mgl_click_class);
 	}
 	/// Run main loop for event handling
-	int Run()	{	return wnd==0? mgl_fltk_run():(wnd==1?mgl_qt_run():mgl_wx_run());	}
+	int Run()	{	return wnd==0? mgl_fltk_run():mgl_qt_run();	}
 	/// Run main loop for event handling in separate thread (for FLTK only)
 	inline int RunThr()	{	return wnd==0 ? mgl_fltk_thr():0;	}
 };
diff --git a/include/mgl2/wnd.h b/include/mgl2/wnd.h
index dc0d907..98fe225 100644
--- a/include/mgl2/wnd.h
+++ b/include/mgl2/wnd.h
@@ -24,8 +24,9 @@
 //-----------------------------------------------------------------------------
 /// Class for drawing in windows (like, mglCanvasFL, mglCanvasQT and so on)
 /// Make inherited class and redefine Draw() function if you don't want to use function pointers.
-struct mglDraw
+class MGL_EXPORT mglDraw
 {
+public:
 	virtual int Draw(mglGraph *)=0;	///< Function for drawing
 	virtual void Reload()	{}		///< Function for reloading data
 	virtual void Click()	{}		///< Callback function on mouse click
@@ -51,7 +52,7 @@ void MGL_EXPORT mgl_reload_class(void *p);
 }
 //-----------------------------------------------------------------------------
 /// Abstract class for windows displaying graphics
-class mglWnd : public mglGraph
+class MGL_EXPORT mglWnd : public mglGraph
 {
 public:
 	mglWnd() : mglGraph(-1)	{}
diff --git a/include/mgl2/wx.h b/include/mgl2/wx.h
index 4876ad9..287df0d 100644
--- a/include/mgl2/wx.h
+++ b/include/mgl2/wx.h
@@ -20,47 +20,18 @@
 #ifndef MGL_WX_H
 #define MGL_WX_H
 //-----------------------------------------------------------------------------
-#include <mgl2/base.h>
-//-----------------------------------------------------------------------------
-#ifdef __cplusplus
-extern "C" {
-#endif
-/// Creates WX window for plotting
-HMGL MGL_EXPORT mgl_create_graph_wx(int (*draw)(HMGL gr, void *p), const char *title, void *par, void (*load)(void *p));
-uintptr_t MGL_EXPORT mgl_create_graph_wx_(const char *title, int);
-/// Run main WX loop for event handling.
-int MGL_EXPORT mgl_wx_run();
-int MGL_EXPORT mgl_wx_run_();
-#ifdef __cplusplus
-}
-//-----------------------------------------------------------------------------
 #include <mgl2/wnd.h>
-//-----------------------------------------------------------------------------
-/// Wrapper class for windows displaying graphics
-class mglWX : public mglWnd
-{
-public:
-	mglWX(const char *title="MathGL") : mglWnd()
-	{	gr = mgl_create_graph_wx(0,title,0,0);	}
-	mglWX(int (*draw)(HMGL gr, void *p), const char *title="MathGL", void *par=NULL, void (*load)(void *p)=0) : mglWnd()
-	{	gr = mgl_create_graph_wx(draw,title,par,load);	}
-	mglWX(int (*draw)(mglGraph *gr), const char *title="MathGL") : mglWnd()
-	{	gr = mgl_create_graph_wx(draw?mgl_draw_graph:0,title,(void*)draw,0);	}
-	mglWX(mglDraw *draw, const char *title="MathGL") : mglWnd()
-	{	gr = mgl_create_graph_wx(draw?mgl_draw_class:0,title,draw,mgl_reload_class);
-		mgl_set_click_func(gr, mgl_click_class);	}
-	int Run()	{	return mgl_wx_run();	}	///< Run main loop for event handling
-
-};
-//-----------------------------------------------------------------------------
 #include <wx/window.h>
 #include <wx/image.h>
 #include <wx/timer.h>
 #include <wx/bitmap.h>
 class mglCanvas;
 //-----------------------------------------------------------------------------
+/// Convert MathGL image to wxBitmap
+wxBitmap MGL_EXPORT ConvertFromGraph(HMGL gr);
+//-----------------------------------------------------------------------------
 /// Class is Wx widget which display MathGL graphics
-class wxMathGL : public wxWindow
+class MGL_EXPORT wxMathGL : public wxWindow
 {
 public:
 	wxString appName;	///< Application name for message boxes
@@ -127,7 +98,6 @@ public:
 	void Animation(bool st=true);	///< Start animation
 
 	void About();		///< Show about information
-	void AboutQt();		///< Show information about Qt version
 
 protected:
 	void OnPaint(wxPaintEvent& event);
@@ -163,8 +133,6 @@ protected:
 	DECLARE_EVENT_TABLE()
 private:
 	int x0, y0, xe, ye;		///< Temporary variables for mouse
-	unsigned char *grBuf;
 };
 //-----------------------------------------------------------------------------
 #endif
-#endif
diff --git a/json/main.js b/json/main.js
index e35326b..6fbeead 100644
--- a/json/main.js
+++ b/json/main.js
@@ -24,34 +24,12 @@ var main = function() {
 //var script = "rotate 10 20: box:axis:fsurf 'sin(pi*x*y)'";
 
 var makeSampleScript = function() {
-  var mgl = "";
-  mgl += "ranges -2 2 -2 2 -2 2:"   // NOTE: Ranges MUST BE specified for correctly work of zoomaxis feature
-  mgl += "facenum 50:";
-//  mgl += "rotate 1 0:";
-
-  //mgl += "origin 0 0 0:axis 'Uxyz':xlabel 'x':ylabel 'y':zlabel 'z':"
-  mgl += "origin 0 0 0:axis 'x':xlabel 'x':ylabel 'y':zlabel 'z':"
-
-  mgl += "box:"
-
-//mgl += "fsurf 'x':"
-  mgl += "fplot 'sin(x^2)'\n";   // This is just for testing zoomaxis features
-  mgl += "fplot 'sin(2*pi*t)' '2*t-1' 'cos(2*pi*t)' 'm2o':";
-//mgl += "fsurf '0':"
-//  mgl += "fplot 'sin(2*pi*t)' '2*t-1' '2*cos(2*pi*t)' 'm2o':";
-
-  //mgl += "axis:fsurf 'sin(2*pi*x*y)':";
-mgl += "axis:fsurf 'cos(2*pi*x*y)':";
-
-  //mgl += "zoomaxis";
-///////  mgl += "box:axis:fplot 'sin(2*pi*t)' 'cos(2*pi*t)' '2*t-1' 'm2o'\n";
-
-  //mgl += "xlabel 'x':ylabel 'y':axis:fsurf 'sin(2*pi*x*y)'\n";
-  //mgl += "box:axis:fplot 'sin(2*pi*t)' 'cos(2*pi*t)' '2*t-1' 'm2o'\n";
-  // only axes are kept for debug purposes
-
-  //  mgl += "rotate 1 0:xlabel 'x':ylabel 'y':axis:\n";
-
-//mgl += "fsurf 'sin(2*pi*x*y)':"
-  return mgl;  
+	var mgl = "origintick off\n";
+	mgl += "ranges -2 2 -2 2 -2 2:"   // NOTE: Ranges MUST BE specified for correctly work of zoomaxis feature
+	mgl += "facenum 50:";
+	mgl += "origin 0 0 0:axis :xlabel 'x':ylabel 'y':zlabel 'z':"
+	mgl += "box:fplot 'sin(x^2)'\n";   // This is just for testing zoomaxis features
+	mgl += "fplot 'sin(2*pi*t)' '2*t-1' 'cos(2*pi*t)' 'm2o':";
+	mgl += "text 0 0 'aaa'";
+	return mgl;
 }
diff --git a/json/mathgl.Graph.js b/json/mathgl.Graph.js
index 7cb17f9..6ce28a9 100644
--- a/json/mathgl.Graph.js
+++ b/json/mathgl.Graph.js
@@ -8,21 +8,21 @@
  * @param canvas {Canvas} canvas to plot graph on
  */
 mathgl.Graph = function(canvas, backend) {
-  this.__backend = backend;
-  this.__canvas = canvas;
-  this.__view = null;
-  this.__geometry = null;
-  // indicate whether rendering handlers are in the event queue
-  this.__isDraftRenderingInScheduled = false;
-  this.__isPreciseRenderingScheduled = false;
-  // draft rendering finished timestamp
-  this.__draftFinishedTimestamp = new Date();
-  this.__backgroundFillStyle = '#EEEEFF';
-  this.__preciseRenderingDelay = 700;
-  // TODO add setters/getters
-  this.__maxDraftPoints = 9000;
-  this.__x1 = 0;    this.__y1 = 0;
-  this.__x2 = 1;    this.__y2 = 1;
+	this.__backend = backend;
+	this.__canvas = canvas;
+	this.__view = null;
+	this.__geometry = null;
+	// indicate whether rendering handlers are in the event queue
+	this.__isDraftRenderingInScheduled = false;
+	this.__isPreciseRenderingScheduled = false;
+	// draft rendering finished timestamp
+	this.__draftFinishedTimestamp = new Date();
+	this.__backgroundFillStyle = '#EEEEFF';
+	this.__preciseRenderingDelay = 700;
+	// TODO add setters/getters
+	this.__maxDraftPoints = 9000;
+	this.__x1 = 0;	this.__y1 = 0;	this.__z1 = 0;
+	this.__x2 = 1;	this.__y2 = 1;	this.__z2 = 1;
 }
 
 
@@ -31,18 +31,18 @@ mathgl.Graph = function(canvas, backend) {
  * @param mgl {String} MGL script
  */
 mathgl.Graph.prototype.init = function(mgl) {
-  // request backend for geometry object
-  this.__geometry = this.__backend.geometry(mgl);
-  this.__geometry.mgl = mgl;
-  // construct view according the view type recieved from backend (within geometry object) and initialize it
-
-  this.__view = new mathgl.View();
-  // connect method which starts rendering to view object
-  this.__view.setRenderLauncher(mathgl.bind(this.__renderStart, this));
-  // connect pick point handler
-  this.__view.setPickPointHandler(mathgl.bind(this.__pickPointHandler, this));
-  // attach canvas to view
-  this.__view.attachCanvas(this.__canvas);
+	// request backend for geometry object
+	this.__geometry = this.__backend.geometry(mgl);
+	this.__geometry.mgl = mgl;
+	// construct view according the view type recieved from backend (within geometry object) and initialize it
+
+	this.__view = new mathgl.View();
+	// connect method which starts rendering to view object
+	this.__view.setRenderLauncher(mathgl.bind(this.__renderStart, this));
+	// connect pick point handler
+	this.__view.setPickPointHandler(mathgl.bind(this.__pickPointHandler, this));
+	// attach canvas to view
+	this.__view.attachCanvas(this.__canvas);
 }
 
 
@@ -51,7 +51,7 @@ mathgl.Graph.prototype.init = function(mgl) {
  * @param json {String} string in JSON format with previously saved state
  */
 mathgl.Graph.prototype.load = function(json) {
-  throw new Error("TODO");
+	throw new Error("TODO");
 }
 
 
@@ -60,7 +60,7 @@ mathgl.Graph.prototype.load = function(json) {
  * @return {String} state serialized to JSON string
  */
 mathgl.Graph.prototype.save = function() {
-  throw new Error("TODO");
+	throw new Error("TODO");
 }
 
 
@@ -69,327 +69,322 @@ mathgl.Graph.prototype.save = function() {
  * @param fillStyle something that will be accepted by canvas' 2d context as fill style, e.g. color, gradient, pattern.
  */
 mathgl.Graph.prototype.setBackgroundFillStyle = function(fillStyle) {
-  this.__backgroundFillStyle = fillStyle;
+	this.__backgroundFillStyle = fillStyle;
 }
 
 
 /** @return background fill style */
 mathgl.Graph.prototype.backgroundFillStyle = function() {
-  return this.__backgroundFillStyle;
+	return this.__backgroundFillStyle;
 }
 
 
 /** called when user picks the point on the graph, point shall be somehow displayed/highlighted */
 mathgl.Graph.prototype.__pickPointHandler = function(x, y) {
-    console.log("Point picked: ", x, y);
-    var obj = this.__geometry;
-    var xy = x*obj.width/this.__canvas.width + " " + y*obj.height/this.__canvas.height;
-    // introduce zoom and view coomand for server side
-    var zoom = "zoom "+(0.5-obj.pf/2)+" "+(0.5-obj.pf/2)+" "+(0.5+obj.pf/2)+" "+(0.5+obj.pf/2)+"\n";
-    var view1 = "view 0 "+this.__view.__pitch*180/Math.PI+" 0"+"\n";
-    var view2 = "view 0 0 "+(-this.__view.__yaw)*180/Math.PI+"\n";
-    console.debug(xy,"pf=",obj.pf,zoom+view1+view2)
-    // now ask server side for proper coordinates
-    var res = globalBackend.coor(xy, zoom+view1+view2+obj.mgl);
-    console.debug("coordinates are ", res);
+	var obj = this.__geometry;
+	var xy = x*obj.width/this.__canvas.width + " " + y*obj.height/this.__canvas.height;
+	// introduce zoom and view coomand for server side
+	var zoom = "zoom "+(0.5-obj.pf/2)+" "+(0.5-obj.pf/2)+" "+(0.5+obj.pf/2)+" "+(0.5+obj.pf/2)+"\n";
+	var view1 = "view 0 "+this.__view.__pitch*180/Math.PI+" 0"+"\n";
+	var view2 = "view 0 0 "+(-this.__view.__yaw)*180/Math.PI+"\n";
+	// now ask server side for proper coordinates
+	var res = this.__backend.coor(xy, zoom+view1+view2+obj.mgl);
 }
 
 
 /** called when user shift axis range */
-mathgl.Graph.prototype.shiftAxis = function(x, y) {
-    var dx = x*(this.__x2-this.__x1), dy = y*(this.__y2-this.__y1)
-    this.__x1 += dx; this.__x2 += dx;
-    this.__y1 += dy; this.__y2 += dy;
-    // introduce zoomaxis coomand for server side
-    var zoom = "zoomaxis "+this.__x1+" "+this.__y1+" "+this.__x2+" "+this.__y2+"\n";
-    var mgl = this.__geometry.mgl;
-            console.log(zoom, "Old: ", this.__geometry);
-    // now ask server side for proper coordinates
-    this.__geometry = this.__backend.geometry(zoom+mgl);
-    this.__geometry.mgl = mgl;
-            console.log("New: ", this.__geometry);
-    this.__renderStart();
+mathgl.Graph.prototype.shiftAxis = function(x, y, z) {
+	var dx = x*(this.__x2-this.__x1), dy = y*(this.__y2-this.__y1), dz = z*(this.__z2-this.__z1)
+	this.__x1 += dx; this.__x2 += dx;
+	this.__y1 += dy; this.__y2 += dy;
+	this.__z1 += dz; this.__z2 += dz;
+	// introduce zoomaxis coomand for server side
+	var zoom = "zoomaxis "+this.__x1+" "+this.__y1+" "+this.__z1+" "+this.__x2+" "+this.__y2+" "+this.__z2+"\n";
+	var mgl = this.__geometry.mgl;
+	// now ask server side for proper coordinates
+	this.__geometry = this.__backend.geometry(zoom+mgl);
+	this.__geometry.mgl = mgl;
+	this.__renderStart();
 }
 
 
 /** called when user shift axis range */
 mathgl.Graph.prototype.zoomAxis = function(factor) {
-    var d, c;
-    d=(this.__x2-this.__x1)*factor/2; c=(this.__x2+this.__x1)/2;
-    this.__x1 = c-d; this.__x2 = c+d;
-    d=(this.__y2-this.__y1)*factor/2; c=(this.__y2+this.__y1)/2;
-    this.__y1 = c-d; this.__y2 = c+d;
-    // introduce zoomaxis coomand for server side
-    var zoom = "zoomaxis "+this.__x1+" "+this.__y1+" "+this.__x2+" "+this.__y2+"\n";
-    var mgl = this.__geometry.mgl;
-            console.log(zoom, "Old: ", this.__geometry);
-    // now ask server side for proper coordinates
-    this.__geometry = this.__backend.geometry(zoom+this.__geometry.mgl);
-    this.__geometry.mgl = mgl;
-            console.log("New: ", this.__geometry);
-    this.__renderStart();
+	var d, c;
+	d=(this.__x2-this.__x1)*factor/2; c=(this.__x2+this.__x1)/2;
+	this.__x1 = c-d; this.__x2 = c+d;
+	d=(this.__y2-this.__y1)*factor/2; c=(this.__y2+this.__y1)/2;
+	this.__y1 = c-d; this.__y2 = c+d;
+	d=(this.__z2-this.__z1)*factor/2; c=(this.__z2+this.__z1)/2;
+	this.__z1 = c-d; this.__z2 = c+d;
+	// introduce zoomaxis coomand for server side
+	var zoom = "zoomaxis "+this.__x1+" "+this.__y1+" "+this.__z1+" "+this.__x2+" "+this.__y2+" "+this.__z2+"\n";
+	var mgl = this.__geometry.mgl;
+	// now ask server side for proper coordinates
+	this.__geometry = this.__backend.geometry(zoom+this.__geometry.mgl);
+	this.__geometry.mgl = mgl;
+	this.__renderStart();
 }
 
 
 /** initiate the chains of rendering the geometry to the canvas */
 mathgl.Graph.prototype.__renderStart = function() {
-  // do nothing if processing is already started
-  if (!this.__isDraftRenderingInScheduled) {
-    // enqueue draft rendering step
-    this.__isDraftRenderingInScheduled = true;
-    setTimeout(mathgl.bind(this.__renderDraft, this), 0);
-  }
+	// do nothing if processing is already started
+	if (!this.__isDraftRenderingInScheduled) {
+		// enqueue draft rendering step
+		this.__isDraftRenderingInScheduled = true;
+		setTimeout(mathgl.bind(this.__renderDraft, this), 0);
+	}
 }
 
 
 /** draft rendering */
 mathgl.Graph.prototype.__renderDraft = function() {
-  this.__drawMesh(false);
-  this.__isDraftRenderingInScheduled = false;
-
-  // enqueue precise rendering step
-  if (!this.__isPreciseRenderingScheduled) {
-    this.__isPreciseRenderingScheduled = true;
-    setTimeout(mathgl.bind(this.__renderPrecise, this), this.__preciseRenderingDelay);
-  }
-  this.__draftFinishedTimestamp = new Date();
+	this.__drawMesh(false);
+	this.__isDraftRenderingInScheduled = false;
+
+	// enqueue precise rendering step
+	if (!this.__isPreciseRenderingScheduled) {
+		this.__isPreciseRenderingScheduled = true;
+		setTimeout(mathgl.bind(this.__renderPrecise, this), this.__preciseRenderingDelay);
+	}
+	this.__draftFinishedTimestamp = new Date();
 }
 
 
 /** precise rendering */
 mathgl.Graph.prototype.__renderPrecise = function() {
-  // do nothing if draft rendering is scheduled
-  if (this.__isDraftRenderingInScheduled) {
-    this.__isPreciseRenderingScheduled = false;
-    return;
-  }
-
-  // check that enough time has passed since last occurance of draft rendering finished
-  // rechedule pricese rendering if it is not
-  var current = new Date();
-  if (current - this.__draftFinishedTimestamp < this.__preciseRenderingDelay) {
-    setTimeout(mathgl.bind(this.__renderPrecise, this), this.__preciseRenderingDelay - (current - this.__draftFinishedTimestamp));
-    return;
-  }
-  this.__drawMesh(true);
-  this.__isPreciseRenderingScheduled = false;
+	// do nothing if draft rendering is scheduled
+	if (this.__isDraftRenderingInScheduled) {
+		this.__isPreciseRenderingScheduled = false;
+		return;
+	}
+
+	// check that enough time has passed since last occurance of draft rendering finished
+	// rechedule pricese rendering if it is not
+	var current = new Date();
+	if (current - this.__draftFinishedTimestamp < this.__preciseRenderingDelay) {
+		setTimeout(mathgl.bind(this.__renderPrecise, this), this.__preciseRenderingDelay - (current - this.__draftFinishedTimestamp));
+		return;
+	}
+	this.__drawMesh(true);
+	this.__isPreciseRenderingScheduled = false;
 }
 
 
 /** fill canvas background */
 mathgl.Graph.prototype.__drawBackground = function() {
-  var c = this.__canvas.getContext("2d");
-  var h = this.__canvas.height;
-  var w = this.__canvas.width;
-  c.fillStyle = this.__backgroundFillStyle;
-  c.fillRect(0, 0 , w, h);
+	var c = this.__canvas.getContext("2d");
+	var h = this.__canvas.height;
+	var w = this.__canvas.width;
+	c.fillStyle = this.__backgroundFillStyle;
+	c.fillRect(0, 0 , w, h);
 }
 
 
 /** auxiliary function to draw mesh */
 mathgl.Graph.prototype.__drawMesh = function(isPrecise) {
-  var c = this.__canvas.getContext("2d");
-  var m = this.__view.viewMatrix().inverse();
-//  var vvv = $M([[1,0,0,1]]);
-//  console.log(vvv.x(m).elements);
-  var obj = this.__geometry;
-  var h = this.__canvas.height;
-  var dy = h / obj.height;
-  var w = this.__canvas.width;
-  var dx = w / obj.width;
-  obj.pf = -m.e(4,3);
-  obj.b = [dx*m.e(1,1),  dx*m.e(2,1),  dx*m.e(3,1),
-           dy*m.e(1,2),  dy*m.e(2,2),  dy*m.e(3,2),
-           m.e(1,3),     m.e(2,3),     m.e(3,3),
-           w/2, h/2, obj.depth/2];
-
-  this.__drawBackground();
-
-  if (!isPrecise) {
-    obj.fast = 1;
-    obj.good = 0;
-    this.__mgl_draw_fast(obj,c,1);
-  } else {
-    obj.fast = 0;
-    obj.good = 1;
-    this.__mgl_draw_good(obj,c,1);
-  }
+	var c = this.__canvas.getContext("2d");
+	var m = this.__view.viewMatrix().inverse();
+//	var vvv = $M([[1,0,0,1]]);
+	var obj = this.__geometry;
+	var h = this.__canvas.height;
+	var dy = h / obj.height;
+	var w = this.__canvas.width;
+	var dx = w / obj.width;
+	obj.pf = -m.e(4,3);
+	obj.b = [dx*m.e(1,1),	dx*m.e(2,1),	dx*m.e(3,1),
+			dy*m.e(1,2),	dy*m.e(2,2),	dy*m.e(3,2),
+			m.e(1,3),		m.e(2,3),		m.e(3,3),
+			w/2,			h/2,			obj.depth/2];
+
+	this.__drawBackground();
+
+	if (!isPrecise) {
+		obj.fast = 1;
+		obj.good = 0;
+		this.__mgl_draw_fast(obj,c,1);
+	} else {
+		obj.fast = 0;
+		obj.good = 1;
+		this.__mgl_draw_good(obj,c,1);
+	}
 }
 
 
 /** perform fast drawing */
 mathgl.Graph.prototype.__mgl_draw_fast = function(obj, ctx, skip) {
-    if(obj.fast==0)	return;
-    this.__mgl_prepare(obj,skip);	// update coordinates
-    var i,n1,n2;
-    // for each primitive skipping superfluous
-    for(var i=0;i<obj.nprim;i += 1 + Math.round(obj.nprim / this.__maxDraftPoints))
-    {
-        n1 = obj.prim[i][1];    n2 = obj.prim[i][2];
-        if(obj.prim[i][0]==1)
-        {
-            ctx.strokeStyle = obj.prim[i][10];
-            ctx.beginPath();
-            ctx.moveTo(obj.pp[n1][0],obj.pp[n1][1]);
-            ctx.lineTo(obj.pp[n2][0],obj.pp[n2][1]);
-            ctx.lineWidth = obj.prim[i][7];
-            ctx.stroke();
-        }
-        else
+	if(obj.fast==0)	return;
+	this.__mgl_prepare(obj,skip);	// update coordinates
+	var i,n1,n2;
+	// for each primitive skipping superfluous
+	for(var i=0;i<obj.nprim;i += 1 + Math.round(obj.nprim / this.__maxDraftPoints))
+	{
+		n1 = obj.prim[i][1];	n2 = obj.prim[i][2];
+		if(obj.prim[i][0]==1)
+		{
+			ctx.strokeStyle = obj.prim[i][10];
+			ctx.beginPath();
+			ctx.moveTo(obj.pp[n1][0],obj.pp[n1][1]);
+			ctx.lineTo(obj.pp[n2][0],obj.pp[n2][1]);
+			ctx.lineWidth = obj.prim[i][7]/100;
+			ctx.stroke();
+		}
+		else
 		{
 			ctx.fillStyle = obj.prim[i][10];
 			ctx.fillRect(obj.pp[n1][0], obj.pp[n1][1], 2, 2);
 		}
-    }
+	}
 }
 
 
 /** perform high-quality drawing */
 mathgl.Graph.prototype.__mgl_draw_good = function(obj, ctx, skip) {
-    obj.fast = 0;
-    this.__mgl_prepare(obj,skip);	// update coordinates
+	obj.fast = 0;
+	this.__mgl_prepare(obj,skip);	// update coordinates
 //	var scl = 1/Math.abs(obj.z[1]-obj.z[0]);
-    // NOTE: this valid only for current zoom/view. In general case it should be more complicated
-    var s1 = Math.sqrt(obj.b[0]*obj.b[0]+obj.b[1]*obj.b[1]+obj.b[2]*obj.b[2]);
-    var deg = Math.PI/180;  //0.017453293;
-    for(var i=0;i<obj.nprim;i++)	// for each primitive
-    {
-        var scl = s1*this.__mgl_pf(obj, obj.prim[i][9]);
-        var n1 = obj.prim[i][1], n2 = obj.prim[i][2];
-        var n3 = obj.prim[i][3], n4 = obj.prim[i][4];
-        ctx.strokeStyle = obj.prim[i][10];
-        ctx.fillStyle = obj.prim[i][10];
-        ctx.lineWidth = 1;
-        switch(obj.prim[i][0])		// draw it depending on its type
-        {
-        case 0: // marks
-            ctx.lineWidth = obj.prim[i][7]*obj.prim[i][6]*50;
-            this.__mgl_draw_mark(ctx, obj.pp[n1][0], obj.pp[n1][1], n4, obj.prim[i][6], scl);
-            break;
-        case 1: // lines
-            ctx.beginPath();
-            ctx.moveTo(obj.pp[n1][0],obj.pp[n1][1]);
-            ctx.lineTo(obj.pp[n2][0],obj.pp[n2][1]);
-            ctx.lineWidth = obj.prim[i][7];
-            ctx.stroke();	break;
-        case 2: // triangles
-            ctx.beginPath();
-            ctx.moveTo(obj.pp[n1][0],obj.pp[n1][1]);
-            ctx.lineTo(obj.pp[n2][0],obj.pp[n2][1]);
-            ctx.lineTo(obj.pp[n3][0],obj.pp[n3][1]);
-            ctx.closePath();	ctx.fill();	break;
-        case 3: // quadrangles
-            ctx.beginPath();
-            ctx.moveTo(obj.pp[n1][0],obj.pp[n1][1]);
-            ctx.lineTo(obj.pp[n2][0],obj.pp[n2][1]);
-            ctx.lineTo(obj.pp[n4][0],obj.pp[n4][1]);
-            ctx.lineTo(obj.pp[n3][0],obj.pp[n3][1]);
-            ctx.closePath();
-            // NOTE: look as alpha is disabled for lines
-            // So, next code should be only for the case alpha=false
-            if(obj.prim[i][10].charAt(0)=='#')	ctx.stroke();
-            ctx.fill();	break;
-        case 4: // glyphs
-            var t=obj.prim[i][7]*deg;
-            var xx=obj.coor[n2][2],yy=-obj.coor[n2][3],zz=obj.coor[n2][4];
-            var xc = obj.b[0]*xx + obj.b[1]*yy + obj.b[2]*zz;
-            var yc = obj.b[3]*xx + obj.b[4]*yy + obj.b[5]*zz;
-            var zc = obj.b[6]*xx + obj.b[7]*yy + obj.b[8]*zz;
-            var ll = xc*xc+yc*yc;
-            if(ll < 1e-10)	break;
-            console.debug("t=",t);
-            if(ll<1e10 && t/deg<1e4)
-            {
-                t = Math.atan2(yc,xc);
-                if(Math.abs(t)>Math.PI/2)	t += Math.PI;
-            }
-            else t=0;
-            var c=Math.cos(t), s=Math.sin(t), d=obj.prim[i][6]/2;
-
-            var b=[d*c, d*s, d*s, -d*c, obj.pp[n1][0],obj.pp[n1][1]];
-            var x=obj.coor[n2][0]*scl, y=obj.coor[n2][1]*scl, f=obj.prim[i][8]*scl;
-            if(n3&8)
-            {
-                if(!(n3&4))	this.__mgl_line_glyph(ctx, x,y, f,1,b);
-                this.__mgl_line_glyph(ctx, x,y, f,0,b);
-            }
-            else
-            {
-                if(!(n3&4)) this.__mgl_fill_glyph(ctx, x,y, f,obj.glfs[n4],b);
-                this.__mgl_wire_glyph(ctx, x,y, f,obj.glfs[n4],b);
-            }
-            break;
-        }
-    }
+	// NOTE: this valid only for current zoom/view. In general case it should be more complicated
+	var s1 = Math.sqrt(obj.b[0]*obj.b[0]+obj.b[1]*obj.b[1]+obj.b[2]*obj.b[2]);
+	var deg = Math.PI/180;  //0.017453293;
+	for(var i=0;i<obj.nprim;i++)	// for each primitive
+	{
+		var scl = s1*this.__mgl_pf(obj, obj.prim[i][9]);
+		var n1 = obj.prim[i][1], n2 = obj.prim[i][2];
+		var n3 = obj.prim[i][3], n4 = obj.prim[i][4];
+		ctx.strokeStyle = obj.prim[i][10];
+		ctx.fillStyle = obj.prim[i][10];
+		ctx.lineWidth = 1;
+		switch(obj.prim[i][0])		// draw it depending on its type
+		{
+		case 0: // marks
+//			ctx.lineWidth = obj.prim[i][7]*obj.prim[i][6]*50;
+			ctx.lineWidth = obj.prim[i][7]*obj.prim[i][6]*5e-4;
+			this.__mgl_draw_mark(ctx, obj.pp[n1][0], obj.pp[n1][1], n4, obj.prim[i][6]/100, scl);
+			break;
+		case 1: // lines
+			ctx.beginPath();
+			ctx.moveTo(obj.pp[n1][0],obj.pp[n1][1]);
+			ctx.lineTo(obj.pp[n2][0],obj.pp[n2][1]);
+			ctx.lineWidth = obj.prim[i][7]/100;
+			ctx.stroke();	break;
+		case 2: // triangles
+			ctx.beginPath();
+			ctx.moveTo(obj.pp[n1][0],obj.pp[n1][1]);
+			ctx.lineTo(obj.pp[n2][0],obj.pp[n2][1]);
+			ctx.lineTo(obj.pp[n3][0],obj.pp[n3][1]);
+			ctx.closePath();	ctx.fill();	break;
+		case 3: // quadrangles
+			ctx.beginPath();
+			ctx.moveTo(obj.pp[n1][0],obj.pp[n1][1]);
+			ctx.lineTo(obj.pp[n2][0],obj.pp[n2][1]);
+			ctx.lineTo(obj.pp[n4][0],obj.pp[n4][1]);
+			ctx.lineTo(obj.pp[n3][0],obj.pp[n3][1]);
+			ctx.closePath();
+			// NOTE: look as alpha is disabled for lines
+			// So, next code should be only for the case alpha=false
+			if(obj.prim[i][10].charAt(0)=='#')	ctx.stroke();
+			ctx.fill();	break;
+		case 4: // glyphs
+			var t=obj.prim[i][7]*deg/100;
+			var xx=obj.coor[n2][2]/100,yy=-obj.coor[n2][3]/100,zz=obj.coor[n2][4]/100;
+			var xc = obj.b[0]*xx + obj.b[1]*yy + obj.b[2]*zz;
+			var yc = obj.b[3]*xx + obj.b[4]*yy + obj.b[5]*zz;
+//			var zc = obj.b[6]*xx + obj.b[7]*yy + obj.b[8]*zz;
+			var ll = xc*xc+yc*yc;
+			if(ll < 1e-10)	break;
+			if(ll<1e10 && t/deg<1e4)
+			{
+				t = Math.atan2(yc,xc);
+				if(Math.abs(t)>Math.PI/2)	t += Math.PI;
+			}
+			else t=0;
+			var c=Math.cos(t), s=Math.sin(t), d=obj.prim[i][6]/200;
+
+			var b=[d*c, d*s, d*s, -d*c, obj.pp[n1][0],obj.pp[n1][1]];
+			var x=obj.coor[n2][0]*scl/100, y=obj.coor[n2][1]*scl/100, f=obj.prim[i][8]*scl/1e5;
+			if(n3&8)
+			{
+				if(!(n3&4))	this.__mgl_line_glyph(ctx, x,y, f,1,b);
+				else this.__mgl_line_glyph(ctx, x,y, f,0,b);
+			}
+			else
+			{
+				if(!(n3&4)) this.__mgl_fill_glyph(ctx, x,y, f,obj.glfs[n4],b);
+				else this.__mgl_wire_glyph(ctx, x,y, f,obj.glfs[n4],b);
+			}
+			break;
+		}
+	}
 }
 
 
 mathgl.Graph.prototype.__mgl_pf = function(obj, z) {
-  return 1/obj.pf;
-// return 1/(1+obj.pf*(1-z/obj.depth));
+	return 1/obj.pf;
+//	return 1/(1+obj.pf*(1-z/obj.depth));
 }
 
 
 /** change coordinates according current transformations, usually called internally by draw() */
 mathgl.Graph.prototype.__mgl_prepare = function(obj, skip) {
-    // fill transformation matrix
-    if(!skip)
-    {
-        var dx = 1/Math.abs(obj.z[1]-obj.z[0]);
-        var dy = 1/Math.abs(obj.z[3]-obj.z[2]);
-        var cx=Math.cos(obj.tet*deg), sx=Math.sin(obj.tet*deg);	// tetx
-        var cy=Math.cos(obj.phi*deg), sy=Math.sin(obj.phi*deg);	// tety
-        var cz=Math.cos(obj.bet*deg), sz=Math.sin(obj.bet*deg);	// tetz
-        obj.b = [dx*cx*cy, -dx*cy*sx, dx*sy,
-                    dy*(cx*sy*sz+cz*sx), dy*(cx*cz-sx*sy*sz), -dy*cy*sz,
-                    sx*sz-cx*cz*sy, cx*sz+cz*sx*sy, cy*cz,
-                    obj.width/2*(1+dx-obj.z[1]-obj.z[0])/dx,
-                    obj.height/2*(1+dy-obj.z[3]-obj.z[2])/dy, obj.depth/2];
-    }
-    // now transform points for found transformation matrix
-    var b = obj.b, i;
-    for(i=0;i<obj.npnts;i++)
-    {
-        var x = obj.pnts[i][0]-obj.width/2;
-        var y = obj.pnts[i][1]-obj.height/2;
-        var z = obj.pnts[i][2]-obj.depth/2;
-        obj.pp[i] = [b[9]  + b[0]*x + b[1]*y + b[2]*z,
-                     b[10] + b[3]*x + b[4]*y + b[5]*z,
-                     b[11] + b[6]*x + b[7]*y + b[8]*z];
-    }
-    if(obj.pf)	for(var i=0;i<obj.npnts;i++)	// perspective
-    {	// NOTE: it is not supported for coordinate determining now
-        var d = this.__mgl_pf(obj, obj.pp[i][2]);
-        obj.pp[i][0] = d*obj.pp[i][0] + (1-d)*obj.b[9];
-        obj.pp[i][1] = d*obj.pp[i][1] + (1-d)*obj.b[10];
-    }
-    // fill z-coordinates for primitives
-    if(!obj.fast)   for(i=0;i<obj.nprim;i++)
-    {
-        var n1 = obj.prim[i][1], n2 = obj.prim[i][2], n3 = obj.prim[i][3], n4 = obj.prim[i][4];
-        switch(obj.prim[i][0])
-        {
-        case 1: // lines
-            obj.prim[i][9] = (obj.pp[n1][2]+obj.pp[n2][2])/2;	break;
-        case 2: // triangles
-            obj.prim[i][9] = (obj.pp[n1][2]+obj.pp[n2][2]+obj.pp[n3][2])/3;	break;
-        case 3: // quadrangles
-            obj.prim[i][9] = (obj.pp[n1][2]+obj.pp[n2][2]+obj.pp[n3][2]+obj.pp[n4][2])/4;	break;
-        default:
-            obj.prim[i][9] = obj.pp[n1][2];	break;
-        }
-    }
-    if(!obj.fast) // sort primitives according its z-coordinate
-        obj.prim.sort(this.__mgl_cmp); // more accurate sorting
+	// fill transformation matrix
+	if(!skip)
+	{
+		var dx = 1/Math.abs(obj.z[1]-obj.z[0]);
+		var dy = 1/Math.abs(obj.z[3]-obj.z[2]);
+		var cx=Math.cos(obj.tet*deg), sx=Math.sin(obj.tet*deg);	// tetx
+		var cy=Math.cos(obj.phi*deg), sy=Math.sin(obj.phi*deg);	// tety
+		var cz=Math.cos(obj.bet*deg), sz=Math.sin(obj.bet*deg);	// tetz
+		obj.b = [dx*cx*cy, -dx*cy*sx, dx*sy,
+				dy*(cx*sy*sz+cz*sx), dy*(cx*cz-sx*sy*sz), -dy*cy*sz,
+				sx*sz-cx*cz*sy, cx*sz+cz*sx*sy, cy*cz,
+				obj.width/2*(1+dx-obj.z[1]-obj.z[0])/dx,
+				obj.height/2*(1+dy-obj.z[3]-obj.z[2])/dy, obj.depth/2];
+	}
+	// now transform points for found transformation matrix
+	var b = obj.b, i;
+	for(i=0;i<obj.npnts;i++)
+	{
+		var x = obj.pnts[i][0]-obj.width/2;
+		var y = obj.pnts[i][1]-obj.height/2;
+		var z = obj.pnts[i][2]-obj.depth/2;
+		obj.pp[i] = [b[9]  + b[0]*x + b[1]*y + b[2]*z,
+					 b[10] + b[3]*x + b[4]*y + b[5]*z,
+					 b[11] + b[6]*x + b[7]*y + b[8]*z];
+	}
+	if(obj.pf)	for(var i=0;i<obj.npnts;i++)	// perspective
+	{	// NOTE: it is not supported for coordinate determining now
+		var d = this.__mgl_pf(obj, obj.pp[i][2]);
+		obj.pp[i][0] = d*obj.pp[i][0] + (1-d)*obj.b[9];
+		obj.pp[i][1] = d*obj.pp[i][1] + (1-d)*obj.b[10];
+	}
+	// fill z-coordinates for primitives
+	if(!obj.fast)	for(i=0;i<obj.nprim;i++)
+	{
+		var n1 = obj.prim[i][1], n2 = obj.prim[i][2], n3 = obj.prim[i][3], n4 = obj.prim[i][4];
+		switch(obj.prim[i][0])
+		{
+		case 1: // lines
+			obj.prim[i][9] = (obj.pp[n1][2]+obj.pp[n2][2])/2;	break;
+		case 2: // triangles
+			obj.prim[i][9] = (obj.pp[n1][2]+obj.pp[n2][2]+obj.pp[n3][2])/3;	break;
+		case 3: // quadrangles
+			obj.prim[i][9] = (obj.pp[n1][2]+obj.pp[n2][2]+obj.pp[n3][2]+obj.pp[n4][2])/4;	break;
+		default:
+			obj.prim[i][9] = obj.pp[n1][2];	break;
+		}
+	}
+	if(!obj.fast) // sort primitives according its z-coordinate
+		obj.prim.sort(this.__mgl_cmp); // more accurate sorting
 }
 
 
 mathgl.Graph.prototype.__mgl_cmp = function(a,b) {
-    var tt = [0,2,4,5, 1,3,6, 7];
-    if(a[9]!=b[9])	return a[9] - b[9];
-    if(a[0]!=b[0])	return tt[b[0]]-tt[a[0]];
-    if(a[8]!=b[8])	return a[8] - b[8];
-    return a[3]-b[3];
+	var tt = [0,2,4,5, 1,3,6, 7];
+	if(a[9]!=b[9])	return a[9] - b[9];
+	if(a[0]!=b[0])	return tt[b[0]]-tt[a[0]];
+	if(a[8]!=b[8])	return a[8] - b[8];
+	return a[3]-b[3];
 }
 
 
@@ -398,193 +393,197 @@ mathgl.Graph.prototype.__mgl_cmp = function(a,b) {
  * Usually this function is called internally, but it can be called by user as well
  */
 mathgl.Graph.prototype.__mgl_draw_mark = function(ctx,x,y,st,size,d) {
-    if(size<=0) {	st = 46;	size=1; }
-    var s = size*d;
-    ctx.beginPath();
-    switch(st)
-    {
-    case 111:	// 'o'
-        ctx.arc(x,y,s,0,Math.PI*2);	 ctx.stroke();	break;
-    case 79:	// 'O'
-        ctx.arc(x,y,s,0,Math.PI*2);	 ctx.fill();	 break;
-    case 67:	// 'C'
-        ctx.arc(x,y,s,0,Math.PI*2);	 ctx.stroke();
-        ctx.arc(x,y,0.1*s,0,Math.PI*2); ctx.fill();	 break;
-    case 80:	// 'P'
-        ctx.moveTo(x-s,y-s);	ctx.lineTo(x+s,y-s);
-        ctx.lineTo(x+s,y+s);	ctx.lineTo(x-s,y+s);	ctx.lineTo(x-s,y-s);
-        ctx.moveTo(x-s,y);		ctx.lineTo(x+s,y);
-        ctx.moveTo(x,y-s);		ctx.lineTo(x,y+s);
-        ctx.stroke();	break;
-    case 43:	// '+'
-        ctx.moveTo(x-s,y);		ctx.lineTo(x+s,y);
-        ctx.moveTo(x,y-s);		ctx.lineTo(x,y+s);
-        ctx.stroke();	break;
-    case 88:	// 'X'
-        ctx.moveTo(x-s,y-s);	ctx.lineTo(x+s,y-s);
-        ctx.lineTo(x+s,y+s);	ctx.lineTo(x-s,y+s);	ctx.lineTo(x-s,y-s);
-        ctx.moveTo(x-s,y-s);	ctx.lineTo(x+s,y+s);
-        ctx.moveTo(x+s,y-s);	ctx.lineTo(x-s,y+s);
-        ctx.stroke();	break;
-    case 120:	// 'x'
-        ctx.moveTo(x-s,y-s);	ctx.lineTo(x+s,y+s);
-        ctx.moveTo(x+s,y-s);	ctx.lineTo(x-s,y+s);
-        ctx.stroke();	break;
-    case 115:	// 's'
-        ctx.moveTo(x-s,y-s);	ctx.lineTo(x+s,y-s);
-        ctx.lineTo(x+s,y+s);	ctx.lineTo(x-s,y+s);
-        ctx.closePath();		ctx.stroke();	break;
-    case 83:	// 'S'
-        ctx.moveTo(x-s,y-s);	ctx.lineTo(x+s,y-s);
-        ctx.lineTo(x+s,y+s);	ctx.lineTo(x-s,y+s);
-        ctx.closePath();		ctx.fill();	 break;
-    case 100:	// 'd'
-        ctx.moveTo(x-s,y);		ctx.lineTo(x,y-s);
-        ctx.lineTo(x+s,y);		ctx.lineTo(x,y+s);
-        ctx.closePath();		ctx.stroke();	break;
-    case 68:	// 'D'
-        ctx.moveTo(x-s,y);		ctx.lineTo(x,y-s);
-        ctx.lineTo(x+s,y);		ctx.lineTo(x,y+s);
-        ctx.closePath();		ctx.fill();	 break;
-    case 42:	// '*'
-        ctx.moveTo(x-s,y);		ctx.lineTo(x+s,y);
-        ctx.moveTo(x-0.6*s,y-0.8*s);	ctx.lineTo(x+0.6*s,y+0.8*s);
-        ctx.moveTo(x+0.6*s,y-0.8*s);	ctx.lineTo(x-0.6*s,y+0.8*s);
-        ctx.stroke();	break;
-    case 89:	// 'Y'
-        ctx.moveTo(x,y-s);		ctx.lineTo(x,y);
-        ctx.moveTo(x-0.8*s,y+0.6*s);	ctx.lineTo(x,y);
-        ctx.moveTo(x+0.8*s,y+0.6*s);	ctx.lineTo(x,y);
-        ctx.stroke();	break;
-    case 86:	// 'T'
-        ctx.moveTo(x-s,y-s/2);	ctx.lineTo(x+s,y-s/2);
-        ctx.lineTo(x,y+s);		ctx.closePath();
-        ctx.fill();	 break;
-    case 118:	// '^'
-        ctx.moveTo(x-s,y-s/2);	ctx.lineTo(x+s,y-s/2);
-        ctx.lineTo(x,y+s);		ctx.closePath();
-        ctx.stroke();	break;
-    case 84:	// 'V'
-        ctx.moveTo(x-s,y+s/2);	ctx.lineTo(x+s,y+s/2);
-        ctx.lineTo(x,y-s);		ctx.closePath();
-        ctx.fill();	 break;
-    case 94:	// 'v'
-        ctx.moveTo(x-s,y+s/2);	ctx.lineTo(x+s,y+s/2);
-        ctx.lineTo(x,y-s);		ctx.closePath();
-        ctx.stroke();	break;
-    case 76:	// 'L'
-        ctx.moveTo(x+s/2,y-s);	ctx.lineTo(x+s/2,y+s);
-        ctx.lineTo(x-s,y);		ctx.closePath();
-        ctx.fill();	 break;
-    case 60:	// '<'
-        ctx.moveTo(x+s/2,y-s);	ctx.lineTo(x+s/2,y+s);
-        ctx.lineTo(x-s,y);		ctx.closePath();
-        ctx.stroke();	break;
-    case 82:	// 'R'
-        ctx.moveTo(x-s/2,y-s);	ctx.lineTo(x-s/2,y+s);
-        ctx.lineTo(x+s,y);		ctx.closePath();
-        ctx.fill();	 break;
-    case 62:	// '>'
-        ctx.moveTo(x-s/2,y-s);	ctx.lineTo(x-s/2,y+s);
-        ctx.lineTo(x+s,y);		ctx.closePath();
-        ctx.stroke();	break;
+	if(size<=0) {	st = 46;	size=1; }
+	var s = size*d;
+	ctx.beginPath();
+	switch(st)
+	{
+	case 111:	// 'o'
+		ctx.arc(x,y,s,0,Math.PI*2);	 ctx.stroke();	break;
+	case 79:	// 'O'
+		ctx.arc(x,y,s,0,Math.PI*2);	 ctx.fill();	 break;
+	case 67:	// 'C'
+		ctx.arc(x,y,s,0,Math.PI*2);	 ctx.stroke();
+		ctx.arc(x,y,0.1*s,0,Math.PI*2); ctx.fill();	 break;
+	case 80:	// 'P'
+		ctx.moveTo(x-s,y-s);	ctx.lineTo(x+s,y-s);
+		ctx.lineTo(x+s,y+s);	ctx.lineTo(x-s,y+s);	ctx.lineTo(x-s,y-s);
+		ctx.moveTo(x-s,y);		ctx.lineTo(x+s,y);
+		ctx.moveTo(x,y-s);		ctx.lineTo(x,y+s);
+		ctx.stroke();	break;
+	case 43:	// '+'
+		ctx.moveTo(x-s,y);		ctx.lineTo(x+s,y);
+		ctx.moveTo(x,y-s);		ctx.lineTo(x,y+s);
+		ctx.stroke();	break;
+	case 88:	// 'X'
+		ctx.moveTo(x-s,y-s);	ctx.lineTo(x+s,y-s);
+		ctx.lineTo(x+s,y+s);	ctx.lineTo(x-s,y+s);	ctx.lineTo(x-s,y-s);
+		ctx.moveTo(x-s,y-s);	ctx.lineTo(x+s,y+s);
+		ctx.moveTo(x+s,y-s);	ctx.lineTo(x-s,y+s);
+		ctx.stroke();	break;
+	case 120:	// 'x'
+		ctx.moveTo(x-s,y-s);	ctx.lineTo(x+s,y+s);
+		ctx.moveTo(x+s,y-s);	ctx.lineTo(x-s,y+s);
+		ctx.stroke();	break;
+	case 115:	// 's'
+		ctx.moveTo(x-s,y-s);	ctx.lineTo(x+s,y-s);
+		ctx.lineTo(x+s,y+s);	ctx.lineTo(x-s,y+s);
+		ctx.closePath();		ctx.stroke();	break;
+	case 83:	// 'S'
+		ctx.moveTo(x-s,y-s);	ctx.lineTo(x+s,y-s);
+		ctx.lineTo(x+s,y+s);	ctx.lineTo(x-s,y+s);
+		ctx.closePath();		ctx.fill();	 break;
+	case 100:	// 'd'
+		ctx.moveTo(x-s,y);		ctx.lineTo(x,y-s);
+		ctx.lineTo(x+s,y);		ctx.lineTo(x,y+s);
+		ctx.closePath();		ctx.stroke();	break;
+	case 68:	// 'D'
+		ctx.moveTo(x-s,y);		ctx.lineTo(x,y-s);
+		ctx.lineTo(x+s,y);		ctx.lineTo(x,y+s);
+		ctx.closePath();		ctx.fill();	 break;
+	case 42:	// '*'
+		ctx.moveTo(x-s,y);		ctx.lineTo(x+s,y);
+		ctx.moveTo(x-0.6*s,y-0.8*s);	ctx.lineTo(x+0.6*s,y+0.8*s);
+		ctx.moveTo(x+0.6*s,y-0.8*s);	ctx.lineTo(x-0.6*s,y+0.8*s);
+		ctx.stroke();	break;
+	case 89:	// 'Y'
+		ctx.moveTo(x,y-s);		ctx.lineTo(x,y);
+		ctx.moveTo(x-0.8*s,y+0.6*s);	ctx.lineTo(x,y);
+		ctx.moveTo(x+0.8*s,y+0.6*s);	ctx.lineTo(x,y);
+		ctx.stroke();	break;
+	case 86:	// 'T'
+		ctx.moveTo(x-s,y-s/2);	ctx.lineTo(x+s,y-s/2);
+		ctx.lineTo(x,y+s);		ctx.closePath();
+		ctx.fill();	 break;
+	case 118:	// '^'
+		ctx.moveTo(x-s,y-s/2);	ctx.lineTo(x+s,y-s/2);
+		ctx.lineTo(x,y+s);		ctx.closePath();
+		ctx.stroke();	break;
+	case 84:	// 'V'
+		ctx.moveTo(x-s,y+s/2);	ctx.lineTo(x+s,y+s/2);
+		ctx.lineTo(x,y-s);		ctx.closePath();
+		ctx.fill();	 break;
+	case 94:	// 'v'
+		ctx.moveTo(x-s,y+s/2);	ctx.lineTo(x+s,y+s/2);
+		ctx.lineTo(x,y-s);		ctx.closePath();
+		ctx.stroke();	break;
+	case 76:	// 'L'
+		ctx.moveTo(x+s/2,y-s);	ctx.lineTo(x+s/2,y+s);
+		ctx.lineTo(x-s,y);		ctx.closePath();
+		ctx.fill();	 break;
+	case 60:	// '<'
+		ctx.moveTo(x+s/2,y-s);	ctx.lineTo(x+s/2,y+s);
+		ctx.lineTo(x-s,y);		ctx.closePath();
+		ctx.stroke();	break;
+	case 82:	// 'R'
+		ctx.moveTo(x-s/2,y-s);	ctx.lineTo(x-s/2,y+s);
+		ctx.lineTo(x+s,y);		ctx.closePath();
+		ctx.fill();	 break;
+	case 62:	// '>'
+		ctx.moveTo(x-s/2,y-s);	ctx.lineTo(x-s/2,y+s);
+		ctx.lineTo(x+s,y);		ctx.closePath();
+		ctx.stroke();	break;
 //	case 46:	// '.'
-    default:
-        ctx.rect(x,y,1,1); ctx.fill();	 break;
-    }
+	default:
+		ctx.rect(x,y,1,1); ctx.fill();	 break;
+	}
 }
 
 
 /** for internal use only */
 mathgl.Graph.prototype.__mgl_fill_glyph = function(ctx, x,y, f,g,b) {
-    var xx,yy,j,xs,ys;
-    for(j=0;j<g[0];j++)
-    {
-        xx = x+f*g[2][6*j];	yy = y+f*g[2][6*j+1]; ctx.beginPath();
-        ctx.moveTo(b[4]+b[0]*xx+b[1]*yy, b[5]+b[2]*xx+b[3]*yy)
-        xx = x+f*g[2][6*j+2]; yy = y+f*g[2][6*j+3];
-        ctx.lineTo(b[4]+b[0]*xx+b[1]*yy, b[5]+b[2]*xx+b[3]*yy)
-        xx = x+f*g[2][6*j+4]; yy = y+f*g[2][6*j+5];
-        ctx.lineTo(b[4]+b[0]*xx+b[1]*yy, b[5]+b[2]*xx+b[3]*yy)
-        ctx.closePath();	ctx.fill();
-    }
+	var xx,yy,j;
+	var np=0;	ctx.beginPath();
+	for(j=0;j<g[0];j++)
+	{
+		xx = g[1][2*j]; yy = g[1][2*j+1];
+		if(xx==16383 && yy==16383)
+		{
+			ctx.closePath();	np = 1;
+		}
+		else if(np)
+		{
+			xx = x+f*xx;	yy = y+f*yy;	np = 0;
+			ctx.moveTo(b[4]+b[0]*xx+b[1]*yy, b[5]+b[2]*xx+b[3]*yy);
+		}
+		else
+		{
+			xx = x+f*xx;	yy = y+f*yy;
+			ctx.lineTo(b[4]+b[0]*xx+b[1]*yy, b[5]+b[2]*xx+b[3]*yy);
+		}
+	}
+	ctx.closePath();	ctx.fill('evenodd');
 }
 
 
 /** for internal use only */
 mathgl.Graph.prototype.__mgl_wire_glyph = function(ctx, x,y, f,g,b) {
-    var xx,yy,j,xs,ys;
-    var np=1;
-    for(j=0;j<g[1];j++)
-    {
-        xx = g[3][2*j]; yy = g[3][2*j+1];	ctx.beginPath();
-        if(xx==16383 && yy==16383)
-        {
-            ctx.closePath();	ctx.stroke();
-            ctx.beginPath();	np = 1;
-        }
-        else if(np)
-        {
-            xx = x+f*xx;	yy = y+f*yy;	np = 0;
-            ctx.moveTo(b[4]+b[0]*xx+b[1]*yy, b[5]+b[2]*xx+b[3]*yy);
-        }
-        else
-        {
-            xx = x+f*xx;	yy = y+f*yy;
-            ctx.lineTo(b[4]+b[0]*xx+b[1]*yy, b[5]+b[2]*xx+b[3]*yy);
-        }
-        ctx.closePath();	ctx.stroke();
-    }
+	var xx,yy,j;
+	var np=0;	ctx.beginPath();
+	for(j=0;j<g[0];j++)
+	{
+		xx = g[1][2*j]; yy = g[1][2*j+1];
+		if(xx==16383 && yy==16383)
+		{
+			ctx.closePath();	np = 1;
+		}
+		else if(np)
+		{
+			xx = x+f*xx;	yy = y+f*yy;	np = 0;
+			ctx.moveTo(b[4]+b[0]*xx+b[1]*yy, b[5]+b[2]*xx+b[3]*yy);
+		}
+		else
+		{
+			xx = x+f*xx;	yy = y+f*yy;
+			ctx.lineTo(b[4]+b[0]*xx+b[1]*yy, b[5]+b[2]*xx+b[3]*yy);
+		}
+	}
+	ctx.closePath();	ctx.stroke();
 }
 
 
 /** for internal use only */
 mathgl.Graph.prototype.__mgl_line_glyph = function(ctx, x,y, f,solid,b) {
-    var xx,yy,j,xs,ys;
-    var dy = 0.004;
-    ctx.moveTo(b[4]+b[0]*x+b[1]*(y-dy), b[5]+b[2]*x+b[3]*(y-dy));
-    ctx.lineTo(b[4]+b[0]*x+b[1]*(y+dy), b[5]+b[2]*x+b[3]*(y+dy));
-    ctx.lineTo(b[4]+b[0]*(x+f)+b[1]*(y+dy), b[5]+b[2]*(x+f)+b[3]*(y+dy));
-    ctx.lineTo(b[4]+b[0]*(x+f)+b[1]*(y-dy), b[5]+b[2]*(x+f)+b[3]*(y-dy));
-    ctx.closePath();
-    if(solid)	ctx.fill();
-    else		ctx.stroke();
+	var xx,yy,j,xs,ys;
+	var dy = 0.004;
+	ctx.moveTo(b[4]+b[0]*x+b[1]*(y-dy), b[5]+b[2]*x+b[3]*(y-dy));
+	ctx.lineTo(b[4]+b[0]*x+b[1]*(y+dy), b[5]+b[2]*x+b[3]*(y+dy));
+	ctx.lineTo(b[4]+b[0]*(x+f)+b[1]*(y+dy), b[5]+b[2]*(x+f)+b[3]*(y+dy));
+	ctx.lineTo(b[4]+b[0]*(x+f)+b[1]*(y-dy), b[5]+b[2]*(x+f)+b[3]*(y-dy));
+	ctx.closePath();
+	if(solid)	ctx.fill();
+	else		ctx.stroke();
 }
 
 
-mathgl.Graph.prototype.moveLeft = function() { 
+mathgl.Graph.prototype.moveLeft = function() {
 	var b = this.__geometry.b;
 	var f = 0.1/Math.sqrt(b[0]*b[0]+b[1]*b[1]+b[2]*b[2]);
-	this.shiftAxis(f*b[0],f*b[1]);
-	//this.shiftAxis(-0.1,0);
+	this.shiftAxis(f*b[0],f*b[1],f*b[2]);
 }
 
-mathgl.Graph.prototype.moveRight = function() { 
+mathgl.Graph.prototype.moveRight = function() {
 	var b = this.__geometry.b;
 	var f = -0.1/Math.sqrt(b[0]*b[0]+b[1]*b[1]+b[2]*b[2]);
-	this.shiftAxis(f*b[0],f*b[1]);
-	//this.shiftAxis(0.1,0);
+	this.shiftAxis(f*b[0],f*b[1],f*b[2]);
 }
 
-mathgl.Graph.prototype.moveUp = function() { 
+mathgl.Graph.prototype.moveUp = function() {
 	var b = this.__geometry.b;
 	var f = -0.1/Math.sqrt(b[3]*b[3]+b[4]*b[4]+b[5]*b[5]);
-	this.shiftAxis(f*b[3],f*b[4]);
-	//this.shiftAxis(0,-0.1);
+	this.shiftAxis(-f*b[3],f*b[4],-f*b[5]);
 }
 
-mathgl.Graph.prototype.moveDown = function() { 
+mathgl.Graph.prototype.moveDown = function() {
 	var b = this.__geometry.b;
 	var f = 0.1/Math.sqrt(b[3]*b[3]+b[4]*b[4]+b[5]*b[5]);
-	this.shiftAxis(f*b[3],f*b[4]);
-	//this.shiftAxis(0,0.1);
+	this.shiftAxis(-f*b[3],f*b[4],-f*b[5]);
 }
 
-mathgl.Graph.prototype.zoomIn = function() { 
-  this.zoomAxis(1.1);
+mathgl.Graph.prototype.zoomIn = function() {
+	this.zoomAxis(1.1);
 }
 
-mathgl.Graph.prototype.zoomOut = function() { 
-  this.zoomAxis(1./1.1);
+mathgl.Graph.prototype.zoomOut = function() {
+	this.zoomAxis(1./1.1);
 }
-
diff --git a/json/mathgl.WebkitBackend.js b/json/mathgl.WebkitBackend.js
index 92e4c8c..032385b 100644
--- a/json/mathgl.WebkitBackend.js
+++ b/json/mathgl.WebkitBackend.js
@@ -11,21 +11,17 @@ mathgl.WebkitBackend.prototype = new mathgl.Backend();
 
 /** return geometry */
 mathgl.WebkitBackend.prototype.geometry = function(mgl) {
-    var geometryData = globalBackend.geometry(mgl);
-    console.log("geometryData size:",geometryData.length);
+	var geometryData = globalBackend.geometry(mgl);
 
 	/*
 	var zlib = require('zlib');
 	zlib.unzip(geometryData, function(err, buffer) {
-		if (!err)
-		{	geometryData = buffer;
-			console.log("geometryData size:",geometryData.length);	}
-	 });
+		if (!err)	{	geometryData = buffer;	 });
 	 */
 	
-    var obj = JSON.parse(geometryData);
-    obj.pp = new Array();
-    for(var i=0;i<obj.npnts;i++)	// copy original data for transformation
-        obj.pp[i] = [obj.pnts[i][0],obj.pnts[i][1],obj.pnts[i][2]];
-    return obj;
+	var obj = JSON.parse(geometryData);
+	obj.pp = new Array();
+	for(var i=0;i<obj.npnts;i++)	// copy original data for transformation
+		obj.pp[i] = [obj.pnts[i][0],obj.pnts[i][1],obj.pnts[i][2]];
+return obj;
 }
diff --git a/lang/CMakeLists.txt b/lang/CMakeLists.txt
index 9c1a717..6cecfe0 100644
--- a/lang/CMakeLists.txt
+++ b/lang/CMakeLists.txt
@@ -19,7 +19,8 @@ if(MGL_HAVE_PYTHON)
 	SWIG_LINK_LIBRARIES(mathgl mgl ${PYTHON_LIBRARIES})
 	set_target_properties(_mathgl PROPERTIES BUILD_WITH_INSTALL_RPATH ON)
 	add_custom_command(OUTPUT mathgl.pyc
-		COMMAND ${PYTHON_EXECUTABLE} -c \"from py_compile import compile\; compile('mathgl.py')\"
+		COMMAND ${PYTHON_EXECUTABLE}
+		ARGS -c \"from py_compile import compile\; compile('mathgl.py') \"
 		WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/lang
 		DEPENDS _mathgl
 	)
@@ -30,6 +31,16 @@ if(MGL_HAVE_PYTHON)
 	set(mgl_clean_files ${mgl_clean_files} mathgl.py)
 endif(MGL_HAVE_PYTHON)
 
+if(MGL_HAVE_LUA)
+	include_directories(${LUA_INCLUDE_DIR})
+	set(SWIG_MODULE_mgl-lua_EXTRA_DEPS numpy.i ${src_imp_dep})
+	SWIG_ADD_MODULE(mgl-lua lua mathgl.i)
+	SWIG_LINK_LIBRARIES(mgl-lua mgl ${LUA_LIBRARIES})
+	set_target_properties(mgl-lua PROPERTIES PREFIX "" BUILD_WITH_INSTALL_RPATH ON)
+
+	install (TARGETS mgl-lua LIBRARY DESTINATION ${MGL_LIB_INSTALL_DIR})
+endif(MGL_HAVE_LUA)
+
 if(MGL_HAVE_OCTAVE)
 	execute_process(COMMAND ${oct_prog} -p CANONICAL_HOST_TYPE
 	OUTPUT_VARIABLE oct_host
diff --git a/include/mgl2/data.h b/lang/data.i
similarity index 76%
copy from include/mgl2/data.h
copy to lang/data.i
index 7ff2725..77dd22d 100644
--- a/include/mgl2/data.h
+++ b/lang/data.i
@@ -1,521 +1,455 @@
-/***************************************************************************
- * data.h is part of Math Graphic Library
- * Copyright (C) 2007-2012 Alexey Balakin <mathgl.abalakin at gmail.ru>       *
- *                                                                         *
- *   This program is free software; you can redistribute it and/or modify  *
- *   it under the terms of the GNU Library General Public License as       *
- *   published by the Free Software Foundation; either version 3 of the    *
- *   License, or (at your option) any later version.                       *
- *                                                                         *
- *   This program is distributed in the hope that it will be useful,       *
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
- *   GNU General Public License for more details.                          *
- *                                                                         *
- *   You should have received a copy of the GNU Library General Public     *
- *   License along with this program; if not, write to the                 *
- *   Free Software Foundation, Inc.,                                       *
- *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
- ***************************************************************************/
-#ifndef _MGL_DATA_H_
-#define _MGL_DATA_H_
-
-#include "mgl2/data_cf.h"
-#ifdef __cplusplus
-//-----------------------------------------------------------------------------
-#include <vector>
-#include <string>
-//-----------------------------------------------------------------------------
-/// Class for working with data array
-#if MGL_NO_DATA_A
-class mglData
-#else
-class mglData : public mglDataA
-#endif
-{
-public:
-
-	long nx;		///< number of points in 1st dimensions ('x' dimension)
-	long ny;		///< number of points in 2nd dimensions ('y' dimension)
-	long nz;		///< number of points in 3d dimensions ('z' dimension)
-	mreal *a;		///< data array
-	std::string id;	///< column (or slice) names
-	bool link;		///< use external data (i.e. don't free it)
-
-	/// Initiate by other mglData variable
-	inline mglData(const mglData &d)	{	a=0;	mgl_data_set(this,&d);		}	// NOTE: must be constructor for mglData& to exclude copy one
-	inline mglData(const mglDataA *d)	{	a=0;	mgl_data_set(this, d);		}
-	inline mglData(bool, mglData *d)	// NOTE: Variable d will be deleted!!!
-	{	if(d)
-		{	nx=d->nx;	ny=d->ny;	nz=d->nz;	a=d->a;	d->a=0;
-			id=d->id;	link=d->link;	delete d;	}
-		else	{	a=0;	Create(1);	}	}
-	/// Initiate by flat array
-	inline mglData(int size, const float *d)	{	a=0;	Set(d,size);	}
-	inline mglData(int rows, int cols, const float *d)	{	a=0;	Set(d,cols,rows);	}
-	inline mglData(int size, const double *d)	{	a=0;	Set(d,size);	}
-	inline mglData(int rows, int cols, const double *d)	{	a=0;	Set(d,cols,rows);	}
-	inline mglData(const double *d, int size)	{	a=0;	Set(d,size);	}
-	inline mglData(const double *d, int rows, int cols)	{	a=0;	Set(d,cols,rows);	}
-	/// Read data from file
-	inline mglData(const char *fname)			{	a=0;	Read(fname);	}
-	/// Allocate the memory for data array and initialize it zero
-	inline mglData(long xx=1,long yy=1,long zz=1)	{	a=0;	Create(xx,yy,zz);	}
-	/// Delete the array
-	virtual ~mglData()	{	if(!link && a)	delete []a;	}
-	inline mreal GetVal(long i, long j=0, long k=0)
-	{	return mgl_data_get_value(this,i,j,k);}
-	inline void SetVal(mreal f, long i, long j=0, long k=0)
-	{	mgl_data_set_value(this,f,i,j,k);	}
-	/// Get sizes
-	inline long GetNx() const	{	return nx;	}
-	inline long GetNy() const	{	return ny;	}
-	inline long GetNz() const	{	return nz;	}
-
-	/// Link external data array (don't delete it at exit)
-	inline void Link(mreal *A, long NX, long NY=1, long NZ=1)
-	{	mgl_data_link(this,A,NX,NY,NZ);	}
-	inline void Link(mglData &d)	{	Link(d.a,d.nx,d.ny,d.nz);	}
-	/// Allocate memory and copy the data from the gsl_vector
-	inline void Set(gsl_vector *m)	{	mgl_data_set_vector(this,m);	}
-	/// Allocate memory and copy the data from the gsl_matrix
-	inline void Set(gsl_matrix *m)	{	mgl_data_set_matrix(this,m);	}
-
-	/// Allocate memory and copy the data from the (float *) array
-	inline void Set(const float *A,long NX,long NY=1,long NZ=1)
-	{	mgl_data_set_float(this,A,NX,NY,NZ);	}
-	/// Allocate memory and copy the data from the (double *) array
-	inline void Set(const double *A,long NX,long NY=1,long NZ=1)
-	{	mgl_data_set_double(this,A,NX,NY,NZ);	}
-	/// Allocate memory and copy the data from the (float **) array
-	inline void Set(const float **A,long N1,long N2)
-	{	mgl_data_set_float2(this,A,N1,N2);	}
-	/// Allocate memory and copy the data from the (double **) array
-	inline void Set(const double **A,long N1,long N2)
-	{	mgl_data_set_double2(this,A,N1,N2);	}
-	/// Allocate memory and copy the data from the (float ***) array
-	inline void Set(const float ***A,long N1,long N2,long N3)
-	{	mgl_data_set_float3(this,A,N1,N2,N3);	}
-	/// Allocate memory and copy the data from the (double ***) array
-	inline void Set(const double ***A,long N1,long N2,long N3)
-	{	mgl_data_set_double3(this,A,N1,N2,N3);	}
-	/// Allocate memory and scanf the data from the string
-	inline void Set(const char *str,long NX,long NY=1,long NZ=1)
-	{	mgl_data_set_values(this,str,NX,NY,NZ);	}
-	/// Import data from abstract type
-	inline void Set(HCDT dat)	{	mgl_data_set(this, dat);	}
-	inline void Set(const mglDataA &dat)	{	mgl_data_set(this, &dat);	}
-	/// Allocate memory and copy data from std::vector<T>
-	inline void Set(const std::vector<int> &d)
-	{	if(d.size()<1)	return;
-		Create(d.size());	for(long i=0;i<nx;i++)	a[i] = d[i];	}
-	inline void Set(const std::vector<float> &d)
-	{	if(d.size()<1)	return;
-		Create(d.size());	for(long i=0;i<nx;i++)	a[i] = d[i];	}
-	inline void Set(const std::vector<double> &d)
-	{	if(d.size()<1)	return;
-		Create(d.size());	for(long i=0;i<nx;i++)	a[i] = d[i];	}
-
-	/// Create or recreate the array with specified size and fill it by zero
-	inline void Create(long mx,long my=1,long mz=1)
-	{	mgl_data_create(this,mx,my,mz);	}
-	/// Rearange data dimensions
-	inline void Rearrange(long mx, long my=0, long mz=0)
-	{	mgl_data_rearrange(this,mx,my,mz);	}
-	/// Transpose dimensions of the data (generalization of Transpose)
-	inline void Transpose(const char *dim="yx")
-	{	mgl_data_transpose(this,dim);	}
-	/// Extend data dimensions
-	inline void Extend(long n1, long n2=0)
-	{	mgl_data_extend(this,n1,n2);	}
-	/// Reduce size of the data
-	inline void Squeeze(long rx,long ry=1,long rz=1,bool smooth=false)
-	{	mgl_data_squeeze(this,rx,ry,rz,smooth);	}
-	/// Crop the data
-	inline void Crop(long n1, long n2,char dir='x')
-	{	mgl_data_crop(this,n1,n2,dir);	}
-	/// Insert data rows/columns/slices
-	inline void Insert(char dir, long at=0, long num=1)
-	{	mgl_data_insert(this,dir,at,num);	}
-	/// Delete data rows/columns/slices
-	inline void Delete(char dir, long at=0, long num=1)
-	{	mgl_data_delete(this,dir,at,num);	}
-	/// Remove rows with duplicate values in column id
-	inline void Clean(long id)
-	{	mgl_data_clean(this,id);	}
-	/// Join with another data array
-	inline void Join(const mglDataA &d)
-	{	mgl_data_join(this,&d);	}
-	
-	/// Modify the data by specified formula
-	inline void Modify(const char *eq,long dim=0)
-	{	mgl_data_modify(this, eq, dim);	}
-	/// Modify the data by specified formula
-	inline void Modify(const char *eq,const mglDataA &vdat, const mglDataA &wdat)
-	{	mgl_data_modify_vw(this,eq,&vdat,&wdat);	}
-	/// Modify the data by specified formula
-	inline void Modify(const char *eq,const mglDataA &vdat)
-	{	mgl_data_modify_vw(this,eq,&vdat,0);	}
-	/// Modify the data by specified formula assuming x,y,z in range [r1,r2]
-	inline void Fill(mglBase *gr, const char *eq, const char *opt="")
-	{	mgl_data_fill_eq(gr,this,eq,0,0,opt);	}
-	inline void Fill(mglBase *gr, const char *eq, const mglDataA &vdat, const char *opt="")
-	{	mgl_data_fill_eq(gr,this,eq,&vdat,0,opt);	}
-	inline void Fill(mglBase *gr, const char *eq, const mglDataA &vdat, const mglDataA &wdat,const char *opt="")
-	{	mgl_data_fill_eq(gr,this,eq,&vdat,&wdat,opt);	}
-	/// Equidistantly fill the data to range [x1,x2] in direction dir
-	inline void Fill(mreal x1,mreal x2=NaN,char dir='x')
-	{	return mgl_data_fill(this,x1,x2,dir);	}
-	/// Set the data by triangulated surface values assuming x,y,z in range [r1,r2]
-	inline void Grid(mglBase *gr, const mglDataA &x, const mglDataA &y, const mglDataA &z, const char *opt="")
-	{	mgl_data_grid(gr,this,&x,&y,&z,opt);	}
-	/// Put value to data element(s)
-	inline void Put(mreal val, long i=-1, long j=-1, long k=-1)
-	{	mgl_data_put_val(this,val,i,j,k);	}
-	/// Put array to data element(s)
-	inline void Put(const mglDataA &dat, long i=-1, long j=-1, long k=-1)
-	{	mgl_data_put_dat(this,&dat,i,j,k);	}
-	/// Set names for columns (slices)
-	inline void SetColumnId(const char *ids)
-	{	mgl_data_set_id(this,ids);	}
-	/// Make new id
-	inline void NewId()	{	id.clear();	}
-
-	/// Read data from tab-separated text file with auto determining size
-	inline bool Read(const char *fname)
-	{	return mgl_data_read(this,fname); }
-	/// Read data from text file with specifeid size
-	inline bool Read(const char *fname,long mx,long my=1,long mz=1)
-	{	return mgl_data_read_dim(this,fname,mx,my,mz);	}
-	/// Save whole data array (for ns=-1) or only ns-th slice to text file
-	inline void Save(const char *fname,long ns=-1) const
-	{	mgl_data_save(this,fname,ns);	}
-	/// Export data array (for ns=-1) or only ns-th slice to PNG file according color scheme
-	inline void Export(const char *fname,const char *scheme,mreal v1=0,mreal v2=0,long ns=-1) const
-	{	mgl_data_export(this,fname,scheme,v1,v2,ns);	}
-	/// Import data array from PNG file according color scheme
-	inline void Import(const char *fname,const char *scheme,mreal v1=0,mreal v2=1)
-	{	mgl_data_import(this,fname,scheme,v1,v2);	}
-	/// Read data from tab-separated text files with auto determining size which filenames are result of sprintf(fname,templ,t) where t=from:step:to
-	inline bool ReadRange(const char *templ, double from, double to, double step=1, bool as_slice=false)
-	{	return mgl_data_read_range(this,templ,from,to,step,as_slice);	}
-	/// Read data from tab-separated text files with auto determining size which filenames are satisfied to template (like "t_*.dat")
-	inline bool ReadAll(const char *templ, bool as_slice=false)
-	{	return mgl_data_read_all(this, templ, as_slice);	}
-	/// Read data from text file with size specified at beginning of the file
-	inline bool ReadMat(const char *fname, long dim=2)
-	{	return mgl_data_read_mat(this,fname,dim);	}
-	/// Read data array from HDF file (parse HDF4 and HDF5 files)
-	inline int ReadHDF(const char *fname,const char *data)
-	{	return mgl_data_read_hdf(this,fname,data);	}
-	/// Save data to HDF file
-	inline void SaveHDF(const char *fname,const char *data,bool rewrite=false) const
-	{	mgl_data_save_hdf(this,fname,data,rewrite);	}
-	/// Put HDF data names into buf as '\t' separated.
-	inline static int DatasHDF(const char *fname, char *buf, long size)
-	{	return mgl_datas_hdf(fname,buf,size);	}
-
-	/// Get column (or slice) of the data filled by formulas of named columns
-	inline mglData Column(const char *eq) const
-	{	return mglData(true,mgl_data_column(this,eq));	}
-	/// Get momentum (1D-array) of data along direction 'dir'. String looks like "x1" for median in x-direction, "x2" for width in x-dir and so on.
-	inline mglData Momentum(char dir, const char *how) const
-	{	return mglData(true,mgl_data_momentum(this,dir,how));	}
-	/// Get sub-array of the data with given fixed indexes
-	inline mglData SubData(long xx,long yy=-1,long zz=-1) const
-	{	return mglData(true,mgl_data_subdata(this,xx,yy,zz));	}
-	inline mglData SubData(const mglDataA &xx, const mglDataA &yy, const mglDataA &zz) const
-	{	return mglData(true,mgl_data_subdata_ext(this,&xx,&yy,&zz));	}
-	/// Get trace of the data array
-	inline mglData Trace() const
-	{	return mglData(true,mgl_data_trace(this));	}
-	/// Create n-th points distribution of this data values in range [v1, v2]
-	inline mglData Hist(long n,mreal v1=0,mreal v2=1, long nsub=0) const
-	{	return mglData(true,mgl_data_hist(this,n,v1,v2,nsub));	}
-	/// Create n-th points distribution of this data values in range [v1, v2] with weight w
-	inline mglData Hist(const mglDataA &w, long n,mreal v1=0,mreal v2=1, long nsub=0) const
-	{	return mglData(true,mgl_data_hist_w(this,&w,n,v1,v2,nsub));	}
-	/// Get array which is result of summation in given direction or directions
-	inline mglData Sum(const char *dir) const
-	{	return mglData(true,mgl_data_sum(this,dir));	}
-	/// Get array which is result of maximal values in given direction or directions
-	inline mglData Max(const char *dir) const
-	{	return mglData(true,mgl_data_max_dir(this,dir));	}
-	/// Get array which is result of minimal values in given direction or directions
-	inline mglData Min(const char *dir) const
-	{	return mglData(true,mgl_data_min_dir(this,dir));	}
-	/// Get the data which is direct multiplication (like, d[i,j] = this[i]*a[j] and so on)
-	inline mglData Combine(const mglDataA &dat) const
-	{	return mglData(true,mgl_data_combine(this,&dat));	}
-	/// Resize the data to new size of box [x1,x2]*[y1,y2]*[z1,z2]
-	inline mglData Resize(long mx,long my=1,long mz=1, mreal x1=0,mreal x2=1, mreal y1=0,mreal y2=1, mreal z1=0,mreal z2=1) const
-	{	return mglData(true,mgl_data_resize_box(this,mx,my,mz,x1,x2,y1,y2,z1,z2));	}
-	/// Get array which values is result of interpolation this for coordinates from other arrays
-	inline mglData Evaluate(const mglData &idat, bool norm=true) const
-	{	return mglData(true,mgl_data_evaluate(this,&idat,0,0,norm));	}
-	inline mglData Evaluate(const mglData &idat, const mglData &jdat, bool norm=true) const
-	{	return mglData(true,mgl_data_evaluate(this,&idat,&jdat,0,norm));	}
-	inline mglData Evaluate(const mglData &idat, const mglData &jdat, const mglData &kdat, bool norm=true) const
-	{	return mglData(true,mgl_data_evaluate(this,&idat,&jdat,&kdat,norm));	}
-	/// Find roots for set of nonlinear equations defined by textual formula
-	inline mglData Roots(const char *func, char var='x') const
-	{	return mglData(true,mgl_data_roots(func, this, var));	}
-	
-	/// Cumulative summation the data in given direction or directions
-	inline void CumSum(const char *dir)	{	mgl_data_cumsum(this,dir);	}
-	/// Integrate (cumulative summation) the data in given direction or directions
-	inline void Integral(const char *dir)	{	mgl_data_integral(this,dir);	}
-	/// Differentiate the data in given direction or directions
-	inline void Diff(const char *dir)	{	mgl_data_diff(this,dir);	}
-	/// Differentiate the parametrically specified data along direction v1 with v2=const
-	inline void Diff(const mglDataA &v1, const mglDataA &v2)
-	{	mgl_data_diff_par(this,&v1,&v2,0);	}
-	/// Differentiate the parametrically specified data along direction v1 with v2,v3=const
-	inline void Diff(const mglDataA &v1, const mglDataA &v2, const mglDataA &v3)
-	{	mgl_data_diff_par(this,&v1,&v2,&v3);	}
-	/// Double-differentiate (like Laplace operator) the data in given direction
-	inline void Diff2(const char *dir)	{	mgl_data_diff2(this,dir);	}
-
-	/// Swap left and right part of the data in given direction (useful for Fourier spectrum)
-	inline void Swap(const char *dir)		{	mgl_data_swap(this,dir);	}
-	/// Roll data along direction dir by num slices
-	inline void Roll(char dir, long num)	{	mgl_data_roll(this,dir,num);	}
-	/// Mirror the data in given direction (useful for Fourier spectrum)
-	inline void Mirror(const char *dir)		{	mgl_data_mirror(this,dir);	}
-	/// Sort rows (or slices) by values of specified column
-	inline void Sort(long idx, long idy=-1)	{	mgl_data_sort(this,idx,idy);	}
-
-	/// Set as the data envelop
-	inline void Envelop(char dir='x')
-	{	mgl_data_envelop(this,dir);	}
-	/// Remove phase jump
-	inline void Sew(const char *dirs="xyz", mreal da=2*Pi)
-	{	mgl_data_sew(this,dirs,da);	}
-	/// Smooth the data on specified direction or directions
-	inline void Smooth(const char *dirs="xyz",mreal delta=0)
-	{	mgl_data_smooth(this,dirs,delta);	}
-	/// Normalize the data to range [v1,v2]
-	inline void Norm(mreal v1=0,mreal v2=1,bool sym=false,long dim=0)
-	{	mgl_data_norm(this,v1,v2,sym,dim);	}
-	/// Normalize the data to range [v1,v2] slice by slice
-	inline void NormSl(mreal v1=0,mreal v2=1,char dir='z',bool keep_en=true,bool sym=false)
-	{	mgl_data_norm_slice(this,v1,v2,dir,keep_en,sym);	}
-
-	/// Apply Hankel transform
-	inline void Hankel(const char *dir)	{	mgl_data_hankel(this,dir);	}
-	/// Apply Sin-Fourier transform
-	inline void SinFFT(const char *dir)	{	mgl_data_sinfft(this,dir);	}
-	/// Apply Cos-Fourier transform
-	inline void CosFFT(const char *dir)	{	mgl_data_cosfft(this,dir);	}
-	/// Fill data by 'x'/'k' samples for Hankel ('h') or Fourier ('f') transform
-	inline void FillSample(const char *how)
-	{	mgl_data_fill_sample(this,how);	}
-
-	/// Interpolate by cubic spline the data to given point x=[0...nx-1], y=[0...ny-1], z=[0...nz-1]
-	inline mreal Spline(mreal x,mreal y=0,mreal z=0) const
-	{	return mgl_data_spline(this, x,y,z);	}
-	/// Interpolate by cubic spline the data to given point x,\a y,\a z which normalized in range [0, 1]
-	inline mreal Spline1(mreal x,mreal y=0,mreal z=0) const
-	{	return mgl_data_spline(this, x*(nx-1),y*(ny-1),z*(nz-1));	}
-	/// Interpolate by linear function the data to given point x=[0...nx-1], y=[0...ny-1], z=[0...nz-1]
-	inline mreal Linear(mreal x,mreal y=0,mreal z=0)	const
-	{	return mgl_data_linear(this,x,y,z);	}
-	/// Interpolate by line the data to given point x,\a y,\a z which normalized in range [0, 1]
-	inline mreal Linear1(mreal x,mreal y=0,mreal z=0) const
-	{	return mgl_data_linear(this,x*(nx-1),y*(ny-1),z*(nz-1));	}
-	/// Return an approximated x-value (root) when dat(x) = val
-	inline mreal Solve(mreal val, bool use_spline=true, long i0=0) const
-	{	return mgl_data_solve_1d(this, val, use_spline, i0);		}
-	/// Return an approximated value (root) when dat(x) = val
-	inline mglData Solve(mreal val, char dir, bool norm=true) const
-	{	return mglData(true,mgl_data_solve(this, val, dir, 0, norm));	}
-	inline mglData Solve(mreal val, char dir, const mglData &i0, bool norm=true) const
-	{	return mglData(true,mgl_data_solve(this, val, dir, &i0, norm));	}
-	
-	/// Interpolate by cubic spline the data and return its derivatives at given point x=[0...nx-1], y=[0...ny-1], z=[0...nz-1]
-	inline mreal Spline(mglPoint &dif, mreal x,mreal y=0,mreal z=0) const
-	{	return mgl_data_spline_ext(this, x,y,z, &(dif.x),&(dif.y), &(dif.z));	}
-	/// Interpolate by cubic spline the data and return its derivatives at given point x,\a y,\a z which normalized in range [0, 1]
-	inline mreal Spline1(mglPoint &dif, mreal x,mreal y=0,mreal z=0) const
-	{	mreal res=mgl_data_spline_ext(this, x*(nx-1),y*(ny-1),z*(nz-1), &(dif.x),&(dif.y), &(dif.z));
-		dif.x*=nx>1?nx-1:1;	dif.y*=ny>1?ny-1:1;	dif.z*=nz>1?nz-1:1;	return res;	}
-	/// Interpolate by linear function the data and return its derivatives at given point x=[0...nx-1], y=[0...ny-1], z=[0...nz-1]
-	inline mreal Linear(mglPoint &dif, mreal x,mreal y=0,mreal z=0)	const
-	{	return mgl_data_linear_ext(this,x,y,z, &(dif.x),&(dif.y), &(dif.z));	}
-	/// Interpolate by line the data and return its derivatives at given point x,\a y,\a z which normalized in range [0, 1]
-	inline mreal Linear1(mglPoint &dif, mreal x,mreal y=0,mreal z=0) const
-	{	mreal res=mgl_data_linear_ext(this,x*(nx-1),y*(ny-1),z*(nz-1), &(dif.x),&(dif.y), &(dif.z));
-		dif.x*=nx>1?nx-1:1;	dif.y*=ny>1?ny-1:1;	dif.z*=nz>1?nz-1:1;	return res;	}
-	
-	/// Get information about the data (sizes and momentum) to string
-	inline const char *PrintInfo() const	{	return mgl_data_info(this);	}
-	/// Print information about the data (sizes and momentum) to FILE (for example, stdout)
-	inline void PrintInfo(FILE *fp) const
-	{	if(fp)	{	fprintf(fp,"%s",mgl_data_info(this));	fflush(fp);	}	}
-	/// Get maximal value of the data
-	inline mreal Maximal() const	{	return mgl_data_max(this);	}
-	/// Get minimal value of the data
-	inline mreal Minimal() const	{	return mgl_data_min(this);	}
-	/// Get maximal value of the data and its position
-	inline mreal Maximal(long &i,long &j,long &k) const
-	{	return mgl_data_max_int(this,&i,&j,&k);	}
-	/// Get minimal value of the data and its position
-	inline mreal Minimal(long &i,long &j,long &k) const
-	{	return mgl_data_min_int(this,&i,&j,&k);	}
-	/// Get maximal value of the data and its approximated position
-	inline mreal Maximal(mreal &x,mreal &y,mreal &z) const
-	{	return mgl_data_max_real(this,&x,&y,&z);	}
-	/// Get minimal value of the data and its approximated position
-	inline mreal Minimal(mreal &x,mreal &y,mreal &z) const
-	{	return mgl_data_min_real(this,&x,&y,&z);	}
-	/// Get "energy" and find first (median) and second (width) momenta of data
-	inline mreal Momentum(char dir,mreal &m,mreal &w) const
-	{	return mgl_data_momentum_val(this,dir,&m,&w,0,0);	}
-	/// Get "energy and find 4 momenta of data: median, width, skewness, kurtosis
-	inline mreal Momentum(char dir,mreal &m,mreal &w,mreal &s,mreal &k) const
-	{	return mgl_data_momentum_val(this,dir,&m,&w,&s,&k);	}
-	/// Find position (after specified in i,j,k) of first nonzero value of formula
-	inline mreal Find(const char *cond, long &i, long &j, long &k) const
-	{	return mgl_data_first(this,cond,&i,&j,&k);	}
-	/// Find position (before specified in i,j,k) of last nonzero value of formula
-	inline mreal Last(const char *cond, long &i, long &j, long &k) const
-	{	return mgl_data_last(this,cond,&i,&j,&k);	}
-	/// Find position of first in direction 'dir' nonzero value of formula
-	inline long Find(const char *cond, char dir, long i=0, long j=0, long k=0) const
-	{	return mgl_data_find(this,cond,dir,i,j,k);	}
-	/// Find if any nonzero value of formula
-	inline bool FindAny(const char *cond) const
-	{	return mgl_data_find_any(this,cond);	}
-
-	/// Copy data from other mglData variable
-	inline mglData &operator=(const mglData &d)
-	{	if(this!=&d)	Set(d.a,d.nx,d.ny,d.nz);	return *this;	}
-	inline mreal operator=(mreal val)
-	{	for(long i=0;i<nx*ny*nz;i++)	a[i]=val;	return val;	}
-	/// Multiply the data by other one for each element
-	inline void operator*=(const mglDataA &d)	{	mgl_data_mul_dat(this,&d);	}
-	/// Divide the data by other one for each element
-	inline void operator/=(const mglDataA &d)	{	mgl_data_div_dat(this,&d);	}
-	/// Add the other data
-	inline void operator+=(const mglDataA &d)	{	mgl_data_add_dat(this,&d);	}
-	/// Subtract the other data
-	inline void operator-=(const mglDataA &d)	{	mgl_data_sub_dat(this,&d);	}
-	/// Multiply each element by the number
-	inline void operator*=(mreal d)		{	mgl_data_mul_num(this,d);	}
-	/// Divide each element by the number
-	inline void operator/=(mreal d)		{	mgl_data_div_num(this,d);	}
-	/// Add the number
-	inline void operator+=(mreal d)		{	mgl_data_add_num(this,d);	}
-	/// Subtract the number
-	inline void operator-=(mreal d)		{	mgl_data_sub_num(this,d);	}
-#ifndef SWIG
-	/// Direct access to the data cell
-	inline mreal &operator[](long i)	{	return a[i];	}
-	// NOTE see 13.10 for operator(), operator[] -- m.b. I should add it ???
-#endif
-#if MGL_NO_DATA_A
-	inline long GetNN() const {	return nx*ny*nz;	}
-#else
-protected:
-#endif
-	/// Get the value in given cell of the data without border checking
-	inline mreal v(long i,long j=0,long k=0) const
-#ifdef DEBUG
-	{	if(i<0 || j<0 || k<0 || i>=nx || j>=ny || k>=nz)	printf("Wrong index in mglData");
-		return a[i+nx*(j+ny*k)];	}
-#else
-	{	return a[i+nx*(j+ny*k)];	}
-#endif
-	inline mreal vthr(long i) const {	return a[i];	}
-	// add for speeding up !!!
-	inline mreal dvx(long i,long j=0,long k=0) const
-	{   register long i0=i+nx*(j+ny*k);
-		return i>0? (i<nx-1? (a[i0+1]-a[i0-1])/2:a[i0]-a[i0-1]) : a[i0+1]-a[i0];	}
-	inline mreal dvy(long i,long j=0,long k=0) const
-	{   register long i0=i+nx*(j+ny*k);
-		return j>0? (j<ny-1? (a[i0+nx]-a[i0-nx])/2:a[i0]-a[i0-nx]) : a[i0+nx]-a[i0];}
-	inline mreal dvz(long i,long j=0,long k=0) const
-	{   register long i0=i+nx*(j+ny*k), n=nx*ny;
-		return k>0? (k<nz-1? (a[i0+n]-a[i0-n])/2:a[i0]-a[i0-n]) : a[i0+n]-a[i0];	}
-};
-//-----------------------------------------------------------------------------
-#ifndef SWIG
-inline mglData operator*(const mglDataA &b, const mglDataA &d)
-{	mglData a(&b);	a*=d;	return a;	}
-inline mglData operator*(mreal b, const mglDataA &d)
-{	mglData a(&d);	a*=b;	return a;	}
-inline mglData operator*(const mglDataA &d, mreal b)
-{	mglData a(&d);	a*=b;	return a;	}
-inline mglData operator-(const mglDataA &b, const mglDataA &d)
-{	mglData a(&b);	a-=d;	return a;	}
-inline mglData operator-(mreal b, const mglDataA &d)
-{	mglData a(&d);	a-=b;	return a;	}
-inline mglData operator-(const mglDataA &d, mreal b)
-{	mglData a(&d);	a-=b;	return a;	}
-inline mglData operator+(const mglDataA &b, const mglDataA &d)
-{	mglData a(&b);	a+=d;	return a;	}
-inline mglData operator+(mreal b, const mglDataA &d)
-{	mglData a(&d);	a+=b;	return a;	}
-inline mglData operator+(const mglDataA &d, mreal b)
-{	mglData a(&d);	a+=b;	return a;	}
-inline mglData operator/(const mglDataA &b, const mglDataA &d)
-{	mglData a(&b);	a/=d;	return a;	}
-inline mglData operator/(const mglDataA &d, mreal b)
-{	mglData a(&d);	a/=b;	return a;	}
-inline bool operator==(const mglData &b, const mglData &d)
-{	if(b.nx!=d.nx || b.ny!=d.ny || b.ny!=d.ny)	return false;
-	return !memcmp(b.a,d.a,b.nx*b.ny*b.nz*sizeof(mreal));	}
-inline bool operator<(const mglDataA &b, const mglDataA &d)
-{	return b.Maximal()<d.Maximal();	}
-inline bool operator>(const mglDataA &b, const mglDataA &d)
-{	return b.Minimal()>d.Minimal();	}
-#endif
-//-----------------------------------------------------------------------------
-#ifndef SWIG
-mreal mglLinear(const mreal *a, long nx, long ny, long nz, mreal x, mreal y, mreal z);
-mreal mglSpline3(const mreal *a, long nx, long ny, long nz, mreal x, mreal y, mreal z,mreal *dx=0, mreal *dy=0, mreal *dz=0);
-#endif
-//-----------------------------------------------------------------------------
-/// Integral data transformation (like Fourier 'f' or 'i', Hankel 'h' or None 'n') for amplitude and phase
-inline mglData mglTransformA(const mglDataA &am, const mglDataA &ph, const char *tr)
-{	return mglData(true,mgl_transform_a(&am,&ph,tr));	}
-/// Integral data transformation (like Fourier 'f' or 'i', Hankel 'h' or None 'n') for real and imaginary parts
-inline mglData mglTransform(const mglDataA &re, const mglDataA &im, const char *tr)
-{	return mglData(true,mgl_transform(&re,&im,tr));	}
-/// Apply Fourier transform for the data and save result into it
-inline void mglFourier(mglData &re, mglData &im, const char *dir)
-{	mgl_data_fourier(&re,&im,dir);	}
-/// Short time Fourier analysis for real and imaginary parts. Output is amplitude of partial Fourier (result will have size {dn, floor(nx/dn), ny} for dir='x'
-inline mglData mglSTFA(const mglDataA &re, const mglDataA &im, long dn, char dir='x')
-{	return mglData(true, mgl_data_stfa(&re,&im,dn,dir));	}
-//-----------------------------------------------------------------------------
-/// Saves result of PDE solving (|u|^2) for "Hamiltonian" ham with initial conditions ini
-inline mglData mglPDE(mglBase *gr, const char *ham, const mglDataA &ini_re, const mglDataA &ini_im, mreal dz=0.1, mreal k0=100,const char *opt="")
-{	return mglData(true, mgl_pde_solve(gr,ham, &ini_re, &ini_im, dz, k0,opt));	}
-/// Saves result of PDE solving for "Hamiltonian" ham with initial conditions ini along a curve ray (must have nx>=7 - x,y,z,px,py,pz,tau or nx=5 - x,y,px,py,tau)
-inline mglData mglQO2d(const char *ham, const mglDataA &ini_re, const mglDataA &ini_im, const mglDataA &ray, mreal r=1, mreal k0=100)
-{	return mglData(true, mgl_qo2d_solve(ham, &ini_re, &ini_im, &ray, r, k0, 0, 0));	}
-inline mglData mglQO2d(const char *ham, const mglDataA &ini_re, const mglDataA &ini_im, const mglDataA &ray, mglData &xx, mglData &yy, mreal r=1, mreal k0=100)
-{	return mglData(true, mgl_qo2d_solve(ham, &ini_re, &ini_im, &ray, r, k0, &xx, &yy));	}
-/// Saves result of PDE solving for "Hamiltonian" ham with initial conditions ini along a curve ray (must have nx>=7 - x,y,z,px,py,pz,tau or nx=5 - x,y,px,py,tau)
-inline mglData mglQO3d(const char *ham, const mglDataA &ini_re, const mglDataA &ini_im, const mglDataA &ray, mreal r=1, mreal k0=100)
-{	return mglData(true, mgl_qo3d_solve(ham, &ini_re, &ini_im, &ray, r, k0, 0, 0, 0));	}
-inline mglData mglQO3d(const char *ham, const mglDataA &ini_re, const mglDataA &ini_im, const mglDataA &ray, mglData &xx, mglData &yy, mglData &zz, mreal r=1, mreal k0=100)
-{	return mglData(true, mgl_qo3d_solve(ham, &ini_re, &ini_im, &ray, r, k0, &xx, &yy, &zz));	}
-/// Finds ray with starting point r0, p0 (and prepares ray data for mglQO2d)
-inline mglData mglRay(const char *ham, mglPoint r0, mglPoint p0, mreal dt=0.1, mreal tmax=10)
-{	return mglData(true, mgl_ray_trace(ham, r0.x, r0.y, r0.z, p0.x, p0.y, p0.z, dt, tmax));	}
-/// Calculate Jacobian determinant for D{x(u,v), y(u,v)} = dx/du*dy/dv-dx/dv*dy/du
-inline mglData mglJacobian(const mglDataA &x, const mglDataA &y)
-{	return mglData(true, mgl_jacobian_2d(&x, &y));	}
-/// Calculate Jacobian determinant for D{x(u,v,w), y(u,v,w), z(u,v,w)}
-inline mglData mglJacobian(const mglDataA &x, const mglDataA &y, const mglDataA &z)
-{	return mglData(true, mgl_jacobian_3d(&x, &y, &z));	}
-/// Do something like Delone triangulation
-inline mglData mglTriangulation(const mglDataA &x, const mglDataA &y, const mglDataA &z)
-{	return mglData(true,mgl_triangulation_3d(&x,&y,&z));	}
-inline mglData mglTriangulation(const mglDataA &x, const mglDataA &y)
-{	return mglData(true,mgl_triangulation_2d(&x,&y));	}
-//-----------------------------------------------------------------------------
-#endif
-#endif
+/***************************************************************************
+ * data.i is part of Math Graphic Library
+ * Copyright (C) 2007-2012 Alexey Balakin <mathgl.abalakin at gmail.ru>       *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU Library General Public License as       *
+ *   published by the Free Software Foundation; either version 3 of the    *
+ *   License, or (at your option) any later version.                       *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU Library General Public     *
+ *   License along with this program; if not, write to the                 *
+ *   Free Software Foundation, Inc.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+//-----------------------------------------------------------------------------
+#include <string>
+class mglData
+{
+public:
+
+	long nx;		///< number of points in 1st dimensions ('x' dimension)
+	long ny;		///< number of points in 2nd dimensions ('y' dimension)
+	long nz;		///< number of points in 3d dimensions ('z' dimension)
+	mreal *a;		///< data array
+	std::string id;	///< column (or slice) names
+	bool link;		///< use external data (i.e. don't free it)
+
+	/// Initiate by other mglData variable
+	inline mglData(const mglData &d)	{	a=0;	mgl_data_set(this,&d);		}	// NOTE: must be constructor for mglData& to exclude copy one
+	inline mglData(const mglData *d)	{	a=0;	mgl_data_set(this, d);		}
+	inline mglData(bool, mglData *d)	// NOTE: Variable d will be deleted!!!
+	{	if(d)
+		{	nx=d->nx;	ny=d->ny;	nz=d->nz;	a=d->a;	d->a=0;
+			id=d->id;	link=d->link;	delete d;	}
+		else	{	a=0;	Create(1);	}	}
+	/// Initiate by flat array
+	inline mglData(int size, const float *d)	{	a=0;	Set(d,size);	}
+	inline mglData(int rows, int cols, const float *d)	{	a=0;	Set(d,cols,rows);	}
+	inline mglData(int size, const double *d)	{	a=0;	Set(d,size);	}
+	inline mglData(int rows, int cols, const double *d)	{	a=0;	Set(d,cols,rows);	}
+	inline mglData(const double *d, int size)	{	a=0;	Set(d,size);	}
+	inline mglData(const double *d, int rows, int cols)	{	a=0;	Set(d,cols,rows);	}
+	/// Read data from file
+	inline mglData(const char *fname)			{	a=0;	Read(fname);	}
+	/// Allocate the memory for data array and initialize it zero
+	inline mglData(long xx=1,long yy=1,long zz=1)	{	a=0;	Create(xx,yy,zz);	}
+	/// Delete the array
+	virtual ~mglData()	{	if(!link && a)	delete []a;	}
+	inline mreal GetVal(long i, long j=0, long k=0)
+	{	return mgl_data_get_value(this,i,j,k);}
+	inline void SetVal(mreal f, long i, long j=0, long k=0)
+	{	mgl_data_set_value(this,f,i,j,k);	}
+	/// Get sizes
+	inline long GetNx() const	{	return nx;	}
+	inline long GetNy() const	{	return ny;	}
+	inline long GetNz() const	{	return nz;	}
+
+	/// Link external data array (don't delete it at exit)
+	inline void Link(mreal *A, long NX, long NY=1, long NZ=1)
+	{	mgl_data_link(this,A,NX,NY,NZ);	}
+	inline void Link(mglData &d)	{	Link(d.a,d.nx,d.ny,d.nz);	}
+	/// Allocate memory and copy the data from the gsl_vector
+	inline void Set(gsl_vector *m)	{	mgl_data_set_vector(this,m);	}
+	/// Allocate memory and copy the data from the gsl_matrix
+	inline void Set(gsl_matrix *m)	{	mgl_data_set_matrix(this,m);	}
+
+	/// Allocate memory and copy the data from the (float *) array
+	inline void Set(const float *A,long NX,long NY=1,long NZ=1)
+	{	mgl_data_set_float(this,A,NX,NY,NZ);	}
+	/// Allocate memory and copy the data from the (double *) array
+	inline void Set(const double *A,long NX,long NY=1,long NZ=1)
+	{	mgl_data_set_double(this,A,NX,NY,NZ);	}
+	/// Allocate memory and copy the data from the (float **) array
+	inline void Set(float const * const *A,long N1,long N2)
+	{	mgl_data_set_float2(this,A,N1,N2);	}
+	/// Allocate memory and copy the data from the (double **) array
+	inline void Set(double const * const *A,long N1,long N2)
+	{	mgl_data_set_double2(this,A,N1,N2);	}
+	/// Allocate memory and copy the data from the (float ***) array
+	inline void Set(float const * const * const *A,long N1,long N2,long N3)
+	{	mgl_data_set_float3(this,A,N1,N2,N3);	}
+	/// Allocate memory and copy the data from the (double ***) array
+	inline void Set(double const * const * const *A,long N1,long N2,long N3)
+	{	mgl_data_set_double3(this,A,N1,N2,N3);	}
+	/// Allocate memory and scanf the data from the string
+	inline void Set(const char *str,long NX,long NY=1,long NZ=1)
+	{	mgl_data_set_values(this,str,NX,NY,NZ);	}
+	/// Import data from abstract type
+	inline void Set(const mglData &dat)	{	mgl_data_set(this, &dat);	}
+
+	/// Create or recreate the array with specified size and fill it by zero
+	inline void Create(long mx,long my=1,long mz=1)
+	{	mgl_data_create(this,mx,my,mz);	}
+	/// Rearange data dimensions
+	inline void Rearrange(long mx, long my=0, long mz=0)
+	{	mgl_data_rearrange(this,mx,my,mz);	}
+	/// Transpose dimensions of the data (generalization of Transpose)
+	inline void Transpose(const char *dim="yx")
+	{	mgl_data_transpose(this,dim);	}
+	/// Extend data dimensions
+	inline void Extend(long n1, long n2=0)
+	{	mgl_data_extend(this,n1,n2);	}
+	/// Reduce size of the data
+	inline void Squeeze(long rx,long ry=1,long rz=1,bool smooth=false)
+	{	mgl_data_squeeze(this,rx,ry,rz,smooth);	}
+	/// Crop the data
+	inline void Crop(long n1, long n2,char dir='x')
+	{	mgl_data_crop(this,n1,n2,dir);	}
+	/// Insert data rows/columns/slices
+	inline void Insert(char dir, long at=0, long num=1)
+	{	mgl_data_insert(this,dir,at,num);	}
+	/// Delete data rows/columns/slices
+	inline void Delete(char dir, long at=0, long num=1)
+	{	mgl_data_delete(this,dir,at,num);	}
+	/// Remove rows with duplicate values in column id
+	inline void Clean(long id)
+	{	mgl_data_clean(this,id);	}
+	/// Join with another data array
+	inline void Join(const mglData &d)
+	{	mgl_data_join(this,&d);	}
+
+	/// Modify the data by specified formula
+	inline void Modify(const char *eq,long dim=0)
+	{	mgl_data_modify(this, eq, dim);	}
+	/// Modify the data by specified formula
+	inline void Modify(const char *eq,const mglData &vdat, const mglData &wdat)
+	{	mgl_data_modify_vw(this,eq,&vdat,&wdat);	}
+	/// Modify the data by specified formula
+	inline void Modify(const char *eq,const mglData &vdat)
+	{	mgl_data_modify_vw(this,eq,&vdat,0);	}
+	/// Modify the data by specified formula assuming x,y,z in range [r1,r2]
+	inline void Fill(mglBase *gr, const char *eq, const char *opt="")
+	{	mgl_data_fill_eq(gr,this,eq,0,0,opt);	}
+	inline void Fill(mglBase *gr, const char *eq, const mglData &vdat, const char *opt="")
+	{	mgl_data_fill_eq(gr,this,eq,&vdat,0,opt);	}
+	inline void Fill(mglBase *gr, const char *eq, const mglData &vdat, const mglData &wdat,const char *opt="")
+	{	mgl_data_fill_eq(gr,this,eq,&vdat,&wdat,opt);	}
+	/// Equidistantly fill the data to range [x1,x2] in direction dir
+	inline void Fill(mreal x1,mreal x2=NaN,char dir='x')
+	{	return mgl_data_fill(this,x1,x2,dir);	}
+	/// Fill the data by interpolated values of vdat parametrically depended on xdat,ydat,zdat for x,y,z in range [p1,p2]
+	inline void Refill(const mglData &xdat, const mglData &vdat, mreal x1, mreal x2,long sl=-1)
+	{	mgl_data_refill_x(this,&xdat,&vdat,x1,x2,sl);	}
+	inline void Refill(const mglData &xdat, const mglData &vdat, mglPoint p1, mglPoint p2,long sl=-1)
+	{	mgl_data_refill_x(this,&xdat,&vdat,p1.x,p2.x,sl);	}
+	inline void Refill(const mglData &xdat, const mglData &ydat, const mglData &vdat, mglPoint p1, mglPoint p2,long sl=-1)
+	{	mgl_data_refill_xy(this,&xdat,&ydat,&vdat,p1.x,p2.x,p1.y,p2.y,sl);	}
+	inline void Refill(const mglData &xdat, const mglData &ydat, const mglData &zdat, const mglData &vdat, mglPoint p1, mglPoint p2)
+	{	mgl_data_refill_xyz(this,&xdat,&ydat,&zdat,&vdat,p1.x,p2.x,p1.y,p2.y,p1.z,p2.z);	}
+	/// Fill the data by interpolated values of vdat parametrically depended on xdat,ydat,zdat for x,y,z in axis range of gr
+	inline void Refill(mglBase *gr, const mglData &xdat, const mglData &vdat, long sl=-1, const char *opt="")
+	{	mgl_data_refill_gr(gr,this,&xdat,0,0,&vdat,sl,opt);	}
+	inline void Refill(mglBase *gr, const mglData &xdat, const mglData &ydat, const mglData &vdat, long sl=-1, const char *opt="")
+	{	mgl_data_refill_gr(gr,this,&xdat,&ydat,0,&vdat,sl,opt);	}
+	inline void Refill(mglBase *gr, const mglData &xdat, const mglData &ydat, const mglData &zdat, const mglData &vdat, const char *opt="")
+	{	mgl_data_refill_gr(gr,this,&xdat,&ydat,&zdat,&vdat,-1,opt);	}
+/// Set the data by triangulated surface values assuming x,y,z in axis range of gr
+	inline void Grid(mglBase *gr, const mglData &x, const mglData &y, const mglData &z, const char *opt="")
+	{	mgl_data_grid(gr,this,&x,&y,&z,opt);	}
+	/// Set the data by triangulated surface values assuming x,y,z in range [p1, p2]
+	inline void Grid(const mglData &xdat, const mglData &ydat, const mglData &vdat, mglPoint p1, mglPoint p2)
+	{	mgl_data_grid_xy(this,&xdat,&ydat,&vdat,p1.x,p2.x,p1.y,p2.y);	}
+	/// Put value to data element(s)
+	inline void Put(mreal val, long i=-1, long j=-1, long k=-1)
+	{	mgl_data_put_val(this,val,i,j,k);	}
+	/// Put array to data element(s)
+	inline void Put(const mglData &dat, long i=-1, long j=-1, long k=-1)
+	{	mgl_data_put_dat(this,&dat,i,j,k);	}
+	/// Set names for columns (slices)
+	inline void SetColumnId(const char *ids)
+	{	mgl_data_set_id(this,ids);	}
+	/// Make new id
+	inline void NewId()	{	id.clear();	}
+
+	/// Read data from tab-separated text file with auto determining size
+	inline bool Read(const char *fname)
+	{	return mgl_data_read(this,fname); }
+	/// Read data from text file with specifeid size
+	inline bool Read(const char *fname,long mx,long my=1,long mz=1)
+	{	return mgl_data_read_dim(this,fname,mx,my,mz);	}
+	/// Save whole data array (for ns=-1) or only ns-th slice to text file
+	inline void Save(const char *fname,long ns=-1) const
+	{	mgl_data_save(this,fname,ns);	}
+	/// Export data array (for ns=-1) or only ns-th slice to PNG file according color scheme
+	inline void Export(const char *fname,const char *scheme,mreal v1=0,mreal v2=0,long ns=-1) const
+	{	mgl_data_export(this,fname,scheme,v1,v2,ns);	}
+	/// Import data array from PNG file according color scheme
+	inline void Import(const char *fname,const char *scheme,mreal v1=0,mreal v2=1)
+	{	mgl_data_import(this,fname,scheme,v1,v2);	}
+	/// Read data from tab-separated text files with auto determining size which filenames are result of sprintf(fname,templ,t) where t=from:step:to
+	inline bool ReadRange(const char *templ, double from, double to, double step=1, bool as_slice=false)
+	{	return mgl_data_read_range(this,templ,from,to,step,as_slice);	}
+	/// Read data from tab-separated text files with auto determining size which filenames are satisfied to template (like "t_*.dat")
+	inline bool ReadAll(const char *templ, bool as_slice=false)
+	{	return mgl_data_read_all(this, templ, as_slice);	}
+	/// Read data from text file with size specified at beginning of the file
+	inline bool ReadMat(const char *fname, long dim=2)
+	{	return mgl_data_read_mat(this,fname,dim);	}
+	/// Read data array from HDF file (parse HDF4 and HDF5 files)
+	inline int ReadHDF(const char *fname,const char *data)
+	{	return mgl_data_read_hdf(this,fname,data);	}
+	/// Save data to HDF file
+	inline void SaveHDF(const char *fname,const char *data,bool rewrite=false) const
+	{	mgl_data_save_hdf(this,fname,data,rewrite);	}
+	/// Put HDF data names into buf as '\t' separated.
+	inline static int DatasHDF(const char *fname, char *buf, long size)
+	{	return mgl_datas_hdf(fname,buf,size);	}
+
+	/// Get column (or slice) of the data filled by formulas of named columns
+	inline mglData Column(const char *eq) const
+	{	return mglData(true,mgl_data_column(this,eq));	}
+	/// Get momentum (1D-array) of data along direction 'dir'. String looks like "x1" for median in x-direction, "x2" for width in x-dir and so on.
+	inline mglData Momentum(char dir, const char *how) const
+	{	return mglData(true,mgl_data_momentum(this,dir,how));	}
+	/// Get sub-array of the data with given fixed indexes
+	inline mglData SubData(long xx,long yy=-1,long zz=-1) const
+	{	return mglData(true,mgl_data_subdata(this,xx,yy,zz));	}
+	inline mglData SubData(const mglData &xx, const mglData &yy, const mglData &zz) const
+	{	return mglData(true,mgl_data_subdata_ext(this,&xx,&yy,&zz));	}
+	/// Get trace of the data array
+	inline mglData Trace() const
+	{	return mglData(true,mgl_data_trace(this));	}
+	/// Create n-th points distribution of this data values in range [v1, v2]
+	inline mglData Hist(long n,mreal v1=0,mreal v2=1, long nsub=0) const
+	{	return mglData(true,mgl_data_hist(this,n,v1,v2,nsub));	}
+	/// Create n-th points distribution of this data values in range [v1, v2] with weight w
+	inline mglData Hist(const mglData &w, long n,mreal v1=0,mreal v2=1, long nsub=0) const
+	{	return mglData(true,mgl_data_hist_w(this,&w,n,v1,v2,nsub));	}
+	/// Get array which is result of summation in given direction or directions
+	inline mglData Sum(const char *dir) const
+	{	return mglData(true,mgl_data_sum(this,dir));	}
+	/// Get array which is result of maximal values in given direction or directions
+	inline mglData Max(const char *dir) const
+	{	return mglData(true,mgl_data_max_dir(this,dir));	}
+	/// Get array which is result of minimal values in given direction or directions
+	inline mglData Min(const char *dir) const
+	{	return mglData(true,mgl_data_min_dir(this,dir));	}
+	/// Get the data which is direct multiplication (like, d[i,j] = this[i]*a[j] and so on)
+	inline mglData Combine(const mglData &dat) const
+	{	return mglData(true,mgl_data_combine(this,&dat));	}
+	/// Resize the data to new size of box [x1,x2]*[y1,y2]*[z1,z2]
+	inline mglData Resize(long mx,long my=0,long mz=0, mreal x1=0,mreal x2=1, mreal y1=0,mreal y2=1, mreal z1=0,mreal z2=1) const
+	{	return mglData(true,mgl_data_resize_box(this,mx,my,mz,x1,x2,y1,y2,z1,z2));	}
+	/// Get array which values is result of interpolation this for coordinates from other arrays
+	inline mglData Evaluate(const mglData &idat, bool norm=true) const
+	{	return mglData(true,mgl_data_evaluate(this,&idat,0,0,norm));	}
+	inline mglData Evaluate(const mglData &idat, const mglData &jdat, bool norm=true) const
+	{	return mglData(true,mgl_data_evaluate(this,&idat,&jdat,0,norm));	}
+	inline mglData Evaluate(const mglData &idat, const mglData &jdat, const mglData &kdat, bool norm=true) const
+	{	return mglData(true,mgl_data_evaluate(this,&idat,&jdat,&kdat,norm));	}
+	/// Find roots for set of nonlinear equations defined by textual formula
+	inline mglData Roots(const char *func, char var='x') const
+	{	return mglData(true,mgl_data_roots(func, this, var));	}
+	/// Find correlation with another data arrays
+	inline mglData Correl(const mglData &dat, const char *dir) const
+	{	return mglData(true,mgl_data_correl(this,&dat,dir));	}
+	/// Find auto correlation function
+	inline mglData AutoCorrel(const char *dir) const
+	{	return mglData(true,mgl_data_correl(this,this,dir));	}
+
+	/// Cumulative summation the data in given direction or directions
+	inline void CumSum(const char *dir)	{	mgl_data_cumsum(this,dir);	}
+	/// Integrate (cumulative summation) the data in given direction or directions
+	inline void Integral(const char *dir)	{	mgl_data_integral(this,dir);	}
+	/// Differentiate the data in given direction or directions
+	inline void Diff(const char *dir)	{	mgl_data_diff(this,dir);	}
+	/// Differentiate the parametrically specified data along direction v1 with v2=const
+	inline void Diff(const mglData &v1, const mglData &v2)
+	{	mgl_data_diff_par(this,&v1,&v2,0);	}
+	/// Differentiate the parametrically specified data along direction v1 with v2,v3=const
+	inline void Diff(const mglData &v1, const mglData &v2, const mglData &v3)
+	{	mgl_data_diff_par(this,&v1,&v2,&v3);	}
+	/// Double-differentiate (like Laplace operator) the data in given direction
+	inline void Diff2(const char *dir)	{	mgl_data_diff2(this,dir);	}
+
+	/// Swap left and right part of the data in given direction (useful for Fourier spectrum)
+	inline void Swap(const char *dir)		{	mgl_data_swap(this,dir);	}
+	/// Roll data along direction dir by num slices
+	inline void Roll(char dir, long num)	{	mgl_data_roll(this,dir,num);	}
+	/// Mirror the data in given direction (useful for Fourier spectrum)
+	inline void Mirror(const char *dir)		{	mgl_data_mirror(this,dir);	}
+	/// Sort rows (or slices) by values of specified column
+	inline void Sort(long idx, long idy=-1)	{	mgl_data_sort(this,idx,idy);	}
+
+	/// Set as the data envelop
+	inline void Envelop(char dir='x')
+	{	mgl_data_envelop(this,dir);	}
+	/// Remove phase jump
+	inline void Sew(const char *dirs="xyz", mreal da=2*Pi)
+	{	mgl_data_sew(this,dirs,da);	}
+	/// Smooth the data on specified direction or directions
+	inline void Smooth(const char *dirs="xyz",mreal delta=0)
+	{	mgl_data_smooth(this,dirs,delta);	}
+	/// Normalize the data to range [v1,v2]
+	inline void Norm(mreal v1=0,mreal v2=1,bool sym=false,long dim=0)
+	{	mgl_data_norm(this,v1,v2,sym,dim);	}
+	/// Normalize the data to range [v1,v2] slice by slice
+	inline void NormSl(mreal v1=0,mreal v2=1,char dir='z',bool keep_en=true,bool sym=false)
+	{	mgl_data_norm_slice(this,v1,v2,dir,keep_en,sym);	}
+
+	/// Apply Hankel transform
+	inline void Hankel(const char *dir)	{	mgl_data_hankel(this,dir);	}
+	/// Apply Sin-Fourier transform
+	inline void SinFFT(const char *dir)	{	mgl_data_sinfft(this,dir);	}
+	/// Apply Cos-Fourier transform
+	inline void CosFFT(const char *dir)	{	mgl_data_cosfft(this,dir);	}
+	/// Fill data by 'x'/'k' samples for Hankel ('h') or Fourier ('f') transform
+	inline void FillSample(const char *how)
+	{	mgl_data_fill_sample(this,how);	}
+
+	/// Interpolate by cubic spline the data to given point x=[0...nx-1], y=[0...ny-1], z=[0...nz-1]
+	inline mreal Spline(mreal x,mreal y=0,mreal z=0) const
+	{	return mgl_data_spline(this, x,y,z);	}
+	/// Interpolate by cubic spline the data to given point x,\a y,\a z which normalized in range [0, 1]
+	inline mreal Spline1(mreal x,mreal y=0,mreal z=0) const
+	{	return mgl_data_spline(this, x*(nx-1),y*(ny-1),z*(nz-1));	}
+	/// Interpolate by linear function the data to given point x=[0...nx-1], y=[0...ny-1], z=[0...nz-1]
+	inline mreal Linear(mreal x,mreal y=0,mreal z=0)	const
+	{	return mgl_data_linear(this,x,y,z);	}
+	/// Interpolate by line the data to given point x,\a y,\a z which normalized in range [0, 1]
+	inline mreal Linear1(mreal x,mreal y=0,mreal z=0) const
+	{	return mgl_data_linear(this,x*(nx-1),y*(ny-1),z*(nz-1));	}
+	/// Return an approximated x-value (root) when dat(x) = val
+	inline mreal Solve(mreal val, bool use_spline=true, long i0=0) const
+	{	return mgl_data_solve_1d(this, val, use_spline, i0);		}
+	/// Return an approximated value (root) when dat(x) = val
+	inline mglData Solve(mreal val, char dir, bool norm=true) const
+	{	return mglData(true,mgl_data_solve(this, val, dir, 0, norm));	}
+	inline mglData Solve(mreal val, char dir, const mglData &i0, bool norm=true) const
+	{	return mglData(true,mgl_data_solve(this, val, dir, &i0, norm));	}
+
+	/// Interpolate by cubic spline the data and return its derivatives at given point x=[0...nx-1], y=[0...ny-1], z=[0...nz-1]
+	inline mreal Spline(mglPoint &dif, mreal x,mreal y=0,mreal z=0) const
+	{	return mgl_data_spline_ext(this, x,y,z, &(dif.x),&(dif.y), &(dif.z));	}
+	/// Interpolate by cubic spline the data and return its derivatives at given point x,\a y,\a z which normalized in range [0, 1]
+	inline mreal Spline1(mglPoint &dif, mreal x,mreal y=0,mreal z=0) const
+	{	mreal res=mgl_data_spline_ext(this, x*(nx-1),y*(ny-1),z*(nz-1), &(dif.x),&(dif.y), &(dif.z));
+		dif.x*=nx>1?nx-1:1;	dif.y*=ny>1?ny-1:1;	dif.z*=nz>1?nz-1:1;	return res;	}
+	/// Interpolate by linear function the data and return its derivatives at given point x=[0...nx-1], y=[0...ny-1], z=[0...nz-1]
+	inline mreal Linear(mglPoint &dif, mreal x,mreal y=0,mreal z=0)	const
+	{	return mgl_data_linear_ext(this,x,y,z, &(dif.x),&(dif.y), &(dif.z));	}
+	/// Interpolate by line the data and return its derivatives at given point x,\a y,\a z which normalized in range [0, 1]
+	inline mreal Linear1(mglPoint &dif, mreal x,mreal y=0,mreal z=0) const
+	{	mreal res=mgl_data_linear_ext(this,x*(nx-1),y*(ny-1),z*(nz-1), &(dif.x),&(dif.y), &(dif.z));
+		dif.x*=nx>1?nx-1:1;	dif.y*=ny>1?ny-1:1;	dif.z*=nz>1?nz-1:1;	return res;	}
+
+	/// Get information about the data (sizes and momentum) to string
+	inline const char *PrintInfo() const	{	return mgl_data_info(this);	}
+	/// Print information about the data (sizes and momentum) to FILE (for example, stdout)
+	inline void PrintInfo(FILE *fp) const
+	{	if(fp)	{	fprintf(fp,"%s",mgl_data_info(this));	fflush(fp);	}	}
+	/// Get maximal value of the data
+	inline mreal Maximal() const	{	return mgl_data_max(this);	}
+	/// Get minimal value of the data
+	inline mreal Minimal() const	{	return mgl_data_min(this);	}
+	/// Get maximal value of the data and its position
+	inline mreal Maximal(long &i,long &j,long &k) const
+	{	return mgl_data_max_int(this,&i,&j,&k);	}
+	/// Get minimal value of the data and its position
+	inline mreal Minimal(long &i,long &j,long &k) const
+	{	return mgl_data_min_int(this,&i,&j,&k);	}
+	/// Get maximal value of the data and its approximated position
+	inline mreal Maximal(mreal &x,mreal &y,mreal &z) const
+	{	return mgl_data_max_real(this,&x,&y,&z);	}
+	/// Get minimal value of the data and its approximated position
+	inline mreal Minimal(mreal &x,mreal &y,mreal &z) const
+	{	return mgl_data_min_real(this,&x,&y,&z);	}
+	/// Get "energy" and find first (median) and second (width) momenta of data
+	inline mreal Momentum(char dir,mreal &m,mreal &w) const
+	{	return mgl_data_momentum_val(this,dir,&m,&w,0,0);	}
+	/// Get "energy and find 4 momenta of data: median, width, skewness, kurtosis
+	inline mreal Momentum(char dir,mreal &m,mreal &w,mreal &s,mreal &k) const
+	{	return mgl_data_momentum_val(this,dir,&m,&w,&s,&k);	}
+	/// Find position (after specified in i,j,k) of first nonzero value of formula
+	inline mreal Find(const char *cond, long &i, long &j, long &k) const
+	{	return mgl_data_first(this,cond,&i,&j,&k);	}
+	/// Find position (before specified in i,j,k) of last nonzero value of formula
+	inline mreal Last(const char *cond, long &i, long &j, long &k) const
+	{	return mgl_data_last(this,cond,&i,&j,&k);	}
+	/// Find position of first in direction 'dir' nonzero value of formula
+	inline long Find(const char *cond, char dir, long i=0, long j=0, long k=0) const
+	{	return mgl_data_find(this,cond,dir,i,j,k);	}
+	/// Find if any nonzero value of formula
+	inline bool FindAny(const char *cond) const
+	{	return mgl_data_find_any(this,cond);	}
+
+	/// Copy data from other mglData variable
+	inline mglData &operator=(const mglData &d)
+	{	if(this!=&d)	Set(d.a,d.nx,d.ny,d.nz);	return *this;	}
+	inline mreal operator=(mreal val)
+	{	for(long i=0;i<nx*ny*nz;i++)	a[i]=val;	return val;	}
+	/// Multiply the data by other one for each element
+	inline void operator*=(const mglData &d)	{	mgl_data_mul_dat(this,&d);	}
+	/// Divide the data by other one for each element
+	inline void operator/=(const mglData &d)	{	mgl_data_div_dat(this,&d);	}
+	/// Add the other data
+	inline void operator+=(const mglData &d)	{	mgl_data_add_dat(this,&d);	}
+	/// Subtract the other data
+	inline void operator-=(const mglData &d)	{	mgl_data_sub_dat(this,&d);	}
+	/// Multiply each element by the number
+	inline void operator*=(mreal d)		{	mgl_data_mul_num(this,d);	}
+	/// Divide each element by the number
+	inline void operator/=(mreal d)		{	mgl_data_div_num(this,d);	}
+	/// Add the number
+	inline void operator+=(mreal d)		{	mgl_data_add_num(this,d);	}
+	/// Subtract the number
+	inline void operator-=(mreal d)		{	mgl_data_sub_num(this,d);	}
+};
+//-----------------------------------------------------------------------------
+/// Integral data transformation (like Fourier 'f' or 'i', Hankel 'h' or None 'n') for amplitude and phase
+inline mglData mglTransformA(const mglData &am, const mglData &ph, const char *tr)
+{	return mglData(true,mgl_transform_a(&am,&ph,tr));	}
+/// Integral data transformation (like Fourier 'f' or 'i', Hankel 'h' or None 'n') for real and imaginary parts
+inline mglData mglTransform(const mglData &re, const mglData &im, const char *tr)
+{	return mglData(true,mgl_transform(&re,&im,tr));	}
+/// Apply Fourier transform for the data and save result into it
+inline void mglFourier(mglData &re, mglData &im, const char *dir)
+{	mgl_data_fourier(&re,&im,dir);	}
+/// Short time Fourier analysis for real and imaginary parts. Output is amplitude of partial Fourier (result will have size {dn, floor(nx/dn), ny} for dir='x'
+inline mglData mglSTFA(const mglData &re, const mglData &im, long dn, char dir='x')
+{	return mglData(true, mgl_data_stfa(&re,&im,dn,dir));	}
+//-----------------------------------------------------------------------------
+/// Saves result of PDE solving (|u|^2) for "Hamiltonian" ham with initial conditions ini
+inline mglData mglPDE(mglBase *gr, const char *ham, const mglData &ini_re, const mglData &ini_im, mreal dz=0.1, mreal k0=100,const char *opt="")
+{	return mglData(true, mgl_pde_solve(gr,ham, &ini_re, &ini_im, dz, k0,opt));	}
+/// Saves result of PDE solving for "Hamiltonian" ham with initial conditions ini along a curve ray (must have nx>=7 - x,y,z,px,py,pz,tau or nx=5 - x,y,px,py,tau)
+inline mglData mglQO2d(const char *ham, const mglData &ini_re, const mglData &ini_im, const mglData &ray, mreal r=1, mreal k0=100)
+{	return mglData(true, mgl_qo2d_solve(ham, &ini_re, &ini_im, &ray, r, k0, 0, 0));	}
+inline mglData mglQO2d(const char *ham, const mglData &ini_re, const mglData &ini_im, const mglData &ray, mglData &xx, mglData &yy, mreal r=1, mreal k0=100)
+{	return mglData(true, mgl_qo2d_solve(ham, &ini_re, &ini_im, &ray, r, k0, &xx, &yy));	}
+/// Saves result of PDE solving for "Hamiltonian" ham with initial conditions ini along a curve ray (must have nx>=7 - x,y,z,px,py,pz,tau or nx=5 - x,y,px,py,tau)
+inline mglData mglQO3d(const char *ham, const mglData &ini_re, const mglData &ini_im, const mglData &ray, mreal r=1, mreal k0=100)
+{	return mglData(true, mgl_qo3d_solve(ham, &ini_re, &ini_im, &ray, r, k0, 0, 0, 0));	}
+inline mglData mglQO3d(const char *ham, const mglData &ini_re, const mglData &ini_im, const mglData &ray, mglData &xx, mglData &yy, mglData &zz, mreal r=1, mreal k0=100)
+{	return mglData(true, mgl_qo3d_solve(ham, &ini_re, &ini_im, &ray, r, k0, &xx, &yy, &zz));	}
+/// Finds ray with starting point r0, p0 (and prepares ray data for mglQO2d)
+inline mglData mglRay(const char *ham, mglPoint r0, mglPoint p0, mreal dt=0.1, mreal tmax=10)
+{	return mglData(true, mgl_ray_trace(ham, r0.x, r0.y, r0.z, p0.x, p0.y, p0.z, dt, tmax));	}
+/// Calculate Jacobian determinant for D{x(u,v), y(u,v)} = dx/du*dy/dv-dx/dv*dy/du
+inline mglData mglJacobian(const mglData &x, const mglData &y)
+{	return mglData(true, mgl_jacobian_2d(&x, &y));	}
+/// Calculate Jacobian determinant for D{x(u,v,w), y(u,v,w), z(u,v,w)}
+inline mglData mglJacobian(const mglData &x, const mglData &y, const mglData &z)
+{	return mglData(true, mgl_jacobian_3d(&x, &y, &z));	}
+/// Do something like Delone triangulation
+inline mglData mglTriangulation(const mglData &x, const mglData &y, const mglData &z)
+{	return mglData(true,mgl_triangulation_3d(&x,&y,&z));	}
+inline mglData mglTriangulation(const mglData &x, const mglData &y)
+{	return mglData(true,mgl_triangulation_2d(&x,&y));	}
+//-----------------------------------------------------------------------------
diff --git a/lang/mathgl.i b/lang/mathgl.i
index 7069cfd..5bd9517 100644
--- a/lang/mathgl.i
+++ b/lang/mathgl.i
@@ -37,11 +37,9 @@
 
 %{
 #define SWIG_FILE_WITH_INIT
-//#include "mgl2/config.h"
 #include "mgl2/type.h"
 #include "mgl2/data.h"
 #include "mgl2/mgl.h"
-//#include "mgl2/window.h"
 %}
 
 #if MGL_USE_DOUBLE
@@ -86,15 +84,13 @@ import_array();
 %apply (int DIM1, int DIM2, int DIM3, double* IN_ARRAY3) {(int rows, int cols, int slc, const double* d)};
 #endif
 
-//%include "mgl2/config.h"
-%include "mgl2/type.h"
-%include "mgl2/data.h"
-%include "mgl2/mgl.h"
-//%include "mgl2/window.h"
+%include "type.i"
+%include "data.i"
+%include "mgl.i"
 %extend mglData
 {
-	float __getitem__( int i)	{	return self->GetVal(i);	};
-	float __paren( int i)		{	return self->GetVal(i);	};
-	void __setitem__( int i, float y)	{	self->SetVal(y,i);	};
-	void __paren_asgn( int i, float y)	{	self->SetVal(y,i);	};
+	mreal __getitem__( int i)	{	return self->GetVal(i);	};
+	mreal __paren( int i)		{	return self->GetVal(i);	};
+	void __setitem__( int i, mreal y)	{	self->SetVal(y,i);	};
+	void __paren_asgn( int i, mreal y)	{	self->SetVal(y,i);	};
 };
diff --git a/include/mgl2/mgl.h b/lang/mgl.i
similarity index 64%
copy from include/mgl2/mgl.h
copy to lang/mgl.i
index 713823f..88703ba 100644
--- a/include/mgl2/mgl.h
+++ b/lang/mgl.i
@@ -1,1329 +1,1309 @@
-/***************************************************************************
- * mgl.h is part of Math Graphic Library
- * Copyright (C) 2007-2012 Alexey Balakin <mathgl.abalakin at gmail.ru>       *
- *                                                                         *
- *   This program is free software; you can redistribute it and/or modify  *
- *   it under the terms of the GNU General Public License as published by  *
- *   the Free Software Foundation; either version 2 of the License, or     *
- *   (at your option) any later version.                                   *
- *                                                                         *
- *   This program is distributed in the hope that it will be useful,       *
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
- *   GNU General Public License for more details.                          *
- *                                                                         *
- *   You should have received a copy of the GNU General Public License     *
- *   along with this program; if not, write to the                         *
- *   Free Software Foundation, Inc.,                                       *
- *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
- ***************************************************************************/
-#ifndef _MGL_H_
-#define _MGL_H_
-
-#include "mgl2/mgl_cf.h"
-#include "mgl2/data.h"
-#include "mgl2/datac.h"
-//-----------------------------------------------------------------------------
-/// Wrapper class for all graphics
-class mglGraph
-{
-protected:
-	HMGL gr;
-public:
-	inline mglGraph(int kind=0, int width=600, int height=400)
-	{
-		if(kind==-1)	gr=NULL;
-#if MGL_HAVE_OPENGL
-		else if(kind==1)	gr=mgl_create_graph_gl();
-#else
-		else if(kind==1)
-		{	gr=mgl_create_graph(width, height);
-			mglGlobalMess += "OpenGL support was disabled. Please, enable it and rebuild MathGL.\n";	}
-#endif
-		else	gr=mgl_create_graph(width, height);
-	}
-	inline mglGraph(const mglGraph &graph)
-	{	gr = graph.gr;	mgl_use_graph(gr,1);	}
-	inline mglGraph(HMGL graph)
-	{	gr = graph;		mgl_use_graph(gr,1);	}
-	virtual ~mglGraph()
-	{	if(mgl_use_graph(gr,-1)<1)	mgl_delete_graph(gr);	}
-	/// Get pointer to internal mglCanvas object
-	inline HMGL Self()	{	return gr;	}
-	/// Set default parameters for plotting
-	inline void DefaultPlotParam()			{	mgl_set_def_param(gr);	}
-	/// Set name of plot for saving filename
-	inline void SetPlotId(const char *id)	{	mgl_set_plotid(gr,id);	}
-	/// Get name of plot for saving filename
-	inline const char *GetPlotId()	{	return mgl_get_plotid(gr);	}
-	
-	/// Set the transparency on/off.
-	inline void Alpha(bool enable)			{	mgl_set_alpha(gr, enable);	}
-	/// Set default value of alpha-channel
-	inline void SetAlphaDef(double alpha)	{	mgl_set_alpha_default(gr, alpha);	}
-	/// Set the transparency type (0 - usual, 1 - glass, 2 - lamp)
-	inline void SetTranspType(int type)		{	mgl_set_transp_type(gr, type);	}
-
-	/// Set the using of light on/off.
-	inline void Light(bool enable)			{	mgl_set_light(gr, enable);	}
-	/// Switch on/off the specified light source.
-	inline void Light(int n,bool enable)	{	mgl_set_light_n(gr, n, enable);	}
-	/// Use diffusive light (only for local light sources)
-	inline void SetDifLight(bool dif)		{	mgl_set_light_dif(gr, dif);	}
-	/// Add a light source.
-	inline void AddLight(int n, mglPoint p, char col='w', double bright=0.5, double ap=0)
-	{	mgl_add_light_ext(gr, n, p.x, p.y, p.z, col, bright, ap);	}
-	inline void AddLight(int n, mglPoint r, mglPoint p, char col='w', double bright=0.5, double ap=0)
-	{	mgl_add_light_loc(gr, n, r.x, r.y, r.z, p.x, p.y, p.z, col, bright, ap);	}
-	/// Set ambient light brightness
-	inline void SetAmbient(double i)			{	mgl_set_ambbr(gr, i);	}
-	/// Set the fog distance or switch it off (if d=0).
-	inline void Fog(double d, double dz=0.25)	{	mgl_set_fog(gr, d, dz);		}
-
-	/// Set relative width of rectangles in Bars, Barh, BoxPlot
-	inline void SetBarWidth(double width)	{	mgl_set_bar_width(gr, width);	}
-	/// Set default size of marks (locally you can use "size" option)
-	inline void SetMarkSize(double size)		{	mgl_set_mark_size(gr, size);	}
-	/// Set default size of arrows (locally you can use "size" option)
-	inline void SetArrowSize(double size)	{	mgl_set_arrow_size(gr, size);	}
-	/// Set number of mesh lines (use 0 to draw all of them)
-	inline void SetMeshNum(int num)			{	mgl_set_meshnum(gr, num);	}
-	/// Set number of visible faces (use 0 to draw all of them)
-	inline void SetFaceNum(int num)			{	mgl_set_facenum(gr, num);	}
-	
-	/// Set cutting for points outside of bounding box
-	inline void SetCut(bool cut)				{	mgl_set_cut(gr, cut);	}
-	/// Set additional cutting box
-	inline void SetCutBox(mglPoint p1, mglPoint p2)
-	{	mgl_set_cut_box(gr, p1.x, p1.y, p1.z, p2.x, p2.y, p2.z);	}
-	/// Set the cutting off condition (formula)
-	inline void CutOff(const char *EqC)		{	mgl_set_cutoff(gr, EqC);	}
-
-	/// Set default font size
-	inline void SetFontSize(double size)		{	mgl_set_font_size(gr, size);	}
-	/// Set default font style and color
-	inline void SetFontDef(const char *fnt)		{	mgl_set_font_def(gr, fnt);	}
-	/// Set FontSize by size in pt and picture DPI (default is 16 pt for dpi=72)
-	virtual void SetFontSizePT(double pt, int dpi=72){	SetFontSize(pt*27.f/dpi);	}
-	/// Set FontSize by size in centimeters and picture DPI (default is 0.56 cm = 16 pt)
-	inline void SetFontSizeCM(double cm, int dpi=72)	{	SetFontSizePT(cm*28.45f,dpi);	}
-	/// Set FontSize by size in inch and picture DPI (default is 0.22 in = 16 pt)
-	inline void SetFontSizeIN(double in, int dpi=72)	{	SetFontSizePT(in*72.27f,dpi);	}
-	/// Load font from file
-	inline void LoadFont(const char *name, const char *path=NULL)
-	{	mgl_load_font(gr, name, path);	}
-	/// Copy font from another mglGraph instance
-	inline void CopyFont(const mglGraph *GR)	{	mgl_copy_font(gr, GR->gr);}
-	/// Restore font (load default font for new HMGL objects)
-	inline void RestoreFont()				{	mgl_restore_font(gr);	}
-	/// Set to use or not text rotation
-	inline void SetRotatedText(bool rotated)	{	mgl_set_rotated_text(gr, rotated);	}
-
-	/// Set default palette
-	inline void SetPalette(const char *colors)	{	mgl_set_palette(gr, colors);	}
-	/// Set default color scheme
-	inline void SetDefScheme(const char *sch)	{	mgl_set_def_sch(gr, sch);	}
-
-	/// Get last warning code
-	inline int  GetWarn()	{	return mgl_get_warn(gr);}
-	/// Set warning code ant fill message
-	inline void SetWarn(int code, const char *info)	{	mgl_set_warn(gr,code,info);	}
-	/// Set buffer for warning messages
-	inline const char *Message()	{	return mgl_get_mess(gr);	}
-
-	/// Set axis range scaling -- simplified way to shift/zoom axis range -- need to replot whole image!
-	inline void ZoomAxis(mglPoint p1=mglPoint(0,0,0,0), mglPoint p2=mglPoint(1,1,1,1))
-	{	mgl_zoom_axis(gr, p1.x,p1.y,p1.z,p1.c, p2.x,p2.y,p2.z,p2.c);	}
-	/// Set range in direction dir as [v1, v2]
-	inline void SetRange(char dir, double v1, double v2)
-	{	mgl_set_range_val(gr, dir, v1, v2);	}
-	/// Set range in direction dir as minimal and maximal values of data a
-	inline void SetRange(char dir, const mglDataA &dat, bool add=false)
-	{	mgl_set_range_dat(gr, dir, &dat, add);	}
-	/// Set values of axis range as minimal and maximal values of datas
-	inline void SetRanges(const mglDataA &xx, const mglDataA &yy, const mglDataA &zz, const mglDataA &cc)
-	{	mgl_set_range_dat(gr,'x',&xx,0);	mgl_set_range_dat(gr,'y',&yy,0);
-		mgl_set_range_dat(gr,'z',&zz,0);	mgl_set_range_dat(gr,'c',&cc,0);	}
-	/// Set values of axis range as minimal and maximal values of datas
-	inline void SetRanges(const mglDataA &xx, const mglDataA &yy, const mglDataA &zz)
-	{	mgl_set_range_dat(gr,'x',&xx,0);	mgl_set_range_dat(gr,'y',&yy,0);
-		mgl_set_range_dat(gr,'z',&zz,0);	mgl_set_range_dat(gr,'c',&zz,0);	}
-	/// Set values of axis range as minimal and maximal values of datas
-	inline void SetRanges(const mglDataA &xx, const mglDataA &yy)
-	{	mgl_set_range_dat(gr,'x',&xx,0);	mgl_set_range_dat(gr,'y',&yy,0);	}
-	/// Set values of axis ranges
-	inline void SetRanges(double x1, double x2, double y1, double y2, double z1=0, double z2=0)
-	{	mgl_set_ranges(gr, x1, x2, y1, y2, z1, z2);	}
-	/// Set values of axis ranges
-	inline void SetRanges(mglPoint p1, mglPoint p2)
-	{	mgl_set_ranges(gr, p1.x, p2.x, p1.y, p2.y, p1.z, p2.z);	}
-	/// Set ranges for automatic variables
-	inline void SetAutoRanges(double x1, double x2, double y1=0, double y2=0, double z1=0, double z2=0, double c1=0, double c2=0)
-	{	mgl_set_auto_ranges(gr, x1, x2, y1, y2, z1, z2, c1, c2);	}
-	/// Set ranges for automatic variables
-	inline void SetAutoRanges(mglPoint p1, mglPoint p2)
-	{	mgl_set_auto_ranges(gr, p1.x, p2.x, p1.y, p2.y, p1.z, p2.z, p1.c, p2.c);	}
-	/// Set axis origin
-	inline void SetOrigin(mglPoint p)
-	{	mgl_set_origin(gr, p.x, p.y, p.z);	}
-	inline void SetOrigin(double x0, double y0, double z0=NaN)
-	{	mgl_set_origin(gr, x0, y0, z0);	}
-
-	/// Set the transformation formulas for coordinate
-	inline void SetFunc(const char *EqX, const char *EqY, const char *EqZ=NULL, const char *EqA=NULL)
-	{	mgl_set_func(gr, EqX, EqY, EqZ, EqA);	}
-	/// Set one of predefined transformation rule
-	inline void SetCoor(int how)		{	mgl_set_coor(gr, how);	}
-	/// Set to draw Ternary axis (triangle like axis, grid and so on)
-	inline void Ternary(int val)		{	mgl_set_ternary(gr, val);	}
-
-	/// Set to use or not tick labels rotation
-	inline void SetTickRotate(bool val)	{	mgl_set_tick_rotate(gr,val);	}
-	/// Set to use or not tick labels skipping
-	inline void SetTickSkip(bool val)	{	mgl_set_tick_skip(gr,val);	}
-	/// Set tick length
-	inline void SetTickLen(double len, double stt=1)
-	{	mgl_set_tick_len(gr, len, stt);	}
-	/// Set axis and ticks style
-	inline void SetAxisStl(const char *stl="k", const char *tck=0, const char *sub=0)
-	{	mgl_set_axis_stl(gr, stl, tck, sub);	}
-
-	/// Set time templates for ticks
-	inline void SetTicksTime(char dir, double d=0, const char *t="")
-	{	mgl_set_ticks_time(gr,dir,d,t);	}
-	/// Set ticks text (\n separated). Use "" to disable this feature.
-	inline void SetTicksVal(char dir, const char *lbl, bool add=false)
-	{	mgl_set_ticks_str(gr,dir,lbl,add);	}
-	inline void SetTicksVal(char dir, const wchar_t *lbl, bool add=false)
-	{	mgl_set_ticks_wcs(gr,dir,lbl,add);	}
-	/// Set ticks position and text (\n separated). Use "" to disable this feature.
-	inline void SetTicksVal(char dir, const mglDataA &v, const char *lbl, bool add=false)
-	{	mgl_set_ticks_val(gr,dir,&v,lbl,add);	}
-	inline void SetTicksVal(char dir, const mglDataA &v, const wchar_t *lbl, bool add=false)
-	{	mgl_set_ticks_valw(gr,dir,&v,lbl,add);	}
-	/// Set the ticks parameters
-	inline void SetTicks(char dir, double d=0, int ns=0, double org=NaN)
-	{	mgl_set_ticks(gr, dir, d, ns, org);	}
-	/// Auto adjust ticks
-	inline void Adjust(const char *dir="xyzc")
-	{	mgl_adjust_ticks(gr, dir);	}
-	/// Set templates for ticks
-	inline void SetTickTempl(char dir, const char *t)
-	{	mgl_set_tick_templ(gr,dir,t);	}
-	inline void SetTickTempl(char dir, const wchar_t *t)
-	{	mgl_set_tick_templw(gr,dir,t);	}
-	/// Tune ticks
-	inline void SetTuneTicks(int tune, double fact_pos=1.15)
-	{	mgl_tune_ticks(gr, tune, fact_pos);	}
-	/// Set additional shift of tick labels
-	inline void SetTickShift(mglPoint p)
-	{	mgl_set_tick_shift(gr,p.x,p.y,p.z,p.c);	}
-	/// Set to use UTC time instead of local time
-	inline void SetTimeUTC(bool enable)
-	{	mgl_set_flag(gr,enable, MGL_USE_GMTIME);	}
-	/// Set to draw tick labels at axis origin
-	inline void SetOriginTick(bool enable=true)
-	{	mgl_set_flag(gr,!enable, MGL_NO_ORIGIN);	}
-	
-	/// Put further plotting in some region of whole frame.
-	inline void SubPlot(int nx,int ny,int m,const char *style="<>_^", double dx=0, double dy=0)
-	{	mgl_subplot_d(gr, nx, ny, m, style, dx, dy);	}
-	/// Like SubPlot() but "join" several cells
-	inline void MultiPlot(int nx,int ny,int m, int dx, int dy, const char *style="<>_^")
-	{	mgl_multiplot(gr, nx, ny, m, dx, dy, style);	}
-	/// Put further plotting in a region of whole frame.
-	inline void InPlot(double x1,double x2,double y1,double y2, bool rel=true)
-	{	if(rel)	mgl_relplot(gr, x1, x2, y1, y2);
-		else	mgl_inplot(gr, x1, x2, y1, y2);	}
-	/// Put further plotting in column cell of previous subplot
-	inline void ColumnPlot(int num, int ind, double d=0)
-	{	mgl_columnplot(gr,num,ind,d);	}
-	/// Put further plotting in matrix cell of previous subplot
-	inline void GridPlot(int nx, int ny, int ind, double d=0)
-	{	mgl_gridplot(gr,nx,ny,ind,d);	}
-	/// Put further plotting in cell of stick rotated on angles tet, phi
-	inline void StickPlot(int num, int i, double tet, double phi)
-	{	mgl_stickplot(gr,num,i,tet,phi);	}
-
-	/// Set factor of plot size
-	inline void SetPlotFactor(double val)
-	{	mgl_set_plotfactor(gr,val);	}
-	/// Push transformation matrix into stack
-	inline void Push()	{	mgl_mat_push(gr);	}
-	/// Pop transformation matrix from stack
-	inline void Pop()	{	mgl_mat_pop(gr);	}
-	
-	/// Add title for current subplot/inplot
-	inline 	void Title(const char *title,const char *stl="",double size=-2)
-	{	mgl_title(gr,title,stl,size);	}
-	inline 	void Title(const wchar_t *title,const char *stl="",double size=-2)
-	{	mgl_titlew(gr,title,stl,size);	}
-	/// Set aspect ratio for further plotting.
-	inline void Aspect(double Ax,double Ay,double Az=1)
-	{	mgl_aspect(gr, Ax, Ay, Az);		}
-	/// Rotate a further plotting.
-	inline void Rotate(double TetX,double TetZ=0,double TetY=0)
-	{	mgl_rotate(gr, TetX, TetZ, TetY);	}
-	/// Rotate a further plotting around vector {x,y,z}.
-	inline void RotateN(double Tet,double x,double y,double z)
-	{	mgl_rotate_vector(gr, Tet, x, y, z);	}
-	/// Set perspective (in range [0,1)) for plot. Set to zero for switching off.
-	inline void Perspective(double val)
-	{	mgl_perspective(gr, val);	}
-	/// Set angle of view independently from Rotate().
-	inline void View(double TetX,double TetZ=0,double TetY=0)
-	{	mgl_view(gr, TetX, TetZ, TetY);	}
-	/// Zoom in/out a part of picture (use Zoom(0, 0, 1, 1) for restore default)
-	inline void Zoom(double x1, double y1, double x2, double y2)
-	{	mgl_zoom(gr, x1, y1, x2, y2);	}
-
-	/// Set size of frame in pixels. Normally this function is called internally.
-	inline void SetSize(int width, int height)	{	mgl_set_size(gr, width, height);	}
-	/// Set plot quality
-	inline void SetQuality(int qual=MGL_DRAW_NORM)	{	mgl_set_quality(gr, qual);	}
-	/// Get plot quality
-	inline int GetQuality()	{	return mgl_get_quality(gr);	}
-	/// Start group of objects
-	inline void StartGroup(const char *name)		{	mgl_start_group(gr, name);	}
-	/// End group of objects
-	inline void EndGroup()	{	mgl_end_group(gr);	}
-	/// Highlight objects with given id
-	inline void Highlight(int id)	{	mgl_highlight(gr, id);	}
-
-	/// Show current image
-	inline void ShowImage(const char *viewer, bool keep=0)
-	{	mgl_show_image(gr, viewer, keep);	}
-	/// Write the frame in file (depending extension, write current frame if fname is empty)
-	inline void WriteFrame(const char *fname=0,const char *descr="")
-	{	mgl_write_frame(gr, fname, descr);	}
-	/// Write the frame in file using JPEG format
-	inline void WriteJPEG(const char *fname,const char *descr="")
-	{	mgl_write_jpg(gr, fname, descr);	}
-	/// Write the frame in file using PNG format with transparency
-	inline void WritePNG(const char *fname,const char *descr="", bool alpha=true)
-	{	if(alpha)	mgl_write_png(gr, fname, descr);
-		else	mgl_write_png_solid(gr, fname, descr);	}
-	/// Write the frame in file using BMP format
-	inline void WriteBMP(const char *fname,const char *descr="")
-	{	mgl_write_bmp(gr, fname, descr);	}
-	/// Write the frame in file using BMP format
-	inline void WriteTGA(const char *fname,const char *descr="")
-	{	mgl_write_tga(gr, fname, descr);	}
-	/// Write the frame in file using PostScript format
-	inline void WriteEPS(const char *fname,const char *descr="")
-	{	mgl_write_eps(gr, fname, descr);	}
-	/// Write the frame in file using LaTeX format
-	inline void WriteTEX(const char *fname,const char *descr="")
-	{	mgl_write_tex(gr, fname, descr);	}
-	/// Write the frame in file using PostScript format as bitmap
-	inline void WriteBPS(const char *fname,const char *descr="")
-	{	mgl_write_bps(gr, fname, descr);	}
-	/// Write the frame in file using SVG format
-	inline void WriteSVG(const char *fname,const char *descr="")
-	{	mgl_write_svg(gr, fname, descr);	}
-	/// Write the frame in file using GIF format (only for current frame!)
-	inline void WriteGIF(const char *fname,const char *descr="")
-	{	mgl_write_gif(gr, fname, descr);	}
-
-	/// Write the frame in file using OBJ format
-	inline void WriteOBJ(const char *fname,const char *descr="",bool use_png=true)
-	{	mgl_write_obj(gr, fname, descr, use_png);	}
-	/// Write the frame in file using OBJ format - Balakin way
-	inline void WriteOBJold(const char *fname,const char *descr="",bool use_png=true)
-	{	mgl_write_obj_old(gr, fname, descr, use_png);	}
-	/// Write the frame in file using XYZ format
-	inline void WriteXYZ(const char *fname,const char *descr="")
-	{	mgl_write_xyz(gr, fname, descr);	}
-	/// Write the frame in file using STL format (faces only)
-	inline void WriteSTL(const char *fname,const char *descr="")
-	{	mgl_write_stl(gr, fname, descr);	}
-	/// Write the frame in file using OFF format
-	inline void WriteOFF(const char *fname,const char *descr="", bool colored=false)
-	{	mgl_write_off(gr, fname, descr,colored);	}
-//	/// Write the frame in file using X3D format
-//	inline void WriteX3D(const char *fname,const char *descr="")
-//	{	mgl_write_x3d(gr, fname, descr);	}
-	/// Write the frame in file using PRC format
-	inline void WritePRC(const char *fname,const char *descr="",bool make_pdf=true)
-	{	mgl_write_prc(gr, fname, descr, make_pdf);	}
-	/// Export in JSON format suitable for later drawing by JavaScript
-	inline void WriteJSON(const char *fname,const char *descr="")
-	{	mgl_write_json(gr, fname, descr);	}
-
-	/// Force preparing the image. It can be useful for OpenGL mode mostly.
-	inline void Finish()			{	mgl_finish(gr);	}
-	/// Create new frame.
-	inline void NewFrame()		{	mgl_new_frame(gr);	}
-	/// Finish frame drawing
-	inline void EndFrame()		{	mgl_end_frame(gr);	}
-	/// Get the number of created frames
-	inline int GetNumFrame()	{	return mgl_get_num_frame(gr);	}
-	/// Reset frames counter (start it from zero)
-	inline void ResetFrames()	{	mgl_reset_frames(gr);	}
-	/// Delete primitives for i-th frame (work if MGL_VECT_FRAME is set on)
-	inline void DelFrame(int i)	{	mgl_del_frame(gr, i);	}
-	/// Get drawing data for i-th frame (work if MGL_VECT_FRAME is set on)
-	inline void GetFrame(int i)	{	mgl_get_frame(gr, i);	}
-	/// Set drawing data for i-th frame (work if MGL_VECT_FRAME is set on). Work as EndFrame() but don't add frame to GIF image.
-	inline void SetFrame(int i)	{	mgl_set_frame(gr, i);	}
-	/// Append drawing data from i-th frame (work if MGL_VECT_FRAME is set on)
-	inline void ShowFrame(int i){	mgl_show_frame(gr, i);	}
-	
-	/// Start write frames to cinema using GIF format
-	inline void StartGIF(const char *fname, int ms=100)
-	{	mgl_start_gif(gr, fname,ms);	}
-	/// Stop writing cinema using GIF format
-	inline void CloseGIF()		{	mgl_close_gif(gr);	}
-	/// Export points and primitives in file using MGLD format
-	inline void ExportMGLD(const char *fname, const char *descr=0)
-	{	mgl_export_mgld(gr, fname, descr);	}
-	/// Import points and primitives from file using MGLD format
-	inline void ImportMGLD(const char *fname, bool add=false)
-	{	mgl_import_mgld(gr, fname, add);	}
-
-	/// Copy RGB values into array which is allocated by user
-	inline void GetRGB(char *imgdata, int imglen)
-	{
-		long w=mgl_get_width(gr), h=mgl_get_height(gr);
-		if(imglen>=3*w*h)	memcpy(imgdata, mgl_get_rgb(gr),3*w*h);
-	}
-	inline const unsigned char *GetRGB()		{	return mgl_get_rgb(gr);	}
-	/// Copy RGBA values into array which is allocated by user
-	inline void GetRGBA(char *imgdata, int imglen)
-	{
-		long w=mgl_get_width(gr), h=mgl_get_height(gr);
-		if(imglen>=4*w*h)	memcpy(imgdata, mgl_get_rgba(gr),4*w*h);
-	}
-	inline const unsigned char *GetRGBA()	{	return mgl_get_rgba(gr);	}
-	/// Copy BGRN values into array which is allocated by user
-	inline void GetBGRN(unsigned char *imgdata, int imglen)
-	{
-		long w=mgl_get_width(gr), h=mgl_get_height(gr), i;
-		const unsigned char *buf=mgl_get_rgb(gr);
-		if(imglen>=4*w*h)	for(i=0;i<w*h;i++)
-		{
-			imgdata[4*i]   = buf[3*i+2];
-			imgdata[4*i+1] = buf[3*i+1];
-			imgdata[4*i+2] = buf[3*i];
-			imgdata[4*i+3] = 255;
-		}
-	}
-	/// Get width of the image
-	inline int GetWidth()	{	return mgl_get_width(gr);	}
-	/// Get height of the image
-	inline int GetHeight()	{	return mgl_get_height(gr);}
-	/// Calculate 3D coordinate {x,y,z} for screen point {xs,ys}
-	inline mglPoint CalcXYZ(int xs, int ys)
-	{
-		mreal x,y,z;
-		mgl_calc_xyz(gr,xs,ys,&x,&y,&z);
-		return mglPoint(x,y,z);
-	}
-	/// Calculate screen point {xs,ys} for 3D coordinate {x,y,z}
-	inline mglPoint CalcScr(mglPoint p)
-	{
-		int xs,ys;
-		mgl_calc_scr(gr,p.x,p.y,p.z,&xs,&ys);
-		return mglPoint(xs,ys);
-	}
-	/// Set object/subplot id
-	inline void SetObjId(int id)		{	mgl_set_obj_id(gr,id);	}
-	/// Get object id
-	inline int GetObjId(long x,long y)	{	return mgl_get_obj_id(gr,x,y);	}
-	/// Get subplot id
-	inline int GetSplId(long x,long y)	{	return mgl_get_spl_id(gr,x,y);	}
-	/// Check if {\a xs,\a ys} is close to active point with accuracy d, and return its position or -1
-	inline long IsActive(int xs, int ys, int d=1)	{	return mgl_is_active(gr,xs,ys,d);	}
-
-	/// Combine plots from 2 canvases. Result will be saved into this
-	inline void Combine(const mglGraph *g)	{	mgl_combine_gr(gr,g->gr);	}
-
-	/// Clear up the frame
-	inline void Clf(double r, double g, double b)	{	mgl_clf_rgb(gr, r, g, b);	}
-	inline void Clf()	{	mgl_clf(gr);	}
-	/// Clear unused points and primitives. Useful only in combination with SetFaceNum().
-	inline void ClearUnused()	{	mgl_clear_unused(gr);	}
-	/// Draws the point (ball) at position {x,y,z} with color c
-	inline void Ball(mglPoint p, char c='r')
-	{	char s[3]={'.',c,0};	mgl_mark(gr, p.x, p.y, p.z, s);	}
-	/// Draws the mark at position p
-	inline void Mark(mglPoint p, const char *mark)
-	{	mgl_mark(gr, p.x, p.y, p.z, mark);	}
-	/// Draws the line between points by specified pen
-	inline void Line(mglPoint p1, mglPoint p2, const char *pen="B",int n=2)
-	{	mgl_line(gr, p1.x, p1.y, p1.z, p2.x, p2.y, p2.z, pen, n);	}
-	/// Draws the spline curve between points by specified pen
-	inline void Curve(mglPoint p1, mglPoint d1, mglPoint p2, mglPoint d2, const char *pen="B", int n=100)
-	{	mgl_curve(gr, p1.x, p1.y, p1.z, d1.x, d1.y, d1.z, p2.x, p2.y, p2.z, d2.x, d2.y, d2.z, pen, n);	}
-	/// Draws the 3d error box e for point p
-	inline void Error(mglPoint p, mglPoint e, const char *pen="k")
-	{	mgl_error_box(gr, p.x, p.y, p.z, e.x, e.y, e.z, pen);	}
-
-	/// Draws the face between points with color stl (include interpolation up to 4 colors).
-	inline void Face(mglPoint p1, mglPoint p2, mglPoint p3, mglPoint p4, const char *stl="r")
-	{	mgl_face(gr, p1.x, p1.y, p1.z, p2.x, p2.y, p2.z, p3.x, p3.y, p3.z, p4.x, p4.y, p4.z, stl);	}
-	/// Draws the face in y-z plane at point p with color stl (include interpolation up to 4 colors).
-	inline void FaceX(mglPoint p, double wy, double wz, const char *stl="w", double dx=0, double dy=0)
-	{	mgl_facex(gr, p.x, p.y, p.z, wy, wz, stl, dx, dy);	}
-	/// Draws the face in x-z plane at point p with color stl (include interpolation up to 4 colors).
-	inline void FaceY(mglPoint p, double wx, double wz, const char *stl="w", double dx=0, double dy=0)
-	{	mgl_facey(gr, p.x, p.y, p.z, wx, wz, stl, dx, dy);	}
-	/// Draws the face in x-y plane at point p with color stl (include interpolation up to 4 colors).
-	inline void FaceZ(mglPoint p, double wx, double wy, const char *stl="w", double dx=0, double dy=0)
-	{	mgl_facez(gr, p.x, p.y, p.z, wx, wy, stl, dx, dy);	}
-	/// Draws the drop at point p in direction d with color col and radius r
-	inline void Drop(mglPoint p, mglPoint d, double r, const char *col="r", double shift=1, double ap=1)
-	{	mgl_drop(gr, p.x, p.y, p.z, d.x, d.y, d.z, r, col, shift, ap);	}
-	/// Draws the sphere at point p with color col and radius r
-	inline void Sphere(mglPoint p, double r, const char *col="r")
-	{	mgl_sphere(gr, p.x, p.y, p.z, r, col);	}
-	/// Draws the cone between points p1,p2 with radius r1,r2 and with style stl
-	inline void Cone(mglPoint p1, mglPoint p2, double r1, double r2=-1, const char *stl="r@")
-	{	mgl_cone(gr, p1.x, p1.y, p1.z, p2.x, p2.y, p2.z,r1,r2,stl);	}
-	/// Draws the ellipse between points p1,p2 with color stl and width r
-	inline void Ellipse(mglPoint p1, mglPoint p2, double r, const char *stl="r")
-	{	mgl_ellipse(gr, p1.x, p1.y, p1.z, p2.x, p2.y, p2.z, r,stl);	}
-	/// Draws the circle at point p with color stl and radius r
-	inline void Circle(mglPoint p, double r, const char *stl="r")
-	{	mgl_ellipse(gr, p.x, p.y, p.z, p.x, p.y, p.z, r,stl);	}
-	/// Draws the rhomb between points p1,p2 with color stl and width r
-	inline void Rhomb(mglPoint p1, mglPoint p2, double r, const char *stl="r")
-	{	mgl_rhomb(gr, p1.x, p1.y, p1.z, p2.x, p2.y, p2.z, r,stl);	}
-
-	/// Print text in position p with specified font
-	inline void Putsw(mglPoint p,const wchar_t *text,const char *font=":C",double size=-1)
-	{	mgl_putsw(gr, p.x, p.y, p.z, text, font, size);	}
-	inline void Puts(mglPoint p,const char *text,const char *font=":C",double size=-1)
-	{	mgl_puts(gr, p.x, p.y, p.z, text, font, size);	}
-	inline void Putsw(double x, double y,const wchar_t *text,const char *font=":AC",double size=-1)
-	{	mgl_putsw(gr, x, y, 0, text, font, size);	}
-	inline void Puts(double x, double y,const char *text,const char *font=":AC",double size=-1)
-	{	mgl_puts(gr, x, y, 0, text, font, size);	}
-	/// Print text in position p along direction d with specified font
-	inline void Putsw(mglPoint p, mglPoint d, const wchar_t *text, const char *font=":L", double size=-1)
-	{	mgl_putsw_dir(gr, p.x, p.y, p.z, d.x, d.y, d.z, text, font, size);	}
-	inline void Puts(mglPoint p, mglPoint d, const char *text, const char *font=":L", double size=-1)
-	{	mgl_puts_dir(gr, p.x, p.y, p.z, d.x, d.y, d.z, text, font, size);	}
-
-	/// Print text along the curve
-	inline void Text(const mglDataA &x, const mglDataA &y, const mglDataA &z, const char *text, const char *font="", const char *opt="")
-	{	mgl_text_xyz(gr, &x, &y, &z, text, font, opt);	}
-	inline void Text(const mglDataA &x, const mglDataA &y, const char *text, const char *font="", const char *opt="")
-	{	mgl_text_xy(gr, &x, &y, text, font, opt);	}
-	inline void Text(const mglDataA &y, const char *text, const char *font="", const char *opt="")
-	{	mgl_text_y(gr, &y, text, font, opt);	}
-	inline void Text(const mglDataA &x, const mglDataA &y, const mglDataA &z, const wchar_t *text, const char *font="", const char *opt="")
-	{	mgl_textw_xyz(gr, &x, &y, &z, text, font, opt);	}
-	inline void Text(const mglDataA &x, const mglDataA &y, const wchar_t *text, const char *font="", const char *opt="")
-	{	mgl_textw_xy(gr, &x, &y, text, font, opt);	}
-	inline void Text(const mglDataA &y, const wchar_t *text, const char *font="", const char *opt="")
-	{	mgl_textw_y(gr, &y, text, font, opt);	}
-
-	/// Draws bounding box outside the plotting volume with color c.
-	inline void Box(const char *col="", bool ticks=true)
-	{	mgl_box_str(gr, col, ticks);	}
-	/// Draw axises with ticks in direction(s) dir.
-	inline void Axis(const char *dir="xyzt", const char *stl="", const char *opt="")
-	{	mgl_axis(gr, dir,stl,opt);	}
-	/// Draw grid lines perpendicular to direction(s) dir.
-	inline void Grid(const char *dir="xyzt",const char *pen="B", const char *opt="")
-	{	mgl_axis_grid(gr, dir, pen, opt);	}
-	/// Print the label text for axis dir.
-	inline void Label(char dir, const char *text, double pos=+1, const char *opt="")
-	{	mgl_label(gr, dir, text, pos, opt);	}
-	inline void Label(char dir, const wchar_t *text, double pos=+1, const char *opt="")
-	{	mgl_labelw(gr, dir, text, pos, opt);	}
-
-	/// Draw colorbar at edge of axis
-	inline void Colorbar(const char *sch="")
-	{	mgl_colorbar(gr, sch);	}
-	inline void Colorbar(const char *sch,double x,double y,double w=1,double h=1)
-	{	mgl_colorbar_ext(gr, sch, x,y,w,h);	}
-	/// Draw colorbar with manual colors at edge of axis
-	inline void Colorbar(const mglDataA &val, const char *sch="")
-	{	mgl_colorbar_val(gr, &val, sch);	}
-	inline void Colorbar(const mglDataA &val, const char *sch,double x,double y,double w=1,double h=1)
-	{	mgl_colorbar_val_ext(gr, &val, sch, x,y,w,h);	}
-
-	/// Add string to legend
-	inline void AddLegend(const char *text,const char *style)
-	{	mgl_add_legend(gr, text, style);	}
-	inline void AddLegend(const wchar_t *text,const char *style)
-	{	mgl_add_legendw(gr, text, style);	}
-	/// Clear saved legend string
-	inline void ClearLegend()
-	{	mgl_clear_legend(gr);	}
-	/// Draw legend of accumulated strings at position {x,y}
-	inline void Legend(double x, double y, const char *font="#", const char *opt="")
-	{	mgl_legend_pos(gr, x, y, font, opt);	}
-	/// Draw legend of accumulated strings
-	inline void Legend(int where=3, const char *font="#", const char *opt="")
-	{	mgl_legend(gr, where, font, opt);	}
-	/// Set number of marks in legend sample
-	inline void SetLegendMarks(int num)		{	mgl_set_legend_marks(gr, num);	}
-
-	/// Draw usual curve {x,y,z}
-	inline void Plot(const mglDataA &x, const mglDataA &y, const mglDataA &z, const char *pen="", const char *opt="")
-	{	mgl_plot_xyz(gr, &x, &y, &z, pen, opt);	}
-	inline void Plot(const mglDataA &x, const mglDataA &y, const char *pen="", const char *opt="")
-	{	mgl_plot_xy(gr, &x, &y, pen,opt);	}
-	inline void Plot(const mglDataA &y, const char *pen="", const char *opt="")
-	{	mgl_plot(gr, &y, pen,opt);	}
-	/// Draw tape(s) which rotates as (bi-)normales of curve {x,y,z}
-	inline void Tape(const mglDataA &x, const mglDataA &y, const mglDataA &z, const char *pen="", const char *opt="")
-	{	mgl_tape_xyz(gr, &x, &y, &z, pen, opt);	}
-	inline void Tape(const mglDataA &x, const mglDataA &y, const char *pen="", const char *opt="")
-	{	mgl_tape_xy(gr, &x, &y, pen,opt);	}
-	inline void Tape(const mglDataA &y, const char *pen="", const char *opt="")
-	{	mgl_tape(gr, &y, pen,opt);	}
-	/// Draw radar chart (plot in curved coordinates)
-	inline void Radar(const mglDataA &a, const char *pen="", const char *opt="")
-	{	mgl_radar(gr, &a, pen, opt);	}
-	/// Draw stairs for points in arrays {x,y,z}
-	inline void Step(const mglDataA &x, const mglDataA &y, const mglDataA &z, const char *pen="", const char *opt="")
-	{	mgl_step_xyz(gr, &x, &y, &z, pen, opt);	}
-	inline void Step(const mglDataA &x, const mglDataA &y, const char *pen="", const char *opt="")
-	{	mgl_step_xy(gr, &x, &y, pen, opt);	}
-	inline void Step(const mglDataA &y, const char *pen="", const char *opt="")
-	{	mgl_step(gr, &y, pen, opt);	}
-	/// Draw curve {x,y,z} which is colored by c (like tension plot)
-	inline void Tens(const mglDataA &x, const mglDataA &y, const mglDataA &z, const mglDataA &c, const char *pen="", const char *opt="")
-	{	mgl_tens_xyz(gr, &x, &y, &z, &c, pen, opt);	}
-	inline void Tens(const mglDataA &x, const mglDataA &y, const mglDataA &c, const char *pen="", const char *opt="")
-	{	mgl_tens_xy(gr, &x, &y, &c, pen, opt);	}
-	inline void Tens(const mglDataA &y, const mglDataA &c, const char *pen="", const char *opt="")
-	{	mgl_tens(gr, &y, &c, pen, opt);	}
-	/// Fill area between curve {x,y,z} and axis plane
-	inline void Area(const mglDataA &x, const mglDataA &y, const mglDataA &z, const char *pen="", const char *opt="")
-	{	mgl_area_xyz(gr, &x, &y, &z, pen, opt);	}
-	inline void Area(const mglDataA &x, const mglDataA &y, const char *pen="", const char *opt="")
-	{	mgl_area_xy(gr, &x, &y, pen, opt);	}
-	inline void Area(const mglDataA &y, const char *pen="", const char *opt="")
-	{	mgl_area(gr, &y, pen, opt);	}
-	/// Fill area between curves y1 and y2 specified parametrically
-	inline void Region(const mglDataA &y1, const mglDataA &y2, const char *pen="", const char *opt="")
-	{	mgl_region(gr, &y1, &y2, pen, opt);	}
-	inline void Region(const mglDataA &x, const mglDataA &y1, const mglDataA &y2, const char *pen="", const char *opt="")
-	{	mgl_region_xy(gr, &x, &y1, &y2, pen, opt);	}
-	/// Draw vertical lines from points {x,y,z} to axis plane
-	inline void Stem(const mglDataA &x, const mglDataA &y, const mglDataA &z, const char *pen="", const char *opt="")
-	{	mgl_stem_xyz(gr, &x, &y, &z, pen, opt);	}
-	inline void Stem(const mglDataA &x, const mglDataA &y, const char *pen="", const char *opt="")
-	{	mgl_stem_xy(gr, &x, &y, pen, opt);	}
-	inline void Stem(const mglDataA &y, const char *pen="", const char *opt="")
-	{	mgl_stem(gr, &y, pen, opt);	}
-
-	/// Draw vertical bars from points {x,y,z} to axis plane
-	inline void Bars(const mglDataA &x, const mglDataA &y, const mglDataA &z, const char *pen="", const char *opt="")
-	{	mgl_bars_xyz(gr, &x, &y, &z, pen, opt);	}
-	inline void Bars(const mglDataA &x, const mglDataA &y, const char *pen="", const char *opt="")
-	{	mgl_bars_xy(gr, &x, &y, pen, opt);	}
-	inline void Bars(const mglDataA &y, const char *pen="", const char *opt="")
-	{	mgl_bars(gr, &y, pen, opt);	}
-	/// Draw horizontal bars from points {x,y} to axis plane
-	inline void Barh(const mglDataA &y, const mglDataA &v, const char *pen="", const char *opt="")
-	{	mgl_barh_yx(gr, &y, &v, pen, opt);	}
-	inline void Barh(const mglDataA &v, const char *pen="", const char *opt="")
-	{	mgl_barh(gr, &v, pen, opt);	}
-	/// Draw chart for data a
-	inline void Chart(const mglDataA &a, const char *colors="", const char *opt="")
-	{	mgl_chart(gr, &a, colors,opt);	}
-	/// Draw box-plot (special 5-value plot used in statistic)
-	inline void BoxPlot(const mglDataA &x, const mglDataA &y, const char *pen="", const char *opt="")
-	{	mgl_boxplot_xy(gr, &x, &y, pen,opt);	}
-	inline void BoxPlot(const mglDataA &y, const char *pen="", const char *opt="")
-	{	mgl_boxplot(gr, &y, pen,opt);	}
-	/// Draw candle plot
-	inline void Candle(const mglDataA &x, const mglDataA &v1, const mglDataA &v2, const mglDataA &y1, const mglDataA &y2, const char *pen="", const char *opt="")
-	{	mgl_candle_xyv(gr, &x, &v1, &v2, &y1, &y2, pen, opt);	}
-	inline void Candle(const mglDataA &v1, const mglDataA &v2, const mglDataA &y1, const mglDataA &y2, const char *pen="", const char *opt="")
-	{	mgl_candle_yv(gr, &v1, &v2, &y1, &y2, pen, opt);	}
-	inline void Candle(const mglDataA &v1, const mglDataA &v2, const char *pen="", const char *opt="")
-	{	mgl_candle_yv(gr, &v1, &v2, NULL, NULL, pen, opt);	}
-	inline void Candle(const mglDataA &y, const mglDataA &y1, const mglDataA &y2, const char *pen="", const char *opt="")
-	{	mgl_candle(gr, &y, &y1, &y2, pen, opt);	}
-	inline void Candle(const mglDataA &y, const char *pen="", const char *opt="")
-	{	mgl_candle(gr, &y, NULL, NULL, pen, opt);	}
-	/// Draw cones from points {x,y,z} to axis plane
-	inline void Cones(const mglDataA &x, const mglDataA &y, const mglDataA &z, const char *pen="@", const char *opt="")
-	{	mgl_cones_xyz(gr, &x, &y, &z, pen, opt);	}
-	inline void Cones(const mglDataA &x, const mglDataA &z, const char *pen="@", const char *opt="")
-	{	mgl_cones_xz(gr, &x, &z, pen, opt);	}
-	inline void Cones(const mglDataA &z, const char *pen="@", const char *opt="")
-	{	mgl_cones(gr, &z, pen, opt);	}
-
-	/// Draw error boxes {ex,ey} at points {x,y}
-	inline void Error(const mglDataA &y, const mglDataA &ey, const char *pen="", const char *opt="")
-	{	mgl_error(gr, &y, &ey, pen, opt);	}
-	inline void Error(const mglDataA &x, const mglDataA &y, const mglDataA &ey, const char *pen="", const char *opt="")
-	{	mgl_error_xy(gr, &x, &y, &ey, pen, opt);	}
-	inline void Error(const mglDataA &x, const mglDataA &y, const mglDataA &ex, const mglDataA &ey, const char *pen="", const char *opt="")
-	{	mgl_error_exy(gr, &x, &y, &ex, &ey, pen, opt);	}
-	/// Draw marks with size r at points {x,y,z}
-	inline void Mark(const mglDataA &x, const mglDataA &y, const mglDataA &z, const mglDataA &r, const char *pen, const char *opt="")
-	{	mgl_mark_xyz(gr, &x, &y, &z, &r, pen, opt);	}
-	inline void Mark(const mglDataA &x, const mglDataA &y, const mglDataA &r, const char *pen, const char *opt="")
-	{	mgl_mark_xy(gr, &x, &y, &r, pen, opt);	}
-	inline void Mark(const mglDataA &y, const mglDataA &r, const char *pen, const char *opt="")
-	{	mgl_mark_y(gr, &y, &r, pen, opt);	}
-	/// Draw textual marks with size r at points {x,y,z}
-	inline void TextMark(const mglDataA &x, const mglDataA &y, const mglDataA &z, const mglDataA &r, const char *text, const char *fnt="", const char *opt="")
-	{	mgl_textmark_xyzr(gr, &x, &y, &z, &r, text, fnt, opt);	}
-	inline void TextMark(const mglDataA &x, const mglDataA &y, const mglDataA &r, const char *text, const char *fnt="", const char *opt="")
-	{	mgl_textmark_xyr(gr, &x, &y, &r, text, fnt, opt);	}
-	inline void TextMark(const mglDataA &y, const mglDataA &r, const char *text, const char *fnt="", const char *opt="")
-	{	mgl_textmark_yr(gr, &y, &r, text, fnt, opt);	}
-	inline void TextMark(const mglDataA &y, const char *text, const char *fnt="", const char *opt="")
-	{	mgl_textmark(gr, &y, text, fnt, opt);	}
-	inline void TextMark(const mglDataA &x, const mglDataA &y, const mglDataA &z, const mglDataA &r, const wchar_t *text, const char *fnt="", const char *opt="")
-	{	mgl_textmarkw_xyzr(gr, &x, &y, &z, &r, text, fnt, opt);	}
-	inline void TextMark(const mglDataA &x, const mglDataA &y, const mglDataA &r, const wchar_t *text, const char *fnt="", const char *opt="")
-	{	mgl_textmarkw_xyr(gr, &x, &y, &r, text, fnt, opt);	}
-	inline void TextMark(const mglDataA &y, const mglDataA &r, const wchar_t *text, const char *fnt="", const char *opt="")
-	{	mgl_textmarkw_yr(gr, &y, &r, text, fnt, opt);	}
-	inline void TextMark(const mglDataA &y, const wchar_t *text, const char *fnt="", const char *opt="")
-	{	mgl_textmarkw(gr, &y, text, fnt, opt);	}
-
-	/// Draw labels for points coordinate(s) at points {x,y,z}
-	inline void Label(const mglDataA &x, const mglDataA &y, const mglDataA &z, const char *text, const char *fnt="", const char *opt="")
-	{	mgl_label_xyz(gr, &x, &y, &z, text, fnt, opt);	}
-	inline void Label(const mglDataA &x, const mglDataA &y, const char *text, const char *fnt="", const char *opt="")
-	{	mgl_label_xy(gr, &x, &y, text, fnt, opt);	}
-	inline void Label(const mglDataA &y, const char *text, const char *fnt="", const char *opt="")
-	{	mgl_label_y(gr, &y, text, fnt, opt);	}
-	inline void Label(const mglDataA &x, const mglDataA &y, const mglDataA &z, const wchar_t *text, const char *fnt="", const char *opt="")
-	{	mgl_labelw_xyz(gr, &x, &y, &z, text, fnt, opt);	}
-	inline void Label(const mglDataA &x, const mglDataA &y, const wchar_t *text, const char *fnt="", const char *opt="")
-	{	mgl_labelw_xy(gr, &x, &y, text, fnt, opt);	}
-	inline void Label(const mglDataA &y, const wchar_t *text, const char *fnt="", const char *opt="")
-	{	mgl_labelw_y(gr, &y, text, fnt, opt);	}
-
-	/// Draw table for values val along given direction with row labels text
-	inline void Table(const mglDataA &val, const char *text, const char *fnt="#|", const char *opt="")
-	{	mgl_table(gr, 0, 0, &val, text, fnt, opt);	}
-	inline void Table(const mglDataA &val, const wchar_t *text, const char *fnt="#|", const char *opt="")
-	{	mgl_tablew(gr, 0, 0, &val, text, fnt, opt);	}
-	/// Draw table for values val along given direction with row labels text at given position
-	inline void Table(double x, double y, const mglDataA &val, const char *text, const char *fnt="#|", const char *opt="")
-	{	mgl_table(gr, x, y, &val, text, fnt, opt);	}
-	inline void Table(double x, double y, const mglDataA &val, const wchar_t *text, const char *fnt="#|", const char *opt="")
-	{	mgl_tablew(gr, x, y, &val, text, fnt, opt);	}
-	
-	/// Draw tube with radius r around curve {x,y,z}
-	inline void Tube(const mglDataA &x, const mglDataA &y, const mglDataA &z, const mglDataA &r, const char *pen="", const char *opt="")
-	{	mgl_tube_xyzr(gr, &x, &y, &z, &r, pen, opt);	}
-	inline void Tube(const mglDataA &x, const mglDataA &y, const mglDataA &z, double r, const char *pen="", const char *opt="")
-	{	mgl_tube_xyz(gr, &x, &y, &z, r, pen, opt);	}
-	inline void Tube(const mglDataA &x, const mglDataA &y, const mglDataA &r, const char *pen="", const char *opt="")
-	{	mgl_tube_xyr(gr, &x, &y, &r, pen, opt);	}
-	inline void Tube(const mglDataA &x, const mglDataA &y, double r, const char *pen="", const char *opt="")
-	{	mgl_tube_xy(gr, &x, &y, r, pen, opt);	}
-	inline void Tube(const mglDataA &y, const mglDataA &r, const char *pen="", const char *opt="")
-	{	mgl_tube_r(gr, &y, &r, pen, opt);	}
-	inline void Tube(const mglDataA &y, double r, const char *pen="", const char *opt="")
-	{	mgl_tube(gr, &y, r, pen, opt);	}
-	/// Draw surface of curve {r,z} rotatation around axis
-	inline void Torus(const mglDataA &r, const mglDataA &z, const char *pen="", const char *opt="")
-	{	mgl_torus(gr, &r, &z, pen,opt);	}
-
-	/// Draw mesh lines for 2d data specified parametrically
-	inline void Mesh(const mglDataA &x, const mglDataA &y, const mglDataA &z, const char *stl="", const char *opt="")
-	{	mgl_mesh_xy(gr, &x, &y, &z, stl, opt);	}
-	inline void Mesh(const mglDataA &z, const char *stl="", const char *opt="")
-	{	mgl_mesh(gr, &z, stl, opt);	}
-	/// Draw mesh lines for 2d data specified parametrically
-	inline void Fall(const mglDataA &x, const mglDataA &y, const mglDataA &z, const char *stl="", const char *opt="")
-	{	mgl_fall_xy(gr, &x, &y, &z, stl, opt);	}
-	inline void Fall(const mglDataA &z, const char *stl="", const char *opt="")
-	{	mgl_fall(gr, &z, stl, opt);	}
-	/// Draw belts for 2d data specified parametrically
-	inline void Belt(const mglDataA &x, const mglDataA &y, const mglDataA &z, const char *stl="", const char *opt="")
-	{	mgl_belt_xy(gr, &x, &y, &z, stl, opt);	}
-	inline void Belt(const mglDataA &z, const char *stl="", const char *opt="")
-	{	mgl_belt(gr, &z, stl, opt);	}
-	/// Draw surface for 2d data specified parametrically with color proportional to z
-	inline void Surf(const mglDataA &x, const mglDataA &y, const mglDataA &z, const char *stl="", const char *opt="")
-	{	mgl_surf_xy(gr, &x, &y, &z, stl, opt);	}
-	inline void Surf(const mglDataA &z, const char *stl="", const char *opt="")
-	{	mgl_surf(gr, &z, stl, opt);	}
-	/// Draw grid lines for density plot of 2d data specified parametrically
-	inline void Grid(const mglDataA &x, const mglDataA &y, const mglDataA &z, const char *stl="", const char *opt="")
-	{	mgl_grid_xy(gr, &x, &y, &z, stl, opt);	}
-	inline void Grid(const mglDataA &z, const char *stl="", const char *opt="")
-	{	mgl_grid(gr, &z, stl, opt);	}
-	/// Draw vertical tiles for 2d data specified parametrically
-	inline void Tile(const mglDataA &x, const mglDataA &y, const mglDataA &z, const char *stl="", const char *opt="")
-	{	mgl_tile_xy(gr, &x, &y, &z, stl, opt);	}
-	inline void Tile(const mglDataA &z, const char *stl="", const char *opt="")
-	{	mgl_tile(gr, &z, stl, opt);	}
-	/// Draw density plot for 2d data specified parametrically
-	inline void Dens(const mglDataA &x, const mglDataA &y, const mglDataA &z, const char *stl="", const char *opt="")
-	{	mgl_dens_xy(gr, &x, &y, &z, stl, opt);	}
-	inline void Dens(const mglDataA &z, const char *stl="", const char *opt="")
-	{	mgl_dens(gr, &z, stl, opt);	}
-	/// Draw vertical boxes for 2d data specified parametrically
-	inline void Boxs(const mglDataA &x, const mglDataA &y, const mglDataA &z, const char *stl="", const char *opt="")
-	{	mgl_boxs_xy(gr, &x, &y, &z, stl, opt);	}
-	inline void Boxs(const mglDataA &z, const char *stl="", const char *opt="")
-	{	mgl_boxs(gr, &z, stl, opt);	}
-
-	/// Draw contour lines for 2d data specified parametrically
-	inline void Cont(const mglDataA &v, const mglDataA &x, const mglDataA &y, const mglDataA &z, const char *sch="", const char *opt="")
-	{	mgl_cont_xy_val(gr, &v, &x, &y, &z, sch, opt);	}
-	inline void Cont(const mglDataA &v, const mglDataA &z, const char *sch="", const char *opt="")
-	{	mgl_cont_val(gr, &v, &z, sch, opt);	}
-	inline void Cont(const mglDataA &x, const mglDataA &y, const mglDataA &z, const char *sch="", const char *opt="")
-	{	mgl_cont_xy(gr, &x, &y, &z, sch, opt);	}
-	inline void Cont(const mglDataA &z, const char *sch="", const char *opt="")
-	{	mgl_cont(gr, &z, sch, opt);	}
-	/// Draw solid contours for 2d data specified parametrically
-	inline void ContF(const mglDataA &v, const mglDataA &x, const mglDataA &y, const mglDataA &z, const char *sch="", const char *opt="")
-	{	mgl_contf_xy_val(gr, &v, &x, &y, &z, sch, opt);	}
-	inline void ContF(const mglDataA &v, const mglDataA &z, const char *sch="", const char *opt="")
-	{	mgl_contf_val(gr, &v, &z, sch, opt);	}
-	inline void ContF(const mglDataA &x, const mglDataA &y, const mglDataA &z, const char *sch="", const char *opt="")
-	{	mgl_contf_xy(gr, &x, &y, &z, sch, opt);	}
-	inline void ContF(const mglDataA &z, const char *sch="", const char *opt="")
-	{	mgl_contf(gr, &z, sch, opt);	}
-	/// Draw solid contours for 2d data specified parametrically with manual colors
-	inline void ContD(const mglDataA &v, const mglDataA &x, const mglDataA &y, const mglDataA &z, const char *sch="", const char *opt="")
-	{	mgl_contd_xy_val(gr, &v, &x, &y, &z, sch, opt);	}
-	inline void ContD(const mglDataA &v, const mglDataA &z, const char *sch="", const char *opt="")
-	{	mgl_contd_val(gr, &v, &z, sch, opt);	}
-	inline void ContD(const mglDataA &x, const mglDataA &y, const mglDataA &z, const char *sch="", const char *opt="")
-	{	mgl_contd_xy(gr, &x, &y, &z, sch, opt);	}
-	inline void ContD(const mglDataA &z, const char *sch="", const char *opt="")
-	{	mgl_contd(gr, &z, sch, opt);	}
-	/// Draw contour tubes for 2d data specified parametrically
-	inline void ContV(const mglDataA &v, const mglDataA &x, const mglDataA &y, const mglDataA &z, const char *sch="", const char *opt="")
-	{	mgl_contv_xy_val(gr, &v, &x, &y, &z, sch, opt);	}
-	inline void ContV(const mglDataA &v, const mglDataA &z, const char *sch="", const char *opt="")
-	{	mgl_contv_val(gr, &v, &z, sch, opt);	}
-	inline void ContV(const mglDataA &x, const mglDataA &y, const mglDataA &z, const char *sch="", const char *opt="")
-	{	mgl_contv_xy(gr, &x, &y, &z, sch, opt);	}
-	inline void ContV(const mglDataA &z, const char *sch="", const char *opt="")
-	{	mgl_contv(gr, &z, sch, opt);	}
-
-	/// Draw axial-symmetric isosurfaces for 2d data specified parametrically
-	inline void Axial(const mglDataA &v, const mglDataA &x, const mglDataA &y, const mglDataA &z, const char *sch="", const char *opt="")
-	{	mgl_axial_xy_val(gr, &v, &x, &y, &z, sch,opt);	}
-	inline void Axial(const mglDataA &v, const mglDataA &z, const char *sch="", const char *opt="")
-	{	mgl_axial_val(gr, &v, &z, sch, opt);	}
-	inline void Axial(const mglDataA &x, const mglDataA &y, const mglDataA &z, const char *sch="", const char *opt="")
-	{	mgl_axial_xy(gr, &x, &y, &z, sch, opt);	}
-	inline void Axial(const mglDataA &z, const char *sch="", const char *opt="")
-	{	mgl_axial(gr, &z, sch, opt);	}
-
-	/// Draw grid lines for density plot at slice for 3d data specified parametrically
-	inline void Grid3(const mglDataA &x, const mglDataA &y, const mglDataA &z, const mglDataA &a, const char *stl="", double sVal=-1, const char *opt="")
-	{	mgl_grid3_xyz(gr, &x, &y, &z, &a, stl, sVal, opt);	}
-	inline void Grid3(const mglDataA &a, const char *stl="", double sVal=-1, const char *opt="")
-	{	mgl_grid3(gr, &a, stl, sVal, opt);	}
-	/// Draw density plot at slice for 3d data specified parametrically
-	inline void Dens3(const mglDataA &x, const mglDataA &y, const mglDataA &z, const mglDataA &a, const char *stl="", double sVal=-1, const char *opt="")
-	{	mgl_dens3_xyz(gr, &x, &y, &z, &a, stl, sVal, opt);	}
-	inline void Dens3(const mglDataA &a, const char *stl="", double sVal=-1, const char *opt="")
-	{	mgl_dens3(gr, &a, stl, sVal, opt);	}
-
-	/// Draw isosurface(s) for 3d data specified parametrically
-	inline void Surf3(double Val, const mglDataA &x, const mglDataA &y, const mglDataA &z, const mglDataA &a, const char *stl="", const char *opt="")
-	{	mgl_surf3_xyz_val(gr, Val, &x, &y, &z, &a, stl, opt);	}
-	inline void Surf3(double Val, const mglDataA &a, const char *stl="", const char *opt="")
-	{	mgl_surf3_val(gr, Val, &a, stl, opt);	}
-	inline void Surf3(const mglDataA &x, const mglDataA &y, const mglDataA &z, const mglDataA &a, const char *stl="", const char *opt="")
-	{	mgl_surf3_xyz(gr, &x, &y, &z, &a, stl, opt);	}
-	inline void Surf3(const mglDataA &a, const char *stl="", const char *opt="")
-	{	mgl_surf3(gr, &a, stl, opt);	}
-
-	/// Draw a semi-transparent cloud for 3d data
-	inline void Cloud(const mglDataA &x, const mglDataA &y, const mglDataA &z, const mglDataA &a, const char *stl="", const char *opt="")
-	{	mgl_cloud_xyz(gr, &x, &y, &z, &a, stl, opt);	}
-	inline void Cloud(const mglDataA &a, const char *stl="", const char *opt="")
-	{	mgl_cloud(gr, &a, stl, opt);	}
-
-	/// Draw contour lines at slice for 3d data specified parametrically
-	inline void Cont3(const mglDataA &v, const mglDataA &x, const mglDataA &y, const mglDataA &z, const mglDataA &a, const char *sch="", double sVal=-1, const char *opt="")
-	{	mgl_cont3_xyz_val(gr, &v, &x, &y, &z, &a, sch, sVal, opt);	}
-	inline void Cont3(const mglDataA &v, const mglDataA &a, const char *sch="", double sVal=-1, const char *opt="")
-	{	mgl_cont3_val(gr, &v, &a, sch, sVal, opt);	}
-	inline void Cont3(const mglDataA &x, const mglDataA &y, const mglDataA &z, const mglDataA &a, const char *sch="", double sVal=-1, const char *opt="")
-	{	mgl_cont3_xyz(gr, &x, &y, &z, &a, sch, sVal, opt);	}
-	inline void Cont3(const mglDataA &a, const char *sch="", double sVal=-1, const char *opt="")
-	{	mgl_cont3(gr, &a, sch, sVal, opt);	}
-
-	/// Draw solid contours at slice for 3d data specified parametrically
-	inline void ContF3(const mglDataA &v, const mglDataA &x, const mglDataA &y, const mglDataA &z, const mglDataA &a, const char *sch="", double sVal=-1, const char *opt="")
-	{	mgl_contf3_xyz_val(gr, &v, &x, &y, &z, &a, sch, sVal, opt);	}
-	inline void ContF3(const mglDataA &v, const mglDataA &a, const char *sch="", double sVal=-1, const char *opt="")
-	{	mgl_contf3_val(gr, &v, &a, sch, sVal, opt);	}
-	inline void ContF3(const mglDataA &x, const mglDataA &y, const mglDataA &z, const mglDataA &a, const char *sch="", double sVal=-1, const char *opt="")
-	{	mgl_contf3_xyz(gr, &x, &y, &z, &a, sch, sVal, opt);	}
-	inline void ContF3(const mglDataA &a, const char *sch="", double sVal=-1, const char *opt="")
-	{	mgl_contf3(gr, &a, sch, sVal, opt);	}
-
-	/// Draw several isosurfaces for 3d beam in curvilinear coordinates
-	inline void Beam(const mglDataA &tr, const mglDataA &g1, const mglDataA &g2, const mglDataA &a, double r, const char *stl=0, int flag=0, int num=3)
-	{	mgl_beam(gr, &tr,&g1,&g2,&a,r,stl,flag,num);	}
-	inline void Beam(double val, const mglDataA &tr, const mglDataA &g1, const mglDataA &g2, const mglDataA &a, double r, const char *stl=NULL, int flag=0)
-	{	mgl_beam_val(gr,val,&tr,&g1,&g2,&a,r,stl,flag);	}
-
-	/// Draw vertical tiles with variable size r for 2d data specified parametrically
-	inline void TileS(const mglDataA &x, const mglDataA &y, const mglDataA &z, const mglDataA &r, const char *stl="", const char *opt="")
-	{	mgl_tiles_xy(gr, &x, &y, &z, &r, stl, opt);	}
-	inline void TileS(const mglDataA &z, const mglDataA &r, const char *stl="", const char *opt="")
-	{	mgl_tiles(gr, &z, &r, stl, opt);	}
-	/// Draw surface for 2d data specified parametrically with color proportional to c
-	inline void SurfC(const mglDataA &x, const mglDataA &y, const mglDataA &z, const mglDataA &c, const char *sch="", const char *opt="")
-	{	mgl_surfc_xy(gr, &x, &y, &z, &c, sch,opt);	}
-	inline void SurfC(const mglDataA &z, const mglDataA &c, const char *sch="", const char *opt="")
-	{	mgl_surfc(gr, &z, &c, sch,opt);	}
-	/// Draw surface for 2d data specified parametrically with alpha proportional to c
-	inline void SurfA(const mglDataA &x, const mglDataA &y, const mglDataA &z, const mglDataA &c, const char *sch="", const char *opt="")
-	{	mgl_surfa_xy(gr, &x, &y, &z, &c, sch,opt);	}
-	inline void SurfA(const mglDataA &z, const mglDataA &c, const char *sch="", const char *opt="")
-	{	mgl_surfa(gr, &z, &c, sch,opt);	}
-
-	/// Color map of matrix a to matrix b, both matrix can parametrically depend on coordinates
-	inline void Map(const mglDataA &x, const mglDataA &y, const mglDataA &a, const mglDataA &b, const char *sch="", const char *opt="")
-	{	mgl_map_xy(gr, &x, &y, &a, &b, sch, opt);	}
-	inline void Map(const mglDataA &a, const mglDataA &b, const char *sch="", const char *opt="")
-	{	mgl_map(gr, &a, &b, sch, opt);	}
-	/// Draw density plot for spectra-gramm specified parametrically
-	inline void STFA(const mglDataA &x, const mglDataA &y, const mglDataA &re, const mglDataA &im, int dn, const char *sch="", const char *opt="")
-	{	mgl_stfa_xy(gr, &x, &y, &re, &im, dn, sch, opt);	}
-	inline void STFA(const mglDataA &re, const mglDataA &im, int dn, const char *sch="", const char *opt="")
-	{	mgl_stfa(gr, &re, &im, dn, sch, opt);	}
-
-	/// Draw isosurface(s) for 3d data specified parametrically with alpha proportional to b
-	inline void Surf3A(double Val, const mglDataA &x, const mglDataA &y, const mglDataA &z, const mglDataA &a, const mglDataA &b, const char *stl="", const char *opt="")
-	{	mgl_surf3a_xyz_val(gr, Val, &x, &y, &z, &a, &b, stl, opt);	}
-	inline void Surf3A(double Val, const mglDataA &a, const mglDataA &b, const char *stl="", const char *opt="")
-	{	mgl_surf3a_val(gr, Val, &a, &b, stl, opt);	}
-	inline void Surf3A(const mglDataA &x, const mglDataA &y, const mglDataA &z, const mglDataA &a, const mglDataA &b, const char *stl="", const char *opt="")
-	{	mgl_surf3a_xyz(gr, &x, &y, &z, &a, &b, stl, opt);	}
-	inline void Surf3A(const mglDataA &a, const mglDataA &b, const char *stl="", const char *opt="")
-	{	mgl_surf3a(gr, &a, &b, stl, opt);	}
-
-	/// Draw isosurface(s) for 3d data specified parametrically with color proportional to b
-	inline void Surf3C(double Val, const mglDataA &x, const mglDataA &y, const mglDataA &z, const mglDataA &a, const mglDataA &b, const char *stl="", const char *opt="")
-	{	mgl_surf3c_xyz_val(gr, Val, &x, &y, &z, &a, &b, stl,opt);	}
-	inline void Surf3C(double Val, const mglDataA &a, const mglDataA &b, const char *stl="", const char *opt="")
-	{	mgl_surf3c_val(gr, Val, &a, &b, stl, opt);	}
-	inline void Surf3C(const mglDataA &x, const mglDataA &y, const mglDataA &z, const mglDataA &a, const mglDataA &b, const char *stl="", const char *opt="")
-	{	mgl_surf3c_xyz(gr, &x, &y, &z, &a, &b, stl, opt);	}
-	inline void Surf3C(const mglDataA &a, const mglDataA &b, const char *stl="", const char *opt="")
-	{	mgl_surf3c(gr, &a, &b, stl, opt);	}
-
-	/// Plot dew drops for vector field {ax,ay} parametrically depended on coordinate {x,y}
-	inline void Dew(const mglDataA &x, const mglDataA &y, const mglDataA &ax, const mglDataA &ay, const char *sch="", const char *opt="")
-	{	mgl_dew_xy(gr, &x, &y, &ax, &ay, sch, opt);	}
-	inline void Dew(const mglDataA &ax, const mglDataA &ay, const char *sch="", const char *opt="")
-	{	mgl_dew_2d(gr, &ax, &ay, sch, opt);	}
-	/// Plot vectors at position {x,y,z} along {ax,ay,az} with length/color proportional to |a|
-	inline void Traj(const mglDataA &x, const mglDataA &y, const mglDataA &ax, const mglDataA &ay, const char *sch="", const char *opt="")
-	{	mgl_traj_xy(gr, &x, &y, &ax, &ay, sch, opt);	}
-	inline void Traj(const mglDataA &x, const mglDataA &y, const mglDataA &z, const mglDataA &ax, const mglDataA &ay, const mglDataA &az, const char *sch="", const char *opt="")
-	{	mgl_traj_xyz(gr, &x, &y, &z, &ax, &ay, &az, sch, opt);	}
-
-	/// Plot vector field {ax,ay,az} parametrically depended on coordinate {x,y,z} with length/color proportional to |a|
-	inline void Vect(const mglDataA &x, const mglDataA &y, const mglDataA &ax, const mglDataA &ay, const char *sch="", const char *opt="")
-	{	mgl_vect_xy(gr, &x, &y, &ax, &ay, sch, opt);	}
-	inline void Vect(const mglDataA &ax, const mglDataA &ay, const char *sch="", const char *opt="")
-	{	mgl_vect_2d(gr, &ax, &ay, sch, opt);	}
-	inline void Vect(const mglDataA &x, const mglDataA &y, const mglDataA &z, const mglDataA &ax, const mglDataA &ay, const mglDataA &az, const char *sch="", const char *opt="")
-	{	mgl_vect_xyz(gr, &x, &y, &z, &ax, &ay, &az, sch, opt);	}
-	inline void Vect(const mglDataA &ax, const mglDataA &ay, const mglDataA &az, const char *sch="", const char *opt="")
-	{	mgl_vect_3d(gr, &ax, &ay, &az, sch, opt);	}
-
-	/// Draw vector plot at slice for 3d data specified parametrically
-	inline void Vect3(const mglDataA &x, const mglDataA &y, const mglDataA &z, const mglDataA &ax, const mglDataA &ay, const mglDataA &az, const char *stl="", double sVal=-1, const char *opt="")
-	{	mgl_vect3_xyz(gr, &x, &y, &z, &ax,&ay,&az, stl, sVal, opt);	}
-	inline void Vect3(const mglDataA &ax, const mglDataA &ay, const mglDataA &az, const char *stl="", double sVal=-1, const char *opt="")
-	{	mgl_vect3(gr, &ax,&ay,&az, stl, sVal, opt);	}
-
-	/// Plot flows for vector field {ax,ay,az} parametrically depended on coordinate {x,y,z} with color proportional to |a|
-	inline void Flow(const mglDataA &x, const mglDataA &y, const mglDataA &ax, const mglDataA &ay, const char *sch="", const char *opt="")
-	{	mgl_flow_xy(gr, &x, &y, &ax, &ay, sch, opt);	}
-	inline void Flow(const mglDataA &ax, const mglDataA &ay, const char *sch="", const char *opt="")
-	{	mgl_flow_2d(gr, &ax, &ay, sch, opt);	}
-	inline void Flow(const mglDataA &x, const mglDataA &y, const mglDataA &z, const mglDataA &ax, const mglDataA &ay, const mglDataA &az, const char *sch="", const char *opt="")
-	{	mgl_flow_xyz(gr, &x, &y, &z, &ax, &ay, &az, sch, opt);	}
-	inline void Flow(const mglDataA &ax, const mglDataA &ay, const mglDataA &az, const char *sch="", const char *opt="")
-	{	mgl_flow_3d(gr, &ax, &ay, &az, sch, opt);	}
-
-	/// Plot flow from point p for vector field {ax,ay,az} parametrically depended on coordinate {x,y,z} with color proportional to |a|
-	inline void FlowP(mglPoint p, const mglDataA &x, const mglDataA &y, const mglDataA &ax, const mglDataA &ay, const char *sch="", const char *opt="")
-	{	mgl_flowp_xy(gr, p.x, p.y, p.z, &x, &y, &ax, &ay, sch, opt);	}
-	inline void FlowP(mglPoint p, const mglDataA &ax, const mglDataA &ay, const char *sch="", const char *opt="")
-	{	mgl_flowp_2d(gr, p.x, p.y, p.z, &ax, &ay, sch, opt);	}
-	inline void FlowP(mglPoint p, const mglDataA &x, const mglDataA &y, const mglDataA &z, const mglDataA &ax, const mglDataA &ay, const mglDataA &az, const char *sch="", const char *opt="")
-	{	mgl_flowp_xyz(gr, p.x, p.y, p.z, &x, &y, &z, &ax, &ay, &az, sch, opt);	}
-	inline void FlowP(mglPoint p, const mglDataA &ax, const mglDataA &ay, const mglDataA &az, const char *sch="", const char *opt="")
-	{	mgl_flowp_3d(gr, p.x, p.y, p.z, &ax, &ay, &az, sch, opt);	}
-
-	/// Plot flows for gradient of scalar field phi parametrically depended on coordinate {x,y,z}
-	inline void Grad(const mglDataA &x, const mglDataA &y, const mglDataA &z, const mglDataA &phi, const char *sch="", const char *opt="")
-	{	mgl_grad_xyz(gr,&x,&y,&z,&phi,sch,opt);	}
-	inline void Grad(const mglDataA &x, const mglDataA &y, const mglDataA &phi, const char *sch="", const char *opt="")
-	{	mgl_grad_xy(gr,&x,&y,&phi,sch,opt);	}
-	inline void Grad(const mglDataA &phi, const char *sch="", const char *opt="")
-	{	mgl_grad(gr,&phi,sch,opt);	}
-
-	/// Plot flow pipes for vector field {ax,ay,az} parametrically depended on coordinate {x,y,z} with color and radius proportional to |a|
-	inline void Pipe(const mglDataA &x, const mglDataA &y, const mglDataA &ax, const mglDataA &ay, const char *sch="", double r0=0.05, const char *opt="")
-	{	mgl_pipe_xy(gr, &x, &y, &ax, &ay, sch, r0, opt);	}
-	inline void Pipe(const mglDataA &ax, const mglDataA &ay, const char *sch="", double r0=0.05, const char *opt="")
-	{	mgl_pipe_2d(gr, &ax, &ay, sch, r0, opt);	}
-	inline void Pipe(const mglDataA &x, const mglDataA &y, const mglDataA &z, const mglDataA &ax, const mglDataA &ay, const mglDataA &az, const char *sch="", double r0=0.05, const char *opt="")
-	{	mgl_pipe_xyz(gr, &x, &y, &z, &ax, &ay, &az, sch, r0, opt);	}
-	inline void Pipe(const mglDataA &ax, const mglDataA &ay, const mglDataA &az, const char *sch="", double r0=0.05, const char *opt="")
-	{	mgl_pipe_3d(gr, &ax, &ay, &az, sch, r0, opt);	}
-
-	/// Draw density plot for data at x = sVal
-	inline void DensX(const mglDataA &a, const char *stl="", double sVal=NaN, const char *opt="")
-	{	mgl_dens_x(gr, &a, stl, sVal, opt);	}
-	/// Draw density plot for data at y = sVal
-	inline void DensY(const mglDataA &a, const char *stl="", double sVal=NaN, const char *opt="")
-	{	mgl_dens_y(gr, &a, stl, sVal, opt);	}
-	/// Draw density plot for data at z = sVal
-	inline void DensZ(const mglDataA &a, const char *stl="", double sVal=NaN, const char *opt="")
-	{	mgl_dens_z(gr, &a, stl, sVal, opt);	}
-	/// Draw contour lines for data at x = sVal
-	inline void ContX(const mglDataA &a, const char *stl="", double sVal=NaN, const char *opt="")
-	{	mgl_cont_x(gr, &a, stl, sVal, opt);	}
-	inline void ContX(const mglDataA &v, const mglDataA &a, const char *stl="", double sVal=NaN, const char *opt="")
-	{	mgl_cont_x_val(gr, &v, &a, stl, sVal, opt);	}
-	/// Draw contour lines for data at y = sVal
-	inline void ContY(const mglDataA &a, const char *stl="", double sVal=NaN, const char *opt="")
-	{	mgl_cont_y(gr, &a, stl, sVal, opt);	}
-	inline void ContY(const mglDataA &v, const mglDataA &a, const char *stl="", double sVal=NaN, const char *opt="")
-	{	mgl_cont_y_val(gr, &v, &a, stl, sVal, opt);	}
-	/// Draw contour lines for data at z = sVal
-	inline void ContZ(const mglDataA &a, const char *stl="", double sVal=NaN, const char *opt="")
-	{	mgl_cont_z(gr, &a, stl, sVal, opt);	}
-	inline void ContZ(const mglDataA &v, const mglDataA &a, const char *stl="", double sVal=NaN, const char *opt="")
-	{	mgl_cont_z_val(gr, &v, &a, stl, sVal, opt);	}
-	/// Draw solid contours for data at x = sVal
-	inline void ContFX(const mglDataA &a, const char *stl="", double sVal=NaN, const char *opt="")
-	{	mgl_contf_x(gr, &a, stl, sVal, opt);	}
-	inline void ContFX(const mglDataA &v, const mglDataA &a, const char *stl="", double sVal=NaN, const char *opt="")
-	{	mgl_contf_x_val(gr, &v, &a, stl, sVal, opt);	}
-	/// Draw solid contours for data at y = sVal
-	inline void ContFY(const mglDataA &a, const char *stl="", double sVal=NaN, const char *opt="")
-	{	mgl_contf_y(gr, &a, stl, sVal, opt);	}
-	inline void ContFY(const mglDataA &v, const mglDataA &a, const char *stl="", double sVal=NaN, const char *opt="")
-	{	mgl_contf_y_val(gr, &v, &a, stl, sVal, opt);	}
-	/// Draw solid contours for data at z = sVal
-	inline void ContFZ(const mglDataA &a, const char *stl="", double sVal=NaN, const char *opt="")
-	{	mgl_contf_z(gr, &a, stl, sVal, opt);	}
-	inline void ContFZ(const mglDataA &v, const mglDataA &a, const char *stl="", double sVal=NaN, const char *opt="")
-	{	mgl_contf_z_val(gr, &v, &a, stl, sVal, opt);	}
-
-	/// Draw curve for formula with x in x-axis range
-	inline void FPlot(const char *fy, const char *stl="", const char *opt="")
-	{	mgl_fplot(gr, fy, stl, opt);	}
-	/// Draw curve for formulas parametrically depended on t in range [0,1]
-	inline void FPlot(const char *fx, const char *fy, const char *fz, const char *stl, const char *opt="")
-	{	mgl_fplot_xyz(gr, fx, fy, fz, stl, opt);	}
-	/// Draw surface by formula with x,y in axis range
-	inline void FSurf(const char *fz, const char *stl="", const char *opt="")
-	{	mgl_fsurf(gr, fz, stl, opt);	}
-	/// Draw surface by formulas parametrically depended on u,v in range [0,1]
-	inline void FSurf(const char *fx, const char *fy, const char *fz, const char *stl, const char *opt="")
-	{	mgl_fsurf_xyz(gr, fx, fy, fz, stl, opt);	}
-
-	/// Draw triangle mesh for points in arrays {x,y,z} with specified color c.
-	inline void TriPlot(const mglDataA &nums, const mglDataA &x, const mglDataA &y, const mglDataA &z, const mglDataA &c, const char *sch="", const char *opt="")
-	{	mgl_triplot_xyzc(gr, &nums, &x, &y, &z, &c, sch, opt);	}
-	inline void TriPlot(const mglDataA &nums, const mglDataA &x, const mglDataA &y, const mglDataA &z, const char *sch="", const char *opt="")
-	{	mgl_triplot_xyz(gr, &nums, &x, &y, &z, sch, opt);	}
-	inline void TriPlot(const mglDataA &nums, const mglDataA &x, const mglDataA &y, const char *sch="", const char *opt="")
-	{	mgl_triplot_xy(gr, &nums, &x, &y, sch, opt);	}
-	/// Draw quad mesh for points in arrays {x,y,z} with specified color c.
-	inline void QuadPlot(const mglDataA &nums, const mglDataA &x, const mglDataA &y, const mglDataA &z, const mglDataA &c, const char *sch="", const char *opt="")
-	{	mgl_quadplot_xyzc(gr, &nums, &x, &y, &z, &c, sch, opt);	}
-	inline void QuadPlot(const mglDataA &nums, const mglDataA &x, const mglDataA &y, const mglDataA &z, const char *sch="", const char *opt="")
-	{	mgl_quadplot_xyz(gr, &nums, &x, &y, &z, sch, opt);	}
-	inline void QuadPlot(const mglDataA &nums, const mglDataA &x, const mglDataA &y, const char *sch="", const char *opt="")
-	{	mgl_quadplot_xy(gr, &nums, &x, &y, sch, opt);	}
-
-	/// Draw contour lines for triangle mesh for points in arrays {x,y,z} with specified color c.
-	inline void TriCont(const mglDataA &nums, const mglDataA &x, const mglDataA &y, const mglDataA &z, const char *sch="", const char *opt="")
-	{	mgl_tricont_xyc(gr, &nums, &x, &y, &z, sch, opt);	}
-	inline void TriContV(const mglDataA &v, const mglDataA &nums, const mglDataA &x, const mglDataA &y, const mglDataA &z, const char *sch="", const char *opt="")
-	{	mgl_tricont_xycv(gr, &v, &nums, &x, &y, &z, sch, opt);	}
-	inline void TriCont(const mglDataA &nums, const mglDataA &x, const mglDataA &y, const mglDataA &z, const mglDataA &a, const char *sch="", const char *opt="")
-	{	mgl_tricont_xyzc(gr, &nums, &x, &y, &z, &a, sch, opt);	}
-	inline void TriContV(const mglDataA &v, const mglDataA &nums, const mglDataA &x, const mglDataA &y, const mglDataA &z, const mglDataA &a, const char *sch="", const char *opt="")
-	{	mgl_tricont_xyzcv(gr, &v, &nums, &x, &y, &z, &a, sch, opt);	}
-
-	/// Draw dots in points {x,y,z}.
-	inline void Dots(const mglDataA &x, const mglDataA &y, const mglDataA &z, const char *sch="", const char *opt="")
-	{	mgl_dots(gr, &x, &y, &z, sch, opt);	}
-	/// Draw semitransparent dots in points {x,y,z} with alpha a.
-	inline void Dots(const mglDataA &x, const mglDataA &y, const mglDataA &z, const mglDataA &a, const char *sch="", const char *opt="")
-	{	mgl_dots_a(gr, &x, &y, &z, &a, sch, opt);	}
-	/// Draw surface reconstructed for points in arrays {x,y,z}.
-	inline void Crust(const mglDataA &x, const mglDataA &y, const mglDataA &z, const char *sch="", const char *opt="")
-	{	mgl_crust(gr, &x, &y, &z, sch, opt);	}
-
-	/// Fit data along x-direction for each data row. Return array with values for found formula.
-	inline mglData Fit(const mglDataA &y, const char *eq, const char *var, const char *opt="")
-	{	return mglData(true,mgl_fit_1(gr, &y, eq,var,0, opt));	}
-	inline mglData Fit(const mglDataA &y, const char *eq, const char *var, mglData &ini, const char *opt="")
-	{	return mglData(true,mgl_fit_1(gr, &y, eq, var, &ini, opt));	}
-	/// Fit data along x-, y-directions for each data slice. Return array with values for found formula.
-	inline mglData Fit2(const mglDataA &z, const char *eq, const char *var, const char *opt="")
-	{	return mglData(true,mgl_fit_2(gr, &z, eq, var,0, opt));	}
-	inline mglData Fit2(const mglDataA &z, const char *eq, const char *var, mglData &ini, const char *opt="")
-	{	return mglData(true,mgl_fit_2(gr, &z, eq, var, &ini, opt));	}
-	/// Fit data along along all directions. Return array with values for found formula.
-	inline mglData Fit3(const mglDataA &a, const char *eq, const char *var, const char *opt="")
-	{	return mglData(true,mgl_fit_3(gr, &a, eq, var,0, opt));	}
-	inline mglData Fit3(const mglDataA &a, const char *eq, const char *var, mglData &ini, const char *opt="")
-	{	return mglData(true,mgl_fit_3(gr, &a, eq, var, &ini, opt));	}
-	/// Fit data along x-direction for each data row. Return array with values for found formula.
-	inline mglData Fit(const mglDataA &x, const mglDataA &y, const char *eq, const char *var, const char *opt="")
-	{	return mglData(true,mgl_fit_xy(gr, &x, &y, eq, var,0, opt));	}
-	inline mglData Fit(const mglDataA &x, const mglDataA &y, const char *eq, const char *var, mglData &ini, const char *opt="")
-	{	return mglData(true,mgl_fit_xy(gr, &x, &y, eq, var, &ini, opt));	}
-	/// Fit data along x-, y-directions for each data slice. Return array with values for found formula.
-	inline mglData Fit(const mglDataA &x, const mglDataA &y, const mglDataA &z, const char *eq, const char *var, const char *opt="")
-	{	return mglData(true,mgl_fit_xyz(gr, &x, &y, &z, eq, var,0, opt));	}
-	inline mglData Fit(const mglDataA &x, const mglDataA &y, const mglDataA &z, const char *eq, const char *var, mglData &ini, const char *opt="")
-	{	return mglData(true,mgl_fit_xyz(gr, &x, &y, &z, eq, var, &ini, opt));	}
-	/// Fit data along along all directions. Return array with values for found formula.
-	inline mglData Fit(const mglDataA &x, const mglDataA &y, const mglDataA &z, const mglDataA &a, const char *eq, const char *var, const char *opt="")
-	{	return mglData(true,mgl_fit_xyza(gr, &x, &y, &z, &a, eq, var,0, opt));	}
-	inline mglData Fit(const mglDataA &x, const mglDataA &y, const mglDataA &z, const mglDataA &a, const char *eq, const char *var, mglData &ini, const char *opt="")
-	{	return mglData(true,mgl_fit_xyza(gr, &x, &y, &z, &a, eq,var, &ini, opt));	}
-	/// Fit data with dispersion s along x-direction for each data row. Return array with values for found formula.
-	inline mglData FitS(const mglDataA &y, const mglDataA &s, const char *eq, const char *var, const char *opt="")
-	{	return mglData(true,mgl_fit_ys(gr, &y, &s, eq, var,0, opt));	}
-	inline mglData FitS(const mglDataA &y, const mglDataA &s, const char *eq, const char *var, mglData &ini, const char *opt="")
-	{	return mglData(true,mgl_fit_ys(gr, &y, &s, eq, var, &ini, opt));	}
-	inline mglData FitS(const mglDataA &x, const mglDataA &y, const mglDataA &s, const char *eq, const char *var, const char *opt="")
-	{	return mglData(true,mgl_fit_xys(gr, &x, &y, &s, eq, var,0, opt));	}
-	inline mglData FitS(const mglDataA &x, const mglDataA &y, const mglDataA &s, const char *eq, const char *var, mglData &ini, const char *opt="")
-	{	return mglData(true,mgl_fit_xys(gr, &x, &y, &s, eq, var, &ini, opt));	}
-	/// Fit data with dispersion s along x-, y-directions for each data slice. Return array with values for found formula.
-	inline mglData FitS(const mglDataA &x, const mglDataA &y, const mglDataA &z, const mglDataA &s, const char *eq, const char *var, const char *opt="")
-	{	return mglData(true,mgl_fit_xyzs(gr, &x, &y, &z, &s, eq, var,0, opt));	}
-	inline mglData FitS(const mglDataA &x, const mglDataA &y, const mglDataA &z, const mglDataA &s, const char *eq, const char *var, mglData &ini, const char *opt="")
-	{	return mglData(true,mgl_fit_xyzs(gr, &x, &y, &z, &s, eq, var, &ini, opt));	}
-	/// Fit data with dispersion s along all directions. Return array with values for found formula.
-	inline mglData FitS(const mglDataA &x, const mglDataA &y, const mglDataA &z, const mglDataA &a, const mglDataA &s, const char *eq, const char *var, const char *opt="")
-	{	return mglData(true,mgl_fit_xyzas(gr, &x, &y, &z, &a, &s, eq, var,0, opt));	}
-	inline mglData FitS(const mglDataA &x, const mglDataA &y, const mglDataA &z, const mglDataA &a, const mglDataA &s, const char *eq, const char *var, mglData &ini, const char *opt="")
-	{	return mglData(true,mgl_fit_xyzas(gr, &x, &y, &z, &a, &s, eq, var, &ini, opt));	}
-	/// Print fitted last formula (with coefficients)
-	inline void PutsFit(mglPoint p, const char *prefix=0, const char *font="", double size=-1)
-	{	mgl_puts_fit(gr, p.x, p.y, p.z, prefix, font, size);	}
-	/// Get last fitted formula
-	inline const char *GetFit()
-	{	return mgl_get_fit(gr);	}
-
-	/// Solve PDE with x,y,z in range [Min, Max]
-	inline mglData PDE(const char *ham, const mglDataA &ini_re, const mglDataA &ini_im, double dz=0.1, double k0=100, const char *opt="")
-	{	return mglData(true,mgl_pde_solve(gr,ham,&ini_re,&ini_im,dz,k0, opt));	}
-	/// Fill data by formula with x,y,z in range [Min, Max]
-	inline void Fill(mglData &u, const char *eq, const char *opt="")
-	{	mgl_data_fill_eq(gr, &u, eq, 0, 0, opt);	}
-	inline void Fill(mglData &u, const char *eq, const mglDataA &v, const char *opt="")
-	{	mgl_data_fill_eq(gr, &u, eq, &v, 0, opt);	}
-	inline void Fill(mglData &u, const char *eq, const mglDataA &v, const mglDataA &w, const char *opt="")
-	{	mgl_data_fill_eq(gr, &u, eq, &v, &w, opt);	}
-	/// Fill data by formula with x,y,z in range [Min, Max]
-	inline void Fill(mglDataC &u, const char *eq, const char *opt="")
-	{	mgl_datac_fill_eq(gr, &u, eq, 0, 0, opt);	}
-	inline void Fill(mglDataC &u, const char *eq, const mglDataA &v, const char *opt="")
-	{	mgl_datac_fill_eq(gr, &u, eq, &v, 0, opt);	}
-	inline void Fill(mglDataC &u, const char *eq, const mglDataA &v, const mglDataA &w, const char *opt="")
-	{	mgl_datac_fill_eq(gr, &u, eq, &v, &w, opt);	}
-	
-	/// Set the data by triangulated surface values assuming x,y,z in range [Min, Max]
-	inline void DataGrid(mglData &d, const mglDataA &x, const mglDataA &y, const mglDataA &z, const char *opt="")
-	{	mgl_data_grid(gr,&d,&x,&y,&z,opt);	}
-	
-	/// Make histogram (distribution) of data. This function do not plot data.
-	inline mglData Hist(const mglDataA &x, const mglDataA &a, const char *opt="")
-	{	return mglData(true, mgl_hist_x(gr, &x, &a, opt));	}
-	inline mglData Hist(const mglDataA &x, const mglDataA &y, const mglDataA &a, const char *opt="")
-	{	return mglData(true, mgl_hist_xy(gr, &x, &y, &a, opt));	}
-	inline mglData Hist(const mglDataA &x, const mglDataA &y, const mglDataA &z, const mglDataA &a, const char *opt="")
-	{	return mglData(true, mgl_hist_xyz(gr, &x, &y, &z, &a, opt));	}
-
-	inline void Compression(bool){}		// NOTE: Add later -- IDTF
-	/// Set the preference for vertex color on/off (for formats that support it, now only PRC does).
-	inline void VertexColor(bool enable)	{	mgl_set_flag(gr,enable, MGL_PREFERVC);	}
-	/// Render only front side of surfaces for dubugging purposes (for formats that support it, now only PRC does).
-	inline void DoubleSided(bool enable)	{	mgl_set_flag(gr,!enable, MGL_ONESIDED);	}
-//	inline void TextureColor(bool){}	// NOTE: Add later -- IDTF
-};
-//-----------------------------------------------------------------------------
-/// Structure for handling named mglData (used by mglParse class).
-class mglVar : public mglData
-{
-public:
-	std::wstring s;	///< Data name
-	void *o; 		///< Pointer to external object
-	mglVar *next;	///< Pointer to next instance in list
-	mglVar *prev;	///< Pointer to previous instance in list
-	bool temp;		///< This is temporary variable
-	void (*func)(void *);	///< Callback function for destroying
-	
-	mglVar():mglData()	{	o=0;	next=prev=0;	func=0;	temp=false;	}
-	virtual ~mglVar()
-	{
-		if(func)	func(o);
-		if(prev)	prev->next = next;
-		if(next)	next->prev = prev;
-	}
-	/// Move variable after var and copy func from var (if func is 0)
-	void MoveAfter(mglVar *var)
-	{
-		if(prev)	prev->next = next;
-		if(next)	next->prev = prev;
-		prev = next = 0;
-		if(var)
-		{
-			prev = var;	next = var->next;
-			var->next = this;
-			if(func==0)	func = var->func;
-		}
-		if(next)	next->prev = this;
-	}
-};
-//-----------------------------------------------------------------------------
-/// Wrapper class for MGL parsing
-class mglParse
-{
-	HMPR pr;
-public:
-	mglParse(HMPR p)		{	pr = p;		mgl_use_parser(pr,1);	}
-	mglParse(mglParse &p)	{	pr = p.pr;	mgl_use_parser(pr,1);	}
-	mglParse(bool setsize=false)
-	{	pr=mgl_create_parser();	mgl_parser_allow_setsize(pr, setsize);	}
-	~mglParse()	{	if(mgl_use_parser(pr,-1)<1)	mgl_delete_parser(pr);	}
-	/// Get pointer to internal mglParser object
-	inline HMPR Self()	{	return pr;	}
-	/// Parse and draw single line of the MGL script
-	inline int Parse(mglGraph *gr, const char *str, int pos)
-	{	return mgl_parse_line(gr->Self(), pr, str, pos);	}
-	inline int Parse(mglGraph *gr, const wchar_t *str, int pos)
-	{	return mgl_parse_linew(gr->Self(), pr, str, pos);	}
-	/// Execute MGL script text with '\n' separated lines
-	inline void Execute(mglGraph *gr, const char *str)
-	{	mgl_parse_text(gr->Self(), pr, str);	}
-	inline void Execute(mglGraph *gr, const wchar_t *str)
-	{	mgl_parse_textw(gr->Self(), pr, str);	}
-	/// Execute and draw script from the file
-	inline void Execute(mglGraph *gr, FILE *fp, bool print=false)
-	{	mgl_parse_file(gr->Self(), pr, fp, print);	}
-
-	/// Return type of command: 0 - not found, 1 - data plot, 2 - other plot,
-	///		3 - setup, 4 - data handle, 5 - data create, 6 - subplot, 7 - program
-	///		8 - 1d plot, 9 - 2d plot, 10 - 3d plot, 11 - dd plot, 12 - vector plot
-	///		13 - axis, 14 - primitives, 15 - axis setup, 16 - text/legend, 17 - data transform
-	inline int CmdType(const char *name)
-	{	return mgl_parser_cmd_type(pr, name);	}
-	/// Return string of command format (command name and its argument[s])
-	inline const char *CmdFormat(const char *name)
-	{	return mgl_parser_cmd_frmt(pr, name);	}
-	/// Return description of MGL command
-	inline const char *CmdDesc(const char *name)
-	{	return mgl_parser_cmd_desc(pr, name);	}
-	/// Get name of command with nmber n
-	inline const char *GetCmdName(long n)
-	{	return mgl_parser_cmd_name(pr,n);	}
-	/// Get number of defined commands
-	inline long GetCmdNum()
-	{	return mgl_parser_cmd_num(pr);	}
-
-	/// Set value for parameter $N
-	inline void AddParam(int id, const char *str)
-	{	mgl_parser_add_param(pr, id, str);	}
-	inline void AddParam(int id, const wchar_t *str)
-	{	mgl_parser_add_paramw(pr, id, str);	}
-	/// Restore once flag
-	inline void RestoreOnce()	{	mgl_parser_restore_once(pr);	}
-	/// Allow changing size of the picture
-	inline void AllowSetSize(bool allow)	{	mgl_parser_allow_setsize(pr, allow);	}
-	/// Allow reading/saving files
-	inline void AllowFileIO(bool allow)		{	mgl_parser_allow_file_io(pr, allow);	}
-	/// Set flag to stop script parsing
-	inline void Stop()	{	mgl_parser_stop(pr);	}
-
-	/// Return result of formula evaluation
-	inline mglData Calc(const char *formula)
-	{	return mglData(true,mgl_parser_calc(pr,formula)); 	}
-	inline mglData Calc(const wchar_t *formula)
-	{	return mglData(true,mgl_parser_calcw(pr,formula));	}
-	
-	/// Find variable with given name or add a new one
-	/// NOTE !!! You must not delete obtained data arrays !!!
-	inline mglVar *AddVar(const char *name)
-	{	return dynamic_cast<mglVar *>(mgl_parser_add_var(pr, name));	}
-	inline mglVar *AddVar(const wchar_t *name)
-	{	return dynamic_cast<mglVar *>(mgl_parser_add_varw(pr, name));	}
-	/// Find variable with given name or return NULL if no one
-	/// NOTE !!! You must not delete obtained data arrays !!!
-	inline mglVar *FindVar(const char *name)
-	{	return dynamic_cast<mglVar *>(mgl_parser_find_var(pr, name));	}
-	inline mglVar *FindVar(const wchar_t *name)
-	{	return dynamic_cast<mglVar *>(mgl_parser_find_varw(pr, name));	}
-	/// Delete variable with name
-	inline void DeleteVar(const char *name)		{	mgl_parser_del_var(pr, name);		}
-	inline void DeleteVar(const wchar_t *name)	{	mgl_parser_del_varw(pr, name);		}
-	/// Delete all data variables
-	void DeleteAll()	{	mgl_parser_del_all(pr);	}
-};
-//-----------------------------------------------------------------------------
-/// Wrapper class expression evaluating
-class mglExpr
-{
-	HMEX ex;
-public:
-	mglExpr(const char *expr)		{	ex = mgl_create_expr(expr);	}
-	~mglExpr()	{	mgl_delete_expr(ex);	}
-	/// Return value of expression for given x,y,z variables
-	inline double Eval(double x, double y=0, double z=0)
-	{	return mgl_expr_eval(ex,x,y,z);	}
-	/// Return value of expression differentiation over variable dir for given x,y,z variables
-	inline double Diff(char dir, double x, double y=0, double z=0)
-	{	return mgl_expr_diff(ex,dir, x,y,z);	}
-#ifndef SWIG
-	/// Return value of expression for given variables
-	inline double Eval(mreal var[26])
-	{	return mgl_expr_eval_v(ex,var);	}
-	/// Return value of expression differentiation over variable dir for given variables
-	inline double Diff(char dir, mreal var[26])
-	{	return mgl_expr_diff_v(ex,dir, var);	}
-#endif
-};
-//-----------------------------------------------------------------------------
-/// Wrapper class expression evaluating
-class mglExprC
-{
-	HAEX ex;
-public:
-	mglExprC(const char *expr)		{	ex = mgl_create_cexpr(expr);	}
-	~mglExprC()	{	mgl_delete_cexpr(ex);	}
-	/// Return value of expression for given x,y,z variables
-	inline dual Eval(dual x, dual y=0, dual z=0)
-	{	return mgl_cexpr_eval(ex,x,y,z);	}
-	/// Return value of expression for given x,y,z,u,v,w variables
-	inline dual Eval(dual x, dual y, dual z, dual u, dual v, dual w)
-	{
-		dual var[26];
-		var['x'-'a']=x;	var['y'-'a']=y;	var['z'-'a']=z;
-		var['u'-'a']=u;	var['v'-'a']=v;	var['w'-'a']=w;
-		return mgl_cexpr_eval_v(ex,var);	}
-#ifndef SWIG
-	/// Return value of expression for given variables
-	inline dual Eval(dual var[26])
-	{	return mgl_cexpr_eval_v(ex,var);	}
-#endif
-};
-//-----------------------------------------------------------------------------
-#endif
+/***************************************************************************
+ * mgl.h is part of Math Graphic Library
+ * Copyright (C) 2007-2012 Alexey Balakin <mathgl.abalakin at gmail.ru>       *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+//-----------------------------------------------------------------------------
+/// Wrapper class for all graphics
+class mglGraph
+{
+protected:
+	HMGL gr;
+public:
+	inline mglGraph(int kind=0, int width=600, int height=400)
+	{
+		if(kind==-1)	gr=NULL;
+#if MGL_HAVE_OPENGL
+		else if(kind==1)	gr=mgl_create_graph_gl();
+#else
+		else if(kind==1)
+		{	gr=mgl_create_graph(width, height);
+			mglGlobalMess += "OpenGL support was disabled. Please, enable it and rebuild MathGL.\n";	}
+#endif
+		else	gr=mgl_create_graph(width, height);
+	}
+	inline mglGraph(const mglGraph &graph)
+	{	gr = graph.gr;	mgl_use_graph(gr,1);	}
+	inline mglGraph(HMGL graph)
+	{	gr = graph;		mgl_use_graph(gr,1);	}
+	virtual ~mglGraph()
+	{	if(mgl_use_graph(gr,-1)<1)	mgl_delete_graph(gr);	}
+	/// Get pointer to internal mglCanvas object
+	inline HMGL Self()	{	return gr;	}
+	/// Set default parameters for plotting
+	inline void DefaultPlotParam()			{	mgl_set_def_param(gr);	}
+	/// Set name of plot for saving filename
+	inline void SetPlotId(const char *id)	{	mgl_set_plotid(gr,id);	}
+	/// Get name of plot for saving filename
+	inline const char *GetPlotId()	{	return mgl_get_plotid(gr);	}
+
+	/// Set the transparency on/off.
+	inline void Alpha(bool enable)			{	mgl_set_alpha(gr, enable);	}
+	/// Set default value of alpha-channel
+	inline void SetAlphaDef(double alpha)	{	mgl_set_alpha_default(gr, alpha);	}
+	/// Set the transparency type (0 - usual, 1 - glass, 2 - lamp)
+	inline void SetTranspType(int type)		{	mgl_set_transp_type(gr, type);	}
+
+	/// Set the using of light on/off.
+	inline void Light(bool enable)			{	mgl_set_light(gr, enable);	}
+	/// Switch on/off the specified light source.
+	inline void Light(int n,bool enable)	{	mgl_set_light_n(gr, n, enable);	}
+	/// Use diffusive light (only for local light sources) -- OBSOLETE
+	inline void SetDifLight(bool dif)		{	mgl_set_light_dif(gr, dif);	}
+	/// Add a light source.
+	inline void AddLight(int n, mglPoint p, char col='w', double bright=0.5, double ap=0)
+	{	mgl_add_light_ext(gr, n, p.x, p.y, p.z, col, bright, ap);	}
+	inline void AddLight(int n, mglPoint r, mglPoint p, char col='w', double bright=0.5, double ap=0)
+	{	mgl_add_light_loc(gr, n, r.x, r.y, r.z, p.x, p.y, p.z, col, bright, ap);	}
+	/// Set ambient light brightness
+	inline void SetAmbient(double i)			{	mgl_set_ambbr(gr, i);	}
+	/// Set diffusive light brightness
+	inline void SetDiffuse(double i)			{	mgl_set_difbr(gr, i);	}
+	/// Set the fog distance or switch it off (if d=0).
+	inline void Fog(double d, double dz=0.25)	{	mgl_set_fog(gr, d, dz);		}
+
+	/// Set relative width of rectangles in Bars, Barh, BoxPlot
+	inline void SetBarWidth(double width)	{	mgl_set_bar_width(gr, width);	}
+	/// Set default size of marks (locally you can use "size" option)
+	inline void SetMarkSize(double size)		{	mgl_set_mark_size(gr, size);	}
+	/// Set default size of arrows (locally you can use "size" option)
+	inline void SetArrowSize(double size)	{	mgl_set_arrow_size(gr, size);	}
+	/// Set number of mesh lines (use 0 to draw all of them)
+	inline void SetMeshNum(int num)			{	mgl_set_meshnum(gr, num);	}
+	/// Set number of visible faces (use 0 to draw all of them)
+	inline void SetFaceNum(int num)			{	mgl_set_facenum(gr, num);	}
+
+	/// Set cutting for points outside of bounding box
+	inline void SetCut(bool cut)				{	mgl_set_cut(gr, cut);	}
+	/// Set additional cutting box
+	inline void SetCutBox(mglPoint p1, mglPoint p2)
+	{	mgl_set_cut_box(gr, p1.x, p1.y, p1.z, p2.x, p2.y, p2.z);	}
+	/// Set the cutting off condition (formula)
+	inline void CutOff(const char *EqC)		{	mgl_set_cutoff(gr, EqC);	}
+
+	/// Set default font size
+	inline void SetFontSize(double size)		{	mgl_set_font_size(gr, size);	}
+	/// Set default font style and color
+	inline void SetFontDef(const char *fnt)		{	mgl_set_font_def(gr, fnt);	}
+	/// Set FontSize by size in pt and picture DPI (default is 16 pt for dpi=72)
+	virtual void SetFontSizePT(double pt, int dpi=72){	SetFontSize(pt*27.f/dpi);	}
+	/// Set FontSize by size in centimeters and picture DPI (default is 0.56 cm = 16 pt)
+	inline void SetFontSizeCM(double cm, int dpi=72)	{	SetFontSizePT(cm*28.45f,dpi);	}
+	/// Set FontSize by size in inch and picture DPI (default is 0.22 in = 16 pt)
+	inline void SetFontSizeIN(double in, int dpi=72)	{	SetFontSizePT(in*72.27f,dpi);	}
+	/// Load font from file
+	inline void LoadFont(const char *name, const char *path=NULL)
+	{	mgl_load_font(gr, name, path);	}
+	/// Copy font from another mglGraph instance
+	inline void CopyFont(const mglGraph *GR)	{	mgl_copy_font(gr, GR->gr);}
+	/// Restore font (load default font for new HMGL objects)
+	inline void RestoreFont()				{	mgl_restore_font(gr);	}
+	/// Set to use or not text rotation
+	inline void SetRotatedText(bool rotated)	{	mgl_set_rotated_text(gr, rotated);	}
+
+	/// Set default palette
+	inline void SetPalette(const char *colors)	{	mgl_set_palette(gr, colors);	}
+	/// Set default color scheme
+	inline void SetDefScheme(const char *sch)	{	mgl_set_def_sch(gr, sch);	}
+
+	/// Sets RGB values for color with given id
+	static inline void SetColor(char id, double r, double g, double b)	{	mgl_set_color(id, r, g, b);	}
+	/// Set mask for face coloring as array of type 'unsigned char[8]'
+	static inline void SetMask(char id, const char *mask)	{	mgl_set_mask(id, mask);	}
+	/// Set mask for face coloring as uint64_t number
+	static inline void SetMask(char id, uint64_t mask)	{	mgl_set_mask_val(id, mask);	}
+	/// Set default mask rotation angle
+	inline void SetMaskAngle(int angle)	{	mgl_set_mask_angle(gr, angle);	}
+
+	/// Get last warning code
+	inline int  GetWarn()	{	return mgl_get_warn(gr);}
+	/// Set warning code ant fill message
+	inline void SetWarn(int code, const char *info)	{	mgl_set_warn(gr,code,info);	}
+	/// Set buffer for warning messages
+	inline const char *Message()	{	return mgl_get_mess(gr);	}
+
+	/// Set axis range scaling -- simplified way to shift/zoom axis range -- need to replot whole image!
+	inline void ZoomAxis(mglPoint p1=mglPoint(0,0,0,0), mglPoint p2=mglPoint(1,1,1,1))
+	{	mgl_zoom_axis(gr, p1.x,p1.y,p1.z,p1.c, p2.x,p2.y,p2.z,p2.c);	}
+	/// Set range in direction dir as [v1, v2]
+	inline void SetRange(char dir, double v1, double v2)
+	{	mgl_set_range_val(gr, dir, v1, v2);	}
+	/// Set range in direction dir as minimal and maximal values of data a
+	inline void SetRange(char dir, const mglData &dat, bool add=false)
+	{	mgl_set_range_dat(gr, dir, &dat, add);	}
+	/// Set values of axis range as minimal and maximal values of datas
+	inline void SetRanges(const mglData &xx, const mglData &yy, const mglData &zz, const mglData &cc)
+	{	mgl_set_range_dat(gr,'x',&xx,0);	mgl_set_range_dat(gr,'y',&yy,0);
+		mgl_set_range_dat(gr,'z',&zz,0);	mgl_set_range_dat(gr,'c',&cc,0);	}
+	/// Set values of axis range as minimal and maximal values of datas
+	inline void SetRanges(const mglData &xx, const mglData &yy, const mglData &zz)
+	{	mgl_set_range_dat(gr,'x',&xx,0);	mgl_set_range_dat(gr,'y',&yy,0);
+		mgl_set_range_dat(gr,'z',&zz,0);	mgl_set_range_dat(gr,'c',&zz,0);	}
+	/// Set values of axis range as minimal and maximal values of datas
+	inline void SetRanges(const mglData &xx, const mglData &yy)
+	{	mgl_set_range_dat(gr,'x',&xx,0);	mgl_set_range_dat(gr,'y',&yy,0);	}
+	/// Set values of axis ranges
+	inline void SetRanges(double x1, double x2, double y1, double y2, double z1=0, double z2=0)
+	{	mgl_set_ranges(gr, x1, x2, y1, y2, z1, z2);	}
+	/// Set values of axis ranges
+	inline void SetRanges(mglPoint p1, mglPoint p2)
+	{	mgl_set_ranges(gr, p1.x, p2.x, p1.y, p2.y, p1.z, p2.z);	}
+	/// Set ranges for automatic variables
+	inline void SetAutoRanges(double x1, double x2, double y1=0, double y2=0, double z1=0, double z2=0, double c1=0, double c2=0)
+	{	mgl_set_auto_ranges(gr, x1, x2, y1, y2, z1, z2, c1, c2);	}
+	/// Set ranges for automatic variables
+	inline void SetAutoRanges(mglPoint p1, mglPoint p2)
+	{	mgl_set_auto_ranges(gr, p1.x, p2.x, p1.y, p2.y, p1.z, p2.z, p1.c, p2.c);	}
+	/// Set axis origin
+	inline void SetOrigin(mglPoint p)
+	{	mgl_set_origin(gr, p.x, p.y, p.z);	}
+	inline void SetOrigin(double x0, double y0, double z0=NaN)
+	{	mgl_set_origin(gr, x0, y0, z0);	}
+
+	/// Set the transformation formulas for coordinate
+	inline void SetFunc(const char *EqX, const char *EqY, const char *EqZ=NULL, const char *EqA=NULL)
+	{	mgl_set_func(gr, EqX, EqY, EqZ, EqA);	}
+	/// Set one of predefined transformation rule
+	inline void SetCoor(int how)		{	mgl_set_coor(gr, how);	}
+	/// Set to draw Ternary axis (triangle like axis, grid and so on)
+	inline void Ternary(int val)		{	mgl_set_ternary(gr, val);	}
+
+	/// Set to use or not tick labels rotation
+	inline void SetTickRotate(bool val)	{	mgl_set_tick_rotate(gr,val);	}
+	/// Set to use or not tick labels skipping
+	inline void SetTickSkip(bool val)	{	mgl_set_tick_skip(gr,val);	}
+	/// Set tick length
+	inline void SetTickLen(double len, double stt=1)
+	{	mgl_set_tick_len(gr, len, stt);	}
+	/// Set axis and ticks style
+	inline void SetAxisStl(const char *stl="k", const char *tck=0, const char *sub=0)
+	{	mgl_set_axis_stl(gr, stl, tck, sub);	}
+
+	/// Set time templates for ticks
+	inline void SetTicksTime(char dir, double d=0, const char *t="")
+	{	mgl_set_ticks_time(gr,dir,d,t);	}
+	/// Set ticks text (\n separated). Use "" to disable this feature.
+	inline void SetTicksVal(char dir, const char *lbl, bool add=false)
+	{	mgl_set_ticks_str(gr,dir,lbl,add);	}
+	inline void SetTicksVal(char dir, const wchar_t *lbl, bool add=false)
+	{	mgl_set_ticks_wcs(gr,dir,lbl,add);	}
+	/// Set ticks position and text (\n separated). Use "" to disable this feature.
+	inline void SetTicksVal(char dir, const mglData &v, const char *lbl, bool add=false)
+	{	mgl_set_ticks_val(gr,dir,&v,lbl,add);	}
+	inline void SetTicksVal(char dir, const mglData &v, const wchar_t *lbl, bool add=false)
+	{	mgl_set_ticks_valw(gr,dir,&v,lbl,add);	}
+	/// Set the ticks parameters
+	inline void SetTicks(char dir, double d=0, int ns=0, double org=NaN)
+	{	mgl_set_ticks(gr, dir, d, ns, org);	}
+	/// Auto adjust ticks
+	inline void Adjust(const char *dir="xyzc")
+	{	mgl_adjust_ticks(gr, dir);	}
+	/// Set templates for ticks
+	inline void SetTickTempl(char dir, const char *t)
+	{	mgl_set_tick_templ(gr,dir,t);	}
+	inline void SetTickTempl(char dir, const wchar_t *t)
+	{	mgl_set_tick_templw(gr,dir,t);	}
+	/// Tune ticks
+	inline void SetTuneTicks(int tune, double fact_pos=1.15)
+	{	mgl_tune_ticks(gr, tune, fact_pos);	}
+	/// Set additional shift of tick labels
+	inline void SetTickShift(mglPoint p)
+	{	mgl_set_tick_shift(gr,p.x,p.y,p.z,p.c);	}
+	/// Set to use UTC time instead of local time
+	inline void SetTimeUTC(bool enable)
+	{	mgl_set_flag(gr,enable, MGL_USE_GMTIME);	}
+	/// Set to draw tick labels at axis origin
+	inline void SetOriginTick(bool enable=true)
+	{	mgl_set_flag(gr,!enable, MGL_NO_ORIGIN);	}
+
+	/// Put further plotting in some region of whole frame.
+	inline void SubPlot(int nx,int ny,int m,const char *style="<>_^", double dx=0, double dy=0)
+	{	mgl_subplot_d(gr, nx, ny, m, style, dx, dy);	}
+	/// Like SubPlot() but "join" several cells
+	inline void MultiPlot(int nx,int ny,int m, int dx, int dy, const char *style="<>_^")
+	{	mgl_multiplot(gr, nx, ny, m, dx, dy, style);	}
+	/// Put further plotting in a region of whole frame.
+	inline void InPlot(double x1,double x2,double y1,double y2, bool rel=true)
+	{	if(rel)	mgl_relplot(gr, x1, x2, y1, y2);
+		else	mgl_inplot(gr, x1, x2, y1, y2);	}
+	/// Put further plotting in column cell of previous subplot
+	inline void ColumnPlot(int num, int ind, double d=0)
+	{	mgl_columnplot(gr,num,ind,d);	}
+	/// Put further plotting in matrix cell of previous subplot
+	inline void GridPlot(int nx, int ny, int ind, double d=0)
+	{	mgl_gridplot(gr,nx,ny,ind,d);	}
+	/// Put further plotting in cell of stick rotated on angles tet, phi
+	inline void StickPlot(int num, int i, double tet, double phi)
+	{	mgl_stickplot(gr,num,i,tet,phi);	}
+
+	/// Set factor of plot size
+	inline void SetPlotFactor(double val)
+	{	mgl_set_plotfactor(gr,val);	}
+	/// Push transformation matrix into stack
+	inline void Push()	{	mgl_mat_push(gr);	}
+	/// Pop transformation matrix from stack
+	inline void Pop()	{	mgl_mat_pop(gr);	}
+
+	/// Add title for current subplot/inplot
+	inline 	void Title(const char *title,const char *stl="",double size=-2)
+	{	mgl_title(gr,title,stl,size);	}
+	inline 	void Title(const wchar_t *title,const char *stl="",double size=-2)
+	{	mgl_titlew(gr,title,stl,size);	}
+	/// Set aspect ratio for further plotting.
+	inline void Aspect(double Ax,double Ay,double Az=1)
+	{	mgl_aspect(gr, Ax, Ay, Az);		}
+	/// Rotate a further plotting.
+	inline void Rotate(double TetX,double TetZ=0,double TetY=0)
+	{	mgl_rotate(gr, TetX, TetZ, TetY);	}
+	/// Rotate a further plotting around vector {x,y,z}.
+	inline void RotateN(double Tet,double x,double y,double z)
+	{	mgl_rotate_vector(gr, Tet, x, y, z);	}
+	/// Set perspective (in range [0,1)) for plot. Set to zero for switching off.
+	inline void Perspective(double val)
+	{	mgl_perspective(gr, val);	}
+	/// Set angle of view independently from Rotate().
+	inline void View(double TetX,double TetZ=0,double TetY=0)
+	{	mgl_view(gr, TetX, TetZ, TetY);	}
+	/// Zoom in/out a part of picture (use Zoom(0, 0, 1, 1) for restore default)
+	inline void Zoom(double x1, double y1, double x2, double y2)
+	{	mgl_zoom(gr, x1, y1, x2, y2);	}
+
+	/// Set size of frame in pixels. Normally this function is called internally.
+	inline void SetSize(int width, int height)	{	mgl_set_size(gr, width, height);	}
+	/// Set plot quality
+	inline void SetQuality(int qual=MGL_DRAW_NORM)	{	mgl_set_quality(gr, qual);	}
+	/// Get plot quality
+	inline int GetQuality()	{	return mgl_get_quality(gr);	}
+	/// Set drawing region for Quality&4
+	inline void SetDrawReg(long nx, long ny, long m){	mgl_set_draw_reg(gr,nx,ny,m);	}
+	/// Start group of objects
+	inline void StartGroup(const char *name)		{	mgl_start_group(gr, name);	}
+	/// End group of objects
+	inline void EndGroup()	{	mgl_end_group(gr);	}
+	/// Highlight objects with given id
+	inline void Highlight(int id)	{	mgl_highlight(gr, id);	}
+
+	/// Show current image
+	inline void ShowImage(const char *viewer, bool keep=0)
+	{	mgl_show_image(gr, viewer, keep);	}
+	/// Write the frame in file (depending extension, write current frame if fname is empty)
+	inline void WriteFrame(const char *fname=0,const char *descr="")
+	{	mgl_write_frame(gr, fname, descr);	}
+	/// Write the frame in file using JPEG format
+	inline void WriteJPEG(const char *fname,const char *descr="")
+	{	mgl_write_jpg(gr, fname, descr);	}
+	/// Write the frame in file using PNG format with transparency
+	inline void WritePNG(const char *fname,const char *descr="", bool alpha=true)
+	{	if(alpha)	mgl_write_png(gr, fname, descr);
+		else	mgl_write_png_solid(gr, fname, descr);	}
+	/// Write the frame in file using BMP format
+	inline void WriteBMP(const char *fname,const char *descr="")
+	{	mgl_write_bmp(gr, fname, descr);	}
+	/// Write the frame in file using BMP format
+	inline void WriteTGA(const char *fname,const char *descr="")
+	{	mgl_write_tga(gr, fname, descr);	}
+	/// Write the frame in file using PostScript format
+	inline void WriteEPS(const char *fname,const char *descr="")
+	{	mgl_write_eps(gr, fname, descr);	}
+	/// Write the frame in file using LaTeX format
+	inline void WriteTEX(const char *fname,const char *descr="")
+	{	mgl_write_tex(gr, fname, descr);	}
+	/// Write the frame in file using PostScript format as bitmap
+	inline void WriteBPS(const char *fname,const char *descr="")
+	{	mgl_write_bps(gr, fname, descr);	}
+	/// Write the frame in file using SVG format
+	inline void WriteSVG(const char *fname,const char *descr="")
+	{	mgl_write_svg(gr, fname, descr);	}
+	/// Write the frame in file using GIF format (only for current frame!)
+	inline void WriteGIF(const char *fname,const char *descr="")
+	{	mgl_write_gif(gr, fname, descr);	}
+
+	/// Write the frame in file using OBJ format
+	inline void WriteOBJ(const char *fname,const char *descr="",bool use_png=true)
+	{	mgl_write_obj(gr, fname, descr, use_png);	}
+	/// Write the frame in file using OBJ format - Balakin way
+	inline void WriteOBJold(const char *fname,const char *descr="",bool use_png=true)
+	{	mgl_write_obj_old(gr, fname, descr, use_png);	}
+	/// Write the frame in file using XYZ format
+	inline void WriteXYZ(const char *fname,const char *descr="")
+	{	mgl_write_xyz(gr, fname, descr);	}
+	/// Write the frame in file using STL format (faces only)
+	inline void WriteSTL(const char *fname,const char *descr="")
+	{	mgl_write_stl(gr, fname, descr);	}
+	/// Write the frame in file using OFF format
+	inline void WriteOFF(const char *fname,const char *descr="", bool colored=false)
+	{	mgl_write_off(gr, fname, descr,colored);	}
+//	/// Write the frame in file using X3D format
+//	inline void WriteX3D(const char *fname,const char *descr="")
+//	{	mgl_write_x3d(gr, fname, descr);	}
+	/// Write the frame in file using PRC format
+	inline void WritePRC(const char *fname,const char *descr="",bool make_pdf=true)
+	{	mgl_write_prc(gr, fname, descr, make_pdf);	}
+	/// Export in JSON format suitable for later drawing by JavaScript
+	inline void WriteJSON(const char *fname,const char *descr="",bool force_z=false)
+	{	if(force_z)	mgl_write_json_z(gr, fname, descr);
+		else 	mgl_write_json(gr, fname, descr);	}
+	/// Return string of JSON data suitable for later drawing by JavaScript
+	inline const char *GetJSON()	{	return mgl_get_json(gr);	}
+
+	/// Force preparing the image. It can be useful for OpenGL mode mostly.
+	inline void Finish()			{	mgl_finish(gr);	}
+	/// Create new frame.
+	inline void NewFrame()		{	mgl_new_frame(gr);	}
+	/// Finish frame drawing
+	inline void EndFrame()		{	mgl_end_frame(gr);	}
+	/// Get the number of created frames
+	inline int GetNumFrame()	{	return mgl_get_num_frame(gr);	}
+	/// Reset frames counter (start it from zero)
+	inline void ResetFrames()	{	mgl_reset_frames(gr);	}
+	/// Delete primitives for i-th frame (work if MGL_VECT_FRAME is set on)
+	inline void DelFrame(int i)	{	mgl_del_frame(gr, i);	}
+	/// Get drawing data for i-th frame (work if MGL_VECT_FRAME is set on)
+	inline void GetFrame(int i)	{	mgl_get_frame(gr, i);	}
+	/// Set drawing data for i-th frame (work if MGL_VECT_FRAME is set on). Work as EndFrame() but don't add frame to GIF image.
+	inline void SetFrame(int i)	{	mgl_set_frame(gr, i);	}
+	/// Append drawing data from i-th frame (work if MGL_VECT_FRAME is set on)
+	inline void ShowFrame(int i){	mgl_show_frame(gr, i);	}
+
+	/// Start write frames to cinema using GIF format
+	inline void StartGIF(const char *fname, int ms=100)
+	{	mgl_start_gif(gr, fname,ms);	}
+	/// Stop writing cinema using GIF format
+	inline void CloseGIF()		{	mgl_close_gif(gr);	}
+	/// Export points and primitives in file using MGLD format
+	inline void ExportMGLD(const char *fname, const char *descr=0)
+	{	mgl_export_mgld(gr, fname, descr);	}
+	/// Import points and primitives from file using MGLD format
+	inline void ImportMGLD(const char *fname, bool add=false)
+	{	mgl_import_mgld(gr, fname, add);	}
+
+	/// Copy RGB values into array which is allocated by user
+	inline void GetRGB(char *imgdata, int imglen)
+	{
+		long w=mgl_get_width(gr), h=mgl_get_height(gr);
+		if(imglen>=3*w*h)	memcpy(imgdata, mgl_get_rgb(gr),3*w*h);
+	}
+	inline const unsigned char *GetRGB()		{	return mgl_get_rgb(gr);	}
+	/// Copy RGBA values into array which is allocated by user
+	inline void GetRGBA(char *imgdata, int imglen)
+	{
+		long w=mgl_get_width(gr), h=mgl_get_height(gr);
+		if(imglen>=4*w*h)	memcpy(imgdata, mgl_get_rgba(gr),4*w*h);
+	}
+	inline const unsigned char *GetRGBA()	{	return mgl_get_rgba(gr);	}
+	/// Copy BGRN values into array which is allocated by user
+	inline void GetBGRN(unsigned char *imgdata, int imglen)
+	{
+		long w=mgl_get_width(gr), h=mgl_get_height(gr), i;
+		const unsigned char *buf=mgl_get_rgb(gr);
+		if(imglen>=4*w*h)	for(i=0;i<w*h;i++)
+		{
+			imgdata[4*i]   = buf[3*i+2];
+			imgdata[4*i+1] = buf[3*i+1];
+			imgdata[4*i+2] = buf[3*i];
+			imgdata[4*i+3] = 255;
+		}
+	}
+	/// Get width of the image
+	inline int GetWidth()	{	return mgl_get_width(gr);	}
+	/// Get height of the image
+	inline int GetHeight()	{	return mgl_get_height(gr);}
+	/// Calculate 3D coordinate {x,y,z} for screen point {xs,ys}
+	inline mglPoint CalcXYZ(int xs, int ys)
+	{
+		mreal x,y,z;
+		mgl_calc_xyz(gr,xs,ys,&x,&y,&z);
+		return mglPoint(x,y,z);
+	}
+	/// Calculate screen point {xs,ys} for 3D coordinate {x,y,z}
+	inline mglPoint CalcScr(mglPoint p)
+	{
+		int xs,ys;
+		mgl_calc_scr(gr,p.x,p.y,p.z,&xs,&ys);
+		return mglPoint(xs,ys);
+	}
+	/// Set object/subplot id
+	inline void SetObjId(int id)		{	mgl_set_obj_id(gr,id);	}
+	/// Get object id
+	inline int GetObjId(long x,long y)	{	return mgl_get_obj_id(gr,x,y);	}
+	/// Get subplot id
+	inline int GetSplId(long x,long y)	{	return mgl_get_spl_id(gr,x,y);	}
+	/// Check if {\a xs,\a ys} is close to active point with accuracy d, and return its position or -1
+	inline long IsActive(int xs, int ys, int d=1)	{	return mgl_is_active(gr,xs,ys,d);	}
+
+	/// Combine plots from 2 canvases. Result will be saved into this
+	inline void Combine(const mglGraph *g)	{	mgl_combine_gr(gr,g->gr);	}
+
+	/// Clear up the frame
+	inline void Clf(double r, double g, double b)	{	mgl_clf_rgb(gr, r, g, b);	}
+	inline void Clf(char col)	{	mgl_clf_chr(gr, col);	}
+	inline void Clf()	{	mgl_clf(gr);	}
+	/// Clear unused points and primitives. Useful only in combination with SetFaceNum().
+	inline void ClearUnused()	{	mgl_clear_unused(gr);	}
+	/// Draws the point (ball) at position {x,y,z} with color c
+	inline void Ball(mglPoint p, char c='r')
+	{	char s[3]={'.',c,0};	mgl_mark(gr, p.x, p.y, p.z, s);	}
+	/// Draws the mark at position p
+	inline void Mark(mglPoint p, const char *mark)
+	{	mgl_mark(gr, p.x, p.y, p.z, mark);	}
+	/// Draws the line between points by specified pen
+	inline void Line(mglPoint p1, mglPoint p2, const char *pen="B",int n=2)
+	{	mgl_line(gr, p1.x, p1.y, p1.z, p2.x, p2.y, p2.z, pen, n);	}
+	/// Draws the spline curve between points by specified pen
+	inline void Curve(mglPoint p1, mglPoint d1, mglPoint p2, mglPoint d2, const char *pen="B", int n=100)
+	{	mgl_curve(gr, p1.x, p1.y, p1.z, d1.x, d1.y, d1.z, p2.x, p2.y, p2.z, d2.x, d2.y, d2.z, pen, n);	}
+	/// Draws the 3d error box e for point p
+	inline void Error(mglPoint p, mglPoint e, const char *pen="k")
+	{	mgl_error_box(gr, p.x, p.y, p.z, e.x, e.y, e.z, pen);	}
+
+	/// Draws the face between points with color stl (include interpolation up to 4 colors).
+	inline void Face(mglPoint p1, mglPoint p2, mglPoint p3, mglPoint p4, const char *stl="r")
+	{	mgl_face(gr, p1.x, p1.y, p1.z, p2.x, p2.y, p2.z, p3.x, p3.y, p3.z, p4.x, p4.y, p4.z, stl);	}
+	/// Draws the face in y-z plane at point p with color stl (include interpolation up to 4 colors).
+	inline void FaceX(mglPoint p, double wy, double wz, const char *stl="w", double dx=0, double dy=0)
+	{	mgl_facex(gr, p.x, p.y, p.z, wy, wz, stl, dx, dy);	}
+	/// Draws the face in x-z plane at point p with color stl (include interpolation up to 4 colors).
+	inline void FaceY(mglPoint p, double wx, double wz, const char *stl="w", double dx=0, double dy=0)
+	{	mgl_facey(gr, p.x, p.y, p.z, wx, wz, stl, dx, dy);	}
+	/// Draws the face in x-y plane at point p with color stl (include interpolation up to 4 colors).
+	inline void FaceZ(mglPoint p, double wx, double wy, const char *stl="w", double dx=0, double dy=0)
+	{	mgl_facez(gr, p.x, p.y, p.z, wx, wy, stl, dx, dy);	}
+	/// Draws the drop at point p in direction d with color col and radius r
+	inline void Drop(mglPoint p, mglPoint d, double r, const char *col="r", double shift=1, double ap=1)
+	{	mgl_drop(gr, p.x, p.y, p.z, d.x, d.y, d.z, r, col, shift, ap);	}
+	/// Draws the sphere at point p with color col and radius r
+	inline void Sphere(mglPoint p, double r, const char *col="r")
+	{	mgl_sphere(gr, p.x, p.y, p.z, r, col);	}
+	/// Draws the cone between points p1,p2 with radius r1,r2 and with style stl
+	inline void Cone(mglPoint p1, mglPoint p2, double r1, double r2=-1, const char *stl="r@")
+	{	mgl_cone(gr, p1.x, p1.y, p1.z, p2.x, p2.y, p2.z,r1,r2,stl);	}
+	/// Draws the ellipse between points p1,p2 with color stl and width r
+	inline void Ellipse(mglPoint p1, mglPoint p2, double r, const char *stl="r")
+	{	mgl_ellipse(gr, p1.x, p1.y, p1.z, p2.x, p2.y, p2.z, r,stl);	}
+	/// Draws the circle at point p with color stl and radius r
+	inline void Circle(mglPoint p, double r, const char *stl="r")
+	{	mgl_ellipse(gr, p.x, p.y, p.z, p.x, p.y, p.z, r,stl);	}
+	/// Draws the rhomb between points p1,p2 with color stl and width r
+	inline void Rhomb(mglPoint p1, mglPoint p2, double r, const char *stl="r")
+	{	mgl_rhomb(gr, p1.x, p1.y, p1.z, p2.x, p2.y, p2.z, r,stl);	}
+
+	/// Print text in position p with specified font
+	inline void Putsw(mglPoint p,const wchar_t *text,const char *font=":C",double size=-1)
+	{	mgl_putsw(gr, p.x, p.y, p.z, text, font, size);	}
+	inline void Puts(mglPoint p,const char *text,const char *font=":C",double size=-1)
+	{	mgl_puts(gr, p.x, p.y, p.z, text, font, size);	}
+	inline void Putsw(double x, double y,const wchar_t *text,const char *font=":AC",double size=-1)
+	{	mgl_putsw(gr, x, y, 0, text, font, size);	}
+	inline void Puts(double x, double y,const char *text,const char *font=":AC",double size=-1)
+	{	mgl_puts(gr, x, y, 0, text, font, size);	}
+	/// Print text in position p along direction d with specified font
+	inline void Putsw(mglPoint p, mglPoint d, const wchar_t *text, const char *font=":L", double size=-1)
+	{	mgl_putsw_dir(gr, p.x, p.y, p.z, d.x, d.y, d.z, text, font, size);	}
+	inline void Puts(mglPoint p, mglPoint d, const char *text, const char *font=":L", double size=-1)
+	{	mgl_puts_dir(gr, p.x, p.y, p.z, d.x, d.y, d.z, text, font, size);	}
+
+	/// Print text along the curve
+	inline void Text(const mglData &x, const mglData &y, const mglData &z, const char *text, const char *font="", const char *opt="")
+	{	mgl_text_xyz(gr, &x, &y, &z, text, font, opt);	}
+	inline void Text(const mglData &x, const mglData &y, const char *text, const char *font="", const char *opt="")
+	{	mgl_text_xy(gr, &x, &y, text, font, opt);	}
+	inline void Text(const mglData &y, const char *text, const char *font="", const char *opt="")
+	{	mgl_text_y(gr, &y, text, font, opt);	}
+	inline void Text(const mglData &x, const mglData &y, const mglData &z, const wchar_t *text, const char *font="", const char *opt="")
+	{	mgl_textw_xyz(gr, &x, &y, &z, text, font, opt);	}
+	inline void Text(const mglData &x, const mglData &y, const wchar_t *text, const char *font="", const char *opt="")
+	{	mgl_textw_xy(gr, &x, &y, text, font, opt);	}
+	inline void Text(const mglData &y, const wchar_t *text, const char *font="", const char *opt="")
+	{	mgl_textw_y(gr, &y, text, font, opt);	}
+
+	/// Draws bounding box outside the plotting volume with color c.
+	inline void Box(const char *col="", bool ticks=true)
+	{	mgl_box_str(gr, col, ticks);	}
+	/// Draw axises with ticks in direction(s) dir.
+	inline void Axis(const char *dir="xyzt", const char *stl="", const char *opt="")
+	{	mgl_axis(gr, dir,stl,opt);	}
+	/// Draw grid lines perpendicular to direction(s) dir.
+	inline void Grid(const char *dir="xyzt",const char *pen="B", const char *opt="")
+	{	mgl_axis_grid(gr, dir, pen, opt);	}
+	/// Print the label text for axis dir.
+	inline void Label(char dir, const char *text, double pos=+1, const char *opt="")
+	{	mgl_label(gr, dir, text, pos, opt);	}
+	inline void Label(char dir, const wchar_t *text, double pos=+1, const char *opt="")
+	{	mgl_labelw(gr, dir, text, pos, opt);	}
+
+	/// Draw colorbar at edge of axis
+	inline void Colorbar(const char *sch="")
+	{	mgl_colorbar(gr, sch);	}
+	inline void Colorbar(const char *sch,double x,double y,double w=1,double h=1)
+	{	mgl_colorbar_ext(gr, sch, x,y,w,h);	}
+	/// Draw colorbar with manual colors at edge of axis
+	inline void Colorbar(const mglData &val, const char *sch="")
+	{	mgl_colorbar_val(gr, &val, sch);	}
+	inline void Colorbar(const mglData &val, const char *sch,double x,double y,double w=1,double h=1)
+	{	mgl_colorbar_val_ext(gr, &val, sch, x,y,w,h);	}
+
+	/// Add string to legend
+	inline void AddLegend(const char *text,const char *style)
+	{	mgl_add_legend(gr, text, style);	}
+	inline void AddLegend(const wchar_t *text,const char *style)
+	{	mgl_add_legendw(gr, text, style);	}
+	/// Clear saved legend string
+	inline void ClearLegend()
+	{	mgl_clear_legend(gr);	}
+	/// Draw legend of accumulated strings at position {x,y}
+	inline void Legend(double x, double y, const char *font="#", const char *opt="")
+	{	mgl_legend_pos(gr, x, y, font, opt);	}
+	/// Draw legend of accumulated strings
+	inline void Legend(int where=3, const char *font="#", const char *opt="")
+	{	mgl_legend(gr, where, font, opt);	}
+	/// Set number of marks in legend sample
+	inline void SetLegendMarks(int num)		{	mgl_set_legend_marks(gr, num);	}
+
+	/// Draw usual curve {x,y,z}
+	inline void Plot(const mglData &x, const mglData &y, const mglData &z, const char *pen="", const char *opt="")
+	{	mgl_plot_xyz(gr, &x, &y, &z, pen, opt);	}
+	inline void Plot(const mglData &x, const mglData &y, const char *pen="", const char *opt="")
+	{	mgl_plot_xy(gr, &x, &y, pen,opt);	}
+	inline void Plot(const mglData &y, const char *pen="", const char *opt="")
+	{	mgl_plot(gr, &y, pen,opt);	}
+	/// Draw tape(s) which rotates as (bi-)normales of curve {x,y,z}
+	inline void Tape(const mglData &x, const mglData &y, const mglData &z, const char *pen="", const char *opt="")
+	{	mgl_tape_xyz(gr, &x, &y, &z, pen, opt);	}
+	inline void Tape(const mglData &x, const mglData &y, const char *pen="", const char *opt="")
+	{	mgl_tape_xy(gr, &x, &y, pen,opt);	}
+	inline void Tape(const mglData &y, const char *pen="", const char *opt="")
+	{	mgl_tape(gr, &y, pen,opt);	}
+	/// Draw radar chart (plot in curved coordinates)
+	inline void Radar(const mglData &a, const char *pen="", const char *opt="")
+	{	mgl_radar(gr, &a, pen, opt);	}
+	/// Draw stairs for points in arrays {x,y,z}
+	inline void Step(const mglData &x, const mglData &y, const mglData &z, const char *pen="", const char *opt="")
+	{	mgl_step_xyz(gr, &x, &y, &z, pen, opt);	}
+	inline void Step(const mglData &x, const mglData &y, const char *pen="", const char *opt="")
+	{	mgl_step_xy(gr, &x, &y, pen, opt);	}
+	inline void Step(const mglData &y, const char *pen="", const char *opt="")
+	{	mgl_step(gr, &y, pen, opt);	}
+	/// Draw curve {x,y,z} which is colored by c (like tension plot)
+	inline void Tens(const mglData &x, const mglData &y, const mglData &z, const mglData &c, const char *pen="", const char *opt="")
+	{	mgl_tens_xyz(gr, &x, &y, &z, &c, pen, opt);	}
+	inline void Tens(const mglData &x, const mglData &y, const mglData &c, const char *pen="", const char *opt="")
+	{	mgl_tens_xy(gr, &x, &y, &c, pen, opt);	}
+	inline void Tens(const mglData &y, const mglData &c, const char *pen="", const char *opt="")
+	{	mgl_tens(gr, &y, &c, pen, opt);	}
+	/// Fill area between curve {x,y,z} and axis plane
+	inline void Area(const mglData &x, const mglData &y, const mglData &z, const char *pen="", const char *opt="")
+	{	mgl_area_xyz(gr, &x, &y, &z, pen, opt);	}
+	inline void Area(const mglData &x, const mglData &y, const char *pen="", const char *opt="")
+	{	mgl_area_xy(gr, &x, &y, pen, opt);	}
+	inline void Area(const mglData &y, const char *pen="", const char *opt="")
+	{	mgl_area(gr, &y, pen, opt);	}
+	/// Fill area between curves y1 and y2 specified parametrically
+	inline void Region(const mglData &y1, const mglData &y2, const char *pen="", const char *opt="")
+	{	mgl_region(gr, &y1, &y2, pen, opt);	}
+	inline void Region(const mglData &x, const mglData &y1, const mglData &y2, const char *pen="", const char *opt="")
+	{	mgl_region_xy(gr, &x, &y1, &y2, pen, opt);	}
+	/// Draw vertical lines from points {x,y,z} to axis plane
+	inline void Stem(const mglData &x, const mglData &y, const mglData &z, const char *pen="", const char *opt="")
+	{	mgl_stem_xyz(gr, &x, &y, &z, pen, opt);	}
+	inline void Stem(const mglData &x, const mglData &y, const char *pen="", const char *opt="")
+	{	mgl_stem_xy(gr, &x, &y, pen, opt);	}
+	inline void Stem(const mglData &y, const char *pen="", const char *opt="")
+	{	mgl_stem(gr, &y, pen, opt);	}
+
+	/// Draw vertical bars from points {x,y,z} to axis plane
+	inline void Bars(const mglData &x, const mglData &y, const mglData &z, const char *pen="", const char *opt="")
+	{	mgl_bars_xyz(gr, &x, &y, &z, pen, opt);	}
+	inline void Bars(const mglData &x, const mglData &y, const char *pen="", const char *opt="")
+	{	mgl_bars_xy(gr, &x, &y, pen, opt);	}
+	inline void Bars(const mglData &y, const char *pen="", const char *opt="")
+	{	mgl_bars(gr, &y, pen, opt);	}
+	/// Draw horizontal bars from points {x,y} to axis plane
+	inline void Barh(const mglData &y, const mglData &v, const char *pen="", const char *opt="")
+	{	mgl_barh_yx(gr, &y, &v, pen, opt);	}
+	inline void Barh(const mglData &v, const char *pen="", const char *opt="")
+	{	mgl_barh(gr, &v, pen, opt);	}
+	/// Draw chart for data a
+	inline void Chart(const mglData &a, const char *colors="", const char *opt="")
+	{	mgl_chart(gr, &a, colors,opt);	}
+	/// Draw Open-High-Low-Close (OHLC) diagram
+	inline void OHLC(const mglData &x, const mglData &open, const mglData &high, const mglData &low, const mglData &close, const char *pen="", const char *opt="")
+	{	mgl_ohlc_x(gr, &x, &open,&high,&low,&close,pen,opt);	}
+	inline void OHLC(const mglData &open, const mglData &high, const mglData &low, const mglData &close, const char *pen="", const char *opt="")
+	{	mgl_ohlc(gr, &open,&high,&low,&close,pen,opt);	}
+
+	/// Draw box-plot (special 5-value plot used in statistic)
+	inline void BoxPlot(const mglData &x, const mglData &y, const char *pen="", const char *opt="")
+	{	mgl_boxplot_xy(gr, &x, &y, pen,opt);	}
+	inline void BoxPlot(const mglData &y, const char *pen="", const char *opt="")
+	{	mgl_boxplot(gr, &y, pen,opt);	}
+	/// Draw candle plot
+	inline void Candle(const mglData &x, const mglData &v1, const mglData &v2, const mglData &y1, const mglData &y2, const char *pen="", const char *opt="")
+	{	mgl_candle_xyv(gr, &x, &v1, &v2, &y1, &y2, pen, opt);	}
+	inline void Candle(const mglData &v1, const mglData &v2, const mglData &y1, const mglData &y2, const char *pen="", const char *opt="")
+	{	mgl_candle_yv(gr, &v1, &v2, &y1, &y2, pen, opt);	}
+	inline void Candle(const mglData &v1, const mglData &v2, const char *pen="", const char *opt="")
+	{	mgl_candle_yv(gr, &v1, &v2, NULL, NULL, pen, opt);	}
+	inline void Candle(const mglData &y, const mglData &y1, const mglData &y2, const char *pen="", const char *opt="")
+	{	mgl_candle(gr, &y, &y1, &y2, pen, opt);	}
+	inline void Candle(const mglData &y, const char *pen="", const char *opt="")
+	{	mgl_candle(gr, &y, NULL, NULL, pen, opt);	}
+	/// Draw cones from points {x,y,z} to axis plane
+	inline void Cones(const mglData &x, const mglData &y, const mglData &z, const char *pen="@", const char *opt="")
+	{	mgl_cones_xyz(gr, &x, &y, &z, pen, opt);	}
+	inline void Cones(const mglData &x, const mglData &z, const char *pen="@", const char *opt="")
+	{	mgl_cones_xz(gr, &x, &z, pen, opt);	}
+	inline void Cones(const mglData &z, const char *pen="@", const char *opt="")
+	{	mgl_cones(gr, &z, pen, opt);	}
+
+	/// Draw error boxes {ex,ey} at points {x,y}
+	inline void Error(const mglData &y, const mglData &ey, const char *pen="", const char *opt="")
+	{	mgl_error(gr, &y, &ey, pen, opt);	}
+	inline void Error(const mglData &x, const mglData &y, const mglData &ey, const char *pen="", const char *opt="")
+	{	mgl_error_xy(gr, &x, &y, &ey, pen, opt);	}
+	inline void Error(const mglData &x, const mglData &y, const mglData &ex, const mglData &ey, const char *pen="", const char *opt="")
+	{	mgl_error_exy(gr, &x, &y, &ex, &ey, pen, opt);	}
+	/// Draw marks with size r at points {x,y,z}
+	inline void Mark(const mglData &x, const mglData &y, const mglData &z, const mglData &r, const char *pen, const char *opt="")
+	{	mgl_mark_xyz(gr, &x, &y, &z, &r, pen, opt);	}
+	inline void Mark(const mglData &x, const mglData &y, const mglData &r, const char *pen, const char *opt="")
+	{	mgl_mark_xy(gr, &x, &y, &r, pen, opt);	}
+	inline void Mark(const mglData &y, const mglData &r, const char *pen, const char *opt="")
+	{	mgl_mark_y(gr, &y, &r, pen, opt);	}
+	/// Draw textual marks with size r at points {x,y,z}
+	inline void TextMark(const mglData &x, const mglData &y, const mglData &z, const mglData &r, const char *text, const char *fnt="", const char *opt="")
+	{	mgl_textmark_xyzr(gr, &x, &y, &z, &r, text, fnt, opt);	}
+	inline void TextMark(const mglData &x, const mglData &y, const mglData &r, const char *text, const char *fnt="", const char *opt="")
+	{	mgl_textmark_xyr(gr, &x, &y, &r, text, fnt, opt);	}
+	inline void TextMark(const mglData &y, const mglData &r, const char *text, const char *fnt="", const char *opt="")
+	{	mgl_textmark_yr(gr, &y, &r, text, fnt, opt);	}
+	inline void TextMark(const mglData &y, const char *text, const char *fnt="", const char *opt="")
+	{	mgl_textmark(gr, &y, text, fnt, opt);	}
+	inline void TextMark(const mglData &x, const mglData &y, const mglData &z, const mglData &r, const wchar_t *text, const char *fnt="", const char *opt="")
+	{	mgl_textmarkw_xyzr(gr, &x, &y, &z, &r, text, fnt, opt);	}
+	inline void TextMark(const mglData &x, const mglData &y, const mglData &r, const wchar_t *text, const char *fnt="", const char *opt="")
+	{	mgl_textmarkw_xyr(gr, &x, &y, &r, text, fnt, opt);	}
+	inline void TextMark(const mglData &y, const mglData &r, const wchar_t *text, const char *fnt="", const char *opt="")
+	{	mgl_textmarkw_yr(gr, &y, &r, text, fnt, opt);	}
+	inline void TextMark(const mglData &y, const wchar_t *text, const char *fnt="", const char *opt="")
+	{	mgl_textmarkw(gr, &y, text, fnt, opt);	}
+
+	/// Draw labels for points coordinate(s) at points {x,y,z}
+	inline void Label(const mglData &x, const mglData &y, const mglData &z, const char *text, const char *fnt="", const char *opt="")
+	{	mgl_label_xyz(gr, &x, &y, &z, text, fnt, opt);	}
+	inline void Label(const mglData &x, const mglData &y, const char *text, const char *fnt="", const char *opt="")
+	{	mgl_label_xy(gr, &x, &y, text, fnt, opt);	}
+	inline void Label(const mglData &y, const char *text, const char *fnt="", const char *opt="")
+	{	mgl_label_y(gr, &y, text, fnt, opt);	}
+	inline void Label(const mglData &x, const mglData &y, const mglData &z, const wchar_t *text, const char *fnt="", const char *opt="")
+	{	mgl_labelw_xyz(gr, &x, &y, &z, text, fnt, opt);	}
+	inline void Label(const mglData &x, const mglData &y, const wchar_t *text, const char *fnt="", const char *opt="")
+	{	mgl_labelw_xy(gr, &x, &y, text, fnt, opt);	}
+	inline void Label(const mglData &y, const wchar_t *text, const char *fnt="", const char *opt="")
+	{	mgl_labelw_y(gr, &y, text, fnt, opt);	}
+
+	/// Draw table for values val along given direction with row labels text
+	inline void Table(const mglData &val, const char *text, const char *fnt="#|", const char *opt="")
+	{	mgl_table(gr, 0, 0, &val, text, fnt, opt);	}
+	inline void Table(const mglData &val, const wchar_t *text, const char *fnt="#|", const char *opt="")
+	{	mgl_tablew(gr, 0, 0, &val, text, fnt, opt);	}
+	/// Draw table for values val along given direction with row labels text at given position
+	inline void Table(double x, double y, const mglData &val, const char *text, const char *fnt="#|", const char *opt="")
+	{	mgl_table(gr, x, y, &val, text, fnt, opt);	}
+	inline void Table(double x, double y, const mglData &val, const wchar_t *text, const char *fnt="#|", const char *opt="")
+	{	mgl_tablew(gr, x, y, &val, text, fnt, opt);	}
+
+	/// Draw tube with radius r around curve {x,y,z}
+	inline void Tube(const mglData &x, const mglData &y, const mglData &z, const mglData &r, const char *pen="", const char *opt="")
+	{	mgl_tube_xyzr(gr, &x, &y, &z, &r, pen, opt);	}
+	inline void Tube(const mglData &x, const mglData &y, const mglData &z, double r, const char *pen="", const char *opt="")
+	{	mgl_tube_xyz(gr, &x, &y, &z, r, pen, opt);	}
+	inline void Tube(const mglData &x, const mglData &y, const mglData &r, const char *pen="", const char *opt="")
+	{	mgl_tube_xyr(gr, &x, &y, &r, pen, opt);	}
+	inline void Tube(const mglData &x, const mglData &y, double r, const char *pen="", const char *opt="")
+	{	mgl_tube_xy(gr, &x, &y, r, pen, opt);	}
+	inline void Tube(const mglData &y, const mglData &r, const char *pen="", const char *opt="")
+	{	mgl_tube_r(gr, &y, &r, pen, opt);	}
+	inline void Tube(const mglData &y, double r, const char *pen="", const char *opt="")
+	{	mgl_tube(gr, &y, r, pen, opt);	}
+	/// Draw surface of curve {r,z} rotatation around axis
+	inline void Torus(const mglData &r, const mglData &z, const char *pen="", const char *opt="")
+	{	mgl_torus(gr, &r, &z, pen,opt);	}
+
+	/// Draw mesh lines for 2d data specified parametrically
+	inline void Mesh(const mglData &x, const mglData &y, const mglData &z, const char *stl="", const char *opt="")
+	{	mgl_mesh_xy(gr, &x, &y, &z, stl, opt);	}
+	inline void Mesh(const mglData &z, const char *stl="", const char *opt="")
+	{	mgl_mesh(gr, &z, stl, opt);	}
+	/// Draw mesh lines for 2d data specified parametrically
+	inline void Fall(const mglData &x, const mglData &y, const mglData &z, const char *stl="", const char *opt="")
+	{	mgl_fall_xy(gr, &x, &y, &z, stl, opt);	}
+	inline void Fall(const mglData &z, const char *stl="", const char *opt="")
+	{	mgl_fall(gr, &z, stl, opt);	}
+	/// Draw belts for 2d data specified parametrically
+	inline void Belt(const mglData &x, const mglData &y, const mglData &z, const char *stl="", const char *opt="")
+	{	mgl_belt_xy(gr, &x, &y, &z, stl, opt);	}
+	inline void Belt(const mglData &z, const char *stl="", const char *opt="")
+	{	mgl_belt(gr, &z, stl, opt);	}
+	/// Draw surface for 2d data specified parametrically with color proportional to z
+	inline void Surf(const mglData &x, const mglData &y, const mglData &z, const char *stl="", const char *opt="")
+	{	mgl_surf_xy(gr, &x, &y, &z, stl, opt);	}
+	inline void Surf(const mglData &z, const char *stl="", const char *opt="")
+	{	mgl_surf(gr, &z, stl, opt);	}
+	/// Draw grid lines for density plot of 2d data specified parametrically
+	inline void Grid(const mglData &x, const mglData &y, const mglData &z, const char *stl="", const char *opt="")
+	{	mgl_grid_xy(gr, &x, &y, &z, stl, opt);	}
+	inline void Grid(const mglData &z, const char *stl="", const char *opt="")
+	{	mgl_grid(gr, &z, stl, opt);	}
+	/// Draw vertical tiles for 2d data specified parametrically
+	inline void Tile(const mglData &x, const mglData &y, const mglData &z, const char *stl="", const char *opt="")
+	{	mgl_tile_xy(gr, &x, &y, &z, stl, opt);	}
+	inline void Tile(const mglData &z, const char *stl="", const char *opt="")
+	{	mgl_tile(gr, &z, stl, opt);	}
+	/// Draw density plot for 2d data specified parametrically
+	inline void Dens(const mglData &x, const mglData &y, const mglData &z, const char *stl="", const char *opt="")
+	{	mgl_dens_xy(gr, &x, &y, &z, stl, opt);	}
+	inline void Dens(const mglData &z, const char *stl="", const char *opt="")
+	{	mgl_dens(gr, &z, stl, opt);	}
+	/// Draw vertical boxes for 2d data specified parametrically
+	inline void Boxs(const mglData &x, const mglData &y, const mglData &z, const char *stl="", const char *opt="")
+	{	mgl_boxs_xy(gr, &x, &y, &z, stl, opt);	}
+	inline void Boxs(const mglData &z, const char *stl="", const char *opt="")
+	{	mgl_boxs(gr, &z, stl, opt);	}
+
+	/// Draw contour lines for 2d data specified parametrically
+	inline void Cont(const mglData &v, const mglData &x, const mglData &y, const mglData &z, const char *sch="", const char *opt="")
+	{	mgl_cont_xy_val(gr, &v, &x, &y, &z, sch, opt);	}
+	inline void Cont(const mglData &v, const mglData &z, const char *sch="", const char *opt="")
+	{	mgl_cont_val(gr, &v, &z, sch, opt);	}
+	inline void Cont(const mglData &x, const mglData &y, const mglData &z, const char *sch="", const char *opt="")
+	{	mgl_cont_xy(gr, &x, &y, &z, sch, opt);	}
+	inline void Cont(const mglData &z, const char *sch="", const char *opt="")
+	{	mgl_cont(gr, &z, sch, opt);	}
+	/// Draw solid contours for 2d data specified parametrically
+	inline void ContF(const mglData &v, const mglData &x, const mglData &y, const mglData &z, const char *sch="", const char *opt="")
+	{	mgl_contf_xy_val(gr, &v, &x, &y, &z, sch, opt);	}
+	inline void ContF(const mglData &v, const mglData &z, const char *sch="", const char *opt="")
+	{	mgl_contf_val(gr, &v, &z, sch, opt);	}
+	inline void ContF(const mglData &x, const mglData &y, const mglData &z, const char *sch="", const char *opt="")
+	{	mgl_contf_xy(gr, &x, &y, &z, sch, opt);	}
+	inline void ContF(const mglData &z, const char *sch="", const char *opt="")
+	{	mgl_contf(gr, &z, sch, opt);	}
+	/// Draw solid contours for 2d data specified parametrically with manual colors
+	inline void ContD(const mglData &v, const mglData &x, const mglData &y, const mglData &z, const char *sch="", const char *opt="")
+	{	mgl_contd_xy_val(gr, &v, &x, &y, &z, sch, opt);	}
+	inline void ContD(const mglData &v, const mglData &z, const char *sch="", const char *opt="")
+	{	mgl_contd_val(gr, &v, &z, sch, opt);	}
+	inline void ContD(const mglData &x, const mglData &y, const mglData &z, const char *sch="", const char *opt="")
+	{	mgl_contd_xy(gr, &x, &y, &z, sch, opt);	}
+	inline void ContD(const mglData &z, const char *sch="", const char *opt="")
+	{	mgl_contd(gr, &z, sch, opt);	}
+	/// Draw contour tubes for 2d data specified parametrically
+	inline void ContV(const mglData &v, const mglData &x, const mglData &y, const mglData &z, const char *sch="", const char *opt="")
+	{	mgl_contv_xy_val(gr, &v, &x, &y, &z, sch, opt);	}
+	inline void ContV(const mglData &v, const mglData &z, const char *sch="", const char *opt="")
+	{	mgl_contv_val(gr, &v, &z, sch, opt);	}
+	inline void ContV(const mglData &x, const mglData &y, const mglData &z, const char *sch="", const char *opt="")
+	{	mgl_contv_xy(gr, &x, &y, &z, sch, opt);	}
+	inline void ContV(const mglData &z, const char *sch="", const char *opt="")
+	{	mgl_contv(gr, &z, sch, opt);	}
+
+	/// Draw axial-symmetric isosurfaces for 2d data specified parametrically
+	inline void Axial(const mglData &v, const mglData &x, const mglData &y, const mglData &z, const char *sch="", const char *opt="")
+	{	mgl_axial_xy_val(gr, &v, &x, &y, &z, sch,opt);	}
+	inline void Axial(const mglData &v, const mglData &z, const char *sch="", const char *opt="")
+	{	mgl_axial_val(gr, &v, &z, sch, opt);	}
+	inline void Axial(const mglData &x, const mglData &y, const mglData &z, const char *sch="", const char *opt="")
+	{	mgl_axial_xy(gr, &x, &y, &z, sch, opt);	}
+	inline void Axial(const mglData &z, const char *sch="", const char *opt="")
+	{	mgl_axial(gr, &z, sch, opt);	}
+
+	/// Draw grid lines for density plot at slice for 3d data specified parametrically
+	inline void Grid3(const mglData &x, const mglData &y, const mglData &z, const mglData &a, const char *stl="", double sVal=-1, const char *opt="")
+	{	mgl_grid3_xyz(gr, &x, &y, &z, &a, stl, sVal, opt);	}
+	inline void Grid3(const mglData &a, const char *stl="", double sVal=-1, const char *opt="")
+	{	mgl_grid3(gr, &a, stl, sVal, opt);	}
+	/// Draw density plot at slice for 3d data specified parametrically
+	inline void Dens3(const mglData &x, const mglData &y, const mglData &z, const mglData &a, const char *stl="", double sVal=-1, const char *opt="")
+	{	mgl_dens3_xyz(gr, &x, &y, &z, &a, stl, sVal, opt);	}
+	inline void Dens3(const mglData &a, const char *stl="", double sVal=-1, const char *opt="")
+	{	mgl_dens3(gr, &a, stl, sVal, opt);	}
+
+	/// Draw isosurface(s) for 3d data specified parametrically
+	inline void Surf3(double Val, const mglData &x, const mglData &y, const mglData &z, const mglData &a, const char *stl="", const char *opt="")
+	{	mgl_surf3_xyz_val(gr, Val, &x, &y, &z, &a, stl, opt);	}
+	inline void Surf3(double Val, const mglData &a, const char *stl="", const char *opt="")
+	{	mgl_surf3_val(gr, Val, &a, stl, opt);	}
+	inline void Surf3(const mglData &x, const mglData &y, const mglData &z, const mglData &a, const char *stl="", const char *opt="")
+	{	mgl_surf3_xyz(gr, &x, &y, &z, &a, stl, opt);	}
+	inline void Surf3(const mglData &a, const char *stl="", const char *opt="")
+	{	mgl_surf3(gr, &a, stl, opt);	}
+
+	/// Draw a semi-transparent cloud for 3d data
+	inline void Cloud(const mglData &x, const mglData &y, const mglData &z, const mglData &a, const char *stl="", const char *opt="")
+	{	mgl_cloud_xyz(gr, &x, &y, &z, &a, stl, opt);	}
+	inline void Cloud(const mglData &a, const char *stl="", const char *opt="")
+	{	mgl_cloud(gr, &a, stl, opt);	}
+
+	/// Draw contour lines at slice for 3d data specified parametrically
+	inline void Cont3(const mglData &v, const mglData &x, const mglData &y, const mglData &z, const mglData &a, const char *sch="", double sVal=-1, const char *opt="")
+	{	mgl_cont3_xyz_val(gr, &v, &x, &y, &z, &a, sch, sVal, opt);	}
+	inline void Cont3(const mglData &v, const mglData &a, const char *sch="", double sVal=-1, const char *opt="")
+	{	mgl_cont3_val(gr, &v, &a, sch, sVal, opt);	}
+	inline void Cont3(const mglData &x, const mglData &y, const mglData &z, const mglData &a, const char *sch="", double sVal=-1, const char *opt="")
+	{	mgl_cont3_xyz(gr, &x, &y, &z, &a, sch, sVal, opt);	}
+	inline void Cont3(const mglData &a, const char *sch="", double sVal=-1, const char *opt="")
+	{	mgl_cont3(gr, &a, sch, sVal, opt);	}
+
+	/// Draw solid contours at slice for 3d data specified parametrically
+	inline void ContF3(const mglData &v, const mglData &x, const mglData &y, const mglData &z, const mglData &a, const char *sch="", double sVal=-1, const char *opt="")
+	{	mgl_contf3_xyz_val(gr, &v, &x, &y, &z, &a, sch, sVal, opt);	}
+	inline void ContF3(const mglData &v, const mglData &a, const char *sch="", double sVal=-1, const char *opt="")
+	{	mgl_contf3_val(gr, &v, &a, sch, sVal, opt);	}
+	inline void ContF3(const mglData &x, const mglData &y, const mglData &z, const mglData &a, const char *sch="", double sVal=-1, const char *opt="")
+	{	mgl_contf3_xyz(gr, &x, &y, &z, &a, sch, sVal, opt);	}
+	inline void ContF3(const mglData &a, const char *sch="", double sVal=-1, const char *opt="")
+	{	mgl_contf3(gr, &a, sch, sVal, opt);	}
+
+	/// Draw several isosurfaces for 3d beam in curvilinear coordinates
+	inline void Beam(const mglData &tr, const mglData &g1, const mglData &g2, const mglData &a, double r, const char *stl=0, int flag=0, int num=3)
+	{	mgl_beam(gr, &tr,&g1,&g2,&a,r,stl,flag,num);	}
+	inline void Beam(double val, const mglData &tr, const mglData &g1, const mglData &g2, const mglData &a, double r, const char *stl=NULL, int flag=0)
+	{	mgl_beam_val(gr,val,&tr,&g1,&g2,&a,r,stl,flag);	}
+
+	/// Draw vertical tiles with variable size r for 2d data specified parametrically
+	inline void TileS(const mglData &x, const mglData &y, const mglData &z, const mglData &r, const char *stl="", const char *opt="")
+	{	mgl_tiles_xy(gr, &x, &y, &z, &r, stl, opt);	}
+	inline void TileS(const mglData &z, const mglData &r, const char *stl="", const char *opt="")
+	{	mgl_tiles(gr, &z, &r, stl, opt);	}
+	/// Draw surface for 2d data specified parametrically with color proportional to c
+	inline void SurfC(const mglData &x, const mglData &y, const mglData &z, const mglData &c, const char *sch="", const char *opt="")
+	{	mgl_surfc_xy(gr, &x, &y, &z, &c, sch,opt);	}
+	inline void SurfC(const mglData &z, const mglData &c, const char *sch="", const char *opt="")
+	{	mgl_surfc(gr, &z, &c, sch,opt);	}
+	/// Draw surface for 2d data specified parametrically with alpha proportional to c
+	inline void SurfA(const mglData &x, const mglData &y, const mglData &z, const mglData &c, const char *sch="", const char *opt="")
+	{	mgl_surfa_xy(gr, &x, &y, &z, &c, sch,opt);	}
+	inline void SurfA(const mglData &z, const mglData &c, const char *sch="", const char *opt="")
+	{	mgl_surfa(gr, &z, &c, sch,opt);	}
+
+	/// Color map of matrix a to matrix b, both matrix can parametrically depend on coordinates
+	inline void Map(const mglData &x, const mglData &y, const mglData &a, const mglData &b, const char *sch="", const char *opt="")
+	{	mgl_map_xy(gr, &x, &y, &a, &b, sch, opt);	}
+	inline void Map(const mglData &a, const mglData &b, const char *sch="", const char *opt="")
+	{	mgl_map(gr, &a, &b, sch, opt);	}
+	/// Draw density plot for spectra-gramm specified parametrically
+	inline void STFA(const mglData &x, const mglData &y, const mglData &re, const mglData &im, int dn, const char *sch="", const char *opt="")
+	{	mgl_stfa_xy(gr, &x, &y, &re, &im, dn, sch, opt);	}
+	inline void STFA(const mglData &re, const mglData &im, int dn, const char *sch="", const char *opt="")
+	{	mgl_stfa(gr, &re, &im, dn, sch, opt);	}
+
+	/// Draw isosurface(s) for 3d data specified parametrically with alpha proportional to b
+	inline void Surf3A(double Val, const mglData &x, const mglData &y, const mglData &z, const mglData &a, const mglData &b, const char *stl="", const char *opt="")
+	{	mgl_surf3a_xyz_val(gr, Val, &x, &y, &z, &a, &b, stl, opt);	}
+	inline void Surf3A(double Val, const mglData &a, const mglData &b, const char *stl="", const char *opt="")
+	{	mgl_surf3a_val(gr, Val, &a, &b, stl, opt);	}
+	inline void Surf3A(const mglData &x, const mglData &y, const mglData &z, const mglData &a, const mglData &b, const char *stl="", const char *opt="")
+	{	mgl_surf3a_xyz(gr, &x, &y, &z, &a, &b, stl, opt);	}
+	inline void Surf3A(const mglData &a, const mglData &b, const char *stl="", const char *opt="")
+	{	mgl_surf3a(gr, &a, &b, stl, opt);	}
+
+	/// Draw isosurface(s) for 3d data specified parametrically with color proportional to b
+	inline void Surf3C(double Val, const mglData &x, const mglData &y, const mglData &z, const mglData &a, const mglData &b, const char *stl="", const char *opt="")
+	{	mgl_surf3c_xyz_val(gr, Val, &x, &y, &z, &a, &b, stl,opt);	}
+	inline void Surf3C(double Val, const mglData &a, const mglData &b, const char *stl="", const char *opt="")
+	{	mgl_surf3c_val(gr, Val, &a, &b, stl, opt);	}
+	inline void Surf3C(const mglData &x, const mglData &y, const mglData &z, const mglData &a, const mglData &b, const char *stl="", const char *opt="")
+	{	mgl_surf3c_xyz(gr, &x, &y, &z, &a, &b, stl, opt);	}
+	inline void Surf3C(const mglData &a, const mglData &b, const char *stl="", const char *opt="")
+	{	mgl_surf3c(gr, &a, &b, stl, opt);	}
+
+	/// Plot dew drops for vector field {ax,ay} parametrically depended on coordinate {x,y}
+	inline void Dew(const mglData &x, const mglData &y, const mglData &ax, const mglData &ay, const char *sch="", const char *opt="")
+	{	mgl_dew_xy(gr, &x, &y, &ax, &ay, sch, opt);	}
+	inline void Dew(const mglData &ax, const mglData &ay, const char *sch="", const char *opt="")
+	{	mgl_dew_2d(gr, &ax, &ay, sch, opt);	}
+	/// Plot vectors at position {x,y,z} along {ax,ay,az} with length/color proportional to |a|
+	inline void Traj(const mglData &x, const mglData &y, const mglData &ax, const mglData &ay, const char *sch="", const char *opt="")
+	{	mgl_traj_xy(gr, &x, &y, &ax, &ay, sch, opt);	}
+	inline void Traj(const mglData &x, const mglData &y, const mglData &z, const mglData &ax, const mglData &ay, const mglData &az, const char *sch="", const char *opt="")
+	{	mgl_traj_xyz(gr, &x, &y, &z, &ax, &ay, &az, sch, opt);	}
+
+	/// Plot vector field {ax,ay,az} parametrically depended on coordinate {x,y,z} with length/color proportional to |a|
+	inline void Vect(const mglData &x, const mglData &y, const mglData &ax, const mglData &ay, const char *sch="", const char *opt="")
+	{	mgl_vect_xy(gr, &x, &y, &ax, &ay, sch, opt);	}
+	inline void Vect(const mglData &ax, const mglData &ay, const char *sch="", const char *opt="")
+	{	mgl_vect_2d(gr, &ax, &ay, sch, opt);	}
+	inline void Vect(const mglData &x, const mglData &y, const mglData &z, const mglData &ax, const mglData &ay, const mglData &az, const char *sch="", const char *opt="")
+	{	mgl_vect_xyz(gr, &x, &y, &z, &ax, &ay, &az, sch, opt);	}
+	inline void Vect(const mglData &ax, const mglData &ay, const mglData &az, const char *sch="", const char *opt="")
+	{	mgl_vect_3d(gr, &ax, &ay, &az, sch, opt);	}
+
+	/// Draw vector plot at slice for 3d data specified parametrically
+	inline void Vect3(const mglData &x, const mglData &y, const mglData &z, const mglData &ax, const mglData &ay, const mglData &az, const char *stl="", double sVal=-1, const char *opt="")
+	{	mgl_vect3_xyz(gr, &x, &y, &z, &ax,&ay,&az, stl, sVal, opt);	}
+	inline void Vect3(const mglData &ax, const mglData &ay, const mglData &az, const char *stl="", double sVal=-1, const char *opt="")
+	{	mgl_vect3(gr, &ax,&ay,&az, stl, sVal, opt);	}
+
+	/// Plot flows for vector field {ax,ay,az} parametrically depended on coordinate {x,y,z} with color proportional to |a|
+	inline void Flow(const mglData &x, const mglData &y, const mglData &ax, const mglData &ay, const char *sch="", const char *opt="")
+	{	mgl_flow_xy(gr, &x, &y, &ax, &ay, sch, opt);	}
+	inline void Flow(const mglData &ax, const mglData &ay, const char *sch="", const char *opt="")
+	{	mgl_flow_2d(gr, &ax, &ay, sch, opt);	}
+	inline void Flow(const mglData &x, const mglData &y, const mglData &z, const mglData &ax, const mglData &ay, const mglData &az, const char *sch="", const char *opt="")
+	{	mgl_flow_xyz(gr, &x, &y, &z, &ax, &ay, &az, sch, opt);	}
+	inline void Flow(const mglData &ax, const mglData &ay, const mglData &az, const char *sch="", const char *opt="")
+	{	mgl_flow_3d(gr, &ax, &ay, &az, sch, opt);	}
+
+	/// Plot flow from point p for vector field {ax,ay,az} parametrically depended on coordinate {x,y,z} with color proportional to |a|
+	inline void FlowP(mglPoint p, const mglData &x, const mglData &y, const mglData &ax, const mglData &ay, const char *sch="", const char *opt="")
+	{	mgl_flowp_xy(gr, p.x, p.y, p.z, &x, &y, &ax, &ay, sch, opt);	}
+	inline void FlowP(mglPoint p, const mglData &ax, const mglData &ay, const char *sch="", const char *opt="")
+	{	mgl_flowp_2d(gr, p.x, p.y, p.z, &ax, &ay, sch, opt);	}
+	inline void FlowP(mglPoint p, const mglData &x, const mglData &y, const mglData &z, const mglData &ax, const mglData &ay, const mglData &az, const char *sch="", const char *opt="")
+	{	mgl_flowp_xyz(gr, p.x, p.y, p.z, &x, &y, &z, &ax, &ay, &az, sch, opt);	}
+	inline void FlowP(mglPoint p, const mglData &ax, const mglData &ay, const mglData &az, const char *sch="", const char *opt="")
+	{	mgl_flowp_3d(gr, p.x, p.y, p.z, &ax, &ay, &az, sch, opt);	}
+
+	/// Plot flows for gradient of scalar field phi parametrically depended on coordinate {x,y,z}
+	inline void Grad(const mglData &x, const mglData &y, const mglData &z, const mglData &phi, const char *sch="", const char *opt="")
+	{	mgl_grad_xyz(gr,&x,&y,&z,&phi,sch,opt);	}
+	inline void Grad(const mglData &x, const mglData &y, const mglData &phi, const char *sch="", const char *opt="")
+	{	mgl_grad_xy(gr,&x,&y,&phi,sch,opt);	}
+	inline void Grad(const mglData &phi, const char *sch="", const char *opt="")
+	{	mgl_grad(gr,&phi,sch,opt);	}
+
+	/// Plot flow pipes for vector field {ax,ay,az} parametrically depended on coordinate {x,y,z} with color and radius proportional to |a|
+	inline void Pipe(const mglData &x, const mglData &y, const mglData &ax, const mglData &ay, const char *sch="", double r0=0.05, const char *opt="")
+	{	mgl_pipe_xy(gr, &x, &y, &ax, &ay, sch, r0, opt);	}
+	inline void Pipe(const mglData &ax, const mglData &ay, const char *sch="", double r0=0.05, const char *opt="")
+	{	mgl_pipe_2d(gr, &ax, &ay, sch, r0, opt);	}
+	inline void Pipe(const mglData &x, const mglData &y, const mglData &z, const mglData &ax, const mglData &ay, const mglData &az, const char *sch="", double r0=0.05, const char *opt="")
+	{	mgl_pipe_xyz(gr, &x, &y, &z, &ax, &ay, &az, sch, r0, opt);	}
+	inline void Pipe(const mglData &ax, const mglData &ay, const mglData &az, const char *sch="", double r0=0.05, const char *opt="")
+	{	mgl_pipe_3d(gr, &ax, &ay, &az, sch, r0, opt);	}
+
+	/// Draw density plot for data at x = sVal
+	inline void DensX(const mglData &a, const char *stl="", double sVal=NaN, const char *opt="")
+	{	mgl_dens_x(gr, &a, stl, sVal, opt);	}
+	/// Draw density plot for data at y = sVal
+	inline void DensY(const mglData &a, const char *stl="", double sVal=NaN, const char *opt="")
+	{	mgl_dens_y(gr, &a, stl, sVal, opt);	}
+	/// Draw density plot for data at z = sVal
+	inline void DensZ(const mglData &a, const char *stl="", double sVal=NaN, const char *opt="")
+	{	mgl_dens_z(gr, &a, stl, sVal, opt);	}
+	/// Draw contour lines for data at x = sVal
+	inline void ContX(const mglData &a, const char *stl="", double sVal=NaN, const char *opt="")
+	{	mgl_cont_x(gr, &a, stl, sVal, opt);	}
+	inline void ContX(const mglData &v, const mglData &a, const char *stl="", double sVal=NaN, const char *opt="")
+	{	mgl_cont_x_val(gr, &v, &a, stl, sVal, opt);	}
+	/// Draw contour lines for data at y = sVal
+	inline void ContY(const mglData &a, const char *stl="", double sVal=NaN, const char *opt="")
+	{	mgl_cont_y(gr, &a, stl, sVal, opt);	}
+	inline void ContY(const mglData &v, const mglData &a, const char *stl="", double sVal=NaN, const char *opt="")
+	{	mgl_cont_y_val(gr, &v, &a, stl, sVal, opt);	}
+	/// Draw contour lines for data at z = sVal
+	inline void ContZ(const mglData &a, const char *stl="", double sVal=NaN, const char *opt="")
+	{	mgl_cont_z(gr, &a, stl, sVal, opt);	}
+	inline void ContZ(const mglData &v, const mglData &a, const char *stl="", double sVal=NaN, const char *opt="")
+	{	mgl_cont_z_val(gr, &v, &a, stl, sVal, opt);	}
+	/// Draw solid contours for data at x = sVal
+	inline void ContFX(const mglData &a, const char *stl="", double sVal=NaN, const char *opt="")
+	{	mgl_contf_x(gr, &a, stl, sVal, opt);	}
+	inline void ContFX(const mglData &v, const mglData &a, const char *stl="", double sVal=NaN, const char *opt="")
+	{	mgl_contf_x_val(gr, &v, &a, stl, sVal, opt);	}
+	/// Draw solid contours for data at y = sVal
+	inline void ContFY(const mglData &a, const char *stl="", double sVal=NaN, const char *opt="")
+	{	mgl_contf_y(gr, &a, stl, sVal, opt);	}
+	inline void ContFY(const mglData &v, const mglData &a, const char *stl="", double sVal=NaN, const char *opt="")
+	{	mgl_contf_y_val(gr, &v, &a, stl, sVal, opt);	}
+	/// Draw solid contours for data at z = sVal
+	inline void ContFZ(const mglData &a, const char *stl="", double sVal=NaN, const char *opt="")
+	{	mgl_contf_z(gr, &a, stl, sVal, opt);	}
+	inline void ContFZ(const mglData &v, const mglData &a, const char *stl="", double sVal=NaN, const char *opt="")
+	{	mgl_contf_z_val(gr, &v, &a, stl, sVal, opt);	}
+
+	/// Draw curve for formula with x in x-axis range
+	inline void FPlot(const char *fy, const char *stl="", const char *opt="")
+	{	mgl_fplot(gr, fy, stl, opt);	}
+	/// Draw curve for formulas parametrically depended on t in range [0,1]
+	inline void FPlot(const char *fx, const char *fy, const char *fz, const char *stl, const char *opt="")
+	{	mgl_fplot_xyz(gr, fx, fy, fz, stl, opt);	}
+	/// Draw surface by formula with x,y in axis range
+	inline void FSurf(const char *fz, const char *stl="", const char *opt="")
+	{	mgl_fsurf(gr, fz, stl, opt);	}
+	/// Draw surface by formulas parametrically depended on u,v in range [0,1]
+	inline void FSurf(const char *fx, const char *fy, const char *fz, const char *stl, const char *opt="")
+	{	mgl_fsurf_xyz(gr, fx, fy, fz, stl, opt);	}
+
+	/// Draw triangle mesh for points in arrays {x,y,z} with specified color c.
+	inline void TriPlot(const mglData &nums, const mglData &x, const mglData &y, const mglData &z, const mglData &c, const char *sch="", const char *opt="")
+	{	mgl_triplot_xyzc(gr, &nums, &x, &y, &z, &c, sch, opt);	}
+	inline void TriPlot(const mglData &nums, const mglData &x, const mglData &y, const mglData &z, const char *sch="", const char *opt="")
+	{	mgl_triplot_xyz(gr, &nums, &x, &y, &z, sch, opt);	}
+	inline void TriPlot(const mglData &nums, const mglData &x, const mglData &y, const char *sch="", const char *opt="")
+	{	mgl_triplot_xy(gr, &nums, &x, &y, sch, opt);	}
+	/// Draw quad mesh for points in arrays {x,y,z} with specified color c.
+	inline void QuadPlot(const mglData &nums, const mglData &x, const mglData &y, const mglData &z, const mglData &c, const char *sch="", const char *opt="")
+	{	mgl_quadplot_xyzc(gr, &nums, &x, &y, &z, &c, sch, opt);	}
+	inline void QuadPlot(const mglData &nums, const mglData &x, const mglData &y, const mglData &z, const char *sch="", const char *opt="")
+	{	mgl_quadplot_xyz(gr, &nums, &x, &y, &z, sch, opt);	}
+	inline void QuadPlot(const mglData &nums, const mglData &x, const mglData &y, const char *sch="", const char *opt="")
+	{	mgl_quadplot_xy(gr, &nums, &x, &y, sch, opt);	}
+
+	/// Draw contour lines for triangle mesh for points in arrays {x,y,z} with specified color c.
+	inline void TriCont(const mglData &nums, const mglData &x, const mglData &y, const mglData &z, const char *sch="", const char *opt="")
+	{	mgl_tricont_xyc(gr, &nums, &x, &y, &z, sch, opt);	}
+	inline void TriContV(const mglData &v, const mglData &nums, const mglData &x, const mglData &y, const mglData &z, const char *sch="", const char *opt="")
+	{	mgl_tricont_xycv(gr, &v, &nums, &x, &y, &z, sch, opt);	}
+	inline void TriCont(const mglData &nums, const mglData &x, const mglData &y, const mglData &z, const mglData &a, const char *sch="", const char *opt="")
+	{	mgl_tricont_xyzc(gr, &nums, &x, &y, &z, &a, sch, opt);	}
+	inline void TriContV(const mglData &v, const mglData &nums, const mglData &x, const mglData &y, const mglData &z, const mglData &a, const char *sch="", const char *opt="")
+	{	mgl_tricont_xyzcv(gr, &v, &nums, &x, &y, &z, &a, sch, opt);	}
+
+	/// Draw dots in points {x,y,z}.
+	inline void Dots(const mglData &x, const mglData &y, const mglData &z, const char *sch="", const char *opt="")
+	{	mgl_dots(gr, &x, &y, &z, sch, opt);	}
+	/// Draw semitransparent dots in points {x,y,z} with specified alpha a.
+	inline void Dots(const mglData &x, const mglData &y, const mglData &z, const mglData &a, const char *sch="", const char *opt="")
+	{	mgl_dots_a(gr, &x, &y, &z, &a, sch, opt);	}
+	/// Draw semitransparent dots in points {x,y,z} with specified color c and alpha a.
+	inline void Dots(const mglData &x, const mglData &y, const mglData &z, const mglData &c, const mglData &a, const char *sch="", const char *opt="")
+	{	mgl_dots_ca(gr, &x, &y, &z, &c, &a, sch, opt);	}
+	/// Draw surface reconstructed for points in arrays {x,y,z}.
+	inline void Crust(const mglData &x, const mglData &y, const mglData &z, const char *sch="", const char *opt="")
+	{	mgl_crust(gr, &x, &y, &z, sch, opt);	}
+
+	/// Fit data along x-direction for each data row. Return array with values for found formula.
+	inline mglData Fit(const mglData &y, const char *eq, const char *var, const char *opt="")
+	{	return mglData(true,mgl_fit_1(gr, &y, eq,var,0, opt));	}
+	inline mglData Fit(const mglData &y, const char *eq, const char *var, mglData &ini, const char *opt="")
+	{	return mglData(true,mgl_fit_1(gr, &y, eq, var, &ini, opt));	}
+	/// Fit data along x-, y-directions for each data slice. Return array with values for found formula.
+	inline mglData Fit2(const mglData &z, const char *eq, const char *var, const char *opt="")
+	{	return mglData(true,mgl_fit_2(gr, &z, eq, var,0, opt));	}
+	inline mglData Fit2(const mglData &z, const char *eq, const char *var, mglData &ini, const char *opt="")
+	{	return mglData(true,mgl_fit_2(gr, &z, eq, var, &ini, opt));	}
+	/// Fit data along along all directions. Return array with values for found formula.
+	inline mglData Fit3(const mglData &a, const char *eq, const char *var, const char *opt="")
+	{	return mglData(true,mgl_fit_3(gr, &a, eq, var,0, opt));	}
+	inline mglData Fit3(const mglData &a, const char *eq, const char *var, mglData &ini, const char *opt="")
+	{	return mglData(true,mgl_fit_3(gr, &a, eq, var, &ini, opt));	}
+	/// Fit data along x-direction for each data row. Return array with values for found formula.
+	inline mglData Fit(const mglData &x, const mglData &y, const char *eq, const char *var, const char *opt="")
+	{	return mglData(true,mgl_fit_xy(gr, &x, &y, eq, var,0, opt));	}
+	inline mglData Fit(const mglData &x, const mglData &y, const char *eq, const char *var, mglData &ini, const char *opt="")
+	{	return mglData(true,mgl_fit_xy(gr, &x, &y, eq, var, &ini, opt));	}
+	/// Fit data along x-, y-directions for each data slice. Return array with values for found formula.
+	inline mglData Fit(const mglData &x, const mglData &y, const mglData &z, const char *eq, const char *var, const char *opt="")
+	{	return mglData(true,mgl_fit_xyz(gr, &x, &y, &z, eq, var,0, opt));	}
+	inline mglData Fit(const mglData &x, const mglData &y, const mglData &z, const char *eq, const char *var, mglData &ini, const char *opt="")
+	{	return mglData(true,mgl_fit_xyz(gr, &x, &y, &z, eq, var, &ini, opt));	}
+	/// Fit data along along all directions. Return array with values for found formula.
+	inline mglData Fit(const mglData &x, const mglData &y, const mglData &z, const mglData &a, const char *eq, const char *var, const char *opt="")
+	{	return mglData(true,mgl_fit_xyza(gr, &x, &y, &z, &a, eq, var,0, opt));	}
+	inline mglData Fit(const mglData &x, const mglData &y, const mglData &z, const mglData &a, const char *eq, const char *var, mglData &ini, const char *opt="")
+	{	return mglData(true,mgl_fit_xyza(gr, &x, &y, &z, &a, eq,var, &ini, opt));	}
+	/// Fit data with dispersion s along x-direction for each data row. Return array with values for found formula.
+	inline mglData FitS(const mglData &y, const mglData &s, const char *eq, const char *var, const char *opt="")
+	{	return mglData(true,mgl_fit_ys(gr, &y, &s, eq, var,0, opt));	}
+	inline mglData FitS(const mglData &y, const mglData &s, const char *eq, const char *var, mglData &ini, const char *opt="")
+	{	return mglData(true,mgl_fit_ys(gr, &y, &s, eq, var, &ini, opt));	}
+	inline mglData FitS(const mglData &x, const mglData &y, const mglData &s, const char *eq, const char *var, const char *opt="")
+	{	return mglData(true,mgl_fit_xys(gr, &x, &y, &s, eq, var,0, opt));	}
+	inline mglData FitS(const mglData &x, const mglData &y, const mglData &s, const char *eq, const char *var, mglData &ini, const char *opt="")
+	{	return mglData(true,mgl_fit_xys(gr, &x, &y, &s, eq, var, &ini, opt));	}
+	/// Fit data with dispersion s along x-, y-directions for each data slice. Return array with values for found formula.
+	inline mglData FitS(const mglData &x, const mglData &y, const mglData &z, const mglData &s, const char *eq, const char *var, const char *opt="")
+	{	return mglData(true,mgl_fit_xyzs(gr, &x, &y, &z, &s, eq, var,0, opt));	}
+	inline mglData FitS(const mglData &x, const mglData &y, const mglData &z, const mglData &s, const char *eq, const char *var, mglData &ini, const char *opt="")
+	{	return mglData(true,mgl_fit_xyzs(gr, &x, &y, &z, &s, eq, var, &ini, opt));	}
+	/// Fit data with dispersion s along all directions. Return array with values for found formula.
+	inline mglData FitS(const mglData &x, const mglData &y, const mglData &z, const mglData &a, const mglData &s, const char *eq, const char *var, const char *opt="")
+	{	return mglData(true,mgl_fit_xyzas(gr, &x, &y, &z, &a, &s, eq, var,0, opt));	}
+	inline mglData FitS(const mglData &x, const mglData &y, const mglData &z, const mglData &a, const mglData &s, const char *eq, const char *var, mglData &ini, const char *opt="")
+	{	return mglData(true,mgl_fit_xyzas(gr, &x, &y, &z, &a, &s, eq, var, &ini, opt));	}
+	/// Print fitted last formula (with coefficients)
+	inline void PutsFit(mglPoint p, const char *prefix=0, const char *font="", double size=-1)
+	{	mgl_puts_fit(gr, p.x, p.y, p.z, prefix, font, size);	}
+	/// Get last fitted formula
+	inline const char *GetFit()
+	{	return mgl_get_fit(gr);	}
+
+	/// Solve PDE with x,y,z in range [Min, Max]
+	inline mglData PDE(const char *ham, const mglData &ini_re, const mglData &ini_im, double dz=0.1, double k0=100, const char *opt="")
+	{	return mglData(true,mgl_pde_solve(gr,ham,&ini_re,&ini_im,dz,k0, opt));	}
+	/// Fill data by formula with x,y,z in range [Min, Max]
+	inline void Fill(mglData &u, const char *eq, const char *opt="")
+	{	mgl_data_fill_eq(gr, &u, eq, 0, 0, opt);	}
+	inline void Fill(mglData &u, const char *eq, const mglData &v, const char *opt="")
+	{	mgl_data_fill_eq(gr, &u, eq, &v, 0, opt);	}
+	inline void Fill(mglData &u, const char *eq, const mglData &v, const mglData &w, const char *opt="")
+	{	mgl_data_fill_eq(gr, &u, eq, &v, &w, opt);	}
+	/// Fill data by formula with x,y,z in range [Min, Max]
+	inline void Fill(mglDataC &u, const char *eq, const char *opt="")
+	{	mgl_datac_fill_eq(gr, &u, eq, 0, 0, opt);	}
+	inline void Fill(mglDataC &u, const char *eq, const mglData &v, const char *opt="")
+	{	mgl_datac_fill_eq(gr, &u, eq, &v, 0, opt);	}
+	inline void Fill(mglDataC &u, const char *eq, const mglData &v, const mglData &w, const char *opt="")
+	{	mgl_datac_fill_eq(gr, &u, eq, &v, &w, opt);	}
+
+	/// Fill dat by interpolated values of vdat parametrically depended on xdat,ydat,zdat for x,y,z in axis range
+	inline void Refill(mglData &dat, const mglData &xdat, const mglData &vdat, long sl=-1, const char *opt="")
+	{	mgl_data_refill_gr(gr,&dat,&xdat,0,0,&vdat,sl,opt);	}
+	inline void Refill(mglData &dat, const mglData &xdat, const mglData &ydat, const mglData &vdat, long sl=-1, const char *opt="")
+	{	mgl_data_refill_gr(gr,&dat,&xdat,&ydat,0,&vdat,sl,opt);	}
+	inline void Refill(mglData &dat, const mglData &xdat, const mglData &ydat, const mglData &zdat, const mglData &vdat, const char *opt="")
+	{	mgl_data_refill_gr(gr,&dat,&xdat,&ydat,&zdat,&vdat,-1,opt);	}
+
+	/// Set the data by triangulated surface values assuming x,y,z in range [Min, Max]
+	inline void DataGrid(mglData &d, const mglData &x, const mglData &y, const mglData &z, const char *opt="")
+	{	mgl_data_grid(gr,&d,&x,&y,&z,opt);	}
+
+	/// Make histogram (distribution) of data. This function do not plot data.
+	inline mglData Hist(const mglData &x, const mglData &a, const char *opt="")
+	{	return mglData(true, mgl_hist_x(gr, &x, &a, opt));	}
+	inline mglData Hist(const mglData &x, const mglData &y, const mglData &a, const char *opt="")
+	{	return mglData(true, mgl_hist_xy(gr, &x, &y, &a, opt));	}
+	inline mglData Hist(const mglData &x, const mglData &y, const mglData &z, const mglData &a, const char *opt="")
+	{	return mglData(true, mgl_hist_xyz(gr, &x, &y, &z, &a, opt));	}
+
+	inline void Compression(bool){}		// NOTE: Add later -- IDTF
+	/// Set the preference for vertex color on/off (for formats that support it, now only PRC does).
+	inline void VertexColor(bool enable)	{	mgl_set_flag(gr,enable, MGL_PREFERVC);	}
+	/// Render only front side of surfaces for dubugging purposes (for formats that support it, now only PRC does).
+	inline void DoubleSided(bool enable)	{	mgl_set_flag(gr,!enable, MGL_ONESIDED);	}
+//	inline void TextureColor(bool){}	// NOTE: Add later -- IDTF
+};
+//-----------------------------------------------------------------------------
+/// Wrapper class for MGL parsing
+class mglParse
+{
+	HMPR pr;
+public:
+	mglParse(HMPR p)		{	pr = p;		mgl_use_parser(pr,1);	}
+	mglParse(mglParse &p)	{	pr = p.pr;	mgl_use_parser(pr,1);	}
+	mglParse(bool setsize=false)
+	{	pr=mgl_create_parser();	mgl_parser_allow_setsize(pr, setsize);	}
+	~mglParse()	{	if(mgl_use_parser(pr,-1)<1)	mgl_delete_parser(pr);	}
+	/// Get pointer to internal mglParser object
+	inline HMPR Self()	{	return pr;	}
+	/// Parse and draw single line of the MGL script
+	inline int Parse(mglGraph *gr, const char *str, int pos)
+	{	return mgl_parse_line(gr->Self(), pr, str, pos);	}
+	inline int Parse(mglGraph *gr, const wchar_t *str, int pos)
+	{	return mgl_parse_linew(gr->Self(), pr, str, pos);	}
+	/// Execute MGL script text with '\n' separated lines
+	inline void Execute(mglGraph *gr, const char *str)
+	{	mgl_parse_text(gr->Self(), pr, str);	}
+	inline void Execute(mglGraph *gr, const wchar_t *str)
+	{	mgl_parse_textw(gr->Self(), pr, str);	}
+	/// Execute and draw script from the file
+	inline void Execute(mglGraph *gr, FILE *fp, bool print=false)
+	{	mgl_parse_file(gr->Self(), pr, fp, print);	}
+
+	/// Return type of command: 0 - not found, 1 - data plot, 2 - other plot,
+	///		3 - setup, 4 - data handle, 5 - data create, 6 - subplot, 7 - program
+	///		8 - 1d plot, 9 - 2d plot, 10 - 3d plot, 11 - dd plot, 12 - vector plot
+	///		13 - axis, 14 - primitives, 15 - axis setup, 16 - text/legend, 17 - data transform
+	inline int CmdType(const char *name)
+	{	return mgl_parser_cmd_type(pr, name);	}
+	/// Return string of command format (command name and its argument[s])
+	inline const char *CmdFormat(const char *name)
+	{	return mgl_parser_cmd_frmt(pr, name);	}
+	/// Return description of MGL command
+	inline const char *CmdDesc(const char *name)
+	{	return mgl_parser_cmd_desc(pr, name);	}
+	/// Get name of command with nmber n
+	inline const char *GetCmdName(long n)
+	{	return mgl_parser_cmd_name(pr,n);	}
+	/// Get number of defined commands
+	inline long GetCmdNum()
+	{	return mgl_parser_cmd_num(pr);	}
+
+	/// Set value for parameter $N
+	inline void AddParam(int id, const char *str)
+	{	mgl_parser_add_param(pr, id, str);	}
+	inline void AddParam(int id, const wchar_t *str)
+	{	mgl_parser_add_paramw(pr, id, str);	}
+	/// Restore once flag
+	inline void RestoreOnce()	{	mgl_parser_restore_once(pr);	}
+	/// Allow changing size of the picture
+	inline void AllowSetSize(bool allow)	{	mgl_parser_allow_setsize(pr, allow);	}
+	/// Allow reading/saving files
+	inline void AllowFileIO(bool allow)		{	mgl_parser_allow_file_io(pr, allow);	}
+	/// Set flag to stop script parsing
+	inline void Stop()	{	mgl_parser_stop(pr);	}
+
+	/// Return result of formula evaluation
+	inline mglData Calc(const char *formula)
+	{	return mglData(true,mgl_parser_calc(pr,formula)); 	}
+	inline mglData Calc(const wchar_t *formula)
+	{	return mglData(true,mgl_parser_calcw(pr,formula));	}
+
+	/// Find variable with given name or add a new one
+	/// NOTE !!! You must not delete obtained data arrays !!!
+	inline mglVar *AddVar(const char *name)
+	{	return dynamic_cast<mglVar *>(mgl_parser_add_var(pr, name));	}
+	inline mglVar *AddVar(const wchar_t *name)
+	{	return dynamic_cast<mglVar *>(mgl_parser_add_varw(pr, name));	}
+	/// Find variable with given name or return NULL if no one
+	/// NOTE !!! You must not delete obtained data arrays !!!
+	inline mglVar *FindVar(const char *name)
+	{	return dynamic_cast<mglVar *>(mgl_parser_find_var(pr, name));	}
+	inline mglVar *FindVar(const wchar_t *name)
+	{	return dynamic_cast<mglVar *>(mgl_parser_find_varw(pr, name));	}
+	/// Delete variable with name
+	inline void DeleteVar(const char *name)		{	mgl_parser_del_var(pr, name);		}
+	inline void DeleteVar(const wchar_t *name)	{	mgl_parser_del_varw(pr, name);		}
+	/// Delete all data variables
+	void DeleteAll()	{	mgl_parser_del_all(pr);	}
+};
+//-----------------------------------------------------------------------------
+/// Wrapper class expression evaluating
+class mglExpr
+{
+	HMEX ex;
+public:
+	mglExpr(const char *expr)		{	ex = mgl_create_expr(expr);	}
+	~mglExpr()	{	mgl_delete_expr(ex);	}
+	/// Return value of expression for given x,y,z variables
+	inline double Eval(double x, double y=0, double z=0)
+	{	return mgl_expr_eval(ex,x,y,z);	}
+	/// Return value of expression differentiation over variable dir for given x,y,z variables
+	inline double Diff(char dir, double x, double y=0, double z=0)
+	{	return mgl_expr_diff(ex,dir, x,y,z);	}
+};
+//-----------------------------------------------------------------------------
+/// Wrapper class expression evaluating
+class mglExprC
+{
+	HAEX ex;
+public:
+	mglExprC(const char *expr)		{	ex = mgl_create_cexpr(expr);	}
+	~mglExprC()	{	mgl_delete_cexpr(ex);	}
+	/// Return value of expression for given x,y,z variables
+	inline dual Eval(dual x, dual y=0, dual z=0)
+	{	return mgl_cexpr_eval(ex,x,y,z);	}
+	/// Return value of expression for given x,y,z,u,v,w variables
+	inline dual Eval(dual x, dual y, dual z, dual u, dual v, dual w)
+	{
+		dual var[26];
+		var['x'-'a']=x;	var['y'-'a']=y;	var['z'-'a']=z;
+		var['u'-'a']=u;	var['v'-'a']=v;	var['w'-'a']=w;
+		return mgl_cexpr_eval_v(ex,var);	}
+};
+//-----------------------------------------------------------------------------
diff --git a/lang/sed_rules b/lang/sed_rules
new file mode 100644
index 0000000..8ee5fb6
--- /dev/null
+++ b/lang/sed_rules
@@ -0,0 +1,13 @@
+1,19d
+s/MGL_EXPORT//g
+s/mglDataA/mglData/g
+/SWIG/,/endif/ { s/.*//g }
+s/^.*---.*$//g
+s/^#include.*$//g
+s/^#define.*$//g
+s/^.*public mglData$//g
+s/^#ifndef _MGL_DATA_H_.*$//g
+s/^#ifndef _MGL_H_.*$//g
+s/^#ifdef __cplusplus.*$//g
+/^\s*$/d
+N;$!P;$!D;$d
diff --git a/include/mgl2/type.h b/lang/type.i
similarity index 59%
copy from include/mgl2/type.h
copy to lang/type.i
index fb803ed..133642a 100644
--- a/include/mgl2/type.h
+++ b/lang/type.i
@@ -1,5 +1,5 @@
 /***************************************************************************
- * type.h is part of Math Graphic Library
+ * type.i is part of Math Graphic Library
  * Copyright (C) 2007-2012 Alexey Balakin <mathgl.abalakin at gmail.ru>       *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
@@ -17,22 +17,17 @@
  *   Free Software Foundation, Inc.,                                       *
  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
  ***************************************************************************/
-#ifndef _MGL_TYPE_H_
-#define _MGL_TYPE_H_
-#if !defined(_MSC_VER) && !defined(__BORLANDC__)
-#include <stdint.h>
+#include "mgl2/config.h"
+#if MGL_USE_DOUBLE
+typedef double mreal;
+#else
+typedef float mreal;
 #endif
-#include "mgl2/define.h"
 //-----------------------------------------------------------------------------
 const mreal Pi = M_PI;
 const mreal NaN = NAN;
 const mreal mgl_min_a = 1./256;
 //-----------------------------------------------------------------------------
-#define MGL_SET_XYZ(p,xx,yy,zz)		{p.x=(xx);p.y=(yy);p.z=(zz);}
-#define MGL_SET_XY(p,xx,yy)			{p.x=(xx);p.y=(yy);p.z=0;}
-#define MGL_SET_RGBA(p,rr,gg,bb,aa)	{p.r=(rr);p.g=(gg);p.b=(bb);p.a=(aa);}
-#define MGL_SET_RGB(p,rr,gg,bb)		{p.r=(rr);p.g=(gg);p.b=(bb);}
-//-----------------------------------------------------------------------------
 /// Class for point in 3D space
 struct mglPoint
 {
@@ -50,42 +45,6 @@ struct mglPoint
 	inline void operator*=(mreal a)	{	x*=a;	y*=a;	z*=a;	}
 	inline void operator/=(mreal a)	{	x/=a;	y/=a;	z/=a;	}
 };
-#ifndef SWIG
-inline mglPoint operator+(const mglPoint &a, const mglPoint &b)
-{	return mglPoint(a.x+b.x, a.y+b.y, a.z+b.z, a.c+b.c);	}
-inline mglPoint operator-(const mglPoint &a, const mglPoint &b)
-{	return mglPoint(a.x-b.x, a.y-b.y, a.z-b.z, a.c-b.c);	}
-inline mglPoint operator-(const mglPoint &a)
-{	return mglPoint(-a.x, -a.y, -a.z, -a.c);	}
-inline mglPoint operator*(mreal b, const mglPoint &a)
-{	return mglPoint(a.x*b, a.y*b, a.z*b);	}
-inline mglPoint operator*(const mglPoint &a, mreal b)
-{	return mglPoint(a.x*b, a.y*b, a.z*b);	}
-inline mglPoint operator/(const mglPoint &a, mreal b)
-{	return mglPoint(a.x/b, a.y/b, a.z/b);	}
-inline mreal operator*(const mglPoint &a, const mglPoint &b)
-{	return a.x*b.x+a.y*b.y+a.z*b.z;	}
-inline mglPoint operator/(const mglPoint &a, const mglPoint &b)
-{	return mglPoint(a.x*b.x, a.y*b.y, a.z*b.z);	}
-inline mglPoint operator&(const mglPoint &a, const mglPoint &b)
-{	return a - b*((a*b)/(b*b));	}
-inline mglPoint operator|(const mglPoint &a, const mglPoint &b)
-{	return b*((a*b)/(b*b));	}
-inline mglPoint operator^(const mglPoint &a, const mglPoint &b)
-{	return mglPoint(a.y*b.z-a.z*b.y, a.z*b.x-a.x*b.z, a.x*b.y-a.y*b.x);	}
-inline mglPoint operator!(const mglPoint &a)
-{	mreal f=hypot(a.x,a.y);	return f==0?mglPoint(0.,1.,0.):mglPoint(-a.y/f, a.x/f, 0);	}
-inline bool operator==(const mglPoint &a, const mglPoint &b)
-{	return !memcmp(&a, &b, sizeof(mglPoint));	}
-inline bool operator!=(const mglPoint &a, const mglPoint &b)
-{	return memcmp(&a, &b, sizeof(mglPoint));	}
-inline bool operator<(const mglPoint &a, const mglPoint &b)
-{	return a.x<=b.x && a.y<=b.y && a.z<=b.z;	}
-inline bool operator>(const mglPoint &a, const mglPoint &b)
-{	return a.x>=b.x && a.y>=b.y && a.z>=b.z;	}
-inline mreal mgl_norm(const mglPoint &p)
-{	return sqrt(p.x*p.x+p.y*p.y+p.z*p.z);	}
-#endif
 //-----------------------------------------------------------------------------
 /// Class for RGBA color
 struct mglColor
@@ -137,19 +96,4 @@ struct mglColor
 	inline void operator+=(const mglColor &c)	{	r+=c.r;	g+=c.g;	b+=c.b;	a+=c.a;	}
 	inline void operator-=(const mglColor &c)	{	r-=c.r;	g-=c.g;	b-=c.b;	a-=c.a;	}
 };
-#ifndef SWIG
-inline mglColor operator+(const mglColor &a, const mglColor &b)
-{	return mglColor(a.r+b.r, a.g+b.g, a.b+b.b, a.a+b.a);	}
-inline mglColor operator-(const mglColor &a, const mglColor &b)
-{	return mglColor(a.r-b.r, a.g-b.g, a.b-b.b, a.a-b.a);	}
-inline mglColor operator*(const mglColor &a, float b)
-{	return mglColor(a.r*b, a.g*b, a.b*b, a.a*b);	}
-inline mglColor operator*(float b, const mglColor &a)
-{	return mglColor(a.r*b, a.g*b, a.b*b, a.a*b);	}
-inline mglColor operator/(const mglColor &a, float b)
-{	return mglColor(a.r/b, a.g/b, a.b/b, a.a/b);	}
-inline mglColor operator!(const mglColor &a)
-{	return mglColor(1-a.r, 1-a.g, 1-a.b, a.a);	}
-#endif
 //-----------------------------------------------------------------------------
-#endif
diff --git a/mathgl-2x.cbp b/mathgl-2x.cbp
index a958f50..40ea8f6 100644
--- a/mathgl-2x.cbp
+++ b/mathgl-2x.cbp
@@ -12,28 +12,28 @@
 				<Option object_output="obj/Release/" />
 				<Option type="1" />
 				<Option compiler="gcc" />
+				<Option parameters="-test" />
 				<Compiler>
 					<Add option="-I include/" />
 				</Compiler>
 			</Target>
 		</Build>
 		<Compiler>
-			<Add option="-march=core2" />
-			<Add option="-O3" />
-			<Add option="-O2" />
 			<Add option="-Wall" />
 			<Add option="-pg" />
 			<Add option="-g" />
 			<Add option="-fexceptions" />
+			<Add option="-DMGL_SRC" />
 		</Compiler>
 		<Linker>
 			<Add option="-pg" />
 			<Add option="-pg -lgsl -lgslcblas" />
 			<Add option="-lpng -ljpeg -lgif -lhpdf" />
-			<Add option="-lhdf5 -ldf -lmfhdf" />
+			<Add option="-lhdf5 -lmfhdf -ldf -lmfhdf" />
 		</Linker>
 		<Unit filename="build/include/mgl2/config.h" />
 		<Unit filename="examples/full_test.cpp" />
+		<Unit filename="examples/samples.cpp" />
 		<Unit filename="examples/wnd_samples.cpp" />
 		<Unit filename="include/mgl2/addon.h" />
 		<Unit filename="include/mgl2/base.h" />
@@ -44,6 +44,8 @@
 		<Unit filename="include/mgl2/cont.h" />
 		<Unit filename="include/mgl2/data.h" />
 		<Unit filename="include/mgl2/data_cf.h" />
+		<Unit filename="include/mgl2/datac.h" />
+		<Unit filename="include/mgl2/datac_cf.h" />
 		<Unit filename="include/mgl2/define.h" />
 		<Unit filename="include/mgl2/eval.h" />
 		<Unit filename="include/mgl2/evalc.h" />
@@ -53,23 +55,29 @@
 		<Unit filename="include/mgl2/glut.h" />
 		<Unit filename="include/mgl2/mgl.h" />
 		<Unit filename="include/mgl2/mgl_cf.h" />
+		<Unit filename="include/mgl2/mpi.h" />
 		<Unit filename="include/mgl2/opengl.h" />
 		<Unit filename="include/mgl2/other.h" />
 		<Unit filename="include/mgl2/parser.h" />
 		<Unit filename="include/mgl2/plot.h" />
 		<Unit filename="include/mgl2/prim.h" />
+		<Unit filename="include/mgl2/qmathgl.h" />
 		<Unit filename="include/mgl2/qt.h" />
 		<Unit filename="include/mgl2/surf.h" />
 		<Unit filename="include/mgl2/type.h" />
 		<Unit filename="include/mgl2/vect.h" />
 		<Unit filename="include/mgl2/volume.h" />
 		<Unit filename="include/mgl2/window.h" />
+		<Unit filename="include/mgl2/wnd.h" />
+		<Unit filename="include/mgl2/wx.h" />
 		<Unit filename="src/addon.cpp" />
 		<Unit filename="src/axis.cpp" />
 		<Unit filename="src/base.cpp" />
 		<Unit filename="src/base_cf.cpp" />
 		<Unit filename="src/canvas.cpp" />
 		<Unit filename="src/canvas_cf.cpp" />
+		<Unit filename="src/complex.cpp" />
+		<Unit filename="src/complex_io.cpp" />
 		<Unit filename="src/cont.cpp" />
 		<Unit filename="src/crust.cpp" />
 		<Unit filename="src/data.cpp" />
@@ -84,8 +92,10 @@
 		<Unit filename="src/export.cpp" />
 		<Unit filename="src/export_2d.cpp" />
 		<Unit filename="src/export_3d.cpp" />
+		<Unit filename="src/fft.cpp" />
 		<Unit filename="src/fit.cpp" />
 		<Unit filename="src/font.cpp" />
+		<Unit filename="src/obj.cpp" />
 		<Unit filename="src/other.cpp" />
 		<Unit filename="src/parser.cpp" />
 		<Unit filename="src/pde.cpp" />
@@ -108,6 +118,7 @@
 		<Unit filename="src/tex_table.cpp" />
 		<Unit filename="src/vect.cpp" />
 		<Unit filename="src/volume.cpp" />
+		<Unit filename="src/window.cpp" />
 		<Extensions>
 			<code_completion />
 			<envvars />
diff --git a/mgllab/editor.cpp b/mgllab/editor.cpp
index 89122e0..38de1eb 100644
--- a/mgllab/editor.cpp
+++ b/mgllab/editor.cpp
@@ -290,7 +290,8 @@ void load_file(char *newfile, int ipos)
 
 		char *t = textbuf->text();
 #ifndef WIN32
-		for(size_t i=0;i<strlen(t);i++)	if(t[i]=='\r')	t[i]=' ';
+		register size_t i,l=strlen(t);
+		for(i=0;i<l;i++)	if(t[i]=='\r')	t[i]=' ';
 		textbuf->text(t);
 #endif
 		fill_animate(t);	free(t);
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index be81d91..73b7eee 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,7 +1,7 @@
 set(mgl_src
 	addon.cpp axis.cpp base_cf.cpp base.cpp canvas_cf.cpp canvas.cpp cont.cpp crust.cpp
-	complex.cpp complex_io.cpp fft.cpp
-	data.cpp data_io.cpp data_new.cpp data_png.cpp def_font.cpp
+	complex.cpp complex_io.cpp fft.cpp data_gr.cpp
+	data.cpp data_io.cpp data_ex.cpp data_png.cpp def_font.cpp
 	export_2d.cpp export_3d.cpp eval.cpp evalp.cpp exec.cpp export.cpp
 	fit.cpp font.cpp obj.cpp other.cpp parser.cpp pde.cpp pixel.cpp
 	plot.cpp prim.cpp surf.cpp tex_table.cpp vect.cpp volume.cpp evalc.cpp
@@ -18,7 +18,8 @@ ${MathGL_BINARY_DIR}/include/mgl2/dllexport.h
 	../include/mgl2/data.h		../include/mgl2/volume.h	../include/mgl2/data_cf.h
 	../include/mgl2/define.h	../include/mgl2/other.h		../include/mgl2/eval.h
 	../include/mgl2/parser.h	../include/mgl2/addon.h		../include/mgl2/evalc.h
-	s_hull/s_hull_pro.h		../include/mgl2/wnd.h		../include/mgl2/canvas_wnd.h
+	s_hull/s_hull_pro.h			../include/mgl2/wnd.h		../include/mgl2/canvas_wnd.h
+	../include/mgl2/thread.h	../include/mgl2/abstract.h	../include/mgl2/pde.h
 )
 
 add_definitions(-DMGL_SRC)
@@ -53,10 +54,10 @@ else(enable-mgl2)
 	set_target_properties(mgl-static PROPERTIES OUTPUT_NAME "mgl")
 endif(enable-mgl2)
 
-if(MGL_HAVE_LTDL)
-	target_link_libraries(mgl ${LTDL_LIB})
-	include_directories(${LTDL_INCLUDE_DIR})
-endif(MGL_HAVE_LTDL)
+# if(MGL_HAVE_LTDL)
+# 	target_link_libraries(mgl ${LTDL_LIB})
+# 	include_directories(${LTDL_INCLUDE_DIR})
+# endif(MGL_HAVE_LTDL)
 
 if(MGL_HAVE_PDF)
 	include_directories(${HPDF_INCLUDE_DIR})
@@ -127,7 +128,7 @@ if(MGL_HAVE_MPI)
 #	include_directories(${MPI_C_INCLUDE_PATH})
 	include_directories(${MPI_CXX_INCLUDE_PATH})
 
-	set_target_properties(mgl-mpi PROPERTIES SOVERSION 7.0.0)
+	set_target_properties(mgl-mpi PROPERTIES SOVERSION ${MathGL_SOVERSION})
 	install(
 		TARGETS mgl-mpi mgl-mpi-static
 		RUNTIME DESTINATION bin
@@ -140,7 +141,7 @@ if(M_LIB)
 	target_link_libraries(mgl ${M_LIB})
 endif(M_LIB)
 
-set_target_properties(mgl PROPERTIES SOVERSION 7.0.0)
+set_target_properties(mgl PROPERTIES SOVERSION ${MathGL_SOVERSION})
 install(
 	TARGETS mgl mgl-static
 	RUNTIME DESTINATION bin
diff --git a/src/addon.cpp b/src/addon.cpp
index 1cd87bf..2d46c85 100644
--- a/src/addon.cpp
+++ b/src/addon.cpp
@@ -34,15 +34,16 @@ dual MGL_EXPORT mgl_expi(double a)	{	return dual(cos(a),sin(a));	}
 void MGL_EXPORT mgl_strcls(char *str)
 {
 	size_t len = strlen(str),i,n;
-	char *tmp = new char[len];
+	char *tmp = new char[len+1];	memset(tmp,0,len);
 	for(i=0;i<len;i++)
 	{
 		if(i<len-1 && str[i]==' ' && str[i+1]==' ')
 			continue;
 		tmp[i] = str[i];
 	}
-	for(n=0;n<strlen(tmp);n++)		if(tmp[n]!=' ')	break;
-	for(i=strlen(tmp)-1;i>0;i--)	if(tmp[i]!=' ')	break;
+	len = strlen(tmp);
+	for(n=0;n<len;n++)		if(tmp[n]!=' ')	break;
+	for(i=len-1;i>0;i--)	if(tmp[i]!=' ')	break;
 	tmp[i+1]=0;	strcpy(str,&(tmp[n]));
 	delete []tmp;
 }
@@ -67,16 +68,46 @@ int MGL_EXPORT mgl_chrpos(const char *str,char ch)
 //-----------------------------------------------------------------------------
 MGL_EXPORT char *mgl_fgetstr(FILE *fp)
 {
-	static char s[256];
+	const long size=10240;	// NOTE: this set maximal length of string to be read
+	static char s[size];
 	do
 	{
-		if(!fgets(s,256,fp))	break;
+		if(!fgets(s,size,fp))	break;
 		mgl_strtrim(s);
 		//		strlwr(s);
 	} while(!feof(fp) && (s[0]==0 || s[0]=='%' || s[0]=='#'));
+	for(long i=0;s[i];i++)	if(s[i]=='#')	{	s[i]=0;	break;	}
+	mgl_strtrim(s);
 	return s;
 }
 //-----------------------------------------------------------------------------
+void MGL_EXPORT mgl_fgetpar(FILE *fp, const char *str, ...)
+{
+	if(!str || !str[0])	return;
+	long len=strlen(str), *n;	double *v;
+	char *s, *t, *buf=new char[len+1];
+	memcpy(buf,str,len+1);
+	va_list lst;
+	va_start(lst,str);
+	t = mgl_fgetstr(fp);
+	for(long i=0;i<len;i++)
+	{
+		if(str[i]=='%')
+		{
+			if(str[i+1]=='s')	{	s = va_arg(lst, char*);	strcpy(s, t);	}
+			if(strchr("efg",str[i+1]))	{	v = va_arg(lst, double*);	*v = atof(t);	}
+			if(strchr("ld",str[i+1]))	{	n = va_arg(lst, long*); 	*n = atol(t);	}
+			i++;
+		}
+		if(str[i]==':')
+		{
+			for(;*t && *t!=':';t++);
+			if(*t==':')	t++;
+		}
+		if(str[i]<=' ')	t = mgl_fgetstr(fp);
+	}
+}
+//-----------------------------------------------------------------------------
 int MGL_EXPORT mgl_istrue(char ch)
 {	return (ch=='1' || ch=='t' || ch=='+' || ch=='v');	}
 //-----------------------------------------------------------------------------
@@ -116,7 +147,7 @@ MGL_EXPORT FILE *mgl_next_data(const char *fname,int p)
 	if(pos==0)	{	if(!getcwd(path,256))	return 0;	}	// remember ini dyrectory
 	else		{	if(chdir(path)==-1)		return 0;	}
 
-	// read the initial (common) date from "mbrs.ini"
+	// read the initial (common) data
 	FILE *fp=fopen(fname,"rt");
 	if(fp==NULL)	return NULL;
 	fseek(fp,0,SEEK_END);
@@ -139,14 +170,14 @@ MGL_EXPORT FILE *mgl_next_data(const char *fname,int p)
 //-----------------------------------------------------------------------------
 bool MGL_EXPORT mgl_difr_grid(dual *a,int n,dual q,int Border,dual *b,dual *d,int kk)
 {
-	register int i,k;
 	//	if(n<=0 || q>=0.5)	return false;
 	dual adt = dual(0.,1.)*q;
 
 	memcpy(b,a,n*sizeof(dual));
-	for(k=kk;k>0;k--)	// 3 iterations
+	for(long k=kk;k>0;k--)	// 3 iterations
 	{
-		for(i=1;i<n-1;i++)
+#pragma omp parallel for
+		for(long i=1;i<n-1;i++)
 			d[i] = a[i] + adt*(b[i-1]+b[i+1]-mreal(2)*b[i])/mreal(k);
 		memcpy(b,d,n*sizeof(dual));
 		switch(Border)
@@ -179,19 +210,20 @@ bool MGL_EXPORT mgl_difr_grid(dual *a,int n,dual q,int Border,dual *b,dual *d,in
 //-----------------------------------------------------------------------------
 bool MGL_EXPORT mgl_difr_axial(dual *a, int n, dual q, int Border,dual *b, dual *d, int kk, double di)
 {
-	register int i,k,ii = di<0 ? -int(floor(di)) : 0;
+	int ii = di<0 ? -int(floor(di)) : 0;
 	dual adt = dual(0.,1.)*q;
-	register mreal dd,ff= di==floor(di) ? 4. : 2.,gg;
+	register mreal ff= di==floor(di) ? 4. : 2.;
 
 	memcpy(b,a,n*sizeof(dual));
-	for(k=kk;k>0;k--)	// kk iterations
+	for(long k=kk;k>0;k--)	// kk iterations
 	{
 		d[ii] = a[ii] + adt*(b[ii+1]-b[ii])*(ff/k);
-		for(i=ii+1;i<n-1;i++)
+#pragma omp parallel for
+		for(long i=ii+1;i<n-1;i++)
 		{
-			dd = i+di;
+			register mreal dd = i+di;
 			dd = 1./(sqrt(dd*dd+1.)+dd);	// corrections for "axiality"
-			gg = 1+dd*dd;
+			register mreal gg = 1+dd*dd;
 			d[i] = a[i] + adt*( b[i-1]*((gg-dd)/k) -
 			b[i]*(2*gg/k) + b[i+1]*((gg+dd)/k) );
 		}
@@ -228,9 +260,10 @@ double MGL_EXPORT mgl_gauss_rnd()
 	return v1!=0 ? sqrt(-2.*log(v1))*cos(2*M_PI*v2) : 0;
 }
 //-----------------------------------------------------------------------------
-void MGL_EXPORT mgl_fft_freq(double *freq, size_t nn)
+void MGL_EXPORT mgl_fft_freq(double *freq, long nn)
 {
-	for(size_t i=0;i<=nn/2;i++)
+#pragma omp parallel for
+	for(long i=0;i<=nn/2;i++)
 	{
 		freq[i] = i;
 		if(i>0) freq[nn-i] = -(double)(i);
diff --git a/src/axis.cpp b/src/axis.cpp
index acbbd29..898e188 100644
--- a/src/axis.cpp
+++ b/src/axis.cpp
@@ -26,6 +26,7 @@
 #define islog(a, b) (((a)>0 && (b)>10*(a)) || ((b)<0 && (a)<10*(b)))
 // NOTE: I use <=0 for proper tick labels rotation. But this mirror labels for central origin!
 #define sign(a)	((a)<0 ? -1:1)
+//#define sign(a)	((a)<0 ? -1:((a)>0 ? 1:0))
 //-----------------------------------------------------------------------------
 MGL_NO_EXPORT inline struct tm *mgl_localtime (const time_t *clock, tm *result, bool use_utc)
 {	if (!clock || !result) return NULL;
@@ -41,13 +42,21 @@ long MGL_EXPORT mgl_have_color(const char *stl)
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_wcstrim(wchar_t *str)
 {
-	size_t n=wcslen(str), k, i;
+	if(!str || *str==0)	return;
+	size_t n=mgl_wcslen(str), k, i;
 	for(k=0;k<n;k++)	if(str[k]>' ')	break;
-	for(i=n;i>0;i--)	if(str[i-1]>' ')	break;
+	for(i=n;i>k;i--)	if(str[i-1]>' ')	break;
 	memmove(str, str+k, (i-k)*sizeof(wchar_t));
 	str[i-k]=0;
 }
 //-----------------------------------------------------------------------------
+size_t MGL_EXPORT mgl_wcslen(const wchar_t *str)
+{
+	long i=0;
+	if(str)	while(str[i])	i++;
+	return i;
+}
+//-----------------------------------------------------------------------------
 //		Ticks setup
 //-----------------------------------------------------------------------------
 void mglCanvas::SetAxisStl(const char *stl, const char *tck, const char *sub)
@@ -68,7 +77,7 @@ void mglCanvas::SetTicks(char dir, mreal d, int ns, mreal org)
 	if(!strchr("xyzca",dir))	return;
 	mglAxis &aa = (dir=='x' ? ax : (dir=='y' ? ay : (dir=='z' ? az : ac)));
 
-	if(aa.f==1)	aa.t[0]=0;
+	if(aa.f==1)	aa.t.clear();
 	aa.d=d;	aa.f=0;	aa.ns=ns;	aa.o=org;
 	aa.txt.clear();
 }
@@ -102,16 +111,12 @@ void mglCanvas::SetTicksVal(char dir, HCDT v, const wchar_t *lbl, bool add)
 //-----------------------------------------------------------------------------
 void mglCanvas::SetTicksVal(char dir, HCDT v, const char *lbl, bool add)
 {
-	long ll=mbstowcs(0,lbl,0)+1;
-	wchar_t *wcs = new wchar_t[ll];
-	mbstowcs(wcs,lbl,ll);
-	SetTicksVal(dir,v,wcs,add);
-	delete []wcs;
+	MGL_TO_WCS(lbl,SetTicksVal(dir,v,wcs,add));
 }
 //-----------------------------------------------------------------------------
 void mglCanvas::SetTicksVal(char dir, const wchar_t *lbl, bool add)
 {
-	register long i,j,len=wcslen(lbl);
+	register long i,j,len=mgl_wcslen(lbl);
 	for(i=0,j=1;j<len;j++)
 		if(lbl[j]=='\n' || (lbl[j]=='n' && lbl[j-1]=='\\'))	i++;
 	if(i>63)	i=63;
@@ -153,15 +158,7 @@ void mglCanvas::SetTicksVal(char dir, HCDT v, const char **lbl, bool add)
 	if(add)	{	UpdateAxis();	AdjustTicks(aa,ff);	}
 	if(!v || !lbl)	{	aa.f = 0;	return;	}
 	aa.f = 2;	aa.ns=0;	aa.ds=0;
-	register size_t i,n=v->GetNx(),l=0;
-	for(i=0;i<n;i++)	if(strlen(lbl[i])>l)	l=mbstowcs(0,lbl[i],0)+1;
-	wchar_t *str=new wchar_t[l+1];
-	for(i=0;i<n;i++)
-	{
-		mbstowcs(str,lbl[i],strlen(lbl[i])+1);
-		aa.AddLabel(str,v->v(i));
-	}
-	delete []str;
+	for(long i=0;i<v->GetNx();i++)	MGL_TO_WCS(lbl[i],aa.AddLabel(wcs,v->v(i)));
 }
 //-----------------------------------------------------------------------------
 void mglCanvas::SetTickTempl(char dir, const wchar_t *t)
@@ -170,8 +167,7 @@ void mglCanvas::SetTickTempl(char dir, const wchar_t *t)
 	mglAxis &aa = (dir=='x' ? ax : (dir=='y' ? ay : (dir=='z' ? az : ac)));
 
 	if(aa.f==1)	aa.f = 0;	// remove time ticks
-	if(!t || !t[0])	aa.t[0]=0;
-	else if(wcslen(t)<255) wcscpy(aa.t,t);
+	if(!t)	aa.t.clear();	else aa.t=t;
 }
 //-----------------------------------------------------------------------------
 void mglCanvas::SetTickTempl(char dir, const char *t)
@@ -180,8 +176,8 @@ void mglCanvas::SetTickTempl(char dir, const char *t)
 	mglAxis &aa = (dir=='x' ? ax : (dir=='y' ? ay : (dir=='z' ? az : ac)));
 
 	if(aa.f==1)	aa.f = 0;	// remove time ticks
-	if(!t || !t[0])	aa.t[0]=0;
-	else if(mbstowcs(0,t,0)<256) mbstowcs(aa.t,t,256);
+	if(!t || !t[0])	aa.t.clear();
+	else	MGL_TO_WCS(t,aa.t=wcs);
 }
 //-----------------------------------------------------------------------------
 MGL_NO_EXPORT double mgl_adj_val(double v,mreal *ds=0)
@@ -245,10 +241,10 @@ void mglCanvas::SetTickTime(char dir, mreal d, const char *t)
 	}
 
 	aa.ds = 0;	aa.dv = d;	aa.f = 1;	aa.txt.clear();
-	if(mbstowcs(0,t,0)<256) mbstowcs(aa.t,t,256);
+	MGL_TO_WCS(t,aa.t=wcs);
 
 	if(strchr("xyztuvw",aa.ch))
-		aa.org = mglPoint(GetOrgX(aa.ch), GetOrgY(aa.ch), GetOrgZ(aa.ch));
+		aa.org = mglPoint(GetOrgX(aa.ch,aa.inv), GetOrgY(aa.ch,aa.inv), GetOrgZ(aa.ch,aa.inv));
 	if(aa.ch=='x')	aa.v0 = aa.org.x;
 	if(aa.ch=='y')	aa.v0 = aa.org.y;
 	if(aa.ch=='z')	aa.v0 = aa.org.z;
@@ -262,13 +258,13 @@ void mglCanvas::SetTickTime(char dir, mreal d, const char *t)
 	if(v0+aa.dv!=v0 && v1+aa.dv!=v1)	for(v=v0;v<=v1;v+=aa.dv)
 	{
 		tt = v;	tm tp;		mgl_localtime(&tt, &tp, get(MGL_USE_GMTIME));
-		wcsftime(buf,64,aa.t,&tp);	aa.AddLabel(buf,v);
+		wcsftime(buf,64,aa.t.c_str(),&tp);	aa.AddLabel(buf,v);
 	}
 }
 //-----------------------------------------------------------------------------
 void mglCanvas::AdjustTicks(const char *dir, bool force)
 {
-	if(force)	SetTuneTicks(-1);
+	if(force)	SetTuneTicks(3);
 	UpdateAxis();
 	if(strchr(dir,'x') || strchr(dir,'X'))	// NOTE dir have to be non-NULL here !!!
 	{	if(force)	ax.d=0;	AdjustTicks(ax,fx!=0);	}
@@ -303,7 +299,7 @@ void mglCanvas::AdjustTicks(mglAxis &aa, bool ff)
 int MGL_NO_EXPORT mgl_tick_ext(mreal a, mreal b, wchar_t s[32], mreal &v)
 {
 	int kind = 0;
-	if(fabs(a-b)<=0.001*fabs(a))
+	if(fabs(a-b)<=0.01*fabs(a))
 	{
 		kind = 1;
 		v = fabs(a-b);
@@ -313,7 +309,7 @@ int MGL_NO_EXPORT mgl_tick_ext(mreal a, mreal b, wchar_t s[32], mreal &v)
 			kind=3;		v=mgl_ipow(10.,k);
 			mglprintf(s, 32, L" (@{\\times{}10^{%d}})", k);
 		}
-		if(v<0.02f)
+		else if(v<0.02f)
 		{
 			int k=int(log10(v)-0.01)-1;
 			kind=3;		v=mgl_ipow(10.,k);
@@ -330,7 +326,7 @@ int MGL_NO_EXPORT mgl_tick_ext(mreal a, mreal b, wchar_t s[32], mreal &v)
 			v=mgl_ipow(10.,k);
 			mglprintf(s, 32, L" \\times 10^{%d}", k);
 		}
-		if(v<=1e-3f)
+		else if(v<=1e-3f)
 		{
 			kind = 2;
 			int k=int(log10(v)-0.01)-1;
@@ -341,33 +337,50 @@ int MGL_NO_EXPORT mgl_tick_ext(mreal a, mreal b, wchar_t s[32], mreal &v)
 	return kind;
 }
 //-----------------------------------------------------------------------------
-void MGL_NO_EXPORT mgl_tick_text(mreal z, mreal z0, mreal d, mreal v, int kind, wchar_t str[64], bool tune)
+std::wstring MGL_NO_EXPORT mgl_format(mreal v1, mreal v2, bool zero)
+{
+	v1=fabs(v1);	v2=fabs(v2);	if(v1>v2)	v2=v1;
+	wchar_t str[5]=L"%.3g";
+	int prec=int(2-log10(v2));	if(prec<0)	prec=0;
+	if(v2<=0.001 || v2>=10000)
+	{	str[2] = '2';	str[3]='e';	}
+	else if(zero)
+	{	str[2] = '0'+prec;	str[3]='f';	}
+	return str;
+}
+//-----------------------------------------------------------------------------
+void MGL_NO_EXPORT mgl_tick_text(mreal z, mreal z0, mreal d, std::wstring fmt, mreal v, int kind, wchar_t str[64])
 {
 	mreal u = fabs(z)<d ? 0:z;
 	if((kind&1) && z>z0)	u = fabs(z-z0)<d ? 0:(z-z0);
 	if(kind==2 || (kind==3 && z>z0))	u /= v;
+	if(kind&1)	fmt = z>z0?L"@{(+"+fmt+L")}":L"%g";
+	mglprintf(str,64,fmt.c_str(), u);
+	
+/*	mreal u = fabs(z)<d ? 0:z;
+	if((kind&1) && z>z0)	u = fabs(z-z0)<d ? 0:(z-z0);
+	if(kind==2 || (kind==3 && z>z0))	u /= v;
 	if((kind&1) && z>z0)
 	{
 		size_t n1,n2;
 		mglprintf(str, 64, L"@{(+%.2g)}",u);
-//		mglprintf(str, 64, fabs(u)<1 ? L"@{(+%.2g)}" : L"@{(+%.3g)}",u);
-		n1=wcslen(str);	mglprintf(str, 64, L"@{(+%g)}",u);	n2=wcslen(str);
-//		if(n1<n2)	mglprintf(str, 64, fabs(u)<1 ? L"@{(+%.2g)}" : L"@{(+%.3g)}",u);
+		n1=mgl_wcslen(str);	mglprintf(str, 64, L"@{(+%g)}",u);	n2=mgl_wcslen(str);
 		if(n1<n2)	mglprintf(str, 64, L"@{(+%.2g)}",u);
 	}
 	else
 	{
 		size_t n1,n2;
-		mglprintf(str, 64, fabs(u)<1 ? L"%.2g" :  L"%.3g",u);
-		n1=wcslen(str);	mglprintf(str, 64, L"%g",u);	n2=wcslen(str);
-		if(n1<n2 && tune)	mglprintf(str, 64, fabs(u)<1 ? L"%.2g" :  L"%.3g",u);
-	}
+		mglprintf(str, 64, fabs(u)<1 ? L"%.2g" : L"%.3g",u);
+		n1=mgl_wcslen(str);	mglprintf(str, 64, L"%g",u);	n2=mgl_wcslen(str);
+		if(n1<n2 && tune)	mglprintf(str, 64, fabs(u)<1 ? L"%.2g" : L"%.3g",u);
+	} 
+*/
 }
 //-----------------------------------------------------------------------------
 void mglCanvas::LabelTicks(mglAxis &aa)
 {
 	if(strchr("xyztuvw",aa.ch))
-		aa.org = mglPoint(GetOrgX(aa.ch), GetOrgY(aa.ch), GetOrgZ(aa.ch));
+		aa.org = mglPoint(GetOrgX(aa.ch,aa.inv), GetOrgY(aa.ch,aa.inv), GetOrgZ(aa.ch,aa.inv));
 	if(aa.ch=='x')	aa.v0 = aa.org.x;
 	if(aa.ch=='y')	aa.v0 = aa.org.y;
 	if(aa.ch=='z')	aa.v0 = aa.org.z;
@@ -409,7 +422,7 @@ void mglCanvas::LabelTicks(mglAxis &aa)
 	{
 		int kind=0;
 		wchar_t s[32]=L"";
-		if(aa.t[0]==0 && TuneTicks) kind = mgl_tick_ext(aa.v2, aa.v1, s, w);
+		if(aa.t.empty() && TuneTicks) kind = mgl_tick_ext(aa.v2, aa.v1, s, w);
 		if((TuneTicks&1)==0 && kind==2)	kind=0;
 		if((TuneTicks&2)==0 && kind!=2)	kind=0;
 
@@ -419,12 +432,21 @@ void mglCanvas::LabelTicks(mglAxis &aa)
 		else
 		{	v1 = aa.v1;		v0 = v0 - aa.dv*floor((v0-aa.v2)/aa.dv+1e-3);	}
 
+		std::wstring fmt;
+		switch(kind)
+		{
+			case 1:	fmt=mgl_format(0,v1-v0,TuneTicks&4);	break;
+			case 2:	fmt=mgl_format(v0/w,v1/w,TuneTicks&4);	break;
+			case 3:	fmt=mgl_format(0,(v1-v0)/w,TuneTicks&4);break;
+			default:fmt=mgl_format(v0,v1,TuneTicks&4);	break;
+		}
+
 		if(v0+aa.dv!=v0 && v1+aa.dv!=v1)	for(v=v0;v<=v1;v+=aa.dv)
 		{
-			if(aa.t[0])
-				mglprintf(buf, 64, aa.t, fabs(v)<aa.dv/100 ? 0 : v);
+			if(aa.t.empty())
+				mgl_tick_text(v,v0,aa.dv/100,fmt,w,kind,buf);
 			else
-				mgl_tick_text(v,v0,aa.dv/100,w,kind,buf,TuneTicks);
+				mglprintf(buf, 64, aa.t.c_str(), fabs(v)<aa.dv/100 ? 0 : v);
 			mgl_wcstrim(buf);	aa.AddLabel(buf,v);
 		}
 		if(kind&2)	aa.AddLabel(s,FactorPos*(aa.v2-aa.v1)+aa.v1);
@@ -433,16 +455,18 @@ void mglCanvas::LabelTicks(mglAxis &aa)
 //-----------------------------------------------------------------------------
 void mglCanvas::Axis(const char *dir, const char *stl, const char *opt)
 {
-	if(!dir || !dir[0])	dir="xyz";
-	bool text = !strchr(dir,'_');
+	bool text = !mglchr(dir,'_');
+	bool inv = mglchr(dir,'^');
+	bool adjust = mglchr(stl,'a');
+	bool ret = get(MGL_ENABLE_RTEXT);
+	if(mglchr(dir,'U'))	clr(MGL_ENABLE_RTEXT);
+
 	const char *ar = "AKDTVISO";
 	char arr=0;
 	for(size_t i=0;i<strlen(ar);i++)
 		if(strchr(dir,ar[i]))	{	arr=ar[i];	break;	}
-	bool adjust = mglchr(stl,'a');
+	if(!mglchrs(dir,"xXyYzZ"))	dir="xyz";
 
-	bool ret = get(MGL_ENABLE_RTEXT);
-	if(strchr(dir,'U'))	clr(MGL_ENABLE_RTEXT);
 	SaveState(opt);
 	AdjustTicks(dir,adjust);
 	LoadState();
@@ -450,8 +474,12 @@ void mglCanvas::Axis(const char *dir, const char *stl, const char *opt)
 	ax.pos = strchr(dir,'X') ? 'T':'t';
 	ay.pos = strchr(dir,'Y') ? 'T':'t';
 	az.pos = strchr(dir,'Z') ? 'T':'t';
-	if(strchr(dir,'X') || strchr(dir,'x'))	DrawAxis(ax, text, arr, stl, opt);
-	if(strchr(dir,'Z') || strchr(dir,'z'))	DrawAxis(az, text, arr, stl, opt);
+	ax.inv = ay.inv = az.inv = false;
+
+	if(strchr(dir,'X') || strchr(dir,'x'))
+	{	ax.inv = inv;	DrawAxis(ax, text, arr, stl, opt);	}
+	if(strchr(dir,'Z') || strchr(dir,'z'))
+	{	az.inv = inv;	DrawAxis(az, text, arr, stl, opt);	}
 	if((TernAxis&3))
 	{
 		mglAxis ty(ay);		ty.pos='t';	ty.ch='T';
@@ -460,7 +488,8 @@ void mglCanvas::Axis(const char *dir, const char *stl, const char *opt)
 		ty.dir = mglPoint(0,-1);		ty.org = mglPoint(0,1,ay.org.z);
 		DrawAxis(ty, text, arr, stl, opt);
 	}
-	else if(strchr(dir,'Y') || strchr(dir,'y')) 	DrawAxis(ay, text, arr, stl, opt);
+	else if(strchr(dir,'Y') || strchr(dir,'y'))
+	{	ay.inv = inv;	DrawAxis(ay, text, arr, stl, opt);	}
 	set(ret, MGL_ENABLE_RTEXT);
 }
 //-----------------------------------------------------------------------------
@@ -468,7 +497,7 @@ void mglCanvas::DrawAxis(mglAxis &aa, bool text, char arr,const char *stl,const
 {
 	SaveState(opt);
 	if(strchr("xyz",aa.ch))
-		aa.org = mglPoint(GetOrgX(aa.ch), GetOrgY(aa.ch), GetOrgZ(aa.ch));
+		aa.org = mglPoint(GetOrgX(aa.ch,aa.inv), GetOrgY(aa.ch,aa.inv), GetOrgZ(aa.ch,aa.inv));
 	if(aa.ch=='x')	aa.v0 = aa.org.x;
 	if(aa.ch=='y')	aa.v0 = aa.org.y;
 	if(aa.ch=='z')	aa.v0 = aa.org.z;
@@ -480,52 +509,60 @@ void mglCanvas::DrawAxis(mglAxis &aa, bool text, char arr,const char *stl,const
 	da = aa.a*(dv*aa.a);	db = aa.b*(dv*aa.b);
 	if(aa.v2<aa.v1)	{	da *= -1;	db *= -1;	}
 
-	register long i,j,k1,k2;
-	SetPenPal(mgl_have_color(stl) ? stl:AxisStl);
+	long k1,k2;
+	bool have_color=mgl_have_color(stl);
+	bool dif_color = !have_color && aa.dv==0 && strcmp(TickStl,SubTStl);
+	SetPenPal(have_color ? stl:AxisStl);
 	static int cgid=1;	StartGroup("Axis",cgid++);
-	
-	p = o + d*aa.v1;	k1 = AddPnt(p,CDef,q,-1,3);
-	for(i=1;i<31;i++)	// axis itself
+
+	p = o + d*aa.v1;	k1 = AddPnt(&B, p,CDef,q,-1,3);
+	for(long i=1;i<31;i++)	// axis itself
 	{
 		p = o + d*(aa.v1+(aa.v2-aa.v1)*i/30.);
-		k2 = k1;	k1 = AddPnt(p,CDef,q,-1,3);
+		k2 = k1;	k1 = AddPnt(&B, p,CDef,q,-1,3);
 		line_plot(k2,k1);
 	}
 	if(arr)
 	{
 		p = o + d*(aa.v1+(aa.v2-aa.v1)*1.05);
-		k2 = k1;	k1 = AddPnt(p,CDef,q,-1,3);
-		arrow_plot(k1,k2,arr);
+		k2 = k1;	k1 = AddPnt(&B, p,CDef,q,-1,3);
+		line_plot(k1,k2);	arrow_plot(k1,k2,arr);
 	}
 
 	k2 = aa.txt.size();
 	mreal v, u, v0 = mgl_isnan(aa.o) ? aa.v0 : aa.o;
-	if(k2>0)	for(i=0;i<k2;i++)
+	if(*TickStl && !have_color)	SetPenPal(TickStl);
+	if(k2>0)	for(long i=0;i<k2;i++)
 	{
 		v = aa.txt[i].val;	u = fabs(v);
-		if((v-aa.v2)*(v-aa.v1)<=0)	tick_draw(o+d*v, da, db, 0, stl);
+		if((v-aa.v2)*(v-aa.v1)<=0)	tick_draw(o+d*v, da, db, 0);
+		if(dif_color)	SetPenPal(SubTStl);
 		if(aa.dv==0 && aa.v2>aa.v1 && fabs(u-exp(M_LN10*floor(0.1+log10(u))))<0.01*u)
-			for(j=2;j<10 && v*j<aa.v2;j++)	tick_draw(o+d*(v*j),da,db,1,stl);
+			for(long j=2;j<10 && v*j<aa.v2;j++)	tick_draw(o+d*(v*j),da,db,1);
 		if(aa.dv==0 && aa.v2<aa.v1 && fabs(u-exp(M_LN10*floor(0.1+log10(u))))<0.01*u)
-			for(j=2;j<10 && v*j<aa.v1;j++)	tick_draw(o+d*(v*j),da,db,1,stl);
+			for(long j=2;j<10 && v*j<aa.v1;j++)	tick_draw(o+d*(v*j),da,db,1);
+		if(dif_color)	SetPenPal(TickStl);
 	}
 	if(aa.ds>0 && !get(MGL_NOSUBTICKS))
 	{
 		if(aa.v2>aa.v1)	v0 = v0 - aa.ds*floor((v0-aa.v1)/aa.ds+1e-3);
 		else			v0 = v0 - aa.ds*floor((v0-aa.v2)/aa.ds+1e-3);
 		if(v0+aa.ds!=v0 && aa.v2+aa.ds!=aa.v2)
+		{
+			if(*SubTStl && !have_color)	SetPenPal(SubTStl);
 			for(v=v0;(v-aa.v2)*(v-aa.v1)<=0;v+=aa.ds)
-				tick_draw(o+d*v,da,db,1,stl);
+				tick_draw(o+d*v,da,db,1);
+		}
 	}
-	SetPenPal(mgl_have_color(stl) ? stl:AxisStl);
+	if(!have_color)	SetPenPal(AxisStl);
 	if(text)	DrawLabels(aa);
 	EndGroup();
 }
 //-----------------------------------------------------------------------------
-void mglCanvas::DrawLabels(mglAxis &aa)
+void mglCanvas::DrawLabels(mglAxis &aa, bool inv)
 {
 	if(strchr("xyz",aa.ch))
-		aa.org = mglPoint(GetOrgX(aa.ch), GetOrgY(aa.ch), GetOrgZ(aa.ch));
+		aa.org = mglPoint(GetOrgX(aa.ch,aa.inv), GetOrgY(aa.ch,aa.inv), GetOrgZ(aa.ch,aa.inv));
 	mglPoint d = aa.dir, o = aa.org;	// "transverse" org
 	if(strchr("xyz",aa.ch))	o -= d*(o*d);
 	mglPoint p,q, s=(Min+Max)/2, nn;
@@ -540,7 +577,7 @@ void mglCanvas::DrawLabels(mglAxis &aa)
 	for(i=0;i<n;i++)
 	{
 		w[i] = TextWidth(aa.txt[i].text.c_str(),FontDef,-1);
-		kk[i] = AddPnt(o+d*aa.txt[i].val,-1,d,0,7);
+		kk[i] = AddPnt(&B, o+d*aa.txt[i].val,-1,d,0,7);
 	}
 
 	for(l=0,c=1e7,i=0;i<n-1;i++)
@@ -548,33 +585,36 @@ void mglCanvas::DrawLabels(mglAxis &aa)
 		// exclude factors
 		if(aa.ch!='c' && (aa.txt[i].val<aa.v1 || aa.txt[i+1].val<aa.v1 || aa.txt[i].val>aa.v2 || aa.txt[i+1].val>aa.v2))
 			continue;
+		if(kk[i]<0 || kk[i+1]<0)	continue;
 		v = (GetPntP(kk[i+1])-GetPntP(kk[i])).norm();	// distance between ticks
 		vv = (w[i]+w[i+1])/2;	// length of labels
 		if(v>0 && l < vv/v)	l = vv/v;
 		if(c>v)	c = v;
 	}
 	if(get(MGL_ENABLE_RTEXT) && get(MGL_TICKS_ROTATE) && l>1 && c>0)	// try rotate first
-	{	tet = c>1.1*h ? asin(1.1*h/c) : M_PI/2;	pos[2]=aa.ch=='c'?'R':'L';
+	{	tet = c>1.1*h ? asin(1.1*h/c) : M_PI/2;	pos[2]=(aa.ch=='c' && !inv)?'R':'L';
 		l=0.99*h/sin(tet)/c;	for(i=0;i<n;i++)	w[i]=l*c;	}
 	// TODO: do clever points exclusion (i.e. longest and so on)
 	long k = get(MGL_TICKS_SKIP) ? 1+l : 1;
 	if(n>0)	for(i=0;i<n;i++)
 	{
-		if(kk[i]<0)	continue;	// should be never here?!
+		if(kk[i]<0)	continue;
 		c = aa.txt[i].val;
 		if(get(MGL_NO_ORIGIN) && c==aa.v0)	continue;
 		if(c>aa.v1 && c<aa.v2 && i%k!=0)	continue;
-		p = o+d*c;	nn = (s-o)/(Max-Min);	ScalePoint(p,nn);
+		p = o+d*c;	nn = (s-o)/(Max-Min);	ScalePoint(&B,p,nn);
 		mglPnt &qq = Pnt[kk[i]];
 		mreal ux=qq.u*cos(tet) + qq.v*sin(tet), uy=qq.v*cos(tet) - qq.u*sin(tet);
+		if(ux==0)	uy = fabs(uy);
 		qq.u = ux;	qq.v = uy;
 
-		if((!get(MGL_ENABLE_RTEXT) || tet) && nn.x!=0)	pos[2] = nn.x<0 ? 'L':'R';
+		if((!get(MGL_ENABLE_RTEXT) || tet) && nn.x!=0 && aa.ch!='c')	pos[2] = nn.x<0 ? 'L':'R';
 //		if(tet && nn.x==0)	pos[2] = 'R';
 		if(aa.ch=='c' && aa.txt[i].text[0]==' ')	qq.u = qq.v = NAN;
 		int ts = 1;
 		if(!get(MGL_DISABLE_SCALE))	ts = sign(qq.v*nn.x-qq.u*nn.y)*sign(aa.v2-aa.v1);
-		if(aa.ch=='c')	ts=(aa.ns==0 || aa.ns==3)?1:-1;
+		if(aa.ch=='c')	ts=inv?-1:1;	// use manual settings by inv argument
+//		else if(ux==0 && uy<0)	ts *= -1;
 		if(aa.ch=='T')	ts *= -1;
 		if(aa.pos=='T')	ts *= -1;
 		pos[0] = ts>0 ? 't':'T';
@@ -587,7 +627,7 @@ void mglCanvas::DrawLabels(mglAxis &aa)
 char mglCanvas::GetLabelPos(mreal c, long kk, mglAxis &aa)
 {
 	if(strchr("xyz",aa.ch))
-		aa.org = mglPoint(GetOrgX(aa.ch), GetOrgY(aa.ch), GetOrgZ(aa.ch));
+		aa.org = mglPoint(GetOrgX(aa.ch,aa.inv), GetOrgY(aa.ch,aa.inv), GetOrgZ(aa.ch,aa.inv));
 	mglPoint d = aa.dir, o = aa.org;	// "transverse" org
 	if(strchr("xyz",aa.ch))	o -= d*(o*d);
 	mglPoint p,q, s=(Min+Max)/2, nn;
@@ -596,10 +636,10 @@ char mglCanvas::GetLabelPos(mreal c, long kk, mglAxis &aa)
 	int ts = 1;
 	if(aa.ch=='c')	ts=(aa.ns==0 || aa.ns==3)?1:-1;
 	if(aa.ch=='T')	ts=-1;
-	
-	p = o+d*c;	nn = (s-o)/(Max-Min);	ScalePoint(p,nn);
+
+	p = o+d*c;	nn = (s-o)/(Max-Min);	ScalePoint(&B,p,nn);
 	mglPnt &qq = Pnt[kk];
-	
+
 	if(aa.ch=='c')	qq.u = qq.v = NAN;
 	if(!get(MGL_DISABLE_SCALE))	ts = sign(qq.v*nn.x-qq.u*nn.y)*sign(aa.v2-aa.v1);
 	if(aa.ch=='T')	ts *= -1;
@@ -607,7 +647,7 @@ char mglCanvas::GetLabelPos(mreal c, long kk, mglAxis &aa)
 	return ts>0 ? 't':'T';
 }
 //-----------------------------------------------------------------------------
-void mglCanvas::tick_draw(mglPoint o, mglPoint d1, mglPoint d2, int f, const char *stl)
+void mglCanvas::tick_draw(mglPoint o, mglPoint d1, mglPoint d2, int f)
 {
 	if(TickLen==0)	return;
 	// try to exclude ticks out of axis range
@@ -615,16 +655,12 @@ void mglCanvas::tick_draw(mglPoint o, mglPoint d1, mglPoint d2, int f, const cha
 		return;
 	mreal v = font_factor*TickLen/sqrt(1.f+f*st_t);
 	mglPoint p=o;
-	long k1,k2,k3=mgl_have_color(stl);
 
-	if(*TickStl && !f)	SetPenPal(k3 ? stl:TickStl);
-	if(*SubTStl && f)	SetPenPal(k3 ? stl:SubTStl);
-
-	ScalePoint(o, d1, false);	d1.Normalize();
-	ScalePoint(p, d2, false);	d2.Normalize();
-	k2 = AddPnt(p, CDef, mglPoint(NAN), 0, 0);
-	p += d1*v;	k1 = AddPnt(p, CDef, mglPoint(NAN), 0, 0);
-	p = o+d2*v;	k3 = AddPnt(p, CDef, mglPoint(NAN), 0, 0);
+	ScalePoint(&B,o, d1, false);	d1.Normalize();
+	ScalePoint(&B,p, d2, false);	d2.Normalize();
+	long k2 = AddPnt(&B, p, CDef, mglPoint(NAN), 0, 0);
+	long k1 = AddPnt(&B, p+d1*v, CDef, mglPoint(NAN), 0, 0);
+	long k3 = AddPnt(&B, p+d2*v, CDef, mglPoint(NAN), 0, 0);
 	line_plot(k1,k2);	line_plot(k2,k3);
 }
 //-----------------------------------------------------------------------------
@@ -651,7 +687,7 @@ void mglCanvas::DrawGrid(mglAxis &aa)
 	memcpy(oo,pp,8*sizeof(mglPoint));
 	for(int i=0;i<8;i++)	// find deepest point
 	{
-		ScalePoint(pp[i],nan,false);
+		ScalePoint(&B,pp[i],nan,false);
 		if(pp[i].z<zm)	{	zm=pp[i].z;	org=oo[i];	}
 	}
 	if(Org.x==Org.x) 	org.x = Org.x;
@@ -669,21 +705,21 @@ void mglCanvas::DrawGrid(mglAxis &aa)
 	if(n>0)	for(i=0;i<n;i++)
 	{
 		q = oa+d*aa.txt[i].val;	p = q+da1;	// lines along 'a'
-		k1 = AddPnt(p,CDef);
+		k1 = AddPnt(&B, p,CDef);
 		for(j=1;j<31;j++)
 		{
 			v = j/30.;
 			p = q+da1*(1-v)+da2*v;
-			k2 = k1;	k1 = AddPnt(p,CDef);
+			k2 = k1;	k1 = AddPnt(&B, p,CDef);
 			line_plot(k2,k1);
 		}
 		q = ob+d*aa.txt[i].val;	p = q+db1;	// lines along 'b'
-		k1 = AddPnt(p,CDef);
+		k1 = AddPnt(&B, p,CDef);
 		for(j=1;j<31;j++)
 		{
 			v = j/30.;
 			p = q+db1*(1-v)+db2*v;
-			k2 = k1;	k1 = AddPnt(p,CDef);
+			k2 = k1;	k1 = AddPnt(&B, p,CDef);
 			line_plot(k2,k1);
 		}
 	}
@@ -691,18 +727,12 @@ void mglCanvas::DrawGrid(mglAxis &aa)
 //-----------------------------------------------------------------------------
 void mglCanvas::Label(char dir, const char *str, mreal pos, const char *opt)
 {
-	size_t s = mbstowcs(0,str,0)+1;
-	wchar_t *wcs = new wchar_t[s];
-	mbstowcs(wcs,str,s);
-	Labelw(dir, wcs, pos, opt);
-	delete []wcs;
+	MGL_TO_WCS(str,Labelw(dir, wcs, pos, opt));
 }
 //-----------------------------------------------------------------------------
 void mglCanvas::Labelw(char dir, const wchar_t *text, mreal pos, const char *opt)
 {
-	mreal shift =  SaveState(opt);	if(mgl_isnan(shift))	shift=0;
-	mreal t=0, x0, y0, z0;
-	x0 = GetOrgX(dir);	y0 = GetOrgY(dir);	z0 = GetOrgZ(dir);
+	mreal shift =  SaveState(opt), t=0;	if(mgl_isnan(shift))	shift=0;
 	mglPoint p,q;
 	mglAxis *aa=0;
 
@@ -713,14 +743,16 @@ void mglCanvas::Labelw(char dir, const wchar_t *text, mreal pos, const char *opt
 		AdjustTicks(ax,fx!=0);	aa = &ax;
 		if(ax.dv)	t = (Min.x+Max.x+pos*(Max.x-Min.x))/2;
 		else	t = Min.x*pow(Max.x/Min.x, (pos+1)/2);
-		p = mglPoint(t,y0,z0);	q = mglPoint(1,0,0);	shift += ax.sh;
+		p = mglPoint(t, GetOrgY(ax.ch,ax.inv), GetOrgZ(ax.ch,ax.inv));
+		q = mglPoint(1,0,0);	shift += ax.sh;
 	}
 	if(dir=='y' && !(TernAxis&3))
 	{
 		AdjustTicks(ay,fy!=0);	aa = &ay;
 		if(ay.dv)	t = (Min.y+Max.y+pos*(Max.y-Min.y))/2;
 		else	t = Min.y*pow(Max.y/Min.y, (pos+1)/2);
-		p = mglPoint(x0,t,z0);	q = mglPoint(0,1,0);	shift += ay.sh;
+		p = mglPoint(GetOrgX(ay.ch,ay.inv), t, GetOrgZ(ay.ch,ay.inv));
+		q = mglPoint(0,1,0);	shift += ay.sh;
 		if(TernAxis&3)
 		{
 			q = mglPoint(-1,1,0);	pos=-pos;
@@ -732,7 +764,8 @@ void mglCanvas::Labelw(char dir, const wchar_t *text, mreal pos, const char *opt
 		AdjustTicks(ty,fy!=0);	aa = &ty;
 		if(ty.dv)	t = (Min.y+Max.y+pos*(Max.y-Min.y))/2;
 		else	t = Min.y*pow(Max.y/Min.y, (pos+1)/2);
-		p = mglPoint(x0,t,z0);	q = mglPoint(0,1,0);	shift += ty.sh;
+		p = mglPoint(GetOrgX(ty.ch,ty.inv), t, GetOrgZ(ty.ch,ty.inv));
+		q = mglPoint(0,1,0);	shift += ty.sh;
 		if(TernAxis&3)
 		{
 			q = mglPoint(-1,1,0);	pos=-pos;
@@ -744,21 +777,26 @@ void mglCanvas::Labelw(char dir, const wchar_t *text, mreal pos, const char *opt
 		AdjustTicks(ty,fy!=0);	pos = -pos;	aa = &ty;
 		if(ty.dv)	t = (Min.y+Max.y+pos*(Max.y-Min.y))/2;
 		else	t = Min.y*pow(Max.y/Min.y, (pos+1)/2);
-		p = mglPoint(x0,t,z0);	q = mglPoint(0,1,0);	shift += ty.sh;
+		p = mglPoint(GetOrgX(ty.ch,ty.inv), t, GetOrgZ(ty.ch,ty.inv));
+		q = mglPoint(0,1,0);	shift += ty.sh;
 	}
 	if(dir=='z')
 	{
 		AdjustTicks(az,fz!=0);	aa = &az;
 		if(az.dv)	t = (Min.z+Max.z+pos*(Max.z-Min.z))/2;
 		else	t = Min.z*pow(Max.z/Min.z, (pos+1)/2);
-		p = mglPoint(x0,y0,t);	q = mglPoint(0,0,1);	shift += az.sh;
-	}
-	char font[64],ff[3]=":C";	memset(font,0,64);
-	if(pos<-0.2)	ff[1]='L';	if(pos>0.2)	ff[1]='R';
-	strncpy(font,FontDef,63);	strcat(font,ff);
-	long kk = AddPnt(p,-1,q,0,7);	ff[1]=0;
-	ff[0] = GetLabelPos(t, kk, *aa);	strcat(font,ff);
-	text_plot(kk,text,font,-1.4,0.35+shift);
+		p = mglPoint(GetOrgX(az.ch,az.inv), GetOrgY(az.ch,az.inv), t);
+		q = mglPoint(0,0,1);	shift += az.sh;
+	}
+	if(aa)
+	{
+		char font[64],ff[3]=":C";	memset(font,0,64);
+		if(pos<-0.2)	ff[1]='L';	if(pos>0.2)	ff[1]='R';
+		strncpy(font,FontDef,63);	strcat(font,ff);
+		long kk = AddPnt(&B, p,-1,q,0,7);	ff[1]=0;
+		ff[0] = GetLabelPos(t, kk, *aa);	strcat(font,ff);
+		text_plot(kk,text,font,-1.4,0.35+shift);
+	}
 	LoadState();
 }
 //-----------------------------------------------------------------------------
@@ -772,8 +810,10 @@ void mglCanvas::Box(const char *col, bool ticks)
 	Axis("xyz_",col);
 	if(TernAxis&1)
 	{
-		Org.z=Max.z;	Org.x=Max.x;	Axis("xz_",col);
-		Org.x=Min.x;	Org.y=Max.y;	Axis("z_",col);
+		Org.x=Max.x;	Org.y=Min.y;	Org.z=Max.z;
+		DrawAxis(ax, false, 0,col);	DrawAxis(az, false, 0,col);
+		Org.x=Min.x;	Org.y=Max.y;	Org.z=Max.z;
+		DrawAxis(az, false, 0,col);
 
 		mglAxis ty(ay);				ty.ch='T';
 		ty.dir = mglPoint(-1,1);	ty.org = mglPoint(1,0,Max.z);
@@ -808,7 +848,7 @@ void mglCanvas::Box(const char *col, bool ticks)
 			memcpy(oo,p,8*sizeof(mglPoint));
 			for(int i=0;i<8;i++)	// find deepest point
 			{
-				ScalePoint(p[i],nan,false);
+				ScalePoint(&B,p[i],nan,false);
 				if(p[i].z<zm)	{	zm=p[i].z;	im=i;	}
 			}
 			// now draw faces
@@ -831,11 +871,12 @@ void mglCanvas::Box(const char *col, bool ticks)
 void mglCanvas::Colorbar(const char *sch)
 {
 	bool in = mglchr(sch,'I');
-	mreal s=1/B.pf, x=1, y=0;
-	if(mglchr(sch,'>'))	{	x=in?(1+s)/2:1;	y=0;	}
-	if(mglchr(sch,'<'))	{	x=in?(1-s)/2:0;	y=0;	}
-	if(mglchr(sch,'^'))	{	x=0;	y=in?(1+s)/2:1;	}
-	if(mglchr(sch,'_'))	{	x=0;	y=in?(1-s)/2:0;	}
+	mreal sx = (fabs(B.b[0])+fabs(B.b[1])+fabs(B.b[2]))/B.pf/B1.b[0], x=1;
+	mreal sy = (fabs(B.b[3])+fabs(B.b[4])+fabs(B.b[5]))/B.pf/B1.b[4], y=0;
+	if(mglchr(sch,'>'))	{	x=in?(1+sx)/2:1;	y=0;	}
+	if(mglchr(sch,'<'))	{	x=in?(1-sx)/2:0;	y=0;	}
+	if(mglchr(sch,'^'))	{	x=0;	y=in?(1+sy)/2:1;	}
+	if(mglchr(sch,'_'))	{	x=0;	y=in?(1-sy)/2:0;	}
 	Colorbar(sch, x, y, 1, 1);
 }
 //-----------------------------------------------------------------------------
@@ -866,11 +907,12 @@ void mglCanvas::Colorbar(const char *sch, mreal x, mreal y, mreal w, mreal h)
 void mglCanvas::Colorbar(HCDT v, const char *sch)
 {
 	bool in = mglchr(sch,'I');
-	mreal s=1/B.pf, x=1, y=0;
-	if(mglchr(sch,'>'))	{	x=in?(1+s)/2:1;	y=0;	}
-	if(mglchr(sch,'<'))	{	x=in?(1-s)/2:0;	y=0;	}
-	if(mglchr(sch,'^'))	{	x=0;	y=in?(1+s)/2:1;	}
-	if(mglchr(sch,'_'))	{	x=0;	y=in?(1-s)/2:0;	}
+	mreal sx = (fabs(B.b[0])+fabs(B.b[1])+fabs(B.b[2]))/B.pf/B1.b[0], x=1;
+	mreal sy = (fabs(B.b[3])+fabs(B.b[4])+fabs(B.b[5]))/B.pf/B1.b[4], y=0;
+	if(mglchr(sch,'>'))	{	x=in?(1+sx)/2:1;	y=0;	}
+	if(mglchr(sch,'<'))	{	x=in?(1-sx)/2:0;	y=0;	}
+	if(mglchr(sch,'^'))	{	x=0;	y=in?(1+sy)/2:1;	}
+	if(mglchr(sch,'_'))	{	x=0;	y=in?(1-sy)/2:0;	}
 	Colorbar(v, sch, x, y, 1, 1);
 }
 //-----------------------------------------------------------------------------
@@ -898,14 +940,16 @@ void mglCanvas::Colorbar(HCDT v, const char *sch, mreal x, mreal y, mreal w, mre
 void mglCanvas::colorbar(HCDT vv, const mreal *c, int where, mreal x, mreal y, mreal w, mreal h)
 {
 	static int cgid=1;	StartGroup("Colorbar",cgid++);
-	register size_t i,n=vv->GetNx();
+	long n=vv->GetNx();
 	long n1,n2,n3,n4;
 	mreal d,s3=B.pf,ss=1/s3;		// NOTE: colorbar was wider ss=0.9;
 	mglPoint p1,p2;
+	mglMatrix M=B1;	M.pf=s3;
 
-	Push();	set(MGL_DISABLE_SCALE);	B=B1;	B.pf=s3;
+	set(MGL_DISABLE_SCALE);		// NOTE this make colorbar non-thread-safe!!!
 	x = s3*(2*x-1);	y = s3*(2*y-1);	w *= s3;	h *= s3;
-	for(i=0;i<n-1;i++)
+	mask = MGL_SOLID_MASK;
+	for(long i=0;i<n-1;i++)
 	{
 		d = GetA(vv->v(i))*2-1;
 		p1 = p2 = mglPoint((ss*d+1)*w+x, (ss*d+1)*h+y, s3);
@@ -916,7 +960,7 @@ void mglCanvas::colorbar(HCDT vv, const mreal *c, int where, mreal x, mreal y, m
 			case 3:	p1.y = y;	p2.y = y+0.1*h;	break;
 			default:p1.x = x-0.1*w;	p2.x = x;	break;
 		}
-		n1 = AddPnt(p1,c[i]);	n2 = AddPnt(p2,c[i]);
+		n1 = AddPnt(&M, p1,c[i]);	n2 = AddPnt(&M, p2,c[i]);
 		d = GetA(vv->v(i+1))*2-1;
 		p1 = p2 = mglPoint((ss*d+1)*w+x, (ss*d+1)*h+y, s3);
 		switch(where)
@@ -926,23 +970,23 @@ void mglCanvas::colorbar(HCDT vv, const mreal *c, int where, mreal x, mreal y, m
 			case 3:	p1.y = y;	p2.y = y+0.1*h;	break;
 			default:p1.x = x-0.1*w;	p2.x = x;	break;
 		}
-		n3 = AddPnt(p1,c[i]);	n4 = AddPnt(p2,c[i]);
+		n3 = AddPnt(&M, p1,c[i]);	n4 = AddPnt(&M, p2,c[i]);
 		quad_plot(n1,n2,n3,n4);
 	}
 	if(n<64)
 	{
-		wchar_t buf[64];
-		for(i=0;i<n;i++)
+		wchar_t buf[64];	ac.txt.clear();
+		for(long i=0;i<n;i++)
 		{
 			d = vv->v(i);
-			mglprintf(buf,64,ac.t[0]?ac.t:(fabs(d)<1 ? L"%.2g" :  L"%.3g"),d);
+			mglprintf(buf,64,ac.t.empty()?(fabs(d)<1 ? L"%.2g" :  L"%.3g"):ac.t.c_str(),d);
 			ac.AddLabel(buf,d);
 		}
 	}
 	else	{	UpdateAxis();	AdjustTicks(ac,fa!=0);	}
 	// hint for using standard label drawing function
 	SetPenPal(TickStl);
-	for(i=0;i<ac.txt.size();i++)
+	for(size_t i=0;i<ac.txt.size();i++)
 	{
 		d = ac.txt[i].val = GetA(ac.txt[i].val)*2-1;
 		p1 = p2 = mglPoint((ss*d+1)*w+x, (ss*d+1)*h+y, s3);
@@ -953,7 +997,7 @@ void mglCanvas::colorbar(HCDT vv, const mreal *c, int where, mreal x, mreal y, m
 			case 3:	p1.y = y;	p2.y = y+0.1*h;	break;
 			default:p1.x = x-0.1*w;	p2.x = x;	break;
 		}
-		n1 = AddPnt(p1);	n2 = AddPnt(p2);
+		n1 = AddPnt(&M, p1);	n2 = AddPnt(&M, p2);
 		line_plot(n1,n2);
 	}
 	ac.dir = mglPoint(ss*w,ss*h,0);
@@ -966,7 +1010,9 @@ void mglCanvas::colorbar(HCDT vv, const mreal *c, int where, mreal x, mreal y, m
 		default:ac.dir.x = 0;	ac.org.x = x-0.1*w;	break;
 	}
 	SetPenPal(AxisStl);
-	ac.ns = where;	DrawLabels(ac);	// NOTE ns isn't used for colorbar
-	Pop();	clr(MGL_DISABLE_SCALE);	EndGroup();
+//	bool out = fabs(x)>1 && fabs(y)>1;
+	bool inv = where!=3 && where!=0;
+	ac.ns = where;	DrawLabels(ac,inv);	// NOTE ns isn't used for colorbar
+	clr(MGL_DISABLE_SCALE);	EndGroup();
 }
 //-----------------------------------------------------------------------------
diff --git a/src/base.cpp b/src/base.cpp
index af5f2d7..acc65b1 100644
--- a/src/base.cpp
+++ b/src/base.cpp
@@ -30,7 +30,7 @@ char *mgl_strdup(const char *s)
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_create_cpp_font(HMGL gr, const wchar_t *how)
 {
-	unsigned long l=wcslen(how), i, n=0, m;
+	unsigned long l=mgl_wcslen(how), i, n=0, m;
 	wchar_t ch=*how;
 	const mglFont *f = gr->GetFont();
 	std::vector<wchar_t> s;	s.push_back(ch);
@@ -72,19 +72,18 @@ void MGL_EXPORT mgl_create_cpp_font(HMGL gr, const wchar_t *how)
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_strtrim(char *str)
 {
-	char *c = mgl_strdup(str);
-	long k,n=strlen(str);
+	if(!str || *str==0)	return;
+	size_t n=strlen(str), k, i;
 	for(k=0;k<n;k++)	if(str[k]>' ')	break;
-	strcpy(c,&(str[k]));
-	n = strlen(c);
-	for(k=n-1;k>=0;k--)	if(c[k]>' ')	break;
-	c[k+1] = 0;
-	strcpy(str,c);	free(c);
+	for(i=n;i>k;i--)	if(str[i-1]>' ')	break;
+	memmove(str, str+k, (i-k));
+	str[i-k]=0;
 }
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_strlwr(char *str)
 {
-	for(long k=0;k<(long)strlen(str);k++)
+	register size_t k,l=strlen(str);
+	for(k=0;k<l;k++)
 		str[k] = (str[k]>='A' && str[k]<='Z') ? str[k]+'a'-'A' : str[k];
 }
 //-----------------------------------------------------------------------------
@@ -109,9 +108,13 @@ mglBase::mglBase()
 
 	InUse = 1;	SetQuality();	FaceNum = 0;
 	// Always create default palette txt[0] and default scheme txt[1]
-	Txt.reserve(3);
-	MGL_PUSH(Txt,mglTexture(MGL_DEF_PAL,-1),mutexTxt);
-	MGL_PUSH(Txt,mglTexture(MGL_DEF_SCH,1),mutexTxt);
+#pragma omp critical(txt)
+	{
+		mglTexture t1(MGL_DEF_PAL,-1), t2(MGL_DEF_SCH,1);
+		Txt.reserve(3);
+		MGL_PUSH(Txt,t1,mutexTxt);
+		MGL_PUSH(Txt,t2,mutexTxt);
+	}
 	memcpy(last_style,"{k5}-1\0",8);
 	MinS=mglPoint(-1,-1,-1);	MaxS=mglPoint(1,1,1);
 	fnt = new mglFont;	fnt->gr = this;	PrevState=NAN;
@@ -137,6 +140,7 @@ void mglBase::AddActive(long k,int n)
 	int h=GetHeight();
 	p.x = int(q.x);	p.y = h>1?h-1-int(q.y):int(q.y);
 	p.id = ObjId;	p.n = n;
+#pragma omp critical(act)
 	MGL_PUSH(Act,p,mutexAct);
 }
 //-----------------------------------------------------------------------------
@@ -146,29 +150,32 @@ int mglBase::GetHeight() const	{	return 1;	}
 //-----------------------------------------------------------------------------
 void mglBase::StartGroup(const char *name, int id)
 {
-	LightScale();
+	LightScale(&B);
 	char buf[128];
 	snprintf(buf,128,"%s_%d",name,id);
 	StartAutoGroup(buf);
 }
 //-----------------------------------------------------------------------------
-const char *mglWarn[mglWarnEnd] = {"data dimension(s) is incompatible",
-								"data dimension(s) is too small",
-								"minimal data value is negative",
-								"no file or wrong data dimensions",
-								"not enough memory",
-								"data values are zero",
-								"too many legend entries",
-								"no legend entries",
-								"slice value is out of range",
-								"number of contours is zero or negative",
-								"couldn't open file",
-								"light: ID is out of range",
-								"size(s) is zero or negative",
-								"format is not supported for that build",
-								"axis ranges are incompatible",
-								"pointer is NULL",
-								"not enough space for plot"};
+const char *mglWarn[mglWarnEnd] = {"data dimension(s) is incompatible",	//mglWarnDim
+								"data dimension(s) is too small",		//mglWarnLow
+								"minimal data value is negative",		//mglWarnNeg
+								"no file or wrong data dimensions",		//mglWarnFile
+								"not enough memory", 					//mglWarnMem
+								"data values are zero",					//mglWarnZero
+								"no legend entries",					//mglWarnLeg
+								"slice value is out of range",			//mglWarnSlc
+								"number of contours is zero or negative",//mglWarnCnt
+								"couldn't open file",					//mglWarnOpen
+								"light: ID is out of range",			//mglWarnLId
+								"size(s) is zero or negative",			//mglWarnSize
+								"format is not supported for that build",//mglWarnFmt
+								"axis ranges are incompatible",			//mglWarnTern
+								"pointer is NULL",						//mglWarnNull
+								"not enough space for plot",			//mglWarnSpc
+								"There are wrong argument(s) in script",//mglScrArg
+								"There are wrong command in script",	//mglScrCmd
+								"There are too long string in script",	//mglScrLong
+								"There are unbalanced ' in script"};	//mglScrStr
 //-----------------------------------------------------------------------------
 void mglBase::SetWarn(int code, const char *who)
 {
@@ -189,7 +196,7 @@ void mglBase::SetWarn(int code, const char *who)
 void mglGlyph::Create(long Nt, long Nl)
 {
 	if(Nt<0 || Nl<0)	return;
-	nt=Nt;	nl=Nl;	
+	nt=Nt;	nl=Nl;
 	if(trig)	delete []trig;
 	trig = nt>0?new short[6*nt]:0;
 	if(line)	delete []line;
@@ -208,22 +215,29 @@ long mglBase::AddGlyph(int s, long j)
 {
 	// first create glyph for current typeface
 	s = s&3;
-	mglGlyph g(fnt->GetNt(s,j), fnt->GetNl(s,j));	
+	mglGlyph g(fnt->GetNt(s,j), fnt->GetNl(s,j));
 	memcpy(g.trig, fnt->GetTr(s,j), 6*g.nt*sizeof(short));
 	memcpy(g.line, fnt->GetLn(s,j), 2*g.nl*sizeof(short));
 	// now let find the similar glyph
-	register size_t i;
-	for(i=0;i<Glf.size();i++)	if(g==Glf[i])	return i;
+	for(size_t i=0;i<Glf.size();i++)	if(g==Glf[i])	return i;
 	// if no one then let add it
-	MGL_PUSH(Glf,g,mutexGlf);	return Glf.size()-1;
+	long k;
+#pragma omp critical(glf)
+	{MGL_PUSH(Glf,g,mutexGlf);	k=Glf.size()-1;}	return k;
 }
 //-----------------------------------------------------------------------------
 //		Add points to the buffer
 //-----------------------------------------------------------------------------
-long mglBase::AddPnt(mglPoint p, mreal c, mglPoint n, mreal a, int scl)
+long mglBase::AddPnt(const mglMatrix *mat, mglPoint p, mreal c, mglPoint n, mreal a, int scl)
 {
+	// scl=0 -- no scaling
+	// scl&1 -- usual scaling
+	// scl&2 -- disable NAN at scaling
+	// scl&4 -- ???
+	// scl&8 -- bypass palette for enabling alpha
 	if(mgl_isnan(c) || mgl_isnan(a))	return -1;
-	if(scl>0)	ScalePoint(p,n,!(scl&2));
+	bool norefr = mgl_isnan(n.x) && mgl_isnan(n.y);
+	if(scl>0)	ScalePoint(mat,p,n,!(scl&2));
 	if(mgl_isnan(p.x))	return -1;
 	a = (a>=0 && a<=1) ? a : AlphaDef;
 	c = (c>=0) ? c:CDef;
@@ -233,7 +247,9 @@ long mglBase::AddPnt(mglPoint p, mreal c, mglPoint n, mreal a, int scl)
 	{
 		q.x=q.xx=int(p.x*10)*0.1;	q.y=q.yy=int(p.y*10)*0.1;	q.z=q.zz=int(p.z*10)*0.1;
 		q.c=int(c*100)*0.01;	q.t=q.ta=int(a*100)*0.01;
-		q.u=int(n.x*100)*0.01;	q.v=int(n.y*100)*0.01;	q.w=int(n.z*100)*0.01;
+		q.u=mgl_isnum(n.x)?int(n.x*100)*0.01:NAN;
+		q.v=mgl_isnum(n.y)?int(n.y*100)*0.01:NAN;
+		q.w=mgl_isnum(n.z)?int(n.z*100)*0.01:NAN;
 	}
 	else
 	{
@@ -250,20 +266,24 @@ long mglBase::AddPnt(mglPoint p, mreal c, mglPoint n, mreal a, int scl)
 	q.c = ci+(q.c-ci)*(1-2*gap)+gap;
 	q.t = q.t*(1-2*gap)+gap;
 	q.ta = q.t;
-	
+
 	if(scl&8 && scl>0)	q.a=a;	// bypass palette for enabling alpha in Error()
 	if(!get(MGL_ENABLE_ALPHA))	{	q.a=1;	if(txt.Smooth!=2)	q.ta=1-gap;	}
-//	if(q.ta<0.005)	q.ta = 0.005;	// bypass OpenGL/OBJ/PRC bug
+	if(norefr)	q.v=0;
 	if(!get(MGL_ENABLE_LIGHT) && !(scl&4))	q.u=q.v=NAN;
-	MGL_PUSH(Pnt,q,mutexPnt);	return Pnt.size()-1;
+	long k;
+#pragma omp critical(pnt)
+	{MGL_PUSH(Pnt,q,mutexPnt);	k=Pnt.size()-1;}	return k;
 }
 //-----------------------------------------------------------------------------
 long mglBase::CopyNtoC(long from, mreal c)
 {
 	if(from<0)	return -1;
 	mglPnt p=Pnt[from];
-	if(!mgl_isnan(c))	{	p.c=c;	p.t=0;	Txt[long(c)].GetC(c,0,p);	}
-	MGL_PUSH(Pnt,p,mutexPnt);	return Pnt.size()-1;
+	if(mgl_isnum(c))	{	p.c=c;	p.t=0;	Txt[long(c)].GetC(c,0,p);	}
+	long k;
+#pragma omp critical(pnt)
+	{MGL_PUSH(Pnt,p,mutexPnt);	k=Pnt.size()-1;}	return k;
 }
 //-----------------------------------------------------------------------------
 long mglBase::CopyProj(long from, mglPoint p, mglPoint n)
@@ -272,19 +292,23 @@ long mglBase::CopyProj(long from, mglPoint p, mglPoint n)
 	mglPnt q=Pnt[from];
 	q.x=q.xx=p.x;	q.y=q.yy=p.y;	q.z=q.zz=p.z;
 	q.u = n.x;		q.v = n.y;		q.w = n.z;
-	MGL_PUSH(Pnt,q,mutexPnt);	return Pnt.size()-1;
+	long k;
+#pragma omp critical(pnt)
+	{MGL_PUSH(Pnt,q,mutexPnt);	k=Pnt.size()-1;}	return k;
 }
 //-----------------------------------------------------------------------------
 void mglBase::Reserve(long n)
 {
 	if(TernAxis&4)	n*=4;
+#pragma omp critical(pnt)
 	Pnt.reserve(n);
 }
 //-----------------------------------------------------------------------------
 //		Boundaries and scaling
 //---------------------------------------------------------------------------
-void mglBase::RecalcCRange()
+bool mglBase::RecalcCRange()
 {
+	bool wrong=false;
 	if(!fa)
 	{	FMin.c = Min.c;	FMax.c = Max.c;	}
 	else
@@ -296,15 +320,18 @@ void mglBase::RecalcCRange()
 		for(i=0;i<=n;i++)
 		{
 			a = fa->Calc(0,0,0,Min.c+i*(Max.c-Min.c)/n);
+			if(mgl_isbad(a))	wrong=true;
 			if(a<FMin.c)	FMin.c=a;
 			if(a>FMax.c)	FMax.c=a;
 		}
 	}
+	return wrong;
 }
 //-----------------------------------------------------------------------------
 void mglBase::RecalcBorder()
 {
 	ZMin = 1.;
+	bool wrong=false;
 	if(!fx && !fy && !fz)
 	{	FMin = Min;	FMax = Max;	}
 	else
@@ -315,18 +342,18 @@ void mglBase::RecalcBorder()
 		int n=30;
 		for(i=0;i<=n;i++)	for(j=0;j<=n;j++)	// x range
 		{
-			SetFBord(Min.x, Min.y+i*(Max.y-Min.y)/n, Min.z+j*(Max.z-Min.z)/n);
-			SetFBord(Max.x, Min.y+i*(Max.y-Min.y)/n, Min.z+j*(Max.z-Min.z)/n);
+			if(SetFBord(Min.x, Min.y+i*(Max.y-Min.y)/n, Min.z+j*(Max.z-Min.z)/n))	wrong=true;
+			if(SetFBord(Max.x, Min.y+i*(Max.y-Min.y)/n, Min.z+j*(Max.z-Min.z)/n))	wrong=true;
 		}
 		for(i=0;i<=n;i++)	for(j=0;j<=n;j++)	// y range
 		{
-			SetFBord(Min.x+i*(Max.x-Min.x)/n, Min.y, Min.z+j*(Max.z-Min.z)/n);
-			SetFBord(Min.x+i*(Max.x-Min.x)/n, Max.y, Min.z+j*(Max.z-Min.z)/n);
+			if(SetFBord(Min.x+i*(Max.x-Min.x)/n, Min.y, Min.z+j*(Max.z-Min.z)/n))	wrong=true;
+			if(SetFBord(Min.x+i*(Max.x-Min.x)/n, Max.y, Min.z+j*(Max.z-Min.z)/n))	wrong=true;
 		}
 		for(i=0;i<=n;i++)	for(j=0;j<=n;j++)	// x range
 		{
-			SetFBord(Min.x+i*(Max.x-Min.x)/n, Min.y+j*(Max.y-Min.y)/n, Min.x);
-			SetFBord(Min.x+i*(Max.x-Min.x)/n, Min.y+j*(Max.y-Min.y)/n, Max.z);
+			if(SetFBord(Min.x+i*(Max.x-Min.x)/n, Min.y+j*(Max.y-Min.y)/n, Min.z))	wrong=true;
+			if(SetFBord(Min.x+i*(Max.x-Min.x)/n, Min.y+j*(Max.y-Min.y)/n, Max.z))	wrong=true;
 		}
 		mreal d;
 		if(!fx)	{	FMin.x = Min.x;	FMax.x = Max.x;	}
@@ -336,32 +363,38 @@ void mglBase::RecalcBorder()
 		if(!fz)	{	FMin.z = Min.z;	FMax.z = Max.z;	}
 		else	{	d=0.01*(FMax.z-FMin.z);	FMin.z-=d;	FMax.z+=d;	}
 	}
-	RecalcCRange();
+	if(RecalcCRange())	wrong=true;
+	if(wrong)	SetWarn(mglWarnTern, "Curved coordinates");
 }
 //-----------------------------------------------------------------------------
-void mglBase::SetFBord(mreal x,mreal y,mreal z)
+bool mglBase::SetFBord(mreal x,mreal y,mreal z)
 {
+	bool wrong=false;
 	if(fx)
 	{
 		mreal v = fx->Calc(x,y,z);
+		if(mgl_isbad(v))	wrong = true;
 		if(FMax.x < v)	FMax.x = v;
 		if(FMin.x > v)	FMin.x = v;
 	}
 	if(fy)
 	{
 		mreal v = fy->Calc(x,y,z);
+		if(mgl_isbad(v))	wrong = true;
 		if(FMax.y < v)	FMax.y = v;
 		if(FMin.y > v)	FMin.y = v;
 	}
 	if(fz)
 	{
 		mreal v = fz->Calc(x,y,z);
+		if(mgl_isbad(v))	wrong = true;
 		if(FMax.z < v)	FMax.z = v;
 		if(FMin.z > v)	FMin.z = v;
 	}
+	return wrong;
 }
 //-----------------------------------------------------------------------------
-bool mglBase::ScalePoint(mglPoint &p, mglPoint &n, bool use_nan) const
+bool mglBase::ScalePoint(const mglMatrix *, mglPoint &p, mglPoint &n, bool use_nan) const
 {
 	mreal &x=p.x, &y=p.y, &z=p.z;
 	if(mgl_isnan(x) || mgl_isnan(y) || mgl_isnan(z))	{	x=NAN;	return false;	}
@@ -466,12 +499,12 @@ void mglBase::SetRanges(mglPoint m1, mglPoint m2)
 	if(m1.c!=m2.c)	{	Min.c=m1.c;	Max.c=m2.c;	}
 	else			{	Min.c=Min.z;Max.c=Max.z;}
 
-	if(Org.x<Min.x && !mgl_isnan(Org.x))	Org.x = Min.x;
-	if(Org.x>Max.x && !mgl_isnan(Org.x))	Org.x = Max.x;
-	if(Org.y<Min.y && !mgl_isnan(Org.y))	Org.y = Min.y;
-	if(Org.y>Max.y && !mgl_isnan(Org.y))	Org.y = Max.y;
-	if(Org.z<Min.z && !mgl_isnan(Org.z))	Org.z = Min.z;
-	if(Org.z>Max.z && !mgl_isnan(Org.z))	Org.z = Max.z;
+	if(Org.x<Min.x && mgl_isnum(Org.x))	Org.x = Min.x;
+	if(Org.x>Max.x && mgl_isnum(Org.x))	Org.x = Max.x;
+	if(Org.y<Min.y && mgl_isnum(Org.y))	Org.y = Min.y;
+	if(Org.y>Max.y && mgl_isnum(Org.y))	Org.y = Max.y;
+	if(Org.z<Min.z && mgl_isnum(Org.z))	Org.z = Min.z;
+	if(Org.z>Max.z && mgl_isnum(Org.z))	Org.z = Max.z;
 
 	if((TernAxis&3)==0)
 	{
@@ -480,7 +513,7 @@ void mglBase::SetRanges(mglPoint m1, mglPoint m2)
 		mglScaleAxis(Min.y, Max.y, Org.y, AMin.y, AMax.y);
 		mglScaleAxis(Min.z, Max.z, Org.z, AMin.z, AMax.z);
 		mglScaleAxis(Min.c, Max.c, Org.c, AMin.c, AMax.c);
-	}	
+	}
 
 	CutMin = mglPoint(0,0,0);	CutMax = mglPoint(0,0,0);
 	RecalcBorder();
@@ -490,7 +523,7 @@ void mglBase::CRange(HCDT a,bool add, mreal fact)
 {
 	mreal v1=a->Minimal(), v2=a->Maximal(), dv;
 	dv=(v2-v1)*fact;	v1 -= dv;	v2 += dv;
-	if(v1==v2)	return;
+	if(v1==v2 && !add)	return;
 	if(!add)	{	Min.c = v1;	Max.c = v2;	}
 	else if(Min.c<Max.c)
 	{
@@ -503,8 +536,8 @@ void mglBase::CRange(HCDT a,bool add, mreal fact)
 		Min.c = v1<Max.c ? v1:Max.c;
 		Max.c = v2>dv ? v2:dv;
 	}
-	if(Org.c<Min.c && !mgl_isnan(Org.c))	Org.c = Min.c;
-	if(Org.c>Max.c && !mgl_isnan(Org.c))	Org.c = Max.c;
+	if(Org.c<Min.c && mgl_isnum(Org.c))	Org.c = Min.c;
+	if(Org.c>Max.c && mgl_isnum(Org.c))	Org.c = Max.c;
 	if((TernAxis&3)==0)
 	{
 		OMax.c = Max.c;	OMin.c = Min.c;
@@ -517,7 +550,7 @@ void mglBase::XRange(HCDT a,bool add,mreal fact)
 {
 	mreal v1=a->Minimal(), v2=a->Maximal(), dv;
 	dv=(v2-v1)*fact;	v1 -= dv;	v2 += dv;
-	if(v1==v2)	return;
+	if(v1==v2 && !add)	return;
 	if(!add)	{	Min.x = v1;	Max.x = v2;	}
 	else if(Min.x<Max.x)
 	{
@@ -530,8 +563,8 @@ void mglBase::XRange(HCDT a,bool add,mreal fact)
 		Min.x = v1<Max.x ? v1:Max.x;
 		Max.x = v2>dv ? v2:dv;
 	}
-	if(Org.x<Min.x && !mgl_isnan(Org.x))	Org.x = Min.x;
-	if(Org.x>Max.x && !mgl_isnan(Org.x))	Org.x = Max.x;
+	if(Org.x<Min.x && mgl_isnum(Org.x))	Org.x = Min.x;
+	if(Org.x>Max.x && mgl_isnum(Org.x))	Org.x = Max.x;
 	if((TernAxis&3)==0)
 	{
 		OMax.x = Max.x;	OMin.x = Min.x;
@@ -544,7 +577,7 @@ void mglBase::YRange(HCDT a,bool add,mreal fact)
 {
 	mreal v1=a->Minimal(), v2=a->Maximal(), dv;
 	dv=(v2-v1)*fact;	v1 -= dv;	v2 += dv;
-	if(v1==v2)	return;
+	if(v1==v2 && !add)	return;
 	if(!add)	{	Min.y = v1;	Max.y = v2;	}
 	else if(Min.y<Max.y)
 	{
@@ -557,13 +590,13 @@ void mglBase::YRange(HCDT a,bool add,mreal fact)
 		Min.y = v1<Max.y ? v1:Max.y;
 		Max.y = v2>dv ? v2:dv;
 	}
-	if(Org.y<Min.y && !mgl_isnan(Org.y))	Org.y = Min.y;
-	if(Org.y>Max.y && !mgl_isnan(Org.y))	Org.y = Max.y;
+	if(Org.y<Min.y && mgl_isnum(Org.y))	Org.y = Min.y;
+	if(Org.y>Max.y && mgl_isnum(Org.y))	Org.y = Max.y;
 	if((TernAxis&3)==0)
 	{
 		OMax.y = Max.y;	OMin.y = Min.y;
 		mglScaleAxis(Min.y, Max.y, Org.y, AMin.y, AMax.y);
-	
+
 	}
 	RecalcBorder();
 }
@@ -572,7 +605,7 @@ void mglBase::ZRange(HCDT a,bool add,mreal fact)
 {
 	mreal v1=a->Minimal(), v2=a->Maximal(), dv;
 	dv=(v2-v1)*fact;	v1 -= dv;	v2 += dv;
-	if(v1==v2)	return;
+	if(v1==v2 && !add)	return;
 	if(!add)	{	Min.z = v1;	Max.z = v2;	}
 	else if(Min.z<Max.z)
 	{
@@ -585,8 +618,8 @@ void mglBase::ZRange(HCDT a,bool add,mreal fact)
 		Min.z = v1<Max.z ? v1:Max.z;
 		Max.z = v2>dv ? v2:dv;
 	}
-	if(Org.z<Min.z && !mgl_isnan(Org.z))	Org.z = Min.z;
-	if(Org.z>Max.z && !mgl_isnan(Org.z))	Org.z = Max.z;
+	if(Org.z<Min.z && mgl_isnum(Org.z))	Org.z = Min.z;
+	if(Org.z>Max.z && mgl_isnum(Org.z))	Org.z = Max.z;
 	if((TernAxis&3)==0)
 	{
 		OMax.z = Max.z;	OMin.z = Min.z;
@@ -611,9 +644,8 @@ void mglBase::Ternary(int t)
 	if(t&3)
 	{
 		if(c)	{	x1 = Min;	x2 = Max;	o = Org;	}
-//		c = get(MGL_ENABLE_CUT);	clr(MGL_ENABLE_CUT);
-		SetRanges(mglPoint(0,0),mglPoint(1,1,t==1?0:1));
-		Org=mglPoint(0,0,0);	c = false;
+		SetRanges(mglPoint(0,0,0),mglPoint(1,1,(t&3)==1?0:1));
+		Org=mglPoint(0,0,(t&3)==1?NAN:0);	c = false;
 	}
 	else if(!c)	{	SetRanges(x1,x2);	Org=o;	c=true;	}
 }
@@ -780,7 +812,7 @@ void mglTexture::Set(const char *s, int smooth, mreal alpha)
 		if(s[i]=='A' && j<1 && m>0 && s[i+1]>'0' && s[i+1]<='9')
 		{	man=false;	alpha = 0.1*(s[i+1]-'0');	i++;	}
 	}
-	for(i=0;i<n;i++)	// default texture
+	for(long i=0;i<n;i++)	// default texture
 	{	c[2*i+1]=c[2*i];	c[2*i].a=man?0:alpha;	c[2*i+1].a=alpha;	}
 	if(map && sm)		// map texture
 	{
@@ -790,7 +822,7 @@ void mglTexture::Set(const char *s, int smooth, mreal alpha)
 		{	c[1]=c[2];	c[2]=c[0];	c[0]=BC;	c[3]=c[4];	n=2;}
 		else
 		{	c[1]=c[4];	c[3]=c[6];	n=2;	}
-		for(i=0;i<4;i++)	c[i].a=alpha;
+		c[0].a = c[1].a = c[2].a = c[3].a = alpha;
 		val[0]=val[1]=-1;
 	}
 	// TODO if(!sm && n==1)	then try to find color in palette ???
@@ -799,7 +831,7 @@ void mglTexture::Set(const char *s, int smooth, mreal alpha)
 	float  v1=0,v2=1;
 	std::vector <long>  def;
 	val[0]=0;	val[n-1]=1;	// boundary have to be [0,1]
-	for(i=0;i<n;i++) if(val[i]>0 && val[i]<1) 	def.push_back(i);
+	for(long i=0;i<n;i++) if(val[i]>0 && val[i]<1) 	def.push_back(i);
 	def.push_back(n-1);
 	long i1=0,i2;
 	for(size_t j=0;j<def.size();j++)	for(i=i1+1;i<def[j];i++)
@@ -810,24 +842,27 @@ void mglTexture::Set(const char *s, int smooth, mreal alpha)
 		val[i]=v1+v2*(i-i1);
 	}
 	// fill texture itself
-	register mreal u,v=sm?(n-1)/255.:n/256.;
-	for(i=0,i1=0;i<256;i++)
+	mreal v=sm?(n-1)/255.:n/256.;
+	if(!sm)
+#pragma omp parallel for
+		for(long i=0;i<256;i++)
+		{
+			register long j = 2*long(v*i);	//u-=j;
+			col[2*i] = c[j];	col[2*i+1] = c[j+1];
+		}
+	else	for(i=i1=0;i<256;i++)
 	{
-		u = v*i;	j = long(u);	//u-=j;
-		if(!sm || j==n-1)
-		{	col[2*i] = c[2*j];	col[2*i+1] = c[2*j+1];	}
-		else if(j>n-1)	// NOTE: never should be here!
-		{	col[2*i] = c[2*n-2];col[2*i+1] = c[2*n-1];	/*printf("AddTexture -- out of bounds");*/	}
-		else
+		register mreal u = v*i;	j = long(u);	//u-=j;
+		if(j<n-1)	// advanced scheme using val
 		{
-			// advanced scheme using val
 			for(;i1<n-1 && i>=255*val[i1];i1++);
 			v2 = i1<n?1/(val[i1]-val[i1-1]):0;
 			j=i1-1;	u=(i/255.-val[j])*v2;
-
 			col[2*i] = c[2*j]*(1-u)+c[2*j+2]*u;
 			col[2*i+1]=c[2*j+1]*(1-u)+c[2*j+3]*u;
 		}
+		else
+		{	col[2*i] = c[2*n-2];col[2*i+1] = c[2*n-1];	}
 	}
 	delete []c;	delete []val;
 }
@@ -836,13 +871,13 @@ mglColor mglTexture::GetC(mreal u,mreal v) const
 {
 	u -= long(u);
 	register long i=long(255*u);	u = u*255-i;
-	const mglColor *s=col+2*i;	mglColor p;
-	p.r = (s[0].r*(1-u)+s[2].r*u)*(1-v) + (s[1].r*(1-u)+s[3].r*u)*v;
-	p.g = (s[0].g*(1-u)+s[2].g*u)*(1-v) + (s[1].g*(1-u)+s[3].g*u)*v;
-	p.b = (s[0].b*(1-u)+s[2].b*u)*(1-v) + (s[1].b*(1-u)+s[3].b*u)*v;
-	p.a = (s[0].a*(1-u)+s[2].a*u)*(1-v) + (s[1].a*(1-u)+s[3].a*u)*v;
-	//	p.a = (s[0].a*(1-u)+s[2].a*u)*v + (s[1].a*(1-u)+s[3].a*u)*(1-v);	// for alpha use inverted
-	return p;
+	const mglColor *s=col+2*i;	//mglColor p;
+	return (s[0]*(1-u)+s[2]*u)*(1-v) + (s[1]*(1-u)+s[3]*u)*v;
+// 	p.r = (s[0].r*(1-u)+s[2].r*u)*(1-v) + (s[1].r*(1-u)+s[3].r*u)*v;
+// 	p.g = (s[0].g*(1-u)+s[2].g*u)*(1-v) + (s[1].g*(1-u)+s[3].g*u)*v;
+// 	p.b = (s[0].b*(1-u)+s[2].b*u)*(1-v) + (s[1].b*(1-u)+s[3].b*u)*v;
+// 	p.a = (s[0].a*(1-u)+s[2].a*u)*(1-v) + (s[1].a*(1-u)+s[3].a*u)*v;
+// 	return p;
 }
 //-----------------------------------------------------------------------------
 void mglTexture::GetC(mreal u,mreal v,mglPnt &p) const
@@ -859,27 +894,32 @@ void mglTexture::GetC(mreal u,mreal v,mglPnt &p) const
 //-----------------------------------------------------------------------------
 long mglBase::AddTexture(const char *cols, int smooth)
 {
+	if(smooth>=0)	SetMask(cols);
 	mglTexture t(cols,smooth,smooth==2?AlphaDef:1);
 	if(t.n==0)	return smooth<0 ? 0:1;
 	if(smooth<0)	CurrPal=0;
 	// check if already exist
 	for(size_t i=0;i<Txt.size();i++)	if(t.IsSame(Txt[i]))	return i;
 	// create new one
-	MGL_PUSH(Txt,t,mutexTxt);	return Txt.size()-1;
+	long k;
+#pragma omp critical(txt)
+	{MGL_PUSH(Txt,t,mutexTxt);	k=Txt.size()-1;}	return k;
 }
 //-----------------------------------------------------------------------------
 mreal mglBase::AddTexture(mglColor c)
 {
-	register size_t i,j;
 	if(!c.Valid())	return -1;
 	// first lets try an existed one
-	for(i=0;i<Txt.size();i++)	for(j=0;j<255;j++)
+	for(size_t i=0;i<Txt.size();i++)	for(int j=0;j<255;j++)
 		if(c==Txt[i].col[2*j])
 			return i+j/255.;
 	// add new texture
 	mglTexture t;
-	for(i=0;i<MGL_TEXTURE_COLOURS;i++)	t.col[i]=c;
-	MGL_PUSH(Txt,t,mutexTxt);	return Txt.size()-1;
+#pragma omp parallel for
+	for(long i=0;i<MGL_TEXTURE_COLOURS;i++)	t.col[i]=c;
+	long k;
+#pragma omp critical(txt)
+	{MGL_PUSH(Txt,t,mutexTxt);	k=Txt.size()-1;}	return k;
 }
 //-----------------------------------------------------------------------------
 //		Coloring and palette
@@ -908,14 +948,32 @@ mreal mglBase::NextColor(long &id)
 	return CDef;
 }
 //-----------------------------------------------------------------------------
+mreal mglBase::NextColor(long id, long sh)
+{
+	long i=abs(id)/256, n=Txt[i].n, p=abs(id)&0xff;
+	if(id>=0)	p=(p+sh)%n;
+	return i + (n>0 ? (p+0.5)/n : 0);
+}
+//-----------------------------------------------------------------------------
+const char *mglchrs(const char *str, const char *chr)
+{
+	if(!str || !str[0] || !chr || !chr[0])	return NULL;
+	size_t l=strlen(str);
+	for(size_t i=0;i<l;i++)
+	{
+		const char *res = mglchr(str,chr[i]);
+		if(res)	return res;
+	}
+	return NULL;
+}
+//-----------------------------------------------------------------------------
 const char *mglchr(const char *str, char ch)
 {
 	if(!str || !str[0])	return NULL;
-	register char c;
-	register size_t l=strlen(str),i,k=0;
-	for(i=0;i<l;i++)
+	size_t l=strlen(str),k=0;
+	for(size_t i=0;i<l;i++)
 	{
-		c = str[i];
+		register char c = str[i];
 		if(c=='{')	k++;
 		if(c=='}')	k--;
 		if(c==ch && k==0)	return str+i;
@@ -923,7 +981,7 @@ const char *mglchr(const char *str, char ch)
 	return NULL;
 }
 //-----------------------------------------------------------------------------
-char mglBase::SetPenPal(const char *p, long *Id)
+char mglBase::SetPenPal(const char *p, long *Id, bool pal)
 {
 	char mk=0;
 	PDef = 0xffff;	// reset to solid line
@@ -933,30 +991,20 @@ char mglBase::SetPenPal(const char *p, long *Id)
 	if(p && *p)
 	{
 //		const char *col = "wkrgbcymhRGBCYMHWlenuqpLENUQP";
-		const char *stl = " -|;:ji=";
+		unsigned val[8] = {0x0000, 0xffff, 0x00ff, 0x0f0f, 0x1111, 0x087f, 0x2727, 0x3333};
+		const char *stl = " -|;:ji=", *s;
 		const char *mrk = "*o+xsd.^v<>";
+		const char *MRK = "YOPXSDCTVLR";
 		const char *wdh = "123456789";
 		const char *arr = "AKDTVISO_";
 		long m=0;
-		for(size_t i=0;i<strlen(p);i++)
+		size_t l=strlen(p);
+		for(size_t i=0;i<l;i++)
 		{
 			if(p[i]=='{')	m++;	if(p[i]=='}')	m--;
 			if(m>0)	continue;
-			if(mglchr(stl,p[i]))
-			{
-				switch(p[i])
-				{
-				case '|': PDef = 0x00ff;	break;
-				case ';': PDef = 0x0f0f;	break;
-				case '=': PDef = 0x3333;	break;
-				case ':': PDef = 0x1111;	break;
-				case 'j': PDef = 0x087f;	break;
-				case 'i': PDef = 0x2727;	break;
-				case ' ': PDef = 0x0000;	break;
-				default:  PDef = 0xffff;	break;	// '-'
-				}
-				last_style[4]=p[i];
-			}
+			s = mglchr(stl,p[i]);
+			if(s)	{	PDef = val[s-stl];	last_style[4]=p[i];	}
 			else if(mglchr(mrk,p[i]))	mk = p[i];
 			else if(mglchr(wdh,p[i]))
 			{	last_style[5] = p[i];	PenWidth = p[i]-'0';	}
@@ -969,27 +1017,56 @@ char mglBase::SetPenPal(const char *p, long *Id)
 		if(Arrow1=='_')	Arrow1=0;	if(Arrow2=='_')	Arrow2=0;
 		if(mglchr(p,'#'))
 		{
-			if(mk=='.')	mk = 'C';
-			if(mk=='+')	mk = 'P';
-			if(mk=='x')	mk = 'X';
-			if(mk=='o')	mk = 'O';
-			if(mk=='d')	mk = 'D';
-			if(mk=='s')	mk = 'S';
-			if(mk=='^')	mk = 'T';
-			if(mk=='v')	mk = 'V';
-			if(mk=='<')	mk = 'L';
-			if(mk=='>')	mk = 'R';
-			if(mk=='*')	mk = 'Y';
+			s = mglchr(mrk,mk);
+			if(s)	mk = MRK[s-mrk];
 		}
 	}
-	last_style[6]=mk;
-	long tt, n;
-	tt = AddTexture(p,-1);	n=Txt[tt].n;
-	CDef = tt+((n+CurrPal-1)%n+0.5)/n;
-	if(Id)	*Id=long(tt)*256+(n+CurrPal-1)%n;
+	if(pal)
+	{
+		last_style[6]=mk;
+		long tt, n;
+		tt = AddTexture(p,-1);	n=Txt[tt].n;
+		CDef = tt+((n+CurrPal-1)%n+0.5)/n;
+		if(Id)	*Id=long(tt)*256+(n+CurrPal-1)%n;
+	}
 	return mk;
 }
 //-----------------------------------------------------------------------------
+// keep this for restore default mask
+uint64_t mgl_mask_def[16]={0x000000FF00000000,	0x080808FF08080808,	0x0000FF00FF000000,	0x0000007700000000,
+							0x0000182424180000,	0x0000183C3C180000,	0x00003C24243C0000,	0x00003C3C3C3C0000,
+							0x0000060990600000,	0x0060584658600000,	0x00061A621A060000,	0x0000005F00000000,
+							0x0008142214080000,	0x00081C3E1C080000,	0x8142241818244281,	0x0000001824420000};
+uint64_t mgl_mask_val[16]={0x000000FF00000000,	0x080808FF08080808,	0x0000FF00FF000000,	0x0000007700000000,
+							0x0000182424180000,	0x0000183C3C180000,	0x00003C24243C0000,	0x00003C3C3C3C0000,
+							0x0000060990600000,	0x0060584658600000,	0x00061A621A060000,	0x0000005F00000000,
+							0x0008142214080000,	0x00081C3E1C080000,	0x8142241818244281,	0x0000001824420000};
+void mglBase::SetMask(const char *p)
+{
+	mask = MGL_SOLID_MASK;	// reset to solid face
+	PenWidth = 1;	MaskAn=DefMaskAn;
+	if(p && *p)
+	{
+		const char *msk = MGL_MASK_ID, *s;
+		const char *wdh = "123456789";
+		long m=0, l=strlen(p);
+		for(long i=0;i<l;i++)
+		{
+			if(p[i]=='{')	m++;	if(p[i]=='}')	m--;
+			if(m>0)	continue;
+			if(p[i]==':')	break;
+			s = mglchr(msk, p[i]);
+			if(s)	mask = mgl_mask_val[s-msk];
+			else if(mglchr(wdh,p[i]))	PenWidth = p[i]-'0';
+			else if(p[i]=='I')	MaskAn=90;
+			else if(p[i]=='/')	MaskAn=315;	// =360-45
+			else if(p[i]=='\\')	MaskAn=45;
+		}
+		// use line if rotation only specified
+		if(mask==MGL_SOLID_MASK && MaskAn!=0)	mask = mgl_mask_val[0];
+	}
+}
+//-----------------------------------------------------------------------------
 mreal mglBase::GetA(mreal a) const
 {
 	if(fa)	a = fa->Calc(0,0,0,a);
@@ -1036,15 +1113,18 @@ void mglBase::vect_plot(long p1, long p2, mreal s)
 	s2.y=s2.yy = q2.y - 3*s*(q2.y-q1.y) + s*(q2.x-q1.x);
 	s1.z=s1.zz=s2.z=s2.zz = q2.z - 3*s*(q2.z-q1.z);
 	long n1,n2;
-	n1=Pnt.size();	MGL_PUSH(Pnt,s1,mutexPnt);
-	n2=Pnt.size();	MGL_PUSH(Pnt,s2,mutexPnt);
+#pragma omp critical(pnt)
+	{
+		n1=Pnt.size();	MGL_PUSH(Pnt,s1,mutexPnt);
+		n2=Pnt.size();	MGL_PUSH(Pnt,s2,mutexPnt);
+	}
 	line_plot(p1,p2);	line_plot(n1,p2);	line_plot(p2,n2);
 }
 //-----------------------------------------------------------------------------
 int mglFindArg(const char *str)
 {
-	register long l=0,k=0,i;//,j,len=strlen(lst);
-	for(i=0;i<long(strlen(str));i++)
+	long l=0,k=0,len=strlen(str);
+	for(long i=0;i<len;i++)
 	{
 		if(str[i]=='\'') l++;
 		if(str[i]=='{') k++;
@@ -1059,6 +1139,7 @@ int mglFindArg(const char *str)
 }
 //-----------------------------------------------------------------------------
 void mglBase::SetAmbient(mreal bright)	{	AmbBr = bright;	}
+void mglBase::SetDiffuse(mreal bright)	{	DifBr = bright;	}
 //-----------------------------------------------------------------------------
 mreal mglBase::SaveState(const char *opt)
 {
@@ -1122,16 +1203,15 @@ void mglBase::LoadState()
 }
 //-----------------------------------------------------------------------------
 void mglBase::AddLegend(const wchar_t *text,const char *style)
-{	if(text)	MGL_PUSH(Leg,mglText(text,style),mutexLeg);	}
+{
+	if(text)
+#pragma omp critical(leg)
+		MGL_PUSH(Leg,mglText(text,style),mutexLeg);
+}
 //-----------------------------------------------------------------------------
 void mglBase::AddLegend(const char *str,const char *style)
 {
-	if(!str || *str==0)	return;
-	size_t s = mbstowcs(0,str,0)+1;
-	wchar_t *wcs = new wchar_t[s];
-	mbstowcs(wcs,str,s);
-	AddLegend(wcs, style);
-	delete []wcs;
+	MGL_TO_WCS(str,AddLegend(wcs, style));
 }
 //-----------------------------------------------------------------------------
 bool MGL_EXPORT mgl_check_dim2(HMGL gr, HCDT x, HCDT y, HCDT z, HCDT a, const char *name, bool less)
@@ -1246,39 +1326,42 @@ void mglBase::ClearUnused()
 #if MGL_HAVE_PTHREAD
 	pthread_mutex_lock(&mutexPnt);	pthread_mutex_lock(&mutexPrm);
 #endif
-	register size_t i, l=Prm.size();
-	// find points which are actually used
-	long *used = new long[Pnt.size()];	memset(used,0,Pnt.size()*sizeof(long));
-	for(i=0;i<l;i++)
+#pragma omp critical
 	{
-		const mglPrim &p=Prm[i];
-		if(p.n1<0)	continue;
-		used[p.n1] = 1;
-		switch(p.type)
+		size_t l=Prm.size();
+		// find points which are actually used
+		long *used = new long[Pnt.size()];	memset(used,0,Pnt.size()*sizeof(long));
+		for(size_t i=0;i<l;i++)
 		{
-		case 1:	if(p.n2>=0)	used[p.n2] = 1;	break;
-		case 2:	if(p.n2>=0 && p.n3>=0)
-			used[p.n2] = used[p.n3] = 1;	break;
-		case 3:	if(p.n2>=0 && p.n3>=0 && p.n4>=0)
-			used[p.n2] = used[p.n3] = used[p.n4] = 1;	break;
+			const mglPrim &p=Prm[i];
+			if(p.n1<0)	continue;
+			used[p.n1] = 1;
+			switch(p.type)
+			{
+			case 1:	case 4:	if(p.n2>=0)	used[p.n2] = 1;	break;
+			case 2:	if(p.n2>=0 && p.n3>=0)
+				used[p.n2] = used[p.n3] = 1;	break;
+			case 3:	if(p.n2>=0 && p.n3>=0 && p.n4>=0)
+				used[p.n2] = used[p.n3] = used[p.n4] = 1;	break;
+			}
 		}
+		// now add proper indexes
+		l=Pnt.size();
+		std::vector<mglPnt> pnt;
+		for(size_t i=0;i<l;i++)	if(used[i])
+		{	pnt.push_back(Pnt[i]);	used[i]=pnt.size();	}
+		Pnt = pnt;	pnt.clear();
+		// now replace point id
+		l=Prm.size();
+		for(size_t i=0;i<l;i++)
+		{
+			mglPrim &p=Prm[i];	p.n1=used[p.n1]-1;
+			if(p.type==1 || p.type==4)	p.n2=used[p.n2]-1;
+			if(p.type==2)	{	p.n2=used[p.n2]-1;	p.n3=used[p.n3]-1;	}
+			if(p.type==3)	{	p.n2=used[p.n2]-1;	p.n3=used[p.n3]-1;	p.n4=used[p.n4]-1;	}
+		}
+		delete []used;
 	}
-	// now add proper indexes
-	l=Pnt.size();
-	std::vector<mglPnt> pnt;
-	for(i=0;i<l;i++)	if(used[i])
-	{	pnt.push_back(Pnt[i]);	used[i]=pnt.size();	}
-	Pnt = pnt;	pnt.clear();
-	// now replace point id
-	l=Prm.size();
-	for(i=0;i<l;i++)
-	{
-		mglPrim &p=Prm[i];	p.n1=used[p.n1]-1;
-		if(p.type==1)	p.n2=used[p.n2]-1;
-		if(p.type==2)	{	p.n2=used[p.n2]-1;	p.n3=used[p.n3]-1;	}
-		if(p.type==3)	{	p.n2=used[p.n2]-1;	p.n3=used[p.n3]-1;	p.n4=used[p.n4]-1;	}
-	}
-	delete []used;
 #if MGL_HAVE_PTHREAD
 	pthread_mutex_unlock(&mutexPnt);	pthread_mutex_unlock(&mutexPrm);
 #endif
diff --git a/src/base_cf.cpp b/src/base_cf.cpp
index 221134a..874d660 100644
--- a/src/base_cf.cpp
+++ b/src/base_cf.cpp
@@ -19,6 +19,7 @@
  ***************************************************************************/
 #include "mgl2/font.h"
 #include "mgl2/base_cf.h"
+#include "mgl2/base.h"
 //-----------------------------------------------------------------------------
 //
 //		C interfaces
@@ -29,15 +30,19 @@ void MGL_EXPORT mgl_set_quality_(uintptr_t *gr, int *qual)	{	_GR_->SetQuality(*q
 int MGL_EXPORT mgl_get_quality(HMGL gr)	{	return gr->GetQuality();	}
 int MGL_EXPORT mgl_get_quality_(uintptr_t *gr)	{	return _GR_->GetQuality();	}
 int MGL_EXPORT mgl_is_frames(HMGL gr)
-{	return gr->get(MGL_VECT_FRAME) && !(gr->GetQuality()&4);	}
+{	return gr->get(MGL_VECT_FRAME) && !(gr->GetQuality()&MGL_DRAW_LMEM);	}
+void MGL_EXPORT mgl_set_draw_reg(HMGL gr, long nx, long ny, long m)	{	gr->SetDrawReg(nx,ny,m);	}
+void MGL_EXPORT mgl_set_draw_reg_(uintptr_t *gr, int *nx, int *ny, int *m)	{	_GR_->SetDrawReg(*nx,*ny,*m);	}
 //-----------------------------------------------------------------------------
-int MGL_EXPORT mgl_get_flag(HMGL gr, long flag)			{	return gr->get(flag);	}
-void MGL_EXPORT mgl_set_flag(HMGL gr, int val, long flag)	{	gr->set(val,flag);	}
+int MGL_EXPORT mgl_get_flag(HMGL gr, uint32_t flag)	{	return gr->get(flag);	}
+int MGL_EXPORT mgl_get_flag_(uintptr_t *gr, unsigned long *flag)	{	return _GR_->get(*flag);	}
+void MGL_EXPORT mgl_set_flag(HMGL gr, int val, uint32_t flag)		{	gr->set(val,flag);	}
+void MGL_EXPORT mgl_set_flag_(uintptr_t *gr, int *val, unsigned long *flag)	{	_GR_->set(*val,*flag);	}
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_set_color(char id, double r, double g, double b)
 {
-	register size_t i;
-	for(i=0;mglColorIds[i].id;i++)	if(mglColorIds[i].id==id)	mglColorIds[i].col = mglColor(r,g,b);
+	for(long i=0;mglColorIds[i].id;i++)
+		if(mglColorIds[i].id==id)	mglColorIds[i].col = mglColor(r,g,b);
 }
 void MGL_EXPORT mgl_set_color_(char *id, mreal *r, mreal *g, mreal *b, int)	{	mgl_set_color(*id,*r,*g,*b);	}
 //-----------------------------------------------------------------------------
@@ -79,13 +84,15 @@ void MGL_EXPORT mgl_set_range_val(HMGL gr, char dir, double v1,double v2)
 	if(dir=='c')		gr->CRange(v1,v2);
 	else if(dir=='x')	gr->XRange(v1,v2);
 	else if(dir=='y')	gr->YRange(v1,v2);
-	else if(dir=='z')	gr->ZRange(v1,v2);	}
+	else if(dir=='z')	gr->ZRange(v1,v2);
+}
 void MGL_EXPORT mgl_set_range_dat(HMGL gr, char dir, HCDT a, int add)
 {
 	if(dir=='c')		gr->CRange(a,add);
 	else if(dir=='x')	gr->XRange(a,add);
 	else if(dir=='y')	gr->YRange(a,add);
-	else if(dir=='z')	gr->ZRange(a,add);	}
+	else if(dir=='z')	gr->ZRange(a,add);
+}
 void MGL_EXPORT mgl_set_ranges(HMGL gr, double x1, double x2, double y1, double y2, double z1, double z2)
 {	gr->SetRanges(x1,x2,y1,y2,z1,z2);	}
 void MGL_EXPORT mgl_set_auto_ranges(HMGL gr, double x1, double x2, double y1, double y2, double z1, double z2, double c1, double c2)
@@ -217,8 +224,35 @@ long MGL_EXPORT mgl_use_graph_(uintptr_t *gr, int *inc)
 void MGL_EXPORT mgl_set_ambbr(HMGL gr, double i)		{	gr->SetAmbient(i);	}
 void MGL_EXPORT mgl_set_ambbr_(uintptr_t *gr, mreal *i){	_GR_->SetAmbient(*i);	}
 //---------------------------------------------------------------------------
+void MGL_EXPORT mgl_set_difbr(HMGL gr, double i)		{	gr->SetDiffuse(i);	}
+void MGL_EXPORT mgl_set_difbr_(uintptr_t *gr, mreal *i){	_GR_->SetDiffuse(*i);	}
+//---------------------------------------------------------------------------
 void MGL_EXPORT mgl_zoom_axis(HMGL gr, double x1,double y1,double z1,double c1,double x2,double y2,double z2,double c2)
 {	gr->ZoomAxis(mglPoint(x1,y1,z1,c1), mglPoint(x2,y2,z2,c2));	}
 void MGL_EXPORT mgl_zoom_axis_(uintptr_t *gr, mreal *x1, mreal *y1, mreal *z1, mreal *c1, mreal *x2, mreal *y2, mreal *z2, mreal *c2)
 {	_GR_->ZoomAxis(mglPoint(*x1,*y1,*z1,*c1), mglPoint(*x2,*y2,*z2,*c2));	}
 //---------------------------------------------------------------------------
+extern uint64_t mgl_mask_def[16];
+void MGL_EXPORT mgl_set_mask(char id, const char *mask)
+{
+	const char *msk = MGL_MASK_ID, *s = mglchr(msk, id);
+	if(s)
+	{
+		uint64_t val = (mask && *mask) ? strtoull(mask,NULL,16) : mgl_mask_def[s-msk];
+		mgl_mask_val[s-msk] = val;
+	}
+}
+void MGL_EXPORT mgl_set_mask_(const char *id, const char *mask,int,int l)
+{	char *s=new char[l+1];	memcpy(s,mask,l);	s[l]=0;	mgl_set_mask(*id,s);	delete []s;	}
+//---------------------------------------------------------------------------
+void MGL_EXPORT mgl_set_mask_val(char id, uint64_t mask)
+{
+	const char *msk = MGL_MASK_ID, *s = mglchr(msk, id);
+	if(s)	mgl_mask_val[s-msk]=mask;
+}
+void MGL_EXPORT mgl_set_mask_val_(const char *id, uint64_t *mask,int)
+{	mgl_set_mask_val(*id,*mask);	}
+//---------------------------------------------------------------------------
+void MGL_EXPORT mgl_set_mask_angle(HMGL gr, int angle)	{	gr->SetMaskAngle(angle);	}
+void MGL_EXPORT mgl_set_mask_angle_(uintptr_t *gr, int *angle)	{	_GR_->SetMaskAngle(*angle);	}
+//---------------------------------------------------------------------------
diff --git a/src/canvas.cpp b/src/canvas.cpp
index b69308d..16a0c15 100644
--- a/src/canvas.cpp
+++ b/src/canvas.cpp
@@ -31,7 +31,6 @@ mglCanvas::mglCanvas(int w, int h) : mglBase()
 	CurFrameId=0;	Delay=0.5;
 	Width=Height=Depth=0;	ObjId=-1;
 	fscl=ftet=0;		PlotId = "frame";
-	dr_nx1=dr_nx2=dr_ny1=dr_ny2=0;	// Allowed drawing region
 
 	ac.ch='c';
 	ax.dir = mglPoint(1,0,0);	ax.a = mglPoint(0,1,0);	ax.b = mglPoint(0,0,1);	ax.ch='x';
@@ -50,6 +49,7 @@ long mglCanvas::PushDrwDat()
 {
 	mglDrawDat d;
 	d.Pnt=Pnt;	d.Prm=Prm;	d.Glf=Glf;	d.Ptx=Ptx;	d.Txt=Txt;
+#pragma omp critical(drw)
 	MGL_PUSH(DrwDat,d,mutexDrw);
 	return DrwDat.size();
 }
@@ -58,16 +58,18 @@ void mglCanvas::ResetFrames()	{	CurFrameId=0;	DrwDat.clear();	}
 //-----------------------------------------------------------------------------
 void mglCanvas::SetFrame(long i)
 {
-	if(get(MGL_VECT_FRAME) && i>=0 && i<DrwDat.size())
+	if(get(MGL_VECT_FRAME) && i>=0 && i<long(DrwDat.size()))
 	{
 		Finish();	CurFrameId--;
 		mglDrawDat d;
 		d.Pnt=Pnt;	d.Prm=Prm;	d.Glf=Glf;	d.Ptx=Ptx;	d.Txt=Txt;
 #if MGL_HAVE_PTHREAD
 		pthread_mutex_lock(&mutexDrw);
+#pragma omp critical(drw)
 		DrwDat[i] = d;
 		pthread_mutex_unlock(&mutexDrw);
 #else
+#pragma omp critical(drw)
 		DrwDat[i] = d;
 #endif
 	}
@@ -85,7 +87,8 @@ void mglCanvas::GetFrame(long k)
 	pthread_mutex_lock(&mutexPtx);
 	pthread_mutex_lock(&mutexTxt);
 #endif
-	Pnt=d.Pnt;	Prm=d.Prm;	Glf=d.Glf;	Ptx=d.Ptx;	Txt=d.Txt;
+#pragma omp critical
+	{	Pnt=d.Pnt;	Prm=d.Prm;	Glf=d.Glf;	Ptx=d.Ptx;	Txt=d.Txt;	}
 #if MGL_HAVE_PTHREAD
 	pthread_mutex_unlock(&mutexTxt);
 	pthread_mutex_unlock(&mutexPtx);
@@ -107,33 +110,35 @@ void mglCanvas::ShowFrame(long k)
 	pthread_mutex_lock(&mutexPtx);
 	pthread_mutex_lock(&mutexTxt);
 #endif
-	const mglDrawDat &d=DrwDat[k];
-	register size_t i;
-	Glf.reserve(d.Glf.size());	for(i=0;i<d.Glf.size();i++)	Glf.push_back(d.Glf[i]);
-	Ptx.reserve(d.Ptx.size());	for(i=0;i<d.Ptx.size();i++)	Ptx.push_back(d.Ptx[i]);
-	Txt.reserve(d.Pnt.size());	for(i=0;i<d.Txt.size();i++)	Txt.push_back(d.Txt[i]);
-	Pnt.reserve(d.Pnt.size());
-	for(i=0;i<d.Pnt.size();i++)
-	{
-		mglPnt p = d.Pnt[i]; 	p.c += ntxt;
-		Pnt.push_back(p);
-	}
-	Prm.reserve(d.Prm.size());
-	for(i=0;i<d.Prm.size();i++)
+#pragma omp critical
 	{
-		mglPrim p = d.Prm[i];
-		p.n1 += npnt;
-
-		switch(p.type)
+		const mglDrawDat &d=DrwDat[k];
+		Glf.reserve(d.Glf.size());	for(size_t i=0;i<d.Glf.size();i++)	Glf.push_back(d.Glf[i]);
+		Ptx.reserve(d.Ptx.size());	for(size_t i=0;i<d.Ptx.size();i++)	Ptx.push_back(d.Ptx[i]);
+		Txt.reserve(d.Pnt.size());	for(size_t i=0;i<d.Txt.size();i++)	Txt.push_back(d.Txt[i]);
+		Pnt.reserve(d.Pnt.size());
+		for(size_t i=0;i<d.Pnt.size();i++)
 		{
-		case 1:	p.n2 += npnt;	break;
-		case 2:	p.n2 += npnt;	p.n3 += npnt;	break;
-		case 3:	p.n2 += npnt;	p.n3 += npnt;	p.n4 += npnt;	break;
-		case 4: p.n4 += nglf;	break;
-		case 5:	p.n2 += npnt;	break;
-		case 6: p.n3 += nptx;	break;
+			mglPnt p = d.Pnt[i]; 	p.c += ntxt;
+			Pnt.push_back(p);
+		}
+		Prm.reserve(d.Prm.size());
+		for(size_t i=0;i<d.Prm.size();i++)
+		{
+			mglPrim p = d.Prm[i];
+			p.n1 += npnt;
+
+			switch(p.type)
+			{
+			case 1:	p.n2 += npnt;	break;
+			case 2:	p.n2 += npnt;	p.n3 += npnt;	break;
+			case 3:	p.n2 += npnt;	p.n3 += npnt;	p.n4 += npnt;	break;
+			case 4: p.n4 += nglf;	break;
+			case 5:	p.n2 += npnt;	break;
+			case 6: p.n3 += nptx;	break;
+			}
+			Prm.push_back(p);
 		}
-		Prm.push_back(p);
 	}
 #if MGL_HAVE_PTHREAD
 	pthread_mutex_unlock(&mutexPnt);
@@ -153,11 +158,14 @@ void mglCanvas::add_prim(mglPrim &a)
 	if(a.n1>=0)
 	{
 		a.z = Pnt[a.n1].z;	// this is a bit less accurate but simpler for transformation
-		a.id = ObjId;	MGL_PUSH(Prm,a,mutexPrm);
+		a.id = ObjId;
+#pragma omp critical(prm)
+		MGL_PUSH(Prm,a,mutexPrm);
 		clr(MGL_FINISHED);
 	}
 }
 //-----------------------------------------------------------------------------
+extern uint64_t mgl_mask_def[16];
 void mglCanvas::DefaultPlotParam()
 {
 /* NOTE: following variables and mutex will not be changed by DefaultPlotParam()
@@ -169,6 +177,9 @@ int Height;			///< Height of the image
 int Depth;			///< Depth of the image
 int CurFrameId;		///< Number of automaticle created frames
 GifFileType *gif;*/
+	SetDrawReg(1,1,0);
+	memcpy(mgl_mask_val, mgl_mask_def, 16*sizeof(uint64_t));	// should be > 16*8
+	mgl_clear_fft();		DefMaskAn=0;	ResetMask();
 	SetTickRotate(true);	SetTickSkip(true);
 	SetWarn(mglWarnNone,"");	mglGlobalMess = "";
 	ObjId = -1;	HighId = INT_MIN;
@@ -180,7 +191,7 @@ GifFileType *gif;*/
 	SetTranspType(0);		SetMeshNum(0);	// NOTE: default MeshNum=0
 	SetRotatedText(true);	CurrPal = 0;
 	SetLegendMarks();		SetFontSize(4);
-	SetTuneTicks(-1);		SetAmbient();
+	SetTuneTicks(3);		SetAmbient();	SetDiffuse();
 	clr(MGL_DISABLE_SCALE);
 	clr(MGL_USE_GMTIME);	clr(MGL_NOSUBTICKS);
 	SetDifLight(false);		SetReduceAcc(false);
@@ -190,7 +201,7 @@ GifFileType *gif;*/
 	stack.clear();	Restore();	DefColor('k');
 	SetPlotFactor(0);	InPlot(0,1,0,1,false);
 	SetTickLen(0);	SetCut(true);
-	AdjustTicks("xyzc",true);	Clf();
+	AdjustTicks("xyzc",true);	Clf('w');
 
 	for(int i=0;i<10;i++)	{	AddLight(i, mglPoint(0,0,1));	Light(i,false);	}
 	Light(0,true);	Light(false);	SetDifLight(true);
@@ -200,70 +211,54 @@ GifFileType *gif;*/
 //-----------------------------------------------------------------------------
 mreal mglCanvas::FindOptOrg(char dir, int ind) const
 {
-	static mglPoint px, py, pz, m1, m2;
-	static mglMatrix bb;	bb.b[0]=1e30;
+	static mglPoint px, py, pz;
+	static mglMatrix bb;
 	mglPoint nn[8]={mglPoint(0,0,0), mglPoint(0,0,1), mglPoint(0,1,0,0), mglPoint(0,1,1),
-	mglPoint(1,0,0), mglPoint(1,0,1), mglPoint(1,1,0), mglPoint(1,1,1)}, pp[8];
+					mglPoint(1,0,0), mglPoint(1,0,1), mglPoint(1,1,0), mglPoint(1,1,1)}, pp[8];
 	memcpy(pp, nn, 8*sizeof(mglPoint));
-	// do nothing if transformation matrix the same
-	if(memcmp(B.b,bb.b,9*sizeof(mreal)) || m1!=Min || m2!=Max)
+	// do nothing if transformation matrix is the same
+	if(B!=bb)
 	{
-		m1 = Min;	m2 = Max;	memcpy(&bb,&B,sizeof(mglMatrix));
-		PostScale(pp,8);
+		bb = B;
+#pragma omp parallel for
+		for(long i=0;i<8;i++)	PostScale(&B,pp[i]);
 		// find point with minimal y
-		register long i,j=0;
-		for(i=1;i<8;i++)	if(pp[i].y<pp[j].y)	j=i;
+		long j=0;
+		for(long i=1;i<8;i++)	if(pp[i].y<pp[j].y)	j=i;
 		pp[0]=pp[j];
-		// find max angle and left point
 		// first select 3 closest points
-		pp[1]=nn[j];	pp[1].x=1-pp[1].x;
-		pp[2]=nn[j];	pp[2].y=1-pp[2].y;
-		pp[3]=nn[j];	pp[3].z=1-pp[3].z;
-		PostScale(pp+1,3);
-		pp[1]-=pp[0];	pp[2]-=pp[0];	pp[3]-=pp[0];
+		pp[1].x=1-nn[j].x;	pp[1].y=nn[j].y;	pp[1].z=nn[j].z;	PostScale(&B,pp[1]);	pp[1]-=pp[0];
+		pp[2].x=nn[j].x;	pp[2].y=1-nn[j].y;	pp[2].z=nn[j].z;	PostScale(&B,pp[2]);	pp[2]-=pp[0];
+		pp[3].x=nn[j].x;	pp[3].y=nn[j].y;	pp[3].z=1-nn[j].z;	PostScale(&B,pp[3]);	pp[3]-=pp[0];
 		// find cosine of axis projection
-		mreal cxy, cxz, cyz, dx, dy, dz;
-		dx = pp[1].x*pp[1].x + pp[1].y*pp[1].y;
-		dy = pp[2].x*pp[2].x + pp[2].y*pp[2].y;
-		dz = pp[3].x*pp[3].x + pp[3].y*pp[3].y;
-		cxy= pp[1].x*pp[2].x + pp[1].y*pp[1].y;
-		cxz= pp[1].x*pp[3].x + pp[1].y*pp[3].y;
-		cyz= pp[3].x*pp[2].x + pp[3].y*pp[2].y;
-		if(dx==0)		cxy = cxz = 1;
-		else if(dy==0)	cxy = cyz = 1;
-		else if(dz==0)	cyz = cxz = 1;
-		else
-		{	cxy /= sqrt(dx*dy);	cxz /= sqrt(dx*dz);	cyz /= sqrt(dz*dy);	}
-		// find points for axis
-		px = py = pz = nn[j];
-		if(cxy<cxz && cxy<cyz)	// xy is lowest
-		{	// px, py the same as pp
-			if(pp[1].x<pp[2].x)	pz.x = 1-pz.x;
-			else	pz.y = 1-pz.y;
-		}
-		if(cxz<cxy && cxz<cyz)	// xz is lowest
-		{	// px, pz the same as pp
-			if(pp[1].x<pp[3].x)	py.x = 1-py.x;
-			else	py.z = 1-py.z;
-		}
-		if(cyz<cxz && cyz<cxy)	// yz is lowest
-		{	// py, pz the same as pp
-			if(pp[3].x<pp[2].x)	px.z = 1-px.z;
-			else	px.y = 1-px.y;
+		register mreal tx=fabs(pp[1].x/pp[1].y), ty=fabs(pp[2].x/pp[2].y), tz=fabs(pp[3].x/pp[3].y);
+		px=py=pz=nn[j];
+		if(tz==0 && (ty==0 || tx==0))	// (x- & z-) or (y- & z-) axis are vertical
+		{	if(pp[1].x>pp[2].x)	pz.y=1-pz.y;	else	pz.x=1-pz.x;	}
+		else if(tx==0 && ty==0)	// x- && y-axis is vertical
+		{
+			py.x=1-py.x;
+			if(pp[1].x>pp[3].x)
+			{	px.z=1-px.z;	py.z=1-py.z;	}
 		}
-		// return to normal variables
-		// NOTE: this may not work in "inverse" curvilinear coordinates like x->1-x
-		px = Min+(Max-Min)/px;
-		py = Min+(Max-Min)/py;
-		pz = Min+(Max-Min)/pz;
+		else if(tz<tx && tz<ty)	// z-axis is vertical
+		{	if(pp[1].x>pp[2].x)	pz.y=1-pz.y;	else	pz.x=1-pz.x;	}
+		else if(ty<tx && ty<tz)	// y-axis is vertical
+		{	if(pp[1].x>pp[3].x)	py.z=1-py.z;	else	py.x=1-py.x;	}
+		else if(tx<tz && tx<tz)	// x-axis is vertical
+		{	if(pp[3].x>pp[2].x)	px.y=1-px.y;	else	px.z=1-px.z;	}
 	}
-	mreal res = px.val(ind);
-	if(dir=='y')	res = py.val(ind);
-	if(dir=='z')	res = pz.val(ind);
+	// return to normal variables
+	mglPoint rx = Min+(Max-Min)/px;
+	mglPoint ry = Min+(Max-Min)/py;
+	mglPoint rz = Min+(Max-Min)/pz;
+	mreal res = rx.val(ind);
+	if(dir=='y')	res = ry.val(ind);
+	if(dir=='z')	res = rz.val(ind);
 	return res;
 }
 //-----------------------------------------------------------------------------
-mreal mglCanvas::GetOrgX(char dir) const
+mreal mglCanvas::GetOrgX(char dir, bool inv) const
 {
 	mreal res = Org.x;
 	if(mgl_isnan(res))
@@ -271,11 +266,12 @@ mreal mglCanvas::GetOrgX(char dir) const
 		if(strchr("xyz",dir))	res = FindOptOrg(dir,0);
 		else if(dir=='t')		res = Min.x;
 		else res = B.b[6]>0 ? Max.x:Min.x;
+		if(inv)	res = Min.x+Max.x-res;
 	}
 	return res;
 }
 //-----------------------------------------------------------------------------
-mreal mglCanvas::GetOrgY(char dir) const
+mreal mglCanvas::GetOrgY(char dir, bool inv) const
 {
 	mreal res = Org.y;
 	if(mgl_isnan(res))
@@ -283,11 +279,12 @@ mreal mglCanvas::GetOrgY(char dir) const
 		if(strchr("xyz",dir))	res = FindOptOrg(dir,1);
 		else if(dir=='t')	res = Min.y;
 		else res = B.b[7]>0 ? Max.y:Min.y;
+		if(inv)	res = Min.y+Max.y-res;
 	}
 	return res;
 }
 //-----------------------------------------------------------------------------
-mreal mglCanvas::GetOrgZ(char dir) const
+mreal mglCanvas::GetOrgZ(char dir, bool inv) const
 {
 	mreal res = Org.z;
 	if(mgl_isnan(res))
@@ -295,36 +292,37 @@ mreal mglCanvas::GetOrgZ(char dir) const
 		if(strchr("xyz",dir))	res = FindOptOrg(dir,2);
 		else if(dir=='t')	res = Min.z;
 		else res = B.b[8]>0 ? Max.z:Min.z;
+		if(inv)	res = Min.z+Max.z-res;
 	}
 	return res;
 }
 //-----------------------------------------------------------------------------
 //	Put primitives
 //-----------------------------------------------------------------------------
-#define MGL_MARK_PLOT	if(Quality&4)	mark_draw(Pnt[p],type,size,&d);else	\
+#define MGL_MARK_PLOT	if(Quality&MGL_DRAW_LMEM)	mark_draw(Pnt[p],type,size,&d);else	\
 						{	mglPrim a;	a.w = pw;	a.s = size;	\
-							a.n1 = p;	a.n4 = type;	add_prim(a);	}
+							a.n1 = p;	a.n4 = type;	a.angl=0;	add_prim(a);	}
 void mglCanvas::mark_plot(long p, char type, mreal size)
 {
 	if(p<0 || mgl_isnan(Pnt[p].x) || mgl_isnan(size))	return;
 	long pp=p;
 //	mreal pw = fabs(PenWidth)*0.15/sqrt(font_factor);
 	mreal pw = 0.15/sqrt(font_factor);
-	mglDrawReg d;	d.set(this,1,1,0);
-	d.PDef = PDef;	d.pPos = pPos;
-	d.ObjId = ObjId;	d.PenWidth=pw;
-	if(size>=0)	size *= MarkSize;
-	if(size==0)	size = MarkSize;
-	size *= 0.35*font_factor;
+	mglDrawReg d;	d.set(this,dr_x,dr_y,dr_p);
+	d.PDef = PDef;	d.pPos = pPos;	d.PenWidth=pw;
+//	if(size>=0)	size *= MarkSize;
+//	if(size==0)	size = MarkSize;
+	size = size?fabs(size):1;
+	size *= MarkSize*0.35*font_factor;
 	if(type=='.')	size = fabs(PenWidth)*sqrt(font_factor/400);
 	if(TernAxis&4) for(int i=0;i<4;i++)
 	{	p = ProjScale(i, pp);	MGL_MARK_PLOT	}
 	else	{	MGL_MARK_PLOT	}
 }
 //-----------------------------------------------------------------------------
-#define MGL_LINE_PLOT	if(Quality&4)	line_draw(Pnt[p1],Pnt[p2],&dd);else	\
+#define MGL_LINE_PLOT	if(Quality&MGL_DRAW_LMEM)	line_draw(Pnt[p1],Pnt[p2],&dd);else	\
 						{	mglPrim a(1);	a.n3=PDef;	a.s = pPos;	\
-							a.n1 = p1;	a.n2 = p2;	a.w = pw;	add_prim(a);	}
+							a.n1 = p1;	a.n2 = p2;	a.w = pw;	a.angl=0;	add_prim(a);	}
 void mglCanvas::line_plot(long p1, long p2)
 {
 	if(PDef==0)	return;
@@ -334,9 +332,8 @@ void mglCanvas::line_plot(long p1, long p2)
 	mreal pw = fabs(PenWidth)*sqrt(font_factor/400), d;
 	d = hypot(Pnt[p1].x-Pnt[p2].x, Pnt[p1].y-Pnt[p2].y);
 
-	mglDrawReg dd;		dd.set(this,1,1,0);
-	dd.PDef = PDef;		dd.pPos = pPos;
-	dd.ObjId = ObjId;	dd.PenWidth=pw;
+	mglDrawReg dd;	dd.set(this,dr_x,dr_y,dr_p);
+	dd.PDef = PDef;	dd.pPos = pPos;	dd.PenWidth=pw;
 
 	if(TernAxis&4) for(int i=0;i<4;i++)
 	{	p1 = ProjScale(i, pp1);	p2 = ProjScale(i, pp2);
@@ -345,23 +342,24 @@ void mglCanvas::line_plot(long p1, long p2)
 	pPos = fmod(pPos+d/pw/1.5, 16);
 }
 //-----------------------------------------------------------------------------
-#define MGL_TRIG_PLOT	if(Quality&4)	trig_draw(Pnt[p1],Pnt[p2],Pnt[p3],true,&d);else	\
-						{	mglPrim a(2);	a.n1 = p1;	a.n2 = p2;	\
-							a.n3 = p3;	add_prim(a);}
+#define MGL_TRIG_PLOT	if(Quality&MGL_DRAW_LMEM)	trig_draw(Pnt[p1],Pnt[p2],Pnt[p3],true,&d);else	\
+						{	mglPrim a(2);	a.n1 = p1;	a.n2 = p2;	a.n3 = p3;	\
+							a.m=mask;	a.angl=MaskAn;	a.w = pw;	add_prim(a);}
 void mglCanvas::trig_plot(long p1, long p2, long p3)
 {
 	if(p1<0 || p2<0 || p3<0 || mgl_isnan(Pnt[p1].x) || mgl_isnan(Pnt[p2].x) || mgl_isnan(Pnt[p3].x))	return;
 	long pp1=p1,pp2=p2,pp3=p3;
-	mglDrawReg d;	d.set(this,1,1,0);	d.ObjId = ObjId;
+	mreal pw = fabs(PenWidth)*sqrt(font_factor/400);
+	mglDrawReg d;	d.set(this,dr_x,dr_y,dr_p);	d.PenWidth=pw;
 	if(TernAxis&4) for(int i=0;i<4;i++)
 	{	p1 = ProjScale(i, pp1);	p2 = ProjScale(i, pp2);
 		p3 = ProjScale(i, pp3);	MGL_TRIG_PLOT	}
 	else	{	MGL_TRIG_PLOT	}
 }
 //-----------------------------------------------------------------------------
-#define MGL_QUAD_PLOT	if(Quality&4)	quad_draw(Pnt[p1],Pnt[p2],Pnt[p3],Pnt[p4],&d);else	\
-						{	mglPrim a(3);	a.n1 = p1;	a.n2 = p2;	\
-							a.n3 = p3;	a.n4 = p4;	add_prim(a);	}
+#define MGL_QUAD_PLOT	if(Quality&MGL_DRAW_LMEM)	quad_draw(Pnt[p1],Pnt[p2],Pnt[p3],Pnt[p4],&d);else	\
+						{	mglPrim a(3);	a.n1 = p1;	a.n2 = p2;	a.n3 = p3;	a.n4 = p4;	\
+							a.m=mask;	a.angl=MaskAn;	a.w = pw;	add_prim(a);	}
 void mglCanvas::quad_plot(long p1, long p2, long p3, long p4)
 {
 	if(p1<0 || mgl_isnan(Pnt[p1].x))	{	trig_plot(p4,p2,p3);	return;	}
@@ -369,7 +367,8 @@ void mglCanvas::quad_plot(long p1, long p2, long p3, long p4)
 	if(p3<0 || mgl_isnan(Pnt[p3].x))	{	trig_plot(p1,p2,p4);	return;	}
 	if(p4<0 || mgl_isnan(Pnt[p4].x))	{	trig_plot(p1,p2,p3);	return;	}
 	long pp1=p1,pp2=p2,pp3=p3,pp4=p4;
-	mglDrawReg d;	d.set(this,1,1,0);	d.ObjId = ObjId;
+	mreal pw = fabs(PenWidth)*sqrt(font_factor/400);
+	mglDrawReg d;	d.set(this,dr_x,dr_y,dr_p);	d.PenWidth=pw;
 	if(TernAxis&4) for(int i=0;i<4;i++)
 	{	p1 = ProjScale(i, pp1);	p2 = ProjScale(i, pp2);
 		p3 = ProjScale(i, pp3);	p4 = ProjScale(i, pp4);
@@ -401,99 +400,98 @@ mreal mglCanvas::text_plot(long p,const wchar_t *text,const char *font,mreal siz
 
 	mreal fsize=size/6.5*font_factor, h = fnt->Height(font)*fsize, w, shift = -(sh+0.02)*h;
 	// text drawing itself
-	Push();
+
 #if MGL_HAVE_PTHREAD
 pthread_mutex_lock(&mutexPtx);
 #endif
-	inv = inv ^ (strchr(font,'T')!=0);
-	if(inv)	shift = 0.2*h-shift;
-	shift += 0.015*h;	// Correction for glyph rotation around proper point
-//	shift *= h;
-
-	int align;	mglGetStyle(font,0,&align);	align = align&3;
-	B.x = q.x;	B.y = q.y - shift;	B.z = q.z;
-	if(ll>0)
+#pragma omp critical(ptx)
 	{
-		B.x += shift*q.v/sqrt(ll);	B.y += shift*(1-q.u/sqrt(ll));
-		if(q.u==0 && !get(MGL_ENABLE_RTEXT))	B.y -= 0.1*h;
-	}
-	fscl = fsize;	forg = p;
+		Bt = B;
+		inv = inv ^ (strchr(font,'T')!=0);
+		if(inv)	shift = 0.2*h-shift;
+		shift += 0.015*h;	// Correction for glyph rotation around proper point
+	//		shift *= h;
 
-	if(mgl_isnan(ll) || !get(MGL_ENABLE_RTEXT))	ftet = 0;
-	else if(ll)	ftet = -180*atan2(q.v,q.u)/M_PI;
-	else 	ftet = NAN;
+		int align;	mglGetStyle(font,0,&align);	align = align&3;
+		Bt.x = q.x;	Bt.y = q.y - shift;	Bt.z = q.z;
+		if(ll>0)
+		{
+			Bt.x += shift*q.v/sqrt(ll);	Bt.y += shift*(1-q.u/sqrt(ll));
+			if(q.u==0 && !get(MGL_ENABLE_RTEXT))	Bt.y -= 0.1*h;
+		}
+		fscl = fsize;	forg = p;
 
-	if(!(Quality&4))	// add text itself
-	{
-		char ch = mglGetStyle(font,0,0);
-		mglColor mc(ch);
-		if(!ch)	mc = col<0 ? mglColor(char(0.5-col)):Txt[long(col)].GetC(col);
+		if(mgl_isnan(ll) || !get(MGL_ENABLE_RTEXT))	ftet = 0;
+		else if(ll)	ftet = -180*atan2(q.v,q.u)/M_PI;
+		else 	ftet = NAN;
 
-/*		for(long i=0;i<Prm.size();i++)	// try don't draw text if one present at this point
+		if(!(Quality&MGL_DRAW_LMEM))	// add text itself
 		{
-			const mglPnt &t=Pnt[Prm[i].n1];
-			if(Prm[i].type==6 && t.x==q.x && t.y==q.y)
-			{
-#if MGL_HAVE_PTHREAD
-				pthread_mutex_unlock(&mutexPtx);
-#endif
-				Pop();
-				return 0;
-			}
-		}*/
+			char ch = mglGetStyle(font,0,0);
+			mglColor mc(ch);
+			if(!ch)	mc = col<0 ? mglColor(char(0.5-col)):Txt[long(col)].GetC(col);
 
-		mglPrim a(6);	a.n1 = p;
-		a.n2 = int(255*mc.r) + 256*(int(255*mc.g) + 256*int(255*mc.b));
-		mglText txt(text,font);
-		Ptx.push_back(txt);	a.n3 = Ptx.size()-1;
-		a.s = size;	a.w = shift;	a.p=ftet;
-		add_prim(a);
-	}
+			mglPrim a(6);	a.n1 = p;
+			a.n2 = int(255*mc.r) + 256*(int(255*mc.g) + 256*int(255*mc.b));
+			mglText txt(text,font);
+			Ptx.push_back(txt);	a.n3 = Ptx.size()-1;
+			a.s = size;	a.w = shift;	a.p=ftet;
+			add_prim(a);
+		}
 
-	memset(B.b,0,9*sizeof(mreal));
-	B.b[0] = B.b[4] = B.b[8] = fscl;
-	register mreal opf = B.pf;
-	RotateN(ftet,0,0,1);	B.pf = opf;
-	if(strchr(font,'@'))	// draw box around text
-	{
-		long k1,k2,k3,k4;	mglPnt pt;	mglPoint pp;
-		w = fnt->Width(text,font);	h = fnt->Height(font);
-//		int align;	mglGetStyle(font,0,&align);	align = align&3;
-		mreal d=-w*align/2.-h*0.2;	w+=h*0.4;
-		pt = q;	pp = mglPoint(d,-h*0.4);		PostScale(pp);
-		pt.x=pt.xx=pp.x;	pt.y=pt.yy=pp.y;	MGL_PUSH(Pnt,pt,mutexPnt);	k1=Pnt.size()-1;
-		pt = q;	pp = mglPoint(w+d,-h*0.4);		PostScale(pp);
-		pt.x=pt.xx=pp.x;	pt.y=pt.yy=pp.y;	MGL_PUSH(Pnt,pt,mutexPnt);	k2=Pnt.size()-1;
-		pt = q;	pp = mglPoint(d,h*1.2);			PostScale(pp);
-		pt.x=pt.xx=pp.x;	pt.y=pt.yy=pp.y;	MGL_PUSH(Pnt,pt,mutexPnt);	k3=Pnt.size()-1;
-		pt = q;	pp = mglPoint(w+d,h*1.2);		PostScale(pp);
-		pt.x=pt.xx=pp.x;	pt.y=pt.yy=pp.y;	MGL_PUSH(Pnt,pt,mutexPnt);	k4=Pnt.size()-1;
-		line_plot(k1,k2);	line_plot(k1,k3);	line_plot(k4,k2);	line_plot(k4,k3);
+		memset(Bt.b,0,9*sizeof(mreal));
+		Bt.b[0] = Bt.b[4] = Bt.b[8] = fscl;
+		register mreal opf = Bt.pf;
+		Bt.RotateN(ftet,0,0,1);	Bt.pf = opf;
+		if(strchr(font,'@'))	// draw box around text
+		{
+			long k1,k2,k3,k4;	mglPnt pt;	mglPoint pp;
+			w = fnt->Width(text,font);	h = fnt->Height(font);
+//			int align;	mglGetStyle(font,0,&align);	align = align&3;
+			mreal d=-w*align/2.-h*0.2;	w+=h*0.4;
+			pt = q;	pp = mglPoint(d,-h*0.4);		PostScale(&Bt,pp);
+			pt.x=pt.xx=pp.x;	pt.y=pt.yy=pp.y;
+#pragma omp critical(pnt)
+			{MGL_PUSH(Pnt,pt,mutexPnt);	k1=Pnt.size()-1;}
+			pt = q;	pp = mglPoint(w+d,-h*0.4);		PostScale(&Bt,pp);
+			pt.x=pt.xx=pp.x;	pt.y=pt.yy=pp.y;
+#pragma omp critical(pnt)
+			{MGL_PUSH(Pnt,pt,mutexPnt);	k2=Pnt.size()-1;}
+			pt = q;	pp = mglPoint(d,h*1.2);			PostScale(&Bt,pp);
+			pt.x=pt.xx=pp.x;	pt.y=pt.yy=pp.y;
+#pragma omp critical(pnt)
+			{MGL_PUSH(Pnt,pt,mutexPnt);	k3=Pnt.size()-1;}
+			pt = q;	pp = mglPoint(w+d,h*1.2);		PostScale(&Bt,pp);
+			pt.x=pt.xx=pp.x;	pt.y=pt.yy=pp.y;
+#pragma omp critical(pnt)
+			{MGL_PUSH(Pnt,pt,mutexPnt);	k4=Pnt.size()-1;}
+			line_plot(k1,k2);	line_plot(k1,k3);
+			line_plot(k4,k2);	line_plot(k4,k3);
+		}
+		fsize *= fnt->Puts(text,font,col)/2;
 	}
-	fsize *= fnt->Puts(text,font,col)/2;
 #if MGL_HAVE_PTHREAD
 	pthread_mutex_unlock(&mutexPtx);
 #endif
-	Pop();	return fsize;
+	return fsize;
 }
 //-----------------------------------------------------------------------------
 void mglCanvas::Glyph(mreal x, mreal y, mreal f, int s, long j, mreal col)
 {
 	mglPrim a(4);	// NOTE: no projection since text_plot() did it
-	a.s = fscl/B.pf;
+	a.s = fscl/Bt.pf;
 	a.w = get(MGL_ENABLE_RTEXT)?ftet:1e5;
 	a.p = f/fnt->GetFact(s&3);
 	mreal cc = col<0 ? AddTexture(char(0.5-col)):col;
 	if(cc<0)	cc = CDef;
-	a.n1 = AddPnt(mglPoint(B.x,B.y,B.z), cc, mglPoint(x,y,NAN), -1, -1);
+	a.n1 = AddPnt(&Bt, mglPoint(Bt.x,Bt.y,Bt.z), cc, mglPoint(x,y,NAN), -1, -1);
 	a.n2 = forg; 	a.n3 = s;	a.n4 = AddGlyph(s,j);
 	if(a.n1<0)	return;
 
-	mglDrawReg d;	d.set(this,1,1,0);
-	d.PDef = s;		d.pPos = a.s;
-	d.ObjId=ObjId;	d.PenWidth=a.w;
-	
-	if(Quality&4)	glyph_draw(a,&d);
+	mglDrawReg d;	d.set(this,dr_x,dr_y,dr_p);
+	d.PDef = s;		d.pPos = a.s;	d.PenWidth=a.w;
+
+	if(Quality&MGL_DRAW_LMEM)	glyph_draw(a,&d);
 	else	add_prim(a);
 }
 //-----------------------------------------------------------------------------
@@ -507,6 +505,7 @@ void mglCanvas::InPlot(mreal x1,mreal x2,mreal y1,mreal y2, const char *st)
 	inX=Width*x1;	inY=Height*y1;	ZMin=1;
 	mglPrim p;	p.id = ObjId;
 	p.n1=x1*Width;	p.n2=x2*Width;	p.n3=y1*Height;	p.n4=y2*Height;
+#pragma omp critical(sub)
 	MGL_PUSH(Sub,p,mutexSub);
 
 	if(strchr(st,'T'))	{	y1*=0.9;	y2*=0.9;	}	// general title
@@ -534,33 +533,34 @@ void mglCanvas::InPlot(mreal x1,mreal x2,mreal y1,mreal y2, const char *st)
 	B1=B;	font_factor = B.b[0] < B.b[4] ? B.b[0] : B.b[4];
 }
 //-----------------------------------------------------------------------------
-void mglCanvas::InPlot(mreal x1,mreal x2,mreal y1,mreal y2, bool rel)
+void mglCanvas::InPlot(mglMatrix &M,mreal x1,mreal x2,mreal y1,mreal y2, bool rel)
 {
 	if(Width<=0 || Height<=0 || Depth<=0)	return;
-	B.clear();
-	if(get(MGL_AUTO_FACTOR)) B.pf = 1.55;	// Automatically change plot factor !!!
+	M.clear();
+	if(get(MGL_AUTO_FACTOR)) M.pf = 1.55;	// Automatically change plot factor !!!
 	if(rel)
 	{
-		B.x = B1.x + (x1+x2-1)/2*B1.b[0]/1.55;
-		B.y = B1.y + (y1+y2-1)/2*B1.b[4]/1.55;
-		B.b[0] = B1.b[0]*(x2-x1);	B.b[4] = B1.b[4]*(y2-y1);
-		B.b[8] = sqrt(B.b[0]*B.b[4]);
-		B.z = B1.z + (1.f-B.b[8]/(2*Depth))*B1.b[8];
+		M.x = B1.x + (x1+x2-1)/2*B1.b[0]/1.55;
+		M.y = B1.y + (y1+y2-1)/2*B1.b[4]/1.55;
+		M.b[0] = B1.b[0]*(x2-x1);	M.b[4] = B1.b[4]*(y2-y1);
+		M.b[8] = sqrt(M.b[0]*M.b[4]);
+		M.z = B1.z + (1.f-M.b[8]/(2*Depth))*B1.b[8];
 	}
 	else
 	{
-		B.x = (x1+x2)/2*Width;
-		B.y = (y1+y2)/2*Height;
-		B.b[0] = Width*(x2-x1);	B.b[4] = Height*(y2-y1);
-		B.b[8] = sqrt(B.b[0]*B.b[4]);
-		B.z = (1.f-B.b[8]/(2*Depth))*Depth;
+		M.x = (x1+x2)/2*Width;
+		M.y = (y1+y2)/2*Height;
+		M.b[0] = Width*(x2-x1);	M.b[4] = Height*(y2-y1);
+		M.b[8] = sqrt(M.b[0]*M.b[4]);
+		M.z = (1.f-M.b[8]/(2*Depth))*Depth;
 		B1=B;
 	}
-	inW=B.b[0];	inH=B.b[4];	ZMin=1;
+	inW=M.b[0];	inH=M.b[4];	ZMin=1;
 	inX=Width*x1;	inY=Height*y1;
-	font_factor = B.b[0] < B.b[4] ? B.b[0] : B.b[4];
+	font_factor = M.b[0] < M.b[4] ? M.b[0] : M.b[4];
 	mglPrim p;	p.id = ObjId;
 	p.n1=x1*Width;	p.n2=x2*Width;	p.n3=y1*Height;	p.n4=y2*Height;
+#pragma omp critical(sub)
 	MGL_PUSH(Sub,p,mutexSub);
 }
 //-----------------------------------------------------------------------------
@@ -570,7 +570,7 @@ void mglCanvas::StickPlot(int num, int id, mreal tet, mreal phi)
 	mglPoint p1(-1,0,0), p2(1,0,0);
 	// first iteration
 	InPlot(0,1,0,1,true);	Rotate(tet, phi);
-	PostScale(p1);	PostScale(p2);	f1 = B.pf;
+	PostScale(GetB(),p1);	PostScale(GetB(),p2);	f1 = B.pf;
 	dx=(p2.x-p1.x)*1.55/B1.b[0];	dy=(p2.y-p1.y)*1.55/B1.b[4];
 	wx=1/(1+(num-1)*fabs(dx));		wy=1/(1+(num-1)*fabs(dy));
 	x1=dx>0?dx*id:dx*(id-num+1);	y1=dy>0?dy*id:dy*(id-num+1);
@@ -587,6 +587,17 @@ void mglCanvas::StickPlot(int num, int id, mreal tet, mreal phi)
 //-----------------------------------------------------------------------------
 void mglCanvas::Rotate(mreal tetz,mreal tetx,mreal tety)
 {
+	B.Rotate(tetz,tetx,tety);
+	if(get(MGL_AUTO_FACTOR))
+	{
+		mreal w=(fabs(B.b[3])+fabs(B.b[4])+fabs(B.b[5]))/B1.b[4];
+		mreal h=(fabs(B.b[0])+fabs(B.b[1])+fabs(B.b[2]))/B1.b[0];
+		B.pf = 1.55+0.6147*(w<h ? (h-1):(w-1));
+	}
+}
+//-----------------------------------------------------------------------------
+void mglMatrix::Rotate(mreal tetz,mreal tetx,mreal tety)
+{
 //	RotateN(TetX,1.,0.,0.);
 //	RotateN(TetY,0.,1.,0.);
 //	RotateN(TetZ,0.,0.,1.);
@@ -595,16 +606,21 @@ void mglCanvas::Rotate(mreal tetz,mreal tetx,mreal tety)
 	R[0] = cx*cy;			R[1] = -cy*sx;			R[2] = sy;
 	R[3] = cx*sy*sz+cz*sx;	R[4] = cx*cz-sx*sy*sz;	R[5] =-cy*sz;
 	R[6] = sx*sz-cx*cz*sy;	R[7] = cx*sz+cz*sx*sy;	R[8] = cy*cz;
-	memcpy(O,B.b,9*sizeof(mreal));
-	B.b[0] = R[0]*O[0] + R[3]*O[1] + R[6]*O[2];
-	B.b[1] = R[1]*O[0] + R[4]*O[1] + R[7]*O[2];
-	B.b[2] = R[2]*O[0] + R[5]*O[1] + R[8]*O[2];
-	B.b[3] = R[0]*O[3] + R[3]*O[4] + R[6]*O[5];
-	B.b[4] = R[1]*O[3] + R[4]*O[4] + R[7]*O[5];
-	B.b[5] = R[2]*O[3] + R[5]*O[4] + R[8]*O[5];
-	B.b[6] = R[0]*O[6] + R[3]*O[7] + R[6]*O[8];
-	B.b[7] = R[1]*O[6] + R[4]*O[7] + R[7]*O[8];
-	B.b[8] = R[2]*O[6] + R[5]*O[7] + R[8]*O[8];
+	memcpy(O,b,9*sizeof(mreal));
+	b[0] = R[0]*O[0] + R[3]*O[1] + R[6]*O[2];
+	b[1] = R[1]*O[0] + R[4]*O[1] + R[7]*O[2];
+	b[2] = R[2]*O[0] + R[5]*O[1] + R[8]*O[2];
+	b[3] = R[0]*O[3] + R[3]*O[4] + R[6]*O[5];
+	b[4] = R[1]*O[3] + R[4]*O[4] + R[7]*O[5];
+	b[5] = R[2]*O[3] + R[5]*O[4] + R[8]*O[5];
+	b[6] = R[0]*O[6] + R[3]*O[7] + R[6]*O[8];
+	b[7] = R[1]*O[6] + R[4]*O[7] + R[7]*O[8];
+	b[8] = R[2]*O[6] + R[5]*O[7] + R[8]*O[8];
+}
+//-----------------------------------------------------------------------------
+void mglCanvas::RotateN(mreal Tet,mreal x,mreal y,mreal z)
+{
+	B.RotateN(Tet,x,y,z);
 	if(get(MGL_AUTO_FACTOR))
 	{
 		mreal w=(fabs(B.b[3])+fabs(B.b[4])+fabs(B.b[5]))/B1.b[4];
@@ -613,51 +629,27 @@ void mglCanvas::Rotate(mreal tetz,mreal tetx,mreal tety)
 	}
 }
 //-----------------------------------------------------------------------------
-void mglCanvas::RotateN(mreal Tet,mreal x,mreal y,mreal z)
+void mglMatrix::RotateN(mreal Tet,mreal x,mreal y,mreal z)
 {
 	mreal R[9],T[9],c=cos(Tet*M_PI/180),s=-sin(Tet*M_PI/180),r=1-c,n=sqrt(x*x+y*y+z*z);
 	x/=n;	y/=n;	z/=n;
 	T[0] = x*x*r+c;		T[1] = x*y*r-z*s;	T[2] = x*z*r+y*s;
 	T[3] = x*y*r+z*s;	T[4] = y*y*r+c;		T[5] = y*z*r-x*s;
 	T[6] = x*z*r-y*s;	T[7] = y*z*r+x*s;	T[8] = z*z*r+c;
-	memcpy(R,B.b,9*sizeof(mreal));
-	B.b[0] = T[0]*R[0] + T[3]*R[1] + T[6]*R[2];
-	B.b[1] = T[1]*R[0] + T[4]*R[1] + T[7]*R[2];
-	B.b[2] = T[2]*R[0] + T[5]*R[1] + T[8]*R[2];
-	B.b[3] = T[0]*R[3] + T[3]*R[4] + T[6]*R[5];
-	B.b[4] = T[1]*R[3] + T[4]*R[4] + T[7]*R[5];
-	B.b[5] = T[2]*R[3] + T[5]*R[4] + T[8]*R[5];
-	B.b[6] = T[0]*R[6] + T[3]*R[7] + T[6]*R[8];
-	B.b[7] = T[1]*R[6] + T[4]*R[7] + T[7]*R[8];
-	B.b[8] = T[2]*R[6] + T[5]*R[7] + T[8]*R[8];
-	if(get(MGL_AUTO_FACTOR))
-	{
-		mreal w=(fabs(B.b[3])+fabs(B.b[4])+fabs(B.b[5]))/B1.b[4];
-		mreal h=(fabs(B.b[0])+fabs(B.b[1])+fabs(B.b[2]))/B1.b[0];
-		B.pf = 1.55+0.6147*(w<h ? (h-1):(w-1));
-	}
+	memcpy(R,b,9*sizeof(mreal));
+	b[0] = T[0]*R[0] + T[3]*R[1] + T[6]*R[2];
+	b[1] = T[1]*R[0] + T[4]*R[1] + T[7]*R[2];
+	b[2] = T[2]*R[0] + T[5]*R[1] + T[8]*R[2];
+	b[3] = T[0]*R[3] + T[3]*R[4] + T[6]*R[5];
+	b[4] = T[1]*R[3] + T[4]*R[4] + T[7]*R[5];
+	b[5] = T[2]*R[3] + T[5]*R[4] + T[8]*R[5];
+	b[6] = T[0]*R[6] + T[3]*R[7] + T[6]*R[8];
+	b[7] = T[1]*R[6] + T[4]*R[7] + T[7]*R[8];
+	b[8] = T[2]*R[6] + T[5]*R[7] + T[8]*R[8];
 }
 //-----------------------------------------------------------------------------
 void mglCanvas::View(mreal tetx,mreal tetz,mreal tety)
-{
-	mreal R[9], A[9];
-	mreal cx=cos(tetx*M_PI/180), sx=sin(tetx*M_PI/180);
-	mreal cy=cos(tety*M_PI/180), sy=sin(tety*M_PI/180);
-	mreal cz=cos(tetz*M_PI/180), sz=sin(tetz*M_PI/180);
-	R[0] = cx*cy;			R[1] = -cy*sx;			R[2] = sy;
-	R[3] = cx*sy*sz+cz*sx;	R[4] = cx*cz-sx*sy*sz;	R[5] =-cy*sz;
-	R[6] = sx*sz-cx*cz*sy;	R[7] = cx*sz+cz*sx*sy;	R[8] = cy*cz;
-	memcpy(A,Bp.b,9*sizeof(mreal));		ClfZB();
-	Bp.b[0] = R[0]*A[0] + R[3]*A[1] + R[6]*A[2];
-	Bp.b[1] = R[1]*A[0] + R[4]*A[1] + R[7]*A[2];
-	Bp.b[2] = R[2]*A[0] + R[5]*A[1] + R[8]*A[2];
-	Bp.b[3] = R[0]*A[3] + R[3]*A[4] + R[6]*A[5];
-	Bp.b[4] = R[1]*A[3] + R[4]*A[4] + R[7]*A[5];
-	Bp.b[5] = R[2]*A[3] + R[5]*A[4] + R[8]*A[5];
-	Bp.b[6] = R[0]*A[6] + R[3]*A[7] + R[6]*A[8];
-	Bp.b[7] = R[1]*A[6] + R[4]*A[7] + R[7]*A[8];
-	Bp.b[8] = R[2]*A[6] + R[5]*A[7] + R[8]*A[8];
-}
+{	Bp.Rotate(-tetz,-tetx,-tety);	}
 //-----------------------------------------------------------------------------
 void mglCanvas::Zoom(mreal x1, mreal y1, mreal x2, mreal y2)
 {
@@ -689,7 +681,7 @@ void mglCanvas::Aspect(mreal Ax,mreal Ay,mreal Az)
 		if(islog(Min.x,Max.x) && fx)	dx = log10(Max.x/Min.x);
 		if(islog(Min.y,Max.y) && fy)	dy = log10(Max.y/Min.y);
 		mreal f=exp(M_LN10*floor(0.5+log10(fabs(dy/dx))));
-		if(!mgl_isnan(Ay))	f=Ay;
+		if(mgl_isnum(Ay))	f=Ay;
 		Ax = Height*dx*f;	Ay = Width*dy;	Az = Depth;
 	}
 	mreal a = fabs(Ax) > fabs(Ay) ? fabs(Ax) : fabs(Ay);
@@ -723,15 +715,19 @@ void mglCanvas::arrow_plot(long n1, long n2, char st)
 {
 	if(n1<0 || n2<0 || !strchr("AVKSDTIO",st))	return;
 	float ll = PenWidth*ArrowSize*0.35*font_factor;
+	uint64_t m=mask;	int ma=MaskAn;
+	ResetMask();
 	if((Quality&3)==3)
 		arrow_plot_3d(n1, n2, st, ll);
 	else
 		arrow_draw(n1, n2, st, ll);
+	mask=m;	MaskAn=ma;
 }
 //-----------------------------------------------------------------------------
 void mglCanvas::Legend(const std::vector<mglText> &leg, mreal x, mreal y, const char *font, const char *opt)
 {
-	long n=leg.size(), iw, ih;
+	long n=leg.size();
+	mreal iw, ih;
 	if(n<1)	{	SetWarn(mglWarnLeg,"Legend");	return;	}
 	mreal ll = SaveState(opt);	if(mgl_isnan(ll))	ll=0.1;
 	if(saved)	MarkSize=MSS;	// restore back size of marks
@@ -765,11 +761,20 @@ void mglCanvas::Legend(const std::vector<mglText> &leg, mreal x, mreal y, const
 		nrow = 1+(n-1)/j;
 		ncol = (n+nrow-1)/nrow;
 	}
-	x = x*(iw-w*ncol-2*dx)+B.x-iw/2+dx;
-	y = y*(ih-h*nrow-2*dy)+B.y-ih/2+dy;
+	if(mglchr(font,'^'))	// use "external" positioning
+	{
+		x = x>=0.5 ? x*iw : x*iw-w*ncol-2*dx;
+		y = y>=0.5 ? y*ih : y*ih-h*nrow-2*dy;
+	}
+	else
+	{
+		x *= iw-w*ncol-2*dx;
+		y *= ih-h*nrow-2*dy;
+	}
+	x += B.x-iw/2+dx;	y += B.y-ih/2+dy;
 	// draw it
 	long k1=0,k2=0,k3=0,k4=0;
-	mglPoint p,q=mglPoint(NAN,NAN);
+	mglPoint p,q=mglPoint(NAN);
 
 	for(i=0;ff[i] && ff[i]!=':';i++)	if(strchr(MGL_COLORS,ff[i]))
 	{
@@ -786,10 +791,10 @@ void mglCanvas::Legend(const std::vector<mglText> &leg, mreal x, mreal y, const
 	if(strchr(ff,'#'))	// draw bounding box
 	{
 		SetPenPal("k-");
-		k1=AddPnt(mglPoint(x,y,Depth/MGL_FEPSILON),c1,q,-1,0);
-		k2=AddPnt(mglPoint(x+w*ncol,y,Depth/MGL_FEPSILON),c1,q,-1,0);
-		k3=AddPnt(mglPoint(x,y+h*nrow,Depth/MGL_FEPSILON),c1,q,-1,0);
-		k4=AddPnt(mglPoint(x+w*ncol,y+h*nrow,Depth/MGL_FEPSILON),c1,q,-1,0);
+		k1=AddPnt(&B,mglPoint(x,y,Depth/MGL_FEPSILON),c1,q,-1,0);
+		k2=AddPnt(&B,mglPoint(x+w*ncol,y,Depth/MGL_FEPSILON),c1,q,-1,0);
+		k3=AddPnt(&B,mglPoint(x,y+h*nrow,Depth/MGL_FEPSILON),c1,q,-1,0);
+		k4=AddPnt(&B,mglPoint(x+w*ncol,y+h*nrow,Depth/MGL_FEPSILON),c1,q,-1,0);
 		quad_plot(k1,k2,k3,k4);
 		k1=CopyNtoC(k1,c2);	k2=CopyNtoC(k2,c2);
 		k3=CopyNtoC(k3,c2);	k4=CopyNtoC(k4,c2);
@@ -800,16 +805,16 @@ void mglCanvas::Legend(const std::vector<mglText> &leg, mreal x, mreal y, const
 	{
 		register long iy=nrow-(i%nrow)-1,ix=i/nrow;
 		char m=SetPenPal(leg[i].stl.c_str());
-		k1=AddPnt(mglPoint(x+ix*w+0.1*ll,y+iy*h+0.45*h,Depth),CDef,q,-1,0);
-		k2=AddPnt(mglPoint(x+ix*w+0.9*ll,y+iy*h+0.45*h,Depth),CDef,q,-1,0);	pPos=0;
+		k1=AddPnt(&B,mglPoint(x+ix*w+0.1*ll,y+iy*h+0.45*h,Depth),CDef,q,-1,0);
+		k2=AddPnt(&B,mglPoint(x+ix*w+0.9*ll,y+iy*h+0.45*h,Depth),CDef,q,-1,0);	pPos=0;
 		if(!leg[i].stl.empty())	line_plot(k1,k2);
 		if(m)	for(j=0;j<LegendMarks;j++)
 		{
 			p = mglPoint(x+ix*w+0.1f*ll + (j+1)*0.8f*ll/(1.+LegendMarks),y+iy*h+0.45*h,Depth);
-			mark_plot(AddPnt(p,CDef,q,-1,0),m);
+			mark_plot(AddPnt(&B,p,CDef,q,-1,0),m);
 		}
 		p = mglPoint(x+ix*w+((!leg[i].stl.empty())?ll:0.01*iw), y+iy*h+0.15*h, Depth);
-		text_plot(AddPnt(p,-1,q,-1,0), leg[i].text.c_str(), ff, size);
+		text_plot(AddPnt(&B,p,-1,q,-1,0), leg[i].text.c_str(), ff, size);
 	}
 	Pop();	EndGroup();	delete []ff;
 }
@@ -865,24 +870,24 @@ void mglCanvas::Table(mreal x, mreal y, HCDT val, const wchar_t *text, const cha
 	if(grid)	// draw bounding box
 	{
 		SetPenPal("k-");
-		k1=AddPnt(mglPoint(x,y,Depth),-1,q,-1,0);
-		k2=AddPnt(mglPoint(x,y+m*h,Depth),-1,q,-1,0);
+		k1=AddPnt(&B,mglPoint(x,y,Depth),-1,q,-1,0);
+		k2=AddPnt(&B,mglPoint(x,y+m*h,Depth),-1,q,-1,0);
 		line_plot(k1,k2);
 		ww = *text ? TextWidth(text,frm,-1)+sp:0;
-		k1=AddPnt(mglPoint(x+ww,y,Depth),-1,q,-1,0);
-		k2=AddPnt(mglPoint(x+ww,y+m*h,Depth),-1,q,-1,0);
+		k1=AddPnt(&B,mglPoint(x+ww,y,Depth),-1,q,-1,0);
+		k2=AddPnt(&B,mglPoint(x+ww,y+m*h,Depth),-1,q,-1,0);
 		line_plot(k1,k2);
 		for(i=0,xx=x+ww,yy=y;i<n;i++)
 		{
 			xx += eqd ? w1:(TextWidth(str[i].c_str(),frm,-1)+sp);
-			k1=AddPnt(mglPoint(xx,yy,Depth),-1,q,-1,0);
-			k2=AddPnt(mglPoint(xx,yy+m*h,Depth),-1,q,-1,0);
+			k1=AddPnt(&B,mglPoint(xx,yy,Depth),-1,q,-1,0);
+			k2=AddPnt(&B,mglPoint(xx,yy+m*h,Depth),-1,q,-1,0);
 			line_plot(k1,k2);
 		}
 		for(i=0,xx=x,yy=y;i<=m;i++)
 		{
-			k1=AddPnt(mglPoint(xx,yy,Depth),-1,q,-1,0);
-			k2=AddPnt(mglPoint(xx+w,yy,Depth),-1,q,-1,0);
+			k1=AddPnt(&B,mglPoint(xx,yy,Depth),-1,q,-1,0);
+			k2=AddPnt(&B,mglPoint(xx+w,yy,Depth),-1,q,-1,0);
 			line_plot(k1,k2);	yy += h;
 		}
 	}
@@ -890,14 +895,14 @@ void mglCanvas::Table(mreal x, mreal y, HCDT val, const wchar_t *text, const cha
 	if(*text)
 	{
 		ww = TextWidth(text,frm,-1)+sp;
-		k1=AddPnt(mglPoint(x+ww*align/2.,y+h*(m-0.99),Depth),-1,q,-1,0);
+		k1=AddPnt(&B,mglPoint(x+ww*align/2.,y+h*(m-0.99),Depth),-1,q,-1,0);
 		text_plot(k1,text,frm);
 	}
 	else 	ww = 0;
 	for(i=0,xx=x+ww,yy=y+h*(m-0.99);i<n;i++)	// draw lines and legend
 	{
 		ww = eqd ? w1:(TextWidth(str[i].c_str(),frm,-1)+sp);
-		k1=AddPnt(mglPoint(xx+ww*align/2.,yy,Depth),-1,q,-1,0);
+		k1=AddPnt(&B,mglPoint(xx+ww*align/2.,yy,Depth),-1,q,-1,0);
 		text_plot(k1,str[i].c_str(),frm);	xx += ww;
 	}
 	FontSize = fsize;	EndGroup();
@@ -906,11 +911,7 @@ void mglCanvas::Table(mreal x, mreal y, HCDT val, const wchar_t *text, const cha
 void mglCanvas::Title(const char *title,const char *stl,mreal size)
 {
 	if(!title)	title="";
-	size_t s = mbstowcs(0,title,0)+1;
-	wchar_t *wcs = new wchar_t[s];
-	mbstowcs(wcs,title,s);
-	Title(wcs, stl,size);
-	delete []wcs;
+	MGL_TO_WCS(title,Title(wcs, stl,size));
 }
 //-----------------------------------------------------------------------------
 void mglCanvas::Title(const wchar_t *title,const char *stl,mreal size)
@@ -928,10 +929,10 @@ void mglCanvas::Title(const wchar_t *title,const char *stl,mreal size)
 		mreal c1=AddTexture('w'), c2=AddTexture('k');
 		if((Flag&3)==2)	{	mreal cc=c1;	c2=c1;	c1=cc;	}
 		long k1,k2,k3,k4;
-		k1=AddPnt(mglPoint(inX,y,Depth),c1,q,-1,0);
-		k2=AddPnt(mglPoint(inX+inW,y,Depth),c1,q,-1,0);
-		k3=AddPnt(mglPoint(inX,y+h,Depth),c1,q,-1,0);
-		k4=AddPnt(mglPoint(inX+inW,y+h,Depth),c1,q,-1,0);
+		k1=AddPnt(&B,mglPoint(inX,y,Depth),c1,q,-1,0);
+		k2=AddPnt(&B,mglPoint(inX+inW,y,Depth),c1,q,-1,0);
+		k3=AddPnt(&B,mglPoint(inX,y+h,Depth),c1,q,-1,0);
+		k4=AddPnt(&B,mglPoint(inX+inW,y+h,Depth),c1,q,-1,0);
 		quad_plot(k1,k2,k3,k4);
 		k1=CopyNtoC(k1,c2);	k2=CopyNtoC(k2,c2);
 		k3=CopyNtoC(k3,c2);	k4=CopyNtoC(k4,c2);
@@ -952,15 +953,17 @@ void mglCanvas::StartAutoGroup (const char *lbl)
 	if(ObjId<0)	{	ObjId = -id;	id++;	}
 	register size_t len = Grp.size();
 	if(ObjId>=0 && len>0 && ObjId!=Grp[len-1].Id)
-	{	MGL_PUSH(Grp,mglGroup(lbl,ObjId),mutexGrp);	}
+#pragma omp critical(grp)
+	{	MGL_PUSH(Grp,mglGroup(lbl,ObjId),mutexGrp);}
 	else if(ObjId<0)
-	{	MGL_PUSH(Grp,mglGroup(lbl,ObjId),mutexGrp);	}
+#pragma omp critical(grp)
+	{	MGL_PUSH(Grp,mglGroup(lbl,ObjId),mutexGrp);}
 }
 //-----------------------------------------------------------------------------
 void mglCanvas::EndGroup()
 {
 	LoadState();
-	if(Quality&4)
+	if(Quality&MGL_DRAW_LMEM)
 	{
 		Pnt.clear();		Prm.clear();		Ptx.clear();
 		Glf.clear();		Act.clear(); 	Grp.clear();
@@ -980,3 +983,9 @@ int mglCanvas::IsActive(int xs, int ys,int &n)
 	n=-1;	return GetObjId(xs,ys);
 }
 //-----------------------------------------------------------------------------
+void mglCanvas::Push()
+{
+#pragma omp critical(stk)
+	{MGL_PUSH(stack,B,mutexStk);}
+}
+//-----------------------------------------------------------------------------
diff --git a/src/canvas_cf.cpp b/src/canvas_cf.cpp
index 4d673cb..0c4bbe4 100644
--- a/src/canvas_cf.cpp
+++ b/src/canvas_cf.cpp
@@ -99,6 +99,8 @@ void MGL_EXPORT mgl_mat_pop(HMGL gr)
 {	mglCanvas *g = dynamic_cast<mglCanvas *>(gr);	if(g)	g->Pop();	}
 void MGL_EXPORT mgl_clf(HMGL gr)
 {	mglCanvas *g = dynamic_cast<mglCanvas *>(gr);	if(g)	g->Clf();	}
+void MGL_EXPORT mgl_clf_chr(HMGL gr, char ch)
+{	mglCanvas *g = dynamic_cast<mglCanvas *>(gr);	if(g)	g->Clf(mglColor(ch));	}
 void MGL_EXPORT mgl_clf_rgb(HMGL gr, double r, double g, double b)
 {	mglCanvas *gg = dynamic_cast<mglCanvas *>(gr);	if(gg)	gg->Clf(mglColor(r,g,b));	}
 //-----------------------------------------------------------------------------
@@ -194,6 +196,8 @@ void MGL_EXPORT mgl_mat_push_(uintptr_t *gr)	{	_GR_->Push();	}
 void MGL_EXPORT mgl_mat_pop_(uintptr_t *gr)	{	_GR_->Pop();	}
 void MGL_EXPORT mgl_clf_(uintptr_t *gr)
 {	_GR_->Clf();	}
+void MGL_EXPORT mgl_clf_chr_(uintptr_t *gr, const char *ch, int)
+{	_GR_->Clf(mglColor(*ch));	}
 void MGL_EXPORT mgl_clf_rgb_(uintptr_t *gr, mreal *r, mreal *g, mreal *b)
 {	_GR_->Clf(mglColor(*r,*g,*b));	}
 //-----------------------------------------------------------------------------
diff --git a/src/complex.cpp b/src/complex.cpp
index e7e6ec8..d39d897 100644
--- a/src/complex.cpp
+++ b/src/complex.cpp
@@ -19,6 +19,10 @@
  ***************************************************************************/
 #include "mgl2/datac.h"
 #include "mgl2/evalc.h"
+#include "mgl2/thread.h"
+
+#include "interp.hpp"
+
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mglStartThreadC(void *(*func)(void *), void (*post)(mglThreadC *,dual *), long n,
 					dual *a, const dual *b, const dual *c, const long *p,
@@ -84,76 +88,121 @@ void MGL_EXPORT mglStartThreadV(void *(*func)(void *), long n, dual *a, const vo
 MGL_NO_EXPORT void *mgl_csmth_x(void *par)
 {
 	mglThreadC *t=(mglThreadC *)par;
-	register long i,j,d3,d5, nx=t->p[0];
-	dual *b=t->a, y5,y3,x2y;
+	long nx=t->p[0], kind=t->p[2];
+	dual *b=t->a;
 	const dual *a=t->b;
-	for(i=t->id;i<t->n;i+=mglNumThr)
-	{
-		j = i%nx;
-		d3 = d5 = 0;
-		if(j==0)	{	d3 = 1;		d5 = 2;	}
-		if(j==1)	{	d5 = 1;	}
-		if(j==nx-1)	{	d3 = -1;	d5 = -2;}
-		if(j==nx-2)	{	d5 = -1;}
-		y3 = (a[i+d3-1] + a[i+d3] + a[i+d3+1]);
-		y5 = (a[i+d5-2] + a[i+d5-1] + a[i+d5] + a[i+d5+1] + a[i+d5+2]);
-		x2y= (a[i+d5+1] + mgl4*a[i+d5+2] + mgl4*a[i+d5-2] + a[i+d5-1]);
-		j = t->p[2];
-		if(d3)	b[i] = a[i];
-		else if(j==SMOOTH_LINE_3 || d5)	b[i] = y3/mgl3;
-		else if(j==SMOOTH_LINE_5)		b[i] = y5/mreal(5);
-		else if(j==SMOOTH_QUAD_5)		b[i] = (mreal(17)*y5-mreal(5)*x2y)/mreal(35);
-	}
+	if(kind==SMOOTH_LINE_3)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+		for(long i=t->id;i<t->n;i+=mglNumThr)
+		{
+			register long j = i%nx;
+			if(j>0 && j<nx-1)	b[i] = (a[i-1] + a[i] + a[i+1])/mreal(3);
+			else	b[i] = a[i];
+		}
+	else if(kind==SMOOTH_LINE_5)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+		for(long i=t->id;i<t->n;i+=mglNumThr)
+		{
+			register long j = i%nx;
+			if(j>1 && j<nx-2)	b[i] = (a[i-2] + a[i-1] + a[i] + a[i+1] + a[i+2])/mreal(5);
+			else if(j==1 || j==nx-2)	b[i] = (a[i-1] + a[i] + a[i+1])/mreal(3);
+			else	b[i] = a[i];
+		}
+	else if(kind==SMOOTH_QUAD_5)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+		for(long i=t->id;i<t->n;i+=mglNumThr)
+		{
+			register long j = i%nx;
+			if(j>1 && j<nx-2)	b[i] = (mreal(12)*a[i-2] - mreal(3)*a[i-1] + mreal(17)*a[i] - mreal(3)*a[i+1] + mreal(12)*a[i+2])/mreal(35);
+			else if(j==1 || j==nx-2)	b[i] = (a[i-1] + a[i] + a[i+1])/mreal(3);
+			else	b[i] = a[i];
+		}
 	return 0;
 }
 MGL_NO_EXPORT void *mgl_csmth_y(void *par)
 {
 	mglThreadC *t=(mglThreadC *)par;
-	register long i,j,d3,d5, nx=t->p[0],ny=t->p[1];
-	dual *b=t->a, y5,y3,x2y;
+	long nx=t->p[0],ny=t->p[1], kind=t->p[2];
+	dual *b=t->a;
 	const dual *a=t->b;
-	for(i=t->id;i<t->n;i+=mglNumThr)
-	{
-		j = (i/nx)%ny;
-		d3 = d5 = 0;
-		if(j==0)	{	d3 = 1;		d5 = 2;	}
-		if(j==1)	{	d5 = 1;	}
-		if(j==ny-1)	{	d3 = -1;	d5 = -2;}
-		if(j==ny-2)	{	d5 = -1;}
-		y3 = (a[i+nx*(d3-1)] + a[i+nx*d3] + a[i+nx*(d3+1)]);
-		y5 = (a[i+nx*(d5-2)] + a[i+nx*(d5-1)] + a[i+nx*d5] + a[i+nx*(d5+1)] + a[i+nx*(d5+2)]);
-		x2y= (a[i+nx*(d5+1)] + mgl4*a[i+nx*(d5+2)] + mgl4*a[i+nx*(d5-2)] + a[i+nx*(d5-1)]);
-		j = t->p[2];
-		if(d3)	b[i] = a[i];
-		else if(j==SMOOTH_LINE_3 || d5)	b[i] = y3/mgl3;
-		else if(j==SMOOTH_LINE_5)		b[i] = y5/mreal(5);
-		else if(j==SMOOTH_QUAD_5)		b[i] = (mreal(17)*y5-mreal(5)*x2y)/mreal(35);
-	}
+	if(kind==SMOOTH_LINE_3)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+		for(long i=t->id;i<t->n;i+=mglNumThr)
+		{
+			register long j = (i/nx)%ny;
+			if(j>0 && j<ny-1)	b[i] = (a[i-nx] + a[i] + a[i+nx])/mreal(3);
+			else	b[i] = a[i];
+		}
+	else if(kind==SMOOTH_LINE_5)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+		for(long i=t->id;i<t->n;i+=mglNumThr)
+		{
+			register long j = (i/nx)%ny;
+			if(j>1 && j<ny-2)	b[i] = (a[i-2*nx] + a[i-nx] + a[i] + a[i+nx] + a[i+2*nx])/mreal(5);
+			else if(j==1 || j==ny-2)	b[i] = (a[i-nx] + a[i] + a[i+nx])/mreal(3);
+			else	b[i] = a[i];
+		}
+	else if(kind==SMOOTH_QUAD_5)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+		for(long i=t->id;i<t->n;i+=mglNumThr)
+		{
+			register long j = (i/nx)%ny;
+			if(j>1 && j<ny-2)	b[i] = (mreal(12)*a[i-2*nx] - mreal(3)*a[i-nx] + mreal(17)*a[i] - mreal(3)*a[i+nx] + mreal(12)*a[i+2*nx])/mreal(35);
+			else if(j==1 || j==ny-2)	b[i] = (a[i-nx] + a[i] + a[i+nx])/mreal(3);
+			else	b[i] = a[i];
+		}
 	return 0;
 }
 MGL_NO_EXPORT void *mgl_csmth_z(void *par)
 {
 	mglThreadC *t=(mglThreadC *)par;
-	register long i,j,d3,d5, nn=t->p[0]*t->p[1], nz=t->n/nn;
-	dual *b=t->a, y5,y3,x2y;
+	register long nn=t->p[0]*t->p[1], nz=t->n/nn, kind=t->p[2];
+	dual *b=t->a;
 	const dual *a=t->b;
-	for(i=t->id;i<t->n;i+=mglNumThr)
-	{
-		j = i/nn;
-		d3 = d5 = 0;
-		if(j==0)	{	d3 = 1;		d5 = 2;	}
-		if(j==1)	{	d5 = 1;	}
-		if(j==nz-1)	{	d3 = -1;	d5 = -2;}
-		if(j==nz-2)	{	d5 = -1;}
-		y3 = (a[i+nn*(d3-1)] + a[i+nn*d3] + a[i+nn*(d3+1)]);
-		y5 = (a[i+nn*(d5-2)] + a[i+nn*(d5-1)] + a[i+nn*d5] + a[i+nn*(d5+1)] + a[i+nn*(d5+2)]);
-		x2y= (a[i+nn*(d5+1)] + mgl4*a[i+nn*(d5+2)] + mgl4*a[i+nn*(d5-2)] + a[i+nn*(d5-1)]);
-		j = t->p[2];
-		if(d3)	b[i] = a[i];
-		else if(j==SMOOTH_LINE_3 || d5)	b[i] = y3/mgl3;
-		else if(j==SMOOTH_LINE_5)		b[i] = y5/mreal(5);
-		else if(j==SMOOTH_QUAD_5)		b[i] = (mreal(17)*y5-mreal(5)*x2y)/mreal(35);
-	}
+	if(kind==SMOOTH_LINE_3)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+		for(long i=t->id;i<t->n;i+=mglNumThr)
+		{
+			register long j = i/nn;
+			if(j>0 && j<nz-1)	b[i] = (a[i-nn] + a[i] + a[i+nn])/mreal(3);
+			else	b[i] = a[i];
+		}
+	else if(kind==SMOOTH_LINE_5)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+		for(long i=t->id;i<t->n;i+=mglNumThr)
+		{
+			register long j = i/nn;
+			if(j>1 && j<nz-2)	b[i] = (a[i-2*nn] + a[i-nn] + a[i] + a[i+nn] + a[i+2*nn])/mreal(5);
+			else if(j==1 || j==nz-2)	b[i] = (a[i-nn] + a[i] + a[i+nn])/mreal(3);
+			else	b[i] = a[i];
+		}
+	else if(kind==SMOOTH_QUAD_5)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+		for(long i=t->id;i<t->n;i+=mglNumThr)
+		{
+			register long j = i/nn;
+			if(j>1 && j<nz-2)	b[i] = (mreal(12)*a[i-2*nn] - mreal(3)*a[i-nn] + mreal(17)*a[i] - mreal(3)*a[i+nn] + mreal(12)*a[i+2*nn])/mreal(35);
+			else if(j==1 || j==nz-2)	b[i] = (a[i-nn] + a[i] + a[i+nn])/mreal(3);
+			else	b[i] = a[i];
+		}
 	return 0;
 }
 void MGL_EXPORT mgl_datac_smooth(HADT d, const char *dirs, mreal )
@@ -195,39 +244,48 @@ void MGL_EXPORT mgl_datac_smooth_(uintptr_t *d, const char *dir, mreal *delta,in
 MGL_NO_EXPORT void *mgl_ccsum_z(void *par)
 {
 	mglThreadC *t=(mglThreadC *)par;
-	register long i,j, nz=t->p[2], nn=t->n;
+	long nz=t->p[2], nn=t->n;
 	dual *b=t->a;
 	const dual *a=t->b;
-	for(i=t->id;i<nn;i+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i=t->id;i<nn;i+=mglNumThr)
 	{
 		b[i] = a[i];
-		for(j=1;j<nz;j++)	b[i+j*nn] = b[i+j*nn-nn] + a[i+j*nn];
+		for(long j=1;j<nz;j++)	b[i+j*nn] = b[i+j*nn-nn] + a[i+j*nn];
 	}
 	return 0;
 }
 MGL_NO_EXPORT void *mgl_ccsum_y(void *par)
 {
 	mglThreadC *t=(mglThreadC *)par;
-	register long i,j,k, nx=t->p[0], ny=t->p[1], nn=t->n;
+	long nx=t->p[0], ny=t->p[1], nn=t->n;
 	dual *b=t->a;
 	const dual *a=t->b;
-	for(i=t->id;i<nn;i+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i=t->id;i<nn;i+=mglNumThr)
 	{
-		k = (i%nx)+nx*ny*(i/nx);		b[k] = a[k];
-		for(j=1;j<ny;j++)	b[k+j*nx] = b[k+j*nx-nx] + a[k+nx*j];
+		register long k = (i%nx)+nx*ny*(i/nx);		b[k] = a[k];
+		for(long j=1;j<ny;j++)	b[k+j*nx] = b[k+j*nx-nx] + a[k+nx*j];
 	}
 	return 0;
 }
 MGL_NO_EXPORT void *mgl_ccsum_x(void *par)
 {
 	mglThreadC *t=(mglThreadC *)par;
-	register long i,j,k, nx=t->p[0], nn=t->n;
+	long nx=t->p[0], nn=t->n;
 	dual *b=t->a;
 	const dual *a=t->b;
-	for(i=t->id;i<nn;i+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i=t->id;i<nn;i+=mglNumThr)
 	{
-		k = i*nx;			b[k] = a[k];
-		for(j=1;j<nx;j++)	b[j+k] = b[j+k-1] + a[j+k];
+		register long k = i*nx;			b[k] = a[k];
+		for(long j=1;j<nx;j++)	b[j+k] = b[j+k-1] + a[j+k];
 	}
 	return 0;
 }
@@ -262,39 +320,48 @@ void MGL_EXPORT mgl_datac_cumsum_(uintptr_t *d, const char *dir,int l)
 MGL_NO_EXPORT void *mgl_cint_z(void *par)
 {
 	mglThreadC *t=(mglThreadC *)par;
-	register long i,j, nz=t->p[2], nn=t->n;
+	long nz=t->p[2], nn=t->n;
 	dual *b=t->a, dd=0.5/nz;
 	const dual *a=t->b;
-	for(i=t->id;i<nn;i+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i=t->id;i<nn;i+=mglNumThr)
 	{
 		b[i] = 0;
-		for(j=1;j<nz;j++)	b[i+j*nn] = b[i+j*nn-nn] + (a[i+nn*j]+a[i+j*nn-nn])*dd;
+		for(long j=1;j<nz;j++)	b[i+j*nn] = b[i+j*nn-nn] + (a[i+nn*j]+a[i+j*nn-nn])*dd;
 	}
 	return 0;
 }
 MGL_NO_EXPORT void *mgl_cint_y(void *par)
 {
 	mglThreadC *t=(mglThreadC *)par;
-	register long i,j,k, nx=t->p[0], ny=t->p[1], nn=t->n;
+	long nx=t->p[0], ny=t->p[1], nn=t->n;
 	dual *b=t->a, dd=0.5/ny;
 	const dual *a=t->b;
-	for(i=t->id;i<nn;i+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i=t->id;i<nn;i+=mglNumThr)
 	{
-		k = (i%nx)+nx*ny*(i/nx);	b[k] = 0;
-		for(j=1;j<ny;j++)	b[k+j*nx] = b[k+j*nx-nx] + (a[k+j*nx]+a[k+j*nx-nx])*dd;
+		register long k = (i%nx)+nx*ny*(i/nx);	b[k] = 0;
+		for(long j=1;j<ny;j++)	b[k+j*nx] = b[k+j*nx-nx] + (a[k+j*nx]+a[k+j*nx-nx])*dd;
 	}
 	return 0;
 }
 MGL_NO_EXPORT void *mgl_cint_x(void *par)
 {
 	mglThreadC *t=(mglThreadC *)par;
-	register long i,j,k, nx=t->p[0], nn=t->n;
+	long nx=t->p[0], nn=t->n;
 	dual *b=t->a, dd=0.5/nx;
 	const dual *a=t->b;
-	for(i=t->id;i<nn;i+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i=t->id;i<nn;i+=mglNumThr)
 	{
-		k = i*nx;			b[k] = 0;
-		for(j=1;j<nx;j++)	b[j+k] = b[j+k-1] + (a[j+k]+a[j+k-1])*dd;
+		register long k = i*nx;			b[k] = 0;
+		for(long j=1;j<nx;j++)	b[j+k] = b[j+k-1] + (a[j+k]+a[j+k-1])*dd;
 	}
 	return 0;
 }
@@ -329,44 +396,53 @@ void MGL_EXPORT mgl_datac_integral_(uintptr_t *d, const char *dir,int l)
 MGL_NO_EXPORT void *mgl_cdif_z(void *par)
 {
 	mglThreadC *t=(mglThreadC *)par;
-	register long i,j, nz=t->p[2], nn=t->n;
+	long nz=t->p[2], nn=t->n;
 	dual *b=t->a, dd=0.5*nz;
 	const dual *a=t->b;
-	for(i=t->id;i<nn;i+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i=t->id;i<nn;i+=mglNumThr)
 	{
 		b[i] = -(mgl3*a[i]-mgl4*a[i+nn]+a[i+2*nn])*dd;
 		b[i+(nz-1)*nn] = (mgl3*a[i+(nz-1)*nn]-mgl4*a[i+(nz-2)*nn]+a[i+(nz-3)*nn])*dd;
-		for(j=1;j<nz-1;j++)		b[i+j*nn] = (a[i+j*nn+nn]-a[i+j*nn-nn])*dd;
+		for(long j=1;j<nz-1;j++)		b[i+j*nn] = (a[i+j*nn+nn]-a[i+j*nn-nn])*dd;
 	}
 	return 0;
 }
 MGL_NO_EXPORT void *mgl_cdif_y(void *par)
 {
 	mglThreadC *t=(mglThreadC *)par;
-	register long i,j,k, nx=t->p[0], ny=t->p[1], nn=t->n;
+	long nx=t->p[0], ny=t->p[1], nn=t->n;
 	dual *b=t->a, dd=0.5*ny;
 	const dual *a=t->b;
-	for(i=t->id;i<nn;i+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i=t->id;i<nn;i+=mglNumThr)
 	{
-		k = (i%nx)+nx*ny*(i/nx);
+		register long k = (i%nx)+nx*ny*(i/nx);
 		b[k] = -(mgl3*a[k]-mgl4*a[k+nx]+a[k+2*nx])*dd;
 		b[k+(ny-1)*nx] = (mgl3*a[k+(ny-1)*nx]-mgl4*a[k+(ny-2)*nx]+a[k+(ny-3)*nx])*dd;
-		for(j=1;j<ny-1;j++)	b[k+j*nx] = (a[k+j*nx+nx]-a[k+j*nx-nx])*dd;
+		for(long j=1;j<ny-1;j++)	b[k+j*nx] = (a[k+j*nx+nx]-a[k+j*nx-nx])*dd;
 	}
 	return 0;
 }
 MGL_NO_EXPORT void *mgl_cdif_x(void *par)
 {
 	mglThreadC *t=(mglThreadC *)par;
-	register long i,j,k, nx=t->p[0], nn=t->n;
+	long nx=t->p[0], nn=t->n;
 	dual *b=t->a, dd=0.5*nx;
 	const dual *a=t->b;
-	for(i=t->id;i<nn;i+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i=t->id;i<nn;i+=mglNumThr)
 	{
-		k = i*nx;
+		register long k = i*nx;
 		b[k] = -(mgl3*a[k]-mgl4*a[k+1]+a[k+2])*dd;
 		b[k+nx-1] = (mgl3*a[k+nx-1]-mgl4*a[k+nx-2]+a[k+nx-3])*dd;
-		for(j=1;j<nx-1;j++)	b[j+k] = (a[j+k+1]-a[j+k-1])*dd;
+		for(long j=1;j<nx-1;j++)	b[j+k] = (a[j+k+1]-a[j+k-1])*dd;
 	}
 	return 0;
 }
@@ -400,39 +476,48 @@ void MGL_EXPORT mgl_datac_diff_(uintptr_t *d, const char *dir,int l)
 MGL_NO_EXPORT void *mgl_cdif2_z(void *par)
 {
 	mglThreadC *t=(mglThreadC *)par;
-	register long i,j, nz=t->p[2], nn=t->n;
+	long nz=t->p[2], nn=t->n;
 	dual *b=t->a, dd=0.5*nz*nz;
 	const dual *a=t->b;
-	for(i=t->id;i<nn;i+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i=t->id;i<nn;i+=mglNumThr)
 	{
 		b[i] = b[i+(nz-1)*nn] = 0;
-		for(j=1;j<nz-1;j++)		b[i+j*nn] = (a[i+j*nn+nn]+a[i+j*nn-nn]-mgl2*a[i+j*nn])*dd;
+		for(long j=1;j<nz-1;j++)		b[i+j*nn] = (a[i+j*nn+nn]+a[i+j*nn-nn]-mgl2*a[i+j*nn])*dd;
 	}
 	return 0;
 }
 MGL_NO_EXPORT void *mgl_cdif2_y(void *par)
 {
 	mglThreadC *t=(mglThreadC *)par;
-	register long i,j,k, nx=t->p[0], ny=t->p[1], nn=t->n;
+	long nx=t->p[0], ny=t->p[1], nn=t->n;
 	dual *b=t->a, dd=0.5*ny*ny;
 	const dual *a=t->b;
-	for(i=t->id;i<nn;i+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i=t->id;i<nn;i+=mglNumThr)
 	{
-		k = (i%nx)+nx*ny*(i/nx);	b[k] = b[k+(ny-1)*nx] = 0;
-		for(j=1;j<ny-1;j++)	b[k+j*nx] = (a[k+j*nx+nx]+a[k+j*nx-nx]-mgl2*a[k+j*nx])*dd;
+		register long k = (i%nx)+nx*ny*(i/nx);	b[k] = b[k+(ny-1)*nx] = 0;
+		for(long j=1;j<ny-1;j++)	b[k+j*nx] = (a[k+j*nx+nx]+a[k+j*nx-nx]-mgl2*a[k+j*nx])*dd;
 	}
 	return 0;
 }
 MGL_NO_EXPORT void *mgl_cdif2_x(void *par)
 {
 	mglThreadC *t=(mglThreadC *)par;
-	register long i,j,k, nx=t->p[0], nn=t->n;
+	long nx=t->p[0], nn=t->n;
 	dual *b=t->a, dd=0.5*nx*nx;
 	const dual *a=t->b;
-	for(i=t->id;i<nn;i+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i=t->id;i<nn;i+=mglNumThr)
 	{
-		k = i*nx;			b[k] = b[k+nx-1] = 0;
-		for(j=1;j<nx-1;j++)	b[j+k] = (a[j+k+1]+a[j+k-1]-mgl2*a[j+k])*dd;
+		register long k = i*nx;			b[k] = b[k+nx-1] = 0;
+		for(long j=1;j<nx-1;j++)	b[j+k] = (a[j+k+1]+a[j+k-1]-mgl2*a[j+k])*dd;
 	}
 	return 0;
 }
@@ -476,8 +561,7 @@ void MGL_EXPORT mgl_datac_swap_(uintptr_t *d, const char *dir,int l)
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_datac_roll(HADT dd, char dir, long num)
 {
-	long nx=dd->nx,ny=dd->ny,nz=dd->nz;
-	register long i,d;
+	long nx=dd->nx,ny=dd->ny,nz=dd->nz, d;
 	dual *b,*a=dd->a;
 	if(dir=='z' && nz>1)
 	{
@@ -494,7 +578,8 @@ void MGL_EXPORT mgl_datac_roll(HADT dd, char dir, long num)
 		if(d==0)	return;		// nothing to do
 		b = new dual[nx*ny*nz];
 		memcpy(b,a+nx*d,(nx*ny*nz-nx*d)*sizeof(dual));
-		for(i=0;i<nz;i++)
+#pragma omp parallel for
+		for(long i=0;i<nz;i++)
 			memcpy(b+nx*(ny-d)+nx*ny*i,a+nx*ny*i,nx*d*sizeof(dual));
 		memcpy(a,b,nx*ny*nz*sizeof(dual));	delete []b;
 	}
@@ -504,7 +589,8 @@ void MGL_EXPORT mgl_datac_roll(HADT dd, char dir, long num)
 		if(d==0)	return;		// nothing to do
 		b = new dual[nx*ny*nz];
 		memcpy(b,a+d,(nx*ny*nz-d)*sizeof(dual));
-		for(i=0;i<nz*ny;i++)
+#pragma omp parallel for
+		for(long i=0;i<nz*ny;i++)
 			memcpy(b+nx-d+nx*i,a+nx*i,d*sizeof(dual));
 		memcpy(a,b,nx*ny*nz*sizeof(dual));	delete []b;
 	}
@@ -516,35 +602,32 @@ void MGL_EXPORT mgl_datac_mirror(HADT d, const char *dir)
 {
 	if(!dir || *dir==0)	return;
 	long nx=d->nx,ny=d->ny,nz=d->nz;
-	register long i,j,k,i0,j0;
-	dual b, *a=d->a;
+	dual *a=d->a;
 	if(strchr(dir,'z') && nz>1)
 	{
-		for(j=0;j<nz/2;j++)	for(i=0;i<nx*ny;i++)
+#pragma omp parallel for collapse(2)
+		for(long i=0;i<nx*ny;i++)	for(long j=0;j<nz/2;j++)
 		{
-			i0 = i+j*nx*ny;	j0 = i+(nz-1-j)*nx*ny;
-			b = a[i0];	a[i0] = a[j0];	a[j0] = b;
+			register long i0 = i+j*nx*ny, j0 = i+(nz-1-j)*nx*ny;
+			register dual b = a[i0];	a[i0] = a[j0];	a[j0] = b;
 		}
 	}
 	if(strchr(dir,'y') && ny>1)
 	{
-		for(k=0;k<nz;k++)	for(i=0;i<nx;i++)
+#pragma omp parallel for collapse(2)
+		for(long i=0;i<nx*nz;i++)	for(long j=0;j<ny/2;j++)
 		{
-			j0 = i+nx*ny*k;
-			for(j=0;j<ny/2;j++)
-			{
-				i0 = j0+(ny-1-j)*nx;	b = a[j0+j*nx];
-				a[j0+j*nx] = a[i0];	a[i0] = b;
-			}
+			register long j0 = (i%nx)+nx*(ny*(i/nx)+j), i0 = j0+(ny-1-2*j)*nx;
+			register dual b = a[j0];	a[j0] = a[i0];	a[i0] = b;
 		}
 	}
 	if(strchr(dir,'x') && nx>1)
 	{
-		for(j=0;j<ny*nz;j++)
+#pragma omp parallel for collapse(2)
+		for(long j=0;j<ny*nz;j++)	for(long i=0;i<nx/2;i++)
 		{
-			j0 = j*nx;
-			for(i=0;i<nx/2;i++)
-			{	i0 = nx-1-i+j0;	b = a[i+j0];	a[i+j0] = a[i0];	a[i0] = b;	}
+			register long i0 = nx-1-i+j*nx, j0 = i+j*nx;
+			register dual b = a[j0];	a[j0] = a[i0];	a[i0] = b;
 		}
 	}
 }
@@ -552,46 +635,80 @@ void MGL_EXPORT mgl_datac_mirror_(uintptr_t *d, const char *dir,int l)
 {	char *s=new char[l+1];	memcpy(s,dir,l);	s[l]=0;
 	mgl_datac_mirror(_DC_,s);	delete []s;	}
 //-----------------------------------------------------------------------------
+dual mglSpline3C(const dual *a, long nx, long ny, long nz, mreal x, mreal y, mreal z,dual *dx, dual *dy, dual *dz)
+{	return mglSpline3t<dual>(a,nx,ny,nz,x,y,z,dx,dy,dz);	}
+//-----------------------------------------------------------------------------
+dual mglLinearC(const dual *a, long nx, long ny, long nz, mreal x, mreal y, mreal z)
+{	return mglLineart<dual>(a,nx,ny,nz,x,y,z);	}
+//-----------------------------------------------------------------------------
+dual MGL_EXPORT mgl_datac_spline(HCDT d, mreal x,mreal y,mreal z)
+{
+	const mglDataC *dd=dynamic_cast<const mglDataC *>(d);
+	if(!dd)	return mgl_data_spline(d,x,y,z);
+	return dd->ny*dd->nz==1?mglSpline1st<dual>(dd->a,dd->nx,x):mglSpline3st<dual>(dd->a,dd->nx,dd->ny,dd->nz,x,y,z);
+}
+//-----------------------------------------------------------------------------
+dual MGL_EXPORT mgl_datac_spline_ext(HCDT d, mreal x,mreal y,mreal z, dual *dx,dual *dy,dual *dz)
+{
+	const mglDataC *dd=dynamic_cast<const mglDataC *>(d);
+	if(!dd)
+	{
+		mreal rx,ry,rz,res;
+		res=mgl_data_spline_ext(d,x,y,z,&rx,&ry,&rz);
+		if(dx)	*dx=rx;	if(dy)	*dy=ry;	if(dz)	*dz=rz;
+		return res;
+	}
+	return mglSpline3t<dual>(dd->a,dd->nx,dd->ny,dd->nz,x,y,z,dx,dy,dz);
+}
+//-----------------------------------------------------------------------------
+dual MGL_EXPORT mgl_datac_spline_(uintptr_t *d, mreal *x,mreal *y,mreal *z)
+{	return mgl_datac_spline(_DA_(d),*x,*y,*z);	}
+dual MGL_EXPORT mgl_datac_spline_ext_(uintptr_t *d, mreal *x,mreal *y,mreal *z, dual *dx,dual *dy,dual *dz)
+{	return mgl_datac_spline_ext(_DA_(d),*x,*y,*z,dx,dy,dz);	}
+//-----------------------------------------------------------------------------
 dual MGL_EXPORT mgl_datac_linear_ext(HCDT d, mreal x,mreal y,mreal z, dual *dx,dual *dy,dual *dz)
 {
 	long kx=long(x), ky=long(y), kz=long(z);
 	dual b0,b1;
-	bool dif = (dx && dy && dz);
 	const mglDataC *dd=dynamic_cast<const mglDataC *>(d);
-	if(dd)
-	{
-		long nx=dd->nx, ny=dd->ny, nz=dd->nz, dn=ny>1?nx:0;
-		kx = kx<nx-1 ? kx:nx-2;	kx = kx>=0 ? kx:0;
-		ky = ky<ny-1 ? ky:ny-2;	ky = ky>=0 ? ky:0;
-		kz = kz<nz-1 ? kz:nz-2;	kz = kz>=0 ? kz:0;
-		x -= kx;	if(nx==1)	x=0;
-		y -= ky;	if(ny==1)	y=0;
-		z -= kz;	if(nz==1)	z=0;
+	if(!dd)
+	{
+		mreal rx,ry,rz,res;
+		res=mgl_data_linear_ext(d,x,y,z,&rx,&ry,&rz);
+		if(dx)	*dx=rx;	if(dy)	*dy=ry;	if(dz)	*dz=rz;
+		return res;
+	}
 
-		const dual *aa=dd->a+kx+nx*(ky+ny*kz), *bb = aa+(nz>1?nx*ny:0);
+	long nx=dd->nx, ny=dd->ny, nz=dd->nz, dn=ny>1?nx:0;
+	kx = kx>=0 ? kx:0;	kx = kx<nx-1 ? kx:nx-2;
+	ky = ky>=0 ? ky:0;	ky = ky<ny-1 ? ky:ny-2;
+	kz = kz>=0 ? kz:0;	kz = kz<nz-1 ? kz:nz-2;
+	x -= kx;	y -= ky;	z -= kz;
+	const dual *aa = dd->a, *bb;
+	if(kz>=0)
+	{
+		aa=dd->a+kx+nx*(ky+ny*kz);	bb = aa+nx*ny;
 		b0 = aa[0]*(1-x-y+x*y) + x*(1-y)*aa[1] + y*(1-x)*aa[dn] + x*y*aa[1+dn];
 		b1 = bb[0]*(1-x-y+x*y) + x*(1-y)*bb[1] + y*(1-x)*bb[dn] + x*y*bb[1+dn];
-		if(dif)
-		{	*dx = aa[1]-aa[0];	*dy = aa[dn]-aa[0];	*dz = bb[0]-aa[0];	}
 	}
 	else
 	{
-		long n=d->GetNx(), ny=d->GetNy(), nz=d->GetNz();
-		kx = (kx>=0 ? (kx<n ? kx:n -1):0);
-		ky = (ky>=0 ? (ky<ny? ky:ny-1):0);
-		kz = (kz>=0 ? (kz<nz? kz:nz-1):0);
-		x -= kx;	y -= ky;	z -= kz;
-
-		dual a0 = d->v(kx,ky,kz), a1 = d->v(kx+1,ky,kz), a2 = d->v(kx,ky+1,kz);
-		if(dif)	{	*dx = a1-a0;	*dy = a2-a0;	*dz = -a0;	}
-		b0 = a0*(1-x-y+x*y) + x*(1-y)*a1 +
-			y*(1-x)*a2 + x*y*d->v(kx+1,ky+1,kz);
-		kz++;
-		a0 = d->v(kx,ky,kz);
-		if(dif)	*dz += a0;
-		b1 = a0*(1-x-y+x*y) + x*(1-y)*d->v(kx+1,ky,kz) +
-			y*(1-x)*d->v(kx,ky+1,kz) + x*y*d->v(kx+1,ky+1,kz);
+		z=0;
+		if(ky>=0)
+		{
+			aa=dd->a+kx+nx*ky;
+			b0 = b1 = aa[0]*(1-x-y+x*y) + x*(1-y)*aa[1] + y*(1-x)*aa[dn] + x*y*aa[1+dn];
+		}
+		else if(kx>=0)
+		{
+			aa=dd->a+kx;	b0 = b1 = aa[0]*(1-x) + x*aa[1];
+		}
+		else	b0 = b1 = dd->a[0];
 	}
+	if(dx)	*dx = kx>=0?aa[1]-aa[0]:0;
+	if(dy)	*dy = ky>=0?aa[dn]-aa[0]:0;
+	if(dz)	*dz = b1-b0;
+
 	return b0 + z*(b1-b0);
 }
 dual MGL_EXPORT mgl_datac_linear(HCDT d, mreal x,mreal y,mreal z)
@@ -605,7 +722,6 @@ dual MGL_EXPORT mgl_datac_linear_ext_(uintptr_t *d, mreal *x,mreal *y,mreal *z,
 void MGL_EXPORT mgl_datac_crop(HADT d, long n1, long n2, char dir)
 {
 	long nx=d->nx,ny=d->ny,nz=d->nz, nn;
-	register long i,k;
 	dual *b;
 	if(n1<0)	n1=0;
 	switch(dir)
@@ -614,7 +730,8 @@ void MGL_EXPORT mgl_datac_crop(HADT d, long n1, long n2, char dir)
 		n2 = n2>0 ? n2 : nx+n2;
 		if(n2<0 || n2>=nx || n2<n1)	n2 = nx;
 		nn = n2-n1;	b = new dual[nn*ny*nz];
-		for(i=0;i<ny*nz;i++)
+#pragma omp parallel for
+		for(long i=0;i<ny*nz;i++)
 			memcpy(b+nn*i,d->a+nx*i+n1,nn*sizeof(dual));
 		d->nx = nn;	if(!d->link)	delete []d->a;
 		d->a = b;	d->link=false;	d->NewId();
@@ -623,8 +740,9 @@ void MGL_EXPORT mgl_datac_crop(HADT d, long n1, long n2, char dir)
 		n2 = n2>0 ? n2 : ny+n2;
 		if(n2<0 || n2>=ny || n2<n1)	n2 = ny;
 		nn = n2-n1;	b = new dual[nn*nx*nz];
-		for(long j=0;j<nz;j++)	for(k=0;k<nn;k++)
-			memcpy(b+nx*(k+nn*j),d->a+nx*(n1+k+ny*j),nx*sizeof(dual));
+#pragma omp parallel for
+		for(long i=0;i<nn;i++)	for(long j=0;j<nz;j++)
+			memcpy(b+nx*(i+nn*j),d->a+nx*(n1+i+ny*j),nx*sizeof(dual));
 		d->ny = nn;	if(!d->link)	delete []d->a;
 		d->a = b;	d->link=false;
 		break;
@@ -645,18 +763,18 @@ void MGL_EXPORT mgl_datac_insert(HADT d, char dir, long at, long num)
 {
 	if(num<1)	return;
 	at = at<0 ? 0:at;
-	register long i,k,nn;
-	long nx=d->nx, ny=d->ny, nz=d->nz;
+	long nx=d->nx, ny=d->ny, nz=d->nz, nn;
 	mglDataC b;
 	if(dir=='x')
 	{
 		if(at>nx)	at=nx;
 		nn=nx+num;	b.Create(nn,ny,nz);
-		for(k=0;k<ny*nz;k++)
+#pragma omp parallel for
+		for(long k=0;k<ny*nz;k++)
 		{
 			if(at>0)	memcpy(b.a+nn*k, d->a+nx*k,at*sizeof(dual));
 			if(at<nx)	memcpy(b.a+at+num+nn*k, d->a+at+nx*k,(nx-at)*sizeof(dual));
-			for(i=0;i<num;i++)	b.a[nn*k+at+i]=d->a[nx*k+at];	// copy values
+			for(long i=0;i<num;i++)	b.a[nn*k+at+i]=d->a[nx*k+at];	// copy values
 		}
 		d->Set(b);	nx+=num;
 	}
@@ -664,11 +782,12 @@ void MGL_EXPORT mgl_datac_insert(HADT d, char dir, long at, long num)
 	{
 		if(at>ny)	at=ny;
 		nn=num+ny;	b.Create(nx,nn,nz);
-		for(k=0;k<nz;k++)
+#pragma omp parallel for
+		for(long k=0;k<nz;k++)
 		{
 			if(at>0)	memcpy(b.a+nx*nn*k, d->a+nx*ny*k,at*nx*sizeof(dual));
 			if(at<ny)	memcpy(b.a+nx*(at+num+nn*k), d->a+nx*(at+ny*k),(ny-at)*nx*sizeof(dual));
-			for(i=0;i<num;i++)	memcpy(b.a+nx*(nn*k+at+i),d->a+nx*(ny*k+at),nx*sizeof(dual));
+			for(long i=0;i<num;i++)	memcpy(b.a+nx*(nn*k+at+i),d->a+nx*(ny*k+at),nx*sizeof(dual));
 		}
 		d->Set(b);	ny+=num;
 	}
@@ -678,7 +797,8 @@ void MGL_EXPORT mgl_datac_insert(HADT d, char dir, long at, long num)
 		b.Create(nx,ny,nz+num);
 		if(at>0)	memcpy(b.a, d->a,at*nx*ny*sizeof(dual));
 		if(at<nz)	memcpy(b.a+nx*ny*(at+num), d->a+nx*ny*at,(nz-at)*nx*ny*sizeof(dual));
-		for(i=0;i<num;i++)	memcpy(b.a+nx*ny*(at+i),d->a+nx*ny*at,nx*ny*sizeof(dual));
+#pragma omp parallel for
+		for(long i=0;i<num;i++)	memcpy(b.a+nx*ny*(at+i),d->a+nx*ny*at,nx*ny*sizeof(dual));
 		d->Set(b);	nz+=num;
 	}
 }
@@ -687,13 +807,13 @@ void MGL_EXPORT mgl_datac_delete(HADT d, char dir, long at, long num)
 {
 	if(num<1 || at<0)	return;
 	mglDataC b;
-	long nx=d->nx, ny=d->ny, nz=d->nz;
-	register long k,nn;
+	long nx=d->nx, ny=d->ny, nz=d->nz, nn;
 	if(dir=='x')
 	{
 		if(at+num>=nx)	return;
 		nn=nx-num;	b.Create(nn,ny,nz);
-		for(k=0;k<ny*nz;k++)
+#pragma omp parallel for
+		for(long k=0;k<ny*nz;k++)
 		{
 			if(at>0)	memcpy(b.a+nn*k, d->a+nx*k,at*sizeof(dual));
 			memcpy(b.a+at+nn*k, d->a+at+num+nx*k,(nx-at-num)*sizeof(dual));
@@ -704,7 +824,8 @@ void MGL_EXPORT mgl_datac_delete(HADT d, char dir, long at, long num)
 	{
 		if(at+num>=ny)	return;
 		nn=ny-num;	b.Create(nx,nn,nz);
-		for(k=0;k<nz;k++)
+#pragma omp parallel for
+		for(long k=0;k<nz;k++)
 		{
 			if(at>0)	memcpy(b.a+nx*nn*k, d->a+nx*ny*k,at*nx*sizeof(dual));
 			memcpy(b.a+nx*(at+nn*k), d->a+nx*(at+num+ny*k),(ny-at-num)*nx*sizeof(dual));
@@ -739,7 +860,7 @@ dual MGL_EXPORT mgl_datac_get_value(HCDT dat, long i, long j, long k)
 	if(i<0 || i>=dat->GetNx() || j<0 || j>=dat->GetNy() || k<0 || k>=dat->GetNz())
 		return NAN;
 	const mglDataC *d = dynamic_cast<const mglDataC*>(dat);
-	return d ? d->a[i+d->nx*(j+d->nz*k)] : dual(dat->v(i,j,k),0);	
+	return d ? d->a[i+d->nx*(j+d->nz*k)] : dual(dat->v(i,j,k),0);
 }
 dual MGL_EXPORT mgl_datac_get_value_(uintptr_t *d, int *i, int *j, int *k)
 {	return mgl_datac_get_value(_DA_(d),*i,*j,*k);	}
@@ -754,15 +875,16 @@ void MGL_EXPORT mgl_datac_join(HADT d, HCDT v)
 {
 	register long nx=d->nx, ny=d->ny, nz=d->nz;
 	const mglDataC *mv = dynamic_cast<const mglDataC *>(v);
-	long vx=v->GetNx(), vy=v->GetNy(), vz=v->GetNz();
-	register long i,k=nx*ny*nz;
+	long vx=v->GetNx(), vy=v->GetNy(), vz=v->GetNz(), k=nx*ny*nz;
 
 	if(nx==vx && ny==vy && (nz>1 || vz>1))
 	{
 		dual *b = new dual[nx*ny*(nz+vz)];
 		memcpy(b,d->a,nx*ny*nz*sizeof(dual));
 		if(mv)	memcpy(b+nx*ny*nz,mv->a,nx*ny*vz*sizeof(dual));
-		else 	for(i=0;i<nx*ny*vz;i++)	b[k+i] = v->vthr(i);
+		else
+#pragma omp parallel for
+			for(long i=0;i<nx*ny*vz;i++)	b[k+i] = v->vthr(i);
 		if(!d->link)	delete []d->a;	d->nz += vz;
 		d->a = b;	d->link=false;	d->NewId();
 	}
@@ -772,7 +894,9 @@ void MGL_EXPORT mgl_datac_join(HADT d, HCDT v)
 		dual *b = new dual[nx*(ny+vy)];
 		memcpy(b,d->a,nx*ny*sizeof(dual));
 		if(mv)	memcpy(b+nx*ny,mv->a,nx*vy*sizeof(dual));
-		else 	for(i=0;i<nx*vy;i++)	b[k+i] = v->vthr(i);
+		else
+#pragma omp parallel for
+			for(long i=0;i<nx*vy;i++)	b[k+i] = v->vthr(i);
 		if(!d->link)	delete []d->a;
 		d->nz = 1;	d->ny = ny+vy;
 		d->a = b;	d->link=false;	d->NewId();
@@ -783,7 +907,9 @@ void MGL_EXPORT mgl_datac_join(HADT d, HCDT v)
 		dual *b = new dual[nx+vx];
 		memcpy(b,d->a,nx*sizeof(dual));
 		if(mv)	memcpy(b+nx,mv->a,vx*sizeof(dual));
-		else 	for(i=0;i<vx;i++)	b[k+i] = v->vthr(i);
+		else
+#pragma omp parallel for
+			for(long i=0;i<vx;i++)	b[k+i] = v->vthr(i);
 		if(!d->link)	delete []d->a;
 		d->nz = d->ny = 1;	d->nx = nx+vx;
 		d->a = b;	d->link=false;	d->NewId();
@@ -793,3 +919,148 @@ void MGL_EXPORT mgl_datac_join(HADT d, HCDT v)
 void MGL_EXPORT mgl_datac_join_(uintptr_t *d, uintptr_t *val)
 {	mgl_datac_join(_DC_,_DA_(val));	}
 //-----------------------------------------------------------------------------
+void MGL_EXPORT mgl_datac_put_val(HADT d, dual val, long xx, long yy, long zz)
+{
+	long nx=d->nx, ny=d->ny, nz=d->nz;
+	if(xx>=nx || yy>=ny || zz>=nz)	return;
+	dual *a=d->a;
+	if(xx<0 && yy<0 && zz<0)
+#pragma omp parallel for
+		for(long i=0;i<nx*ny*nz;i++)	a[i] = val;
+	else if(xx<0 && yy<0)
+#pragma omp parallel for
+		for(long i=0;i<nx*ny;i++)	a[i+zz*nx*ny] = val;
+	else if(yy<0 && zz<0)
+#pragma omp parallel for
+		for(long i=0;i<nz*ny;i++)	a[xx+i*nx] = val;
+	else if(xx<0 && zz<0)
+#pragma omp parallel for collapse(2)
+		for(long i=0;i<nx;i++)	for(long j=0;j<nz;j++)	a[i+nx*(yy+j*ny)] = val;
+	else if(xx<0)
+#pragma omp parallel for
+		for(long i=0;i<nx;i++)	a[i+nx*(yy+zz*ny)] = val;
+	else if(yy<0)
+#pragma omp parallel for
+		for(long i=0;i<ny;i++)	a[xx+nx*(i+zz*ny)] = val;
+	else if(zz<0)
+#pragma omp parallel for
+		for(long i=0;i<nz;i++)	a[xx+nx*(yy+i*ny)] = val;
+	else	a[xx+nx*(yy+zz*ny)] = val;
+}
+//-----------------------------------------------------------------------------
+void MGL_EXPORT mgl_datac_put_dat(HADT d, HCDT v, long xx, long yy, long zz)
+{
+	long nx=d->nx, ny=d->ny, nz=d->nz;
+	if(xx>=nx || yy>=ny || zz>=nz)	return;
+	const mglDataC *mv = dynamic_cast<const mglDataC *>(v);
+	dual *a=d->a, vv=v->v(0);
+	const dual *b = mv?mv->a:0;
+	long vx=v->GetNx(), vy=v->GetNy(), vz=v->GetNz();
+	if(xx<0 && yy<0 && zz<0)	// whole array
+	{
+		if(vx>=nx && vy>=ny && vz>=nz)
+#pragma omp parallel for
+			for(long ii=0;ii<nx*ny*nz;ii++)
+			{	register long i=ii%nx, j=(ii/nx)%ny, k=ii/(nx*ny);
+				a[ii] = b?b[i+vx*(j+k*vy)]:v->v(i,j,k);	}
+		else if(vx>=nx && vy>=ny)
+#pragma omp parallel for
+			for(long ii=0;ii<nx*ny*nz;ii++)
+			{	register long i=ii%nx, j=(ii/nx)%ny;
+				a[ii] = b?b[i+vx*j]:v->v(i,j);	}
+		else if(vx>=nx)
+#pragma omp parallel for
+			for(long ii=0;ii<nx*ny*nz;ii++)
+			{	register long i=ii%nx;	a[ii] = b?b[i]:v->v(i);	}
+		else
+#pragma omp parallel for
+			for(long ii=0;ii<nx*ny*nz;ii++)	a[ii] = vv;
+	}
+	else if(xx<0 && yy<0)	// 2d
+	{
+		zz*=nx*ny;
+		if(vx>=nx && vy>=ny)
+#pragma omp parallel for
+			for(long ii=0;ii<nx*ny;ii++)
+			{	register long i=ii%nx, j=ii/nx;
+				a[ii+zz] = b?b[i+vx*j]:v->v(i,j);	}
+		else if(vx>=nx)
+#pragma omp parallel for
+			for(long ii=0;ii<nx*ny;ii++)
+			{	register long i=ii%nx;	a[ii+zz] = b?b[i]:v->v(i);	}
+		else
+#pragma omp parallel for
+			for(long ii=0;ii<nx*ny;ii++) 	a[ii+zz] = vv;
+	}
+	else if(yy<0 && zz<0)	// 2d
+	{
+		if(vx>=ny && vy>=nz)
+#pragma omp parallel for
+			for(long ii=0;ii<ny*nz;ii++)
+			{	register long i=ii%ny, j=ii/ny;
+				a[ii*nx+xx] = b?b[i+vx*j]:v->v(i,j);	}
+		else if(vx>=ny)
+#pragma omp parallel for
+			for(long ii=0;ii<ny*nz;ii++)
+			{	register long i=ii%ny;	a[ii*nx+xx] = b?b[i]:v->v(i);	}
+		else
+#pragma omp parallel for
+			for(long ii=0;ii<ny*nz;ii++) 	a[ii*nx+xx] = vv;
+	}
+	else if(xx<0 && zz<0)	// 2d
+	{
+		yy *= nx;	zz = nx*ny;
+		if(vx>=nx && vy>=nz)
+#pragma omp parallel for
+			for(long ii=0;ii<nx*nz;ii++)
+			{	register long i=ii%nx, j=ii/nx;
+				a[i+yy+j*zz] = b?b[i+vx*j]:v->v(i,j);	}
+		else if(vx>=nx)
+#pragma omp parallel for
+			for(long ii=0;ii<nx*nz;ii++)
+			{	register long i=ii%nx, j=ii/nx;
+				a[i+yy+j*zz] = b?b[i]:v->v(i);	}
+		else
+#pragma omp parallel for
+			for(long ii=0;ii<nx*nz;ii++)
+			{	register long i=ii%nx, j=ii/nx;
+				a[i+yy+j*zz] = vv;	}
+	}
+	else if(xx<0)
+	{
+		xx = nx*(yy+zz*ny);
+		if(vx>=nx)
+#pragma omp parallel for
+			for(long i=0;i<nx;i++)	a[i+xx] = b?b[i]:v->v(i);
+		else
+#pragma omp parallel for
+			for(long i=0;i<nx;i++)	a[i+xx] = vv;
+	}
+	else if(yy<0)
+	{
+		xx += zz*nx*ny;
+		if(vx>=ny)
+#pragma omp parallel for
+			for(long i=0;i<ny;i++)	a[xx+nx*i] = b?b[i]:v->v(i);
+		else
+#pragma omp parallel for
+			for(long i=0;i<ny;i++)	a[xx+nx*i] = vv;
+	}
+	else if(zz<0)
+	{
+		xx += nx*yy;	yy = nx*ny;
+		if(vx>=nz)
+#pragma omp parallel for
+			for(long i=0;i<nz;i++)	a[xx+yy*i] = b?b[i]:v->v(i);
+		else
+#pragma omp parallel for
+			for(long i=0;i<nz;i++)	a[xx+yy*i] = vv;
+	}
+	else	a[xx+nx*(yy+ny*zz)] = vv;
+}
+//-----------------------------------------------------------------------------
+void MGL_EXPORT mgl_datac_put_val_(uintptr_t *d, dual *val, int *i, int *j, int *k)
+{	mgl_datac_put_val(_DC_,*val, *i,*j,*k);	}
+void MGL_EXPORT mgl_datac_put_dat_(uintptr_t *d, uintptr_t *val, int *i, int *j, int *k)
+{	mgl_datac_put_dat(_DC_,_DA_(val), *i,*j,*k);	}
+//-----------------------------------------------------------------------------
diff --git a/src/complex_io.cpp b/src/complex_io.cpp
index a9461d9..e0669c8 100644
--- a/src/complex_io.cpp
+++ b/src/complex_io.cpp
@@ -25,6 +25,7 @@
 
 #include "mgl2/datac.h"
 #include "mgl2/evalc.h"
+#include "mgl2/thread.h"
 
 #if MGL_HAVE_HDF5
 #define H5_USE_16_API
@@ -140,33 +141,23 @@ void MGL_EXPORT mgl_datac_set_float(HADT d, const float *A,long NX,long NY,long
 {
 	if(NX<=0 || NY<=0 || NZ<=0)	return;
 	mgl_datac_create(d, NX,NY,NZ);	if(!A)	return;
-#if MGL_USE_DOUBLE
+#pragma omp parallel for
 	for(long i=0;i<NX*NY*NZ;i++)	d->a[i] = A[i];
-#else
-	memcpy(d->a,A,NX*NY*NZ*sizeof(float));
-#endif
 }
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_datac_set_double(HADT d, const double *A,long NX,long NY,long NZ)
 {
 	if(NX<=0 || NY<=0 || NZ<=0)	return;
 	mgl_datac_create(d, NX,NY,NZ);	if(!A)	return;
-#if MGL_USE_DOUBLE
-	memcpy(d->a,A,NX*NY*NZ*sizeof(double));
-#else
+#pragma omp parallel for
 	for(long i=0;i<NX*NY*NZ;i++)	d->a[i] = A[i];
-#endif
 }
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_datac_set_complex(HADT d, const dual *A,long NX,long NY,long NZ)
 {
 	if(NX<=0 || NY<=0 || NZ<=0)	return;
 	mgl_datac_create(d, NX,NY,NZ);	if(!A)	return;
-	#if MGL_USE_DOUBLE
-	for(long i=0;i<NX*NY*NZ;i++)	d->a[i] = A[i];
-	#else
 	memcpy(d->a,A,NX*NY*NZ*sizeof(float));
-	#endif
 }
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_datac_set_float_(uintptr_t *d, const float *A,int *NX,int *NY,int *NZ)
@@ -378,10 +369,13 @@ int MGL_EXPORT mgl_datac_read_mat_(uintptr_t *d, const char *fname,int *dim,int
 MGL_NO_EXPORT void *mgl_cfill_x(void *par)
 {
 	mglThreadC *t=(mglThreadC *)par;
-	register long i0, nx=t->p[0],ny=t->p[1];
+	long nx=t->p[0],ny=t->p[1];
 	dual *b=t->a, x1=t->b[0], dx=t->b[1];
-	register char dir = t->s[0];
-	for(i0=t->id;i0<t->n;i0+=mglNumThr)
+	char dir = t->s[0];
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i0=t->id;i0<t->n;i0+=mglNumThr)
 	{
 		if(dir=='x') b[i0] = x1+dx*mreal(i0%nx);
 		else if(dir=='y') b[i0] = x1+dx*mreal((i0/nx)%ny);
@@ -405,8 +399,7 @@ void MGL_EXPORT mgl_datac_fill_(uintptr_t *d, dual *x1,dual *x2,const char *dir,
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_datac_squeeze(HADT d, long rx,long ry,long rz,long smooth)
 {
-	long kx,ky,kz,i,j,k;
-	long nx=d->nx, ny=d->ny, nz=d->nz;
+	long kx,ky,kz, nx=d->nx, ny=d->ny, nz=d->nz;
 	dual *b;
 
 	// simple checking
@@ -416,19 +409,23 @@ void MGL_EXPORT mgl_datac_squeeze(HADT d, long rx,long ry,long rz,long smooth)
 	// new sizes
 	kx = 1+(nx-1)/rx;	ky = 1+(ny-1)/ry;	kz = 1+(nz-1)/rz;
 	b = new dual[kx*ky*kz];
-	if(!smooth)	for(k=0;k<kz;k++)	for(j=0;j<ky;j++)	for(i=0;i<kx;i++)
-		b[i+kx*(j+ky*k)] = d->a[i*rx+nx*(j*ry+ny*rz*k)];
-	else		for(k=0;k<kz;k++)	for(j=0;j<ky;j++)	for(i=0;i<kx;i++)
-	{
-		long dx,dy,dz,i1,j1,k1;
-		dx = (i+1)*rx<=nx ? rx : nx-i*rx;
-		dy = (j+1)*ry<=ny ? ry : ny-j*ry;
-		dz = (k+1)*rz<=nz ? rz : nz-k*rz;
-		dual s = 0;
-		for(k1=k*rz;k1<k*rz+dz;k1++)	for(j1=j*ry;j1<j*ry+dz;j1++)	for(i1=i*rx;i1<i*rx+dx;i1++)
-			s += d->a[i1+nx*(j1+ny*k1)];
-		b[i+kx*(j+ky*k)] = s/mreal(dx*dy*dz);
-	}
+	if(!smooth)
+#pragma omp parallel for collapse(3)
+		for(long k=0;k<kz;k++)	for(long j=0;j<ky;j++)	for(long i=0;i<kx;i++)
+			b[i+kx*(j+ky*k)] = d->a[i*rx+nx*(j*ry+ny*rz*k)];
+	else
+#pragma omp parallel for collapse(3)
+		for(long k=0;k<kz;k++)	for(long j=0;j<ky;j++)	for(long i=0;i<kx;i++)
+		{
+			long dx,dy,dz,i1,j1,k1;
+			dx = (i+1)*rx<=nx ? rx : nx-i*rx;
+			dy = (j+1)*ry<=ny ? ry : ny-j*ry;
+			dz = (k+1)*rz<=nz ? rz : nz-k*rz;
+			dual s = 0;
+			for(k1=k*rz;k1<k*rz+dz;k1++)	for(j1=j*ry;j1<j*ry+dz;j1++)	for(i1=i*rx;i1<i*rx+dx;i1++)
+				s += d->a[i1+nx*(j1+ny*k1)];
+			b[i+kx*(j+ky*k)] = s/mreal(dx*dy*dz);
+		}
 	if(!d->link)	delete [](d->a);
 	d->a=b;	d->nx = kx;  d->ny = ky;  d->nz = kz;	d->NewId();	d->link=false;
 }
@@ -441,16 +438,17 @@ void MGL_EXPORT mgl_datac_extend(HADT d, long n1, long n2)
 	if(nz>2 || n1==0)	return;
 	long mx, my, mz;
 	dual *b=0;
-	register long i,j;
 	if(n1>0) // extend to higher dimension(s)
 	{
 		n2 = n2>0 ? n2:1;
 		mx = nx;	my = ny>1?ny:n1;	mz = ny>1 ? n1 : n2;
 		b = new dual[mx*my*mz];
-		if(ny>1)	for(i=0;i<n1;i++)
-			memcpy(b+i*nx*ny, d->a, nx*ny*sizeof(dual));
-		else		for(i=0;i<n1*n2;i++)
-			memcpy(b+i*nx, d->a, nx*sizeof(dual));
+		if(ny>1)
+#pragma omp parallel for
+			for(long i=0;i<n1;i++)	memcpy(b+i*nx*ny, d->a, nx*ny*sizeof(dual));
+		else
+#pragma omp parallel for
+			for(long i=0;i<n1*n2;i++)	memcpy(b+i*nx, d->a, nx*sizeof(dual));
 	}
 	else
 	{
@@ -458,12 +456,17 @@ void MGL_EXPORT mgl_datac_extend(HADT d, long n1, long n2)
 		if(n2>0 && ny==1)	mz = n2;
 		b = new dual[mx*my*mz];
 		register dual v;
-		if(n2<0)	for(j=0;j<nx;j++)	for(i=0,v=d->a[j];i<mx*my;i++)
-			b[i+mx*my*j] = v;
-		else	for(j=0;j<nx*ny;j++)	for(i=0,v=d->a[j];i<mx;i++)
-			b[i+mx*j] = v;
-		if(n2>0 && ny==1)	for(i=0;i<n2;i++)
-			memcpy(b+i*mx*my, d->a, mx*my*sizeof(dual));
+		if(n2<0)
+#pragma omp parallel for collapse(2)
+			for(long j=0;j<nx;j++)	for(long i=0;i<mx*my;i++)
+				b[i+mx*my*j] = d->a[j];
+		else
+#pragma omp parallel for collapse(2)
+			for(long j=0;j<nx*ny;j++)	for(long i=0;i<mx;i++)
+				b[i+mx*j] = d->a[j];
+		if(n2>0 && ny==1)
+#pragma omp parallel for
+			for(long i=0;i<n2;i++)	memcpy(b+i*mx*my, d->a, mx*my*sizeof(dual));
 	}
 	if(!d->link)	delete [](d->a);
 	d->a=b;	d->nx=mx;	d->ny=my;	d->nz=mz;
@@ -474,37 +477,41 @@ void MGL_EXPORT mgl_datac_extend_(uintptr_t *d, int *n1, int *n2)
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_datac_transpose(HADT d, const char *dim)
 {
-	long nx=d->nx, ny=d->ny, nz=d->nz;
+	long nx=d->nx, ny=d->ny, nz=d->nz, n;
 	dual *b=new dual[nx*ny*nz], *a=d->a;
-	register long i,j,k,n;
 	if(!strcmp(dim,"xyz"))	memcpy(b,a,nx*ny*nz*sizeof(dual));
 	else if(!strcmp(dim,"xzy") || !strcmp(dim,"zy"))
 	{
-		for(j=0;j<ny;j++)	for(k=0;k<nz;k++)	for(i=0;i<nx;i++)
+#pragma omp parallel for collapse(3)
+		for(long j=0;j<ny;j++)	for(long k=0;k<nz;k++)	for(long i=0;i<nx;i++)
 			b[i+nx*(k+nz*j)] = a[i+nx*(j+ny*k)];
 		n=nz;	nz=ny;	ny=n;
 	}
 	else if(!strcmp(dim,"yxz") || !strcmp(dim,"yx"))
 	{
-		for(k=0;k<nz;k++)	for(i=0;i<nx;i++)	for(j=0;j<ny;j++)
+#pragma omp parallel for collapse(3)
+		for(long k=0;k<nz;k++)	for(long i=0;i<nx;i++)	for(long j=0;j<ny;j++)
 			b[j+ny*(i+nx*k)] = a[i+nx*(j+ny*k)];
 		n=nx;	nx=ny;	ny=n;
 	}
 	else if(!strcmp(dim,"yzx"))
 	{
-		for(k=0;k<nz;k++)	for(i=0;i<nx;i++)	for(j=0;j<ny;j++)
+#pragma omp parallel for collapse(3)
+		for(long k=0;k<nz;k++)	for(long i=0;i<nx;i++)	for(long j=0;j<ny;j++)
 			b[j+ny*(k+nz*i)] = a[i+nx*(j+ny*k)];
 		n=nx;	nx=ny;	ny=nz;	nz=n;
 	}
 	else if(!strcmp(dim,"zxy"))
 	{
-		for(i=0;i<nx;i++)	for(j=0;j<ny;j++)	for(k=0;k<nz;k++)
+#pragma omp parallel for collapse(3)
+		for(long i=0;i<nx;i++)	for(long j=0;j<ny;j++)	for(long k=0;k<nz;k++)
 			b[k+nz*(i+nx*j)] = a[i+nx*(j+ny*k)];
 		n=nx;	nx=nz;	nz=ny;	ny=n;
 	}
 	else if(!strcmp(dim,"zyx") || !strcmp(dim,"zx"))
 	{
-		for(i=0;i<nx;i++)	for(j=0;j<ny;j++)	for(k=0;k<nz;k++)
+#pragma omp parallel for collapse(3)
+		for(long i=0;i<nx;i++)	for(long j=0;j<ny;j++)	for(long k=0;k<nz;k++)
 			b[k+nz*(j+ny*i)] = a[i+nx*(j+ny*k)];
 		n=nz;	nz=nx;	nx=n;
 	}
@@ -520,14 +527,17 @@ MGL_NO_EXPORT void *mgl_cmodify(void *par)
 {
 	mglThreadC *t=(mglThreadC *)par;
 	const mglFormulaC *f = (const mglFormulaC *)(t->v);
-	register long i,j,k,i0, nx=t->p[0],ny=t->p[1],nz=t->p[2];
+	long nx=t->p[0],ny=t->p[1],nz=t->p[2];
 	dual *b=t->a;
 	mreal dx,dy,dz;
 	const dual *v=t->b, *w=t->c;
 	dx=nx>1?1/(nx-1.):0;	dy=ny>1?1/(ny-1.):0;	dz=nz>1?1/(nz-1.):0;
-	for(i0=t->id;i0<t->n;i0+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i0=t->id;i0<t->n;i0+=mglNumThr)
 	{
-		i=i0%nx;	j=((i0/nx)%ny);	k=i0/(nx*ny);
+		register long i=i0%nx, j=((i0/nx)%ny), k=i0/(nx*ny);
 		b[i0] = f->Calc(i*dx, j*dy, k*dz, b[i0], v?v[i0]:dual(0,0), w?w[i0]:dual(0,0));
 	}
 	return 0;
@@ -556,14 +566,17 @@ MGL_NO_EXPORT void *mgl_cmodify_gen(void *par)
 {
 	mglThreadV *t=(mglThreadV *)par;
 	const mglFormulaC *f = (const mglFormulaC *)(t->v);
-	register long i,j,k,i0, nx=t->p[0],ny=t->p[1],nz=t->p[2];
+	long nx=t->p[0],ny=t->p[1],nz=t->p[2];
 	dual *b=t->aa;
 	mreal dx,dy,dz;
 	HCDT v=(HCDT)t->b, w=(HCDT)t->c;
 	dx=nx>1?1/(nx-1.):0;	dy=ny>1?1/(ny-1.):0;	dz=nz>1?1/(nz-1.):0;
-	for(i0=t->id;i0<t->n;i0+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i0=t->id;i0<t->n;i0+=mglNumThr)
 	{
-		i=i0%nx;	j=((i0/nx)%ny);	k=i0/(nx*ny);
+		register long i=i0%nx, j=((i0/nx)%ny), k=i0/(nx*ny);
 		b[i0] = f->Calc(i*dx, j*dy, k*dz, b[i0], v?v->vthr(i0):0, w?w->vthr(i0):0);
 	}
 	return 0;
@@ -586,63 +599,6 @@ void MGL_EXPORT mgl_datac_modify_vw_(uintptr_t *d, const char *eq, uintptr_t *v,
 {	char *s=new char[l+1];	memcpy(s,eq,l);	s[l]=0;
 	mgl_datac_modify_vw(_DC_,s,_DA_(v),_DA_(w));	delete []s;	}
 //-----------------------------------------------------------------------------
-MGL_NO_EXPORT void *mgl_cfill_f(void *par)
-{
-	mglThreadC *t=(mglThreadC *)par;
-	const mglFormulaC *f = (const mglFormulaC *)(t->v);
-	register long i,j,k,i0, nx=t->p[0],ny=t->p[1];
-	dual *b=t->a;
-	const dual *v=t->b, *w=t->c, *x=t->d;
-	for(i0=t->id;i0<t->n;i0+=mglNumThr)
-	{
-		i=i0%nx;	j=((i0/nx)%ny);	k=i0/(nx*ny);
-		b[i0] = f->Calc(x[0]+mreal(i)*x[1], x[2]+mreal(j)*x[3], x[4]+mreal(k)*x[5],
-						b[i0], v?v[i0]:dual(0,0), w?w[i0]:dual(0,0));
-	}
-	return 0;
-}
-MGL_NO_EXPORT void *mgl_cfill_fgen(void *par)
-{
-	mglThreadV *t=(mglThreadV *)par;
-	const mglFormulaC *f = (const mglFormulaC *)(t->v);
-	register long i,j,k,i0, nx=t->p[0],ny=t->p[1];
-	dual *b=t->aa;
-	HCDT v=(HCDT)t->b, w=(HCDT)t->c;
-	const mreal *x=t->d;
-	for(i0=t->id;i0<t->n;i0+=mglNumThr)
-	{
-		i=i0%nx;	j=((i0/nx)%ny);	k=i0/(nx*ny);
-		b[i0] = f->Calc(x[0]+i*x[1], x[2]+j*x[3], x[4]+k*x[5],
-						b[i0], v?v->vthr(i0):0, w?w->vthr(i0):0);
-	}
-	return 0;
-}
-void MGL_EXPORT mgl_datac_fill_eq(HMGL gr, HADT d, const char *eq, HCDT vdat, HCDT wdat, const char *opt)
-{
-	const mglDataC *v = dynamic_cast<const mglDataC *>(vdat);
-	const mglDataC *w = dynamic_cast<const mglDataC *>(wdat);
-	long nn = d->nx*d->ny*d->nz, par[3]={d->nx,d->ny,d->nz};
-	if(v && v->nx*v->ny*v->nz!=nn)	return;
-	if(w && w->nx*w->ny*w->nz!=nn)	return;
-	gr->SaveState(opt);
-	mreal xx[6]={gr->Min.x,0, gr->Min.y,0, gr->Min.z,0};
-	if(d->nx>1)	xx[1] = (gr->Max.x-gr->Min.x)/(d->nx-1.);
-	if(d->ny>1)	xx[3] = (gr->Max.y-gr->Min.y)/(d->ny-1.);
-	if(d->nz>1)	xx[5] = (gr->Max.z-gr->Min.z)/(d->nz-1.);
-	dual cc[6]={xx[0],xx[1],xx[2],xx[3],xx[4],xx[5]};
-	mglFormulaC f(eq);
-	if(v && w)	mglStartThreadC(mgl_cfill_f,0,nn,d->a,v->a,w->a,par,&f,cc);
-	else if(vdat && wdat)	mglStartThreadV(mgl_cfill_fgen,nn,d->a,vdat,wdat,par,&f,xx);
-	else if(v)	mglStartThreadC(mgl_cfill_f,0,nn,d->a,v->a,0,par,&f,cc);
-	else if(vdat)	mglStartThreadV(mgl_cfill_fgen,nn,d->a,vdat,0,par,&f,xx);
-	else	mglStartThreadC(mgl_cfill_f,0,nn,d->a,0,0,par,&f,cc);
-	gr->LoadState();
-}
-void MGL_EXPORT mgl_datac_fill_eq_(uintptr_t *gr, uintptr_t *d, const char *eq, uintptr_t *v, uintptr_t *w, const char *opt,int l,int lo)
-{	char *s=new char[l+1];	memcpy(s,eq,l);	s[l]=0;
-	char *o=new char[lo+1];	memcpy(o,opt,lo);	o[lo]=0;
-	mgl_datac_fill_eq(_GR_,_DC_,s,_DA_(v),_DA_(w),o);	delete []o;	delete []s;	}
-//-----------------------------------------------------------------------------
 bool MGL_NO_EXPORT mgl_add_file(long &kx,long &ky, long &kz, dual *&b, mglDataC *d,bool as_slice)
 {
 	if(as_slice && d->nz==1)
@@ -737,12 +693,12 @@ int MGL_EXPORT mgl_datac_read_all(HADT dat, const char *templ, int as_slice)
 	{
 		if(mgl_datac_read(&d,res.gl_pathv[i]))
 			if(!mgl_add_file(kx,ky,kz,b,&d,as_slice))
-			{	delete []fname;		return false;	}
+			{	delete []fname;	free(b);	return false;	}
 	}
 	dat->Set(b,kx,ky,kz);
 
 	globfree (&res);
-	delete []fname;		free(b);
+	delete []fname;	free(b);
 	return true;
 #else
 	return false;
@@ -757,8 +713,9 @@ HMDT MGL_EXPORT mgl_datac_real(HCDT d)
 	long nx=d->GetNx(),ny=d->GetNy(),nz=d->GetNz();
 	mglData *r=new mglData(nx,ny,nz);
 	const mglDataC *dd = dynamic_cast<const mglDataC*>(d);
-	register long i;
-	if(dd)	for(i=0;i<nx*ny*nz;i++)	r->a[i] = real(dd->a[i]);
+	if(dd)
+#pragma omp parallel for
+		for(long i=0;i<nx*ny*nz;i++)	r->a[i] = real(dd->a[i]);
 	else		r->Set(d);
 	return r;
 }
@@ -770,8 +727,9 @@ HMDT MGL_EXPORT mgl_datac_imag(HCDT d)
 	long nx=d->GetNx(),ny=d->GetNy(),nz=d->GetNz();
 	mglData *r=new mglData(nx,ny,nz);
 	const mglDataC *dd = dynamic_cast<const mglDataC*>(d);
-	register long i;
-	if(dd)	for(i=0;i<nx*ny*nz;i++)	r->a[i] = imag(dd->a[i]);
+	if(dd)
+#pragma omp parallel for
+		for(long i=0;i<nx*ny*nz;i++)	r->a[i] = imag(dd->a[i]);
 	return r;
 }
 uintptr_t MGL_EXPORT mgl_datac_imag_(uintptr_t *d)
@@ -782,9 +740,12 @@ HMDT MGL_EXPORT mgl_datac_abs(HCDT d)
 	long nx=d->GetNx(),ny=d->GetNy(),nz=d->GetNz();
 	mglData *r=new mglData(nx,ny,nz);
 	const mglDataC *dd = dynamic_cast<const mglDataC*>(d);
-	register long i;
-	if(dd)	for(i=0;i<nx*ny*nz;i++)	r->a[i] = abs(dd->a[i]);
-	else	for(i=0;i<nx*ny*nz;i++)	r->a[i] = fabs(d->vthr(i));
+	if(dd)
+#pragma omp parallel for
+		for(long i=0;i<nx*ny*nz;i++)	r->a[i] = abs(dd->a[i]);
+	else
+#pragma omp parallel for
+		for(long i=0;i<nx*ny*nz;i++)	r->a[i] = fabs(d->vthr(i));
 	return r;
 }
 uintptr_t MGL_EXPORT mgl_datac_abs_(uintptr_t *d)
@@ -795,8 +756,9 @@ HMDT MGL_EXPORT mgl_datac_arg(HCDT d)
 	long nx=d->GetNx(),ny=d->GetNy(),nz=d->GetNz();
 	mglData *r=new mglData(nx,ny,nz);
 	const mglDataC *dd = dynamic_cast<const mglDataC*>(d);
-	register long i;
-	if(dd)	for(i=0;i<nx*ny*nz;i++)	r->a[i] = arg(dd->a[i]);
+	if(dd)
+#pragma omp parallel for
+		for(long i=0;i<nx*ny*nz;i++)	r->a[i] = arg(dd->a[i]);
 	return r;
 }
 uintptr_t MGL_EXPORT mgl_datac_arg_(uintptr_t *d)
@@ -806,8 +768,8 @@ void MGL_EXPORT mgl_datac_set_ri(HADT d, HCDT re, HCDT im)
 {
 	long nx=d->GetNx(),ny=d->GetNy(),nz=d->GetNz();
 	d->Create(nx,ny,nz);
-	register long i;
-	for(i=0;i<nx*ny*nz;i++)	d->a[i] = dual(re->vthr(i),im->vthr(i));
+#pragma omp parallel for
+	for(long i=0;i<nx*ny*nz;i++)	d->a[i] = dual(re->vthr(i),im->vthr(i));
 }
 void MGL_EXPORT mgl_datac_set_ri_(uintptr_t *d, uintptr_t *re, uintptr_t *im)
 {	mgl_datac_set_ri(_DC_,_DA_(re),_DA_(im));	}
@@ -816,11 +778,10 @@ void MGL_EXPORT mgl_datac_set_ap(HADT d, HCDT a, HCDT p)
 {
 	long nx=d->GetNx(),ny=d->GetNy(),nz=d->GetNz();
 	d->Create(nx,ny,nz);
-	register long i;
-	register mreal aa,pp;
-	for(i=0;i<nx*ny*nz;i++)
+#pragma omp parallel for
+	for(long i=0;i<nx*ny*nz;i++)
 	{
-		aa=a->vthr(i);	pp=p->vthr(i);
+		register mreal aa=a->vthr(i), pp=p->vthr(i);
 		d->a[i] = dual(aa*cos(pp), aa*sin(pp));
 	}
 }
diff --git a/src/cont.cpp b/src/cont.cpp
index f9bd325..d798af5 100644
--- a/src/cont.cpp
+++ b/src/cont.cpp
@@ -17,7 +17,7 @@
  *   Free Software Foundation, Inc.,                                       *
  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
  ***************************************************************************/
-// NOTE: Borland before 2007 (i.e. < 0x0600) use <algorithm.h>, fter 0x0630 it use <algorithm>.
+// NOTE: Borland before 2007 (i.e. < 0x0600) use <algorithm.h>, after 0x0630 it use <algorithm>.
 // I don't find information about 2009, 2010 versions (i.e. 0x0610 and 0x0620).
 // May be condition below can be rewritten as (__CODEGEARC__ >=  0x0600)
 #if !defined(__BORLANDC__) || (__CODEGEARC__ >=  0x0630)
@@ -31,12 +31,13 @@
 #include "mgl2/data.h"
 #include "mgl2/eval.h"
 #include "mgl2/font.h"
+#include "mgl2/base.h"
 //-----------------------------------------------------------------------------
 //
 //	Text printing along a curve
 //
 //-----------------------------------------------------------------------------
-void MGL_NO_EXPORT mgl_string_curve(mglBase *gr,long f,long ,long *ff,long *nn,const wchar_t *text, const char *font, mreal size)
+void MGL_NO_EXPORT mgl_string_curve(mglBase *gr,long f,long ,const long *ff,const long *nn,const wchar_t *text, const char *font, mreal size)
 {
 	if(f<0 || nn[f]==-1)	return;	// do nothing since there is no curve
 	if(!font)	font="";
@@ -75,7 +76,7 @@ void MGL_NO_EXPORT mgl_string_curve(mglBase *gr,long f,long ,long *ff,long *nn,c
 		else		{	strcat(fnt,":L");	align=0;	}
 	}
 	if(rev)	reverse(qa.begin(),qa.end());
-	long len = wcslen(text);
+	long len = mgl_wcslen(text);
 	mreal *wdt=new mreal[len+1];
 	for(j=0;j<len;j++)	{	L[0]=text[j];	wdt[j]=1.2*gr->TextWidth(L,font,size);	}
 	wdt[len]=0;
@@ -84,9 +85,6 @@ void MGL_NO_EXPORT mgl_string_curve(mglBase *gr,long f,long ,long *ff,long *nn,c
 	mglPoint *pt=new mglPoint[len+1];
 	pt[0] = qa[0];	m = qa.size();
 
-	// next string for testing curve position
-	//for(i=0;i<m;i++) gr->mark_plot(gr->AddPnt(qa[i],c,s,-1,-1),'.');
-	
 	mreal a,b,d,w,t1,t2;
 	for(i=j=0,tt=0;j<len;j++)
 	{
@@ -105,8 +103,10 @@ void MGL_NO_EXPORT mgl_string_curve(mglBase *gr,long f,long ,long *ff,long *nn,c
 	}
 	if(rev)	pos=-pos;
 	for(j=0;j<len;j++)	// draw text
-	{	L[0] = text[align!=2?j:len-1-j];	s = pt[j+1]-pt[j];	l = !s;
-	gr->text_plot(gr->AddPnt(pt[j]+(pos*h)*l,c,s,-1,-1),L,font,size,0.05,c);	}
+	{
+		L[0] = text[align!=2?j:len-1-j];	s = pt[j+1]-pt[j];	l = !s;
+		gr->text_plot(gr->AddPnt(pt[j]+(pos*h)*l,c,s,-1,-1),L,font,size,0.05,c);
+	}
 	delete []wdt;	delete []pt;	delete []fnt;
 }
 //-----------------------------------------------------------------------------
@@ -119,16 +119,19 @@ void MGL_EXPORT mgl_textw_xyz(HMGL gr, HCDT x, HCDT y, HCDT z,const wchar_t *tex
 	static int cgid=1;	gr->StartGroup("TextC",cgid++);
 
 	long *nn = new long[n], *ff = new long[n];
-	mglPoint p;
-	register long i;
 	const mglData *mdx = dynamic_cast<const mglData *>(x);
 	const mglData *mdy = dynamic_cast<const mglData *>(y);
 	const mglData *mdz = dynamic_cast<const mglData *>(z);
-	if(mdx && mdy && mdz)	for(i=0;i<n;i++)
-	{	p = mglPoint(mdx->a[i],mdy->a[i],mdz->a[i]);	ff[i] = gr->AddPnt(p,-1);	}
-	else	for(i=0;i<n;i++)
-	{	p = mglPoint(x->v(i),y->v(i),z->v(i));	ff[i] = gr->AddPnt(p,-1);	}
-	for(i=1;i<n;i++)	nn[i-1] = i;
+	if(mdx && mdy && mdz)
+#pragma omp parallel for
+		for(long i=0;i<n;i++)
+			ff[i] = gr->AddPnt(mglPoint(mdx->a[i],mdy->a[i],mdz->a[i]),-1);
+	else
+#pragma omp parallel for
+		for(long i=0;i<n;i++)
+			ff[i] = gr->AddPnt(mglPoint(x->v(i),y->v(i),z->v(i)),-1);
+#pragma omp parallel for
+	for(long i=1;i<n;i++)	nn[i-1] = i;
 	nn[n-1]=-1;
 	mgl_string_curve(gr,0,n,ff,nn,text,font,-1);
 	gr->EndGroup();
@@ -156,11 +159,7 @@ void MGL_EXPORT mgl_textw_y(HMGL gr, HCDT y, const wchar_t *text, const char *fo
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_text_xyz(HMGL gr, HCDT x, HCDT y, HCDT z,const char *text, const char *font, const char *opt)
 {
-	size_t s = mbstowcs(0,text,0)+1;
-	wchar_t *wcs = new wchar_t[s];
-	mbstowcs(wcs,text,s);
-	mgl_textw_xyz(gr,x,y,z, wcs, font, opt);
-	delete []wcs;
+	MGL_TO_WCS(text,mgl_textw_xyz(gr,x,y,z, wcs, font, opt));
 }
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_text_xy(HMGL gr, HCDT x, HCDT y, const char *text, const char *font, const char *opt)
@@ -268,19 +267,19 @@ long *mgl_cont_prep(mreal val, HCDT a,long ak, std::vector<mglPnt2> &kk)
 	const mglData *ma = dynamic_cast<const mglData *>(a);
 	if(ma)
 	{
-		for(i=0;i<n-1;i++)	for(j=0;j<m;j++)
+		for(j=0;j<m;j++)	for(i=0;i<n-1;i++)
 		{
 			d = mgl_d(val,ma->a[i+n*(j+m*ak)],ma->a[i+1+n*(j+m*ak)]);
 			if(d>=0 && d<1)	kk.push_back(mglPnt2(i+d,j));
 		}
 		// add intersection point of isoline and X axis
-		for(i=0;i<n;i++)	for(j=0;j<m-1;j++)
+		for(j=0;j<m-1;j++)	for(i=0;i<n;i++)
 		{
 			d = mgl_d(val,ma->a[i+n*(j+m*ak)],ma->a[i+n*(j+1+m*ak)]);
 			if(d>=0 && d<1)	kk.push_back(mglPnt2(i,j+d));
 		}
 	}
-	else	for(i=0;i<n-1;i++)	for(j=0;j<m;j++)
+	else	for(j=0;j<m-1;j++)	for(i=0;i<n-1;i++)
 	{
 		register mreal vv = a->v(i,j,ak);
 		d = (i<n-1)?mgl_d(val,vv,a->v(i+1,j,ak)):-1;
@@ -396,7 +395,7 @@ void MGL_EXPORT mgl_cont_gen(HMGL gr, double val, HCDT a, HCDT x, HCDT y, HCDT z
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_cont_xy_val(HMGL gr, HCDT v, HCDT x, HCDT y, HCDT z, const char *sch, const char *opt)
 {
-	register long i,j,n=z->GetNx(),m=z->GetNy();
+	long n=z->GetNx(),m=z->GetNy();
 	if(mgl_check_dim2(gr,x,y,z,0,"Cont"))	return;
 
 	gr->SaveState(opt);
@@ -407,28 +406,36 @@ void MGL_EXPORT mgl_cont_xy_val(HMGL gr, HCDT v, HCDT x, HCDT y, HCDT z, const c
 	long s=gr->AddTexture(sch);
 	gr->SetPenPal(sch);
 
-	mglData xx, yy, zz(z->GetNx(), z->GetNy());
+	mglData xx, yy;
 	if(x->GetNx()*x->GetNy()!=m*n || y->GetNx()*y->GetNy()!=m*n)	// make
 	{
 		xx.Create(n, m);		yy.Create(n, m);
 		const mglData *mx = dynamic_cast<const mglData *>(x);
 		const mglData *my = dynamic_cast<const mglData *>(y);
-		if(mx && my)	for(i=0;i<n;i++)	for(j=0;j<m;j++)
-		{	xx.a[i+n*j] = mx->a[i];	yy.a[i+n*j] = my->a[j];	}
-		else	for(i=0;i<n;i++)	for(j=0;j<m;j++)
-		{	xx.a[i+n*j] = x->v(i);	yy.a[i+n*j] = y->v(j);	}
+		if(mx && my)
+#pragma omp parallel for collapse(2)
+			for(long i=0;i<n;i++)	for(long j=0;j<m;j++)
+			{	xx.a[i+n*j] = mx->a[i];	yy.a[i+n*j] = my->a[j];	}
+		else
+#pragma omp parallel for collapse(2)
+			for(long i=0;i<n;i++)	for(long j=0;j<m;j++)
+			{	xx.a[i+n*j] = x->v(i);	yy.a[i+n*j] = y->v(j);	}
 		x = &xx;	y = &yy;
 	}
 	// x, y -- have the same size z
-	mreal z0, v0;
-	for(j=0;j<z->GetNz();j++)	for(i=0;i<v->GetNx();i++)
+#pragma omp parallel
 	{
-		if(gr->Stop)	return;
-		v0 = v->v(i);		z0 = fixed ? gr->Min.z : v0;
-		if(z->GetNz()>1)
-			z0 = gr->Min.z+(gr->Max.z-gr->Min.z)*mreal(j)/(z->GetNz()-1);
-		zz.Fill(z0,z0);
-		mgl_cont_gen(gr,v0,z,x,y,&zz,gr->GetC(s,v0),text,j);
+		mglData zz(n, m);
+#pragma omp for collapse(2)
+		for(long j=0;j<z->GetNz();j++)	for(long i=0;i<v->GetNx();i++)
+		{
+			if(gr->Stop)	continue;
+			mreal v0 = v->v(i), z0 = fixed ? gr->Min.z : v0;
+			if(z->GetNz()>1)
+				z0 = gr->Min.z+(gr->Max.z-gr->Min.z)*mreal(j)/(z->GetNz()-1);
+			zz.Fill(z0,z0);
+			mgl_cont_gen(gr,v0,z,x,y,&zz,gr->GetC(s,v0),text,j);
+		}
 	}
 	gr->EndGroup();
 }
@@ -604,7 +611,7 @@ void MGL_EXPORT mgl_contf_gen(HMGL gr, double v1, double v2, HCDT a, HCDT x, HCD
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_contf_xy_val(HMGL gr, HCDT v, HCDT x, HCDT y, HCDT z, const char *sch, const char *opt)
 {
-	register long i,j,n=z->GetNx(),m=z->GetNy();
+	long n=z->GetNx(),m=z->GetNy();
 	if(mgl_check_dim2(gr,x,y,z,0,"ContF"))	return;
 
 	gr->SaveState(opt);
@@ -612,28 +619,36 @@ void MGL_EXPORT mgl_contf_xy_val(HMGL gr, HCDT v, HCDT x, HCDT y, HCDT z, const
 	long s=gr->AddTexture(sch);
 
 	bool fixed=(mglchr(sch,'_')) || (gr->Min.z==gr->Max.z);
-	mglData xx, yy, zz(n, m);
+	mglData xx, yy;
 	if(x->GetNx()*x->GetNy()!=m*n || y->GetNx()*y->GetNy()!=m*n)	// make
 	{
 		xx.Create(n, m);		yy.Create(n, m);
 		const mglData *mx = dynamic_cast<const mglData *>(x);
 		const mglData *my = dynamic_cast<const mglData *>(y);
-		if(mx && my)	for(i=0;i<n;i++)	for(j=0;j<m;j++)
-		{	xx.a[i+n*j] = mx->a[i];	yy.a[i+n*j] = my->a[j];	}
-		else	for(i=0;i<n;i++)	for(j=0;j<m;j++)
-		{	xx.a[i+n*j] = x->v(i);	yy.a[i+n*j] = y->v(j);	}
+		if(mx && my)
+#pragma omp parallel for collapse(2)
+			for(long j=0;j<m;j++)	for(long i=0;i<n;i++)
+			{	xx.a[i+n*j] = mx->a[i];	yy.a[i+n*j] = my->a[j];	}
+		else
+#pragma omp parallel for collapse(2)
+			for(long j=0;j<m;j++)	for(long i=0;i<n;i++)
+			{	xx.a[i+n*j] = x->v(i);	yy.a[i+n*j] = y->v(j);	}
 		x = &xx;	y = &yy;
 	}
 	// x, y -- have the same size z
-	mreal z0, v0;
-	for(j=0;j<z->GetNz();j++)	for(i=0;i<v->GetNx()-1;i++)
+#pragma omp parallel
 	{
-		if(gr->Stop)	return;
-		v0 = v->v(i);		z0 = fixed ? gr->Min.z : v0;
-		if(z->GetNz()>1)
-			z0 = gr->Min.z+(gr->Max.z-gr->Min.z)*mreal(j)/(z->GetNz()-1);
-		zz.Fill(z0,z0);
-		mgl_contf_gen(gr,v0,v->v(i+1),z,x,y,&zz,gr->GetC(s,v0),j);
+		mglData zz(n, m);
+#pragma omp for collapse(2)
+		for(long j=0;j<z->GetNz();j++)	for(long i=0;i<v->GetNx()-1;i++)
+		{
+			if(gr->Stop)	continue;
+			mreal v0 = v->v(i), z0 = fixed ? gr->Min.z : v0;
+			if(z->GetNz()>1)
+				z0 = gr->Min.z+(gr->Max.z-gr->Min.z)*mreal(j)/(z->GetNz()-1);
+			zz.Fill(z0,z0);
+			mgl_contf_gen(gr,v0,v->v(i+1),z,x,y,&zz,gr->GetC(s,v0),j);
+		}
 	}
 	gr->EndGroup();
 }
@@ -706,7 +721,7 @@ int MGL_NO_EXPORT mgl_get_ncol(const char *sch, char *res)
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_contd_xy_val(HMGL gr, HCDT v, HCDT x, HCDT y, HCDT z, const char *sch, const char *opt)
 {
-	register long i,j=0,n=z->GetNx(),m=z->GetNy();
+	long i,j=0,n=z->GetNx(),m=z->GetNy();
 	if(mgl_check_dim2(gr,x,y,z,0,"ContD"))	return;
 
 	gr->SaveState(opt);
@@ -717,28 +732,37 @@ void MGL_EXPORT mgl_contd_xy_val(HMGL gr, HCDT v, HCDT x, HCDT y, HCDT z, const
 	if(j==0)	sch = MGL_DEF_PAL;
 	long s = gr->AddTexture(sch,1);
 	int nc = gr->GetNumPal(s*256);
-	mglData xx, yy, zz(n, m);
+	mglData xx, yy;
 	if(x->GetNx()*x->GetNy()!=m*n || y->GetNx()*y->GetNy()!=m*n)	// make
 	{
 		xx.Create(n, m);		yy.Create(n, m);
 		const mglData *mx = dynamic_cast<const mglData *>(x);
 		const mglData *my = dynamic_cast<const mglData *>(y);
-		if(mx && my)	for(i=0;i<n;i++)	for(j=0;j<m;j++)
-		{	xx.a[i+n*j] = mx->a[i];	yy.a[i+n*j] = my->a[j];	}
-		else	for(i=0;i<n;i++)	for(j=0;j<m;j++)
-		{	xx.a[i+n*j] = x->v(i);	yy.a[i+n*j] = y->v(j);	}
+		if(mx && my)
+#pragma omp parallel for collapse(2)
+			for(long j=0;j<m;j++)	for(long i=0;i<n;i++)
+			{	xx.a[i+n*j] = mx->a[i];	yy.a[i+n*j] = my->a[j];	}
+		else
+#pragma omp parallel for collapse(2)
+			for(long j=0;j<m;j++)	for(long i=0;i<n;i++)
+			{	xx.a[i+n*j] = x->v(i);	yy.a[i+n*j] = y->v(j);	}
 		x = &xx;	y = &yy;
 	}
 	// x, y -- have the same size z
-	mreal z0, v0, dc = nc>1 ? 1/(MGL_FEPSILON*(nc-1)) : 0;
-	for(j=0;j<z->GetNz();j++)	for(i=0;i<v->GetNx()-1;i++)
+	mreal dc = nc>1 ? 1/(MGL_FEPSILON*(nc-1)) : 0;
+#pragma omp parallel
 	{
-		if(gr->Stop)	return;
-		v0 = v->v(i);		z0 = fixed ? gr->Min.z : v0;
-		if(z->GetNz()>1)
-			z0 = gr->Min.z+(gr->Max.z-gr->Min.z)*mreal(j)/(z->GetNz()-1);
-		zz.Fill(z0,z0);
-		mgl_contf_gen(gr,v0,v->v(i+1),z,x,y,&zz,s+i*dc,j);
+		mglData zz(n, m);
+#pragma omp for collapse(2)
+		for(long j=0;j<z->GetNz();j++)	for(long i=0;i<v->GetNx()-1;i++)
+		{
+			if(gr->Stop)	continue;
+			mreal v0 = v->v(i), z0 = fixed ? gr->Min.z : v0;
+			if(z->GetNz()>1)
+				z0 = gr->Min.z+(gr->Max.z-gr->Min.z)*mreal(j)/(z->GetNz()-1);
+			zz.Fill(z0,z0);
+			mgl_contf_gen(gr,v0,v->v(i+1),z,x,y,&zz,s+i*dc,j);
+		}
 	}
 	gr->EndGroup();
 }
@@ -826,7 +850,7 @@ void MGL_EXPORT mgl_contv_gen(HMGL gr, mreal val, mreal dval, HCDT a, HCDT x, HC
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_contv_xy_val(HMGL gr, HCDT v, HCDT x, HCDT y, HCDT z, const char *sch, const char *opt)
 {
-	register long i,j,n=z->GetNx(),m=z->GetNy();
+	long n=z->GetNx(),m=z->GetNy();
 	if(mgl_check_dim2(gr,x,y,z,0,"ContV"))	return;
 
 	gr->SaveState(opt);
@@ -835,31 +859,39 @@ void MGL_EXPORT mgl_contv_xy_val(HMGL gr, HCDT v, HCDT x, HCDT y, HCDT z, const
 	long s=gr->AddTexture(sch);
 	gr->SetPenPal(sch);
 
-	mglData xx, yy, zz(n, m);
+	mglData xx, yy;
 	if(x->GetNx()*x->GetNy()!=m*n || y->GetNx()*y->GetNy()!=m*n)	// make
 	{
 		xx.Create(n, m);		yy.Create(n, m);
 		const mglData *mx = dynamic_cast<const mglData *>(x);
 		const mglData *my = dynamic_cast<const mglData *>(y);
-		if(mx && my)	for(i=0;i<n;i++)	for(j=0;j<m;j++)
-		{	xx.a[i+n*j] = mx->a[i];	yy.a[i+n*j] = my->a[j];	}
-		else	for(i=0;i<n;i++)	for(j=0;j<m;j++)
-		{	xx.a[i+n*j] = x->v(i);	yy.a[i+n*j] = y->v(j);	}
+		if(mx && my)
+#pragma omp parallel for collapse(2)
+			for(long j=0;j<m;j++)	for(long i=0;i<n;i++)
+			{	xx.a[i+n*j] = mx->a[i];	yy.a[i+n*j] = my->a[j];	}
+		else
+#pragma omp parallel for collapse(2)
+			for(long j=0;j<m;j++)	for(long i=0;i<n;i++)
+			{	xx.a[i+n*j] = x->v(i);	yy.a[i+n*j] = y->v(j);	}
 		x = &xx;	y = &yy;
 	}
 	// x, y -- have the same size z
-	mreal z0, v0;
-	for(j=0;j<z->GetNz();j++)	for(i=0;i<v->GetNx();i++)
+#pragma omp parallel
 	{
-		if(gr->Stop)	return;
-		v0 = v->v(i);		z0 = fixed ? gr->Min.z : v0;
-		if(z->GetNz()>1)	z0 = gr->Min.z+(gr->Max.z-gr->Min.z)*mreal(j)/(z->GetNz()-1);
-		zz.Fill(z0,z0);
-		mreal dv = (gr->Max.c-gr->Min.c)/8;
-		if(i>0)	dv = v->v(i-1)-v->v(i);
-		else if(i<v->GetNx()-1)	dv = v->v(i)-v->v(i+1);
-		if(fixed)	dv=-dv;
-		mgl_contv_gen(gr,v0,dv,z,x,y,&zz,gr->GetC(s,v0),j);
+		mglData zz(n, m);
+#pragma omp for collapse(2)
+		for(long j=0;j<z->GetNz();j++)	for(long i=0;i<v->GetNx();i++)
+		{
+			if(gr->Stop)	continue;
+			mreal v0 = v->v(i), z0 = fixed ? gr->Min.z : v0;
+			if(z->GetNz()>1)	z0 = gr->Min.z+(gr->Max.z-gr->Min.z)*mreal(j)/(z->GetNz()-1);
+			zz.Fill(z0,z0);
+			mreal dv = (gr->Max.c-gr->Min.c)/8;
+			if(i>0)	dv = v->v(i-1)-v->v(i);
+			else if(i<v->GetNx()-1)	dv = v->v(i)-v->v(i+1);
+			if(fixed)	dv=-dv;
+			mgl_contv_gen(gr,v0,dv,z,x,y,&zz,gr->GetC(s,v0),j);
+		}
 	}
 	gr->EndGroup();
 }
@@ -1004,7 +1036,7 @@ void MGL_NO_EXPORT mgl_get_slice(_mgl_slice &s, HCDT x, HCDT y, HCDT z, HCDT a,
 //-----------------------------------------------------------------------------
 void MGL_NO_EXPORT mgl_get_slice_md(_mgl_slice &s, const mglData *x, const mglData *y, const mglData *z, const mglData *a, char dir, mreal d, bool both)
 {
-	register long i,j,i0,i1,n=a->nx,m=a->ny,l=a->nz, nx=1,ny=1,p;
+	long n=a->nx,m=a->ny,l=a->nz, nx=1,ny=1,p;
 
 	if(dir=='x')	{	nx = m;	ny = l;	if(d<0)	d = n/2.;	}
 	if(dir=='y')	{	nx = n;	ny = l;	if(d<0)	d = m/2.;	}
@@ -1019,60 +1051,69 @@ void MGL_NO_EXPORT mgl_get_slice_md(_mgl_slice &s, const mglData *x, const mglDa
 
 	if(both)
 	{
-		if(dir=='x')	for(j=0;j<ny;j++)	for(i=0;i<nx;i++)
-		{
-			i0 = i+nx*j;	i1 = p+n*(i+m*j);
-			s.x.a[i0] = x->a[i1]*(1-d) + x->a[i1+1]*d;
-			s.y.a[i0] = y->a[i1]*(1-d) + y->a[i1+1]*d;
-			s.z.a[i0] = z->a[i1]*(1-d) + z->a[i1+1]*d;
-			s.a.a[i0] = a->a[i1]*(1-d) + a->a[i1+1]*d;
-		}
-		if(dir=='y')	for(j=0;j<ny;j++)	for(i=0;i<nx;i++)
-		{
-			i0 = i+nx*j;	i1 = i+n*(p+m*j);
-			s.x.a[i0] = x->a[i1]*(1-d) + x->a[i1+n]*d;
-			s.y.a[i0] = y->a[i1]*(1-d) + y->a[i1+n]*d;
-			s.z.a[i0] = z->a[i1]*(1-d) + z->a[i1+n]*d;
-			s.a.a[i0] = a->a[i1]*(1-d) + a->a[i1+n]*d;
-		}
-		if(dir=='z')	for(j=0;j<ny;j++)	for(i=0;i<nx;i++)
-		{
-			i0 = i+nx*j;	i1 = i+n*(j+m*p);
-			s.x.a[i0] = x->a[i1]*(1-d) + x->a[i1+n*m]*d;
-			s.y.a[i0] = y->a[i1]*(1-d) + y->a[i1+n*m]*d;
-			s.z.a[i0] = z->a[i1]*(1-d) + z->a[i1+n*m]*d;
-			s.a.a[i0] = a->a[i1]*(1-d) + a->a[i1+n*m]*d;
-		}
+		if(dir=='x')
+#pragma omp parallel for collapse(2)
+			for(long j=0;j<ny;j++)	for(long i=0;i<nx;i++)
+			{
+				register long i0 = i+nx*j, i1 = p+n*(i+m*j);
+				s.x.a[i0] = x->a[i1]*(1-d) + x->a[i1+1]*d;
+				s.y.a[i0] = y->a[i1]*(1-d) + y->a[i1+1]*d;
+				s.z.a[i0] = z->a[i1]*(1-d) + z->a[i1+1]*d;
+				s.a.a[i0] = a->a[i1]*(1-d) + a->a[i1+1]*d;
+			}
+		if(dir=='y')
+#pragma omp parallel for collapse(2)
+			for(long j=0;j<ny;j++)	for(long i=0;i<nx;i++)
+			{
+				register long i0 = i+nx*j, i1 = i+n*(p+m*j);
+				s.x.a[i0] = x->a[i1]*(1-d) + x->a[i1+n]*d;
+				s.y.a[i0] = y->a[i1]*(1-d) + y->a[i1+n]*d;
+				s.z.a[i0] = z->a[i1]*(1-d) + z->a[i1+n]*d;
+				s.a.a[i0] = a->a[i1]*(1-d) + a->a[i1+n]*d;
+			}
+		if(dir=='z')
+#pragma omp parallel for collapse(2)
+			for(long j=0;j<ny;j++)	for(long i=0;i<nx;i++)
+			{
+				register long i0 = i+nx*j, i1 = i+n*(j+m*p);
+				s.x.a[i0] = x->a[i1]*(1-d) + x->a[i1+n*m]*d;
+				s.y.a[i0] = y->a[i1]*(1-d) + y->a[i1+n*m]*d;
+				s.z.a[i0] = z->a[i1]*(1-d) + z->a[i1+n*m]*d;
+				s.a.a[i0] = a->a[i1]*(1-d) + a->a[i1+n*m]*d;
+			}
 	}
 	else	// x, y, z -- vectors
 	{
 		if(dir=='x')
 		{
 			v = x->a[p]*(1-d)+x->a[p+1]*d;
-			for(j=0;j<ny;j++)	for(i=0;i<nx;i++)
+#pragma omp parallel for collapse(2)
+			for(long j=0;j<ny;j++)	for(long i=0;i<nx;i++)
 			{
-				i0 = i+nx*j;	s.x.a[i0] = v;	i1 = p+n*(i+m*j);
-				s.y.a[i0] = y->a[i];	s.z.a[i0] = z->a[j];
+				register long i0 = i+nx*j, i1 = p+n*(i+m*j);
+				s.x.a[i0] = v;	s.y.a[i0] = y->a[i];	s.z.a[i0] = z->a[j];
 				s.a.a[i0] = a->a[i1]*(1-d) + a->a[i1+1]*d;
 			}
 		}
 		if(dir=='y')
 		{
 			v = y->a[p]*(1-d)+y->a[p+1]*d;
-			for(j=0;j<ny;j++)	for(i=0;i<nx;i++)
+#pragma omp parallel for collapse(2)
+			for(long j=0;j<ny;j++)	for(long i=0;i<nx;i++)
 			{
-				i0 = i+nx*j;	s.y.a[i0] = v;	i1 = i+n*(p+m*j);
-				s.x.a[i0] = x->a[i];	s.z.a[i0] = z->a[j];
+				register long i0 = i+nx*j, i1 = i+n*(p+m*j);
+				s.x.a[i0] = x->a[i];	s.y.a[i0] = v;	s.z.a[i0] = z->a[j];
 				s.a.a[i0] = a->a[i1]*(1-d) + a->a[i1+n]*d;
 			}
 		}
 		if(dir=='z')
 		{
 			v = z->a[p]*(1-d)+z->a[p+1]*d;
-			for(j=0;j<ny;j++)	for(i=0;i<nx;i++)
+#pragma omp parallel for collapse(2)
+			for(long j=0;j<ny;j++)	for(long i=0;i<nx;i++)
 			{
-				i0 = i+nx*j;	s.z.a[i0] = v;	i1 = i+n*(j+m*p);
-				s.x.a[i0] = x->a[i];	s.y.a[i0] = y->a[j];
+				register long i0 = i+nx*j, i1 = i+n*(j+m*p);
+				s.x.a[i0] = x->a[i];	s.y.a[i0] = y->a[j];	s.z.a[i0] = v;
 				s.a.a[i0] = a->a[i1]*(1-d) + a->a[i1+n*m]*d;
 			}
 		}
@@ -1101,9 +1142,10 @@ void MGL_EXPORT mgl_cont3_xyz_val(HMGL gr, HCDT v, HCDT x, HCDT y, HCDT z, HCDT
 	const mglData *ma = dynamic_cast<const mglData *>(a);
 	if(mx&&my&&mz&&ma)	mgl_get_slice_md(s,mx,my,mz,ma,dir,sVal,both);
 	else mgl_get_slice(s,x,y,z,a,dir,sVal,both);
+#pragma omp parallel for
 	for(long i=0;i<v->GetNx();i++)
 	{
-		mreal v0 = v->v(i);
+		register mreal v0 = v->v(i);
 		mgl_cont_gen(gr,v0,&s.a,&s.x,&s.y,&s.z,gr->GetC(ss,v0),text,0);
 	}
 	gr->EndGroup();
@@ -1283,9 +1325,10 @@ void MGL_EXPORT mgl_contf3_xyz_val(HMGL gr, HCDT v, HCDT x, HCDT y, HCDT z, HCDT
 	const mglData *ma = dynamic_cast<const mglData *>(a);
 	if(mx&&my&&mz&&ma)	mgl_get_slice_md(s,mx,my,mz,ma,dir,sVal,both);
 	else mgl_get_slice(s,x,y,z,a,dir,sVal,both);
+#pragma omp parallel for
 	for(long i=0;i<v->GetNx()-1;i++)
 	{
-		mreal v0 = v->v(i);
+		register mreal v0 = v->v(i);
 		mgl_contf_gen(gr,v0,v->v(i+1),&s.a,&s.x,&s.y,&s.z,gr->GetC(ss,v0),0);
 	}
 	gr->EndGroup();
@@ -1363,7 +1406,6 @@ void MGL_NO_EXPORT mgl_axial_plot(mglBase *gr,long pc, mglPoint *ff, long *nn,ch
 	b = !a;	c = a^b;
 
 	register long i,j,k;
-	mreal fi,si,co;
 	long p1,p2,p3,p4;
 	gr->Reserve(pc*82);
 	for(i=0;i<pc;i++)
@@ -1380,11 +1422,12 @@ void MGL_NO_EXPORT mgl_axial_plot(mglBase *gr,long pc, mglPoint *ff, long *nn,ch
 		p2 = wire ? gr->AddPnt(p,cc) : gr->AddPnt(p,cc,(a*q2.y + c*q2.x)^b);
 		if(wire==1)	gr->line_plot(p1,p2);
 		else if(wire)	{	gr->mark_plot(p1,'.');	gr->mark_plot(p2,'.');	}
-		
+
 		for(j=1;j<41;j++)
 		{
 			p3 = p1;	p4 = p2;
-			fi = j*M_PI/20;		si = sin(fi);	co = cos(fi);
+			register float co = mgl_cos[(j*18)%360], si = mgl_cos[(270+j*18)%360];
+//			fi = j*M_PI/20;		si = sin(fi);	co = cos(fi);
 			p = a*ff[i].y + b*(si*ff[i].x) +  c*(co*ff[i].x);
 			p1 = wire ?	gr->AddPnt(p,cc) : gr->AddPnt(p,cc,(a*q1.y + b*(si*q1.x) +  c*(co*q1.x))^(b*co-c*si));
 			p = a*ff[nn[i]].y + b*(si*ff[nn[i]].x) +  c*(co*ff[nn[i]].x);
@@ -1495,12 +1538,10 @@ void MGL_EXPORT mgl_axial_gen(HMGL gr, mreal val, HCDT a, HCDT x, HCDT y, mreal
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_axial_xy_val(HMGL gr, HCDT v, HCDT x, HCDT y, HCDT z, const char *sch, const char *opt)
 {
-	register long i,j,n=z->GetNx(),m=z->GetNy();
+	long n=z->GetNx(),m=z->GetNy();
 	if(mgl_check_dim2(gr,x,y,z,0,"Axial"))	return;
-
 	gr->SaveState(opt);
 	static int cgid=1;	gr->StartGroup("Axial",cgid++);
-
 	long s=gr->AddTexture(sch);
 	char dir='y';
 	if(mglchr(sch,'x'))	dir = 'x';
@@ -1512,20 +1553,24 @@ void MGL_EXPORT mgl_axial_xy_val(HMGL gr, HCDT v, HCDT x, HCDT y, HCDT z, const
 		xx.Create(n, m);		yy.Create(n, m);
 		const mglData *mx = dynamic_cast<const mglData *>(x);
 		const mglData *my = dynamic_cast<const mglData *>(y);
-		if(mx && my)	for(i=0;i<n;i++)	for(j=0;j<m;j++)
-		{	xx.a[i+n*j] = mx->a[i];	yy.a[i+n*j] = my->a[j];	}
-		else	for(i=0;i<n;i++)	for(j=0;j<m;j++)
-		{	xx.a[i+n*j] = x->v(i);	yy.a[i+n*j] = y->v(j);	}
+		if(mx && my)
+#pragma omp parallel for collapse(2)
+			for(long i=0;i<n;i++)	for(long j=0;j<m;j++)
+			{	xx.a[i+n*j] = mx->a[i];	yy.a[i+n*j] = my->a[j];	}
+		else
+#pragma omp parallel for collapse(2)
+			for(long i=0;i<n;i++)	for(long j=0;j<m;j++)
+			{	xx.a[i+n*j] = x->v(i);	yy.a[i+n*j] = y->v(j);	}
 		x = &xx;	y = &yy;
 	}
 	// x, y -- have the same size z
-	mreal v0;
 	int wire = mglchr(sch,'#')?1:0;
 	if(mglchr(sch,'.'))	wire = 2;
-	for(j=0;j<z->GetNz();j++)	for(i=0;i<v->GetNx();i++)
+#pragma omp parallel for collapse(2)
+	for(long j=0;j<z->GetNz();j++)	for(long i=0;i<v->GetNx();i++)
 	{
-		if(gr->Stop)	return;
-		v0 = v->v(i);
+		if(gr->Stop)	continue;
+		register mreal v0 = v->v(i);
 		mgl_axial_gen(gr,v0,z,x,y,gr->GetC(s,v0),dir,j,wire);
 	}
 	gr->EndGroup();
diff --git a/src/crust.cpp b/src/crust.cpp
index aa8c417..527a777 100644
--- a/src/crust.cpp
+++ b/src/crust.cpp
@@ -20,6 +20,8 @@
 #include <float.h>
 #include "mgl2/other.h"
 #include "mgl2/data.h"
+#include "mgl2/thread.h"
+#include "mgl2/base.h"
 //-----------------------------------------------------------------------------
 //
 //	TriPlot series
@@ -33,24 +35,24 @@ void MGL_EXPORT mgl_triplot_xyzc(HMGL gr, HCDT nums, HCDT x, HCDT y, HCDT z, HCD
 	long ss=gr->AddTexture(sch);
 	gr->SaveState(opt);	gr->SetPenPal("-");
 	static int cgid=1;	gr->StartGroup("TriPlot",cgid++);
-	mglPoint p1,p2,p3,q=mglPoint(NAN,NAN);
+	mglPoint p1,p2,p3,q;
 
-	register long i,k1,k2,k3;
 	bool wire = mglchr(sch,'#');
 	long nc = a->GetNx();
 	if(nc!=n && nc>=m)	// colors per triangle
 	{
 		gr->Reserve(m*3);
-		for(i=0;i<m;i++)
+#pragma omp parallel for private(p1,p2,p3,q)
+		for(long i=0;i<m;i++)
 		{
-			if(gr->Stop)	return;
-			k1 = long(nums->v(0,i)+0.5);
+			if(gr->Stop)	continue;
+			register long k1 = long(nums->v(0,i)+0.5);
 			p1 = mglPoint(x->v(k1), y->v(k1), z->v(k1));
-			k2 = long(nums->v(1,i)+0.5);
+			register long k2 = long(nums->v(1,i)+0.5);
 			p2 = mglPoint(x->v(k2), y->v(k2), z->v(k2));
-			k3 = long(nums->v(2,i)+0.5);
+			register long k3 = long(nums->v(2,i)+0.5);
 			p3 = mglPoint(x->v(k3), y->v(k3), z->v(k3));
-			if(!wire)	q = (p2-p1) ^ (p3-p1);
+			q = wire ? mglPoint(NAN,NAN) : (p2-p1) ^ (p3-p1);
 			k1 = gr->AddPnt(p1,gr->GetC(ss,a->v(k1)),q);
 			k2 = gr->AddPnt(p2,gr->GetC(ss,a->v(k2)),q);
 			k3 = gr->AddPnt(p3,gr->GetC(ss,a->v(k3)),q);
@@ -62,34 +64,38 @@ void MGL_EXPORT mgl_triplot_xyzc(HMGL gr, HCDT nums, HCDT x, HCDT y, HCDT z, HCD
 		gr->Reserve(n);
 		long *kk = new long[n];
 		mglPoint *pp = new mglPoint[n];
-		for(i=0;i<m;i++)	// add averaged normales
+#pragma omp parallel for
+		for(long i=0;i<m;i++)	// add averaged normales
 		{
-			if(gr->Stop)	{	delete []kk;	delete []pp;	return;	}
-			k1 = long(nums->v(0,i)+0.5);
-			k2 = long(nums->v(1,i)+0.5);
-			k3 = long(nums->v(2,i)+0.5);
+			if(gr->Stop)	continue;
+			register long k1 = long(nums->v(0,i)+0.5);
+			register long k2 = long(nums->v(1,i)+0.5);
+			register long k3 = long(nums->v(2,i)+0.5);
 			if(!wire)
 			{
-				q = mglPoint(x->v(k2)-x->v(k1), y->v(k2)-y->v(k1), z->v(k2)-z->v(k1)) ^
+				mglPoint q = mglPoint(x->v(k2)-x->v(k1), y->v(k2)-y->v(k1), z->v(k2)-z->v(k1)) ^
 					mglPoint(x->v(k3)-x->v(k1), y->v(k3)-y->v(k1), z->v(k3)-z->v(k1));
 				q.Normalize();
-				// try be sure that in the same direction ... 
+				// try be sure that in the same direction ...
 				if(q.z<0)	q *= -1;
-				pp[k1] += q;	pp[k2] += q;	pp[k3] += q;
+#pragma omp critical(quadplot)
+				{pp[k1] += q;	pp[k2] += q;	pp[k3] += q;}
 			}
+			else	pp[k1]=pp[k2]=pp[k3]=mglPoint(NAN,NAN);
 		}
-		for(i=0;i<n;i++)	// add points
+#pragma omp parallel for
+		for(long i=0;i<n;i++)	// add points
 		{
-			if(gr->Stop)	{	delete []kk;	delete []pp;	return;	}
-			q = mglPoint(x->v(i), y->v(i), z->v(i));
-			kk[i] = gr->AddPnt(q,gr->GetC(ss,a->v(i)),pp[i]);
+			if(gr->Stop)	continue;
+			kk[i] = gr->AddPnt(mglPoint(x->v(i), y->v(i), z->v(i)), gr->GetC(ss,a->v(i)), pp[i]);
 		}
-		for(i=0;i<m;i++)	// draw triangles
+#pragma omp parallel for
+		for(long i=0;i<m;i++)	// draw triangles
 		{
-			if(gr->Stop)	{	delete []kk;	delete []pp;	return;	}
-			k1 = long(nums->v(0,i)+0.5);
-			k2 = long(nums->v(1,i)+0.5);
-			k3 = long(nums->v(2,i)+0.5);
+			if(gr->Stop)	continue;
+			register long k1 = long(nums->v(0,i)+0.5);
+			register long k2 = long(nums->v(1,i)+0.5);
+			register long k3 = long(nums->v(2,i)+0.5);
 			if(wire)
 			{
 				gr->line_plot(kk[k1],kk[k2]);	gr->line_plot(kk[k1],kk[k3]);
@@ -143,26 +149,26 @@ void MGL_EXPORT mgl_quadplot_xyzc(HMGL gr, HCDT nums, HCDT x, HCDT y, HCDT z, HC
 	long ss=gr->AddTexture(sch);
 	gr->SaveState(opt);	gr->SetPenPal("-");
 	static int cgid=1;	gr->StartGroup("QuadPlot",cgid++);
-	mglPoint p1,p2,p3,p4,q=mglPoint(NAN,NAN);
+	mglPoint p1,p2,p3,p4;
 
-	register long i,k1,k2,k3,k4;
 	long nc = a->GetNx();
 	bool wire = mglchr(sch,'#');
 	if(nc!=n && nc>=m)	// colors per triangle
 	{
 		gr->Reserve(m*4);
-		for(i=0;i<m;i++)
+#pragma omp parallel for private(p1,p2,p3,p4)
+		for(long i=0;i<m;i++)
 		{
-			if(gr->Stop)	return;
-			k1 = long(nums->v(0,i)+0.5);
+			if(gr->Stop)	continue;
+			register long k1 = long(nums->v(0,i)+0.5);
 			p1 = mglPoint(x->v(k1), y->v(k1), z->v(k1));
-			k2 = long(nums->v(1,i)+0.5);
+			register long k2 = long(nums->v(1,i)+0.5);
 			p2 = mglPoint(x->v(k2), y->v(k2), z->v(k2));
-			k3 = long(nums->v(2,i)+0.5);
+			register long k3 = long(nums->v(2,i)+0.5);
 			p3 = mglPoint(x->v(k3), y->v(k3), z->v(k3));
-			k4 = floor(nums->v(3,i)+0.5);
+			register long k4 = floor(nums->v(3,i)+0.5);
 			p4 = mglPoint(x->v(k4), y->v(k4), z->v(k4));
-			if(!wire)	q = (p2-p1) ^ (p3-p1);
+			mglPoint q = wire ? mglPoint(NAN,NAN):(p2-p1) ^ (p3-p1);
 			k1 = gr->AddPnt(p1,gr->GetC(ss,a->v(k1)),q);
 			k2 = gr->AddPnt(p2,gr->GetC(ss,a->v(k2)),q);
 			k3 = gr->AddPnt(p3,gr->GetC(ss,a->v(k3)),q);
@@ -175,39 +181,44 @@ void MGL_EXPORT mgl_quadplot_xyzc(HMGL gr, HCDT nums, HCDT x, HCDT y, HCDT z, HC
 		gr->Reserve(n);
 		long *kk = new long[n];
 		mglPoint *pp = new mglPoint[n];
-		for(i=0;i<m;i++)	// add averaged normales
+#pragma omp parallel for private(p1,p2,p3,p4)
+		for(long i=0;i<m;i++)	// add averaged normales
 		{
-			if(gr->Stop)	{	delete []kk;	delete []pp;	return;	}
-			k1 = long(nums->v(0,i)+0.5);
+			if(gr->Stop)	continue;
+			register long k1 = long(nums->v(0,i)+0.5);
 			p1 = mglPoint(x->v(k1), y->v(k1), z->v(k1));
-			k2 = long(nums->v(1,i)+0.5);
+			register long k2 = long(nums->v(1,i)+0.5);
 			p2 = mglPoint(x->v(k2), y->v(k2), z->v(k2));
-			k3 = long(nums->v(2,i)+0.5);
+			register long k3 = long(nums->v(2,i)+0.5);
 			p3 = mglPoint(x->v(k3), y->v(k3), z->v(k3));
-			k4 = floor(nums->v(3,i)+0.5);
+			register long k4 = floor(nums->v(3,i)+0.5);
 			p4 = mglPoint(x->v(k4), y->v(k4), z->v(k4));
 
 			if(wire)	pp[k1]=pp[k2]=pp[k3]=pp[k4]=mglPoint(NAN,NAN);
 			else
 			{
-				q = (p2-p1) ^ (p3-p1);	if(q.z<0) q*=-1;	pp[k1] += q;
-				q = (p2-p4) ^ (p3-p4);	if(q.z<0) q*=-1;	pp[k2] += q;
-				q = (p1-p2) ^ (p4-p2);	if(q.z<0) q*=-1;	pp[k3] += q;
-				q = (p1-p4) ^ (p4-p3);	if(q.z<0) q*=-1;	pp[k4] += q;
+				mglPoint q1 = (p2-p1) ^ (p3-p1);	if(q1.z<0) q1*=-1;
+				mglPoint q2 = (p2-p4) ^ (p3-p4);	if(q2.z<0) q2*=-1;
+				mglPoint q3 = (p1-p2) ^ (p4-p2);	if(q3.z<0) q3*=-1;
+				mglPoint q4 = (p1-p4) ^ (p4-p3);	if(q4.z<0) q4*=-1;
+#pragma omp critical(quadplot)
+				{pp[k1] += q1;	pp[k2] += q2;	pp[k3] += q3;	pp[k4] += q4;}
 			}
 		}
-		for(i=0;i<n;i++)	// add points
+#pragma omp parallel for
+		for(long i=0;i<n;i++)	// add points
 		{
-			if(gr->Stop)	{	delete []kk;	delete []pp;	return;	}
+			if(gr->Stop)	continue;
 			kk[i] = gr->AddPnt(mglPoint(x->v(i), y->v(i), z->v(i)),gr->GetC(ss,a->v(i)), pp[i]);
 		}
-		for(i=0;i<m;i++)	// draw quads
+#pragma omp parallel for
+		for(long i=0;i<m;i++)	// draw quads
 		{
-			if(gr->Stop)	{	delete []kk;	delete []pp;	return;	}
-			k1 = floor(nums->v(0,i)+0.5);
-			k2 = floor(nums->v(1,i)+0.5);
-			k3 = floor(nums->v(2,i)+0.5);
-			k4 = floor(nums->v(3,i)+0.5);
+			if(gr->Stop)	continue;
+			register long k1 = floor(nums->v(0,i)+0.5);
+			register long k2 = floor(nums->v(1,i)+0.5);
+			register long k3 = floor(nums->v(2,i)+0.5);
+			register long k4 = floor(nums->v(3,i)+0.5);
 			if(wire)
 			{
 				gr->line_plot(kk[k1],kk[k2]);	gr->line_plot(kk[k1],kk[k3]);
@@ -260,21 +271,17 @@ void MGL_EXPORT mgl_tricont_xyzcv(HMGL gr, HCDT v, HCDT nums, HCDT x, HCDT y, HC
 	long ss=gr->AddTexture(sch);
 	gr->SaveState(opt);
 	static int cgid=1;	gr->StartGroup("TriCont",cgid++);
-	mreal val, c;
-	register long i,k;
-	long k1,k2,k3;
 	bool zVal = !(mglchr(sch,'_'));
-	mreal d1,d2,d3;
 	mglPoint p1,p2,p3;
-	for(k=0;k<v->GetNx();k++)	for(i=0;i<m;i++)
+#pragma omp parallel for private(p1,p2,p3) collapse(2)
+	for(long k=0;k<v->GetNx();k++)	for(long i=0;i<m;i++)
 	{
-		if(gr->Stop)	return;
-		k1 = long(nums->v(0,i)+0.1);	if(k1<0 || k1>=n)	continue;
-		k2 = long(nums->v(1,i)+0.1);	if(k2<0 || k2>=n)	continue;
-		k3 = long(nums->v(2,i)+0.1);	if(k3<0 || k3>=n)	continue;
-		val = v->v(k);
-		c = gr->GetC(ss,val);
-		
+		if(gr->Stop)	continue;
+		register long k1 = long(nums->v(0,i)+0.1);	if(k1<0 || k1>=n)	continue;
+		register long k2 = long(nums->v(1,i)+0.1);	if(k2<0 || k2>=n)	continue;
+		register long k3 = long(nums->v(2,i)+0.1);	if(k3<0 || k3>=n)	continue;
+		register mreal val = v->v(k), c = gr->GetC(ss,val), d1,d2,d3;
+
 		d1 = mgl_d(val,a->v(k1),a->v(k2));
 		p1 = mglPoint(x->v(k1)*(1-d1)+x->v(k2)*d1, y->v(k1)*(1-d1)+y->v(k2)*d1,
 					  zVal?z->v(k1)*(1-d1)+z->v(k2)*d1:gr->Min.z);
@@ -346,36 +353,40 @@ void MGL_EXPORT mgl_tricont_xyc_(uintptr_t *gr, uintptr_t *nums, uintptr_t *x, u
 //	Dots series
 //
 //-----------------------------------------------------------------------------
-void MGL_EXPORT mgl_dots_a(HMGL gr, HCDT x, HCDT y, HCDT z, HCDT a, const char *sch, const char *opt)
+void MGL_EXPORT mgl_dots_ca(HMGL gr, HCDT x, HCDT y, HCDT z, HCDT c, HCDT a, const char *sch, const char *opt)
 {
 	long n = x->GetNN(), d, k=1;
 	if(x->GetNz()>1) 	k=3;		else if(x->GetNy()>1)	k=2;
 
-	if(y->GetNN()!=n || z->GetNN()!=n || a->GetNN()!=n)	{	gr->SetWarn(mglWarnDim,"Dots");	return;	}
+	if(y->GetNN()!=n || z->GetNN()!=n || c->GetNN()!=n || (a && a->GetNN()!=n))
+	{	gr->SetWarn(mglWarnDim,"Dots");	return;	}
 	gr->SaveState(opt);
 
 	d = gr->MeshNum>0 ? mgl_ipow(gr->MeshNum+1,k) : n;
 	d = n>d ? n/d:1;
-	
+
 	static int cgid=1;	gr->StartGroup("Dots",cgid++);
 	char mk=gr->SetPenPal(sch);
-	long ss=gr->AddTexture(sch), pp;
+	long ss=gr->AddTexture(sch);
 	if(mk==0)	mk='.';
 	gr->Reserve(n);
-	mglPoint p;
 
+#pragma omp parallel for
 	for(long i=0;i<n;i+=d)
 	{
-		if(gr->Stop)	return;
-		p = mglPoint(x->vthr(i),y->vthr(i),z->vthr(i));
-		pp = gr->AddPnt(p,gr->GetC(ss,a->vthr(i)));
+		if(gr->Stop)	continue;
+		mglPoint p = mglPoint(x->vthr(i),y->vthr(i),z->vthr(i));
+		long pp = gr->AddPnt(p,gr->GetC(ss,c->vthr(i)),mglPoint(NAN),a?gr->GetA(a->vthr(i)):-1);
 		gr->mark_plot(pp, mk);
 	}
 	gr->EndGroup();
 }
 //-----------------------------------------------------------------------------
+void MGL_EXPORT mgl_dots_a(HMGL gr, HCDT x, HCDT y, HCDT z, HCDT a, const char *sch, const char *opt)
+{	mgl_dots_ca(gr, x, y, z, z, a, sch, opt);	}
+//-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_dots(HMGL gr, HCDT x, HCDT y, HCDT z, const char *sch, const char *opt)
-{	mgl_dots_a(gr, x, y, z, z, sch, opt);	}
+{	mgl_dots_ca(gr, x, y, z, z, NULL, sch, opt);	}
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_dots_(uintptr_t *gr, uintptr_t *x, uintptr_t *y, uintptr_t *z, const char *sch, const char *opt,int l,int lo)
 {	char *s=new char[l+1];	memcpy(s,sch,l);	s[l]=0;
@@ -387,6 +398,11 @@ void MGL_EXPORT mgl_dots_a_(uintptr_t *gr, uintptr_t *x, uintptr_t *y, uintptr_t
 	char *o=new char[lo+1];	memcpy(o,opt,lo);	o[lo]=0;
 	mgl_dots_a(_GR_, _DA_(x),_DA_(y),_DA_(z),_DA_(a),s, o);	delete []o;	delete []s;	}
 //-----------------------------------------------------------------------------
+void MGL_EXPORT mgl_dots_ca_(uintptr_t *gr, uintptr_t *x, uintptr_t *y, uintptr_t *z, uintptr_t *c, uintptr_t *a, const char *sch, const char *opt,int l,int lo)
+{	char *s=new char[l+1];	memcpy(s,sch,l);	s[l]=0;
+	char *o=new char[lo+1];	memcpy(o,opt,lo);	o[lo]=0;
+	mgl_dots_ca(_GR_, _DA_(x),_DA_(y),_DA_(z),_DA_(c),_DA_(a),s, o);	delete []o;	delete []s;	}
+//-----------------------------------------------------------------------------
 //
 //	mglTriangulation
 //
@@ -394,19 +410,20 @@ void MGL_EXPORT mgl_dots_a_(uintptr_t *gr, uintptr_t *x, uintptr_t *y, uintptr_t
 long MGL_NO_EXPORT mgl_crust(long n,mglPoint *pp,long **nn,mreal ff);
 HMDT MGL_EXPORT mgl_triangulation_3d(HCDT x, HCDT y, HCDT z)
 {	// TODO: should be used s-hull or q-hull
-	mglData *nums=new mglData;
+	mglData *nums=0;
 	long n = x->GetNx(), m;
 	if(y->GetNx()!=n || z->GetNx()!=n)	return nums;
-	register long i;
 	mglPoint *pp = new mglPoint[n];
 	long *nn=0;
-	for(i=0;i<n;i++)	pp[i] = mglPoint(x->v(i), y->v(i), z->v(i));
+#pragma omp parallel for
+	for(long i=0;i<n;i++)	pp[i] = mglPoint(x->v(i), y->v(i), z->v(i));
 	m = mgl_crust(n,pp,&nn,0);
 
 	if(m>0)
 	{
-		nums->Create(3,m);
-		for(i=0;i<3*m;i++)	nums->a[i]=nn[i];
+		nums=new mglData(3,m);
+#pragma omp parallel for
+		for(long i=0;i<3*m;i++)	nums->a[i]=nn[i];
 	}
 	delete []pp;	free(nn);	return nums;
 }
@@ -414,26 +431,24 @@ HMDT MGL_EXPORT mgl_triangulation_3d(HCDT x, HCDT y, HCDT z)
 #include "s_hull/s_hull_pro.h"
 HMDT MGL_EXPORT mgl_triangulation_2d(HCDT x, HCDT y)
 {
-	mglData *nums=new mglData;
-	register long n = x->GetNx(), m,i;
-	if(y->GetNx()!=n)	return nums;
+	mglData *nums=0;
+	long n = x->GetNN();
+	if(y->GetNN()!=n)	return nums;
 	// use s-hull here
 	std::vector<Shx> pts;
 	std::vector<size_t> out;
 	Shx pt;
 
-	for(i=0;i<n;i++)
-	{
-		pt.r = x->v(i);	pt.c = y->v(i);
-		pt.id = i;	pts.push_back(pt);
-	}
+	for(long i=0;i<n;i++)
+	{	pt.r = x->vthr(i);	pt.c = y->vthr(i);	pt.id = i;	pts.push_back(pt);	}
 	std::vector<Triad> triads;
 	if(de_duplicate(pts, out))
 		mglGlobalMess += "There are duplicated points for triangulation.\n";
 	s_hull_pro(pts, triads);
-	m = triads.size();
-	nums->Create(3,m);
-	for(i=0;i<m;i++)
+	long m = triads.size();
+	nums=new mglData(3,m);
+#pragma omp parallel for
+	for(long i=0;i<m;i++)
 	{
 		nums->a[3*i]   = triads[i].a;
 		nums->a[3*i+1] = triads[i].b;
@@ -455,12 +470,14 @@ MGL_NO_EXPORT void *mgl_grid_t(void *par)
 {
 	mglThreadD *t=(mglThreadD *)par;
 	long nx=t->p[0],ny=t->p[1];
-	register long i0, k1,k2,k3;
 	mreal *b=t->a;
 	const mreal *x=t->b, *y=t->c, *d=t->d, *z=t->e;
-	for(i0=t->id;i0<t->n;i0+=mglNumThr)
-	{
-		k1 = long(d[3*i0]); k2 = long(d[3*i0+1]); k3 = long(d[3*i0+2]);
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i0=t->id;i0<t->n;i0+=mglNumThr)
+	{	// TODO check if rounding needed
+		register long k1 = long(d[3*i0]), k2 = long(d[3*i0+1]), k3 = long(d[3*i0+2]);
 		mreal dxu,dxv,dyu,dyv;
 		mglPoint d1=mglPoint(x[k2]-x[k1],y[k2]-y[k1],z[k2]-z[k1]), d2=mglPoint(x[k3]-x[k1],y[k3]-y[k1],z[k3]-z[k1]), p;
 
@@ -490,30 +507,40 @@ MGL_NO_EXPORT void *mgl_grid_t(void *par)
 	}
 	return 0;
 }
-void MGL_EXPORT mgl_data_grid(HMGL gr, HMDT d, HCDT xdat, HCDT ydat, HCDT zdat, const char *opt)
+//-----------------------------------------------------------------------------
+void MGL_EXPORT mgl_data_grid_xy(HMDT d, HCDT xdat, HCDT ydat, HCDT zdat, mreal x1, mreal x2, mreal y1, mreal y2)
 { // NOTE: only for mglData
 	const mglData *x = dynamic_cast<const mglData *>(xdat);
 	const mglData *y = dynamic_cast<const mglData *>(ydat);
 	const mglData *z = dynamic_cast<const mglData *>(zdat);
 	if(!x || !y || !z) return;
-	long n=x->nx;
-	if((n<3) || (y->nx!=n) || (z->nx!=n))	return;
+	long n=x->GetNN();
+	if((n<3) || (y->GetNN()!=n) || (z->GetNN()!=n))	return;
 
-	gr->SaveState(opt);
 	mglData *nums = mgl_triangulation_2d(x,y);
 	if(nums->nx<3)	{	delete nums;	return;	}
 	long nn = nums->ny, par[3]={d->nx,d->ny,d->nz};
-	mreal xx[4]={gr->Min.x,0, gr->Min.y,0};
-	if(d->nx>1) xx[1] = (d->nx-1.)/(gr->Max.x-gr->Min.x);
-	if(d->ny>1) xx[3] = (d->ny-1.)/(gr->Max.y-gr->Min.y);
+	mreal xx[4]={x1,0, y1,0};
+	if(d->nx>1) xx[1] = (d->nx-1.)/(x2-x1);
+	if(d->ny>1) xx[3] = (d->ny-1.)/(y2-y1);
 
-	register long i;
 	mreal *xc=new mreal[n], *yc=new mreal[n];
-	for(i=0;i<n;i++)	{	xc[i]=xx[1]*(x->a[i]-xx[0]);	yc[i]=xx[3]*(y->a[i]-xx[2]);	}
+#pragma omp parallel for
+	for(long i=0;i<n;i++)	{	xc[i]=xx[1]*(x->a[i]-xx[0]);	yc[i]=xx[3]*(y->a[i]-xx[2]);	}
+#pragma omp parallel for
 	for(long i=0;i<d->nx*d->ny*d->nz;i++) d->a[i] = NAN;
-	
+
 	mglStartThread(mgl_grid_t,0,nn,d->a,xc,yc,par,0,nums->a,z->a);
-	gr->LoadState();	delete nums;	delete []xc;	delete []yc;
+	delete nums;	delete []xc;	delete []yc;
+}
+void MGL_EXPORT mgl_data_grid_xy_(uintptr_t *d, uintptr_t *x, uintptr_t *y, uintptr_t *z, mreal *x1, mreal *x2, mreal *y1, mreal *y2)
+{	mgl_data_grid_xy(_DT_,_DA_(x),_DA_(y),_DA_(z),*x1,*x2,*y1,*y2);	}
+//-----------------------------------------------------------------------------
+void MGL_EXPORT mgl_data_grid(HMGL gr, HMDT d, HCDT xdat, HCDT ydat, HCDT zdat, const char *opt)
+{
+	gr->SaveState(opt);
+	mgl_data_grid_xy(d,xdat,ydat,zdat,gr->Min.x,gr->Max.x,gr->Min.y,gr->Max.y);
+	gr->LoadState();
 }
 void MGL_EXPORT mgl_data_grid_(uintptr_t *gr, uintptr_t *d, uintptr_t *x, uintptr_t *y, uintptr_t *z, const char *opt,int lo)
 {	char *o=new char[lo+1];	memcpy(o,opt,lo);	o[lo]=0;
diff --git a/src/data.cpp b/src/data.cpp
index 6269f93..98f383d 100644
--- a/src/data.cpp
+++ b/src/data.cpp
@@ -20,12 +20,10 @@
 #include <time.h>
 #include "mgl2/data.h"
 #include "mgl2/eval.h"
+#include "mgl2/thread.h"
+#include "interp.hpp"
 
 MGL_EXPORT int mglNumThr=0;
-void mglFillP(long x,long y, const mreal *a,long nx,long ny,mreal _p[4][4]);
-void mglFillP(long x, const mreal *a,long nx,mreal _p[4]);
-void mglFillP5(long x,long y, const mreal *a,long nx,long ny,mreal _p[6][6]);
-void mglFillP5(long x, const mreal *a,long nx,mreal _p[6]);
 //-----------------------------------------------------------------------------
 #if MGL_HAVE_PTHREAD
 #ifdef WIN32
@@ -116,6 +114,12 @@ void MGL_EXPORT mglStartThreadV(void *(*func)(void *), long n, mreal *a, const v
 	}
 }
 //-----------------------------------------------------------------------------
+mreal mglSpline3(const mreal *a, long nx, long ny, long nz, mreal x, mreal y, mreal z,mreal *dx, mreal *dy, mreal *dz)
+{	return mglSpline3t<mreal>(a,nx,ny,nz,x,y,z,dx,dy,dz);	}
+//-----------------------------------------------------------------------------
+mreal mglLinear(const mreal *a, long nx, long ny, long nz, mreal x, mreal y, mreal z)
+{	return mglLineart<mreal>(a,nx,ny,nz,x,y,z);	}
+//-----------------------------------------------------------------------------
 double mgl_ipow(double x,int n)
 {
 	double t;
@@ -147,79 +151,139 @@ double mgl_get_time_(const char *time, const char *fmt,int l,int m)
 MGL_NO_EXPORT void *mgl_smth_x(void *par)
 {
 	mglThreadD *t=(mglThreadD *)par;
-	register long i,j,d3,d5, nx=t->p[0];
-	mreal *b=t->a, delta=t->c[0], y5,y3,x2y;
+	long nx=t->p[0], kind=t->p[2];
+	mreal *b=t->a, delta=t->c[0];
 	const mreal *a=t->b;
-	for(i=t->id;i<t->n;i+=mglNumThr)
-	{
-		j = i%nx;
-		d3 = d5 = 0;
-		if(j==0)	{	d3 = 1;		d5 = 2;	}
-		if(j==1)	{	d5 = 1;	}
-		if(j==nx-1)	{	d3 = -1;	d5 = -2;}
-		if(j==nx-2)	{	d5 = -1;}
-		y3 = (a[i+d3-1] + a[i+d3] + a[i+d3+1]);
-		y5 = (a[i+d5-2] + a[i+d5-1] + a[i+d5] + a[i+d5+1] + a[i+d5+2]);
-		x2y= (a[i+d5+1] + 4*a[i+d5+2] + 4*a[i+d5-2] + a[i+d5-1]);
-		j = t->p[2];
-		if(d3)	b[i] = a[i];
-		else if(j==SMOOTH_LINE_3 || d5)	b[i] = y3/3.;
-		else if(j==SMOOTH_LINE_5)		b[i] = y5/5.;
-		else if(j==SMOOTH_QUAD_5)		b[i] = (17*y5-5*x2y)/35.;
-		if(delta>0)		b[i] = mgl_max(a[i]-delta,mgl_min(a[i]+delta,b[i]));
-	}
+	if(kind==SMOOTH_LINE_3)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+		for(long i=t->id;i<t->n;i+=mglNumThr)
+		{
+			register long j = i%nx;
+			if(j>0 && j<nx-1)	b[i] = (a[i-1] + a[i] + a[i+1])/3.;
+			else	b[i] = a[i];
+		}
+	else if(kind==SMOOTH_LINE_5)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+		for(long i=t->id;i<t->n;i+=mglNumThr)
+		{
+			register long j = i%nx;
+			if(j>1 && j<nx-2)	b[i] = (a[i-2] + a[i-1] + a[i] + a[i+1] + a[i+2])/5.;
+			else if(j==1 || j==nx-2)	b[i] = (a[i-1] + a[i] + a[i+1])/3.;
+			else	b[i] = a[i];
+		}
+	else if(kind==SMOOTH_QUAD_5)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+		for(long i=t->id;i<t->n;i+=mglNumThr)
+		{
+			register long j = i%nx;
+			if(j>1 && j<nx-2)	b[i] = (12*a[i-2] - 3*a[i-1] + 17*a[i] - 3*a[i+1] + 12*a[i+2])/35.;
+			else if(j==1 || j==nx-2)	b[i] = (a[i-1] + a[i] + a[i+1])/3.;
+			else	b[i] = a[i];
+		}
+	if(delta>0)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+		for(long i=t->id;i<t->n;i+=mglNumThr)
+			b[i] = mgl_max(a[i]-delta,mgl_min(a[i]+delta,b[i]));
 	return 0;
 }
 MGL_NO_EXPORT void *mgl_smth_y(void *par)
 {
 	mglThreadD *t=(mglThreadD *)par;
-	register long i,j,d3,d5, nx=t->p[0],ny=t->p[1];
-	mreal *b=t->a, delta=t->c[0], y5,y3,x2y;
+	long nx=t->p[0],ny=t->p[1], kind=t->p[2];
+	mreal *b=t->a, delta=t->c[0];
 	const mreal *a=t->b;
-	for(i=t->id;i<t->n;i+=mglNumThr)
-	{
-		j = (i/nx)%ny;
-		d3 = d5 = 0;
-		if(j==0)	{	d3 = 1;		d5 = 2;	}
-		if(j==1)	{	d5 = 1;	}
-		if(j==ny-1)	{	d3 = -1;	d5 = -2;}
-		if(j==ny-2)	{	d5 = -1;}
-		y3 = (a[i+nx*(d3-1)] + a[i+nx*d3] + a[i+nx*(d3+1)]);
-		y5 = (a[i+nx*(d5-2)] + a[i+nx*(d5-1)] + a[i+nx*d5] + a[i+nx*(d5+1)] + a[i+nx*(d5+2)]);
-		x2y= (a[i+nx*(d5+1)] + 4*a[i+nx*(d5+2)] + 4*a[i+nx*(d5-2)] + a[i+nx*(d5-1)]);
-		j = t->p[2];
-		if(d3)	b[i] = a[i];
-		else if(j==SMOOTH_LINE_3 || d5)	b[i] = y3/3.;
-		else if(j==SMOOTH_LINE_5)		b[i] = y5/5.;
-		else if(j==SMOOTH_QUAD_5)		b[i] = (17*y5-5*x2y)/35.;
-		if(delta>0)		b[i] = mgl_max(a[i]-delta,mgl_min(a[i]+delta,b[i]));
-	}
+	if(kind==SMOOTH_LINE_3)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+		for(long i=t->id;i<t->n;i+=mglNumThr)
+		{
+			register long j = (i/nx)%ny;
+			if(j>0 && j<ny-1)	b[i] = (a[i-nx] + a[i] + a[i+nx])/3.;
+			else	b[i] = a[i];
+		}
+	else if(kind==SMOOTH_LINE_5)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+		for(long i=t->id;i<t->n;i+=mglNumThr)
+		{
+			register long j = (i/nx)%ny;
+			if(j>1 && j<ny-2)	b[i] = (a[i-2*nx] + a[i-nx] + a[i] + a[i+nx] + a[i+2*nx])/5.;
+			else if(j==1 || j==ny-2)	b[i] = (a[i-nx] + a[i] + a[i+nx])/3.;
+			else	b[i] = a[i];
+		}
+	else if(kind==SMOOTH_QUAD_5)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+		for(long i=t->id;i<t->n;i+=mglNumThr)
+		{
+			register long j = (i/nx)%ny;
+			if(j>1 && j<ny-2)	b[i] = (12*a[i-2*nx] - 3*a[i-nx] + 17*a[i] - 3*a[i+nx] + 12*a[i+2*nx])/35.;
+			else if(j==1 || j==ny-2)	b[i] = (a[i-nx] + a[i] + a[i+nx])/3.;
+			else	b[i] = a[i];
+		}
+	if(delta>0)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+		for(long i=t->id;i<t->n;i+=mglNumThr)
+			b[i] = mgl_max(a[i]-delta,mgl_min(a[i]+delta,b[i]));
 	return 0;
 }
 MGL_NO_EXPORT void *mgl_smth_z(void *par)
 {
 	mglThreadD *t=(mglThreadD *)par;
-	register long i,j,d3,d5, nn=t->p[0]*t->p[1], nz=t->n/nn;
-	mreal *b=t->a, delta=t->c[0], y5,y3,x2y;
+	register long nn=t->p[0]*t->p[1], nz=t->n/nn, kind=t->p[2];
+	mreal *b=t->a, delta=t->c[0];
 	const mreal *a=t->b;
-	for(i=t->id;i<t->n;i+=mglNumThr)
-	{
-		j = i/nn;
-		d3 = d5 = 0;
-		if(j==0)	{	d3 = 1;		d5 = 2;	}
-		if(j==1)	{	d5 = 1;	}
-		if(j==nz-1)	{	d3 = -1;	d5 = -2;}
-		if(j==nz-2)	{	d5 = -1;}
-		y3 = (a[i+nn*(d3-1)] + a[i+nn*d3] + a[i+nn*(d3+1)]);
-		y5 = (a[i+nn*(d5-2)] + a[i+nn*(d5-1)] + a[i+nn*d5] + a[i+nn*(d5+1)] + a[i+nn*(d5+2)]);
-		x2y= (a[i+nn*(d5+1)] + 4*a[i+nn*(d5+2)] + 4*a[i+nn*(d5-2)] + a[i+nn*(d5-1)]);
-		j = t->p[2];
-		if(d3)	b[i] = a[i];
-		else if(j==SMOOTH_LINE_3 || d5)	b[i] = y3/3.;
-		else if(j==SMOOTH_LINE_5)		b[i] = y5/5.;
-		else if(j==SMOOTH_QUAD_5)		b[i] = (17*y5-5*x2y)/35.;
-		if(delta>0)		b[i] = mgl_max(a[i]-delta,mgl_min(a[i]+delta,b[i]));
-	}
+	if(kind==SMOOTH_LINE_3)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+		for(long i=t->id;i<t->n;i+=mglNumThr)
+		{
+			register long j = i/nn;
+			if(j>0 && j<nz-1)	b[i] = (a[i-nn] + a[i] + a[i+nn])/3.;
+			else	b[i] = a[i];
+		}
+	else if(kind==SMOOTH_LINE_5)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+		for(long i=t->id;i<t->n;i+=mglNumThr)
+		{
+			register long j = i/nn;
+			if(j>1 && j<nz-2)	b[i] = (a[i-2*nn] + a[i-nn] + a[i] + a[i+nn] + a[i+2*nn])/5.;
+			else if(j==1 || j==nz-2)	b[i] = (a[i-nn] + a[i] + a[i+nn])/3.;
+			else	b[i] = a[i];
+		}
+	else if(kind==SMOOTH_QUAD_5)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+		for(long i=t->id;i<t->n;i+=mglNumThr)
+		{
+			register long j = i/nn;
+			if(j>1 && j<nz-2)	b[i] = (12*a[i-2*nn] - 3*a[i-nn] + 17*a[i] - 3*a[i+nn] + 12*a[i+2*nn])/35.;
+			else if(j==1 || j==nz-2)	b[i] = (a[i-nn] + a[i] + a[i+nn])/3.;
+			else	b[i] = a[i];
+		}
+	if(delta>0)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+		for(long i=t->id;i<t->n;i+=mglNumThr)
+			b[i] = mgl_max(a[i]-delta,mgl_min(a[i]+delta,b[i]));
 	return 0;
 }
 void MGL_EXPORT mgl_data_smooth(HMDT d, const char *dirs, mreal delta)
@@ -261,39 +325,48 @@ void MGL_EXPORT mgl_data_smooth_(uintptr_t *d, const char *dir, mreal *delta,int
 MGL_NO_EXPORT void *mgl_csum_z(void *par)
 {
 	mglThreadD *t=(mglThreadD *)par;
-	register long i,j, nz=t->p[2], nn=t->n;
+	long nz=t->p[2], nn=t->n;
 	mreal *b=t->a;
 	const mreal *a=t->b;
-	for(i=t->id;i<nn;i+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i=t->id;i<nn;i+=mglNumThr)
 	{
 		b[i] = a[i];
-		for(j=1;j<nz;j++)	b[i+j*nn] = b[i+j*nn-nn] + a[i+j*nn];
+		for(long j=1;j<nz;j++)	b[i+j*nn] = b[i+j*nn-nn] + a[i+j*nn];
 	}
 	return 0;
 }
 MGL_NO_EXPORT void *mgl_csum_y(void *par)
 {
 	mglThreadD *t=(mglThreadD *)par;
-	register long i,j,k, nx=t->p[0], ny=t->p[1], nn=t->n;
+	long nx=t->p[0], ny=t->p[1], nn=t->n;
 	mreal *b=t->a;
 	const mreal *a=t->b;
-	for(i=t->id;i<nn;i+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i=t->id;i<nn;i+=mglNumThr)
 	{
-		k = (i%nx)+nx*ny*(i/nx);		b[k] = a[k];
-		for(j=1;j<ny;j++)	b[k+j*nx] = b[k+j*nx-nx] + a[k+nx*j];
+		register long k = (i%nx)+nx*ny*(i/nx);		b[k] = a[k];
+		for(long j=1;j<ny;j++)	b[k+j*nx] = b[k+j*nx-nx] + a[k+nx*j];
 	}
 	return 0;
 }
 MGL_NO_EXPORT void *mgl_csum_x(void *par)
 {
 	mglThreadD *t=(mglThreadD *)par;
-	register long i,j,k, nx=t->p[0], nn=t->n;
+	long nx=t->p[0], nn=t->n;
 	mreal *b=t->a;
 	const mreal *a=t->b;
-	for(i=t->id;i<nn;i+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i=t->id;i<nn;i+=mglNumThr)
 	{
-		k = i*nx;			b[k] = a[k];
-		for(j=1;j<nx;j++)	b[j+k] = b[j+k-1] + a[j+k];
+		register long k = i*nx;			b[k] = a[k];
+		for(long j=1;j<nx;j++)	b[j+k] = b[j+k-1] + a[j+k];
 	}
 	return 0;
 }
@@ -328,39 +401,48 @@ void MGL_EXPORT mgl_data_cumsum_(uintptr_t *d, const char *dir,int l)
 MGL_NO_EXPORT void *mgl_int_z(void *par)
 {
 	mglThreadD *t=(mglThreadD *)par;
-	register long i,j, nz=t->p[2], nn=t->n;
+	long nz=t->p[2], nn=t->n;
 	mreal *b=t->a, dd=0.5/nz;
 	const mreal *a=t->b;
-	for(i=t->id;i<nn;i+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i=t->id;i<nn;i+=mglNumThr)
 	{
 		b[i] = 0;
-		for(j=1;j<nz;j++)	b[i+j*nn] = b[i+j*nn-nn] + (a[i+nn*j]+a[i+j*nn-nn])*dd;
+		for(long j=1;j<nz;j++)	b[i+j*nn] = b[i+j*nn-nn] + (a[i+nn*j]+a[i+j*nn-nn])*dd;
 	}
 	return 0;
 }
 MGL_NO_EXPORT void *mgl_int_y(void *par)
 {
 	mglThreadD *t=(mglThreadD *)par;
-	register long i,j,k, nx=t->p[0], ny=t->p[1], nn=t->n;
+	long nx=t->p[0], ny=t->p[1], nn=t->n;
 	mreal *b=t->a, dd=0.5/ny;
 	const mreal *a=t->b;
-	for(i=t->id;i<nn;i+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i=t->id;i<nn;i+=mglNumThr)
 	{
-		k = (i%nx)+nx*ny*(i/nx);	b[k] = 0;
-		for(j=1;j<ny;j++)	b[k+j*nx] = b[k+j*nx-nx] + (a[k+j*nx]+a[k+j*nx-nx])*dd;
+		register long k = (i%nx)+nx*ny*(i/nx);	b[k] = 0;
+		for(long j=1;j<ny;j++)	b[k+j*nx] = b[k+j*nx-nx] + (a[k+j*nx]+a[k+j*nx-nx])*dd;
 	}
 	return 0;
 }
 MGL_NO_EXPORT void *mgl_int_x(void *par)
 {
 	mglThreadD *t=(mglThreadD *)par;
-	register long i,j,k, nx=t->p[0], nn=t->n;
+	long nx=t->p[0], nn=t->n;
 	mreal *b=t->a, dd=0.5/nx;
 	const mreal *a=t->b;
-	for(i=t->id;i<nn;i+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i=t->id;i<nn;i+=mglNumThr)
 	{
-		k = i*nx;			b[k] = 0;
-		for(j=1;j<nx;j++)	b[j+k] = b[j+k-1] + (a[j+k]+a[j+k-1])*dd;
+		register long k = i*nx;			b[k] = 0;
+		for(long j=1;j<nx;j++)	b[j+k] = b[j+k-1] + (a[j+k]+a[j+k-1])*dd;
 	}
 	return 0;
 }
@@ -395,44 +477,53 @@ void MGL_EXPORT mgl_data_integral_(uintptr_t *d, const char *dir,int l)
 MGL_NO_EXPORT void *mgl_dif_z(void *par)
 {
 	mglThreadD *t=(mglThreadD *)par;
-	register long i,j, nz=t->p[2], nn=t->n;
+	long nz=t->p[2], nn=t->n;
 	mreal *b=t->a, dd=0.5*nz;
 	const mreal *a=t->b;
-	for(i=t->id;i<nn;i+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i=t->id;i<nn;i+=mglNumThr)
 	{
 		b[i] = -(3*a[i]-4*a[i+nn]+a[i+2*nn])*dd;
 		b[i+(nz-1)*nn] = (3*a[i+(nz-1)*nn]-4*a[i+(nz-2)*nn]+a[i+(nz-3)*nn])*dd;
-		for(j=1;j<nz-1;j++)		b[i+j*nn] = (a[i+j*nn+nn]-a[i+j*nn-nn])*dd;
+		for(long j=1;j<nz-1;j++)		b[i+j*nn] = (a[i+j*nn+nn]-a[i+j*nn-nn])*dd;
 	}
 	return 0;
 }
 MGL_NO_EXPORT void *mgl_dif_y(void *par)
 {
 	mglThreadD *t=(mglThreadD *)par;
-	register long i,j,k, nx=t->p[0], ny=t->p[1], nn=t->n;
+	long nx=t->p[0], ny=t->p[1], nn=t->n;
 	mreal *b=t->a, dd=0.5*ny;
 	const mreal *a=t->b;
-	for(i=t->id;i<nn;i+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i=t->id;i<nn;i+=mglNumThr)
 	{
-		k = (i%nx)+nx*ny*(i/nx);
+		register long k = (i%nx)+nx*ny*(i/nx);
 		b[k] = -(3*a[k]-4*a[k+nx]+a[k+2*nx])*dd;
 		b[k+(ny-1)*nx] = (3*a[k+(ny-1)*nx]-4*a[k+(ny-2)*nx]+a[k+(ny-3)*nx])*dd;
-		for(j=1;j<ny-1;j++)	b[k+j*nx] = (a[k+j*nx+nx]-a[k+j*nx-nx])*dd;
+		for(long j=1;j<ny-1;j++)	b[k+j*nx] = (a[k+j*nx+nx]-a[k+j*nx-nx])*dd;
 	}
 	return 0;
 }
 MGL_NO_EXPORT void *mgl_dif_x(void *par)
 {
 	mglThreadD *t=(mglThreadD *)par;
-	register long i,j,k, nx=t->p[0], nn=t->n;
+	long nx=t->p[0], nn=t->n;
 	mreal *b=t->a, dd=0.5*nx;
 	const mreal *a=t->b;
-	for(i=t->id;i<nn;i+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i=t->id;i<nn;i+=mglNumThr)
 	{
-		k = i*nx;
+		register long k = i*nx;
 		b[k] = -(3*a[k]-4*a[k+1]+a[k+2])*dd;
 		b[k+nx-1] = (3*a[k+nx-1]-4*a[k+nx-2]+a[k+nx-3])*dd;
-		for(j=1;j<nx-1;j++)	b[j+k] = (a[j+k+1]-a[j+k-1])*dd;
+		for(long j=1;j<nx-1;j++)	b[j+k] = (a[j+k+1]-a[j+k-1])*dd;
 	}
 	return 0;
 }
@@ -466,39 +557,48 @@ void MGL_EXPORT mgl_data_diff_(uintptr_t *d, const char *dir,int l)
 MGL_NO_EXPORT void *mgl_dif2_z(void *par)
 {
 	mglThreadD *t=(mglThreadD *)par;
-	register long i,j, nz=t->p[2], nn=t->n;
+	long nz=t->p[2], nn=t->n;
 	mreal *b=t->a, dd=0.5*nz*nz;
 	const mreal *a=t->b;
-	for(i=t->id;i<nn;i+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i=t->id;i<nn;i+=mglNumThr)
 	{
 		b[i] = b[i+(nz-1)*nn] = 0;
-		for(j=1;j<nz-1;j++)		b[i+j*nn] = (a[i+j*nn+nn]+a[i+j*nn-nn]-2*a[i+j*nn])*dd;
+		for(long j=1;j<nz-1;j++)		b[i+j*nn] = (a[i+j*nn+nn]+a[i+j*nn-nn]-2*a[i+j*nn])*dd;
 	}
 	return 0;
 }
 MGL_NO_EXPORT void *mgl_dif2_y(void *par)
 {
 	mglThreadD *t=(mglThreadD *)par;
-	register long i,j,k, nx=t->p[0], ny=t->p[1], nn=t->n;
+	long nx=t->p[0], ny=t->p[1], nn=t->n;
 	mreal *b=t->a, dd=0.5*ny*ny;
 	const mreal *a=t->b;
-	for(i=t->id;i<nn;i+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i=t->id;i<nn;i+=mglNumThr)
 	{
-		k = (i%nx)+nx*ny*(i/nx);	b[k] = b[k+(ny-1)*nx] = 0;
-		for(j=1;j<ny-1;j++)	b[k+j*nx] = (a[k+j*nx+nx]+a[k+j*nx-nx]-2*a[k+j*nx])*dd;
+		register long k = (i%nx)+nx*ny*(i/nx);	b[k] = b[k+(ny-1)*nx] = 0;
+		for(long j=1;j<ny-1;j++)	b[k+j*nx] = (a[k+j*nx+nx]+a[k+j*nx-nx]-2*a[k+j*nx])*dd;
 	}
 	return 0;
 }
 MGL_NO_EXPORT void *mgl_dif2_x(void *par)
 {
 	mglThreadD *t=(mglThreadD *)par;
-	register long i,j,k, nx=t->p[0], nn=t->n;
+	long nx=t->p[0], nn=t->n;
 	mreal *b=t->a, dd=0.5*nx*nx;
 	const mreal *a=t->b;
-	for(i=t->id;i<nn;i+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i=t->id;i<nn;i+=mglNumThr)
 	{
-		k = i*nx;			b[k] = b[k+nx-1] = 0;
-		for(j=1;j<nx-1;j++)	b[j+k] = (a[j+k+1]+a[j+k-1]-2*a[j+k])*dd;
+		register long k = i*nx;			b[k] = b[k+nx-1] = 0;
+		for(long j=1;j<nx-1;j++)	b[j+k] = (a[j+k+1]+a[j+k-1]-2*a[j+k])*dd;
 	}
 	return 0;
 }
@@ -542,8 +642,7 @@ void MGL_EXPORT mgl_data_swap_(uintptr_t *d, const char *dir,int l)
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_data_roll(HMDT dd, char dir, long num)
 {
-	long nx=dd->nx,ny=dd->ny,nz=dd->nz;
-	register long i,d;
+	long nx=dd->nx,ny=dd->ny,nz=dd->nz, d;
 	mreal *b,*a=dd->a;
 	if(dir=='z' && nz>1)
 	{
@@ -560,7 +659,8 @@ void MGL_EXPORT mgl_data_roll(HMDT dd, char dir, long num)
 		if(d==0)	return;		// nothing to do
 		b = new mreal[nx*ny*nz];
 		memcpy(b,a+nx*d,(nx*ny*nz-nx*d)*sizeof(mreal));
-		for(i=0;i<nz;i++)
+#pragma omp parallel for
+		for(long i=0;i<nz;i++)
 			memcpy(b+nx*(ny-d)+nx*ny*i,a+nx*ny*i,nx*d*sizeof(mreal));
 		memcpy(a,b,nx*ny*nz*sizeof(mreal));	delete []b;
 	}
@@ -570,7 +670,8 @@ void MGL_EXPORT mgl_data_roll(HMDT dd, char dir, long num)
 		if(d==0)	return;		// nothing to do
 		b = new mreal[nx*ny*nz];
 		memcpy(b,a+d,(nx*ny*nz-d)*sizeof(mreal));
-		for(i=0;i<nz*ny;i++)
+#pragma omp parallel for
+		for(long i=0;i<nz*ny;i++)
 			memcpy(b+nx-d+nx*i,a+nx*i,d*sizeof(mreal));
 		memcpy(a,b,nx*ny*nz*sizeof(mreal));	delete []b;
 	}
@@ -582,35 +683,40 @@ void MGL_EXPORT mgl_data_mirror(HMDT d, const char *dir)
 {
 	if(!dir || *dir==0)	return;
 	long nx=d->nx,ny=d->ny,nz=d->nz;
-	register long i,j,k,i0,j0;
-	mreal b, *a=d->a;
+	mreal *a=d->a;
 	if(strchr(dir,'z') && nz>1)
 	{
-		for(j=0;j<nz/2;j++)	for(i=0;i<nx*ny;i++)
+#pragma omp parallel for collapse(2)
+		for(long j=0;j<nz/2;j++)	for(long i=0;i<nx*ny;i++)
 		{
-			i0 = i+j*nx*ny;	j0 = i+(nz-1-j)*nx*ny;
-			b = a[i0];	a[i0] = a[j0];	a[j0] = b;
+			register long i0 = i+j*nx*ny, j0 = i+(nz-1-j)*nx*ny;
+			register mreal b = a[i0];	a[i0] = a[j0];	a[j0] = b;
 		}
 	}
 	if(strchr(dir,'y') && ny>1)
 	{
-		for(k=0;k<nz;k++)	for(i=0;i<nx;i++)
+#pragma omp parallel for
+		for(long i=0;i<nx*nz;i++)
 		{
-			j0 = i+nx*ny*k;
-			for(j=0;j<ny/2;j++)
+			register long j0 = (i%nx)+nx*ny*(i/nx);
+			for(long j=0;j<ny/2;j++)
 			{
-				i0 = j0+(ny-1-j)*nx;	b = a[j0+j*nx];
-				a[j0+j*nx] = a[i0];	a[i0] = b;
+				register long i0 = j0+(ny-1-j)*nx;
+				register mreal b = a[j0+j*nx];	a[j0+j*nx] = a[i0];	a[i0] = b;
 			}
 		}
 	}
 	if(strchr(dir,'x') && nx>1)
 	{
-		for(j=0;j<ny*nz;j++)
+#pragma omp parallel for
+		for(long j=0;j<ny*nz;j++)
 		{
-			j0 = j*nx;
-			for(i=0;i<nx/2;i++)
-			{	i0 = nx-1-i+j0;	b = a[i+j0];	a[i+j0] = a[i0];	a[i0] = b;	}
+			register long j0 = j*nx;
+			for(long i=0;i<nx/2;i++)
+			{
+				register long i0 = nx-1-i+j0;
+				register mreal b = a[i+j0];	a[i+j0] = a[i0];	a[i0] = b;
+			}
 		}
 	}
 }
@@ -621,18 +727,21 @@ void MGL_EXPORT mgl_data_mirror_(uintptr_t *d, const char *dir,int l)
 void MGL_EXPORT mgl_data_clean(HMDT d, long id)
 {
 	if(id<0 || id+1>d->nx)	return;
-	register long i,j,k,n=d->nx,m=d->ny;
+	register long i,j,n=d->nx,m=d->ny;
 	mreal *b = new mreal[m*n], *a=d->a;
 	for(i=j=0;i+1<m;i++)
 	{
 		if(a[id+n*i]!=a[id+n*i+n])	// this can be saved
 		{
-			for(k=0;k<n;k++)		b[k+n*j]=a[k+n*i];
+#pragma omp parallel for
+			for(long k=0;k<n;k++)	b[k+n*j]=a[k+n*i];
 			j++;
 		}
 	}
 	// always save last row
-	for(k=0, i=n*(m-1);k<n;k++)		b[k+n*j]=a[k+i];
+	i=n*(m-1);
+#pragma omp parallel for
+	for(long k=0;k<n;k++)	b[k+n*j]=a[k+i];
 	j++;
 	memcpy(a,b,n*j*sizeof(mreal));	d->ny = j;
 	delete []b;
@@ -642,29 +751,31 @@ void MGL_EXPORT mgl_data_clean_(uintptr_t *d, int *id)	{	mgl_data_clean(_DT_,*id
 MGL_NO_EXPORT void *mgl_solve_x(void *par)
 {
 	mglThreadD *t=(mglThreadD *)par;
-	register long l,i,i0,j,k, nx=t->p[0], ny=t->p[1], nz=t->p[2], n1=t->p[3]?nx-1:1, nn=t->n;
+	HCDT d=(HCDT)t->v;
+	long nx=t->p[0], ny=t->p[1], nz=t->p[2], n1=t->p[3]?nx-1:1, nn=t->n;
 	const mreal *a=t->b, *ii=t->c;
-	mreal *b=t->a,x,val=t->d[0],y1,y2,v,v0,dx,dy,dz,da = 1e-5*(val?fabs(val):1);
-	for(l=t->id;l<nn;l+=mglNumThr)
+	mreal *b=t->a,val=t->d[0],da = 1e-5*(val?fabs(val):1);
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long l=t->id;l<nn;l+=mglNumThr)
 	{
-		j = l%ny;	k = l/ny;	b[l] = NAN;
+		register long j=l%ny, k=l/ny;	b[l] = NAN;
 		if(ii && ii[l]!=ii[l])	continue;
-		i0 = ii?(ii[l]*n1+1):0;
+		register long i0 = ii?(ii[l]*n1+1):0;
 		if(i0>nx-2)	continue;
-		if(a)	for(i=i0+1;i<nx;i++)
+		if(a)	for(long i=i0+1;i<nx;i++)
 		{
-			y1=a[i-1+nx*l];	y2=a[i+nx*l];
-			if(val==y1)	{	b[l] = i-1;	break;	}
-			if(val==y2)	{	b[l] = i;	break;	}
-			if((y1-val)*(y2-val)<0)
+			mreal y1=a[i-1+nx*l], y2=a[i+nx*l];
+			if((y1-val)*(y2-val)<=0)
 			{
-				x = i-1 + (val-y1)/(y2-y1);
-				v0 = v = mglSpline3(a,nx,ny,nz,x,j,k, &dx,&dy,&dz);
+				mreal x = i-1 + (val-y1)/(y2-y1), dx;
+				mreal v0=mglSpline3(a,nx,ny,nz,x,j,k, &dx,0,0), v=v0;
 				unsigned kk=0;
 				while(fabs(v-val)>da || dx==0)
 				{
 					x += (val-v)/dx;		kk++;
-					v = mglSpline3(a,nx,ny,nz,x,j,k, &dx,&dy,&dz);
+					v = mglSpline3(a,nx,ny,nz,x,j,k, &dx,0,0);
 					if(kk>=10)
 					{
 						b[l] = x = fabs(v-val)<fabs(v0-val) ? x:i-1 + (val-y1)/(y2-y1);
@@ -674,13 +785,10 @@ MGL_NO_EXPORT void *mgl_solve_x(void *par)
 				b[l] = x;	break;
 			}
 		}
-		else 	for(i=i0+1;i<nx;i++)
+		else 	for(long i=i0+1;i<nx;i++)
 		{
-			HCDT d=(HCDT)t->v;
-			y1=d->v(i-1,j,k);	y2=d->v(i,j,k);
-			if(val==y1)	{	b[l] = i-1;	break;	}
-			if(val==y2)	{	b[l] = i;	break;	}
-			if((y1-val)*(y2-val)<0)
+			register mreal y1=d->v(i-1,j,k), y2=d->v(i,j,k);
+			if((y1-val)*(y2-val)<=0)
 			{	b[l] = i-1 + (val-y1)/(y2-y1);	break;	}
 		}
 		b[l] /= n1;
@@ -690,29 +798,31 @@ MGL_NO_EXPORT void *mgl_solve_x(void *par)
 MGL_NO_EXPORT void *mgl_solve_y(void *par)
 {
 	mglThreadD *t=(mglThreadD *)par;
-	register long l,i,i0,j,k, nx=t->p[0], ny=t->p[1], nz=t->p[2], n1=t->p[3]?ny-1:1, nn=t->n;
+	HCDT d=(HCDT)t->v;
+	long nx=t->p[0], ny=t->p[1], nz=t->p[2], n1=t->p[3]?ny-1:1, nn=t->n;
 	const mreal *a=t->b, *ii=t->c;
-	mreal *b=t->a,x,val=t->d[0],y1,y2,v,v0,dx,dy,dz,da = 1e-5*(val?fabs(val):1);
-	for(l=t->id;l<nn;l+=mglNumThr)
+	mreal *b=t->a,val=t->d[0],da = 1e-5*(val?fabs(val):1);
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long l=t->id;l<nn;l+=mglNumThr)
 	{
-		j = l%nx;	k = l/nx;	b[l] = NAN;
+		register long j=l%nx, k=l/nx;	b[l] = NAN;
 		if(ii && ii[l]!=ii[l])	continue;
-		i0 = ii?(ii[l]*n1+1):0;
+		register long i0 = ii?(ii[l]*n1+1):0;
 		if(i0>ny-2)	continue;
-		if(a)	for(i=i0+1;i<ny;i++)
+		if(a)	for(long i=i0+1;i<ny;i++)
 		{
-			y1=a[j+nx*(i-1+ny*k)];	y2=a[j+nx*(i+ny*k)];
-			if(val==y1)	{	b[l] = i-1;	break;	}
-			if(val==y2)	{	b[l] = i;	break;	}
-			if((y1-val)*(y2-val)<0)
+			mreal y1=a[j+nx*(i-1+ny*k)], y2=a[j+nx*(i+ny*k)];
+			if((y1-val)*(y2-val)<=0)
 			{
-				x = i-1 + (val-y1)/(y2-y1);
-				v0 = v = mglSpline3(a,nx,ny,nz,j,x,k, &dx,&dy,&dz);
+				mreal x = i-1 + (val-y1)/(y2-y1), dy;
+				mreal v0=mglSpline3(a,nx,ny,nz,j,x,k, 0,&dy,0), v=v0;
 				unsigned kk=0;
 				while(fabs(v-val)>da || dy==0)
 				{
 					x += (val-v)/dy;		kk++;
-					v = mglSpline3(a,nx,ny,nz,j,x,k, &dx,&dy,&dz);
+					v = mglSpline3(a,nx,ny,nz,j,x,k, 0,&dy,0);
 					if(kk>=10)
 					{
 						b[l] = x = fabs(v-val)<fabs(v0-val) ? x:i-1 + (val-y1)/(y2-y1);
@@ -722,13 +832,10 @@ MGL_NO_EXPORT void *mgl_solve_y(void *par)
 				b[l] = x;	break;
 			}
 		}
-		else 	for(i=i0+1;i<ny;i++)
+		else 	for(long i=i0+1;i<ny;i++)
 		{
-			HCDT d=(HCDT)t->v;
-			y1=d->v(j,i-1,k);	y2=d->v(j,i,k);
-			if(val==y1)	{	b[l] = i-1;	break;	}
-			if(val==y2)	{	b[l] = i;	break;	}
-			if((y1-val)*(y2-val)<0)
+			register mreal y1=d->v(j,i-1,k), y2=d->v(j,i,k);
+			if((y1-val)*(y2-val)<=0)
 			{	b[l] = i-1 + (val-y1)/(y2-y1);	break;	}
 		}
 		b[l] /= n1;
@@ -738,29 +845,31 @@ MGL_NO_EXPORT void *mgl_solve_y(void *par)
 MGL_NO_EXPORT void *mgl_solve_z(void *par)
 {
 	mglThreadD *t=(mglThreadD *)par;
-	register long l,i,i0,j,k, nx=t->p[0], ny=t->p[1], nz=t->p[2], n1=t->p[3]?nz-1:1, nn=t->n;
+	HCDT d=(HCDT)t->v;
+	long nx=t->p[0], ny=t->p[1], nz=t->p[2], n1=t->p[3]?nz-1:1, nn=t->n;
 	const mreal *a=t->b, *ii=t->c;
-	mreal *b=t->a,x,val=t->d[0],y1,y2,v,v0,dx,dy,dz,da = 1e-5*(val?fabs(val):1);
-	for(l=t->id;l<nn;l+=mglNumThr)
+	mreal *b=t->a,val=t->d[0],da = 1e-5*(val?fabs(val):1);
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long l=t->id;l<nn;l+=mglNumThr)
 	{
-		j = l%nx;	k = l/nx;	b[l] = NAN;
+		register long j=l%nx, k=l/nx;	b[l] = NAN;
 		if(ii && ii[l]!=ii[l])	continue;
-		i0 = ii?(ii[l]*n1+1):0;
+		register long i0 = ii?(ii[l]*n1+1):0;
 		if(i0>nz-2)	continue;
-		if(a)	for(i=i0+1;i<nz;i++)
+		if(a)	for(long i=i0+1;i<nz;i++)
 		{
-			y1=a[nn*i-nn+l];	y2=a[nn*i+l];
-			if(val==y1)	{	b[l] = i-1;	break;	}
-			if(val==y2)	{	b[l] = i;	break;	}
-			if((y1-val)*(y2-val)<0)
+			mreal y1=a[nn*i-nn+l], y2=a[nn*i+l];
+			if((y1-val)*(y2-val)<=0)
 			{
-				x = i-1 + (val-y1)/(y2-y1);
-				v0 = v = mglSpline3(a,nx,ny,nz,j,k,x, &dx,&dy,&dz);
+				mreal x = i-1 + (val-y1)/(y2-y1), dz;
+				mreal v0=mglSpline3(a,nx,ny,nz,j,k,x, 0,0,&dz), v=v0;
 				unsigned kk=0;
 				while(fabs(v-val)>da || dz==0)
 				{
 					x += (val-v)/dz;		kk++;
-					v = mglSpline3(a,nx,ny,nz,j,k,x, &dx,&dy,&dz);
+					v = mglSpline3(a,nx,ny,nz,j,k,x, 0,0,&dz);
 					if(kk>=10)
 					{
 						b[l] = x = fabs(v-val)<fabs(v0-val) ? x:i-1 + (val-y1)/(y2-y1);
@@ -770,13 +879,10 @@ MGL_NO_EXPORT void *mgl_solve_z(void *par)
 				b[l] = x;	break;
 			}
 		}
-		else 	for(i=i0+1;i<nz;i++)
+		else 	for(long i=i0+1;i<nz;i++)
 		{
-			HCDT d=(HCDT)t->v;
-			y1=d->v(j,k,i-1);	y2=d->v(j,k,i);
-			if(val==y1)	{	b[l] = i-1;	break;	}
-			if(val==y2)	{	b[l] = i;	break;	}
-			if((y1-val)*(y2-val)<0)
+			register mreal y1=d->v(j,k,i-1), y2=d->v(j,k,i);
+			if((y1-val)*(y2-val)<=0)
 			{	b[l] = i-1 + (val-y1)/(y2-y1);	break;	}
 		}
 		b[l] /= n1;
@@ -813,24 +919,22 @@ HMDT MGL_EXPORT mgl_data_solve(HCDT dat, mreal val, char dir, HCDT i0, int norm)
 //-----------------------------------------------------------------------------
 mreal MGL_EXPORT mgl_data_solve_1d(HCDT d, mreal val, int spl, long i0)
 {
-	mreal x=0, y1, y2, a, a0, dx=0,dy,dz, da = 1e-5*(val?fabs(val):1);
+	mreal x=0, y1, y2, a, a0, dx=0, da = 1e-5*(val?fabs(val):1);
 	long nx = d->GetNx();
 	if(i0<0 || i0>=nx)	i0=0;
+	if(val==d->v(i0+1))	return i0+1;
 	const mglData *dd=dynamic_cast<const mglData *>(d);
 	if(dd)	for(long i=i0+1;i<nx;i++)
 	{
 		y1=dd->a[i-1];	y2=dd->a[i];
-		if(val==y1)	return i-1;
-		if(val==y2)	return i;
-		if((y1-val)*(y2-val)<0)
+		if((y1-val)*(y2-val)<=0)
 		{
 			x = i-1 + (val-y1)/(y2-y1);
-			a0 = a = mgl_data_spline_ext(d, x,0,0, &dx,&dy,&dz);
-			unsigned k=0;
-			if(spl)	while(fabs(a-val)>da || dx==0)
+			a0 = a = mglSpline1t<mreal>(dd->a,nx,x,&dx);
+			if(spl)	for(unsigned k=0;fabs(a-val)>da || dx==0;)
 			{
 				x += (val-a)/dx;		k++;
-				a = mgl_data_spline_ext(d, x,0,0, &dx,&dy,&dz);
+				a = mglSpline1t<mreal>(dd->a,nx,x,&dx);
 				if(k>=10)
 					return fabs(a-val)<fabs(a0-val) ? x:i-1 + (val-y1)/(y2-y1);
 			}
@@ -840,11 +944,8 @@ mreal MGL_EXPORT mgl_data_solve_1d(HCDT d, mreal val, int spl, long i0)
 	else 	for(long i=i0+1;i<nx;i++)
 	{
 		y1=d->v(i-1);	y2=d->v(i);
-		if(val==y1)	return i-1;
-		if(val==y2)	return i;
-		if((y1-val)*(y2-val)<0)
+		if((y1-val)*(y2-val)<=0)
 			return i-1 + (val-y1)/(y2-y1);
-			
 	}
 	return NAN;
 }
@@ -853,41 +954,70 @@ mreal MGL_EXPORT mgl_data_linear_ext(HCDT d, mreal x,mreal y,mreal z, mreal *dx,
 {
 	long kx=long(x), ky=long(y), kz=long(z);
 	mreal b0,b1;
-	bool dif = (dx && dy && dz);
 	const mglData *dd=dynamic_cast<const mglData *>(d);
 	if(dd)
 	{
 		long nx=dd->nx, ny=dd->ny, nz=dd->nz, dn=ny>1?nx:0;
-		kx = kx<nx-1 ? kx:nx-2;	kx = kx>=0 ? kx:0;
-		ky = ky<ny-1 ? ky:ny-2;	ky = ky>=0 ? ky:0;
-		kz = kz<nz-1 ? kz:nz-2;	kz = kz>=0 ? kz:0;
-		x -= kx;	if(nx==1)	x=0;
-		y -= ky;	if(ny==1)	y=0;
-		z -= kz;	if(nz==1)	z=0;
-
-		const mreal *aa=dd->a+kx+nx*(ky+ny*kz), *bb = aa+(nz>1?nx*ny:0);
-		b0 = x||y ? aa[0]*(1-x-y+x*y) + x*(1-y)*aa[1] + y*(1-x)*aa[dn] + x*y*aa[1+dn] : aa[0];
-		b1 = x||y ? bb[0]*(1-x-y+x*y) + x*(1-y)*bb[1] + y*(1-x)*bb[dn] + x*y*bb[1+dn] : bb[0];
-		if(dif)
-		{	*dx = aa[1]-aa[0];	*dy = aa[dn]-aa[0];	*dz = bb[0]-aa[0];	}
+		kx = kx>=0 ? kx:0;	kx = kx<nx-1 ? kx:nx-2;
+		ky = ky>=0 ? ky:0;	ky = ky<ny-1 ? ky:ny-2;
+		kz = kz>=0 ? kz:0;	kz = kz<nz-1 ? kz:nz-2;
+		x -= kx;	y -= ky;	z -= kz;
+		const mreal *aa = dd->a, *bb;
+		if(kz>=0)
+		{
+			aa=dd->a+kx+nx*(ky+ny*kz);	bb = aa+nx*ny;
+			b0 = aa[0]*(1-x-y+x*y) + x*(1-y)*aa[1] + y*(1-x)*aa[dn] + x*y*aa[1+dn];
+			b1 = bb[0]*(1-x-y+x*y) + x*(1-y)*bb[1] + y*(1-x)*bb[dn] + x*y*bb[1+dn];
+		}
+		else
+		{
+			z=0;
+			if(ky>=0)
+			{
+				aa=dd->a+kx+nx*ky;
+				b0 = b1 = aa[0]*(1-x-y+x*y) + x*(1-y)*aa[1] + y*(1-x)*aa[dn] + x*y*aa[1+dn];
+			}
+			else if(kx>=0)
+			{
+				aa=dd->a+kx;	b0 = b1 = aa[0]*(1-x) + x*aa[1];
+			}
+			else	b0 = b1 = dd->a[0];
+		}
+		if(dx)	*dx = kx>=0?aa[1]-aa[0]:0;
+		if(dy)	*dy = ky>=0?aa[dn]-aa[0]:0;
+		if(dz)	*dz = b1-b0;
 	}
 	else
 	{
-		long n=d->GetNx(), ny=d->GetNy(), nz=d->GetNz();
-		kx = (kx>=0 ? (kx<n ? kx:n -1):0);
-		ky = (ky>=0 ? (ky<ny? ky:ny-1):0);
-		kz = (kz>=0 ? (kz<nz? kz:nz-1):0);
+		long nx=d->GetNx(), ny=d->GetNy(), nz=d->GetNz();
+		kx = kx>=0 ? kx:0;	kx = kx<nx-1 ? kx:nx-2;
+		ky = ky>=0 ? ky:0;	ky = ky<ny-1 ? ky:ny-2;
+		kz = kz>=0 ? kz:0;	kz = kz<nz-1 ? kz:nz-2;
 		x -= kx;	y -= ky;	z -= kz;
-
-		mreal a0 = d->v(kx,ky,kz), a1 = d->v(kx+1,ky,kz), a2 = d->v(kx,ky+1,kz);
-		if(dif)	{	*dx = a1-a0;	*dy = a2-a0;	*dz = -a0;	}
-		if(x||y)	b0 = a0*(1-x-y+x*y) + x*(1-y)*a1 + y*(1-x)*a2 + x*y*d->v(kx+1,ky+1,kz);
-		else 	b0 = a0;
-		kz++;
-		a0 = d->v(kx,ky,kz); 	a1 = d->v(kx+1,ky,kz);	a2 = d->v(kx,ky+1,kz);
-		if(dif)	*dz += a0;
-		if(x||y)	b1 = a0*(1-x-y+x*y) + x*(1-y)*a1 + y*(1-x)*a2 + x*y*d->v(kx+1,ky+1,kz);
-		else 	b1 = a0;
+		mreal a0 = 0, a1 = 0, a2 = 0;
+		if(kz>=0)
+		{
+			a0 = d->v(kx,ky,kz);	a1 = d->v(kx+1,ky,kz);	a2 = d->v(kx,ky+1,kz);
+			b0 = a0*(1-x-y+x*y) + x*(1-y)*a1 + y*(1-x)*a2 + x*y*d->v(kx+1,ky+1,kz);;
+			b1 = d->v(kx,ky,kz+1)*(1-x-y+x*y) + x*(1-y)*d->v(kx+1,ky,kz+1) + y*(1-x)*d->v(kx,ky+1,kz+1) + x*y*d->v(kx+1,ky+1,kz+1);
+		}
+		else
+		{
+			z=0;
+			if(ky>=0)
+			{
+				a0 = d->v(kx,ky);	a1 = d->v(kx+1,ky);	a2 = d->v(kx,ky+1);
+				b0 = b1 = a0*(1-x-y+x*y) + x*(1-y)*a1 + y*(1-x)*a2 + x*y*d->v(kx+1,ky+1);
+			}
+			else if(kx>=0)
+			{
+				a2=a0 = d->v(kx);	a1 = d->v(kx+1);	b0 = b1 = a0*(1-x) + x*a1;
+			}
+			else	b0 = b1 = dd->a[0];
+		}
+		if(dx)	*dx = a1-a0;
+		if(dy)	*dy = a2-a0;
+		if(dz)	*dz = b1-b0;
 	}
 	return b0 + z*(b1-b0);
 }
@@ -899,14 +1029,14 @@ mreal MGL_EXPORT mgl_data_spline(HCDT d, mreal x,mreal y,mreal z)
 {
 	const mglData *dd=dynamic_cast<const mglData *>(d);
 	if(!d)	return 0;	// NOTE: don't support general arrays
-	return mglSpline3(dd->a,dd->nx,dd->ny,dd->nz,x,y,z,0,0,0);
+	return dd->ny*dd->nz==1?mglSpline1st<mreal>(dd->a,dd->nx,x):mglSpline3st<mreal>(dd->a,dd->nx,dd->ny,dd->nz,x,y,z);
 }
 //-----------------------------------------------------------------------------
 mreal MGL_EXPORT mgl_data_spline_ext(HCDT d, mreal x,mreal y,mreal z, mreal *dx,mreal *dy,mreal *dz)
 {
 	const mglData *dd=dynamic_cast<const mglData *>(d);
 	if(!d)	return 0;	// NOTE: don't support general arrays
-	return mglSpline3(dd->a,dd->nx,dd->ny,dd->nz,x,y,z,dx,dy,dz);
+	return mglSpline3t<mreal>(dd->a,dd->nx,dd->ny,dd->nz,x,y,z,dx,dy,dz);
 }
 //-----------------------------------------------------------------------------
 mreal MGL_EXPORT mgl_data_spline_(uintptr_t *d, mreal *x,mreal *y,mreal *z)
@@ -922,250 +1052,9 @@ mreal MGL_EXPORT mgl_data_solve_1d_(uintptr_t *d, mreal *val, int *spl, int *i0)
 uintptr_t MGL_EXPORT mgl_data_solve_(uintptr_t *d, mreal *val, const char *dir, uintptr_t *i0, int *norm,int)
 {	return uintptr_t(mgl_data_solve(_DA_(d),*val, *dir, _DA_(i0), *norm));	}
 //-----------------------------------------------------------------------------
-mreal mglSpline3(const mreal *a, long nx, long ny, long nz, mreal x, mreal y, mreal z,mreal *dx, mreal *dy, mreal *dz)
-{
-	if(!a || nx<1 || ny<1 || nz<1)	return 0;
-	mreal _p[4][4];
-	register long i,j;
-	register mreal fx=1, fy=1;
-	long kx=long(x),ky=long(y),kz=long(z);
-	bool dd = (dx && dy && dz);
-	mreal b=0;
-	x = x>0 ?(x<nx-1 ? x:nx-1):0;
-	y = y>0 ?(y<ny-1 ? y:ny-1):0;
-	z = z>0 ?(z<nz-1 ? z:nz-1):0;
-	//	if(x<0 || y<0 || z<0 || x>nx-1 || y>ny-1 || z>nz-1)		return 0;
-	if(dd)	{	*dx=*dy=*dz=0;	}
-	if(kx>nx-2)	kx = nx-2;	if(kx<0) 	kx = 0;
-	if(ky>ny-2)	ky = ny-2;	if(ky<0) 	ky = 0;
-	if(kz>nz-2)	kz = nz-2;	if(kz<0) 	kz = 0;
-	if(nz>1 && z!=kz)		// 3d interpolation
-	{
-		mreal b1[4]={0,0,0,0},  x1[4]={0,0,0,0},  y1[4]={0,0,0,0};
-		long kk=1;
-		if(kz==0)	{	kk=0;	}
-		else if(nz>3 && kz==nz-2)	{	kk=2;	}
-		for(long k=0;k<4;k++)
-		{
-			if(kz+k-kk<nz && kz+k-kk>=0)
-				mglFillP(kx, ky, a+(kz+k-kk)*nx*ny, nx, ny, _p);
-			else
-			{
-				memset(_p[0],0,4*sizeof(mreal));
-				memset(_p[1],0,4*sizeof(mreal));
-				memset(_p[2],0,4*sizeof(mreal));
-				memset(_p[3],0,4*sizeof(mreal));
-			}
-			for(i=0,fx=1;i<4;i++)
-			{
-				for(j=0,fy=1;j<4;j++)
-				{
-					b1[k] += fy*fx*_p[i][j];
-					x1[k] += i*fy*fx*_p[i][j];
-					y1[k] += j*fy*fx*_p[i][j];
-					fy *= y-ky;
-				}
-				fx *= x-kx;
-			}
-		}
-		mglFillP(kk, b1, nz>3 ? 4:3, _p[0]);
-		mglFillP(kk, x1, nz>3 ? 4:3, _p[1]);
-		mglFillP(kk, y1, nz>3 ? 4:3, _p[2]);
-		for(i=0,fx=1,b=0;i<4;i++)
-		{
-			b += fx*_p[0][i];
-			if(dd)
-			{
-				*dx += fx*_p[1][i];
-				*dy += fx*_p[2][i];
-				*dz += i*fx*_p[0][i];
-			}
-			fx *= z-kz;
-		}
-	}
-	else if(ny>1 && y!=ky)	// 2d interpolation
-	{
-		mglFillP(kx, ky, a+kz*nx*ny, nx, ny, _p);
-		fx = 1;	b = 0;
-		for(i=0;i<4;i++)
-		{
-			fy = 1;
-			for(j=0;j<4;j++)
-			{
-				b += fy*fx*_p[i][j];
-				if(dd)
-				{
-					*dx+= i*fy*fx*_p[i][j];
-					*dy+= j*fy*fx*_p[i][j];
-				}
-				fy *= y-ky;
-			}
-			fx *= x-kx;
-		}
-		if(dd)	{	*dx /= x-kx;	*dy /= y-ky;	}
-	}
-	else if(nx>1 && x!=kx)	// 1d interpolation
-	{
-		mglFillP(kx, a+(ky+ny*kz)*nx, nx, _p[0]);
-		for(i=0,fx=1,b=0;i<4;i++)
-		{
-			b += fx*_p[0][i];
-			if(dd)	*dx+= i*fx*_p[0][i];
-			fx *= x-kx;
-		}
-		if(dd)	*dx /= x-kx;
-	}
-	else					// no interpolation
-		b = a[kx+nx*(ky+ny*kz)];
-	return b;
-}
-//-----------------------------------------------------------------------------
-void mglFillP(long x,long y, const mreal *a,long nx,long ny,mreal _p[4][4])
-{
-	mreal sx[4]={0,0,0,0},sy[4]={0,0,0,0},f[4]={0,0,0,0},d[4]={0,0,0,0};
-	if(x<0 || y<0 || x>nx-2 || y>ny-2)
-	{
-		memset(_p[0],0,4*sizeof(mreal));
-		memset(_p[1],0,4*sizeof(mreal));
-		memset(_p[2],0,4*sizeof(mreal));
-		memset(_p[3],0,4*sizeof(mreal));
-		return;
-	}
-	// �������� �������
-	f[0]=a[x+nx*y];		f[1]=a[x+nx*(y+1)];
-	if(nx>1)	{	f[2]=a[x+1+nx*y];	f[3]=a[x+1+nx*(y+1)];	}
-	else		{	f[2] = f[0];	f[3] = f[1];	}
-	// ����������� �� x
-	if(nx>1)
-	{
-		if(x==0)
-		{
-			sx[0]=a[x+1+y*nx]-a[x+nx*y];
-			sx[1]=a[x+1+nx*(y+1)]-a[x+nx*(y+1)];
-		}
-		else
-		{
-			sx[0]=(a[x+1+nx*y]-a[x-1+nx*y])/2;
-			sx[1]=(a[x+1+nx*(y+1)]-a[x-1+nx*(y+1)])/2;
-		}
-	}
-	if(x==nx-2)
-	{
-		sx[2]=a[x+1+nx*y]-a[x+nx*y];
-		sx[3]=a[x+1+nx*(y+1)]-a[x+nx*(y+1)];
-	}
-	else
-	{
-		sx[2]=(a[x+2+nx*y]-a[x+nx*y])/2;
-		sx[3]=(a[x+2+nx*(y+1)]-a[x+nx*(y+1)])/2;
-	}
-	// ����������� �� y
-	if(y==0)
-	{
-		sy[0]=a[x+nx*(y+1)]-a[x+nx*y];
-		sy[2]=a[x+1+nx*(y+1)]-a[x+1+nx*y];
-	}
-	else
-	{
-		sy[0]=(a[x+nx*(y+1)]-a[x+nx*(y-1)])/2;
-		sy[2]=(a[x+1+nx*(y+1)]-a[x+1+nx*(y-1)])/2;
-	}
-	if(y==ny-2)
-	{
-		sy[1]=a[x+nx*(y+1)]-a[x+nx*y];
-		sy[3]=a[x+1+nx*(y+1)]-a[x+1+nx*y];
-	}
-	else
-	{
-		sy[1]=(a[x+nx*(y+2)]-a[x+nx*y])/2;
-		sy[3]=(a[x+1+nx*(y+2)]-a[x+1+nx*y])/2;
-	}
-	// ������������ �����������
-	if(nx>1)
-	{
-		// ������ d[0]
-		if(y==0 && x==0)
-			d[0]=(a[x+1+nx*(y+1)]-a[x+nx*(y+1)]-a[x+1+nx*y]+a[x+nx*y]);
-		else if(y==0)
-			d[0]=(a[x+1+nx*(y+1)]-a[x-1+nx*(y+1)]-a[x+1+nx*y]+a[x-1+nx*y])/2;
-		else if(x==0)
-			d[0]=(a[x+1+nx*(y+1)]-a[x+nx*(y+1)]-a[x+1+nx*(y-1)]+a[x+nx*(y-1)])/2;
-		else
-			d[0]=(a[x+1+nx*(y+1)]-a[x-1+nx*(y+1)]-a[x+1+nx*(y-1)]+a[x-1+nx*(y-1)])/4;
-		// ������ d[1]
-		if(y==ny-2 && x==0)
-			d[1]=(a[x+1+nx*(y+1)]-a[x+nx*(y+1)]-a[x+1+nx*y]+a[x+nx*y]);
-		else if(y==ny-2)
-			d[1]=(a[x+1+nx*(y+1)]-a[x-1+nx*(y+1)]-a[x+1+nx*y]+a[x-1+nx*y])/2;
-		else if(x==0)
-			d[1]=(a[x+1+nx*(y+2)]-a[x+nx*(y+2)]-a[x+1+nx*y]+a[x+nx*y])/2;
-		else
-			d[1]=(a[x+1+nx*(y+2)]-a[x-1+nx*(y+2)]-a[x+1+nx*y]+a[x-1+nx*y])/4;
-		// ������ d[2]
-		if(y==0 && x==nx-2)
-			d[2]=(a[x+1+nx*(y+1)]-a[x+nx*(y+1)]-a[x+1+nx*y]+a[x+nx*y]);
-		else if(y==0)
-			d[2]=(a[x+2+nx*(y+1)]-a[x+nx*(y+1)]-a[x+2+nx*y]+a[x+nx*y])/2;
-		else if(x==nx-2)
-			d[2]=(a[x+1+nx*(y+1)]-a[x+nx*(y+1)]-a[x+1+nx*(y-1)]+a[x+nx*(y-1)])/2;
-		else
-			d[2]=(a[x+2+nx*(y+1)]-a[x+nx*(y+1)]-a[x+2+nx*(y-1)]+a[x+nx*(y-1)])/4;
-		// ������ d[3]
-		if(y==ny-2 && x==nx-2)
-			d[3]=(a[x+1+nx*(y+1)]-a[x+nx*(y+1)]-a[x+1+nx*y]+a[x+nx*y]);
-		else if(y==ny-2)
-			d[3]=(a[x+2+nx*(y+1)]-a[x+nx*(y+1)]-a[x+2+nx*y]+a[x+nx*y])/2;
-		else if(x==nx-2)
-			d[3]=(a[x+1+nx*(y+2)]-a[x+nx*(y+2)]-a[x+1+nx*y]+a[x+nx*y])/2;
-		else
-			d[3]=(a[x+2+nx*(y+2)]-a[x+nx*(y+2)]-a[x+2+nx*y]+a[x+nx*y])/4;
-	}
-	// ��������� ������������ ��������
-	_p[0][0]=f[0];		_p[1][0]=sx[0];
-	_p[2][0]=3*(f[2]-f[0])-2*sx[0]-sx[2];
-	_p[3][0]=sx[0]+sx[2]+2*(f[0]-f[2]);
-	_p[0][1]=sy[0];		_p[1][1]=d[0];
-	_p[2][1]=3*(sy[2]-sy[0])-2*d[0]-d[2];
-	_p[3][1]=d[0]+d[2]+2*(sy[0]-sy[2]);
-	_p[0][2]=3*(f[1]-f[0])-2*sy[0]-sy[1];
-	_p[1][2]=3*(sx[1]-sx[0])-2*d[0]-d[1];
-	_p[2][2]=9*(f[0]-f[1]-f[2]+f[3])+6*(sy[0]-sy[2]+sx[0]-sx[1])+
-		3*(sx[2]-sx[3]+sy[1]-sy[3])+2*(d[1]+d[2])+4*d[0]+d[3];
-	_p[3][2]=6*(f[1]+f[2]-f[0]-f[3])+3*(sx[1]-sx[0]+sx[3]-sx[2])+
-		4*(sy[2]-sy[0])+2*(sy[3]-sy[1]-d[0]-d[2])-d[1]-d[3];
-	_p[0][3]=2*(f[0]-f[1])+sy[0]+sy[1];
-	_p[1][3]=2*(sx[0]-sx[1])+d[0]+d[1];
-	_p[2][3]=6*(f[1]+f[2]-f[0]-f[3])+3*(sy[2]-sy[1]+sy[3]-sy[0])+
-		4*(sx[1]-sx[0])+2*(sx[3]-sx[2]-d[0]-d[1])-d[2]-d[3];
-	_p[3][3]=d[0]+d[1]+d[2]+d[3]+4*(f[0]-f[1]-f[2]+f[3])+
-		2*(sx[0]-sx[1]+sx[2]-sx[3]+sy[0]-sy[2]+sy[1]-sy[3]);
-}
-//-----------------------------------------------------------------------------
-void mglFillP(long x, const mreal *a,long nx,mreal _p[4])
-{
-	if(x<0 || x>nx-2)
-	{
-		memset(_p,0,4*sizeof(mreal));
-		return;
-	}
-	mreal s[2],f[2];
-	// �������� �������
-	f[0]=a[x];		f[1]=a[x+1];
-	// ����������� �� x
-	if(x==0)	s[0]=a[x+1]-a[x];
-	else		s[0]=(a[x+1]-a[x-1])/2;
-	if(x==nx-2)	s[1]=a[x+1]-a[x];
-	else		s[1]=(a[x+2]-a[x])/2;
-	// ��������� ������������ ��������
-	_p[0]=f[0];		_p[1]=s[0];
-	_p[2]=3*(f[1]-f[0])-2*s[0]-s[1];
-	_p[3]=s[0]+s[1]+2*(f[0]-f[1]);
-}
-//-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_data_crop(HMDT d, long n1, long n2, char dir)
 {
 	long nx=d->nx,ny=d->ny,nz=d->nz, nn;
-	register long i,k;
 	mreal *b;
 	if(n1<0)	n1=0;
 	switch(dir)
@@ -1174,7 +1063,8 @@ void MGL_EXPORT mgl_data_crop(HMDT d, long n1, long n2, char dir)
 		n2 = n2>0 ? n2 : nx+n2;
 		if(n2<0 || n2>=nx || n2<n1)	n2 = nx;
 		nn = n2-n1;	b = new mreal[nn*ny*nz];
-		for(i=0;i<ny*nz;i++)
+#pragma omp parallel for
+		for(long i=0;i<ny*nz;i++)
 			memcpy(b+nn*i,d->a+nx*i+n1,nn*sizeof(mreal));
 		d->nx = nn;	if(!d->link)	delete []d->a;
 		d->a = b;	d->link=false;	d->NewId();
@@ -1183,8 +1073,9 @@ void MGL_EXPORT mgl_data_crop(HMDT d, long n1, long n2, char dir)
 		n2 = n2>0 ? n2 : ny+n2;
 		if(n2<0 || n2>=ny || n2<n1)	n2 = ny;
 		nn = n2-n1;	b = new mreal[nn*nx*nz];
-		for(long j=0;j<nz;j++)	for(k=0;k<nn;k++)
-			memcpy(b+nx*(k+nn*j),d->a+nx*(n1+k+ny*j),nx*sizeof(mreal));
+#pragma omp parallel for
+		for(long i=0;i<nn;i++)	for(long j=0;j<nz;j++)
+			memcpy(b+nx*(i+nn*j),d->a+nx*(n1+i+ny*j),nx*sizeof(mreal));
 		d->ny = nn;	if(!d->link)	delete []d->a;
 		d->a = b;	d->link=false;
 		break;
@@ -1269,15 +1160,14 @@ int MGL_EXPORT mgl_data_find_(uintptr_t *d, const char *cond, char *dir, int *i,
 int MGL_EXPORT mgl_data_find_any(HCDT d, const char *cond)
 {
 	long nx=d->GetNx(),ny=d->GetNy(),nz=d->GetNz();
-	register long i,j,k;
-	register mreal x,y,z;
 	bool cc = false;
 	if(!cond || *cond==0)	cond = "u";
 	mglFormula eq(cond);
-	for(k=0;k<nz;k++)	for(j=0;j<ny;j++)	for(i=0;i<nx;i++)
+#pragma omp parallel for collapse(3)
+	for(long k=0;k<nz;k++)	for(long j=0;j<ny;j++)	for(long i=0;i<nx;i++)
 	{
-		x=i/(nx-1.);	y=j/(ny-1.);	z=k/(nz-1.);
-		if(eq.Calc(x,y,z,d->v(i,j,k)))	{	cc = true;	break;	}
+		if(cc)	continue;
+		if(eq.Calc(i/(nx-1.),j/(ny-1.),k/(nz-1.),d->v(i,j,k)))	cc = true;
 	}
 	return cc;
 }
@@ -1288,43 +1178,43 @@ int MGL_EXPORT mgl_data_find_any_(uintptr_t *d, const char *cond, int l)
 mreal MGL_EXPORT mgl_data_momentum_val(HCDT dd, char dir, mreal *x, mreal *w, mreal *s, mreal *k)
 {
 	long nx=dd->GetNx(),ny=dd->GetNy(),nz=dd->GetNz();
-	mreal i0=0,i1=0,i2=0,i3=0,i4=0,d,t,v;
-	register long i;
+	mreal i0=0,i1=0,i2=0,i3=0,i4=0;
 	const mglData *md = dynamic_cast<const mglData *>(dd);
 	if(dd)	switch(dir)
 	{
 	case 'x':
-		for(i=0;i<nx*ny*nz;i++)
+#pragma omp parallel for reduction(+:i0,i1,i2,i3,i4)
+		for(long i=0;i<nx*ny*nz;i++)
 		{
-			d = i%nx;		t = d*d;
-			v = md->a[i];i0+= v;
-			i1+= v*d;		i2+= v*t;
+			register mreal d = i%nx, t = d*d, v = md->a[i];
+			i0+= v;	i1+= v*d;	i2+= v*t;
 			i3+= v*d*t;		i4+= v*t*t;
 		}
 		break;
 	case 'y':
-		for(i=0;i<nx*ny*nz;i++)
+#pragma omp parallel for reduction(+:i0,i1,i2,i3,i4)
+		for(long i=0;i<nx*ny*nz;i++)
 		{
-			d = (i/nx)%ny;	t = d*d;
-			v = md->a[i];i0+= v;
-			i1+= v*d;		i2+= v*t;
+			register mreal d = (i/nx)%ny, t = d*d, v = md->a[i];
+			i0+= v;	i1+= v*d;	i2+= v*t;
 			i3+= v*d*t;		i4+= v*t*t;
 		}
 		break;
 	case 'z':
-		for(i=0;i<nx*ny*nz;i++)
+#pragma omp parallel for reduction(+:i0,i1,i2,i3,i4)
+		for(long i=0;i<nx*ny*nz;i++)
 		{
-			d = i/(nx*ny);	t = d*d;
-			v = md->a[i];i0+= v;
-			i1+= v*d;		i2+= v*t;
+			register mreal d = i/(nx*ny), t = d*d, v = md->a[i];
+			i0+= v;	i1+= v*d;	i2+= v*t;
 			i3+= v*d*t;		i4+= v*t*t;
 		}
 		break;
 	default:	// "self-dispersion"
 		i0 = nx*ny*nz;
-		for(i=0;i<nx*ny*nz;i++)
+#pragma omp parallel for reduction(+:i1,i2,i3,i4)
+		for(long i=0;i<nx*ny*nz;i++)
 		{
-			v=md->a[i];	t  = v*v;
+			register mreal v=md->a[i], t  = v*v;
 			i1+= v;			i2+= t;
 			i3+= v*t;		i4+= t*t;
 		}
@@ -1332,42 +1222,44 @@ mreal MGL_EXPORT mgl_data_momentum_val(HCDT dd, char dir, mreal *x, mreal *w, mr
 	else	switch(dir)
 	{
 	case 'x':
-		for(i=0;i<nx*ny*nz;i++)
+#pragma omp parallel for reduction(+:i0,i1,i2,i3,i4)
+		for(long i=0;i<nx*ny*nz;i++)
 		{
-			d = i%nx;		t = d*d;
-			v = dd->vthr(i);i0+= v;
-			i1+= v*d;		i2+= v*t;
+			register mreal d = i%nx, t = d*d, v = dd->vthr(i);
+			i0+= v;	i1+= v*d;	i2+= v*t;
 			i3+= v*d*t;		i4+= v*t*t;
 		}
 		break;
 	case 'y':
-		for(i=0;i<nx*ny*nz;i++)
+#pragma omp parallel for reduction(+:i0,i1,i2,i3,i4)
+		for(long i=0;i<nx*ny*nz;i++)
 		{
-			d = (i/nx)%ny;	t = d*d;
-			v = dd->vthr(i);i0+= v;
-			i1+= v*d;		i2+= v*t;
+			register mreal d = (i/nx)%ny, t = d*d, v = dd->vthr(i);
+			i0+= v;	i1+= v*d;	i2+= v*t;
 			i3+= v*d*t;		i4+= v*t*t;
 		}
 		break;
 	case 'z':
-		for(i=0;i<nx*ny*nz;i++)
+#pragma omp parallel for reduction(+:i0,i1,i2,i3,i4)
+		for(long i=0;i<nx*ny*nz;i++)
 		{
-			d = i/(nx*ny);	t = d*d;
-			v = dd->vthr(i);i0+= v;
-			i1+= v*d;		i2+= v*t;
+			register mreal d = i/(nx*ny), t = d*d, v = dd->vthr(i);
+			i0+= v;	i1+= v*d;	i2+= v*t;
 			i3+= v*d*t;		i4+= v*t*t;
 		}
 		break;
 	default:	// "self-dispersion"
 		i0 = nx*ny*nz;
-		for(i=0;i<nx*ny*nz;i++)
+#pragma omp parallel for reduction(+:i1,i2,i3,i4)
+		for(long i=0;i<nx*ny*nz;i++)
 		{
-			v=dd->vthr(i);	t  = v*v;
+			register mreal v = dd->vthr(i), t = v*v;
 			i1+= v;			i2+= t;
 			i3+= v*t;		i4+= t*t;
 		}
 	}
-	if(i0==0)	return 0;	d=i1/i0;
+	if(i0==0)	return 0;
+	register mreal d=i1/i0;
 	if(x)	*x=d;
 	if(w)	*w=i2>d*d*i0 ? sqrt(i2/i0-d*d) : 0;
 	if(s)	*s=i3/i0;
@@ -1384,15 +1276,15 @@ void MGL_EXPORT mgl_data_norm_slice(HMDT d, mreal v1,mreal v2,char dir,long keep
 	long nx=d->nx, ny=d->ny, nz=d->nz;
 	mreal *a=d->a;
 	mglData b(*d);
-	register long i,k;
-	register mreal e0=1, e=1, m1, m2, aa;
+	register mreal e0=1, e, m1, m2, aa;
 	if(sym)	{	v2 = -v1>v2 ? -v1:v2;	v1 = -v2;	}
 	if(dir=='z' && nz>1)
 	{
-		for(k=0;k<nz;k++)
+//#pragma omp parallel for private(m1,m2,aa,e,e0)	// TODO add omp comparison here
+		for(long k=0;k<nz;k++)
 		{
-			m1 = 1e20;	m2 = -1e20;
-			for(i=0;i<nx*ny;i++)
+			m1 = 1e20;	m2 = -1e20;	e=0;
+			for(long i=0;i<nx*ny;i++)
 			{
 				aa = a[i+nx*ny*k];
 				m1 = m1<aa ? m1 : aa;
@@ -1401,19 +1293,19 @@ void MGL_EXPORT mgl_data_norm_slice(HMDT d, mreal v1,mreal v2,char dir,long keep
 			}
 			if(m1==m2)	m2+=1;
 			if(sym)	{	m2 = -m1>m2 ? -m1:m2;	m1 = -m2;	}
-			if(keep_en && k)	e = sqrt(e/e0);
+			if(keep_en && k)	e = e0>0?sqrt(e/e0):1;
 			else	{	e0 = e;	e=1;	}
-			for(i=0;i<nx*ny;i++)
+			for(long i=0;i<nx*ny;i++)
 				b.a[i+nx*ny*k] = (v1 + (v2-v1)*(a[i+nx*ny*k]-m1)/(m2-m1))*e;
 		}
 	}
 	else if(dir=='y' && ny>1)
 	{
-		register long j;
-		for(j=0;j<ny;j++)
+//#pragma omp parallel for private(m1,m2,aa,e,e0)	// TODO add omp comparison here
+		for(long j=0;j<ny;j++)
 		{
-			m1 = 1e20;	m2 = -1e20;
-			for(k=0;k<nz;k++)	for(i=0;i<nx;i++)
+			m1 = 1e20;	m2 = -1e20;	e=0;
+			for(long k=0;k<nz;k++)	for(long i=0;i<nx;i++)
 			{
 				aa = a[i+nx*(j+ny*k)];
 				m1 = m1<aa ? m1 : aa;
@@ -1422,18 +1314,20 @@ void MGL_EXPORT mgl_data_norm_slice(HMDT d, mreal v1,mreal v2,char dir,long keep
 			}
 			if(m1==m2)	m2+=1;
 			if(sym)	{	m2 = -m1>m2 ? -m1:m2;	m1 = -m2;	}
-			if(keep_en && j)	e = sqrt(e/e0);
+			if(keep_en && j)	e = e0>0?sqrt(e/e0):1;
 			else	{	e0 = e;	e=1;	}
-			for(k=0;k<nz;k++)	for(i=0;i<nx;i++)
+#pragma omp parallel for collapse(2)
+			for(long k=0;k<nz;k++)	for(long i=0;i<nx;i++)
 				b.a[i+nx*(j+ny*k)] = (v1 + (v2-v1)*(a[i+nx*(j+ny*k)]-m1)/(m2-m1))*e;
 		}
 	}
 	else if(dir=='x' && nx>1)
 	{
-		for(i=0;i<nx;i++)
+//#pragma omp parallel for private(m1,m2,aa,e,e0)	// TODO add omp comparison here
+		for(long i=0;i<nx;i++)
 		{
-			m1 = 1e20;	m2 = -1e20;
-			for(k=0;k<ny*nz;k++)
+			m1 = 1e20;	m2 = -1e20;	e=0;
+			for(long k=0;k<ny*nz;k++)
 			{
 				aa = a[i+nx*k];
 				m1 = m1<aa ? m1 : aa;
@@ -1442,9 +1336,10 @@ void MGL_EXPORT mgl_data_norm_slice(HMDT d, mreal v1,mreal v2,char dir,long keep
 			}
 			if(m1==m2)	m2+=1;
 			if(sym)	{	m2 = -m1>m2 ? -m1:m2;	m1 = -m2;	}
-			if(keep_en && i)	e = sqrt(e/e0);
+			if(keep_en && i)	e = e0>0?sqrt(e/e0):1;
 			else	{	e0 = e;	e=1;	}
-			for(k=0;k<ny*nz;k++)
+#pragma omp parallel for
+			for(long k=0;k<ny*nz;k++)
 				b.a[i+nx*k] = (v1 + (v2-v1)*(a[i+nx*k]-m1)/(m2-m1))*e;
 		}
 	}
@@ -1477,18 +1372,18 @@ void MGL_EXPORT mgl_data_insert(HMDT d, char dir, long at, long num)
 {
 	if(num<1)	return;
 	at = at<0 ? 0:at;
-	register long i,k,nn;
-	long nx=d->nx, ny=d->ny, nz=d->nz;
+	long nn, nx=d->nx, ny=d->ny, nz=d->nz;
 	mglData b;
 	if(dir=='x')
 	{
 		if(at>nx)	at=nx;
 		nn=nx+num;	b.Create(nn,ny,nz);
-		for(k=0;k<ny*nz;k++)
+#pragma omp parallel for
+		for(long k=0;k<ny*nz;k++)
 		{
 			if(at>0)	memcpy(b.a+nn*k, d->a+nx*k,at*sizeof(mreal));
 			if(at<nx)	memcpy(b.a+at+num+nn*k, d->a+at+nx*k,(nx-at)*sizeof(mreal));
-			for(i=0;i<num;i++)	b.a[nn*k+at+i]=d->a[nx*k+at];	// copy values
+			for(long i=0;i<num;i++)	b.a[nn*k+at+i]=d->a[nx*k+at];	// copy values
 		}
 		d->Set(b);	nx+=num;
 	}
@@ -1496,11 +1391,12 @@ void MGL_EXPORT mgl_data_insert(HMDT d, char dir, long at, long num)
 	{
 		if(at>ny)	at=ny;
 		nn=num+ny;	b.Create(nx,nn,nz);
-		for(k=0;k<nz;k++)
+#pragma omp parallel for
+		for(long k=0;k<nz;k++)
 		{
 			if(at>0)	memcpy(b.a+nx*nn*k, d->a+nx*ny*k,at*nx*sizeof(mreal));
 			if(at<ny)	memcpy(b.a+nx*(at+num+nn*k), d->a+nx*(at+ny*k),(ny-at)*nx*sizeof(mreal));
-			for(i=0;i<num;i++)	memcpy(b.a+nx*(nn*k+at+i),d->a+nx*(ny*k+at),nx*sizeof(mreal));
+			for(long i=0;i<num;i++)	memcpy(b.a+nx*(nn*k+at+i),d->a+nx*(ny*k+at),nx*sizeof(mreal));
 		}
 		d->Set(b);	ny+=num;
 	}
@@ -1510,7 +1406,8 @@ void MGL_EXPORT mgl_data_insert(HMDT d, char dir, long at, long num)
 		b.Create(nx,ny,nz+num);
 		if(at>0)	memcpy(b.a, d->a,at*nx*ny*sizeof(mreal));
 		if(at<nz)	memcpy(b.a+nx*ny*(at+num), d->a+nx*ny*at,(nz-at)*nx*ny*sizeof(mreal));
-		for(i=0;i<num;i++)	memcpy(b.a+nx*ny*(at+i),d->a+nx*ny*at,nx*ny*sizeof(mreal));
+#pragma omp parallel for
+		for(long i=0;i<num;i++)	memcpy(b.a+nx*ny*(at+i),d->a+nx*ny*at,nx*ny*sizeof(mreal));
 		d->Set(b);	nz+=num;
 	}
 }
@@ -1519,13 +1416,13 @@ void MGL_EXPORT mgl_data_delete(HMDT d, char dir, long at, long num)
 {
 	if(num<1 || at<0)	return;
 	mglData b;
-	long nx=d->nx, ny=d->ny, nz=d->nz;
-	register long k,nn;
+	long nx=d->nx, ny=d->ny, nz=d->nz, nn;
 	if(dir=='x')
 	{
 		if(at+num>=nx)	return;
 		nn=nx-num;	b.Create(nn,ny,nz);
-		for(k=0;k<ny*nz;k++)
+#pragma omp parallel for
+		for(long k=0;k<ny*nz;k++)
 		{
 			if(at>0)	memcpy(b.a+nn*k, d->a+nx*k,at*sizeof(mreal));
 			memcpy(b.a+at+nn*k, d->a+at+num+nx*k,(nx-at-num)*sizeof(mreal));
@@ -1536,7 +1433,8 @@ void MGL_EXPORT mgl_data_delete(HMDT d, char dir, long at, long num)
 	{
 		if(at+num>=ny)	return;
 		nn=ny-num;	b.Create(nx,nn,nz);
-		for(k=0;k<nz;k++)
+#pragma omp parallel for
+		for(long k=0;k<nz;k++)
 		{
 			if(at>0)	memcpy(b.a+nx*nn*k, d->a+nx*ny*k,at*nx*sizeof(mreal));
 			memcpy(b.a+nx*(at+nn*k), d->a+nx*(at+num+ny*k),(ny-at-num)*nx*sizeof(mreal));
@@ -1639,22 +1537,31 @@ void MGL_NO_EXPORT mgl_omod(mreal *a, mreal da, int nx, int n)
 MGL_NO_EXPORT void *mgl_sew_z(void *par)
 {
 	mglThreadD *t=(mglThreadD *)par;
-	register long i, nz=t->p[2], nn=t->n;
-	for(i=t->id;i<nn;i+=mglNumThr)	mgl_omod(t->a+i, t->b[0], nz, nn);
+	long nz=t->p[2], nn=t->n;
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i=t->id;i<nn;i+=mglNumThr)	mgl_omod(t->a+i, t->b[0], nz, nn);
 	return 0;
 }
 MGL_NO_EXPORT void *mgl_sew_y(void *par)
 {
 	mglThreadD *t=(mglThreadD *)par;
-	register long i, nx=t->p[0], ny=t->p[1], nn=t->n;
-	for(i=t->id;i<nn;i+=mglNumThr)	mgl_omod(t->a+(i%nx)+nx*ny*(i/nx), t->b[0], ny, nx);
+	long nx=t->p[0], ny=t->p[1], nn=t->n;
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i=t->id;i<nn;i+=mglNumThr)	mgl_omod(t->a+(i%nx)+nx*ny*(i/nx), t->b[0], ny, nx);
 	return 0;
 }
 MGL_NO_EXPORT void *mgl_sew_x(void *par)
 {
 	mglThreadD *t=(mglThreadD *)par;
-	register long i, nx=t->p[0], nn=t->n;
-	for(i=t->id;i<nn;i+=mglNumThr)	mgl_omod(t->a+i*nx, t->b[0], nx, 1);
+	long nx=t->p[0], nn=t->n;
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i=t->id;i<nn;i+=mglNumThr)	mgl_omod(t->a+i*nx, t->b[0], nx, 1);
 	return 0;
 }
 void MGL_EXPORT mgl_data_sew(HMDT d, const char *dirs, mreal delta)
@@ -1676,14 +1583,27 @@ void MGL_EXPORT mgl_data_put_val(HMDT d, mreal val, long xx, long yy, long zz)
 	register long nx=d->nx, ny=d->ny, nz=d->nz;
 	if(xx>=nx || yy>=ny || zz>=nz)	return;
 	mreal *a=d->a;
-	register long i,j;
-	if(xx<0 && yy<0 && zz<0)for(i=0;i<nx*ny*nz;i++)	a[i] = val;
-	else if(xx<0 && yy<0)	for(i=0;i<nx*ny;i++)	a[i+zz*nx*ny] = val;
-	else if(yy<0 && zz<0)	for(i=0;i<nz*ny;i++)	a[xx+i*nx] = val;
-	else if(xx<0 && zz<0)	for(i=0;i<nx;i++)	for(j=0;j<nz;j++)	a[i+nx*(yy+j*ny)] = val;
-	else if(xx<0)	for(i=0;i<nx;i++)	a[i+nx*(yy+zz*ny)] = val;
-	else if(yy<0)	for(i=0;i<ny;i++)	a[xx+nx*(i+zz*ny)] = val;
-	else if(zz<0)	for(i=0;i<nz;i++)	a[xx+nx*(yy+i*ny)] = val;
+	if(xx<0 && yy<0 && zz<0)
+#pragma omp parallel for
+		for(long i=0;i<nx*ny*nz;i++)	a[i] = val;
+	else if(xx<0 && yy<0)
+#pragma omp parallel for
+		for(long i=0;i<nx*ny;i++)	a[i+zz*nx*ny] = val;
+	else if(yy<0 && zz<0)
+#pragma omp parallel for
+		for(long i=0;i<nz*ny;i++)	a[xx+i*nx] = val;
+	else if(xx<0 && zz<0)
+#pragma omp parallel for collapse(2)
+		for(long i=0;i<nx;i++)	for(long j=0;j<nz;j++)	a[i+nx*(yy+j*ny)] = val;
+	else if(xx<0)
+#pragma omp parallel for
+		for(long i=0;i<nx;i++)	a[i+nx*(yy+zz*ny)] = val;
+	else if(yy<0)
+#pragma omp parallel for
+		for(long i=0;i<ny;i++)	a[xx+nx*(i+zz*ny)] = val;
+	else if(zz<0)
+#pragma omp parallel for
+		for(long i=0;i<nz;i++)	a[xx+nx*(yy+i*ny)] = val;
 	else	a[xx+nx*(yy+zz*ny)] = val;
 }
 //-----------------------------------------------------------------------------
@@ -1695,58 +1615,105 @@ void MGL_EXPORT mgl_data_put_dat(HMDT d, HCDT v, long xx, long yy, long zz)
 	mreal *a=d->a, vv=v->v(0);
 	const mreal *b = mv?mv->a:0;
 	long vx=v->GetNx(), vy=v->GetNy(), vz=v->GetNz();
-	register long i,j,k;
 	if(xx<0 && yy<0 && zz<0)	// whole array
 	{
 		if(vx>=nx && vy>=ny && vz>=nz)
-			for(k=0;k<nz;k++)	for(j=0;j<ny;j++)	for(i=0;i<nx;i++)
-				a[i+nx*(j+k*ny)] = b?b[i+vx*(j+k*vy)]:v->v(i,j,k);
+#pragma omp parallel for
+			for(long ii=0;ii<nx*ny*nz;ii++)
+			{	register long i=ii%nx, j=(ii/nx)%ny, k=ii/(nx*ny);
+				a[ii] = b?b[i+vx*(j+k*vy)]:v->v(i,j,k);	}
 		else if(vx>=nx && vy>=ny)
-			for(k=0;k<nz;k++)	for(j=0;j<ny;j++)	for(i=0;i<nx;i++)
-				a[i+nx*(j+k*ny)] = b?b[i+vx*j]:v->v(i,j);
-		else if(vx>=nx)	for(k=0;k<ny*nz;k++)	for(i=0;i<nx;i++)
-				a[i+nx*k] = b?b[i]:v->v(i);
-		else	for(i=0;i<nx*ny*nz;i++)	a[i] = vv;
+#pragma omp parallel for
+			for(long ii=0;ii<nx*ny*nz;ii++)
+			{	register long i=ii%nx, j=(ii/nx)%ny;
+				a[ii] = b?b[i+vx*j]:v->v(i,j);	}
+		else if(vx>=nx)
+#pragma omp parallel for
+			for(long ii=0;ii<nx*ny*nz;ii++)
+			{	register long i=ii%nx;	a[ii] = b?b[i]:v->v(i);	}
+		else
+#pragma omp parallel for
+			for(long ii=0;ii<nx*ny*nz;ii++)	a[ii] = vv;
 	}
 	else if(xx<0 && yy<0)	// 2d
 	{
-		if(vx>=nx && vy>=ny)	for(j=0;j<ny;j++)	for(i=0;i<nx;i++)
-				a[i+nx*(j+zz*ny)] = b?b[i+vx*j]:v->v(i,j);
-		else if(vx>=nx)	for(j=0;j<ny;j++)	for(i=0;i<nx;i++)
-				a[i+nx*(j+zz*ny)] = b?b[i]:v->v(i);
-		else	for(i=0;i<nx*ny;i++)	a[i+nx*ny*zz] = vv;
+		zz*=nx*ny;
+		if(vx>=nx && vy>=ny)
+#pragma omp parallel for
+			for(long ii=0;ii<nx*ny;ii++)
+			{	register long i=ii%nx, j=ii/nx;
+				a[ii+zz] = b?b[i+vx*j]:v->v(i,j);	}
+		else if(vx>=nx)
+#pragma omp parallel for
+			for(long ii=0;ii<nx*ny;ii++)
+			{	register long i=ii%nx;	a[ii+zz] = b?b[i]:v->v(i);	}
+		else
+#pragma omp parallel for
+			for(long ii=0;ii<nx*ny;ii++) 	a[ii+zz] = vv;
 	}
 	else if(yy<0 && zz<0)	// 2d
 	{
-		if(vx>=ny && vy>=nz)	for(j=0;j<nz;j++)	for(i=0;i<ny;i++)
-				a[xx+nx*(i+j*ny)] = b?b[i+vx*j]:v->v(i,j);
-		else if(vx>=ny)	for(j=0;j<nz;j++)	for(i=0;i<ny;i++)
-				a[xx+nx*(i+j*ny)] = b?b[i]:v->v(i);
-		else	for(i=0;i<ny*nz;i++)	a[xx+nx*i] = vv;
+		if(vx>=ny && vy>=nz)
+#pragma omp parallel for
+			for(long ii=0;ii<ny*nz;ii++)
+			{	register long i=ii%ny, j=ii/ny;
+				a[ii*nx+xx] = b?b[i+vx*j]:v->v(i,j);	}
+		else if(vx>=ny)
+#pragma omp parallel for
+			for(long ii=0;ii<ny*nz;ii++)
+			{	register long i=ii%ny;	a[ii*nx+xx] = b?b[i]:v->v(i);	}
+		else
+#pragma omp parallel for
+			for(long ii=0;ii<ny*nz;ii++) 	a[ii*nx+xx] = vv;
 	}
 	else if(xx<0 && zz<0)	// 2d
 	{
-		if(vx>=nx && vy>=nz)	for(j=0;j<nz;j++)	for(i=0;i<nx;i++)
-				a[i+nx*(yy+j*ny)] = b?b[i+vx*j]:v->v(i,j);
-		else if(vx>=nx)	for(j=0;j<nz;j++)	for(i=0;i<nx;i++)
-				a[i+nx*(yy+j*ny)] = b?b[i]:v->v(i);
-		else	for(j=0;j<nz;j++)	for(i=0;i<nx;i++)
-				a[i+nx*(yy+j*ny)] = vv;
+		yy *= nx;	zz = nx*ny;
+		if(vx>=nx && vy>=nz)
+#pragma omp parallel for
+			for(long ii=0;ii<nx*nz;ii++)
+			{	register long i=ii%nx, j=ii/nx;
+				a[i+yy+j*zz] = b?b[i+vx*j]:v->v(i,j);	}
+		else if(vx>=nx)
+#pragma omp parallel for
+			for(long ii=0;ii<nx*nz;ii++)
+			{	register long i=ii%nx, j=ii/nx;
+				a[i+yy+j*zz] = b?b[i]:v->v(i);	}
+		else
+#pragma omp parallel for
+			for(long ii=0;ii<nx*nz;ii++)
+			{	register long i=ii%nx, j=ii/nx;
+				a[i+yy+j*zz] = vv;	}
 	}
 	else if(xx<0)
 	{
-		if(vx>=nx)	for(i=0;i<nx;i++)	a[i+nx*(yy+zz*ny)] = b?b[i]:v->v(i);
-		else for(i=0;i<nx;i++)	a[i+nx*(yy+zz*ny)] = vv;
+		xx = nx*(yy+zz*ny);
+		if(vx>=nx)
+#pragma omp parallel for
+			for(long i=0;i<nx;i++)	a[i+xx] = b?b[i]:v->v(i);
+		else
+#pragma omp parallel for
+			for(long i=0;i<nx;i++)	a[i+xx] = vv;
 	}
 	else if(yy<0)
 	{
-		if(vx>=ny)	for(i=0;i<ny;i++)	a[xx+nx*(i+zz*ny)] = b?b[i]:v->v(i);
-		else for(i=0;i<ny;i++)	a[xx+nx*(i+zz*ny)] = vv;
+		xx += zz*nx*ny;
+		if(vx>=ny)
+#pragma omp parallel for
+			for(long i=0;i<ny;i++)	a[xx+nx*i] = b?b[i]:v->v(i);
+		else
+#pragma omp parallel for
+			for(long i=0;i<ny;i++)	a[xx+nx*i] = vv;
 	}
 	else if(zz<0)
 	{
-		if(vx>=nz)	for(i=0;i<nz;i++)	a[xx+nx*(yy+i*ny)] = b?b[i]:v->v(i);
-		else for(i=0;i<nz;i++)	a[xx+nx*(yy+i*ny)] = vv;
+		xx += nx*yy;	yy = nx*ny;
+		if(vx>=nz)
+#pragma omp parallel for
+			for(long i=0;i<nz;i++)	a[xx+yy*i] = b?b[i]:v->v(i);
+		else
+#pragma omp parallel for
+			for(long i=0;i<nz;i++)	a[xx+yy*i] = vv;
 	}
 	else	a[xx+nx*(yy+ny*zz)] = vv;
 }
@@ -1759,12 +1726,15 @@ void MGL_EXPORT mgl_data_put_dat_(uintptr_t *d, uintptr_t *val, int *i, int *j,
 MGL_NO_EXPORT void *mgl_diff_3(void *par)
 {
 	mglThreadD *t=(mglThreadD *)par;
-	register long i,j,k, i0, nx=t->p[0], ny=t->p[1], nz=t->p[2], nn=t->n;
+	long nx=t->p[0], ny=t->p[1], nz=t->p[2], nn=t->n;
 	mreal *b=t->a,au,av,aw,xu,xv,xw,yu,yv,yw,zu,zv,zw;
 	const mreal *a=t->b, *x=t->c, *y=t->d, *z=t->e;
-	for(i0=t->id;i0<nn;i0+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for private(au,av,aw,xu,xv,xw,yu,yv,yw,zu,zv,zw)
+#endif
+	for(long i0=t->id;i0<nn;i0+=mglNumThr)
 	{
-		i=i0%nx;	j=((i0/nx)%ny);	k=i0/(nx*ny);
+		register long i=i0%nx, j=((i0/nx)%ny), k=i0/(nx*ny);
 		if(i==0)
 		{
 			au = 3*a[i0]-4*a[i0+1]+a[i0+2];
@@ -1835,13 +1805,15 @@ MGL_NO_EXPORT void *mgl_diff_3(void *par)
 MGL_NO_EXPORT void *mgl_diff_2(void *par)
 {
 	mglThreadD *t=(mglThreadD *)par;
-	register long i,j, i0,i1, nx=t->p[0], ny=t->p[1], nn=t->n, same=t->p[2];
+	register long nx=t->p[0], ny=t->p[1], nn=t->n, same=t->p[2];
 	mreal *b=t->a,au,av,xu,xv,yu,yv;
 	const mreal *a=t->b, *x=t->c, *y=t->d;
-	for(i0=t->id;i0<nn;i0+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for private(au,av,xu,xv,yu,yv)
+#endif
+	for(long i0=t->id;i0<nn;i0+=mglNumThr)
 	{
-		i=i0%nx;	j=((i0/nx)%ny);
-		i1 = same ? i0 : i0%(nx*ny);
+		register long i=i0%nx, j=((i0/nx)%ny), i1 = same ? i0 : i0%(nx*ny);
 		if(i==0)
 		{
 			au = 3*a[i0]-4*a[i0+1]+a[i0+2];
@@ -1885,12 +1857,15 @@ MGL_NO_EXPORT void *mgl_diff_2(void *par)
 MGL_NO_EXPORT void *mgl_diff_1(void *par)
 {
 	mglThreadD *t=(mglThreadD *)par;
-	register long i,i0,i1, nx=t->p[0], nn=t->n, same=t->p[1];
+	long nx=t->p[0], nn=t->n, same=t->p[1];
 	mreal *b=t->a,au,xu;
 	const mreal *a=t->b, *x=t->c;
-	for(i0=t->id;i0<nn;i0+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for private(au,xu)
+#endif
+	for(long i0=t->id;i0<nn;i0+=mglNumThr)
 	{
-		i=i0%nx;	i1 = same ? i0 : i;
+		register long i=i0%nx, i1 = same ? i0 : i;
 		if(i==0)
 		{
 			au = 3*a[i0]-4*a[i0+1]+a[i0+2];
@@ -1962,17 +1937,18 @@ long MGL_EXPORT mgl_data_get_nz_(uintptr_t *d)	{	return _DA_(d)->GetNz();	}
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_data_join(HMDT d, HCDT v)
 {
-	register long nx=d->nx, ny=d->ny, nz=d->nz;
+	long nx=d->nx, ny=d->ny, nz=d->nz, k=nx*ny*nz;
 	const mglData *mv = dynamic_cast<const mglData *>(v);
 	long vx=v->GetNx(), vy=v->GetNy(), vz=v->GetNz();
-	register long i,k=nx*ny*nz;
 
 	if(nx==vx && ny==vy && (nz>1 || vz>1))
 	{
 		mreal *b = new mreal[nx*ny*(nz+vz)];
 		memcpy(b,d->a,nx*ny*nz*sizeof(mreal));
 		if(mv)	memcpy(b+nx*ny*nz,mv->a,nx*ny*vz*sizeof(mreal));
-		else 	for(i=0;i<nx*ny*vz;i++)	b[k+i] = v->vthr(i);
+		else
+#pragma omp parallel for
+			for(long i=0;i<nx*ny*vz;i++)	b[k+i] = v->vthr(i);
 		if(!d->link)	delete []d->a;	d->nz += vz;
 		d->a = b;	d->link=false;	d->NewId();
 	}
@@ -1982,7 +1958,9 @@ void MGL_EXPORT mgl_data_join(HMDT d, HCDT v)
 		mreal *b = new mreal[nx*(ny+vy)];
 		memcpy(b,d->a,nx*ny*sizeof(mreal));
 		if(mv)	memcpy(b+nx*ny,mv->a,nx*vy*sizeof(mreal));
-		else 	for(i=0;i<nx*vy;i++)	b[k+i] = v->vthr(i);
+		else
+#pragma omp parallel for
+			for(long i=0;i<nx*vy;i++)	b[k+i] = v->vthr(i);
 		if(!d->link)	delete []d->a;
 		d->nz = 1;	d->ny = ny+vy;
 		d->a = b;	d->link=false;	d->NewId();
@@ -1993,7 +1971,9 @@ void MGL_EXPORT mgl_data_join(HMDT d, HCDT v)
 		mreal *b = new mreal[nx+vx];
 		memcpy(b,d->a,nx*sizeof(mreal));
 		if(mv)	memcpy(b+nx,mv->a,vx*sizeof(mreal));
-		else 	for(i=0;i<vx;i++)	b[k+i] = v->vthr(i);
+		else
+#pragma omp parallel for
+			for(long i=0;i<vx;i++)	b[k+i] = v->vthr(i);
 		if(!d->link)	delete []d->a;
 		d->nz = d->ny = 1;	d->nx = nx+vx;
 		d->a = b;	d->link=false;	d->NewId();
@@ -2003,3 +1983,244 @@ void MGL_EXPORT mgl_data_join(HMDT d, HCDT v)
 void MGL_EXPORT mgl_data_join_(uintptr_t *d, uintptr_t *val)
 {	mgl_data_join(_DT_,_DA_(val));	}
 //-----------------------------------------------------------------------------
+mreal MGL_NO_EXPORT mgl_index_1(mreal v, const mglData *dat, mreal acx)
+{
+	long mx=dat->nx;
+	mreal d,d1=0,d2=mx-1,v1,v2;
+	v1 = mglSpline1t<mreal>(dat->a,mx,d1);
+	v2 = mglSpline1t<mreal>(dat->a,mx,d2);
+	long count=0;
+
+	if(v1==v)	return d1;
+	if(v2==v)	return d2;
+	if((v1-v)*(v2-v)>0)	return NAN;
+	do
+	{
+		d = count<10?(d2-d1)*(v-v1)/(v2-v1)+d1:(d1+d2)/2;	count++;
+		register mreal val = mglSpline1st<mreal>(dat->a,mx,d);
+		if(fabs(val-v)<acx)	break;
+		if((v1-v)*(val-v)<0)	{	v2=val;	d2=d;	}	else	{	v1=val;	d1=d;	}
+	} while(fabs(d2-d1)>1e-3);
+	return d;
+}
+//-----------------------------------------------------------------------------
+void MGL_EXPORT mgl_data_refill_x(HMDT dat, HCDT xdat, HCDT vdat, mreal x1, mreal x2, long sl)
+{
+	long nx=dat->nx,mx=vdat->GetNx(),nn=dat->ny*dat->nz;
+	mreal acx=1e-6*fabs(x2-x1);
+	const mglData *xxd=dynamic_cast<const mglData *>(xdat);
+	const mglData *vvd=dynamic_cast<const mglData *>(vdat);
+	if(!xxd || !vvd || mx!=xxd->nx)	return;	// incompatible dimensions and for mglData only
+#pragma omp parallel for
+	for(long i=0;i<nx;i++)
+	{
+		register mreal u = mgl_index_1(x1+(x2-x1)*i/(nx-1.),xxd,acx);
+		register mreal d = mglSpline1st<mreal>(vvd->a,mx,u);
+		if(sl<0)	for(long j=0;j<nn;j++)	dat->a[i+j*nx] = d;
+		else	dat->a[i+sl*nx] = d;
+	}
+}
+//-----------------------------------------------------------------------------
+mglPoint MGL_NO_EXPORT mgl_index_2(mreal x, mreal y, const mglData *xdat, const mglData *ydat, mreal acx, mreal acy)
+{
+	long mx=xdat->nx, my=xdat->ny;
+	mreal u=fabs(x),u1=0,u2=mx-1, v=fabs(y),v1=0,v2=my-1;
+	mreal x11 = mgl_data_spline(xdat,u1,v1,0), y11 = mgl_data_spline(ydat,u1,v1,0);
+	mreal x21 = mgl_data_spline(xdat,u2,v1,0), y21 = mgl_data_spline(ydat,u2,v1,0);
+	mreal x12 = mgl_data_spline(xdat,u1,v2,0), y12 = mgl_data_spline(ydat,u1,v2,0);
+	mreal x22 = mgl_data_spline(xdat,u2,v2,0), y22 = mgl_data_spline(ydat,u2,v2,0);
+	long count=0;
+
+	if(fabs(x11-x)<acx && fabs(y11-y)<acy)	return mglPoint(u1,v1);
+	if(fabs(x12-x)<acx && fabs(y12-y)<acy)	return mglPoint(u1,v2);
+	if(fabs(x21-x)<acx && fabs(y21-y)<acy)	return mglPoint(u2,v1);
+	if(fabs(x22-x)<acx && fabs(y22-y)<acy)	return mglPoint(u2,v2);
+	if((x11-x)*(x12-x)*(x21-x)*(x22-x)>0 && (x11-x)*(x12-x)*(x21-x)>0)	return mglPoint(NAN,NAN);
+	if((y11-y)*(y12-y)*(y21-y)*(y22-y)>0 && (y11-y)*(y12-y)*(y21-y)>0)	return mglPoint(NAN,NAN);
+
+	do
+	{
+		if(count<10)
+		{
+			register mreal dx0=x-x11, dx1=x21-x11, dx2=x12-x11, dx3=x22+x11-x12-x21;
+			register mreal dy0=y-y11, dy1=y21-y11, dy2=y12-y11, dy3=y22+y11-y12-y21;
+			register mreal t1 = dx0*dx0*dy3*dy3 + 2*dx0*dx1*dy2*dy3 + 2*dx0*dx2*dy1*dy3 - 
+								2*dx0*dx3*dy0*dy3 - 4*dx1*dx2*dy0*dy3 + dx1*dx1*dy2*dy2 - 
+								4*dx0*dx3*dy1*dy2 - 2*dx1*dx2*dy1*dy2 + 2*dx1*dx3*dy0*dy2 + 
+								dx2*dx2*dy1*dy1 + 2*dx2*dx3*dy0*dy1 + dx3*dx3*dy0*dy0, 
+							t2 = dx2*dy1+dx3*dy0-dx0*dy3-dx1*dy2, t3 = 2*(dx2*dy3-dx3*dy2);
+			if(t1<0 || t3==0)	{	count=10;	continue;	}
+			t1 = sqrt(t1);	v = (t2-t1)/t3;
+			if(v<0 || v>1)	v = (t2+t1)/t3;
+			u = (dx0-dx2*v)/(dx1+dx3*v);
+			if(u<0 || v<0 || u>1 || v>1)	{	count=10;	continue;	}
+			u = u1+(u2-u1)*u;	v = v1+(v2-v1)*v;	count++;
+		}
+		else	{	u = (u1+u2)/2;	v = (v1+v2)/2;	}
+
+		mreal tx  = mgl_data_spline(xdat,u,v,0),  ty  = mgl_data_spline(ydat,u,v,0);
+		if(fabs(tx-x)<acx && fabs(ty-y)<acy)	break;
+		mreal tx1 = mgl_data_spline(xdat,u1,v,0), ty1 = mgl_data_spline(ydat,u1,v,0);
+		if(fabs(tx1-x)<acx && fabs(ty1-y)<acy)	{u=u1;	break;}
+		mreal tx2 = mgl_data_spline(xdat,u2,v,0), ty2 = mgl_data_spline(ydat,u2,v,0);
+		if(fabs(tx2-x)<acx && fabs(ty2-y)<acy)	{u=u2;	break;}
+		mreal sx1 = mgl_data_spline(xdat,u,v1,0), sy1 = mgl_data_spline(ydat,u,v1,0);
+		if(fabs(sx1-x)<acx && fabs(sy1-y)<acy)	{v=v1;	break;}
+		mreal sx2 = mgl_data_spline(xdat,u,v2,0), sy2 = mgl_data_spline(ydat,u,v2,0);
+		if(fabs(sx2-x)<acx && fabs(sy2-y)<acy)	{v=v2;	break;}
+		if( ((x11-x)*(sx1-x)*(tx1-x)*(tx-x)>0 || (x11-x)*(sx1-x)*(tx1-x)>0) && ((y11-y)*(sy1-y)*(ty1-y)*(ty-y)>0 && (y11-y)*(sy1-y)*(ty1-y)>0) )
+		{	x12 = tx1;	y12 = ty1;	x21 = sx1;	y21 = sy1;	x22 = tx;	y22 = ty;	u2 = u;	v2 = v;	}
+		if( ((tx1-x)*(tx-x)*(x12-x)*(sx2-x)>0 || (tx1-x)*(tx-x)*(x12-x)>0) && ((ty1-y)*(ty-y)*(y12-y)*(sy2-y)>0 && (ty1-y)*(ty-y)*(y12-y)>0) )
+		{	x11 = tx1;	y11 = ty1;	x21 = tx;	y21 = ty;	x22 = sx2;	y22 = sy2;	u2 = u;	v1 = v;	}
+		if( ((tx-x)*(sx2-x)*(tx2-x)*(x22-x)>0 || (tx-x)*(sx2-x)*(tx2-x)>0) && ((ty-y)*(sy2-y)*(ty2-y)*(y22-y)>0 && (ty-y)*(sy2-y)*(ty2-y)>0) )
+		{	x11 = tx;	y11 = ty;	x12 = sx2;	y12 = sy2;	x21 = tx2;	y21 = ty2;	u1 = u;	v1 = v;	}
+		if( ((sx1-x)*(tx-x)*(x21-x)*(tx2-x)>0 || (sx1-x)*(tx-x)*(x21-x)>0) && ((sy1-y)*(ty-y)*(y21-y)*(ty2-y)>0 && (sy1-y)*(ty-y)*(y21-y)>0) )
+		{	x11 = sx1;	y11 = sy1;	x12 = tx;	y12 = ty;	x22 = tx2;	y22 = ty2;	u1 = u;	v2 = v;	}
+	} while(fabs(u2-u1)>1e-3 || fabs(v2-v1)>1e-3);
+	return mglPoint(u,v);
+}
+//-----------------------------------------------------------------------------
+void MGL_EXPORT mgl_data_refill_xy(HMDT dat, HCDT xdat, HCDT ydat, HCDT vdat, mreal x1, mreal x2, mreal y1, mreal y2, long sl)
+{
+	long nx=dat->nx,ny=dat->ny,nz=dat->nz,mx=vdat->GetNx(),my=vdat->GetNy(),nn=nx*ny;
+	const mglData *xxd=dynamic_cast<const mglData *>(xdat);
+	const mglData *yyd=dynamic_cast<const mglData *>(ydat);
+	const mglData *vvd=dynamic_cast<const mglData *>(vdat);
+	if(!xxd || !vvd || !yyd)	return;	// for mglData only
+	bool both=(xdat->GetNN()==vdat->GetNN() && ydat->GetNN()==vdat->GetNN());
+	if(!both && (xdat->GetNx()!=mx || ydat->GetNx()!=my))	return;	// incompatible dimensions
+	mreal acx=1e-6*fabs(x2-x1), acy=1e-6*fabs(y2-y1);
+	if(both)
+		mgl_data_grid_xy(dat,xdat,ydat,vdat,x1,x2,y1,y2);
+/*#pragma omp parallel for collapse(2)
+		for(long j=0;j<ny;j++)	for(long i=0;i<nx;i++)	// NOTE: too slow
+		{
+			mglPoint p = mgl_index_2(x1+(x2-x1)*i/(nx-1.), y1+(y2-y1)*j/(ny-1.),xxd,yyd,acx,acy);
+			register mreal d = mgl_isnan(p.x)?NAN:mgl_data_spline(vdat,p.x,p.y,0);
+			register long i0=i+nx*j;
+			if(sl<0)	for(long k=0;k<nz;k++)	dat->a[i0+k*nn] = d;
+			else	dat->a[i0+sl*nn] = d;
+		}*/
+	else
+	{
+		mglData u(nx), v(ny);
+#pragma omp parallel for
+		for(long i=0;i<nx;i++)	u.a[i] = mgl_index_1(x1+(x2-x1)*i/(nx-1.),xxd,acx);
+#pragma omp parallel for
+		for(long i=0;i<ny;i++)	v.a[i] = mgl_index_1(y1+(y2-y1)*i/(ny-1.),yyd,acy);
+#pragma omp parallel for collapse(2)
+		for(long j=0;j<ny;j++)	for(long i=0;i<nx;i++)
+		{
+			register mreal d = mgl_data_spline(vdat,u.a[i],v.a[j],0);
+			register long i0=i+nx*j;
+			if(sl<0)	for(long k=0;k<nz;k++)	dat->a[i0+k*nn] = d;
+			else	dat->a[i0+sl*nn] = d;
+		}
+	}
+}
+//-----------------------------------------------------------------------------
+void MGL_EXPORT mgl_data_refill_xyz(HMDT dat, HCDT xdat, HCDT ydat, HCDT zdat, HCDT vdat, mreal x1, mreal x2, mreal y1, mreal y2, mreal z1, mreal z2)
+{
+	long nx=dat->nx,ny=dat->ny,nz=dat->nz,mx=vdat->GetNx(),my=vdat->GetNy(),mz=vdat->GetNz();
+	const mglData *xxd=dynamic_cast<const mglData *>(xdat);
+	const mglData *yyd=dynamic_cast<const mglData *>(ydat);
+	const mglData *zzd=dynamic_cast<const mglData *>(zdat);
+	const mglData *vvd=dynamic_cast<const mglData *>(vdat);
+	if(!xxd || !vvd || !yyd || !zzd)	return;	// for mglData only
+	bool both=(xdat->GetNN()==vdat->GetNN() && ydat->GetNN()==vdat->GetNN() && zdat->GetNN()==vdat->GetNN());
+	if(!both && (xdat->GetNx()!=mx || ydat->GetNx()!=my || zdat->GetNx()!=mz))	return;	// incompatible dimensions
+	mreal acx=1e-6*fabs(x2-x1), acy=1e-6*fabs(y2-y1), acz=1e-6*fabs(z2-z1);
+	if(both)
+#pragma omp parallel for collapse(3)
+		for(long k=0;k<nz;k++)	for(long j=0;j<ny;j++)	for(long i=0;i<nx;i++)
+		{
+			mreal xx = x1+(x2-x1)*i/(nx-1.),dxx,dxy,dxz,vx,dx=0,dd;
+			mreal yy = y1+(y2-y1)*j/(ny-1.),dyx,dyy,dyz,vy,dy=0;
+			mreal zz = z1+(z2-z1)*k/(nz-1.),dzx,dzy,dzz,vz,dz=0;
+			vx = mgl_data_spline_ext(xdat,dx,dy,dz,&dxx,&dxy,&dxz);
+			vy = mgl_data_spline_ext(ydat,dx,dy,dz,&dyx,&dyy,&dyz);
+			vz = mgl_data_spline_ext(zdat,dx,dy,dz,&dzx,&dzy,&dzz);
+			long count=0;
+			do	// use Newton method to find root
+			{
+				if(count>50)	{	dx=NAN;	break;	}	count++;
+				dd = -dxx*dyy*dzz+dxy*dyx*dzz+dxx*dyz*dzy-dxz*dyx*dzy-dxy*dyz*dzx+dxz*dyy*dzx;
+				dx += ((dyz*dzy-dyy*dzz)*(xx-vx)+(dxy*dzz-dxz*dzy)*(yy-vy)+(dxz*dyy-dxy*dyz)*(zz-vz))/dd;
+				dy += ((dyx*dzz-dyz*dzx)*(xx-vx)+(dxz*dzx-dxx*dzz)*(yy-vy)+(dxx*dyz-dxz*dyx)*(zz-vz))/dd;
+				dz += ((dyy*dzx-dyx*dzy)*(xx-vx)+(dxx*dzy-dxy*dzx)*(yy-vy)+(dxy*dyx-dxx*dyy)*(zz-vz))/dd;
+				vx = mgl_data_spline_ext(xdat,dx,dy,dz,&dxx,&dxy,&dxz);
+				vy = mgl_data_spline_ext(ydat,dx,dy,dz,&dyx,&dyy,&dyz);
+				vz = mgl_data_spline_ext(zdat,dx,dy,dz,&dzx,&dzy,&dzz);
+			}	while(fabs(xx-vx)>acx && fabs(yy-vy)>acy && fabs(zz-vz)>acz);	// this valid for linear interpolation
+			dat->a[i+nx*(j+ny*k)] = mgl_isnan(dx)?NAN:mgl_data_spline(vdat,dx,dy,dz);
+		}
+	else
+	{
+		mglData u(nx), v(ny), w(nz);
+#pragma omp parallel for
+		for(long i=0;i<nx;i++)	u.a[i] = mgl_index_1(x1+(x2-x1)*i/(nx-1.),xxd,acx);
+#pragma omp parallel for
+		for(long i=0;i<ny;i++)	v.a[i] = mgl_index_1(y1+(y2-y1)*i/(ny-1.),yyd,acy);
+#pragma omp parallel for
+		for(long i=0;i<nz;i++)	w.a[i] = mgl_index_1(z1+(z2-z1)*i/(nz-1.),zzd,acz);
+#pragma omp parallel for collapse(3)
+		for(long k=0;k<nz;k++)	for(long j=0;j<ny;j++)	for(long i=0;i<nx;i++)
+			dat->a[i+nx*(j+ny*k)] = mgl_data_spline(vdat,u.a[i],v.a[j],w.a[k]);
+	}
+}
+//-----------------------------------------------------------------------------
+MGL_NO_EXPORT void *mgl_eval(void *par)
+{
+	mglThreadD *t=(mglThreadD *)par;
+	long nx=t->p[0], ny=t->p[1], nz=t->p[2], n1=t->p[3], nn=t->n;
+	const mreal *a=t->b, *ii=t->c, *jj=t->d, *kk=t->e;
+	mreal *b=t->a;
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i=t->id;i<nn;i+=mglNumThr)
+	{
+		register mreal x=ii?ii[i]:0, y=jj?jj[i]:0, z=kk?kk[i]:0;
+		if(n1)	{	x*=nx-1;	y*=ny-1;	z*=nz-1;	}
+		b[i] = x*y*z==x*y*z ? mglSpline3st<mreal>(a,nx,ny,nz,x,y,z):NAN;
+	}
+	return 0;
+}
+MGL_NO_EXPORT void *mgl_eval_s(void *par)
+{
+	mglThreadD *t=(mglThreadD *)par;
+	long nx=t->p[0], ny=t->p[1], nz=t->p[2], n1=t->p[3], nn=t->n;
+	const mreal *ii=t->c, *jj=t->d, *kk=t->e;
+	HCDT a = (HCDT)t->v;
+	mreal *b=t->a;
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i=t->id;i<nn;i+=mglNumThr)
+	{
+		register mreal x=ii?ii[i]:0, y=jj?jj[i]:0, z=kk?kk[i]:0;
+		if(n1)	{	x*=nx-1;	y*=ny-1;	z*=nz-1;	}
+		b[i] = x*y*z==x*y*z ? mgl_data_linear(a, x,y,z):NAN;
+	}
+	return 0;
+}
+HMDT MGL_EXPORT mgl_data_evaluate(HCDT dat, HCDT idat, HCDT jdat, HCDT kdat, int norm)
+{
+	const mglData *d=dynamic_cast<const mglData *>(dat);
+	const mglData *i=dynamic_cast<const mglData *>(idat);
+	const mglData *j=dynamic_cast<const mglData *>(jdat);
+	const mglData *k=dynamic_cast<const mglData *>(kdat);
+	if(!i)	return 0;
+
+	long p[4]={dat->GetNx(), dat->GetNy(), dat->GetNz(),norm};
+	register long n=i->nx*i->ny*i->nz;
+	if(j && j->nx*j->ny*j->nz!=n)	return 0;
+	if(k && k->nx*k->ny*k->nz!=n)	return 0;
+	mglData *r=new mglData(i->nx,i->ny,i->nz);
+	if(d)	mglStartThread(mgl_eval,0,n,r->a,d->a,i->a,p,0,j?j->a:0,k?k->a:0);
+	else 	mglStartThread(mgl_eval_s,0,n,r->a,0,i->a,p,dat,j?j->a:0,k?k->a:0);
+	return r;
+}
+uintptr_t MGL_EXPORT mgl_data_evaluate_(uintptr_t *d, uintptr_t *idat, uintptr_t *jdat, uintptr_t *kdat, int *norm)
+{	return uintptr_t(mgl_data_evaluate(_DT_,_DA_(idat),_DA_(jdat),_DA_(kdat),*norm));	}
+//-----------------------------------------------------------------------------
diff --git a/src/data_new.cpp b/src/data_ex.cpp
similarity index 71%
rename from src/data_new.cpp
rename to src/data_ex.cpp
index c552819..a5d3c3e 100644
--- a/src/data_new.cpp
+++ b/src/data_ex.cpp
@@ -20,15 +20,21 @@
 #include <ctype.h>
 #include "mgl2/data.h"
 #include "mgl2/eval.h"
+#include "mgl2/thread.h"
 //-----------------------------------------------------------------------------
 HMDT MGL_EXPORT mgl_data_trace(HCDT d)
 {
 	long nx=d->GetNx(),ny=d->GetNy(),nz=d->GetNz();
 	mglData *r=new mglData(nx);
-	register long i;
-	if(ny>=nx && nz>=nx)	for(i=0;i<nx;i++)	r->a[i] = d->v(i,i,i);
-	else if(ny>=nx)		for(i=0;i<nx;i++)	r->a[i] = d->v(i,i);
-	else		for(i=0;i<nx;i++)	r->a[i] = d->v(i);
+	if(ny>=nx && nz>=nx)
+#pragma omp parallel for
+		for(long i=0;i<nx;i++)	r->a[i] = d->v(i,i,i);
+	else if(ny>=nx)
+#pragma omp parallel for
+		for(long i=0;i<nx;i++)	r->a[i] = d->v(i,i);
+	else
+#pragma omp parallel for
+		for(long i=0;i<nx;i++)	r->a[i] = d->v(i);
 	return r;
 }
 uintptr_t MGL_EXPORT mgl_data_trace_(uintptr_t *d)
@@ -36,62 +42,62 @@ uintptr_t MGL_EXPORT mgl_data_trace_(uintptr_t *d)
 //-----------------------------------------------------------------------------
 HMDT MGL_EXPORT mgl_data_subdata_ext(HCDT d, HCDT xx, HCDT yy, HCDT zz)
 {
-	long n=0,m=0,l=0,i,j,k,i0;
-	mreal x,y,z;
-	mglData *r=new mglData;
+	long n=0,m=0,l=0,j,k;
 	bool ix=false, iy=false, iz=false;
 	if(xx->GetNz()>1)	// 3d data
 	{
 		n = xx->GetNx();	m = xx->GetNy();	l = xx->GetNz();
-		j = yy->GetNx()*yy->GetNy()*yy->GetNz();	if(j>1 && j!=n*m*l)	return r;	// wrong sizes
-		k = zz->GetNx()*zz->GetNy()*zz->GetNz();	if(k>1 && k!=n*m*l)	return r;	// wrong sizes
+		j = yy->GetNx()*yy->GetNy()*yy->GetNz();	if(j>1 && j!=n*m*l)	return 0;	// wrong sizes
+		k = zz->GetNx()*zz->GetNy()*zz->GetNz();	if(k>1 && k!=n*m*l)	return 0;	// wrong sizes
 		ix = true;	iy = j>1;	iz = k>1;
 	}
 	else if(yy->GetNz()>1)
 	{
 		n = yy->GetNx();	m = yy->GetNy();	l = yy->GetNz();
-		j = xx->GetNx()*xx->GetNy()*xx->GetNz();	if(j>1 && j!=n*m*l)	return r;	// wrong sizes
-		k = zz->GetNx()*zz->GetNy()*zz->GetNz();	if(k>1 && k!=n*m*l)	return r;	// wrong sizes
+		j = xx->GetNx()*xx->GetNy()*xx->GetNz();	if(j>1 && j!=n*m*l)	return 0;	// wrong sizes
+		k = zz->GetNx()*zz->GetNy()*zz->GetNz();	if(k>1 && k!=n*m*l)	return 0;	// wrong sizes
 		iy = true;	ix = j>1;	iz = k>1;
 	}
 	else if(zz->GetNz()>1)
 	{
 		n = zz->GetNx();	m = zz->GetNy();	l = zz->GetNz();
-		j = yy->GetNx()*yy->GetNy()*yy->GetNz();	if(j>1 && j!=n*m*l)	return r;	// wrong sizes
-		k = xx->GetNx()*xx->GetNy()*xx->GetNz();	if(k>1 && k!=n*m*l)	return r;	// wrong sizes
+		j = yy->GetNx()*yy->GetNy()*yy->GetNz();	if(j>1 && j!=n*m*l)	return 0;	// wrong sizes
+		k = xx->GetNx()*xx->GetNy()*xx->GetNz();	if(k>1 && k!=n*m*l)	return 0;	// wrong sizes
 		iz = true;	iy = j>1;	ix = k>1;
 	}
 	else if(xx->GetNy()>1)	// 2d data
 	{
 		n = xx->GetNx();	m = xx->GetNy();	l = 1;
-		j = yy->GetNx()*yy->GetNy();	if(j>1 && j!=n*m)	return r;	// wrong sizes
-		k = zz->GetNx()*zz->GetNy();	if(k>1 && k!=n*m)	return r;	// wrong sizes
+		j = yy->GetNx()*yy->GetNy();	if(j>1 && j!=n*m)	return 0;	// wrong sizes
+		k = zz->GetNx()*zz->GetNy();	if(k>1 && k!=n*m)	return 0;	// wrong sizes
 		ix = true;	iy = j>1;	iz = k>1;
 	}
 	else if(yy->GetNy()>1)
 	{
 		n = yy->GetNx();	m = yy->GetNy();	l = 1;
-		j = xx->GetNx()*xx->GetNy();	if(j>1 && j!=n*m)	return r;	// wrong sizes
-		k = zz->GetNx()*zz->GetNy();	if(k>1 && k!=n*m)	return r;	// wrong sizes
+		j = xx->GetNx()*xx->GetNy();	if(j>1 && j!=n*m)	return 0;	// wrong sizes
+		k = zz->GetNx()*zz->GetNy();	if(k>1 && k!=n*m)	return 0;	// wrong sizes
 		iy = true;	ix = j>1;	iz = k>1;
 	}
 	else if(zz->GetNy()>1)
 	{
 		n = zz->GetNx();	m = zz->GetNy();	l = 1;
-		j = yy->GetNx()*yy->GetNy();	if(j>1 && j!=n*m)	return r;	// wrong sizes
-		k = xx->GetNx()*xx->GetNy();	if(k>1 && k!=n*m)	return r;	// wrong sizes
+		j = yy->GetNx()*yy->GetNy();	if(j>1 && j!=n*m)	return 0;	// wrong sizes
+		k = xx->GetNx()*xx->GetNy();	if(k>1 && k!=n*m)	return 0;	// wrong sizes
 		iz = true;	iy = j>1;	ix = k>1;
 	}
 	long nx=d->GetNx(),ny=d->GetNy(),nz=d->GetNz();
 	mreal vx=xx->v(0), vy=yy->v(0), vz=zz->v(0);
+	mglData *r=new mglData;
 	if(n*m*l>1)	// this is 2d or 3d data
 	{
 		r->Create(n,m,l);
-		for(i0=0;i0<n*m*l;i0++)
+#pragma omp parallel for
+		for(long i0=0;i0<n*m*l;i0++)
 		{
-			x = ix?xx->vthr(i0):vx;
-			y = iy?yy->vthr(i0):vy;
-			z = iz?zz->vthr(i0):vz;
+			register mreal x = ix?xx->vthr(i0):vx;
+			register mreal y = iy?yy->vthr(i0):vy;
+			register mreal z = iz?zz->vthr(i0):vz;
 			r->a[i0] = mgl_data_linear(d,x,y,z);
 		}
 		return r;
@@ -104,9 +110,10 @@ HMDT MGL_EXPORT mgl_data_subdata_ext(HCDT d, HCDT xx, HCDT yy, HCDT zz)
 	if(zz->GetNx()>1 || vz>=0)	{	l=zz->GetNx();	iz=true;	}
 	else	{	l=nz;	iz=false;	}
 	r->Create(n,m,l);
-	for(k=0;k<l;k++)	for(j=0;j<m;j++)	for(i=0;i<n;i++)
+#pragma omp parallel for collapse(3)
+	for(long k=0;k<l;k++)	for(long j=0;j<m;j++)	for(long i=0;i<n;i++)
 	{
-		x = ix?xx->v(i):i;	y = iy?yy->v(j):j;	z = iz?zz->v(k):k;
+		register mreal x = ix?xx->v(i):i, y = iy?yy->v(j):j, z = iz?zz->v(k):k;
 		r->a[i+n*(j+m*k)] = mgl_data_linear(d,x,y,z);
 	}
 	if(m==1)	{	r->ny=r->nz;	r->nz=1;	}// "squeeze" dimensions
@@ -130,13 +137,16 @@ MGL_NO_EXPORT void *mgl_column(void *par)
 {
 	mglThreadD *t=(mglThreadD *)par;
 	const mglFormula *f = (const mglFormula *)t->v;
-	register long i,j, nx=t->p[0];
+	long nx=t->p[0];
 	mreal *b=t->a, var[MGL_VS];
 	const mreal *a=t->b;
 	memset(var,0,('z'-'a')*sizeof(mreal));
-	for(i=t->id;i<t->n;i+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i=t->id;i<t->n;i+=mglNumThr)
 	{
-		for(j=0;j<nx;j++)
+		for(long j=0;j<nx;j++)
 			if(t->s[j]>='a' && t->s[j]<='z')
 				var[t->s[j]-'a'] = a[j+nx*i];
 		b[i] = f->Calc(var);
@@ -160,24 +170,28 @@ uintptr_t MGL_EXPORT mgl_data_column_(uintptr_t *d, const char *eq,int l)
 MGL_NO_EXPORT void *mgl_resize(void *par)
 {
 	mglThreadD *t=(mglThreadD *)par;
-	register long i,j,k,i0, nx=t->p[0]+0.1, ny=t->p[1]+0.1;
+	long nx=t->p[0]+0.1, ny=t->p[1]+0.1;
 	long n1=t->p[3]+0.1,n2=t->p[4]+0.1,n3=t->p[5]+0.1;
 	mreal *b=t->a;
 	const mreal *a=t->b, *c=t->c;
-	for(i0=t->id;i0<t->n;i0+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i0=t->id;i0<t->n;i0+=mglNumThr)
 	{
-		i=i0%nx;	j=((i0/nx)%ny);	k=i0/(nx*ny);
+		register long i=i0%nx, j=((i0/nx)%ny), k=i0/(nx*ny);
 		b[i0] = mglSpline3(a,n1,n2,n3, c[0]+i*c[1], c[2]+j*c[3], c[4]+k*c[5]);
 	}
 	return 0;
 }
 HMDT MGL_EXPORT mgl_data_resize_box(HCDT dat, long mx,long my,long mz, mreal x1,mreal x2, mreal y1,mreal y2, mreal z1,mreal z2)
 {	// NOTE: only for mglData (for speeding up)
-	mx = mx<1 ? 1:mx;	my = my<1 ? 1:my;	mz = mz<1 ? 1:mz;
-	mglData *r=new mglData(mx,my,mz);
 	const mglData *d=dynamic_cast<const mglData *>(dat);
-	if(!d)	return r;
+	if(!d)	return 0;
 	register long nx = d->nx-1, ny = d->ny-1, nz = d->nz-1;
+	mx = mx<1 ? nx+1:mx;	my = my<1 ? ny+1:my;	mz = mz<1 ? nz+1:mz;
+	mglData *r=new mglData(mx,my,mz);
+
 	mreal par[6]={nx*x1,0,ny*y1,0,nz*z1,0};
 	long nn[6]={mx,my,mz,nx+1,ny+1,nz+1};
 	if(mx>1)	par[1] = nx*(x2-x1)/(mx-1);
@@ -196,10 +210,13 @@ uintptr_t MGL_EXPORT mgl_data_resize_box_(uintptr_t *d, int *mx,int *my,int *mz,
 MGL_NO_EXPORT void *mgl_combine(void *par)
 {
 	mglThreadD *t=(mglThreadD *)par;
-	register long i0, nx=t->p[0];
+	long nx=t->p[0];
 	mreal *b=t->a;
 	const mreal *c=t->b, *d=t->c;
-	for(i0=t->id;i0<t->n;i0+=mglNumThr)	b[i0] = c[i0%nx]*d[i0/nx];
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i0=t->id;i0<t->n;i0+=mglNumThr)	b[i0] = c[i0%nx]*d[i0/nx];
 	return 0;
 }
 HMDT MGL_EXPORT mgl_data_combine(HCDT d1, HCDT d2)
@@ -207,8 +224,8 @@ HMDT MGL_EXPORT mgl_data_combine(HCDT d1, HCDT d2)
 	const mglData *a=dynamic_cast<const mglData *>(d1);
 	const mglData *b=dynamic_cast<const mglData *>(d2);
 
+	if(!a || !b || a->nz>1 || (a->ny>1 && b->ny>1) || b->nz>1)	return 0;
 	mglData *r=new mglData;
-	if(a->nz>1 || (a->ny>1 && b->ny>1) || b->nz>1)	return r;
 	long n1=a->ny,n2=b->nx;
 	bool dim2=true;
 	if(a->ny==1)	{	n1=b->nx;	n2=b->ny;	dim2 = false;	}
@@ -223,12 +240,16 @@ uintptr_t MGL_EXPORT mgl_data_combine_(uintptr_t *a, uintptr_t *b)
 MGL_NO_EXPORT void *mgl_sum_z(void *par)
 {
 	mglThreadD *t=(mglThreadD *)par;
-	register long i,j, nz=t->p[2], nn=t->n;
+	long nz=t->p[2], nn=t->n;
 	mreal *b=t->a;
 	const mreal *a=t->b;
-	for(i=t->id;i<nn;i+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i=t->id;i<nn;i+=mglNumThr)
 	{
-		for(j=0,b[i]=0;j<nz;j++)	b[i] += a[i+nn*j];
+		b[i]=0;
+		for(long j=0;j<nz;j++)	b[i] += a[i+nn*j];
 		b[i] /= nz;
 	}
 	return 0;
@@ -236,13 +257,16 @@ MGL_NO_EXPORT void *mgl_sum_z(void *par)
 MGL_NO_EXPORT void *mgl_sum_y(void *par)
 {
 	mglThreadD *t=(mglThreadD *)par;
-	register long i,j,k, nx=t->p[0], ny=t->p[1], nn=t->n;
+	long nx=t->p[0], ny=t->p[1], nn=t->n;
 	mreal *b=t->a;
 	const mreal *a=t->b;
-	for(i=t->id;i<nn;i+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i=t->id;i<nn;i+=mglNumThr)
 	{
-		k = (i%nx)+nx*ny*(i/nx);
-		for(j=0,b[i]=0;j<ny;j++)	b[i] += a[k+nx*j];
+		register long k = (i%nx)+nx*ny*(i/nx);	b[i]=0;
+		for(long j=0;j<ny;j++)	b[i] += a[k+nx*j];
 		b[i] /= ny;
 	}
 	return 0;
@@ -250,13 +274,16 @@ MGL_NO_EXPORT void *mgl_sum_y(void *par)
 MGL_NO_EXPORT void *mgl_sum_x(void *par)
 {
 	mglThreadD *t=(mglThreadD *)par;
-	register long i,j,k, nx=t->p[0], nn=t->n;
+	long nx=t->p[0], nn=t->n;
 	mreal *b=t->a;
 	const mreal *a=t->b;
-	for(i=t->id;i<nn;i+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i=t->id;i<nn;i+=mglNumThr)
 	{
-		k = i*nx;
-		for(j=0,b[i]=0;j<nx;j++)	b[i] += a[j+k];
+		register long k = i*nx;	b[i]=0;
+		for(long j=0;j<nx;j++)	b[i] += a[j+k];
 		b[i] /= nx;
 	}
 	return 0;
@@ -271,7 +298,9 @@ HMDT MGL_EXPORT mgl_data_sum(HCDT dat, const char *dir)
 
 	const mglData *d=dynamic_cast<const mglData *>(dat);
 	if(d)	memcpy(c,d->a,nx*ny*nz*sizeof(mreal));
-	else	for(long i=0;i<nx*ny*nz;i++)	c[i]=dat->vthr(i);
+	else
+#pragma omp parallel for
+		for(long i=0;i<nx*ny*nz;i++)	c[i]=dat->vthr(i);
 
 	if(strchr(dir,'z') && nz>1)
 	{
@@ -299,36 +328,48 @@ uintptr_t MGL_EXPORT mgl_data_sum_(uintptr_t *d, const char *dir,int l)
 MGL_NO_EXPORT void *mgl_max_z(void *par)
 {
 	mglThreadD *t=(mglThreadD *)par;
-	register long i,j, nz=t->p[2], nn=t->n;
+	long nz=t->p[2], nn=t->n;
 	mreal *b=t->a;
 	const mreal *a=t->b;
-	for(i=t->id;i<nn;i+=mglNumThr)
-		for(j=1,b[i]=a[i];j<nz;j++)	if(b[i]<a[i+nn*j]) b[i] = a[i+nn*j];
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i=t->id;i<nn;i+=mglNumThr)
+	{
+		b[i]=a[i];
+		for(long j=1;j<nz;j++)	if(b[i]<a[i+nn*j]) b[i] = a[i+nn*j];
+	}
 	return 0;
 }
 MGL_NO_EXPORT void *mgl_max_y(void *par)
 {
 	mglThreadD *t=(mglThreadD *)par;
-	register long i,j,k, nx=t->p[0], ny=t->p[1], nn=t->n;
+	long nx=t->p[0], ny=t->p[1], nn=t->n;
 	mreal *b=t->a;
 	const mreal *a=t->b;
-	for(i=t->id;i<nn;i+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i=t->id;i<nn;i+=mglNumThr)
 	{
-		k = (i%nx)+nx*ny*(i/nx);
-		for(j=1,b[i]=a[k];j<ny;j++)	if(b[i]<a[k+nx*j])	b[i]=a[k+nx*j];
+		register long k = (i%nx)+nx*ny*(i/nx);	b[i]=a[k];
+		for(long j=1;j<ny;j++)	if(b[i]<a[k+nx*j])	b[i]=a[k+nx*j];
 	}
 	return 0;
 }
 MGL_NO_EXPORT void *mgl_max_x(void *par)
 {
 	mglThreadD *t=(mglThreadD *)par;
-	register long i,j,k, nx=t->p[0], nn=t->n;
+	long nx=t->p[0], nn=t->n;
 	mreal *b=t->a;
 	const mreal *a=t->b;
-	for(i=t->id;i<nn;i+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i=t->id;i<nn;i+=mglNumThr)
 	{
-		k = i*nx;
-		for(j=1,b[i]=a[k];j<nx;j++)	if(b[i]<a[j+k])	b[i]=a[j+k];
+		register long k = i*nx;	b[i]=a[k];
+		for(long j=1;j<nx;j++)	if(b[i]<a[j+k])	b[i]=a[j+k];
 	}
 	return 0;
 }
@@ -342,7 +383,9 @@ HMDT MGL_EXPORT mgl_data_max_dir(HCDT dat, const char *dir)
 
 	const mglData *d=dynamic_cast<const mglData *>(dat);
 	if(d)	memcpy(c,d->a,nx*ny*nz*sizeof(mreal));
-	else	for(long i=0;i<nx*ny*nz;i++)	c[i]=dat->vthr(i);
+	else
+#pragma omp parallel for
+		for(long i=0;i<nx*ny*nz;i++)	c[i]=dat->vthr(i);
 
 	if(strchr(dir,'z') && nz>1)
 	{
@@ -370,36 +413,48 @@ uintptr_t MGL_EXPORT mgl_data_max_dir_(uintptr_t *d, const char *dir,int l)
 MGL_NO_EXPORT void *mgl_min_z(void *par)
 {
 	mglThreadD *t=(mglThreadD *)par;
-	register long i,j, nz=t->p[2], nn=t->n;
+	long nz=t->p[2], nn=t->n;
 	mreal *b=t->a;
 	const mreal *a=t->b;
-	for(i=t->id;i<nn;i+=mglNumThr)
-		for(j=1,b[i]=a[i];j<nz;j++)	if(b[i]>a[i+nn*j]) b[i] = a[i+nn*j];
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i=t->id;i<nn;i+=mglNumThr)
+	{
+		b[i]=a[i];
+		for(long j=1;j<nz;j++)	if(b[i]>a[i+nn*j]) b[i] = a[i+nn*j];
+	}
 	return 0;
 }
 MGL_NO_EXPORT void *mgl_min_y(void *par)
 {
 	mglThreadD *t=(mglThreadD *)par;
-	register long i,j,k, nx=t->p[0], ny=t->p[1], nn=t->n;
+	long nx=t->p[0], ny=t->p[1], nn=t->n;
 	mreal *b=t->a;
 	const mreal *a=t->b;
-	for(i=t->id;i<nn;i+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i=t->id;i<nn;i+=mglNumThr)
 	{
-		k = (i%nx)+nx*ny*(i/nx);
-		for(j=1,b[i]=a[k];j<ny;j++)	if(b[i]>a[k+nx*j])	b[i]=a[k+nx*j];
+		register long k = (i%nx)+nx*ny*(i/nx);	b[i]=a[k];
+		for(long j=1;j<ny;j++)	if(b[i]>a[k+nx*j])	b[i]=a[k+nx*j];
 	}
 	return 0;
 }
 MGL_NO_EXPORT void *mgl_min_x(void *par)
 {
 	mglThreadD *t=(mglThreadD *)par;
-	register long i,j,k, nx=t->p[0], nn=t->n;
+	long nx=t->p[0], nn=t->n;
 	mreal *b=t->a;
 	const mreal *a=t->b;
-	for(i=t->id;i<nn;i+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i=t->id;i<nn;i+=mglNumThr)
 	{
-		k = i*nx;
-		for(j=1,b[i]=a[k];j<nx;j++)	if(b[i]>a[j+k])	b[i]=a[j+k];
+		register long k = i*nx;	b[i]=a[k];
+		for(long j=1;j<nx;j++)	if(b[i]>a[j+k])	b[i]=a[j+k];
 	}
 	return 0;
 }
@@ -413,7 +468,9 @@ HMDT MGL_EXPORT mgl_data_min_dir(HCDT dat, const char *dir)
 
 	const mglData *d=dynamic_cast<const mglData *>(dat);
 	if(d)	memcpy(c,d->a,nx*ny*nz*sizeof(mreal));
-	else	for(long i=0;i<nx*ny*nz;i++)	c[i]=dat->vthr(i);
+	else
+#pragma omp parallel for
+		for(long i=0;i<nx*ny*nz;i++)	c[i]=dat->vthr(i);
 
 	if(strchr(dir,'z') && nz>1)
 	{
@@ -441,18 +498,20 @@ uintptr_t MGL_EXPORT mgl_data_min_dir_(uintptr_t *d, const char *dir,int l)
 MGL_NO_EXPORT void *mgl_mom_z(void *par)
 {
 	mglThreadD *t=(mglThreadD *)par;
-	register long i,j,k,ii;
 	long nx=t->p[0], ny=t->p[1], nz=t->p[2], nn=t->n;
-	mreal *b=t->a, i0,i1,x,y,z;
+	mreal *b=t->a;
 	const mreal *a=t->b;
 	const mglFormula *eq = (const mglFormula *)t->v;
-	for(i=t->id;i<nn;i+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i=t->id;i<nn;i+=mglNumThr)
 	{
-		i0 = i1 = 0;
-		for(k=0;k<nx;k++)	for(j=0;j<ny;j++)
+		register mreal i0 = 0, i1 = 0;
+		for(long k=0;k<nx;k++)	for(long j=0;j<ny;j++)
 		{
-			ii = k+nx*(j+ny*i);
-			x = k/(nx-1.);	y = j/(ny-1.);	z = i/(nz-1.);
+			register long ii = k+nx*(j+ny*i);
+			register mreal x = k/(nx-1.), y = j/(ny-1.), z = i/(nz-1.);
 			i0+= a[ii];
 			i1+= a[ii]*eq->Calc(x,y,z,a[ii]);
 		}
@@ -463,18 +522,20 @@ MGL_NO_EXPORT void *mgl_mom_z(void *par)
 MGL_NO_EXPORT void *mgl_mom_y(void *par)
 {
 	mglThreadD *t=(mglThreadD *)par;
-	register long i,j,k,ii;
 	long nx=t->p[0], ny=t->p[1], nz=t->p[2], nn=t->n;
-	mreal *b=t->a, i0,i1,x,y,z;
+	mreal *b=t->a;
 	const mreal *a=t->b;
 	const mglFormula *eq = (const mglFormula *)t->v;
-	for(i=t->id;i<nn;i+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i=t->id;i<nn;i+=mglNumThr)
 	{
-		i0 = i1 = 0;
-		for(j=0;j<nx;j++)	for(k=0;k<nz;k++)
+		register mreal i0 = 0, i1 = 0;
+		for(long j=0;j<nx;j++)	for(long k=0;k<nz;k++)
 		{
-			ii = j+nx*(i+ny*k);
-			x = j/(nx-1.);	y = i/(ny-1.);	z = k/(nz-1.);
+			register long ii = j+nx*(i+ny*k);
+			register mreal x = k/(nx-1.), y = j/(ny-1.), z = i/(nz-1.);
 			i0+= a[ii];
 			i1+= a[ii]*eq->Calc(x,y,z,a[ii]);
 		}
@@ -485,18 +546,20 @@ MGL_NO_EXPORT void *mgl_mom_y(void *par)
 MGL_NO_EXPORT void *mgl_mom_x(void *par)
 {
 	mglThreadD *t=(mglThreadD *)par;
-	register long i,j,k,ii;
 	long nx=t->p[0], ny=t->p[1], nz=t->p[2], nn=t->n;
-	mreal *b=t->a, i0,i1,x,y,z;
+	mreal *b=t->a;
 	const mreal *a=t->b;
 	const mglFormula *eq = (const mglFormula *)t->v;
-	for(i=t->id;i<nn;i+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i=t->id;i<nn;i+=mglNumThr)
 	{
-		i0 = i1 = 0;
-		for(j=0;j<ny;j++)	for(k=0;k<nz;k++)
+		register mreal i0 = 0, i1 = 0;
+		for(long j=0;j<ny;j++)	for(long k=0;k<nz;k++)
 		{
-			ii = i+nx*(j+ny*k);
-			x = i/(nx-1.);	y = j/(ny-1.);	z = k/(nz-1.);
+			register long ii = i+nx*(j+ny*k);
+			register mreal x = k/(nx-1.), y = j/(ny-1.), z = i/(nz-1.);
 			i0+= a[ii];
 			i1+= a[ii]*eq->Calc(x,y,z,a[ii]);
 		}
@@ -508,16 +571,16 @@ HMDT MGL_EXPORT mgl_data_momentum(HCDT dat, char dir, const char *how)
 {	// NOTE: only for mglData (for speeding up)
 	long nx=dat->GetNx(),ny=dat->GetNy(),nz=dat->GetNz();
 	const mglData *d=dynamic_cast<const mglData *>(dat);
-	mglData *b=new mglData;
-	if(!d)	return b;
+	if(!d)	return 0;
 	mglFormula eq(how);
 	long p[3]={nx,ny,nz};
+	mglData *b=0;
 	if(dir=='x')
-	{	b->Create(nx);	mglStartThread(mgl_mom_x,0,nx,b->a,d->a,0,p,&eq);	}
+	{	b=new mglData(nx);	mglStartThread(mgl_mom_x,0,nx,b->a,d->a,0,p,&eq);	}
 	if(dir=='y')
-	{	b->Create(ny);	mglStartThread(mgl_mom_y,0,ny,b->a,d->a,0,p,&eq);	}
+	{	b=new mglData(ny);	mglStartThread(mgl_mom_y,0,ny,b->a,d->a,0,p,&eq);	}
 	if(dir=='z')
-	{	b->Create(nz);	mglStartThread(mgl_mom_z,0,nz,b->a,d->a,0,p,&eq);	}
+	{	b=new mglData(nz);	mglStartThread(mgl_mom_z,0,nz,b->a,d->a,0,p,&eq);	}
 	return b;
 }
 uintptr_t MGL_EXPORT mgl_data_momentum_(uintptr_t *d, char *dir, const char *how, int,int l)
@@ -525,63 +588,16 @@ uintptr_t MGL_EXPORT mgl_data_momentum_(uintptr_t *d, char *dir, const char *how
 	uintptr_t r=uintptr_t(mgl_data_momentum(_DT_,*dir, s));
 	delete []s;	return r;	}
 //-----------------------------------------------------------------------------
-MGL_NO_EXPORT void *mgl_eval(void *par)
-{
-	mglThreadD *t=(mglThreadD *)par;
-	register long i, nx=t->p[0], ny=t->p[1], nz=t->p[2], n1=t->p[3], nn=t->n;
-	const mreal *a=t->b, *ii=t->c, *jj=t->d, *kk=t->e;
-	mreal *b=t->a,x,y,z;
-	for(i=t->id;i<nn;i+=mglNumThr)
-	{
-		x=ii?ii[i]:0;	y=jj?jj[i]:0;	z=kk?kk[i]:0;
-		if(n1)	{	x*=nx-1;	y*=ny-1;	z*=nz-1;	}
-		b[i] = (x==x && y==y && z==z) ? mglSpline3(a,nx,ny,nz, x,y,z):NAN;
-	}
-	return 0;
-}
-MGL_NO_EXPORT void *mgl_eval_s(void *par)
-{
-	mglThreadD *t=(mglThreadD *)par;
-	register long i, nx=t->p[0], ny=t->p[1], nz=t->p[2], n1=t->p[3], nn=t->n;
-	const mreal *ii=t->c, *jj=t->d, *kk=t->e;
-	HCDT a = (HCDT)t->v;
-	mreal *b=t->a,x,y,z;
-	for(i=t->id;i<nn;i+=mglNumThr)
-	{
-		x=ii?ii[i]:0;	y=jj?jj[i]:0;	z=kk?kk[i]:0;
-		if(n1)	{	x*=nx-1;	y*=ny-1;	z*=nz-1;	}
-		b[i] = (x==x && y==y && z==z) ? mgl_data_linear(a, x,y,z):NAN;
-	}
-	return 0;
-}
-HMDT MGL_EXPORT mgl_data_evaluate(HCDT dat, HCDT idat, HCDT jdat, HCDT kdat, int norm)
-{
-	mglData *r=new mglData;
-	const mglData *d=dynamic_cast<const mglData *>(dat);
-	const mglData *i=dynamic_cast<const mglData *>(idat);
-	const mglData *j=dynamic_cast<const mglData *>(jdat);
-	const mglData *k=dynamic_cast<const mglData *>(kdat);
-	if(!i)	return r;
-
-	long p[4]={dat->GetNx(), dat->GetNy(), dat->GetNz(),norm};
-	register long n=i->nx*i->ny*i->nz;
-	if(j && j->nx*j->ny*j->nz!=n)	return r;
-	if(k && k->nx*k->ny*k->nz!=n)	return r;
-	r->Create(i->nx,i->ny,i->nz);
-	if(d)	mglStartThread(mgl_eval,0,n,r->a,d->a,i->a,p,0,j?j->a:0,k?k->a:0);
-	else 	mglStartThread(mgl_eval_s,0,n,r->a,0,i->a,p,dat,j?j->a:0,k?k->a:0);
-	return r;
-}
-uintptr_t MGL_EXPORT mgl_data_evaluate_(uintptr_t *d, uintptr_t *idat, uintptr_t *jdat, uintptr_t *kdat, int *norm)
-{	return uintptr_t(mgl_data_evaluate(_DT_,_DA_(idat),_DA_(jdat),_DA_(kdat),*norm));	}
-//-----------------------------------------------------------------------------
 MGL_NO_EXPORT void *mgl_eqmul(void *par)
 {
 	mglThreadD *t=(mglThreadD *)par;
-	register long i, nx=t->p[0];
+	long nx=t->p[0];
 	mreal *b=t->a;
 	const mreal *a=t->b;
-	for(i=t->id;i<t->n;i+=mglNumThr)	b[i] *= a[i%nx];
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i=t->id;i<t->n;i+=mglNumThr)	b[i] *= a[i%nx];
 	return 0;
 }
 void MGL_EXPORT mgl_data_mul_dat(HMDT d, HCDT a)
@@ -597,8 +613,10 @@ void MGL_EXPORT mgl_data_mul_dat(HMDT d, HCDT a)
 		else if(nz==b->nz && ny==b->ny && nx==b->nx)
 		{	n=nx*ny*nz;	mglStartThread(mgl_eqmul,0,nx*ny*nz,d->a,b->a,0,&n);	}
 	}
-	else	for(long k=0;k<ny;k++)	for(long j=0;j<ny;j++)	for(long i=0;i<nx;i++)
-		d->a[i+nx*(j+ny*k)] *= a->v(i,j,k);
+	else
+#pragma omp parallel for collapse(3)
+		for(long k=0;k<nz;k++)	for(long j=0;j<ny;j++)	for(long i=0;i<nx;i++)
+			d->a[i+nx*(j+ny*k)] *= a->v(i,j,k);
 }
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_data_mul_num(HMDT d, mreal a)
@@ -610,10 +628,13 @@ void MGL_EXPORT mgl_data_mul_num(HMDT d, mreal a)
 MGL_NO_EXPORT void *mgl_eqdiv(void *par)
 {
 	mglThreadD *t=(mglThreadD *)par;
-	register long i, nx=t->p[0];
+	long nx=t->p[0];
 	mreal *b=t->a;
 	const mreal *a=t->b;
-	for(i=t->id;i<t->n;i+=mglNumThr)	b[i] /= a[i%nx];
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i=t->id;i<t->n;i+=mglNumThr)	b[i] /= a[i%nx];
 	return 0;
 }
 void MGL_EXPORT mgl_data_div_dat(HMDT d, HCDT a)
@@ -629,8 +650,10 @@ void MGL_EXPORT mgl_data_div_dat(HMDT d, HCDT a)
 		else if(nz==b->nz && ny==b->ny && nx==b->nx)
 		{	n=nx*ny*nz;	mglStartThread(mgl_eqdiv,0,nx*ny*nz,d->a,b->a,0,&n);	}
 	}
-	else	for(long k=0;k<ny;k++)	for(long j=0;j<ny;j++)	for(long i=0;i<nx;i++)
-		d->a[i+nx*(j+ny*k)] /= a->v(i,j,k);
+	else
+#pragma omp parallel for collapse(3)
+		for(long k=0;k<nz;k++)	for(long j=0;j<ny;j++)	for(long i=0;i<nx;i++)
+			d->a[i+nx*(j+ny*k)] /= a->v(i,j,k);
 }
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_data_div_num(HMDT d, mreal a)
@@ -642,10 +665,13 @@ void MGL_EXPORT mgl_data_div_num(HMDT d, mreal a)
 MGL_NO_EXPORT void *mgl_eqadd(void *par)
 {
 	mglThreadD *t=(mglThreadD *)par;
-	register long i, nx=t->p[0];
+	long nx=t->p[0];
 	mreal *b=t->a;
 	const mreal *a=t->b;
-	for(i=t->id;i<t->n;i+=mglNumThr)	b[i] += a[i%nx];
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i=t->id;i<t->n;i+=mglNumThr)	b[i] += a[i%nx];
 	return 0;
 }
 void MGL_EXPORT mgl_data_add_dat(HMDT d, HCDT a)
@@ -661,8 +687,10 @@ void MGL_EXPORT mgl_data_add_dat(HMDT d, HCDT a)
 		else if(nz==b->nz && ny==b->ny && nx==b->nx)
 		{	n=nx*ny*nz;	mglStartThread(mgl_eqadd,0,nx*ny*nz,d->a,b->a,0,&n);	}
 	}
-	else	for(long k=0;k<ny;k++)	for(long j=0;j<ny;j++)	for(long i=0;i<nx;i++)
-		d->a[i+nx*(j+ny*k)] += a->v(i,j,k);
+	else
+#pragma omp parallel for collapse(3)
+		for(long k=0;k<nz;k++)	for(long j=0;j<ny;j++)	for(long i=0;i<nx;i++)
+			d->a[i+nx*(j+ny*k)] += a->v(i,j,k);
 }
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_data_add_num(HMDT d, mreal a)
@@ -674,10 +702,13 @@ void MGL_EXPORT mgl_data_add_num(HMDT d, mreal a)
 MGL_NO_EXPORT void *mgl_eqsub(void *par)
 {
 	mglThreadD *t=(mglThreadD *)par;
-	register long i, nx=t->p[0];
+	long nx=t->p[0];
 	mreal *b=t->a;
 	const mreal *a=t->b;
-	for(i=t->id;i<t->n;i+=mglNumThr)	b[i] -= a[i%nx];
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i=t->id;i<t->n;i+=mglNumThr)	b[i] -= a[i%nx];
 	return 0;
 }
 void MGL_EXPORT mgl_data_sub_dat(HMDT d, HCDT a)
@@ -693,8 +724,10 @@ void MGL_EXPORT mgl_data_sub_dat(HMDT d, HCDT a)
 		else if(nz==b->nz && ny==b->ny && nx==b->nx)
 		{	n=nx*ny*nz;	mglStartThread(mgl_eqsub,0,nx*ny*nz,d->a,b->a,0,&n);	}
 	}
-	else	for(long k=0;k<ny;k++)	for(long j=0;j<ny;j++)	for(long i=0;i<nx;i++)
-		d->a[i+nx*(j+ny*k)] -= a->v(i,j,k);
+	else
+#pragma omp parallel for collapse(3)
+		for(long k=0;k<nz;k++)	for(long j=0;j<ny;j++)	for(long i=0;i<nx;i++)
+			d->a[i+nx*(j+ny*k)] -= a->v(i,j,k);
 }
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_data_sub_num(HMDT d, mreal a)
@@ -714,58 +747,71 @@ void MGL_EXPORT mgl_data_sub_num_(uintptr_t *d, mreal *b)		{	mgl_data_sub_num(_D
 //-----------------------------------------------------------------------------
 void MGL_NO_EXPORT mgl_hist_p(mglThreadD *t,mreal *a)
 {
-	register long i,j,n=t[0].p[0];
-	mreal *b;
+	long n=t[0].p[0];
 	memset(a,0,n*sizeof(mreal));
-	for(i=0;i<mglNumThr;i++)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i=0;i<mglNumThr;i++)
 	{
-		b = t[i].a;
-		for(j=0;j<n;j++)	a[j] += b[j];
+		mreal *b = t[i].a;
+		for(long j=0;j<n;j++)	a[j] += b[j];
 		delete []b;
 	}
 }
 MGL_NO_EXPORT void *mgl_hist_1(void *par)
 {
 	mglThreadD *t=(mglThreadD *)par;
-	register long i,k, nn=t->n, n = t->p[0];
+	long nn=t->n, n = t->p[0];
 	mreal *b=new mreal[n];
 	memset(b,0,n*sizeof(mreal));
 	const mreal *a=t->b, *c=t->c, *v=(const mreal *)t->v;
-	for(i=t->id;i<nn;i+=mglNumThr)
-	{
-		k = long(n*(a[i]-v[0])/(v[1]-v[0]));
-		if(k>=0 && k<n)	b[k] += c ? c[i]:1.;
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i=t->id;i<nn;i+=mglNumThr)
+	{
+		register long k = long(n*(a[i]-v[0])/(v[1]-v[0]));
+		if(k>=0 && k<n)
+#if !MGL_HAVE_PTHREAD
+#pragma omp critical(hist)
+#endif
+			b[k] += c ? c[i]:1.;
 	}
 	t->a = b;	return 0;
 }
 MGL_NO_EXPORT void *mgl_hist_2(void *par)
 {
 	mglThreadD *t=(mglThreadD *)par;
-	register long i,k, nn=t->n, n = t->p[0];
+	long nn=t->n, n = t->p[0];
 	long ns=t->p[1], nx=t->p[2], ny=t->p[3], nz=t->p[4];
-	mreal *b=new mreal[n], f,w=1, x,y,z, d=1./ns;
+	mreal *b=new mreal[n], d=1./ns;
 	memset(b,0,n*sizeof(mreal));
 	const mreal *a=t->b, *c=t->c, *v=(const mreal *)t->v;
 	bool sp = n>0;
-	for(i=t->id;i<nn;i+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i=t->id;i<nn;i+=mglNumThr)
 	{
-		x = d*(i%(nx*ns));
-		y = d*((i/(nx*ns))%(ny*ns));
-		z = d*(i/(nx*ny*ns*ns));
-		f = sp ? mglSpline3(a,nx,ny,nz,x,y,z) : mglLinear(a,nx,ny,nz,x,y,z);
+		register mreal x = d*(i%(nx*ns)), y = d*((i/(nx*ns))%(ny*ns)), z = d*(i/(nx*ny*ns*ns));
+		register mreal f = sp ? mglSpline3(a,nx,ny,nz,x,y,z) : mglLinear(a,nx,ny,nz,x,y,z), w=1;
 		if(c)	w = sp ? mglSpline3(c,nx,ny,nz,x,y,z) : mglLinear(c,nx,ny,nz,x,y,z);
 		if(mgl_isnan(f) || mgl_isnan(w))	continue;
-		k = long(n*(f-v[0])/(v[1]-v[0]));
-		if(k>=0 && k<n)	b[k] += w * d*d*d;
+		register long k = long(n*(f-v[0])/(v[1]-v[0]));
+		if(k>=0 && k<n)
+#if !MGL_HAVE_PTHREAD
+#pragma omp critical(hist)
+#endif
+			b[k] += w * d*d*d;
 	}
 	t->a = b;	return 0;
 }
 HMDT MGL_EXPORT mgl_data_hist(HCDT dat, long n, mreal v1, mreal v2, long nsub)
 {
-	mglData *b=new mglData;		// NOTE: For mglData only!
 	const mglData *d = dynamic_cast<const mglData *>(dat);
-	if(n<2 || v1==v2 || !d)	return b;
-	mgl_data_create(b,n,1,1);
+	if(n<2 || v1==v2 || !d)	return 0;	// NOTE: For mglData only!
+	mglData *b=new mglData(n);
 	mreal v[2]={v1,v2};
 	long nx=d->nx, ny=d->ny, nz=d->nz;
 	long ns=abs(nsub)+1, p[5]={n,ns,nx,ny,nz};
@@ -776,11 +822,10 @@ HMDT MGL_EXPORT mgl_data_hist(HCDT dat, long n, mreal v1, mreal v2, long nsub)
 //-----------------------------------------------------------------------------
 HMDT MGL_EXPORT mgl_data_hist_w(HCDT dat, HCDT weight, long n, mreal v1, mreal v2, long nsub)
 {
-	mglData *b=new mglData;		// NOTE: For mglData only!
 	const mglData *d = dynamic_cast<const mglData *>(dat);
 	const mglData *w = dynamic_cast<const mglData *>(weight);
-	if(n<2 || v1==v2 || !d || !w)	return b;
-	mgl_data_create(b,n,1,1);
+	if(n<2 || v1==v2 || !d || !w)	return 0;	// NOTE: For mglData only!
+	mglData *b=new mglData(n);
 	mreal v[2]={v1,v2};
 
 	long nx=d->nx, ny=d->ny, nz=d->nz;
@@ -795,45 +840,6 @@ uintptr_t MGL_EXPORT mgl_data_hist_(uintptr_t *d, int *n, mreal *v1, mreal *v2,
 uintptr_t MGL_EXPORT mgl_data_hist_w_(uintptr_t *d, uintptr_t *w, int *n, mreal *v1, mreal *v2, int *nsub)
 {	return uintptr_t(mgl_data_hist_w(_DT_,_DA_(w),*n,*v1,*v2,*nsub));	}
 //-----------------------------------------------------------------------------
-mreal mglLinear(const mreal *a, long nx, long ny, long nz, mreal x, mreal y, mreal z)
-{
-	if(!a || nx<1 || ny<1 || nz<1)	return 0;
-	register long i0;
-	long kx,ky,kz;
-	mreal b=0,dx,dy,dz,b1,b0;
-	if(x<0 || y<0 || z<0 || x>nx-1 || y>ny-1 || z>nz-1)
-		return 0;
-	if(nz>1 && z!=floor(z))		// 3d interpolation
-	{
-		kx=long(x);	ky=long(y);	kz=long(z);
-		dx = x-kx;	dy = y-ky;	dz = z-kz;
-
-		i0 = kx+nx*(ky+ny*kz);
-		b0 = a[i0]*(1-dx-dy+dx*dy) + dx*(1-dy)*a[i0+1] +
-			dy*(1-dx)*a[i0+nx] + dx*dy*a[i0+nx+1];
-		i0 = kx+nx*(ky+ny*(kz+1));
-		b1 = a[i0]*(1-dx-dy+dx*dy) + dx*(1-dy)*a[i0+1] +
-			dy*(1-dx)*a[i0+nx] + dx*dy*a[i0+nx+1];
-		b = b0 + dz*(b1-b0);
-	}
-	else if(ny>1 && y!=floor(y))	// 2d interpolation
-	{
-		kx=long(x);	ky=long(y);
-		dx = x-kx;	dy=y-ky;
-		i0 = kx+nx*ky;
-		b = a[i0]*(1-dx-dy+dx*dy) + dx*(1-dy)*a[i0+1] +
-			dy*(1-dx)*a[i0+nx] + dx*dy*a[i0+nx+1];
-	}
-	else if(nx>1 && x!=floor(x))	// 1d interpolation
-	{
-		kx = long(x);
-		b = a[kx] + (x-kx)*(a[kx+1]-a[kx]);
-	}
-	else						// no interpolation
-		b = a[long(x+nx*(y+ny*z))];
-	return b;
-}
-//-----------------------------------------------------------------------------
 long MGL_NO_EXPORT mgl_idx_var;
 int MGL_NO_EXPORT mgl_cmd_idx(const void *a, const void *b)
 {
@@ -884,13 +890,14 @@ mreal MGL_NO_EXPORT mgl_funcv(mreal v, void *par)
 }
 HMDT MGL_EXPORT mgl_data_roots(const char *func, HCDT ini, char var)
 {
-	if(!ini)	return (new mglData);
+	if(!ini)	return 0;
 	mglData *res = new mglData(ini);
 
 	mglFormula eq(func);
 	mglFuncV f;	f.eq = &eq;	f.var = var;
-	register long i, n = res->nx*res->ny*res->nz;
-	for(i=0;i<n;i++)
+	long n = res->nx*res->ny*res->nz;
+#pragma omp parallel for
+	for(long i=0;i<n;i++)
 		res->a[i] = mgl_find_root(mgl_funcv,res->a[i],&f);
 	return res;
 }
diff --git a/src/data_gr.cpp b/src/data_gr.cpp
new file mode 100644
index 0000000..04f17d6
--- /dev/null
+++ b/src/data_gr.cpp
@@ -0,0 +1,177 @@
+/***************************************************************************
+ * data_gr.cpp is part of Math Graphic Library
+ * Copyright (C) 2007-2012 Alexey Balakin <mathgl.abalakin at gmail.ru>       *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU Library General Public License as       *
+ *   published by the Free Software Foundation; either version 3 of the    *
+ *   License, or (at your option) any later version.                       *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU Library General Public     *
+ *   License along with this program; if not, write to the                 *
+ *   Free Software Foundation, Inc.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+#include <ctype.h>
+
+#ifndef WIN32
+#include <glob.h>
+#endif
+
+#include "mgl2/datac.h"
+#include "mgl2/evalc.h"
+#include "mgl2/thread.h"
+#include "mgl2/base.h"
+//-----------------------------------------------------------------------------
+void MGL_EXPORT mgl_data_refill_gr(HMGL gr, HMDT dat, HCDT xdat, HCDT ydat, HCDT zdat, HCDT vdat, long sl, const char *opt)
+{
+	if(!vdat)	return;
+	gr->SaveState(opt);
+	if(!ydat && !zdat)	mgl_data_refill_x(dat,xdat,vdat,gr->Min.x,gr->Max.x,sl);
+//	else if(!xdat && !zdat)	mgl_data_refill_x(dat,ydat,vdat,gr->Min.y,gr->Max.y,sl);
+//	else if(!xdat && !ydat)	mgl_data_refill_x(dat,zdat,vdat,gr->Min.z,gr->Max.z,sl);
+	else if(!zdat)	mgl_data_refill_xy(dat,xdat,ydat,vdat,gr->Min.x,gr->Max.x,gr->Min.y,gr->Max.y,sl);
+//	else if(!ydat)	mgl_data_refill_xy(dat,xdat,zdat,vdat,gr->Min.x,gr->Max.x,gr->Min.z,gr->Max.z,sl);
+//	else if(!xdat)	mgl_data_refill_xy(dat,ydat,zdat,vdat,gr->Min.y,gr->Max.y,gr->Min.z,gr->Max.z,sl);
+	else	mgl_data_refill_xyz(dat,xdat,ydat,zdat,vdat,gr->Min.x,gr->Max.x,gr->Min.y,gr->Max.y,gr->Min.z,gr->Max.z);
+	gr->LoadState();
+}
+//-----------------------------------------------------------------------------
+void MGL_EXPORT mgl_data_refill_x_(uintptr_t *d, uintptr_t *xdat, uintptr_t *vdat, mreal *x1, mreal *x2, long *sl)
+{	mgl_data_refill_x(_DT_,_DA_(xdat),_DA_(vdat),*x1,*x2,*sl);	}
+void MGL_EXPORT mgl_data_refill_xy_(uintptr_t *d, uintptr_t *xdat, uintptr_t *ydat, uintptr_t *vdat, mreal *x1, mreal *x2, mreal *y1, mreal *y2, long *sl)
+{	mgl_data_refill_xy(_DT_,_DA_(xdat),_DA_(ydat),_DA_(vdat),*x1,*x2,*y1,*y2,*sl);	}
+void MGL_EXPORT mgl_data_refill_xyz_(uintptr_t *d, uintptr_t *xdat, uintptr_t *ydat, uintptr_t *zdat, uintptr_t *vdat, mreal *x1, mreal *x2, mreal *y1, mreal *y2, mreal *z1, mreal *z2)
+{	mgl_data_refill_xyz(_DT_,_DA_(xdat),_DA_(ydat),_DA_(zdat),_DA_(vdat),*x1,*x2,*y1,*y2,*z1,*z2);	}
+void MGL_EXPORT mgl_data_refill_gr_(uintptr_t *gr, uintptr_t *d, uintptr_t *xdat, uintptr_t *ydat, uintptr_t *zdat, uintptr_t *vdat, long *sl, const char *opt,int l)
+{	char *s=new char[l+1];	memcpy(s,opt,l);	s[l]=0;
+	mgl_data_refill_gr(_GR_,_DT_,_DA_(xdat),_DA_(ydat),_DA_(zdat),_DA_(vdat),*sl,s);	delete []s;	}
+//-----------------------------------------------------------------------------
+MGL_NO_EXPORT void *mgl_fill_f(void *par)
+{
+	mglThreadD *t=(mglThreadD *)par;
+	const mglFormula *f = (const mglFormula *)(t->v);
+	long nx=t->p[0],ny=t->p[1];
+	mreal *b=t->a;
+	const mreal *v=t->b, *w=t->c, *x=t->d;
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i0=t->id;i0<t->n;i0+=mglNumThr)
+	{
+		register long i=i0%nx, j=((i0/nx)%ny), k=i0/(nx*ny);
+		b[i0] = f->Calc(x[0]+i*x[1], x[2]+j*x[3], x[4]+k*x[5], b[i0], v?v[i0]:0, w?w[i0]:0);
+	}
+	return 0;
+}
+MGL_NO_EXPORT void *mgl_fill_fgen(void *par)
+{
+	mglThreadV *t=(mglThreadV *)par;
+	const mglFormula *f = (const mglFormula *)(t->v);
+	long nx=t->p[0],ny=t->p[1];
+	mreal *b=t->a;
+	HCDT v=(HCDT)t->b, w=(HCDT)t->c;
+	const mreal *x=t->d;
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i0=t->id;i0<t->n;i0+=mglNumThr)
+	{
+		register long i=i0%nx, j=((i0/nx)%ny), k=i0/(nx*ny);
+		b[i0] = f->Calc(x[0]+i*x[1], x[2]+j*x[3], x[4]+k*x[5], b[i0], v?v->vthr(i0):0, w?w->vthr(i0):0);
+	}
+	return 0;
+}
+void MGL_EXPORT mgl_data_fill_eq(HMGL gr, HMDT d, const char *eq, HCDT vdat, HCDT wdat, const char *opt)
+{
+	const mglData *v = dynamic_cast<const mglData *>(vdat);
+	const mglData *w = dynamic_cast<const mglData *>(wdat);
+	long nn = d->nx*d->ny*d->nz, par[3]={d->nx,d->ny,d->nz};
+	if(vdat && vdat->GetNN()!=nn)	return;
+	if(wdat && wdat->GetNN()!=nn)	return;
+	gr->SaveState(opt);
+	mreal xx[6]={gr->Min.x,0, gr->Min.y,0, gr->Min.z,0};
+	if(d->nx>1)	xx[1] = (gr->Max.x-gr->Min.x)/(d->nx-1.);
+	if(d->ny>1)	xx[3] = (gr->Max.y-gr->Min.y)/(d->ny-1.);
+	if(d->nz>1)	xx[5] = (gr->Max.z-gr->Min.z)/(d->nz-1.);
+	mglFormula f(eq);
+	if(v && w)	mglStartThread(mgl_fill_f,0,nn,d->a,v->a,w->a,par,&f,xx);
+	else if(vdat && wdat)	mglStartThreadV(mgl_fill_fgen,nn,d->a,vdat,wdat,par,&f,xx);
+	else if(v)	mglStartThread(mgl_fill_f,0,nn,d->a,v->a,0,par,&f,xx);
+	else if(vdat)	mglStartThreadV(mgl_fill_fgen,nn,d->a,vdat,0,par,&f,xx);
+	else	mglStartThread(mgl_fill_f,0,nn,d->a,0,0,par,&f,xx);
+	gr->LoadState();
+}
+void MGL_EXPORT mgl_data_fill_eq_(uintptr_t *gr, uintptr_t *d, const char *eq, uintptr_t *v, uintptr_t *w, const char *opt,int l,int lo)
+{	char *s=new char[l+1];	memcpy(s,eq,l);	s[l]=0;
+	char *o=new char[lo+1];	memcpy(o,opt,lo);	o[lo]=0;
+	mgl_data_fill_eq(_GR_,_DT_,s,_DA_(v),_DA_(w),o);	delete []o;	delete []s;	}
+//-----------------------------------------------------------------------------
+MGL_NO_EXPORT void *mgl_cfill_f(void *par)
+{
+	mglThreadC *t=(mglThreadC *)par;
+	const mglFormulaC *f = (const mglFormulaC *)(t->v);
+	long nx=t->p[0],ny=t->p[1];
+	dual *b=t->a;
+	const dual *v=t->b, *w=t->c, *x=t->d;
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i0=t->id;i0<t->n;i0+=mglNumThr)
+	{
+		register long i=i0%nx, j=((i0/nx)%ny), k=i0/(nx*ny);
+		b[i0] = f->Calc(x[0]+mreal(i)*x[1], x[2]+mreal(j)*x[3], x[4]+mreal(k)*x[5],
+						b[i0], v?v[i0]:dual(0,0), w?w[i0]:dual(0,0));
+	}
+	return 0;
+}
+MGL_NO_EXPORT void *mgl_cfill_fgen(void *par)
+{
+	mglThreadV *t=(mglThreadV *)par;
+	const mglFormulaC *f = (const mglFormulaC *)(t->v);
+	long nx=t->p[0],ny=t->p[1];
+	dual *b=t->aa;
+	HCDT v=(HCDT)t->b, w=(HCDT)t->c;
+	const mreal *x=t->d;
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i0=t->id;i0<t->n;i0+=mglNumThr)
+	{
+		register long i=i0%nx, j=((i0/nx)%ny), k=i0/(nx*ny);
+		b[i0] = f->Calc(x[0]+i*x[1], x[2]+j*x[3], x[4]+k*x[5],
+						b[i0], v?v->vthr(i0):0, w?w->vthr(i0):0);
+	}
+	return 0;
+}
+void MGL_EXPORT mgl_datac_fill_eq(HMGL gr, HADT d, const char *eq, HCDT vdat, HCDT wdat, const char *opt)
+{
+	const mglDataC *v = dynamic_cast<const mglDataC *>(vdat);
+	const mglDataC *w = dynamic_cast<const mglDataC *>(wdat);
+	long nn = d->nx*d->ny*d->nz, par[3]={d->nx,d->ny,d->nz};
+	if(v && v->nx*v->ny*v->nz!=nn)	return;
+	if(w && w->nx*w->ny*w->nz!=nn)	return;
+	gr->SaveState(opt);
+	mreal xx[6]={gr->Min.x,0, gr->Min.y,0, gr->Min.z,0};
+	if(d->nx>1)	xx[1] = (gr->Max.x-gr->Min.x)/(d->nx-1.);
+	if(d->ny>1)	xx[3] = (gr->Max.y-gr->Min.y)/(d->ny-1.);
+	if(d->nz>1)	xx[5] = (gr->Max.z-gr->Min.z)/(d->nz-1.);
+	dual cc[6]={xx[0],xx[1],xx[2],xx[3],xx[4],xx[5]};
+	mglFormulaC f(eq);
+	if(v && w)	mglStartThreadC(mgl_cfill_f,0,nn,d->a,v->a,w->a,par,&f,cc);
+	else if(vdat && wdat)	mglStartThreadV(mgl_cfill_fgen,nn,d->a,vdat,wdat,par,&f,xx);
+	else if(v)	mglStartThreadC(mgl_cfill_f,0,nn,d->a,v->a,0,par,&f,cc);
+	else if(vdat)	mglStartThreadV(mgl_cfill_fgen,nn,d->a,vdat,0,par,&f,xx);
+	else	mglStartThreadC(mgl_cfill_f,0,nn,d->a,0,0,par,&f,cc);
+	gr->LoadState();
+}
+void MGL_EXPORT mgl_datac_fill_eq_(uintptr_t *gr, uintptr_t *d, const char *eq, uintptr_t *v, uintptr_t *w, const char *opt,int l,int lo)
+{	char *s=new char[l+1];	memcpy(s,eq,l);	s[l]=0;
+	char *o=new char[lo+1];	memcpy(o,opt,lo);	o[lo]=0;
+	mgl_datac_fill_eq(_GR_,_DC_,s,_DA_(v),_DA_(w),o);	delete []o;	delete []s;	}
+//-----------------------------------------------------------------------------
diff --git a/src/data_io.cpp b/src/data_io.cpp
index f7107ea..1b50dd8 100644
--- a/src/data_io.cpp
+++ b/src/data_io.cpp
@@ -26,6 +26,7 @@
 #include "mgl2/data.h"
 #include "mgl2/datac.h"
 #include "mgl2/eval.h"
+#include "mgl2/thread.h"
 
 #if MGL_HAVE_HDF5
 //#define H5_NO_DEPRECATED_SYMBOLS
@@ -96,11 +97,9 @@ void MGL_EXPORT mgl_data_set(HMDT d, HCDT a)
 	if(dd)	// this one should be much faster
 		memcpy(d->a, dd->a, d->nx*d->ny*d->nz*sizeof(mreal));
 	else	// very inefficient!!!
-	{
-		register long i,j,k;
-		for(k=0;k<d->nz;k++)	for(j=0;j<d->ny;j++)	for(i=0;i<d->nx;i++)
+#pragma omp parallel for collapse(3)
+		for(long k=0;k<d->nz;k++)	for(long j=0;j<d->ny;j++)	for(long i=0;i<d->nx;i++)
 			d->a[i+d->nx*(j+d->ny*k)] = a->v(i,j,k);
-	}
 }
 void MGL_EXPORT mgl_data_set_(uintptr_t *d, uintptr_t *a)	{	mgl_data_set(_DT_,_DA_(a));	}
 //-----------------------------------------------------------------------------
@@ -122,6 +121,7 @@ void MGL_EXPORT mgl_data_set_vector(HMDT d, gsl_vector *v)
 #if MGL_HAVE_GSL
 	if(!v || v->size<1)	return;
 	mgl_data_create(d, v->size,1,1);
+#pragma omp parallel for
 	for(long i=0;i<d->nx;i++)	d->a[i] = v->data[i*v->stride];
 #endif
 }
@@ -131,8 +131,8 @@ void MGL_EXPORT mgl_data_set_matrix(HMDT d, gsl_matrix *m)
 #if MGL_HAVE_GSL
 	if(!m || m->size1<1 || m->size2<1)	return;
 	mgl_data_create(d, m->size1,m->size2,1);
-	register long i,j;
-	for(j=0;j<d->ny;j++)	for(i=0;i<d->nx;i++)
+#pragma omp parallel for collapse(2)
+	for(long j=0;j<d->ny;j++)	for(long i=0;i<d->nx;i++)
 		d->a[i+j*d->nx] = m->data[i * m->tda + j];
 #endif
 }
@@ -142,6 +142,7 @@ void MGL_EXPORT mgl_data_set_float(HMDT d, const float *A,long NX,long NY,long N
 	if(NX<=0 || NY<=0 || NZ<=0)	return;
 	mgl_data_create(d, NX,NY,NZ);	if(!A)	return;
 #if MGL_USE_DOUBLE
+#pragma omp parallel for
 	for(long i=0;i<NX*NY*NZ;i++)	d->a[i] = A[i];
 #else
 	memcpy(d->a,A,NX*NY*NZ*sizeof(float));
@@ -155,53 +156,62 @@ void MGL_EXPORT mgl_data_set_double(HMDT d, const double *A,long NX,long NY,long
 #if MGL_USE_DOUBLE
 	memcpy(d->a,A,NX*NY*NZ*sizeof(double));
 #else
+#pragma omp parallel for
 	for(long i=0;i<NX*NY*NZ;i++)	d->a[i] = A[i];
 #endif
 }
 //-----------------------------------------------------------------------------
-void MGL_EXPORT mgl_data_set_float2(HMDT d, const float **A,long N1,long N2)
+void MGL_EXPORT mgl_data_set_float2(HMDT d, float const * const *A,long N1,long N2)
 {
 	if(N1<=0 || N2<=0)	return;
 	mgl_data_create(d, N2,N1,1);	if(!A)	return;
 #if MGL_USE_DOUBLE
+#pragma omp parallel for collapse(2)
 	for(long i=0;i<N1;i++)	for(long j=0;j<N2;j++)	d->a[j+i*N2] = A[i][j];
 #else
+#pragma omp parallel for
 	for(long i=0;i<N1;i++)	memcpy(d->a+i*N2,A[i],N2*sizeof(float));
 #endif
 }
 //-----------------------------------------------------------------------------
-void MGL_EXPORT mgl_data_set_double2(HMDT d, const double **A,long N1,long N2)
+void MGL_EXPORT mgl_data_set_double2(HMDT d, double const *const *A,long N1,long N2)
 {
 	if(N1<=0 || N2<=0)	return;
 	mgl_data_create(d, N2,N1,1);	if(!A)	return;
 #if MGL_USE_DOUBLE
+#pragma omp parallel for
 	for(long i=0;i<N1;i++)	memcpy(d->a+i*N2,A[i],N2*sizeof(double));
 #else
+#pragma omp parallel for collapse(2)
 	for(long i=0;i<N1;i++)	for(long j=0;j<N2;j++)	d->a[j+i*N2] = A[i][j];
 #endif
 }
 //-----------------------------------------------------------------------------
-void MGL_EXPORT mgl_data_set_float3(HMDT d, const float ***A,long N1,long N2,long N3)
+void MGL_EXPORT mgl_data_set_float3(HMDT d, float const * const * const *A,long N1,long N2,long N3)
 {
 	if(N1<=0 || N2<=0 || N3<=0)	return;
 	mgl_data_create(d, N3,N2,N1);	if(!A)	return;
 #if MGL_USE_DOUBLE
+#pragma omp parallel for collapse(3)
 	for(long i=0;i<N1;i++)	for(long j=0;j<N2;j++)	for(long k=0;k<N3;k++)
 		d->a[k+N3*(j+i*N2)] = A[i][j][k];
 #else
+#pragma omp parallel for collapse(2)
 	for(long i=0;i<N1;i++)	for(long j=0;j<N2;j++)
 		memcpy(d->a+N3*(j+i*N2),A[i][j],N3*sizeof(float));
 #endif
 }
 //-----------------------------------------------------------------------------
-void MGL_EXPORT mgl_data_set_double3(HMDT d, const double ***A,long N1,long N2,long N3)
+void MGL_EXPORT mgl_data_set_double3(HMDT d, double const * const * const *A,long N1,long N2,long N3)
 {
 	if(N1<=0 || N2<=0 || N3<=0)	return;
 	mgl_data_create(d, N3,N2,N1);	if(!A)	return;
 #if MGL_USE_DOUBLE
+#pragma omp parallel for collapse(2)
 	for(long i=0;i<N1;i++)	for(long j=0;j<N2;j++)
 		memcpy(d->a+N3*(j+i*N2),A[i][j],N3*sizeof(double));
 #else
+#pragma omp parallel for collapse(3)
 	for(long i=0;i<N1;i++)	for(long j=0;j<N2;j++)	for(long k=0;k<N3;k++)
 		d->a[k+N3*(j+i*N2)] = A[i][j][k];
 #endif
@@ -250,9 +260,9 @@ void MGL_EXPORT mgl_data_save(HCDT d, const char *fname,long ns)
 	if(ns<0 || (ns>=nz && nz>1))	for(k=0;k<nz;k++)
 	{	// save whole data
 		const mglData *dr = dynamic_cast<const mglData *>(d);
-		if(dr)	fprintf(fp,"## %s\n",dr->id.c_str());
+		if(dr && !dr->id.empty())	fprintf(fp,"## %s\n",dr->id.c_str());
 		const mglDataC *dc = dynamic_cast<const mglDataC *>(d);
-		if(dc)	fprintf(fp,"## %s\n",dc->id.c_str());
+		if(dc && !dc->id.empty())	fprintf(fp,"## %s\n",dc->id.c_str());
 		for(i=0;i<ny;i++)
 		{
 			for(j=0;j<nx-1;j++)	fprintf(fp,"%g\t",d->v(j,i,k));
@@ -444,41 +454,69 @@ int MGL_EXPORT mgl_data_read_mat_(uintptr_t *d, const char *fname,int *dim,int l
 //-----------------------------------------------------------------------------
 mreal MGL_EXPORT mgl_data_max(HCDT d)
 {
-	register mreal m=-1e10, v;
-	register long nn=d->GetNN();
+	mreal m1=-1e10;
+	long nn=d->GetNN();
 	const mglData *b = dynamic_cast<const mglData *>(d);
-	if(b)	for(long i=0;i<nn;i++)
-	{	v = b->a[i];	if(!mgl_isnan(v))	m = m>v ? m:v;	}
-	else	for(long i=0;i<nn;i++)
-	{	v = d->vthr(i);	if(!mgl_isnan(v))	m = m>v ? m:v;	}
-	return m;
+#pragma omp parallel
+	{
+		register mreal m=-1e10, v;
+		if(b)
+#pragma omp for nowait
+			for(long i=0;i<nn;i++)
+			{	v = b->a[i];	m = m<v ? v:m;	}
+		else
+#pragma omp for nowait
+			for(long i=0;i<nn;i++)
+			{	v = d->vthr(i);	m = m<v ? v:m;	}
+#pragma omp critical(max_dat)
+		{	m1 = m1>m ? m1:m;	}
+	}
+	return m1;
 }
 mreal MGL_EXPORT mgl_data_max_(uintptr_t *d)	{	return mgl_data_max(_DT_);	}
 //-----------------------------------------------------------------------------
 mreal MGL_EXPORT mgl_data_min(HCDT d)
 {
-	register mreal m=1e10, v;
-	register long nn=d->GetNN();
+	mreal m1=1e10;
+	long nn=d->GetNN();
 	const mglData *b = dynamic_cast<const mglData *>(d);
-	if(b)	for(long i=0;i<nn;i++)
-	{	v = b->a[i];	if(!mgl_isnan(v))	m = m<v ? m:v;	}
-	else	for(long i=0;i<nn;i++)
-	{	v = d->vthr(i);	if(!mgl_isnan(v))	m = m<v ? m:v;	}
-	return m;
+#pragma omp parallel
+	{
+		register mreal m=1e10, v;
+		if(b)
+#pragma omp for nowait
+			for(long i=0;i<nn;i++)
+			{	v = b->a[i];	m = m>v ? v:m;	}
+		else
+#pragma omp for nowait
+			for(long i=0;i<nn;i++)
+			{	v = d->vthr(i);	m = m>v ? v:m;	}
+#pragma omp critical(min_dat)
+		{	m1 = m1<m ? m1:m;	}
+	}
+	return m1;
 }
 mreal MGL_EXPORT mgl_data_min_(uintptr_t *d)	{	return mgl_data_min(_DT_);	}
 //-----------------------------------------------------------------------------
 mreal MGL_EXPORT mgl_data_max_int(HCDT d, long *i, long *j, long *k)
 {
-	register mreal m=-1e10, v;
+	mreal m1=-1e10;
 	long nx=d->GetNx(), ny=d->GetNy(), nn=d->GetNN();
-	for(long ii=0;ii<nn;ii++)
+#pragma omp parallel
 	{
-		v = d->vthr(ii);
-		if(!mgl_isnan(v) && m < v)
-		{	m=v;	*i=ii%nx;	*j=(ii/nx)%ny;	*k=ii/(nx*ny);   }
+		register mreal m=-1e10, v;
+		long im=-1,jm=-1,km=-1;
+#pragma omp for nowait
+		for(long ii=0;ii<nn;ii++)
+		{
+			v = d->vthr(ii);
+			if(m < v)
+			{	m=v;	im=ii%nx;	jm=(ii/nx)%ny;	km=ii/(nx*ny);   }
+		}
+#pragma omp critical(max_int)
+		if(m1 < m)	{	m1=m;	*i=im;	*j=jm;	*k=km;   }
 	}
-	return m;
+	return m1;
 }
 mreal MGL_EXPORT mgl_data_max_int_(uintptr_t *d, int *i, int *j, int *k)
 {	long ii,jj,kk;	mreal res=mgl_data_max_int(_DT_,&ii,&jj,&kk);
@@ -486,15 +524,23 @@ mreal MGL_EXPORT mgl_data_max_int_(uintptr_t *d, int *i, int *j, int *k)
 //-----------------------------------------------------------------------------
 mreal MGL_EXPORT mgl_data_min_int(HCDT d, long *i, long *j, long *k)
 {
-	register mreal m=1e10, v;
+	mreal m1=1e10;
 	long nx=d->GetNx(), ny=d->GetNy(), nn=d->GetNN();
-	for(long ii=0;ii<nn;ii++)
+#pragma omp parallel
 	{
-		v = d->vthr(ii);
-		if(!mgl_isnan(v) && m > v)
-		{	m=v;	*i=ii%nx;	*j=(ii/nx)%ny;	*k=ii/(nx*ny);   }
+		register mreal m=1e10, v;
+		long im=-1,jm=-1,km=-1;
+#pragma omp for nowait
+		for(long ii=0;ii<nn;ii++)
+		{
+			v = d->vthr(ii);
+			if(m > v)
+			{	m=v;	im=ii%nx;	jm=(ii/nx)%ny;	km=ii/(nx*ny);   }
+		}
+#pragma omp critical(min_int)
+		if(m1 > m)	{	m1=m;	*i=im;	*j=jm;	*k=km;   }
 	}
-	return m;
+	return m1;
 }
 mreal MGL_EXPORT mgl_data_min_int_(uintptr_t *d, int *i, int *j, int *k)
 {	long ii,jj,kk;	mreal res=mgl_data_min_int(_DT_,&ii,&jj,&kk);
@@ -571,15 +617,24 @@ mreal MGL_EXPORT mgl_data_min_real_(uintptr_t *d, mreal *x, mreal *y, mreal *z)
 MGL_NO_EXPORT void *mgl_fill_x(void *par)
 {
 	mglThreadD *t=(mglThreadD *)par;
-	register long i0, nx=t->p[0],ny=t->p[1];
+	long nx=t->p[0],ny=t->p[1];
 	mreal *b=t->a, x1=t->b[0], dx=t->b[1];
 	register char dir = t->s[0];
-	for(i0=t->id;i0<t->n;i0+=mglNumThr)
-	{
-		if(dir=='x') b[i0] = x1+dx*(i0%nx);
-		else if(dir=='y') b[i0] = x1+dx*((i0/nx)%ny);
-		else if(dir=='z') b[i0] = x1+dx*(i0/(nx*ny));
-	}
+	if(dir=='x')
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+		for(long i0=t->id;i0<t->n;i0+=mglNumThr)	b[i0] = x1+dx*(i0%nx);
+	else if(dir=='y')
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+		for(long i0=t->id;i0<t->n;i0+=mglNumThr)	b[i0] = x1+dx*((i0/nx)%ny);
+	else if(dir=='z')
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+		for(long i0=t->id;i0<t->n;i0+=mglNumThr)	b[i0] = x1+dx*(i0/(nx*ny));
 	return 0;
 }
 void MGL_EXPORT mgl_data_fill(HMDT d, mreal x1,mreal x2,char dir)
@@ -598,15 +653,11 @@ void MGL_EXPORT mgl_data_fill_(uintptr_t *d, mreal *x1,mreal *x2,const char *dir
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_data_norm(HMDT d, mreal v1,mreal v2,long sym,long dim)
 {
-	long i,s,nn=d->nx*d->ny*d->nz;
+	long s,nn=d->nx*d->ny*d->nz;
 	mreal a1=1e20,a2=-1e20,v,*a=d->a;
-	if(d->nz>1)	s = dim*d->nx*d->ny;
-	else		s = dim*d->ny;
-	for(i=s;i<nn;i++)	// determines borders of existing data
-	{
-		if(mgl_isnan(a[i]))	continue;
-		a1 = (a1<a[i] ? a1 : a[i]);	a2 = (a2>a[i] ? a2 : a[i]);
-	}
+	s = dim*d->ny*(d->nz>1 ? d->nx : 1);
+	for(long i=s;i<nn;i++)	// determines borders of existing data
+	{	a1 = a1>a[i] ? a[i]:a1;	a2 = a2<a[i] ? a[i]:a2;	}
 	if(a1==a2)  {  if(a1!=0)	a1=0.;  else a2=1;  }
 	if(v1>v2)	{	v=v1;	v1=v2;	v2=v;	}	// swap if uncorrect
 	if(sym)				// use symmetric
@@ -614,16 +665,16 @@ void MGL_EXPORT mgl_data_norm(HMDT d, mreal v1,mreal v2,long sym,long dim)
 		v2 = -v1>v2 ? -v1:v2;	v1 = -v2;
 		a2 = -a1>a2 ? -a1:a2;	a1 = -a2;
 	}
-	for(i=s;i<nn;i++)	// normalize
-		a[i] = v1 + (v2-v1)*(a[i]-a1)/(a2-a1);
+	v2 = (v2-v1)/(a2-a1);	v1 = v1-a1*v2;
+#pragma omp parallel for
+	for(long i=s;i<nn;i++)	a[i] = v1 + v2*a[i];
 }
 void MGL_EXPORT mgl_data_norm_(uintptr_t *d, mreal *v1,mreal *v2,int *sym,int *dim)
 {	mgl_data_norm(_DT_,*v1,*v2,*sym,*dim);	}
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_data_squeeze(HMDT d, long rx,long ry,long rz,long smooth)
 {
-	long kx,ky,kz,i,j,k;
-	long nx=d->nx, ny=d->ny, nz=d->nz;
+	long kx,ky,kz, nx=d->nx, ny=d->ny, nz=d->nz;
 	mreal *b;
 
 	// simple checking
@@ -633,19 +684,23 @@ void MGL_EXPORT mgl_data_squeeze(HMDT d, long rx,long ry,long rz,long smooth)
 	// new sizes
 	kx = 1+(nx-1)/rx;	ky = 1+(ny-1)/ry;	kz = 1+(nz-1)/rz;
 	b = new mreal[kx*ky*kz];
-	if(!smooth)	for(k=0;k<kz;k++)	for(j=0;j<ky;j++)	for(i=0;i<kx;i++)
-		b[i+kx*(j+ky*k)] = d->a[i*rx+nx*(j*ry+ny*rz*k)];
-	else		for(k=0;k<kz;k++)	for(j=0;j<ky;j++)	for(i=0;i<kx;i++)
-	{
-		long dx,dy,dz,i1,j1,k1;
-		dx = (i+1)*rx<=nx ? rx : nx-i*rx;
-		dy = (j+1)*ry<=ny ? ry : ny-j*ry;
-		dz = (k+1)*rz<=nz ? rz : nz-k*rz;
-		mreal s = 0;
-		for(k1=k*rz;k1<k*rz+dz;k1++)	for(j1=j*ry;j1<j*ry+dz;j1++)	for(i1=i*rx;i1<i*rx+dx;i1++)
-			s += d->a[i1+nx*(j1+ny*k1)];
-		b[i+kx*(j+ky*k)] = s/(dx*dy*dz);
-	}
+	if(!smooth)
+#pragma omp parallel for collapse(3)
+		for(long k=0;k<kz;k++)	for(long j=0;j<ky;j++)	for(long i=0;i<kx;i++)
+			b[i+kx*(j+ky*k)] = d->a[i*rx+nx*(j*ry+ny*rz*k)];
+	else
+#pragma omp parallel for collapse(3)
+		for(long k=0;k<kz;k++)	for(long j=0;j<ky;j++)	for(long i=0;i<kx;i++)
+		{
+			long dx,dy,dz,i1,j1,k1;
+			dx = (i+1)*rx<=nx ? rx : nx-i*rx;
+			dy = (j+1)*ry<=ny ? ry : ny-j*ry;
+			dz = (k+1)*rz<=nz ? rz : nz-k*rz;
+			mreal s = 0;
+			for(k1=k*rz;k1<k*rz+dz;k1++)	for(j1=j*ry;j1<j*ry+dz;j1++)	for(i1=i*rx;i1<i*rx+dx;i1++)
+				s += d->a[i1+nx*(j1+ny*k1)];
+			b[i+kx*(j+ky*k)] = s/(dx*dy*dz);
+		}
 	if(!d->link)	delete [](d->a);
 	d->a=b;	d->nx = kx;  d->ny = ky;  d->nz = kz;	d->NewId();	d->link=false;
 }
@@ -658,29 +713,35 @@ void MGL_EXPORT mgl_data_extend(HMDT d, long n1, long n2)
 	if(nz>2 || n1==0)	return;
 	long mx, my, mz;
 	mreal *b=0;
-	register long i,j;
 	if(n1>0) // extend to higher dimension(s)
 	{
 		n2 = n2>0 ? n2:1;
 		mx = nx;	my = ny>1?ny:n1;	mz = ny>1 ? n1 : n2;
 		b = new mreal[mx*my*mz];
-		if(ny>1)	for(i=0;i<n1;i++)
-			memcpy(b+i*nx*ny, d->a, nx*ny*sizeof(mreal));
-		else		for(i=0;i<n1*n2;i++)
-			memcpy(b+i*nx, d->a, nx*sizeof(mreal));
+		if(ny>1)
+#pragma omp parallel for
+			for(long i=0;i<n1;i++)	memcpy(b+i*nx*ny, d->a, nx*ny*sizeof(mreal));
+		else
+#pragma omp parallel for
+			for(long i=0;i<n1*n2;i++)	memcpy(b+i*nx, d->a, nx*sizeof(mreal));
 	}
 	else
 	{
 		mx = -n1;	my = n2<0 ? -n2 : nx;	mz = n2<0 ? nx : ny;
 		if(n2>0 && ny==1)	mz = n2;
 		b = new mreal[mx*my*mz];
-		register mreal v;
-		if(n2<0)	for(j=0;j<nx;j++)	for(i=0,v=d->a[j];i<mx*my;i++)
-			b[i+mx*my*j] = v;
-		else	for(j=0;j<nx*ny;j++)	for(i=0,v=d->a[j];i<mx;i++)
-			b[i+mx*j] = v;
-		if(n2>0 && ny==1)	for(i=0;i<n2;i++)
-			memcpy(b+i*mx*my, d->a, mx*my*sizeof(mreal));
+		if(n2<0)
+#pragma omp parallel for collapse(2)
+			for(long j=0;j<nx;j++)	for(long i=0;i<mx*my;i++)
+				b[i+mx*my*j] = d->a[j];
+		else
+#pragma omp parallel for collapse(2)
+			for(long j=0;j<nx*ny;j++)	for(long i=0;i<mx;i++)
+				b[i+mx*j] = d->a[j];
+		if(n2>0 && ny==1)
+#pragma omp parallel for
+			for(long i=0;i<n2;i++)
+				memcpy(b+i*mx*my, d->a, mx*my*sizeof(mreal));
 	}
 	if(!d->link)	delete [](d->a);
 	d->a=b;	d->nx=mx;	d->ny=my;	d->nz=mz;
@@ -691,37 +752,41 @@ void MGL_EXPORT mgl_data_extend_(uintptr_t *d, int *n1, int *n2)
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_data_transpose(HMDT d, const char *dim)
 {
-	long nx=d->nx, ny=d->ny, nz=d->nz;
+	long nx=d->nx, ny=d->ny, nz=d->nz, n;
 	mreal *b=new mreal[nx*ny*nz], *a=d->a;
-	register long i,j,k,n;
 	if(!strcmp(dim,"xyz"))	memcpy(b,a,nx*ny*nz*sizeof(mreal));
 	else if(!strcmp(dim,"xzy") || !strcmp(dim,"zy"))
 	{
-		for(j=0;j<ny;j++)	for(k=0;k<nz;k++)	for(i=0;i<nx;i++)
+#pragma omp parallel for collapse(3)
+		for(long j=0;j<ny;j++)	for(long k=0;k<nz;k++)	for(long i=0;i<nx;i++)
 			b[i+nx*(k+nz*j)] = a[i+nx*(j+ny*k)];
 		n=nz;	nz=ny;	ny=n;
 	}
 	else if(!strcmp(dim,"yxz") || !strcmp(dim,"yx"))
 	{
-		for(k=0;k<nz;k++)	for(i=0;i<nx;i++)	for(j=0;j<ny;j++)
+#pragma omp parallel for collapse(3)
+		for(long k=0;k<nz;k++)	for(long i=0;i<nx;i++)	for(long j=0;j<ny;j++)
 			b[j+ny*(i+nx*k)] = a[i+nx*(j+ny*k)];
 		n=nx;	nx=ny;	ny=n;
 	}
 	else if(!strcmp(dim,"yzx"))
 	{
-		for(k=0;k<nz;k++)	for(i=0;i<nx;i++)	for(j=0;j<ny;j++)
+#pragma omp parallel for collapse(3)
+		for(long k=0;k<nz;k++)	for(long i=0;i<nx;i++)	for(long j=0;j<ny;j++)
 			b[j+ny*(k+nz*i)] = a[i+nx*(j+ny*k)];
 		n=nx;	nx=ny;	ny=nz;	nz=n;
 	}
 	else if(!strcmp(dim,"zxy"))
 	{
-		for(i=0;i<nx;i++)	for(j=0;j<ny;j++)	for(k=0;k<nz;k++)
+#pragma omp parallel for collapse(3)
+		for(long i=0;i<nx;i++)	for(long j=0;j<ny;j++)	for(long k=0;k<nz;k++)
 			b[k+nz*(i+nx*j)] = a[i+nx*(j+ny*k)];
 		n=nx;	nx=nz;	nz=ny;	ny=n;
 	}
 	else if(!strcmp(dim,"zyx") || !strcmp(dim,"zx"))
 	{
-		for(i=0;i<nx;i++)	for(j=0;j<ny;j++)	for(k=0;k<nz;k++)
+#pragma omp parallel for collapse(3)
+		for(long i=0;i<nx;i++)	for(long j=0;j<ny;j++)	for(long k=0;k<nz;k++)
 			b[k+nz*(j+ny*i)] = a[i+nx*(j+ny*k)];
 		n=nz;	nz=nx;	nx=n;
 	}
@@ -737,13 +802,16 @@ MGL_NO_EXPORT void *mgl_modify(void *par)
 {
 	mglThreadD *t=(mglThreadD *)par;
 	const mglFormula *f = (const mglFormula *)(t->v);
-	register long i,j,k,i0, nx=t->p[0],ny=t->p[1],nz=t->p[2];
+	long nx=t->p[0],ny=t->p[1],nz=t->p[2];
 	mreal *b=t->a, dx,dy,dz;
 	const mreal *v=t->b, *w=t->c;
 	dx=nx>1?1/(nx-1.):0;	dy=ny>1?1/(ny-1.):0;	dz=nz>1?1/(nz-1.):0;
-	for(i0=t->id;i0<t->n;i0+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i0=t->id;i0<t->n;i0+=mglNumThr)
 	{
-		i=i0%nx;	j=((i0/nx)%ny);	k=i0/(nx*ny);
+		register long i=i0%nx, j=((i0/nx)%ny), k=i0/(nx*ny);
 		b[i0] = f->Calc(i*dx, j*dy, k*dz, b[i0], v?v[i0]:0, w?w[i0]:0);
 	}
 	return 0;
@@ -772,13 +840,16 @@ MGL_NO_EXPORT void *mgl_modify_gen(void *par)
 {
 	mglThreadV *t=(mglThreadV *)par;
 	const mglFormula *f = (const mglFormula *)(t->v);
-	register long i,j,k,i0, nx=t->p[0],ny=t->p[1],nz=t->p[2];
+	register long nx=t->p[0],ny=t->p[1],nz=t->p[2];
 	mreal *b=t->a, dx,dy,dz;
 	HCDT v=(HCDT)t->b, w=(HCDT)t->c;
 	dx=nx>1?1/(nx-1.):0;	dy=ny>1?1/(ny-1.):0;	dz=nz>1?1/(nz-1.):0;
-	for(i0=t->id;i0<t->n;i0+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i0=t->id;i0<t->n;i0+=mglNumThr)
 	{
-		i=i0%nx;	j=((i0/nx)%ny);	k=i0/(nx*ny);
+		register long i=i0%nx, j=((i0/nx)%ny), k=i0/(nx*ny);
 		b[i0] = f->Calc(i*dx, j*dy, k*dz, b[i0], v?v->vthr(i0):0, w?w->vthr(i0):0);
 	}
 	return 0;
@@ -801,60 +872,6 @@ void MGL_EXPORT mgl_data_modify_vw_(uintptr_t *d, const char *eq, uintptr_t *v,
 {	char *s=new char[l+1];	memcpy(s,eq,l);	s[l]=0;
 	mgl_data_modify_vw(_DT_,s,_DA_(v),_DA_(w));	delete []s;	}
 //-----------------------------------------------------------------------------
-MGL_NO_EXPORT void *mgl_fill_f(void *par)
-{
-	mglThreadD *t=(mglThreadD *)par;
-	const mglFormula *f = (const mglFormula *)(t->v);
-	register long i,j,k,i0, nx=t->p[0],ny=t->p[1];
-	mreal *b=t->a;
-	const mreal *v=t->b, *w=t->c, *x=t->d;
-	for(i0=t->id;i0<t->n;i0+=mglNumThr)
-	{
-		i=i0%nx;	j=((i0/nx)%ny);	k=i0/(nx*ny);
-		b[i0] = f->Calc(x[0]+i*x[1], x[2]+j*x[3], x[4]+k*x[5], b[i0], v?v[i0]:0, w?w[i0]:0);
-	}
-	return 0;
-}
-MGL_NO_EXPORT void *mgl_fill_fgen(void *par)
-{
-	mglThreadV *t=(mglThreadV *)par;
-	const mglFormula *f = (const mglFormula *)(t->v);
-	register long i,j,k,i0, nx=t->p[0],ny=t->p[1];
-	mreal *b=t->a;
-	HCDT v=(HCDT)t->b, w=(HCDT)t->c;
-	const mreal *x=t->d;
-	for(i0=t->id;i0<t->n;i0+=mglNumThr)
-	{
-		i=i0%nx;	j=((i0/nx)%ny);	k=i0/(nx*ny);
-		b[i0] = f->Calc(x[0]+i*x[1], x[2]+j*x[3], x[4]+k*x[5], b[i0], v?v->vthr(i0):0, w?w->vthr(i0):0);
-	}
-	return 0;
-}
-void MGL_EXPORT mgl_data_fill_eq(HMGL gr, HMDT d, const char *eq, HCDT vdat, HCDT wdat, const char *opt)
-{
-	const mglData *v = dynamic_cast<const mglData *>(vdat);
-	const mglData *w = dynamic_cast<const mglData *>(wdat);
-	long nn = d->nx*d->ny*d->nz, par[3]={d->nx,d->ny,d->nz};
-	if(vdat && vdat->GetNN()!=nn)	return;
-	if(wdat && wdat->GetNN()!=nn)	return;
-	gr->SaveState(opt);
-	mreal xx[6]={gr->Min.x,0, gr->Min.y,0, gr->Min.z,0};
-	if(d->nx>1)	xx[1] = (gr->Max.x-gr->Min.x)/(d->nx-1.);
-	if(d->ny>1)	xx[3] = (gr->Max.y-gr->Min.y)/(d->ny-1.);
-	if(d->nz>1)	xx[5] = (gr->Max.z-gr->Min.z)/(d->nz-1.);
-	mglFormula f(eq);
-	if(v && w)	mglStartThread(mgl_fill_f,0,nn,d->a,v->a,w->a,par,&f,xx);
-	else if(vdat && wdat)	mglStartThreadV(mgl_fill_fgen,nn,d->a,vdat,wdat,par,&f,xx);
-	else if(v)	mglStartThread(mgl_fill_f,0,nn,d->a,v->a,0,par,&f,xx);
-	else if(vdat)	mglStartThreadV(mgl_fill_fgen,nn,d->a,vdat,0,par,&f,xx);
-	else	mglStartThread(mgl_fill_f,0,nn,d->a,0,0,par,&f,xx);
-	gr->LoadState();
-}
-void MGL_EXPORT mgl_data_fill_eq_(uintptr_t *gr, uintptr_t *d, const char *eq, uintptr_t *v, uintptr_t *w, const char *opt,int l,int lo)
-{	char *s=new char[l+1];	memcpy(s,eq,l);	s[l]=0;
-	char *o=new char[lo+1];	memcpy(o,opt,lo);	o[lo]=0;
-	mgl_data_fill_eq(_GR_,_DT_,s,_DA_(v),_DA_(w),o);	delete []o;	delete []s;	}
-//-----------------------------------------------------------------------------
 #if MGL_HAVE_HDF4
 int MGL_EXPORT mgl_data_read_hdf4(HMDT d,const char *fname,const char *data)
 {
@@ -1090,12 +1107,12 @@ int MGL_EXPORT mgl_data_read_all(HMDT dat, const char *templ, int as_slice)
 	{
 		if(mgl_data_read(&d,res.gl_pathv[i]))
 			if(!mgl_add_file(kx,ky,kz,b,&d,as_slice))
-			{	delete []fname;		return false;	}
+			{	delete []fname;	free(b);	return false;	}
 	}
 	dat->Set(b,kx,ky,kz);
 
 	globfree (&res);
-	delete []fname;		free(b);
+	delete []fname;	free(b);
 	return true;
 #else
 	return false;
diff --git a/src/data_png.cpp b/src/data_png.cpp
index 6c527b3..459b9b1 100644
--- a/src/data_png.cpp
+++ b/src/data_png.cpp
@@ -22,9 +22,9 @@
 #include <png.h>
 #endif
 //-----------------------------------------------------------------------------
-long MGL_NO_EXPORT mgl_col_dif(unsigned char *c1,unsigned char *c2,bool sum)
+size_t MGL_NO_EXPORT mgl_col_dif(unsigned char *c1,unsigned char *c2,bool sum)
 {
-	long res,d1=abs(long(c1[0])-long(c2[0])),
+	size_t res,d1=abs(long(c1[0])-long(c2[0])),
 		d2=abs(long(c1[1])-long(c2[1])),d3=abs(long(c1[2])-long(c2[2]));
 	if(sum)	res = d1+d2+d3;
 	else	res = mgl_max(d1,mgl_max(d2,d3));
@@ -33,32 +33,32 @@ long MGL_NO_EXPORT mgl_col_dif(unsigned char *c1,unsigned char *c2,bool sum)
 //-----------------------------------------------------------------------------
 MGL_NO_EXPORT unsigned char *mgl_create_scheme(const char *scheme,long &num)
 {
-	unsigned char *c=0,*cc=new unsigned char[3*strlen(scheme)+3];
-	long nc=1,np=0;
-	register long i,j;
+	unsigned char *c=0,*cc=new unsigned char[3*strlen(scheme)+3],*c1,*c2;
+	size_t nc=1,np=0,l=strlen(scheme);
 	mglColor col;
-	for(i=0;i<long(strlen(scheme));i++)
+	for(size_t i=0;i<l;i++)
 	{
 		col = mglColor(scheme[i]);
 		if(col.Valid())
-		{	cc[3*np]=col.r;	cc[3*np+1]=col.g;	cc[3*np+2]=col.b;	np++;	}
+		{	cc[3*np]=255*col.r;	cc[3*np+1]=255*col.g;	cc[3*np+2]=255*col.b;	np++;	}
 	}
 	if(np<2)	{	delete []cc;	return 0;	}
-	for(i=0;i<np-1;i++)	nc+=mgl_col_dif(cc+3*i,cc+3*i+3,false);
+	for(size_t i=0;i<np-1;i++)	nc+=mgl_col_dif(cc+3*i,cc+3*i+3,false);
 	c = new unsigned char[3*nc+3];
-	long dd,pos=0;
-	for(i=0;i<np-1;i++)
+	size_t dd,pos=0;
+	for(size_t i=0;i<np-1;i++)
 	{
 		dd=mgl_col_dif(cc+3*i,cc+3*i+3,false);
-		for(j=0;j<dd;j++)
+		for(size_t j=0;j<dd;j++)
 		{
-			c[3*(pos+j)] = cc[3*i]+(cc[3*i+3]-cc[3*i])*j/dd;
-			c[3*(pos+j)+1] = cc[3*i+1]+(cc[3*i+4]-cc[3*i+1])*j/dd;
-			c[3*(pos+j)+2] = cc[3*i+2]+(cc[3*i+5]-cc[3*i+2])*j/dd;
+			c1 = c+3*(pos+j);	c2 = cc+3*i;
+			c1[0] = c2[0]+(c2[3]-c2[0])*j/dd;
+			c1[1] = c2[1]+(c2[4]-c2[1])*j/dd;
+			c1[2] = c2[2]+(c2[5]-c2[2])*j/dd;
 		}
 		pos += dd;
 	}
-	memcpy(c+3*nc-3,cc+3*np-3,3*sizeof(unsigned char));
+	memcpy(c+3*nc-3,cc+3*np-3,3);
 	delete []cc;
 	num=nc;
 	return c;
@@ -91,11 +91,11 @@ void MGL_EXPORT mgl_data_import(HMDT d, const char *fname, const char *scheme,mr
 		long w=png_get_image_width(png_ptr, info_ptr);
 		long h=png_get_image_height(png_ptr, info_ptr);
 		d->Create(w,h,1);
-		register long i,j,k;
-		long pos=0,val,mval=256;
-		for(i=0;i<d->ny;i++)	for(j=0;j<d->nx;j++)
+#pragma omp parallel for collapse(2)
+		for(long i=0;i<d->ny;i++)	for(long j=0;j<d->nx;j++)
 		{
-			for(mval=256,k=0;k<num;k++)
+			size_t pos=0,val,mval=256;
+			for(long k=0;k<num;k++)
 			{
 				val = mgl_col_dif(c+3*k,rows[d->ny-i-1]+3*j,true);
 				if(val==0)	{	pos=k;	break;	}
@@ -104,9 +104,8 @@ void MGL_EXPORT mgl_data_import(HMDT d, const char *fname, const char *scheme,mr
 			d->a[j+d->nx*i] = v1 + pos*(v2-v1)/num;
 		}
 	}
-	delete []c;
 	png_destroy_read_struct(&png_ptr, &info_ptr,&end_info);
-	fclose(fp);
+	fclose(fp);	delete []c;
 #else
 	mglGlobalMess += "PNG support was disabled. Please, enable it and rebuild MathGL.\n";
 #endif
@@ -115,49 +114,57 @@ void MGL_EXPORT mgl_data_import(HMDT d, const char *fname, const char *scheme,mr
 void MGL_EXPORT mgl_data_export(HCDT dd, const char *fname, const char *scheme,mreal v1,mreal v2,long ns)
 {
 #if MGL_HAVE_PNG
-	register long i,j,k;
 	long nx=dd->GetNx(), ny=dd->GetNy(), nz=dd->GetNz();
 	const mglData *md = dynamic_cast<const mglData *>(dd);
-	mreal vv;
 	if(v1>v2)	return;
 	if(ns<0 || ns>=nz)	ns=0;
 	if(v1==v2)
 	{
 		v1 = 1e20;	v2=-1e20;
-		if(md)	for(i=0;i<nx*ny*nz;i++)
-		{	vv = md->a[i];	if(vv<v1)	v1=vv;	if(vv>v2)	v2=vv;	}
-		else	for(i=0;i<nx*ny*nz;i++)
-		{	vv = dd->vthr(i);	if(vv<v1)	v1=vv;	if(vv>v2)	v2=vv;	}
+		if(md)
+//#pragma omp parallel for	// NOTE comparison here
+			for(long i=0;i<nx*ny*nz;i++)
+			{	register mreal vv = md->a[i];	if(vv<v1)	v1=vv;	if(vv>v2)	v2=vv;	}
+		else
+//#pragma omp parallel for	// NOTE comparison here
+			for(long i=0;i<nx*ny*nz;i++)
+			{	register mreal vv = dd->vthr(i);	if(vv<v1)	v1=vv;	if(vv>v2)	v2=vv;	}
 	}
 	if(v1==v2)	return;
 	long num=0;
 	unsigned char *c = mgl_create_scheme(scheme,num);
 	if(num<2)	{	delete []c;		return;		}
 
-	unsigned char **p = (unsigned char **)malloc(ny*sizeof(unsigned char *));
-	unsigned char *d = (unsigned char *)malloc(3*nx*ny*sizeof(unsigned char));
-	for(i=0;i<ny;i++)	p[i] = d+3*nx*(ny-1-i);
-	if(md)	for(i=0;i<ny;i++)	for(j=0;j<nx;j++)
-	{
-		k = long(num*(md->a[j+nx*(i+ny*nz)]-v1)/(v2-v1));
-		if(k<0)	k=0;	if(k>=num) k=num-1;
-		memcpy(d+3*(j+i*nx),c+3*k,3*sizeof(unsigned char));
-	}
-	else	for(i=0;i<ny;i++)	for(j=0;j<nx;j++)
-	{
-		k = long(num*(dd->v(j,i,ns)-v1)/(v2-v1));
-		if(k<0)	k=0;	if(k>=num) k=num-1;
-		memcpy(d+3*(j+i*nx),c+3*k,3*sizeof(unsigned char));
-	}
+	unsigned char **p = new unsigned char*[ny];
+	unsigned char *d = new unsigned char[3*nx*ny];
+#pragma omp parallel for
+	for(long i=0;i<ny;i++)	p[i] = d+3*nx*(ny-1-i);
+	if(md)
+#pragma omp parallel for collapse(2)
+		for(long i=0;i<ny;i++)	for(long j=0;j<nx;j++)
+		{
+			register mreal vv = md->a[j+nx*(i+ny*ns)];
+			register long k = long(num*(vv-v1)/(v2-v1));
+			if(k<0)	k=0;	if(k>=num) k=num-1;
+			memcpy(d+3*(j+i*nx),c+3*k,3);
+		}
+	else
+#pragma omp parallel for collapse(2)
+		for(long i=0;i<ny;i++)	for(long j=0;j<nx;j++)
+		{
+			register long k = long(num*(dd->v(j,i,ns)-v1)/(v2-v1));
+			if(k<0)	k=0;	if(k>=num) k=num-1;
+			memcpy(d+3*(j+i*nx),c+3*k,3);
+		}
 	delete []c;
 
 	FILE *fp = fopen(fname, "wb");
-	if (!fp)	{	free(p);	free(d);	return;	}
+	if (!fp)	{	delete []p;	delete []d;	return;	}
 	png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
-	if (!png_ptr)	{	free(p);	free(d);	fclose(fp);	return;	}
+	if (!png_ptr)	{	delete []p;	delete []d;	fclose(fp);	return;	}
 	png_infop info_ptr = png_create_info_struct(png_ptr);
 	if (!info_ptr)
-	{	png_destroy_write_struct(&png_ptr,0);	free(p);	free(d);	fclose(fp);	return;	}
+	{	png_destroy_write_struct(&png_ptr,0);	delete []p;	delete []d;	fclose(fp);	return;	}
 	png_init_io(png_ptr, fp);
 	png_set_filter(png_ptr, 0, PNG_ALL_FILTERS);
 	png_set_compression_level(png_ptr, Z_BEST_COMPRESSION);
@@ -167,7 +174,7 @@ void MGL_EXPORT mgl_data_export(HCDT dd, const char *fname, const char *scheme,m
 	png_write_png(png_ptr, info_ptr,  PNG_TRANSFORM_IDENTITY, 0);
 	png_write_end(png_ptr, info_ptr);
 	png_destroy_write_struct(&png_ptr, &info_ptr);
-	fclose(fp);	free(p);	free(d);
+	fclose(fp);	delete []p;	delete []d;
 #else
 	mglGlobalMess += "PNG support was disabled. Please, enable it and rebuild MathGL.\n";
 #endif
diff --git a/src/eval.cpp b/src/eval.cpp
index 8e180a6..2f92d9e 100644
--- a/src/eval.cpp
+++ b/src/eval.cpp
@@ -147,20 +147,34 @@ void MGL_EXPORT mgl_srnd(long seed)
 }
 void MGL_EXPORT mgl_srnd_(int *seed)	{	mgl_srnd(*seed);	}
 //-----------------------------------------------------------------------------
+#if MGL_HAVE_PTHREAD
+pthread_mutex_t mutexRnd;
+#endif
 double MGL_EXPORT mgl_rnd()
 {
-#if MGL_HAVE_GSL
-	if(mgl_rng==0)
+#if MGL_HAVE_PTHREAD
+	pthread_mutex_lock(&mutexRnd);
+#endif
+	double res;
+#pragma omp critical(rnd)
 	{
-		gsl_rng_env_setup();
-		mgl_rng = gsl_rng_alloc(gsl_rng_default);
-		gsl_rng_set(mgl_rng, time(0));
-	}
-	return gsl_rng_uniform(mgl_rng);
-//	gsl_rng_free(r);
+#if MGL_HAVE_GSL
+		if(mgl_rng==0)
+		{
+			gsl_rng_env_setup();
+			mgl_rng = gsl_rng_alloc(gsl_rng_default);
+			gsl_rng_set(mgl_rng, time(0));
+		}
+		res = gsl_rng_uniform(mgl_rng);
+//		gsl_rng_free(r);
 #else
-	return rand()/(RAND_MAX-1.);
+		res = rand()/(RAND_MAX-1.);
+#endif
+	}
+#if MGL_HAVE_PTHREAD
+	pthread_mutex_unlock(&mutexRnd);
 #endif
+	return res;
 }
 double MGL_EXPORT mgl_rnd_()	{	return mgl_rnd();	}
 //-----------------------------------------------------------------------------
@@ -483,14 +497,14 @@ typedef double (*func_2)(double, double);
 // evaluation of embedded (included) expressions
 mreal mglFormula::CalcIn(const mreal *a1) const
 {
-	mreal z2[22] = {3,3,3,3,0,3,3,0,0,0,0,0,NAN,0
+	mreal z2[EQ_SIN-EQ_LT] = {3,3,3,3,0,3,3,0,0,0,0,0,NAN,0
 #if MGL_HAVE_GSL
 			,3,NAN, 3,NAN, 0,0,3,1
 #else
 			,0,0,0,0,0,0,0,0
 #endif
 		};
-	func_2 f2[22] = {clt,cgt,ceq,cor,cand,add,sub,mul,del,ipw,pow,fmod,llg,arg
+	func_2 f2[EQ_SIN-EQ_LT] = {clt,cgt,ceq,cor,cand,add,sub,mul,del,ipw,pow,fmod,llg,arg
 #if MGL_HAVE_GSL
 			,gsl_sf_bessel_Jnu,gsl_sf_bessel_Ynu,
 			gsl_sf_bessel_Inu,gsl_sf_bessel_Knu,
@@ -499,7 +513,7 @@ mreal mglFormula::CalcIn(const mreal *a1) const
 			,mgz2,mgz2,mgz2,mgz2,mgz2,mgz2,mgz2,mgz2
 #endif
 		};
-	func_1 f1[42] = {sin,cos,tan,asin,acos,atan,sinh,cosh,tanh,
+	func_1 f1[EQ_SN-EQ_SIN] = {sin,cos,tan,asin,acos,atan,sinh,cosh,tanh,
 					asinh,acosh,atanh,sqrt,exp,log,log10,sgn,stp,floor,fabs
 #if MGL_HAVE_GSL
 			,gsl_sf_dilog,gslEllEc,gslEllFc,gslAi,gslBi,gsl_sf_erf,
@@ -519,21 +533,23 @@ mreal mglFormula::CalcIn(const mreal *a1) const
 		else	return (Kod==EQ_A) ? a1[int(Res)] : Res;
 	}
 	double a = Left->CalcIn(a1);
-	if(!mgl_isnan(a))
+	if(mgl_isfin(a))
 	{
 		if(Kod<EQ_SIN)
 		{
 			// try to bypass calc b if a==0
 			if(a==0 && z2[Kod-EQ_LT]!=3)	return z2[Kod-EQ_LT];
 			double b = Right->CalcIn(a1);
-			return !mgl_isnan(b) ? f2[Kod-EQ_LT](a,b) : NAN;
+			b = mgl_isfin(b) ? f2[Kod-EQ_LT](a,b):NAN;
+			return mgl_isfin(b) ? b : NAN;
 		}
-		else if(Kod<EQ_SN)	return f1[Kod-EQ_SIN](a);
+		else if(Kod<EQ_SN)
+		{	a = f1[Kod-EQ_SIN](a);	return mgl_isfin(a)?a:NAN;	}	
 #if MGL_HAVE_GSL
 		else if(Kod<=EQ_DC)
 		{
 			double sn=0,cn=0,dn=0,b = Right->CalcIn(a1);
-			if(mgl_isnan(b))	return NAN;
+			if(mgl_isbad(b))	return NAN;
 			gsl_sf_elljac_e(a,b, &sn, &cn, &dn);
 			switch(Kod)
 			{
@@ -605,21 +621,21 @@ double MGL_NO_EXPORT gamma_d(double a)	{return gsl_sf_psi(a)*gsl_sf_gamma(a);}
 // evaluation of derivative of embedded (included) expressions
 mreal mglFormula::CalcDIn(int id, const mreal *a1) const
 {
-	func_2 f21[22] = {mgz2,mgz2,mgz2, mgz2,mgz2,mgp, mgp,mul1,div1, ipw1,pow1,mgp,llg1, mgz2
+	func_2 f21[EQ_SIN-EQ_LT] = {mgz2,mgz2,mgz2, mgz2,mgz2,mgp, mgp,mul1,div1, ipw1,pow1,mgp,llg1, mgz2
 #if MGL_HAVE_GSL
 			,mgz2,mgz2,mgz2, mgz2,gslEllE1,gslEllF2, mgz2,mgz2
 #else
 			,mgz2,mgz2,mgz2,mgz2,mgz2,mgz2,mgz2,mgz2
 #endif
 		};
-		func_2 f22[22] = {mgz2,mgz2,mgz2,mgz2,mgz2,mgp,mgm,mul2,div2,pow2,pow2,mgz2,llg2, mgz2
+		func_2 f22[EQ_SIN-EQ_LT] = {mgz2,mgz2,mgz2,mgz2,mgz2,mgp,mgm,mul2,div2,pow2,pow2,mgz2,llg2, mgz2
 #if MGL_HAVE_GSL
 			,gslJnuD,gslYnuD,gslInuD,gslKnuD,gslEllE2,gslEllF2,mgz2/*gslLegP*/,mgz2
 #else
 			,mgz2,mgz2,mgz2,mgz2,mgz2,mgz2,mgz2,mgz2
 #endif
 		};
-	func_1 f11[42] = {cos,cos_d,tan_d,asin_d,acos_d,atan_d,cosh,sinh,tanh_d,
+	func_1 f11[EQ_SN-EQ_SIN] = {cos,cos_d,tan_d,asin_d,acos_d,atan_d,cosh,sinh,tanh_d,
 					asinh_d,acosh_d,atanh_d,sqrt_d,exp,log_d,log10_d,mgz1,mgz1,mgz1,sgn
 #if MGL_HAVE_GSL
 			,dilog_d,gslE_d,gslK_d,gslAi_d,gslBi_d,erf_d,exp3_d,ei_d,e1_d,e2_d,
@@ -632,19 +648,21 @@ mreal mglFormula::CalcDIn(int id, const mreal *a1) const
 	if(Kod<EQ_LT)	return (Kod==EQ_A && id==(int)Res)?1:0;
 
 	double a = Left->CalcIn(a1), d = Left->CalcDIn(id,a1);
-	if(!mgl_isnan(a) && !mgl_isnan(d))
+	if(mgl_isfin(a) && mgl_isfin(d))
 	{
 		if(Kod<EQ_SIN)
 		{
 			double b = Right->CalcIn(a1), c = Right->CalcDIn(id,a1);
-			return !mgl_isnan(b) ? (d?f21[Kod-EQ_LT](a,b)*d:0) + (c?f22[Kod-EQ_LT](a,b)*c:0) : NAN;
+			b = mgl_isfin(b) ? (d?f21[Kod-EQ_LT](a,b)*d:0) + (c?f22[Kod-EQ_LT](a,b)*c:0) : NAN;
+			return mgl_isfin(b) ? b : NAN;
 		}
-		else if(Kod<EQ_SN)	return (d?f11[Kod-EQ_SIN](a)*d:0);
+		else if(Kod<EQ_SN)
+		{	a = (d?f11[Kod-EQ_SIN](a)*d:0);	return mgl_isfin(a)?a:NAN;	}
 #if MGL_HAVE_GSL
 		else if(Kod<=EQ_DC)
 		{
 			double sn=0,cn=0,dn=0,b = Right->CalcIn(a1);
-			if(mgl_isnan(b))	return NAN;
+			if(mgl_isbad(b))	return NAN;
 			gsl_sf_elljac_e(a,b, &sn, &cn, &dn);
 			switch(Kod)	// At this moment parse only differentiation or argument NOT mu !!!
 			{
diff --git a/src/evalc.cpp b/src/evalc.cpp
index eb945ba..22b49fe 100644
--- a/src/evalc.cpp
+++ b/src/evalc.cpp
@@ -56,7 +56,8 @@ EQ_EXP,		// exponential function \exp(x)
 EQ_EXPI,		// exponential function \exp(i*x)
 EQ_LN,		// logarithm of x, ln(x)
 EQ_LG,		// decimal logarithm of x, lg(x) = ln(x)/ln(10)
-EQ_ABS		// absolute value
+EQ_ABS,		// absolute value
+EQ_LAST		// id of last entry
 };
 //-----------------------------------------------------------------------------
 int mglFormulaC::Error=0;
@@ -238,8 +239,8 @@ typedef dual (*func_2)(dual, dual);
 // evaluation of embedded (included) expressions
 dual mglFormulaC::CalcIn(const dual *a1) const
 {
-	func_2 f2[7] = {addc,subc,mulc,divc,ipwc,powc,llgc};
-	func_1 f1[18] = {sinc,cosc,tanc,asinc,acosc,atanc,sinhc,coshc,tanhc,
+	func_2 f2[EQ_SIN-EQ_ADD] = {addc,subc,mulc,divc,ipwc,powc,llgc};
+	func_1 f1[EQ_LAST-EQ_SIN] = {sinc,cosc,tanc,asinc,acosc,atanc,sinhc,coshc,tanhc,
 					asinhc,acoshc,atanhc,sqrtc,expc,expi,logc,lgc,absc};
 //	if(Error)	return 0;
 	if(Kod==EQ_A)	return a1[(int)Res.real()];
@@ -247,16 +248,18 @@ dual mglFormulaC::CalcIn(const dual *a1) const
 	if(Kod==EQ_NUM) return Res;
 
 	dual a = Left->CalcIn(a1);
-	if(mgl_isnan(a.real()) || mgl_isnan(a.imag()))	return NAN;
-
-	if(Kod<EQ_SIN)
+	if(mgl_isfin(a))
 	{
-		dual b = Right->CalcIn(a1);
-		if(mgl_isnan(b.real()) || mgl_isnan(b.imag()))	return NAN;
-		return f2[Kod-EQ_ADD](a,b);
+		if(Kod<EQ_SIN)
+		{
+			dual b = Right->CalcIn(a1);
+			b = mgl_isfin(b)?f2[Kod-EQ_ADD](a,b):NAN;
+			return mgl_isfin(b)?b:NAN;
+		}
+		else
+		{	a = f1[Kod-EQ_SIN](a);	return mgl_isfin(a)?a:NAN;	}
 	}
-	else	return f1[Kod-EQ_SIN](a);
-	return Res;
+	return NAN;
 }
 //-----------------------------------------------------------------------------
 dual MGL_EXPORT mgl_ipowc(dual x,int n)
diff --git a/src/evalp.cpp b/src/evalp.cpp
index a0d7700..fdc8191 100644
--- a/src/evalp.cpp
+++ b/src/evalp.cpp
@@ -25,37 +25,53 @@
 #include <gsl/gsl_errno.h>
 #endif
 //-----------------------------------------------------------------------------
+std::wstring mgl_trim_ws(const std::wstring &str);
 int mglFormulaError;
-mglData MGL_NO_EXPORT mglFormulaCalc(const wchar_t *string, mglParser *arg);
+mglData MGL_NO_EXPORT mglFormulaCalc(std::wstring string, mglParser *arg);
 //-----------------------------------------------------------------------------
-mglData mglApplyOper(const wchar_t *a1, const wchar_t *a2, mglParser *arg, double (*func)(double,double))
+void mglApplyFunc(mglData &d, double (*func)(double))
+{
+	long n = d.nx*d.ny*d.nz;
+#pragma omp parallel for
+	for(long i=0;i<n;i++)	d.a[i] = func(d.a[i]);
+}
+//-----------------------------------------------------------------------------
+mglData mglApplyOper(std::wstring a1, std::wstring a2, mglParser *arg, double (*func)(double,double))
 {
 	const mglData &a = mglFormulaCalc(a1,arg), &b = mglFormulaCalc(a2,arg);
 	long n = mgl_max(a.nx,b.nx), m = mgl_max(a.ny,b.ny), l = mgl_max(a.nz,b.nz);
 	mglData r(n, m, l);
-	register int i,j,k;
-	if(b.nx*b.ny*b.nz==1)	for(i=0;i<a.nx*a.ny*a.nz;i++)
-		r.a[i] = func(a.a[i],b.a[0]);
-	else if(a.nx*a.ny*a.nz==1)	for(i=0;i<b.nx*b.ny*b.nz;i++)
-		r.a[i] = func(a.a[0],b.a[i]);
-	else if(a.nx==b.nx && b.ny==a.ny && b.nz==a.nz)	for(i=0;i<n*m*l;i++)
-		r.a[i] = func(a.a[i], b.a[i]);
-	else if(a.nx==b.nx && b.ny*b.nz==1)	for(i=0;i<n;i++)	for(j=0;j<a.ny*a.nz;j++)
-		r.a[i+n*j] = func(a.a[i+n*j], b.a[i]);
-	else if(a.nx==b.nx && a.ny*a.nz==1)	for(i=0;i<n;i++)	for(j=0;j<b.ny*b.nz;j++)
-		r.a[i+n*j] = func(a.a[i], b.a[i+n*j]);
+	if(b.nx*b.ny*b.nz==1)
+#pragma omp parallel for
+		for(long i=0;i<a.nx*a.ny*a.nz;i++)	r.a[i] = func(a.a[i],b.a[0]);
+	else if(a.nx*a.ny*a.nz==1)
+#pragma omp parallel for
+		for(long i=0;i<b.nx*b.ny*b.nz;i++)	r.a[i] = func(a.a[0],b.a[i]);
+	else if(a.nx==b.nx && b.ny==a.ny && b.nz==a.nz)
+#pragma omp parallel for
+		for(long i=0;i<n*m*l;i++)	r.a[i] = func(a.a[i], b.a[i]);
+	else if(a.nx==b.nx && b.ny*b.nz==1)
+#pragma omp parallel for collapse(2)
+		for(long j=0;j<a.ny*a.nz;j++)	for(long i=0;i<n;i++)
+			r.a[i+n*j] = func(a.a[i+n*j], b.a[i]);
+	else if(a.nx==b.nx && a.ny*a.nz==1)
+#pragma omp parallel for collapse(2)
+		for(long i=0;i<n;i++)	for(long j=0;j<b.ny*b.nz;j++)
+			r.a[i+n*j] = func(a.a[i], b.a[i+n*j]);
 	else if(a.nx==b.nx && b.ny==a.ny && b.nz==1)
-		for(i=0;i<n;i++)	for(j=0;j<m;j++)	for(k=0;k<a.nz;k++)
+#pragma omp parallel for collapse(3)
+		for(long k=0;k<a.nz;k++)	for(long j=0;j<m;j++)	for(long i=0;i<n;i++)
 			r.a[i+n*(j+m*k)] = func(a.a[i+n*(j+m*k)], b.a[i+n*j]);
 	else if(a.nx==b.nx && b.ny==a.ny && a.nz==1)
-		for(i=0;i<n;i++)	for(j=0;j<m;j++)	for(k=0;k<b.nz;k++)
+#pragma omp parallel for collapse(3)
+		for(long k=0;k<b.nz;k++)	for(long j=0;j<m;j++)	for(long i=0;i<n;i++)
 			r.a[i+n*(j+m*k)] = func(a.a[i+n*j], b.a[i+n*(j+m*k)]);
 	return r;
 }
 //-----------------------------------------------------------------------------
-bool mglCheck(wchar_t *str,int n)
+bool mglCheck(std::wstring str)
 {
-	register long s = 0,i;
+	register long s = 0,i,n=str.length();
 	for(i=0;i<n;i++)
 	{
 		if(str[i]=='(')	s++;
@@ -65,10 +81,10 @@ bool mglCheck(wchar_t *str,int n)
 	return (s==0) ? true : false;
 }
 //-----------------------------------------------------------------------------
-int mglFindInText(wchar_t *str,const char *lst)
+int mglFindInText(std::wstring str,const char *lst)
 {
 	register long l=0,r=0,i;//,j,len=strlen(lst);
-	for(i=wcslen(str)-1;i>=0;i--)
+	for(i=str.length()-1;i>=0;i--)
 	{
 		if(str[i]=='(') l++;
 		if(str[i]==')') r++;
@@ -109,24 +125,17 @@ void MGL_EXPORT mgl_wcstombs(char *dst, const wchar_t *src, int size)
 // NOTE: In any case where number is required the mglData::a[0] is used.
 // String flag is binary 0x1 -> 'x', 0x2 -> 'y', 0x4 -> 'z'
 // NOTE: the speed is not a goal (mglFormula is faster). It is true interpreter!
-mglData MGL_NO_EXPORT mglFormulaCalc(const wchar_t *string, mglParser *arg)
+mglData MGL_NO_EXPORT mglFormulaCalc(std::wstring str, mglParser *arg)
 {
 #if MGL_HAVE_GSL
 	gsl_set_error_handler_off();
 #endif
 	mglData res;
-	if(!string || !(*string) || mglFormulaError)	return res;	// nothing to parse
-	wchar_t *str = new wchar_t[wcslen(string)+1],ch;
-	wcscpy(str,string);
-	long n,len;
-	mgl_wcstrim(str);	//	mgl_wcslwr(str);
-	len=wcslen(str);
-	if(str[0]=='(' && mglCheck(&(str[1]),len-2))	// remove braces
-	{
-		memmove(str,str+1,len*sizeof(wchar_t));
-		len-=2;	str[len]=0;
-	}
-	len=wcslen(str);
+	if(str.empty() || mglFormulaError)	return res;	// nothing to parse
+	str = mgl_trim_ws(str);
+	long n,len=str.length();
+	if(str[0]=='(' && mglCheck(str.substr(1,len-2)))	// remove braces
+	{	str = str.substr(1,len-2);	len-=2;	}
 	if(str[0]=='[')	// this is manual subdata
 	{
 		mglData a1;
@@ -138,7 +147,7 @@ mglData MGL_NO_EXPORT mglFormulaCalc(const wchar_t *string, mglParser *arg)
 			if(str[i]==']' && br>0)	br--;
 			if(str[i]==',' && !br)
 			{
-				str[i]=0;	a1=mglFormulaCalc(str+j, arg);
+				a1=mglFormulaCalc(str.substr(j,i-j), arg);
 				if(j==1)
 				{	res = a1;	ar = (a1.nx==1);	mt = (a1.nx>1 && a1.ny==1);	}
 				else
@@ -153,7 +162,7 @@ mglData MGL_NO_EXPORT mglFormulaCalc(const wchar_t *string, mglParser *arg)
 				j=i+1;
 			}
 		}
-		str[i]=0;	a1=mglFormulaCalc(str+j, arg);
+		a1=mglFormulaCalc(str.substr(j,i-j), arg);
 		if(j==1)
 		{	res = a1;	ar = (a1.nx==1);	mt = (a1.nx>1 && a1.ny==1);	}
 		else
@@ -170,132 +179,98 @@ mglData MGL_NO_EXPORT mglFormulaCalc(const wchar_t *string, mglParser *arg)
 
 	n=mglFindInText(str,"&|");				// lowest priority -- logical
 	if(n>=0)
-	{
-		ch=str[n];	str[n]=0;
-		res = mglApplyOper(str,str+n+1,arg, ch=='|'?cor:cand);
-		delete []str;		return res;
-	}
+		return mglApplyOper(str.substr(0,n),str.substr(n+1),arg, str[n]=='|'?cor:cand);
 	n=mglFindInText(str,"<>=");				// low priority -- conditions
 	if(n>=0)
-	{
-		ch=str[n];	str[n]=0;
-		if(ch=='<')		res = mglApplyOper(str,str+n+1,arg, clt);
-		else if(ch=='>')	res = mglApplyOper(str,str+n+1,arg, cgt);
-		else 	res = mglApplyOper(str,str+n+1,arg, ceq);
-		delete []str;		return res;
-	}
+		return mglApplyOper(str.substr(0,n),str.substr(n+1),arg, str[n]=='<'?clt:(str[n]=='>'?cgt:ceq));
 	n=mglFindInText(str,"+-");				// normal priority -- additions
 	if(n>=0 && (n<2 || str[n-1]!='e' || (str[n-2]!='.' && !isdigit(str[n-2]))))
-	{
-		ch=str[n];	str[n]=0;
-		res = mglApplyOper(str,str+n+1,arg, ch=='+'?add:sub);
-		delete []str;		return res;
-	}
+		return mglApplyOper(str.substr(0,n),str.substr(n+1),arg, str[n]=='+'?add:sub);
 	n=mglFindInText(str,"*/");				// high priority -- multiplications
 	if(n>=0)
-	{
-		ch=str[n];	str[n]=0;
-		res = mglApplyOper(str,str+n+1,arg, ch=='*'?mul:del);
-		delete []str;		return res;
-	}
+		return mglApplyOper(str.substr(0,n),str.substr(n+1),arg, str[n]=='*'?mul:del);
 	n=mglFindInText(str,"@");				// high priority -- combine
 	if(n>=0)
-	{
-		str[n]=0;
-		const mglData &a = mglFormulaCalc(str,arg), &b = mglFormulaCalc(str+n+1,arg);
-		delete []str;		return a.Combine(b);
-	}
+		return mglFormulaCalc(str.substr(0,n),arg).Combine(mglFormulaCalc(str.substr(n+1),arg));
 	n=mglFindInText(str,"^");				// highest priority -- power
 	if(n>=0)
-	{
-		str[n]=0;
-		res = mglApplyOper(str,str+n+1,arg, ipw);
-		delete []str;		return res;
-	}
+		return mglApplyOper(str.substr(0,n),str.substr(n+1),arg, ipw);
 	n=mglFindInText(str,":");				// highest priority -- array
-	if(n>=0 && wcscmp(str,L":"))
+	if(n>=0 && str.compare(L":"))
 	{
-		str[n]=0;
-		mglData a1=mglFormulaCalc(str, arg);
-		mglData a2=mglFormulaCalc(str+n+1, arg);
+		const mglData &a1=mglFormulaCalc(str.substr(0,n), arg);
+		const mglData &a2=mglFormulaCalc(str.substr(n+1), arg);
 		res.Create(abs(int(a2.a[0]+0.5)-int(a1.a[0]+0.5))+1);
 		res.Fill(a1.a[0], a2.a[0]);
-		delete []str;		return res;
+		return res;
 	}
 	n=mglFindInText(str,".");				// highest priority -- suffixes
 	if(n>=0)
 	{
-		str[n]=0;
 		mreal x,y,z,k,v=NAN;
-		mglData d = mglFormulaCalc(str, arg);
-		const wchar_t *p=str+n+1;
-		if(!wcscmp(p,L"a"))			v = d.a[0];
-		else if(!wcscmp(p,L"fst"))	{	long i=-1,j=-1,l=-1;	v = d.Find(0,i,j,l);	}
-		else if(!wcscmp(p,L"lst"))	{	long i=-1,j=-1,l=-1;	v = d.Last(0,i,j,l);	}
-		else if(!wcscmp(p,L"nx"))	v=d.nx;
-		else if(!wcscmp(p,L"ny"))	v=d.ny;
-		else if(!wcscmp(p,L"nz"))	v=d.nz;
-		else if(!wcscmp(p,L"max"))	v=d.Maximal();
-		else if(!wcscmp(p,L"min"))	v=d.Minimal();
-		else if(!wcscmp(p,L"sum"))	v=d.Momentum('x',x,y);
-		else if(!wcscmp(p,L"mx"))	{	d.Maximal(x,y,z);	v=x/d.nx;	}
-		else if(!wcscmp(p,L"my"))	{	d.Maximal(x,y,z);	v=y/d.ny;	}
-		else if(!wcscmp(p,L"mz"))	{	d.Maximal(x,y,z);	v=z/d.nz;	}
-		else if(!wcscmp(p,L"ax"))	{	d.Momentum('x',x,y);	v=x/d.nx;	}
-		else if(!wcscmp(p,L"ay"))	{	d.Momentum('y',x,y);	v=x/d.ny;	}
-		else if(!wcscmp(p,L"az"))	{	d.Momentum('z',x,y);	v=x/d.nz;	}
-		else if(!wcscmp(p,L"wx"))	{	d.Momentum('x',x,y);	v=y/d.nx;	}
-		else if(!wcscmp(p,L"wy"))	{	d.Momentum('y',x,y);	v=y/d.ny;	}
-		else if(!wcscmp(p,L"wz"))	{	d.Momentum('z',x,y);	v=y/d.nz;	}
-		else if(!wcscmp(p,L"sx"))	{	d.Momentum('x',x,y,z,k);	v=z/d.nx;	}
-		else if(!wcscmp(p,L"sy"))	{	d.Momentum('y',x,y,z,k);	v=z/d.ny;	}
-		else if(!wcscmp(p,L"sz"))	{	d.Momentum('z',x,y,z,k);	v=z/d.nz;	}
-		else if(!wcscmp(p,L"kx"))	{	d.Momentum('x',x,y,z,k);	v=k/d.nx;	}
-		else if(!wcscmp(p,L"ky"))	{	d.Momentum('y',x,y,z,k);	v=k/d.ny;	}
-		else if(!wcscmp(p,L"kz"))	{	d.Momentum('z',x,y,z,k);	v=k/d.nz;	}
-		else if(!wcscmp(p,L"aa"))	{	d.Momentum('a',x,y);	v=x;	}
-		else if(!wcscmp(p,L"wa"))	{	d.Momentum('a',x,y);	v=y;	}
-		else if(!wcscmp(p,L"sa"))	{	d.Momentum('a',x,y,z,k);v=z;	}
-		else if(!wcscmp(p,L"ka"))	{	d.Momentum('a',x,y,z,k);v=k;	}
+		mglData d = mglFormulaCalc(str.substr(0,n), arg);
+		const std::wstring &p=str.substr(n+1);
+		if(!p.compare(L"a"))			v = d.a[0];
+		else if(!p.compare(L"fst"))	{	long i=-1,j=-1,l=-1;	v = d.Find(0,i,j,l);	}
+		else if(!p.compare(L"lst"))	{	long i=-1,j=-1,l=-1;	v = d.Last(0,i,j,l);	}
+		else if(!p.compare(L"nx"))	v=d.nx;
+		else if(!p.compare(L"ny"))	v=d.ny;
+		else if(!p.compare(L"nz"))	v=d.nz;
+		else if(!p.compare(L"max"))	v=d.Maximal();
+		else if(!p.compare(L"min"))	v=d.Minimal();
+		else if(!p.compare(L"pmax"))	{	v=d.Maximal();	v = v>0?v:0;	}
+		else if(!p.compare(L"pmin"))	{	v=d.Minimal();	v = v>0?v:0;	}
+		else if(!p.compare(L"sum"))	v=d.Momentum('x',x,y);
+		else if(!p.compare(L"mx"))	{	d.Maximal(x,y,z);	v=x/d.nx;	}
+		else if(!p.compare(L"my"))	{	d.Maximal(x,y,z);	v=y/d.ny;	}
+		else if(!p.compare(L"mz"))	{	d.Maximal(x,y,z);	v=z/d.nz;	}
+		else if(!p.compare(L"ax"))	{	d.Momentum('x',x,y);	v=x/d.nx;	}
+		else if(!p.compare(L"ay"))	{	d.Momentum('y',x,y);	v=x/d.ny;	}
+		else if(!p.compare(L"az"))	{	d.Momentum('z',x,y);	v=x/d.nz;	}
+		else if(!p.compare(L"wx"))	{	d.Momentum('x',x,y);	v=y/d.nx;	}
+		else if(!p.compare(L"wy"))	{	d.Momentum('y',x,y);	v=y/d.ny;	}
+		else if(!p.compare(L"wz"))	{	d.Momentum('z',x,y);	v=y/d.nz;	}
+		else if(!p.compare(L"sx"))	{	d.Momentum('x',x,y,z,k);	v=z/d.nx;	}
+		else if(!p.compare(L"sy"))	{	d.Momentum('y',x,y,z,k);	v=z/d.ny;	}
+		else if(!p.compare(L"sz"))	{	d.Momentum('z',x,y,z,k);	v=z/d.nz;	}
+		else if(!p.compare(L"kx"))	{	d.Momentum('x',x,y,z,k);	v=k/d.nx;	}
+		else if(!p.compare(L"ky"))	{	d.Momentum('y',x,y,z,k);	v=k/d.ny;	}
+		else if(!p.compare(L"kz"))	{	d.Momentum('z',x,y,z,k);	v=k/d.nz;	}
+		else if(!p.compare(L"aa"))	{	d.Momentum('a',x,y);	v=x;	}
+		else if(!p.compare(L"wa"))	{	d.Momentum('a',x,y);	v=y;	}
+		else if(!p.compare(L"sa"))	{	d.Momentum('a',x,y,z,k);v=z;	}
+		else if(!p.compare(L"ka"))	{	d.Momentum('a',x,y,z,k);v=k;	}
 		// if this is valid suffix when finish parsing (it can be mreal number)
-		if(!mgl_isnan(v))	{	res.a[0] = v;	delete []str;	return res;	}
-		else 	str[n]='.';
+		if(mgl_isfin(v))	{	res.a[0] = v;	return res;	}
 	}
 	for(n=0;n<len;n++)	if(str[n]=='(')	break;
 	if(n>=len)		// this is number or variable
 	{
-		mglVar *v = arg->FindVar(str);
-		mglNum *f = arg->FindNum(str);
+		mglVar *v = arg->FindVar(str.c_str());
+		mglNum *f = arg->FindNum(str.c_str());
 		if(v)	res = v;
 		else if(f)	res.a[0] = f->d;
-		else if(!wcscmp(str,L"rnd"))	res.a[0] = mgl_rnd();
-		else if(!wcscmp(str,L"nan"))	res.a[0] = NAN;
-		else if(!wcscmp(str,L"pi"))		res.a[0] = M_PI;
-		else if(!wcscmp(str,L"on"))		res.a[0] = 1;
-		else if(!wcscmp(str,L"off"))	res.a[0] = 0;
-		else if(!wcscmp(str,L":"))		res.a[0] = -1;
-		else res.a[0] = wcstod(str,0);		// this is number
-		delete []str;	return res;
+		else if(!str.compare(L"rnd"))	res.a[0] = mgl_rnd();
+		else if(!str.compare(L"nan"))	res.a[0] = NAN;
+		else if(!str.compare(L"pi"))	res.a[0] = M_PI;
+		else if(!str.compare(L"on"))	res.a[0] = 1;
+		else if(!str.compare(L"off"))	res.a[0] = 0;
+		else if(!str.compare(L":"))		res.a[0] = -1;
+		else res.a[0] = wcstod(str.c_str(),0);	// this is number
+		return res;
 	}
 	else
 	{
-		register long i;
-		wchar_t name[128];
-		wcsncpy(name,str,128);	name[127]=name[n]=0;
-		memmove(str,str+n+1,(len-n)*sizeof(wchar_t));
-		len=wcslen(str);		str[--len]=0;
-		mglVar *v = arg->FindVar(name);
-		if(!v)
-		{
-			if(!wcsncmp(name,L"jacobi_",7))
-				memmove(name,name+7,(wcslen(name+7)+1)*sizeof(wchar_t));
-		}
+		std::wstring nm = str.substr(0,n);
+		str = str.substr(n+1,len-n-2);	len -= n+2;
+		mglVar *v = arg->FindVar(nm.c_str());
+		if(!v && !nm.compare(0,7,L"jacobi_"))	nm = nm.substr(7);
 		if(v)	// subdata
 		{
 			if(str[0]=='\'' && str[len-1]=='\'')	// this is column call
 			{
 				char *buf = new char[len];
-				str[len-1]=0;	mgl_wcstombs(buf, str+1, len-1);
+				mgl_wcstombs(buf, str.substr(1).c_str(), len-1);	buf[len-1]=0;
 				res=v->Column(buf);	delete []buf;
 			}
 			else
@@ -306,333 +281,275 @@ mglData MGL_NO_EXPORT mglFormulaCalc(const wchar_t *string, mglParser *arg)
 				n=mglFindInText(str,",");
 				if(n>0)
 				{
-					str[n]=0;	m=mglFindInText(str,",");
+					m=mglFindInText(str.substr(0,n),",");
 					if(m>0)
 					{
 						str[m]=0;
-						a1 = mglFormulaCalc(str, arg);
-						a2 = mglFormulaCalc(str+m+1, arg);
-						a3 = mglFormulaCalc(str+n+1, arg);
+						a1 = mglFormulaCalc(str.substr(0,m), arg);
+						a2 = mglFormulaCalc(str.substr(m+1,n-m-1), arg);
+						a3 = mglFormulaCalc(str.substr(n+1), arg);
 					}
 					else
 					{
-						a1 = mglFormulaCalc(str, arg);
-						a2 = mglFormulaCalc(str+n+1, arg);
+						a1 = mglFormulaCalc(str.substr(0,n), arg);
+						a2 = mglFormulaCalc(str.substr(n+1), arg);
 					}
 				}
 				else	a1 = mglFormulaCalc(str, arg);
 				res = v->SubData(a1,a2,a3);
 			}
 		}
-		else if(name[0]=='a')	// function
+		else if(nm[0]=='a')	// function
 		{
-			if(!wcscmp(name+1,L"sin"))
-			{	res=mglFormulaCalc(str, arg);
-				for(i=0;i<res.nx*res.ny*res.nz;i++)	res.a[i] = asin(res.a[i]);	}
-			else if(!wcscmp(name+1,L"cos"))
-			{	res=mglFormulaCalc(str, arg);
-				for(i=0;i<res.nx*res.ny*res.nz;i++)	res.a[i] = acos(res.a[i]);	}
-			else if(!wcscmp(name+1,L"tan"))
-			{	res=mglFormulaCalc(str, arg);
-				for(i=0;i<res.nx*res.ny*res.nz;i++)	res.a[i] = atan(res.a[i]);	}
-			else if(!wcscmp(name+1,L"rg"))
+			if(!nm.compare(L"asin"))
+			{	res=mglFormulaCalc(str, arg);	mglApplyFunc(res,asin);	}
+			else if(!nm.compare(L"acos"))
+			{	res=mglFormulaCalc(str, arg);	mglApplyFunc(res,acos);	}
+			else if(!nm.compare(L"atan"))
+			{	res=mglFormulaCalc(str, arg);	mglApplyFunc(res,atan);	}
+			else if(!nm.compare(L"arg"))
 			{
 				n=mglFindInText(str,",");
 				if(n<=0)	mglFormulaError=true;
-				else
-				{	str[n]=0;	res = mglApplyOper(str+n+1,str,arg, atan2);	}
+				else	res = mglApplyOper(str.substr(n+1),str.substr(0,n),arg, atan2);
 			}
-			else if(!wcscmp(name+1,L"bs"))
-			{	res=mglFormulaCalc(str, arg);
-				for(i=0;i<res.nx*res.ny*res.nz;i++)	res.a[i] = fabs(res.a[i]);	}
+			else if(!nm.compare(L"abs"))
+			{	res=mglFormulaCalc(str, arg);	mglApplyFunc(res,fabs);	}
 #if MGL_HAVE_GSL
-			else if(!wcscmp(name+1,L"i"))
-			{	res=mglFormulaCalc(str, arg);
-				for(i=0;i<res.nx*res.ny*res.nz;i++)
-					res.a[i] = gsl_sf_airy_Ai(res.a[i],GSL_PREC_SINGLE);	}
-			else if(!wcscmp(name+1,L"iry_ai"))
+			else if(!nm.compare(L"ai") || !nm.compare(L"airy_ai"))
 			{	res=mglFormulaCalc(str, arg);
-				for(i=0;i<res.nx*res.ny*res.nz;i++)
+#pragma omp parallel for
+				for(long i=0;i<res.nx*res.ny*res.nz;i++)
 					res.a[i] = gsl_sf_airy_Ai(res.a[i],GSL_PREC_SINGLE);	}
-			else if(!wcscmp(name+1,L"iry_dai"))
+			else if(!nm.compare(L"airy_dai"))
 			{	res=mglFormulaCalc(str, arg);
-				for(i=0;i<res.nx*res.ny*res.nz;i++)
+#pragma omp parallel for
+				for(long i=0;i<res.nx*res.ny*res.nz;i++)
 					res.a[i] = gsl_sf_airy_Ai_deriv(res.a[i],GSL_PREC_SINGLE);	}
-			else if(!wcscmp(name+1,L"iry_bi"))
+			else if(!nm.compare(L"airy_bi"))
 			{	res=mglFormulaCalc(str, arg);
-				for(i=0;i<res.nx*res.ny*res.nz;i++)
+#pragma omp parallel for
+				for(long i=0;i<res.nx*res.ny*res.nz;i++)
 					res.a[i] = gsl_sf_airy_Bi(res.a[i],GSL_PREC_SINGLE);	}
-			else if(!wcscmp(name+1,L"iry_dbi"))
+			else if(!nm.compare(L"airy_dbi"))
 			{	res=mglFormulaCalc(str, arg);
-				for(i=0;i<res.nx*res.ny*res.nz;i++)
+#pragma omp parallel for
+				for(long i=0;i<res.nx*res.ny*res.nz;i++)
 					res.a[i] = gsl_sf_airy_Bi_deriv(res.a[i],GSL_PREC_SINGLE);	}
 		}
-		else if(name[0]=='b')
+		else if(nm[0]=='b')
 		{
-			if(!wcscmp(name+1,L"eta"))
+			if(!nm.compare(L"beta"))
 			{
 				n=mglFindInText(str,",");
 				if(n<=0)	mglFormulaError=true;
-				else
-				{	str[n]=0;	res = mglApplyOper(str,str+n+1,arg, gsl_sf_beta);	}
+				else	res = mglApplyOper(str.substr(0,n),str.substr(n+1),arg, gsl_sf_beta);
 			}
-			else if(!wcscmp(name+1,L"i"))
+			else if(!nm.compare(L"bi"))
 			{	res=mglFormulaCalc(str, arg);
-				for(i=0;i<res.nx*res.ny*res.nz;i++)
+#pragma omp parallel for
+				for(long i=0;i<res.nx*res.ny*res.nz;i++)
 					res.a[i] = gsl_sf_airy_Bi(res.a[i],GSL_PREC_SINGLE);	}
-#endif
-		}
-		else if(name[0]=='c')
-		{
-			if(!wcscmp(name+1,L"os"))
-			{	res=mglFormulaCalc(str, arg);
-				for(i=0;i<res.nx*res.ny*res.nz;i++)	res.a[i] = cos(res.a[i]);	}
-			else if(!wcscmp(name+1,L"osh") || !wcscmp(name+1,L"h"))
-			{	res=mglFormulaCalc(str, arg);
-				for(i=0;i<res.nx*res.ny*res.nz;i++)	res.a[i] = cosh(res.a[i]);	}
-#if MGL_HAVE_GSL
-			else if(!wcscmp(name+1,L"i"))
-			{	res=mglFormulaCalc(str, arg);
-				for(i=0;i<res.nx*res.ny*res.nz;i++)
-					res.a[i] = gsl_sf_Ci(res.a[i]);	}
-			else if(!wcscmp(name+1,L"essel_i"))
+			else if(!nm.compare(L"bessel_i"))
 			{
 				n=mglFindInText(str,",");
 				if(n<=0)	mglFormulaError=true;
-				else
-				{	str[n]=0;	res = mglApplyOper(str,str+n+1,arg, gsl_sf_bessel_Inu);	}
+				else	res = mglApplyOper(str.substr(0,n),str.substr(n+1),arg, gsl_sf_bessel_Inu);
 			}
-			else if(!wcscmp(name+1,L"essel_j"))
+			else if(!nm.compare(L"bessel_j"))
 			{
 				n=mglFindInText(str,",");
 				if(n<=0)	mglFormulaError=true;
-				else
-				{	str[n]=0;	res = mglApplyOper(str,str+n+1,arg, gsl_sf_bessel_Jnu);	}
+				else	res = mglApplyOper(str.substr(0,n),str.substr(n+1),arg, gsl_sf_bessel_Jnu);
 			}
-			else if(!wcscmp(name+1,L"essel_k"))
+			else if(!nm.compare(L"bessel_k"))
 			{
 				n=mglFindInText(str,",");
 				if(n<=0)	mglFormulaError=true;
-				else
-				{	str[n]=0;	res = mglApplyOper(str,str+n+1,arg, gsl_sf_bessel_Knu);	}
+				else	res = mglApplyOper(str.substr(0,n),str.substr(n+1),arg, gsl_sf_bessel_Knu);
 			}
-			else if(!wcscmp(name+1,L"essel_y"))
+			else if(!nm.compare(L"bessel_y"))
 			{
 				n=mglFindInText(str,",");
 				if(n<=0)	mglFormulaError=true;
-				else
-				{	str[n]=0;	res = mglApplyOper(str,str+n+1,arg, gsl_sf_bessel_Ynu);	}
+				else	res = mglApplyOper(str.substr(0,n),str.substr(n+1),arg, gsl_sf_bessel_Ynu);
 			}
 #endif
 		}
-		else if(name[0]=='e')
+		else if(nm[0]=='c')
 		{
-			if(!wcscmp(name+1,L"xp"))
-			{	res=mglFormulaCalc(str, arg);
-				for(i=0;i<res.nx*res.ny*res.nz;i++)	res.a[i] = exp(res.a[i]);	}
+			if(!nm.compare(L"cos"))
+			{	res=mglFormulaCalc(str, arg);	mglApplyFunc(res,cos);	}
+			else if(!nm.compare(L"cosh") || !nm.compare(L"ch"))
+			{	res=mglFormulaCalc(str, arg);	mglApplyFunc(res,cosh);	}
 #if MGL_HAVE_GSL
-			else if(!wcscmp(name+1,L"rf"))
-			{	res=mglFormulaCalc(str, arg);
-				for(i=0;i<res.nx*res.ny*res.nz;i++)
-					res.a[i] = gsl_sf_erf(res.a[i]);	}
-//			else if(!wcscmp(name+1,L"n"))	Kod=EQ_EN;	// NOTE: not supported
-			else if(!wcscmp(name+1,L"e") || !wcscmp(name+1,L"lliptic_ec"))
+			else if(!nm.compare(L"ci"))
+			{	res=mglFormulaCalc(str, arg);	mglApplyFunc(res,gsl_sf_Ci);	}
+#endif
+		}
+		else if(nm[0]=='e')
+		{
+			if(!nm.compare(L"exp"))
+			{	res=mglFormulaCalc(str, arg);	mglApplyFunc(res,exp);	}
+#if MGL_HAVE_GSL
+			else if(!nm.compare(L"erf"))
+			{	res=mglFormulaCalc(str, arg);	mglApplyFunc(res,gsl_sf_erf);	}
+//			else if(!nm.compare(L"en"))	Kod=EQ_EN;	// NOTE: not supported
+			else if(!nm.compare(L"ee") || !nm.compare(L"elliptic_ec"))
 			{	res=mglFormulaCalc(str, arg);
-				for(i=0;i<res.nx*res.ny*res.nz;i++)
+#pragma omp parallel for
+				for(long i=0;i<res.nx*res.ny*res.nz;i++)
 					res.a[i] = gsl_sf_ellint_Ecomp(res.a[i],GSL_PREC_SINGLE);	}
-			else if(!wcscmp(name+1,L"k") || !wcscmp(name+1,L"lliptic_kc"))
+			else if(!nm.compare(L"ek") || !nm.compare(L"elliptic_kc"))
 			{	res=mglFormulaCalc(str, arg);
-				for(i=0;i<res.nx*res.ny*res.nz;i++)
+#pragma omp parallel for
+				for(long i=0;i<res.nx*res.ny*res.nz;i++)
 					res.a[i] = gsl_sf_ellint_Kcomp(res.a[i],GSL_PREC_SINGLE);	}
-			else if(name[0]==0 || !wcscmp(name+1,L"lliptic_e"))
+			else if(!nm.compare(L"e") || !nm.compare(L"elliptic_e"))
 			{
 				n=mglFindInText(str,",");
 				if(n<=0)	mglFormulaError=true;
-				else
-				{	str[n]=0;	res = mglApplyOper(str,str+n+1,arg, gslEllE);	}
+				else	res = mglApplyOper(str.substr(0,n),str.substr(n+1),arg, gslEllE);
 			}
-			else if(!wcscmp(name+1,L"lliptic_f"))
+			else if(!nm.compare(L"elliptic_f"))
 			{
 				n=mglFindInText(str,",");
 				if(n<=0)	mglFormulaError=true;
-				else
-				{	str[n]=0;	res = mglApplyOper(str,str+n+1,arg, gslEllF);	}
+				else	res = mglApplyOper(str.substr(0,n),str.substr(n+1),arg, gslEllF);
 			}
 
-			else if(!wcscmp(name+1,L"i"))
-			{	res=mglFormulaCalc(str, arg);
-				for(i=0;i<res.nx*res.ny*res.nz;i++)
-					res.a[i] = gsl_sf_expint_Ei(res.a[i]);	}
-			else if(!wcscmp(name+1,L"1"))
-			{	res=mglFormulaCalc(str, arg);
-				for(i=0;i<res.nx*res.ny*res.nz;i++)
-					res.a[i] = gsl_sf_expint_E1(res.a[i]);	}
-			else if(!wcscmp(name+1,L"2"))
-			{	res=mglFormulaCalc(str, arg);
-				for(i=0;i<res.nx*res.ny*res.nz;i++)
-					res.a[i] = gsl_sf_expint_E2(res.a[i]);	}
-			else if(!wcscmp(name+1,L"ta"))
-			{	res=mglFormulaCalc(str, arg);
-				for(i=0;i<res.nx*res.ny*res.nz;i++)
-					res.a[i] = gsl_sf_eta(res.a[i]);	}
-			else if(!wcscmp(name+1,L"i3"))
-			{	res=mglFormulaCalc(str, arg);
-				for(i=0;i<res.nx*res.ny*res.nz;i++)
-					res.a[i] = gsl_sf_expint_3(res.a[i]);	}
+			else if(!nm.compare(L"ei"))
+			{	res=mglFormulaCalc(str, arg);	mglApplyFunc(res,gsl_sf_expint_Ei);	}
+			else if(!nm.compare(L"e1"))
+			{	res=mglFormulaCalc(str, arg);	mglApplyFunc(res,gsl_sf_expint_E1);	}
+			else if(!nm.compare(L"e2"))
+			{	res=mglFormulaCalc(str, arg);	mglApplyFunc(res,gsl_sf_expint_E2);	}
+			else if(!nm.compare(L"eta"))
+			{	res=mglFormulaCalc(str, arg);	mglApplyFunc(res,gsl_sf_eta);	}
+			else if(!nm.compare(L"ei3"))
+			{	res=mglFormulaCalc(str, arg);	mglApplyFunc(res,gsl_sf_expint_3);	}
 #endif
 		}
-		else if(name[0]=='l')
+		else if(nm[0]=='l')
 		{
-			if(!wcscmp(name+1,L"og"))
+			if(!nm.compare(L"log"))
 			{
 				n=mglFindInText(str,",");
 				if(n<=0)	mglFormulaError=true;
-				else
-				{	str[n]=0;	res = mglApplyOper(str,str+n+1,arg, llg);	}
+				else	res = mglApplyOper(str.substr(0,n),str.substr(n+1),arg, llg);
 			}
-			else if(!wcscmp(name+1,L"g"))
-			{	res=mglFormulaCalc(str, arg);
-				for(i=0;i<res.nx*res.ny*res.nz;i++)	res.a[i] = log10(res.a[i]);	}
-			else if(!wcscmp(name+1,L"n"))
-			{	res=mglFormulaCalc(str, arg);
-				for(i=0;i<res.nx*res.ny*res.nz;i++)	res.a[i] = log(res.a[i]);	}
+			else if(!nm.compare(L"lg"))
+			{	res=mglFormulaCalc(str, arg);	mglApplyFunc(res,log10);	}
+			else if(!nm.compare(L"ln"))
+			{	res=mglFormulaCalc(str, arg);	mglApplyFunc(res,log);	}
 #if MGL_HAVE_GSL
-			else if(!wcscmp(name+1,L"i2"))
-			{	res=mglFormulaCalc(str, arg);
-				for(i=0;i<res.nx*res.ny*res.nz;i++)
-					res.a[i] = gsl_sf_dilog(res.a[i]);	}
-			else if(!wcscmp(name+1,L"egendre"))
+			else if(!nm.compare(L"li2"))
+			{	res=mglFormulaCalc(str, arg);	mglApplyFunc(res,gsl_sf_dilog);	}
+			else if(!nm.compare(L"legendre"))
 			{
 				n=mglFindInText(str,",");
 				if(n<=0)	mglFormulaError=true;
-				else
-				{	str[n]=0;	res = mglApplyOper(str,str+n+1,arg, gslLegP);	}
+				else	res = mglApplyOper(str.substr(0,n),str.substr(n+1),arg, gslLegP);
 			}
 #endif
 		}
-		else if(name[0]=='s')
+		else if(nm[0]=='s')
 		{
-			if(!wcscmp(name+1,L"qrt"))
-			{	res=mglFormulaCalc(str, arg);
-				for(i=0;i<res.nx*res.ny*res.nz;i++)	res.a[i] = sqrt(res.a[i]);	}
-			else if(!wcscmp(name+1,L"in"))
-			{	res=mglFormulaCalc(str, arg);
-				for(i=0;i<res.nx*res.ny*res.nz;i++)	res.a[i] = sin(res.a[i]);	}
-			else if(!wcscmp(name+1,L"tep"))
-			{	res=mglFormulaCalc(str, arg);
-				for(i=0;i<res.nx*res.ny*res.nz;i++)	res.a[i] = res.a[i]>0?1:0;	}
-			else if(!wcscmp(name+1,L"ign"))
-			{	res=mglFormulaCalc(str, arg);
-				for(i=0;i<res.nx*res.ny*res.nz;i++)
+			if(!nm.compare(L"sqrt"))
+			{	res=mglFormulaCalc(str, arg);	mglApplyFunc(res,sqrt);	}
+			else if(!nm.compare(L"sin"))
+			{	res=mglFormulaCalc(str, arg);	mglApplyFunc(res,sin);	}
+			else if(!nm.compare(L"step"))
+			{	res=mglFormulaCalc(str, arg);
+#pragma omp parallel for
+				for(long i=0;i<res.nx*res.ny*res.nz;i++)	res.a[i] = res.a[i]>0?1:0;	}
+			else if(!nm.compare(L"sign"))
+			{	res=mglFormulaCalc(str, arg);
+#pragma omp parallel for
+				for(long i=0;i<res.nx*res.ny*res.nz;i++)
 					res.a[i] = res.a[i]>0?1:(res.a[i]<0?-1:0);	}
-			else if(!wcscmp(name+1,L"inh") || !wcscmp(name+1,L"h"))
-			{	res=mglFormulaCalc(str, arg);
-				for(i=0;i<res.nx*res.ny*res.nz;i++)	res.a[i] = sinh(res.a[i]);	}
+			else if(!nm.compare(L"sinh") || !nm.compare(L"sh"))
+			{	res=mglFormulaCalc(str, arg);	mglApplyFunc(res,sinh);	}
 #if MGL_HAVE_GSL
-			else if(!wcscmp(name+1,L"i"))
-			{	res=mglFormulaCalc(str, arg);
-				for(i=0;i<res.nx*res.ny*res.nz;i++)
-					res.a[i] = gsl_sf_Si(res.a[i]);	}
-			else if(!wcscmp(name+1,L"inc"))
-			{	res=mglFormulaCalc(str, arg);
-				for(i=0;i<res.nx*res.ny*res.nz;i++)
-					res.a[i] = gsl_sf_sinc(res.a[i]);	}
+			else if(!nm.compare(L"si"))
+			{	res=mglFormulaCalc(str, arg);	mglApplyFunc(res,gsl_sf_Si);	}
+			else if(!nm.compare(L"sinc"))
+			{	res=mglFormulaCalc(str, arg);	mglApplyFunc(res,gsl_sf_sinc);	}
 #endif
 		}
-		else if(name[0]=='t')
+		else if(nm[0]=='t')
 		{
-			if(!wcscmp(name+1,L"g") || !wcscmp(name+1,L"an"))
-			{	res=mglFormulaCalc(str, arg);
-				for(i=0;i<res.nx*res.ny*res.nz;i++)	res.a[i] = tan(res.a[i]);	}
-			else if(!wcscmp(name+1,L"anh") || !wcscmp(name+1,L"h"))
-			{	res=mglFormulaCalc(str, arg);
-				for(i=0;i<res.nx*res.ny*res.nz;i++)	res.a[i] = tanh(res.a[i]);	}
+			if(!nm.compare(L"tg") || !nm.compare(L"tan"))
+			{	res=mglFormulaCalc(str, arg);	mglApplyFunc(res,tan);	}
+			else if(!nm.compare(L"tanh") || !nm.compare(L"th"))
+			{	res=mglFormulaCalc(str, arg);	mglApplyFunc(res,tanh);	}
 		}
-		else if(!wcscmp(name,L"pow"))
+		else if(!nm.compare(L"pow"))
 		{
 			n=mglFindInText(str,",");
 			if(n<=0)	mglFormulaError=true;
-			else
-			{	str[n]=0;	res = mglApplyOper(str,str+n+1,arg, pow);	}
+			else	res = mglApplyOper(str.substr(0,n),str.substr(n+1),arg, pow);
 		}
-		else if(!wcscmp(name,L"mod"))
+		else if(!nm.compare(L"mod"))
 		{
 			n=mglFindInText(str,",");
 			if(n<=0)	mglFormulaError=true;
-			else
-			{	str[n]=0;	res = mglApplyOper(str,str+n+1,arg, fmod);	}
+			else	res = mglApplyOper(str.substr(0,n),str.substr(n+1),arg, fmod);
 		}
-		else if(!wcscmp(name,L"int"))
-		{	res=mglFormulaCalc(str, arg);
-			for(i=0;i<res.nx*res.ny*res.nz;i++)	res.a[i] = floor(res.a[i]);	}
+		else if(!nm.compare(L"int"))
+		{	res=mglFormulaCalc(str, arg);	mglApplyFunc(res,floor);	}
 #if MGL_HAVE_GSL
-		else if(!wcscmp(name,L"i"))
+		else if(!nm.compare(L"i"))
 		{
 			n=mglFindInText(str,",");
 			if(n<=0)	mglFormulaError=true;
-			else
-			{	str[n]=0;	res = mglApplyOper(str,str+n+1,arg, gsl_sf_bessel_Inu);	}
+			else	res = mglApplyOper(str.substr(0,n),str.substr(n+1),arg, gsl_sf_bessel_Inu);
 		}
-		else if(!wcscmp(name,L"j"))
+		else if(!nm.compare(L"j"))
 		{
 			n=mglFindInText(str,",");
 			if(n<=0)	mglFormulaError=true;
-			else
-			{	str[n]=0;	res = mglApplyOper(str,str+n+1,arg, gsl_sf_bessel_Jnu);	}
+			else	res = mglApplyOper(str.substr(0,n),str.substr(n+1),arg, gsl_sf_bessel_Jnu);
 		}
-		else if(!wcscmp(name,L"k"))
+		else if(!nm.compare(L"k"))
 		{
 			n=mglFindInText(str,",");
 			if(n<=0)	mglFormulaError=true;
-			else
-			{	str[n]=0;	res = mglApplyOper(str,str+n+1,arg, gsl_sf_bessel_Knu);	}
+			else	res = mglApplyOper(str.substr(0,n),str.substr(n+1),arg, gsl_sf_bessel_Knu);
 		}
-		else if(!wcscmp(name,L"y"))
+		else if(!nm.compare(L"y"))
 		{
 			n=mglFindInText(str,",");
 			if(n<=0)	mglFormulaError=true;
-			else
-			{	str[n]=0;	res = mglApplyOper(str,str+n+1,arg, gsl_sf_bessel_Ynu);	}
+			else	res = mglApplyOper(str.substr(0,n),str.substr(n+1),arg, gsl_sf_bessel_Ynu);
 		}
-		else if(!wcscmp(name,L"f"))
+		else if(!nm.compare(L"f"))
 		{
 			n=mglFindInText(str,",");
 			if(n<=0)	mglFormulaError=true;
-			else
-			{	str[n]=0;	res = mglApplyOper(str,str+n+1,arg, gslEllF);	}
+			else	res = mglApplyOper(str.substr(0,n),str.substr(n+1),arg, gslEllF);
 		}
-		else if(!wcscmp(name,L"gamma"))
-		{	res=mglFormulaCalc(str, arg);
-			for(i=0;i<res.nx*res.ny*res.nz;i++)
-				res.a[i] = gsl_sf_gamma(res.a[i]);	}
-		else if(!wcscmp(name,L"w0"))
-		{	res=mglFormulaCalc(str, arg);
-			for(i=0;i<res.nx*res.ny*res.nz;i++)
-				res.a[i] = gsl_sf_lambert_W0(res.a[i]);	}
-		else if(!wcscmp(name,L"w1"))
-		{	res=mglFormulaCalc(str, arg);
-			for(i=0;i<res.nx*res.ny*res.nz;i++)
-				res.a[i] = gsl_sf_lambert_Wm1(res.a[i]);	}
-		else if(!wcscmp(name,L"psi"))
-		{	res=mglFormulaCalc(str, arg);
-			for(i=0;i<res.nx*res.ny*res.nz;i++)
-				res.a[i] = gsl_sf_psi(res.a[i]);	}
-		else if(!wcscmp(name,L"zeta"))
-		{	res=mglFormulaCalc(str, arg);
-			for(i=0;i<res.nx*res.ny*res.nz;i++)
-				res.a[i] = gsl_sf_zeta(res.a[i]);	}
-		else if(!wcscmp(name,L"z"))
-		{	res=mglFormulaCalc(str, arg);
-			for(i=0;i<res.nx*res.ny*res.nz;i++)
-				res.a[i] = gsl_sf_dawson(res.a[i]);	}
+		else if(!nm.compare(L"gamma"))
+		{	res=mglFormulaCalc(str, arg);	mglApplyFunc(res,gsl_sf_gamma);	}
+		else if(!nm.compare(L"w0"))
+		{	res=mglFormulaCalc(str, arg);	mglApplyFunc(res,gsl_sf_lambert_W0);	}
+		else if(!nm.compare(L"w1"))
+		{	res=mglFormulaCalc(str, arg);	mglApplyFunc(res,gsl_sf_lambert_Wm1);	}
+		else if(!nm.compare(L"psi"))
+		{	res=mglFormulaCalc(str, arg);	mglApplyFunc(res,gsl_sf_psi);	}
+		else if(!nm.compare(L"zeta"))
+		{	res=mglFormulaCalc(str, arg);	mglApplyFunc(res,gsl_sf_zeta);	}
+		else if(!nm.compare(L"z"))
+		{	res=mglFormulaCalc(str, arg);	mglApplyFunc(res,gsl_sf_dawson);	}
 #endif
 	}
-	delete []str;	return res;
+	return res;
 }
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_wcslwr(wchar_t *str)
 {
-	for(size_t k=0;k<wcslen(str);k++)	// ������� ��������� �������
+	register size_t l=mgl_wcslen(str);
+	for(size_t k=0;k<l;k++)
 		str[k] = (str[k]>='A' && str[k]<='Z') ? str[k]+'a'-'A' : str[k];
 }
 //-----------------------------------------------------------------------------
diff --git a/src/exec.cpp b/src/exec.cpp
index 9361514..e650d5e 100644
--- a/src/exec.cpp
+++ b/src/exec.cpp
@@ -25,7 +25,7 @@
 #endif
 
 #include "mgl2/parser.h"
-#define iint(x)	floor((x)+0.5)
+#define iint(x)	long((x)+0.5)
 wchar_t *mgl_str_copy(const char *s);
 //-----------------------------------------------------------------------------
 int MGL_NO_EXPORT mgls_addlegend(mglGraph *gr, long , mglArg *a, const char *k, const char *)
@@ -66,6 +66,15 @@ int MGL_NO_EXPORT mgls_plotid(mglGraph *gr, long , mglArg *a, const char *k, con
 	else  res = 1;	return res;
 }
 //-----------------------------------------------------------------------------
+int MGL_NO_EXPORT mgls_mask(mglGraph *gr, long , mglArg *a, const char *k, const char *)
+{
+	int res=0;
+	if(!strcmp(k,"sn"))	gr->SetMask(a[0].s[0],a[1].v);
+	else if(!strcmp(k,"ss"))	gr->SetMask(a[0].s[0],a[1].s.c_str());
+	else if(!strcmp(k,"n"))		gr->SetMaskAngle(iint(a[0].v));
+	else res = 1;	return res;
+}
+//-----------------------------------------------------------------------------
 int MGL_NO_EXPORT mgls_alphadef(mglGraph *gr, long , mglArg *a, const char *k, const char *)
 {
 	int res=0;
@@ -80,6 +89,13 @@ int MGL_NO_EXPORT mgls_ambient(mglGraph *gr, long , mglArg *a, const char *k, co
 	else res = 1;	return res;
 }
 //-----------------------------------------------------------------------------
+int MGL_NO_EXPORT mgls_diffuse(mglGraph *gr, long , mglArg *a, const char *k, const char *)
+{
+	int res=0;
+	if(!strcmp(k,"n"))	gr->SetDiffuse(a[0].v);
+	else res = 1;	return res;
+}
+//-----------------------------------------------------------------------------
 int MGL_NO_EXPORT mgls_area(mglGraph *gr, long , mglArg *a, const char *k, const char *opt)
 {
 	int res=0;
@@ -141,6 +157,16 @@ int MGL_NO_EXPORT mgls_box(mglGraph *gr, long , mglArg *a, const char *k, const
 	else res = 1;	return res;
 }
 //-----------------------------------------------------------------------------
+int MGL_NO_EXPORT mgls_ohlc(mglGraph *gr, long , mglArg *a, const char *k, const char *opt)
+{
+	int res=0;
+	if(!strcmp(k,"dddd"))	gr->OHLC(*(a[0].d),*(a[1].d),*(a[2].d),*(a[3].d), "",opt);
+	else if(!strcmp(k,"dddds"))	gr->OHLC(*(a[0].d),*(a[1].d),*(a[2].d),*(a[3].d), a[4].s.c_str(),opt);
+	else if(!strcmp(k,"ddddd"))	gr->OHLC(*(a[0].d),*(a[1].d),*(a[2].d),*(a[3].d),*(a[4].d), "",opt);
+	else if(!strcmp(k,"ddddds"))	gr->OHLC(*(a[0].d),*(a[1].d),*(a[2].d),*(a[3].d),*(a[4].d), a[5].s.c_str(),opt);
+	else res = 1;	return res;
+}
+//-----------------------------------------------------------------------------
 int MGL_NO_EXPORT mgls_bars(mglGraph *gr, long , mglArg *a, const char *k, const char *opt)
 {
 	int res=0;
@@ -222,10 +248,12 @@ int MGL_NO_EXPORT mgls_clearlegend(mglGraph *gr, long , mglArg *, const char *k,
 	else res = 1;	return res;
 }
 //-----------------------------------------------------------------------------
-int MGL_NO_EXPORT mgls_clf(mglGraph *gr, long , mglArg *, const char *k, const char *)
+int MGL_NO_EXPORT mgls_clf(mglGraph *gr, long , mglArg *a, const char *k, const char *)
 {
 	int res=0;
 	if(!strcmp(k,""))	gr->Clf();
+	else if(!strcmp(k,"s"))	gr->Clf(a[0].s[0]);
+	else if(!strcmp(k,"nnn"))	gr->Clf(a[0].v,a[1].v,a[2].v);
 	else res = 1;	return res;
 }
 //-----------------------------------------------------------------------------
@@ -622,6 +650,8 @@ int MGL_NO_EXPORT mgls_dots(mglGraph *gr, long , mglArg *a, const char *k, const
 	else if(!strcmp(k,"ddds"))	gr->Dots(*(a[0].d),*(a[1].d),*(a[2].d),a[3].s.c_str(),opt);
 	else if(!strcmp(k,"dddd"))	gr->Dots(*(a[0].d),*(a[1].d),*(a[2].d),*(a[3].d),"",opt);
 	else if(!strcmp(k,"dddds"))	gr->Dots(*(a[0].d),*(a[1].d),*(a[2].d),*(a[3].d),a[4].s.c_str(),opt);
+	else if(!strcmp(k,"ddddd"))	gr->Dots(*(a[0].d),*(a[1].d),*(a[2].d),*(a[3].d),*(a[4].d),"",opt);
+	else if(!strcmp(k,"ddddds"))gr->Dots(*(a[0].d),*(a[1].d),*(a[2].d),*(a[3].d),*(a[4].d),a[5].s.c_str(),opt);
 	else res = 1;	return res;
 }
 //-----------------------------------------------------------------------------
@@ -779,6 +809,17 @@ int MGL_NO_EXPORT mgls_fill(mglGraph *gr, long , mglArg *a, const char *k, const
 	else res = 1;	return res;
 }
 //-----------------------------------------------------------------------------
+int MGL_NO_EXPORT mgls_refill(mglGraph *gr, long , mglArg *a, const char *k, const char *opt)
+{
+	int res=0;
+	if(!strcmp(k,"ddd"))	gr->Refill(*(a[0].d),*(a[1].d),*(a[2].d),-1,opt);
+	else if(!strcmp(k,"dddn"))	gr->Refill(*(a[0].d),*(a[1].d),*(a[2].d),iint(a[3].v),opt);
+	else if(!strcmp(k,"dddd"))	gr->Refill(*(a[0].d),*(a[1].d),*(a[2].d),*(a[3].d),-1,opt);
+	else if(!strcmp(k,"ddddn"))	gr->Refill(*(a[0].d),*(a[1].d),*(a[2].d),*(a[3].d),iint(a[4].v),opt);
+	else if(!strcmp(k,"ddddd"))	gr->Refill(*(a[0].d),*(a[1].d),*(a[2].d),*(a[3].d),*(a[4].d),opt);
+	else res = 1;	return res;
+}
+//-----------------------------------------------------------------------------
 int MGL_NO_EXPORT mgls_fillsample(mglGraph *, long , mglArg *a, const char *k, const char *)
 {
 	int res=0;
@@ -1096,8 +1137,8 @@ int MGL_NO_EXPORT mgls_face(mglGraph *gr, long , mglArg *a, const char *k, const
 int MGL_NO_EXPORT mgls_resize(mglGraph *, long , mglArg *a, const char *k, const char *)
 {
 	int res=0;
-	if(!strcmp(k,"ddn"))	*(a[0].d) = a[1].d->Resize(iint(a[2].v), 1, 1);
-	else if(!strcmp(k,"ddnn"))	*(a[0].d) = a[1].d->Resize(iint(a[2].v), iint(a[3].v), 1);
+	if(!strcmp(k,"ddn"))	*(a[0].d) = a[1].d->Resize(iint(a[2].v));
+	else if(!strcmp(k,"ddnn"))	*(a[0].d) = a[1].d->Resize(iint(a[2].v), iint(a[3].v));
 	else if(!strcmp(k,"ddnnn"))	*(a[0].d) = a[1].d->Resize(iint(a[2].v), iint(a[3].v), iint(a[4].v));
 	else res = 1;	return res;
 }
@@ -1121,8 +1162,8 @@ int MGL_NO_EXPORT mgls_rotatetext(mglGraph *gr, long , mglArg *a, const char *k,
 int MGL_NO_EXPORT mgls_tuneticks(mglGraph *gr, long , mglArg *a, const char *k, const char *)
 {
 	int res=0;
-	if(!strcmp(k,"n"))	gr->SetTuneTicks(a[0].v!=0);
-	else if(!strcmp(k,"nn"))	gr->SetTuneTicks(a[0].v!=0,a[1].v);
+	if(!strcmp(k,"n"))	gr->SetTuneTicks(iint(a[0].v));
+	else if(!strcmp(k,"nn"))	gr->SetTuneTicks(iint(a[0].v),a[1].v);
 	else res = 1;	return res;
 }
 //-----------------------------------------------------------------------------
@@ -2292,6 +2333,13 @@ int MGL_NO_EXPORT mgls_combine(mglGraph *, long , mglArg *a, const char *k, cons
 	else res = 1;	return res;
 }
 //-----------------------------------------------------------------------------
+int MGL_NO_EXPORT mgls_correl(mglGraph *, long , mglArg *a, const char *k, const char *)
+{
+	int res=0;
+	if(!strcmp(k,"ddds"))	*(a[0].d) = a[1].d->Correl(*(a[2].d), a[3].s.c_str());
+	else res = 1;	return res;
+}
+//-----------------------------------------------------------------------------
 int MGL_NO_EXPORT mgls_roots(mglGraph *, long , mglArg *a, const char *k, const char *)
 {
 	int res=0;
@@ -2497,6 +2545,14 @@ int MGL_NO_EXPORT mgls_zoomaxis(mglGraph *gr, long , mglArg *a, const char *k, c
 	else res = 1;	return res;
 }
 //-----------------------------------------------------------------------------
+int MGL_NO_EXPORT mgls_drawreg(mglGraph *gr, long , mglArg *a, const char *k, const char *)
+{
+	int res=0;
+	if(!strcmp(k,""))	gr->SetDrawReg();
+	if(!strcmp(k,"nnn"))	gr->SetDrawReg(iint(a[0].v), iint(a[1].v), iint(a[2].v));
+	else res = 1;	return res;
+}
+//-----------------------------------------------------------------------------
 mglCommand mgls_base_cmd[] = {
 	{"addlegend","Add legend entry","addlegend 'txt' 'fmt'", mgls_addlegend,15},
 	{"addto","Add data or number","addto Var Dat|Var num", mgls_addto ,3},
@@ -2528,7 +2584,7 @@ mglCommand mgls_base_cmd[] = {
 	{"circle","Draw circle","circle x y r ['fmt']|x y z r ['fmt']", mgls_circle ,13},
 	{"clean","Remove duplicate rows","clean Dat id", mgls_clean ,3},
 	{"clearlegend","Clear legend antries","clearlegend", mgls_clearlegend ,15},
-	{"clf","Clear picture","clf", mgls_clf ,12},
+	{"clf","Clear picture","clf|'col'|r g b", mgls_clf ,12},
 	{"cloud","Draw cloud","cloud Adat ['fmt']|Xdat Ydat Zdat Adat ['fmt']", mgls_cloud ,9},
 	{"colorbar","Draw colorbar","colorbar ['fmt' pos]|Vdat ['fmt' pos]|'sch' pos x y [w h]|Vdat 'sch' pos x y [w h]", mgls_colorbar ,12},
 	{"column","Get data column filled by formula on column ids","column Res Dat 'eq'", mgls_column ,4},
@@ -2550,6 +2606,7 @@ mglCommand mgls_base_cmd[] = {
 	{"conty","Draw contour lines at y-slice (or y-plane)","conty Dat ['fmt' pos num]", mgls_conty ,0},
 	{"contz","Draw contour lines at z-slice (or z-plane)","contz Dat ['fmt' pos num]", mgls_contz ,0},
 	{"copy","Copy data from another variable","copy Dat1 Dat2 ['eq' onaxis]", mgls_copy ,4},
+	{"correl", "Find correlation between data arrays", "correl Res Adat Bdat 'dir'", mgls_correl ,4},
 	{"cosfft","Cos-Fourier transform at some direction","cosfft Dat 'dir'", mgls_cosfft ,16},
 	{"crange","Set color range","crange Dat [sym] | c1 c2", mgls_crange ,14},
 	{"crop","Crop edge of data","crop Dat n1 n2 'dir'", mgls_crop ,16},
@@ -2573,8 +2630,10 @@ mglCommand mgls_base_cmd[] = {
 	{"dew","Draw dew plot","dew Udat Vdat ['fmt']|Xdat Ydat Udat Vdat ['fmt']", mgls_dew ,11},
 	{"diff","Numerically differentiate data","diff Var 'dir'", mgls_diff ,16},
 	{"diff2","Numerically double differentiate data","diff2 Var 'dir'", mgls_diff2 ,16},
+	{"diffuse","Set diffusive light brightness","diffuse val", mgls_diffuse ,2},
 	{"divto","Divide by data or number","divto Var Dat|Var num", mgls_divto ,3},
-	{"dots","Draw dots for arbitrary data points","dots Xdat Ydat Zdat ['fmt']", mgls_dots ,9},
+	{"dots","Draw dots for arbitrary data points","dots Xdat Ydat Zdat ['fmt']|Xdat Ydat Zdat Adat ['fmt']|Xdat Ydat Zdat Cdat Adat ['fmt']", mgls_dots ,9},
+	{"drawreg","Set draw region for quality&4","drawreg|nx ny m", mgls_drawreg ,2},
 	{"drop","Draw drop","drop x0 y0 dx dy r ['col' sh asp]|x0 y0 z0 dx dy dz r ['col' sh asp]", mgls_drop ,13},
 	{"ellipse","Draw ellipse","ellipse x1 y1 x2 y2 r ['fmt']|x1 y1 z1 x2 y2 z2 r ['fmt']", mgls_ellipse ,13},
 	{"else","Execute if condition is false","else", 0, 6},
@@ -2584,7 +2643,7 @@ mglCommand mgls_base_cmd[] = {
 	{"errbox","Draw error box","errbox x y ex ey ['fmt']|x y z ex ey ez ['fmt']", mgls_errbox ,13},
 	{"error","Draw error boxes","error Ydat Yerr ['fmt']|Xdat Ydat Yerr ['fmt']|Xdat Ydat Xerr Yerr ['fmt']", mgls_error ,7},
 	{"evaluate","Evaluate (interpolate) values of array Dat at points i=idat,j=jdat,k=kdat","evaluate Res Dat Idat [norm]|Res Dat Idat Jdat [norm]|Res Dat Idat Jdat Kdat [norm]", mgls_evaluate ,4},
-	{"export","Export data to PNG picture","export Dat 'fname' 'sch' [v1 v2]", mgls_import ,3},
+	{"export","Export data to PNG picture","export Dat 'fname' 'sch' [v1 v2]", mgls_export ,3},
 	{"extend","Extend data array","extend Dat dim1 [dim2]", mgls_extend ,3},
 	{"face","Draw face (quadrangle)","face x1 y1 x2 y2 x3 y3 x4 y4 ['fmt']|x1 y1 z1 x2 y2 z2 x3 y3 z3 x4 y4 z4 ['fmt']", mgls_face ,13},
 	{"facenum","Set number of visible faces","facenum val", mgls_facenum ,2},
@@ -2632,6 +2691,7 @@ mglCommand mgls_base_cmd[] = {
 	{"map","Draw mapping plot","map Udat Vdat ['fmt']|Xdat Ydat Udat Vdat ['fmt']", mgls_map ,10},
 	{"mark","Draw mark plot for 1D data","mark Ydat Rdat ['fmt']|Xdat Ydat Rdat ['fmt']|Xdat Ydat Zdat Rdat ['fmt']", mgls_mark ,7},
 	{"marksize","Set size of markers","marksize val", mgls_marksize ,2},
+	{"mask","Set brush for given mask","mask 'id' 'val'|'id' val|angle", mgls_mask ,2},
 	{"max","Find maximal value over direction","max Res Dat 'dir'", mgls_max ,4},
 	{"mesh","Draw mesh surface","mesh Zdat ['fmt']|Xdat Ydat Zdat ['fmt']", mgls_mesh ,8},
 	{"meshnum","Set number of lines in mesh/fall/vect and so on","meshnum val", mgls_meshnum ,2},
@@ -2645,6 +2705,7 @@ mglCommand mgls_base_cmd[] = {
 	{"next","Start next for-cycle iteration","next", 0, 6},
 	{"norm","Normalize data","norm Dat v1 v2 [sym dim]", mgls_norm ,16},
 	{"normsl","Normalize data slice by slice","normsl Dat v1 v2 ['dir' keep sym] ", mgls_normsl ,16},
+	{"ohlc","Draw Open-High-Low-Close (OHLC) diagram","ohlc Odat Hdat Ldat Cdat ['fmt']|Xdat Odat Hdat Ldat Cdat ['fmt']", mgls_ohlc ,7},
 	{"once","Start/close commands which should executed only once","once val", 0, 6},
 	{"origin","Set axis origin","origin x0 y0 [z0]", mgls_origin ,14},
 	{"origintick","Set tick labels drawing at origin","origintick val", mgls_origintick ,14},
@@ -2669,6 +2730,7 @@ mglCommand mgls_base_cmd[] = {
 	{"readmat","Read data from file with sizes specified in first row","readmat Dat 'file' [dim]", mgls_readmat ,4},
 	{"rearrange","Rearrange data dimensions","rearrange Dat mx [my mz]", mgls_rearrange ,3},
 	{"rect","Draw rectangle","rect x1 y1 x2 y2 ['fmt']|x1 y1 z1 x2 y2 z2 ['fmt']", mgls_rect ,13},
+	{"refill","Fill data by interpolation of Vdat","refill Dat Xdat Vdat [sl] | Dat Xdat Ydat Vdat [sl] | Dat Xdat Ydat Zdat Vdat", mgls_refill ,3},
 	{"region","Draw filled region between 2 curves","region Ydat1 Ydat2 ['fmt' inside]|Xdat Ydat1 Ydat2 ['fmt' inside]", mgls_region ,7},
 	{"resize","Resize data","resize Res Dat mx [my mz]", mgls_resize ,4},
 	{"return","Return from function","return", 0, 6},
diff --git a/src/export.cpp b/src/export.cpp
index 69a87ad..90e8414 100644
--- a/src/export.cpp
+++ b/src/export.cpp
@@ -198,17 +198,28 @@ int MGL_NO_EXPORT mgl_jpeg_save(const char *fname, int w, int h, unsigned char *
 #endif
 }
 //-----------------------------------------------------------------------------
-void MGL_NO_EXPORT mgl_printf(void *fp, bool gz, const char *str, ...)
+void MGL_NO_EXPORT mgl_printf(void *fp, bool gz, const char *str, ...)	// NOTE This function is not thread-safe
 {
-	char buf[512];
+	static char buf[1024];
 	va_list lst;
 	va_start(lst,str);
-	vsnprintf(buf,512,str,lst);
+	vsnprintf(buf,1023,str,lst);
 	va_end(lst);
 	if(gz)	gzprintf((gzFile)fp, "%s", buf);
 	else	fprintf((FILE *)fp, "%s", buf);
 }
 //---------------------------------------------------------------------------
+std::string MGL_NO_EXPORT mgl_sprintf(const char *str, ...)
+{
+	char *buf=new char[1024];
+	va_list lst;
+	va_start(lst,str);
+	vsnprintf(buf,1023,str,lst);
+	va_end(lst);
+	std::string res = buf;	delete []buf;
+	return res;
+}
+//---------------------------------------------------------------------------
 int MGL_NO_EXPORT mgl_bps_save(const char *fname, int w, int h, unsigned char **p)
 {
 	time_t now;	time(&now);
@@ -303,9 +314,9 @@ void mglCanvas::StartGIF(const char *fname, int ms)
 	// get picture sizes
 	// NOTE: you shouldn't call SetSize() after StartGIF() !!!
 	long width, height;
-	unsigned char *f=0;
-	GetRGBLines(width, height, f);
+	unsigned char *f=0, **l=GetRGBLines(width, height, f);
 	if(f)	free(f);
+	if(l)	free(l);
 	// define colormap
 	GifColorType col[256];
 	memset(col,0,256*sizeof(GifColorType));
@@ -367,11 +378,11 @@ void mglCanvas::EndFrame()
 	Finish();
 	if(get(MGL_VECT_FRAME))	PushDrwDat();
 #if MGL_HAVE_GIF
+	if(!gif)	return;
 	long width, height, n;
-	unsigned char *f=0, **l=0;
-	l = GetRGBLines(width, height, f);
+	unsigned char *f=0, **l=GetRGBLines(width, height, f);
 	n = width*height;
-	if(!l || !gif)	return;
+	if(!l)	return;
 	EGifPutImageDesc(gif, 0, 0, width, height, 0, 0);
 	GifPixelType *line = new GifPixelType[n];
 	register long m;
@@ -387,8 +398,8 @@ void mglCanvas::EndFrame()
 	EGifPutLine(gif, line, n);
 	delete []line;	free(l);
 	if(f)	free(f);
-#else
-	mglGlobalMess += "GIF support was disabled. Please, enable it and rebuild MathGL.\n";
+//#else
+//	mglGlobalMess += "GIF support was disabled. Please, enable it and rebuild MathGL.\n";
 #endif
 }
 //-----------------------------------------------------------------------------
@@ -396,9 +407,11 @@ void mglCanvas::DelFrame(long i)
 {
 #if MGL_HAVE_PTHREAD
 	pthread_mutex_lock(&mutexDrw);
+#pragma omp critical(drw)
 	if(get(MGL_VECT_FRAME))	DrwDat.erase(DrwDat.begin()+i);
 	pthread_mutex_unlock(&mutexDrw);
 #else
+#pragma omp critical(drw)
 	if(get(MGL_VECT_FRAME))	DrwDat.erase(DrwDat.begin()+i);
 #endif
 	CurFrameId--;
@@ -542,24 +555,29 @@ void MGL_EXPORT mgl_write_frame(HMGL gr, const char *fname,const char *descr)
 	if(!fname || !fname[0])
 	{	snprintf(buf,64,"%s%04d.jpg",_Gr_->PlotId.c_str(),_Gr_->GetNumFrame());	fname = buf;	}
 	int len=strlen(fname);
-	if(!strcmp(fname+len-4,".jpg"))	mgl_write_jpg(gr,fname,descr);
-	if(!strcmp(fname+len-5,".jpeg"))mgl_write_jpg(gr,fname,descr);
-	if(!strcmp(fname+len-4,".prc")) mgl_write_prc(gr,fname,descr,1);
-	if(!strcmp(fname+len-4,".pdf")) mgl_write_prc(gr,fname,descr,1);
-	if(!strcmp(fname+len-4,".png"))	mgl_write_png(gr,fname,descr);
-	if(!strcmp(fname+len-4,".eps"))	mgl_write_eps(gr,fname,descr);
-	if(!strcmp(fname+len-4,".svg"))	mgl_write_svg(gr,fname,descr);
-	if(!strcmp(fname+len-4,".gif"))	mgl_write_gif(gr,fname,descr);
-	if(!strcmp(fname+len-4,".bmp"))	mgl_write_bmp(gr,fname,descr);
-	if(!strcmp(fname+len-4,".tga"))	mgl_write_tga(gr,fname,descr);
-	if(!strcmp(fname+len-5,".mgld"))mgl_export_mgld(gr,fname,descr);
-	if(!strcmp(fname+len-4,".json")) mgl_write_json(gr,fname,descr);
-	if(!strcmp(fname+len-4,".obj")) mgl_write_obj(gr,fname,descr,1);
-	if(!strcmp(fname+len-4,".tex")) mgl_write_tex(gr,fname,descr);
-	if(!strcmp(fname+len-4,".xyz")) mgl_write_xyz(gr,fname,descr);
-	if(!strcmp(fname+len-4,".stl")) mgl_write_stl(gr,fname,descr);
-	if(!strcmp(fname+len-4,".off")) mgl_write_off(gr,fname,descr,0);
-//	if(!strcmp(fname+len-4,".x3d")) mgl_write_x3d(gr,fname,descr,1);
+	if(!strcmp(fname+len-4,".jpg")) 	mgl_write_jpg(gr,fname,descr);
+	if(!strcmp(fname+len-5,".jpeg"))	mgl_write_jpg(gr,fname,descr);
+	if(!strcmp(fname+len-4,".prc")) 	mgl_write_prc(gr,fname,descr,1);
+	if(!strcmp(fname+len-4,".pdf")) 	mgl_write_prc(gr,fname,descr,1);
+	if(!strcmp(fname+len-4,".png")) 	mgl_write_png(gr,fname,descr);
+	if(!strcmp(fname+len-4,".eps")) 	mgl_write_eps(gr,fname,descr);
+	if(!strcmp(fname+len-5,".epsz"))	mgl_write_eps(gr,fname,descr);
+	if(!strcmp(fname+len-4,".bps")) 	mgl_write_bps(gr,fname,descr);
+	if(!strcmp(fname+len-5,".bpsz"))	mgl_write_bps(gr,fname,descr);
+	if(!strcmp(fname+len-4,".svg")) 	mgl_write_svg(gr,fname,descr);
+	if(!strcmp(fname+len-5,".svgz"))	mgl_write_svg(gr,fname,descr);
+	if(!strcmp(fname+len-4,".gif")) 	mgl_write_gif(gr,fname,descr);
+	if(!strcmp(fname+len-4,".bmp")) 	mgl_write_bmp(gr,fname,descr);
+	if(!strcmp(fname+len-4,".tga")) 	mgl_write_tga(gr,fname,descr);
+	if(!strcmp(fname+len-5,".mgld"))	mgl_export_mgld(gr,fname,descr);
+	if(!strcmp(fname+len-5,".json"))	mgl_write_json(gr,fname,descr);
+	if(!strcmp(fname+len-6,".jsonz"))	mgl_write_json(gr,fname,descr);
+	if(!strcmp(fname+len-4,".obj")) 	mgl_write_obj(gr,fname,descr,1);
+	if(!strcmp(fname+len-4,".tex")) 	mgl_write_tex(gr,fname,descr);
+	if(!strcmp(fname+len-4,".xyz")) 	mgl_write_xyz(gr,fname,descr);
+	if(!strcmp(fname+len-4,".stl")) 	mgl_write_stl(gr,fname,descr);
+	if(!strcmp(fname+len-4,".off")) 	mgl_write_off(gr,fname,descr,0);
+//	if(!strcmp(fname+len-4,".x3d")) 	mgl_write_x3d(gr,fname,descr,1);
 }
 void MGL_EXPORT mgl_write_frame_(uintptr_t *gr, const char *fname,const char *descr,int l,int n)
 {	char *s=new char[l+1];	memcpy(s,fname,l);	s[l]=0;
diff --git a/src/export_2d.cpp b/src/export_2d.cpp
index 8bc307d..99f91d0 100644
--- a/src/export_2d.cpp
+++ b/src/export_2d.cpp
@@ -52,17 +52,17 @@ MGL_NO_EXPORT const char *mgl_get_dash(unsigned short d, mreal w)
 	return s.c_str();
 }
 //-----------------------------------------------------------------------------
-bool MGL_NO_EXPORT mgl_is_same(HMGL gr, const mglPrim &pr,mreal wp,mglColor cp,int st)
+bool MGL_NO_EXPORT mgl_is_same(HMGL gr, long i, mreal wp,uint32_t cp, int st)
 {
+	const mglPrim &pr=_Gr_->GetPrm(i);
 	if(abs(pr.type)!=1)	return false;
 	if(pr.w>=1 && wp!=pr.w)	return false;
 	if(pr.w<1 && wp!=1)	return false;
-	if(st!=pr.n3)			return false;
-	mglColor c=_Gr_->GetColor(pr);
-	return (cp==c);
+	if(st!=pr.n3)	return false;
+	return (cp==_Gr_->GetPrmCol(i));
 }
 //-----------------------------------------------------------------------------
-void MGL_NO_EXPORT put_line(HMGL gr, void *fp, bool gz, long i, mreal wp, mglColor cp,int st, const char *ifmt, const char *nfmt, bool neg, mreal fc)
+void MGL_NO_EXPORT put_line(HMGL gr, void *fp, bool gz, long i, mreal wp, uint32_t cp,int st, const char *ifmt, const char *nfmt, bool neg, mreal fc)
 {
 	long n1=gr->GetPrm(i).n1, n2=gr->GetPrm(i).n2;
 	if(n1>n2)	{	n1=gr->GetPrm(i).n2;	n2=gr->GetPrm(i).n1;	}
@@ -78,7 +78,7 @@ void MGL_NO_EXPORT put_line(HMGL gr, void *fp, bool gz, long i, mreal wp, mglCol
 		{
 			mglPrim &q = gr->GetPrm(j);
 			if(q.type>1)	break;
-			if(mgl_is_same(gr, q,wp,cp,st) && q.type==1 && q.n1>=0 && q.n2>=0)	// previous point
+			if(mgl_is_same(gr, j, wp,cp,st) && q.type==1 && q.n1>=0 && q.n2>=0)	// previous point
 			{
 				const mglPnt &p1 = gr->GetPnt(q.n1);
 				const mglPnt &p2 = gr->GetPnt(q.n2);
@@ -104,7 +104,7 @@ void MGL_NO_EXPORT put_line(HMGL gr, void *fp, bool gz, long i, mreal wp, mglCol
 		{
 			mglPrim &q = gr->GetPrm(j);
 			if(q.type>1)	break;
-			if(mgl_is_same(gr, q,wp,cp,st) && q.type==1 && q.n1>=0 && q.n2>=0)	// next point
+			if(mgl_is_same(gr, j,wp,cp,st) && q.type==1 && q.n1>=0 && q.n2>=0)	// next point
 			{
 				const mglPnt &p1 = gr->GetPnt(q.n1);
 				const mglPnt &p2 = gr->GetPnt(q.n2);
@@ -169,44 +169,11 @@ void MGL_NO_EXPORT put_desc(HMGL gr, void *fp, bool gz, const char *pre, const c
 	delete []g;		delete []s;
 }
 //-----------------------------------------------------------------------------
-mglColor mglCanvas::GetColor(const mglPrim &p)
-{
-	unsigned char res[4],buf[4];
-	mglPnt pp=Pnt[p.type==1?p.n2:p.n1];
-	if(p.type==4)	pp.u=pp.v=NAN;
-	col2int(pp,res,p.id);
-	if(p.type==2 || p.type==3)
-	{
-		col2int(Pnt[p.n2],buf,p.id);	res[0]=(1L*res[0]+buf[0])/2;
-		res[1]=(1L*res[1]+buf[1])/2;	res[2]=(1L*res[2]+buf[2])/2;
-		col2int(Pnt[p.n3],buf,p.id);	res[0]=(2L*res[0]+buf[0])/3;
-		res[1]=(2L*res[1]+buf[1])/3;	res[2]=(2L*res[2]+buf[2])/3;
-	}
-	if(p.type==3)
-	{
-		col2int(Pnt[p.n4],buf,p.id);	res[0]=(3L*res[0]+buf[0])/4;
-		res[1]=(3L*res[1]+buf[1])/4;	res[2]=(3L*res[2]+buf[2])/4;
-	}
-	if(p.type==6)
-	{	res[0]=p.n2&0xff;	res[1]=(p.n2/256)&0xff;	res[2]=(p.n2/65536)&0xff;	}
-	
-	// add fog into resulting color
-	float zf = FogDist*(p.z/Depth-0.5-FogDz);
-	if(zf<0)	// add fog
-	{
-		int d = int(255.f-255.f*exp(5.f*zf));
-		unsigned char cb[4] = {BDef[0], BDef[1], BDef[2], (unsigned char)d};
-		if(d<255)	combine(res,cb);
-	}
-
-	return mglColor(res[0]/255.,res[1]/255.,res[2]/255.,res[3]/255.);
-}
-//-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_write_eps(HMGL gr, const char *fname,const char *descr)
 {
 	if(!fname || *fname==0)	return;
 	if(gr->GetPrmNum()<1)	return;
-	_Gr_->clr(MGL_FINISHED);	_Gr_->Finish(false);
+	_Gr_->clr(MGL_FINISHED);	_Gr_->PreparePrim(1);
 	time_t now;	time(&now);
 
 	bool gz = fname[strlen(fname)-1]=='z';
@@ -277,21 +244,21 @@ void MGL_EXPORT mgl_write_eps(HMGL gr, const char *fname,const char *descr)
 	// write primitives
 	mreal wp=-1;
 	float qs_old=gr->mark_size()/gr->FontFactor();
-	mglColor cp;
+	mglRGBA cp;
 	int st=0;
 	char str[256]="";
 	for(i=0;i<gr->GetPrmNum();i++)
 	{
 		const mglPrim &q = gr->GetPrm(i);
 		if(q.type<0)	continue;	// q.n1>=0 always
-		cp = _Gr_->GetColor(q);
+		cp.c = _Gr_->GetPrmCol(i);
 		const mglPnt p1 = gr->GetPnt(q.n1);
-		if(q.type>1)	snprintf(str,256,"%.2g %.2g %.2g rgb ", cp.r,cp.g,cp.b);
+		if(q.type>1)	snprintf(str,256,"%.2g %.2g %.2g rgb ", cp.r[0]/255.,cp.r[1]/255.,cp.r[2]/255.);
 
 		if(q.type==0)	// mark
 		{
 			mreal x0 = p1.x,y0 = p1.y;
-			snprintf(str,256,"%.2g lw %.2g %.2g %.2g rgb ", 50*q.s*q.w>1?50*q.s*q.w:1, cp.r,cp.g,cp.b);
+			snprintf(str,256,"%.2g lw %.2g %.2g %.2g rgb ", 50*q.s*q.w>1?50*q.s*q.w:1, cp.r[0]/255.,cp.r[1]/255.,cp.r[2]/255.);
 			wp=1;	// NOTE: this may renew line style if a mark inside!
 			if(q.s!=qs_old)
 			{
@@ -329,22 +296,18 @@ void MGL_EXPORT mgl_write_eps(HMGL gr, const char *fname,const char *descr)
 		else if(q.type==3)	// quad
 		{
 			const mglPnt &p2=gr->GetPnt(q.n2), &p3=gr->GetPnt(q.n3), &p4=gr->GetPnt(q.n4);
-			if(p1.a>mgl_min_a || p2.a>mgl_min_a || p3.a>mgl_min_a || p4.a>mgl_min_a)
-				mgl_printf(fp, gz, "np %g %g mt %g %g ll %g %g ll %g %g ll cp %sfill\n",
-					   p1.x, p1.y, p2.x, p2.y, p4.x, p4.y, p3.x, p3.y, str);
+			if(cp.r[3])	mgl_printf(fp, gz, "np %g %g mt %g %g ll %g %g ll %g %g ll cp %sfill\n", p1.x, p1.y, p2.x, p2.y, p4.x, p4.y, p3.x, p3.y, str);
 		}
 		else if(q.type==2)	// trig
 		{
 			const mglPnt &p2=gr->GetPnt(q.n2), &p3=gr->GetPnt(q.n3);
-			if(p1.a>mgl_min_a || p2.a>mgl_min_a || p3.a>mgl_min_a)
-				mgl_printf(fp, gz, "np %g %g mt %g %g ll %g %g ll cp %sfill\n",
-					   p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, str);
+			if(cp.r[3])	mgl_printf(fp, gz, "np %g %g mt %g %g ll %g %g ll cp %sfill\n", p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, str);
 		}
 		else if(q.type==1)	// line
 		{
-			snprintf(str,256,"%.2g lw %.2g %.2g %.2g rgb ", q.w>1 ? q.w:1., cp.r,cp.g,cp.b);
+			snprintf(str,256,"%.2g lw %.2g %.2g %.2g rgb ", q.w>1 ? q.w:1., cp.r[0]/255.,cp.r[1]/255.,cp.r[2]/255.);
 			wp = q.w>1  ? q.w:1;	st = q.n3;
-			put_line(gr,fp,gz,i,wp,cp,st, "np %g %g mt ", "%g %g ll ", false, 1);
+			put_line(gr,fp,gz,i,wp,cp.c,st, "np %g %g mt ", "%g %g ll ", false, 1);
 			const char *sd = mgl_get_dash(q.n3,q.w);
 			if(sd && sd[0])	mgl_printf(fp, gz, "%s [%s] %g sd dr\n",str,sd,q.w*q.s);
 			else			mgl_printf(fp, gz, "%s d0 dr\n",str);
@@ -387,7 +350,7 @@ void MGL_EXPORT mgl_write_svg(HMGL gr, const char *fname,const char *descr)
 {
 	if(!fname || *fname==0)	return;
 	if(gr->GetPrmNum()<1)	return;
-	_Gr_->clr(MGL_FINISHED);	_Gr_->Finish(false);
+	_Gr_->clr(MGL_FINISHED);	_Gr_->PreparePrim(1);
 	time_t now;	time(&now);
 
 	bool gz = fname[strlen(fname)-1]=='z';
@@ -412,13 +375,13 @@ void MGL_EXPORT mgl_write_svg(HMGL gr, const char *fname,const char *descr)
 	mreal wp=-1;
 	register long i;
 	int st=0;
-	mglColor cp;
+	mglRGBA cp;
 
 	for(i=0;i<gr->GetPrmNum();i++)
 	{
 		const mglPrim &q = gr->GetPrm(i);
 		if(q.type<0)	continue;	// q.n1>=0 always
-		cp = _Gr_->GetColor(q);
+		cp.c = _Gr_->GetPrmCol(i);
 		const mglPnt p1=gr->GetPnt(q.n1);
 		if(q.type==0)
 		{
@@ -426,9 +389,9 @@ void MGL_EXPORT mgl_write_svg(HMGL gr, const char *fname,const char *descr)
 			if(!strchr("xsSoO",q.n4))	s *= 1.1;
 			wp = 1;
 			if(strchr("SDVTLR",q.n4))
-				mgl_printf(fp, gz, "<g fill=\"#%02x%02x%02x\">\n", int(255*cp.r),int(255*cp.g),int(255*cp.b));
+				mgl_printf(fp, gz, "<g fill=\"#%02x%02x%02x\">\n", int(cp.r[0]),int(cp.r[1]),int(cp.r[2]));
 			else
-				mgl_printf(fp, gz, "<g stroke=\"#%02x%02x%02x\"  stroke-width=\"%g\">\n", int(255*cp.r),int(255*cp.g),int(255*cp.b), 50*q.s*q.w>1?50*q.s*q.w:1);
+				mgl_printf(fp, gz, "<g stroke=\"#%02x%02x%02x\"  stroke-width=\"%g\">\n", int(cp.r[0]),int(cp.r[1]),int(cp.r[2]), 50*q.s*q.w>1?50*q.s*q.w:1);
 			switch(q.n4)
 			{
 			case 'P':
@@ -463,24 +426,24 @@ void MGL_EXPORT mgl_write_svg(HMGL gr, const char *fname,const char *descr)
 				mgl_printf(fp, gz, "<path d=\"M %g %g L %g %g L %g %g M %g %g L %g %g\"/>\n", x,y-s, x,y, x+s,y+s, x,y, x-s,y+s);	break;
 			case 'C':
 				mgl_printf(fp, gz, "<circle style=\"fill:#%02x%02x%02x\" cx=\"%g\" cy=\"%g\" r=\"0.15\"/>\n<circle cx=\"%g\" cy=\"%g\" r=\"%g\"/>\n",
-							int(255*cp.r),int(255*cp.g),int(255*cp.b),x,y,x,y,s);	break;
+							int(cp.r[0]),int(cp.r[1]),int(cp.r[2]),x,y,x,y,s);	break;
 			case 'o':
 				mgl_printf(fp, gz, "<circle cx=\"%g\" cy=\"%g\" r=\"%g\"/>\n", x,y,s);	break;
 			case 'O':
 				mgl_printf(fp, gz, "<circle style=\"fill:#%02x%02x%02x\" cx=\"%g\" cy=\"%g\" r=\"%g\"/>\n",
-							int(255*cp.r),int(255*cp.g),int(255*cp.b),x,y,s);	break;
+							int(cp.r[0]),int(cp.r[1]),int(cp.r[2]),x,y,s);	break;
 			case '*':
 				mgl_printf(fp, gz, "<path d=\"M %g %g L %g %g M %g %g L %g %g M %g %g L %g %g\"/>\n",
 							x-s,y,x+s,y,x-0.6*s,y-0.8*s,x+0.6*s,y+0.8*s,x+0.6*s,y-0.8*s,x-0.6*s,y+0.8*s);	break;
 			default:
 				mgl_printf(fp, gz, "<circle style=\"fill:#%02x%02x%02x\" cx=\"%g\" cy=\"%g\" r=\"0.15\"/>\n",
-							int(255*cp.r),int(255*cp.g),int(255*cp.b),x,y);	break;
+							int(cp.r[0]),int(cp.r[1]),int(cp.r[2]),x,y);	break;
 			}
 			mgl_printf(fp, gz, "</g>\n");
 		}
 		else if(q.type==1)
 		{
-			mgl_printf(fp,gz,"<g stroke=\"#%02x%02x%02x\"",int(255*cp.r),int(255*cp.g),int(255*cp.b));
+			mgl_printf(fp,gz,"<g stroke=\"#%02x%02x%02x\"",int(cp.r[0]),int(cp.r[1]),int(cp.r[2]));
 			if(q.n3)
 			{
 				mgl_printf(fp, gz, " stroke-dasharray=\"%s\"", mgl_get_dash(q.n3,q.w));
@@ -488,19 +451,19 @@ void MGL_EXPORT mgl_write_svg(HMGL gr, const char *fname,const char *descr)
 			}
 			if(q.w>1)	mgl_printf(fp, gz, " stroke-width=\"%g\"", q.w);
 			wp = q.w>1  ? q.w:1;	st = q.n3;
-			put_line(gr,fp,gz,i,wp,cp,st, "><path d=\" M %g %g", " L %g %g", true, 1);
+			put_line(gr,fp,gz,i,wp,cp.c,st, "><path d=\" M %g %g", " L %g %g", true, 1);
 			mgl_printf(fp, gz, "\"/> </g>\n");
 		}
-		else if(q.type==2 && cp.a>mgl_min_a)
+		else if(q.type==2 && cp.r[3])
 		{
 			const mglPnt &p2=gr->GetPnt(q.n2), &p3=gr->GetPnt(q.n3);
-			mgl_printf(fp, gz, "<g fill=\"#%02x%02x%02x\" opacity=\"%g\">\n", int(255*cp.r),int(255*cp.g),int(255*cp.b),cp.a);
+			mgl_printf(fp, gz, "<g fill=\"#%02x%02x%02x\" opacity=\"%g\">\n", int(cp.r[0]),int(cp.r[1]),int(cp.r[2]),cp.r[3]/255.);
 			mgl_printf(fp, gz, "<path d=\"M %g %g L %g %g L %g %g Z\"/> </g>\n", p1.x, hh-p1.y, p2.x, hh-p2.y, p3.x, hh-p3.y);
 		}
-		else if(q.type==3 && cp.a>mgl_min_a)
+		else if(q.type==3 && cp.r[3])
 		{
 			const mglPnt &p2=gr->GetPnt(q.n2), &p3=gr->GetPnt(q.n3), &p4=gr->GetPnt(q.n4);
-			mgl_printf(fp, gz, "<g fill=\"#%02x%02x%02x\" opacity=\"%g\">\n", int(255*cp.r),int(255*cp.g),int(255*cp.b),cp.a);
+			mgl_printf(fp, gz, "<g fill=\"#%02x%02x%02x\" opacity=\"%g\">\n", int(cp.r[0]),int(cp.r[1]),int(cp.r[2]),cp.r[3]/255.);
 			mgl_printf(fp, gz, "<path d=\"M %g %g L %g %g L %g %g L %g %g Z\"/> </g>\n", p1.x, hh-p1.y, p2.x, hh-p2.y, p4.x, hh-p4.y, p3.x, hh-p3.y);
 		}
 		else if(q.type==4)
@@ -512,9 +475,9 @@ void MGL_EXPORT mgl_write_svg(HMGL gr, const char *fname,const char *descr)
 			{
 				mgl_printf(fp, gz, "<g transform=\"translate(%g,%g) scale(%.3g,%.3g) rotate(%g)\"", p1.x, hh-p1.y, ss, -ss, -phi);
 				if(q.n3&4)
-					mgl_printf(fp, gz, " stroke=\"#%02x%02x%02x\">", int(255*cp.r),int(255*cp.g),int(255*cp.b));
+					mgl_printf(fp, gz, " stroke=\"#%02x%02x%02x\">", int(cp.r[0]),int(cp.r[1]),int(cp.r[2]));
 				else
-					mgl_printf(fp, gz, " fill=\"#%02x%02x%02x\">", int(255*cp.r),int(255*cp.g),int(255*cp.b));
+					mgl_printf(fp, gz, " fill=\"#%02x%02x%02x\">", int(cp.r[0]),int(cp.r[1]),int(cp.r[2]));
 				mreal dy = 0.004,f=fabs(zz);
 				mgl_printf(fp, gz, "<path d=\"M %g %g L %g %g L %g %g L %g %g\"/></g>\n", xx,yy+dy, xx+f,yy+dy, xx+f,yy-dy, xx,yy-dy);
 			}
@@ -523,9 +486,9 @@ void MGL_EXPORT mgl_write_svg(HMGL gr, const char *fname,const char *descr)
 				ss *= zz;
 				mgl_printf(fp, gz, "<g transform=\"translate(%g,%g) scale(%.3g,%.3g) rotate(%g)\"", p1.x, hh-p1.y, ss, -ss, -q.w);
 				if(q.n3&4)
-					mgl_printf(fp, gz, " stroke=\"#%02x%02x%02x\">", int(255*cp.r),int(255*cp.g),int(255*cp.b));
+					mgl_printf(fp, gz, " stroke=\"#%02x%02x%02x\">", int(cp.r[0]),int(cp.r[1]),int(cp.r[2]));
 				else
-					mgl_printf(fp, gz, " fill=\"#%02x%02x%02x\">", int(255*cp.r),int(255*cp.g),int(255*cp.b));
+					mgl_printf(fp, gz, " fill=\"#%02x%02x%02x\">", int(cp.r[0]),int(cp.r[1]),int(cp.r[2]));
 				mgl_printf(fp, gz, "<use x=\"%g\" y=\"%g\" xlink:href=\"#%c%c_%04x\"/></g>\n", xx/zz, yy/zz, q.n3&1?'b':'n', q.n3&2?'i':'n', q.n4);
 			}
 		}
@@ -638,7 +601,7 @@ MGL_NO_EXPORT const char *mglColorName(mglColor c)	// return closest SVG color
 void MGL_EXPORT mgl_write_tex(HMGL gr, const char *fname,const char *descr)
 {
 	if(gr->GetPrmNum()<1)	return;
-	_Gr_->clr(MGL_FINISHED);	_Gr_->Finish(false);
+	_Gr_->clr(MGL_FINISHED);	_Gr_->PreparePrim(1);
 
 	FILE *fp = fopen(fname,"wt");
 	if(!fp)		{	gr->SetWarn(mglWarnOpen,fname);	return;	}
@@ -650,18 +613,18 @@ void MGL_EXPORT mgl_write_tex(HMGL gr, const char *fname,const char *descr)
 	register long i;
 	register int ii,jj,kk;
 	int st=0;
-	mglColor cp;
+	mglRGBA cp;
 	char cname[16];
 
 	for(i=0;i<gr->GetPrmNum();i++)
 	{
 		const mglPrim &q = gr->GetPrm(i);
 		if(q.type<0)	continue;	// q.n1>=0 always
-		cp = _Gr_->GetColor(q);
+		cp.c = _Gr_->GetPrmCol(i);
 
-		ii = (cp.r*255+25)/51;
-		jj = (cp.g*255+25)/51;
-		kk = (cp.b*255+25)/51;
+		ii = (cp.r[0]+25L)/51;
+		jj = (cp.r[1]+25L)/51;
+		kk = (cp.r[2]+25L)/51;
 		snprintf(cname,16,"mgl_%d",ii+6*(jj+6*kk));
 //		cname = mglColorName(cp);
 		const mglPnt p1=gr->GetPnt(q.n1);
@@ -699,15 +662,15 @@ void MGL_EXPORT mgl_write_tex(HMGL gr, const char *fname,const char *descr)
 				default:	fprintf(fp, "\\mglc{%g}{%g}{%s}\n", x,y,cname);	break;
 			}
 		}
-		else if(q.type==2 && cp.a>mgl_min_a)
+		else if(q.type==2 && cp.r[3])
 		{
 			const mglPnt p2=gr->GetPnt(q.n2), p3=gr->GetPnt(q.n3);
-			fprintf(fp, "\\fill[%s, fill opacity=%g] (%g,%g) -- (%g,%g) -- (%g,%g) -- cycle;\n", cname,cp.a, x,y, p2.x/100,p2.y/100, p3.x/100,p3.y/100);
+			fprintf(fp, "\\fill[%s, fill opacity=%g] (%g,%g) -- (%g,%g) -- (%g,%g) -- cycle;\n", cname,cp.r[3]/255., x,y, p2.x/100,p2.y/100, p3.x/100,p3.y/100);
 		}
-		else if(q.type==3 && cp.a>mgl_min_a)
+		else if(q.type==3 && cp.r[3])
 		{
 			const mglPnt p2=gr->GetPnt(q.n2), p3=gr->GetPnt(q.n3), p4=gr->GetPnt(q.n4);
-			fprintf(fp, "\\fill[%s, fill opacity=%g] (%g,%g) -- (%g,%g) -- (%g,%g) -- (%g,%g) -- cycle;\n", cname,cp.a, x,y, p2.x/100,p2.y/100, p4.x/100,p4.y/100, p3.x/100,p3.y/100);
+			fprintf(fp, "\\fill[%s, fill opacity=%g] (%g,%g) -- (%g,%g) -- (%g,%g) -- (%g,%g) -- cycle;\n", cname,cp.r[3]/255., x,y, p2.x/100,p2.y/100, p4.x/100,p4.y/100, p3.x/100,p3.y/100);
 		}
 		else if(q.type==1)	// lines
 		{
@@ -718,10 +681,10 @@ void MGL_EXPORT mgl_write_tex(HMGL gr, const char *fname,const char *descr)
 			else		fprintf(fp,"\\draw[%s,%s] ",cname,w[iw]);
 			// TODO: add line dashing
 			wp = q.w>1  ? q.w:1;	st = q.n3;
-			put_line(gr,fp,false,i,wp,cp,st, "(%g,%g)", " -- (%g,%g)", false, 0.01);
+			put_line(gr,fp,false,i,wp,cp.c,st, "(%g,%g)", " -- (%g,%g)", false, 0.01);
 			fprintf(fp, ";\n");
 		}
-		else if(q.type==6 && !mgl_isnan(q.p))	// text
+		else if(q.type==6 && mgl_isnum(q.p))	// text
 		{
 			const mglText &t = gr->GetPtx(q.n3);
 			mreal dy = q.w*cos(q.p*M_PI/180)/100, dx = q.w*sin(q.p*M_PI/180)/100;
diff --git a/src/export_3d.cpp b/src/export_3d.cpp
index 976d563..ebb1b1d 100644
--- a/src/export_3d.cpp
+++ b/src/export_3d.cpp
@@ -18,6 +18,7 @@
  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
  ***************************************************************************/
 #include <time.h>
+#include <stdarg.h>
 #include "mgl2/canvas.h"
 #include "mgl2/canvas_cf.h"
 #undef _GR_
@@ -26,6 +27,7 @@
 int MGL_NO_EXPORT mgl_tga_save(const char *fname, int w, int h, unsigned char **p);
 int MGL_NO_EXPORT mgl_pnga_save(const char *fname, int w, int h, unsigned char **p);
 void MGL_NO_EXPORT mgl_printf(void *fp, bool gz, const char *str, ...);
+std::string MGL_NO_EXPORT mgl_sprintf(const char *str, ...);
 //-----------------------------------------------------------------------------
 void mglTexture::GetRGBA(unsigned char *f) const
 {
@@ -50,6 +52,7 @@ void MGL_EXPORT mgl_obj_glyph_old(HMGL gr, const mglPrim &q, const mglPnt &p, FI
 {
 	mreal f = q.p/2, dx=p.u/2, dy=p.v/2, x,y;
 	mreal c=q.s*cos(q.w*M_PI/180), s=-q.s*sin(q.w*M_PI/180);
+	if(mgl_isnan(q.s))	c=s=0;
 	double b[4] = {c,-s, s,c};
 	long i=q.n1+1, ik,il=0;
 
@@ -260,14 +263,14 @@ void MGL_EXPORT mgl_obj_prim_old(HMGL gr, const mglPrim &q, const mglPnt &p, FIL
 			fprintf(fp,"l -1/%ld -3/%ld\n", i,i);	break;
 		case 'O':
 			for(j=0;j<=20;j++)
-				fprintf(fp,"v %g %g %g\n",p.x+ss*cos(j*M_PI/10),p.y+ss*sin(j*M_PI/10),p.z);
+				fprintf(fp,"v %g %g %g\n",p.x+ss*mgl_cos[(j*36)%360],p.y+ss*mgl_cos[(270+j*36)%360],p.z);
 			for(j=0;j<20;j++)
 				fprintf(fp,"f %ld/%ld %ld/%ld %ld/%ld\n", j-21,i, j-20,i, i,i);
 			break;
 		case 'C':	fprintf(fp,"p %ld\n", i);
 		case 'o':
 			for(j=0;j<=20;j++)
-				fprintf(fp,"v %g %g %g\n",p.x+ss*cos(j*M_PI/10),p.y+ss*sin(j*M_PI/10),p.z);
+				fprintf(fp,"v %g %g %g\n",p.x+ss*mgl_cos[(j*36)%360],p.y+ss*mgl_cos[(270+j*36)%360],p.z);
 			for(j=0;j<20;j++)
 				fprintf(fp,"l %ld/%ld %ld/%ld\n", j-21,i, j-20,i);
 			break;
@@ -284,13 +287,12 @@ void MGL_EXPORT mgl_obj_prim_old(HMGL gr, const mglPrim &q, const mglPnt &p, FIL
 void MGL_EXPORT mgl_write_obj_old(HMGL gr, const char *fname,const char *descr, int use_png)
 {
 	if(gr->GetPrmNum()==0)	return;	// nothing to do
-	register size_t i,j;
-	long m1=0,m2=0,m;
-	for(i=0;i<gr->Grp.size();i++)	// prepare array of indirect indexing
+	long m1=0,m2=0,m,j;
+	for(size_t i=0;i<gr->Grp.size();i++)	// prepare array of indirect indexing
 	{	m = gr->Grp[i].Id;	if(m<m1) m1=m;	if(m>m2) m2=m;	}
 	long *ng = new long[m2-m1+1];
-	for(i=0;i<gr->Grp.size();i++)	ng[gr->Grp[i].Id-m1] = i;
-	for(i=0;i<size_t(gr->GetPrmNum());i++)	// collect data for groups
+	for(size_t i=0;i<gr->Grp.size();i++)	ng[gr->Grp[i].Id-m1] = i;
+	for(long i=0;i<gr->GetPrmNum();i++)	// collect data for groups
 	// it is rather expensive (extra 4b per primitive) but need for export to 3D
 	{
 		m = gr->GetPrm(i).id-m1;
@@ -303,7 +305,7 @@ void MGL_EXPORT mgl_write_obj_old(HMGL gr, const char *fname,const char *descr,
 	FILE *fp=fopen(fname,"wt");
 	// vertices definition
 	fprintf(fp,"# Created by MathGL library\n# Title: %s\n",(descr && *descr) ? descr : fname);
-	for(i=0;i<size_t(gr->GetPntNum());i++)
+	for(long i=0;i<gr->GetPntNum();i++)
 	{
 		const mglPnt &pp = gr->GetPnt(i);
 		fprintf(fp,"v %g %g %g\n",pp.x,pp.y,pp.z);
@@ -313,14 +315,14 @@ void MGL_EXPORT mgl_write_obj_old(HMGL gr, const char *fname,const char *descr,
 	}
 	// primitive definition in groups
 	tname[len-4]=0;	fprintf(fp,"# Primitives Definitions\nmtllib %s.mtl\nusemtl %s\n",tname,tname);
-	for(i=0;i<gr->Grp.size();i++)
+	for(size_t i=0;i<gr->Grp.size();i++)
 	{
 		fprintf(fp,"g %s\n",gr->Grp[i].Lbl.c_str());
 		std::vector<long> &p = gr->Grp[i].p;
-		for(j=0;j<p.size();j++)
+		for(size_t j=0;j<p.size();j++)
 		{
 			const mglPrim &q=gr->GetPrm(p[j]);
-			mgl_obj_prim_old(gr, q, gr->GetPnt(q.n1), fp, q.s);
+			mgl_obj_prim_old(gr, q, gr->GetPnt(q.n1), fp, mgl_isnan(q.s)?0:q.s);
 		}
 		gr->Grp[i].p.clear();	// we don't need indexes anymore
 	}
@@ -344,8 +346,8 @@ void MGL_EXPORT mgl_write_obj_old(HMGL gr, const char *fname,const char *descr,
 	j=gr->GetTxtNum();
 	unsigned char *buf = new unsigned char[4*256*256*j];
 	unsigned char **pbuf= (unsigned char **)malloc(256*j*sizeof(unsigned char *));
-	for(i=0;i<256*j;i++)	pbuf[i] = buf+4*256*i;
-	for(i=0;i<j;i++)	gr->GetTxt(i).GetRGBA(buf+i*256*256*4);
+	for(long i=0;i<256*j;i++)	pbuf[i] = buf+4*256*i;
+	for(long i=0;i<j;i++)	gr->GetTxt(i).GetRGBA(buf+i*256*256*4);
 	if(use_png)	mgl_pnga_save(tname,256,256*j,pbuf);
 	else		mgl_tga_save(tname,256,256*j,pbuf);
 	free(pbuf);	delete []buf;	delete []tname;
@@ -504,29 +506,60 @@ void MGL_EXPORT mgl_write_off_(uintptr_t *gr, const char *fname,const char *desc
 	char *d=new char[n+1];	memcpy(d,descr,n);	d[n]=0;
 	mgl_write_off(_GR_,s,d,*colored);	delete []s;		delete []d;	}
 //-----------------------------------------------------------------------------
-bool mglCanvas::WriteJSON(const char *fname)
+bool mglCanvas::WriteJSON(const char *fname, bool force_zlib)
 {
 	bool fl = strcmp(fname,"-");
-	bool gz = fname[strlen(fname)-1]=='z';
+	bool gz = force_zlib || fname[strlen(fname)-1]=='z';
 	void *fp = fl ? (gz ? (void*)gzopen(fname,"wt") : (void*)fopen(fname,"wt")) : stdout;
 	if (!fp)	return true;
+	std::string s=GetJSON();
+	if(gz)	gzprintf((gzFile)fp, "%s", s.c_str());
+	else	fprintf((FILE *)fp, "%s", s.c_str());
+	if(fl)	{	if(gz)	gzclose((gzFile)fp);	else	fclose((FILE *)fp);	}
+	return false;
+}
+//-----------------------------------------------------------------------------
+MGL_EXPORT const char *mgl_get_json(HMGL gr)
+{
+	static std::string json;
+	mglCanvas *g = dynamic_cast<mglCanvas *>(gr);
+	if(g)	json = g->GetJSON();
+	return json.c_str();
+}
+//-----------------------------------------------------------------------------
+std::string mglCanvas::GetJSON()
+{
 	ClearUnused();	// clear unused points
-	size_t i,l=Pnt.size();
-	mgl_printf(fp, gz,"{\n\"width\":%d,\t\"height\":%d,\t\"depth\":%d,\t\"plotid\":\"%s\",\t\"npnts\":%lu,\t\"pnts\":[\n",
-			Width, Height, Depth, PlotId.c_str(), (unsigned long)l);
-	for(i=0;i<l;i++)
+	std::string res, buf;
+	long i,ll=0,l=(long)Pnt.size();
+	long factor = Width>1?10:10000;
+	res = res + mgl_sprintf("{\n\"width\":%d,\t\"height\":%d,\t\"depth\":%d,\t\"plotid\":\"%s\",\t\"npnts\":%ld,\t\"pnts\":[\n",
+			factor*Width, factor*Height, factor*Depth, PlotId.c_str(), l);
+	std::string *tmp=new std::string[l];
+#pragma omp parallel for reduction(+:ll)
+	for(long i=0;i<l;i++)
 	{
 		const mglPnt &q=Pnt[i];
-//		fprintf(fp,"[%.4g,%.4g,%.4g]%c\n", q.xx, Height-q.yy, q.zz, i+1<l?',':' ');
-		mgl_printf(fp, gz,"[%d,%d,%d]%c\n", int(q.xx), int(Height-q.yy), int(q.zz), i+1<l?',':' ');
+		tmp[i] = mgl_sprintf("[%ld,%ld,%ld]%c\n", long(factor*q.xx), long(factor*(Height-q.yy)), long(factor*q.zz), i+1<l?',':' ');
+		ll += tmp[i].length();
 	}
-	l = Prm.size();
-	mgl_printf(fp, gz,"],\t\"nprim\":%lu,\t\"prim\":[\n",(unsigned long)l);
+	res.reserve(ll);
+	for(i=0;i<l;i++)	res = res + tmp[i];
+	delete []tmp;
+
+	l = (long)Prm.size();
+	PreparePrim(3);
+	for(ll=i=0;i<l;i++)
+	{	mglRGBA c;	c.c = GetPrmCol(i);	if(c.r[3])	ll++;	}
+
+	res = res + mgl_sprintf("],\t\"nprim\":%ld,\t\"prim\":[\n",ll);
 
 	std::vector<mglPoint> xy;	// vector for glyphs coordinates (to be separated from pnts)
-	for(i=0;i<l;i++)
+	res.reserve(60*ll);
+#pragma omp parallel for private(buf)
+	for(long i=0;i<l;i++)
 	{
-		const mglPrim &p=Prm[i];		mglColor c = GetColor(p);
+		const mglPrim &p=Prm[i];	mglRGBA cp;	cp.c = GetPrmCol(i);
 		if(p.n1<0 || (p.type==1 && p.n2<0) || (p.type==2 && (p.n2<0 || p.n3<0)) || (p.type==3 && (p.n2<0 || p.n3<0 || p.n4<0)))
 			continue;
 		long n1=p.n1, n2=p.n2, n3=0, n4=(p.type==3||p.type==0)?p.n4:0;
@@ -534,52 +567,48 @@ bool mglCanvas::WriteJSON(const char *fname)
 		if(p.type==4)
 		{
 			const mglPnt &q = Pnt[p.n1];
-			xy.push_back(mglPoint(q.u,q.v,p.n2));
-			n2 = xy.size()-1;
+#pragma omp critical
+			{xy.push_back(mglPoint(q.u,q.v,p.n2));	n2 = xy.size()-1;}
 			n3 = p.n3;	n4 = p.n4;
 		}
 		if(p.type==1 && n1>n2)	{	n1=p.n2;	n2=p.n1;	}
-		if(c.a==1 || p.type==0 || p.type==1 || p.type==4 || p.type==6)
-//			fprintf(fp,"[%d,%ld,%ld,%ld,%ld,%d,%.4g,%.4g,%.4g,%.4g,\"#%02x%02x%02x\"]%c\n",
-			mgl_printf(fp, gz,"[%d,%ld,%ld,%ld,%ld,%d,%.3g,%.2g,%.2g,%.2g,\"#%02x%02x%02x\"]%c\n",
-				p.type, n1, n2, n3, n4, p.id, p.s, p.w==p.w?p.w:0, p.p==p.p?p.p:0,
-				0., int(255*c.r), int(255*c.g), int(255*c.b), i+1<l?',':' ');
-		else
-//			fprintf(fp,"[%d,%ld,%ld,%ld,%ld,%d,%.4g,%.4g,%.4g,%.4g,\"rgba(%d,%d,%d,%.2g)\"]%c\n",
-			mgl_printf(fp, gz,"[%d,%ld,%ld,%ld,%ld,%d,%.3g,%.2g,%.2g,%.2g,\"rgba(%d,%d,%d,%.2g)\"]%c\n",
-				p.type, n1, n2, n3, n4, p.id, p.s, p.w==p.w?p.w:0, p.p==p.p?p.p:0,
-				0., int(255*c.r), int(255*c.g), int(255*c.b), c.a, i+1<l?',':' ');
+		register long ps=p.s==p.s?long(100*factor*p.s):0, pw=p.w==p.w?long(100*p.w):0, pp=p.p==p.p?long(1e5*p.p+0.5):0;
+		if(cp.r[3]==255 || p.type==0 || p.type==1 || p.type==4 || p.type==6)
+			buf = mgl_sprintf("[%d,%ld,%ld,%ld,%ld,%d,%ld,%ld,%ld,0,\"#%02x%02x%02x\"],\n",
+				p.type, n1, n2, n3, n4, p.id, ps,pw,pp, int(cp.r[0]),int(cp.r[1]),int(cp.r[2]));
+		else if(cp.r[3])
+			buf = mgl_sprintf("[%d,%ld,%ld,%ld,%ld,%d,%ld,%ld,%ld,0,\"rgba(%d,%d,%d,%.2g)\"],\n",
+				p.type, n1, n2, n3, n4, p.id, ps,pw,pp, int(cp.r[0]),int(cp.r[1]),int(cp.r[2]),cp.r[3]/255.);
+		else	buf = "";
+#pragma omp critical
+		res += buf;
 	}
-	
-	l = xy.size();
-	mgl_printf(fp, gz,"],\t\"ncoor\":%lu,\t\"coor\":[\n",(unsigned long)l);
+	res += "[0,0,0,0,0,0,0,0,0,0,\"#000000\"]\n";	// need to add this empty block
+
+	l = (long)xy.size();
+	res = res + mgl_sprintf("],\t\"ncoor\":%lu,\t\"coor\":[\n",(unsigned long)l);
 	for(i=0;i<l;i++)
 	{
 		const mglPoint &p=xy[i];
 		const mglPnt &q=Pnt[int(0.5+p.z)];
-		if(q.u==q.u)
-			mgl_printf(fp, gz,"[%.3g,%.3g,%.3g,%.3g,%.3g]%c\n", p.x, p.y, q.u, q.v, q.w, i+1<l?',':' ');
-//			fprintf(fp,"[%.4g,%.4g,%.4g,%.4g,%.4g]%c\n", p.x, p.y, q.u, q.v, q.w, i+1<l?',':' ');
+		register long px=long(100*p.x), py=long(100*p.y);
+		if(q.u==q.u && q.v==q.v && q.w==q.w)
+			res = res + mgl_sprintf("[%ld,%ld,%ld,%ld,%ld]%c\n", px, py, long(100*q.u), long(100*q.v), long(100*q.w), i+1<l?',':' ');
 		else
-//			fprintf(fp,"[%.4g,%.4g,1e11,1e11,1e11]%c\n", p.x, p.y, i+1<l?',':' ');
-			mgl_printf(fp, gz,"[%.2g,%.2g,1e11,1e11,1e11]%c\n", p.x, p.y, i+1<l?',':' ');
+			res = res + mgl_sprintf("[%ld,%ld,1e11,1e11,1e11]%c\n", px, py, i+1<l?',':' ');
 	}
 
-	l = Glf.size();
-	mgl_printf(fp, gz,"],\t\"nglfs\":%lu,\t\"glfs\":[\n",(unsigned long)l);
+	l = (long)Glf.size();
+	res = res + mgl_sprintf("],\t\"nglfs\":%lu,\t\"glfs\":[\n",(unsigned long)l);
 	for(i=0;i<l;i++)
 	{
 		const mglGlyph &g=Glf[i];
-		mgl_printf(fp, gz,"[%ld,%ld,\n\t[", g.nt, g.nl);
-		register long j;
-		for(j=0;j<6*g.nt;j++)	mgl_printf(fp, gz,"%d%c", g.trig[j], j+1<6*g.nt?',':' ');
-		mgl_printf(fp, gz,"],\n\t[");
-		for(j=0;j<2*g.nl;j++)	mgl_printf(fp, gz,"%d%c", g.line[j], j+1<2*g.nl?',':' ');
-		mgl_printf(fp, gz,"]\n]%c\n", i+1<l?',':' ');
+		res = res + mgl_sprintf("[%ld,\n\t[", g.nl);
+		for(long j=0;j<2*g.nl;j++)	res = res + mgl_sprintf("%d%c", g.line[j], j+1<2*g.nl?',':' ');
+		res = res + mgl_sprintf("]\n]%c\n", i+1<l?',':' ');
 	}
-	mgl_printf(fp, gz,"]\n}\n");
-	if(fl)	{	if(gz)	gzclose((gzFile)fp);	else	fclose((FILE *)fp);	}
-	return false;
+	res = res + mgl_sprintf("]\n}\n");
+	return res;
 }
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_write_json(HMGL gr, const char *fname,const char *)
@@ -589,6 +618,13 @@ void MGL_EXPORT mgl_write_json_(uintptr_t *gr, const char *fname,const char *des
 	char *f=new char[n+1];	memcpy(f,descr,n);	f[n]=0;
 	mgl_write_json(_GR_,s,f);	delete []s;		delete []f;	}
 //-----------------------------------------------------------------------------
+void MGL_EXPORT mgl_write_json_z(HMGL gr, const char *fname,const char *)
+{	_Gr_->WriteJSON(fname,true);	}
+void MGL_EXPORT mgl_write_json_z_(uintptr_t *gr, const char *fname,const char *descr,int l,int n)
+{	char *s=new char[l+1];	memcpy(s,fname,l);	s[l]=0;
+	char *f=new char[n+1];	memcpy(f,descr,n);	f[n]=0;
+	mgl_write_json_z(_GR_,s,f);	delete []s;		delete []f;	}
+//-----------------------------------------------------------------------------
 bool mglCanvas::ExportMGLD(const char *fname, const char *descr)
 {
 	if(Pnt.size()<1 || Prm.size()<1)	return true;
@@ -596,27 +632,26 @@ bool mglCanvas::ExportMGLD(const char *fname, const char *descr)
 	if(!fp)	return true;
 	// NOTE: I'll save Ptx. So prim type=6 is useless,and no LaTeX
 	fprintf(fp,"MGLD %lu %lu %lu %lu %d %d\n# %s\n", (unsigned long)Pnt.size(), (unsigned long)Prm.size(), (unsigned long)Txt.size(), (unsigned long)Glf.size(), Width, Height, (descr && *descr) ? descr : fname);
-	register size_t i;
 	fprintf(fp,"# Vertexes: x y z c t ta u v w r g b a\n");
-	for(i=0;i<Pnt.size();i++)
+	for(size_t i=0;i<Pnt.size();i++)
 	{
 		const mglPnt &q=Pnt[i];
 		fprintf(fp,"%.4g\t%.4g\t%.4g\t%.4g\t%.4g\t%.4g\t%.4g\t%.4g\t%.4g\t%.4g\t%.4g\t%.4g\t%.4g\n", q.xx, q.yy, q.zz, q.c, q.t, q.ta, q.u, q.v, q.w, q.r, q.g, q.b, q.a);
 	}
 	fprintf(fp,"# Primitives: type n1 n2 n3 n4 id s w p\n");
-	for(i=0;i<Prm.size();i++)
+	for(size_t i=0;i<Prm.size();i++)
 	{
-		const mglPrim &p=Prm[i];
-		fprintf(fp,"%d\t%ld\t%ld\t%ld\t%ld\t%d\t%g\t%g\t%g\n", p.type, p.n1, p.n2, p.n3, p.n4, p.id, p.s, p.w, p.p);
+		const mglPrim &p=Prm[i];	// TODO: check if better save p.m instead of p.s,p.p
+		fprintf(fp,"%d\t%ld\t%ld\t%ld\t%ld\t%d\t%g\t%g\t%g\n", p.type, p.n1, p.n2, p.n3, p.n4, p.id, p.s==p.s?p.s:0, p.w==p.w?p.w:0, p.p==p.p?p.p:0);
 	}
 	fprintf(fp,"# Textures: smooth alpha colors\n");
-	for(i=0;i<Txt.size();i++)
+	for(size_t i=0;i<Txt.size();i++)
 	{
 		const mglTexture &t=Txt[i];
 		fprintf(fp,"%d\t%.4g\t%s\n",t.Smooth,t.Alpha,t.Sch);
 	}
 	fprintf(fp,"# Glyphs: nt nl [trig] [line]\n");
-	for(i=0;i<Glf.size();i++)
+	for(size_t i=0;i<Glf.size();i++)
 	{
 		const mglGlyph &g=Glf[i];
 		fprintf(fp,"%ld\t%ld\n", g.nt, g.nl);
@@ -649,8 +684,7 @@ bool mglCanvas::ImportMGLD(const char *fname, bool add)
 	char *buf=new char[512];
 	if(!fgets(buf,512,fp))	*buf=0;
 	if(strncmp(buf,"MGLD",4))	{	delete []buf;	fclose(fp);	return true;	}
-	register size_t i;
-	unsigned long n=0,m=0,l=0,k=0, npnt=0, nglf=0;
+	unsigned long i,n=0,m=0,l=0,k=0, npnt=0, nglf=0;
 	int w=0,h=0,d;
 	sscanf(buf+5,"%lu%lu%lu%lu%d%d",&n,&m,&l,&k,&w,&h);
 	if(w<=0 || h<=0)	{	w=Width;	h=Height;	}
@@ -658,61 +692,64 @@ bool mglCanvas::ImportMGLD(const char *fname, bool add)
 	if(n<=0 || m<=0 || l<=0)	{	delete []buf;	fclose(fp);	return true;	}
 	if(!add)	{	Clf();	Txt.clear();	}
 	else	{	ClfZB();	npnt=Pnt.size();	nglf=Glf.size();	}
-	Pnt.reserve(n);	Prm.reserve(m);	Txt.reserve(l);	Glf.reserve(k);
 #if MGL_HAVE_PTHREAD
 	pthread_mutex_lock(&mutexGlf);
 	pthread_mutex_lock(&mutexPnt);
 	pthread_mutex_lock(&mutexPrm);
 	pthread_mutex_lock(&mutexTxt);
 #endif
-	mglPnt p;
-	for(i=0;i<n;i++)
+#pragma omp critical
 	{
-		do {	if(!fgets(buf,512,fp))	*buf=0;	mgl_strtrim(buf);	} while(*buf=='#');
-		sscanf(buf,"%g%g%g%g%g%g%g%g%g%g%g%g%g", &p.xx, &p.yy, &p.zz, &p.c, &p.t, &p.ta, &p.u, &p.v, &p.w, &p.r, &p.g, &p.b, &p.a);
-		// rescale to current image size
-		p.xx *= Width/double(w);	p.yy *= Height/double(h);	p.zz *= Depth/double(d);
-		Pnt.push_back(p);
-	}
-	mglPrim q;
-	for(i=0;i<m;i++)
-	{
-		do {	if(!fgets(buf,512,fp))	*buf=0;	mgl_strtrim(buf);	} while(*buf=='#');
-		sscanf(buf,"%d%ld%ld%ld%ld%d%g%g%g", &q.type, &q.n1, &q.n2, &q.n3, &q.n4, &q.id, &q.s, &q.w, &q.p);
-		q.n1 = q.n1>=0?q.n1+npnt:-1;
-		q.n2 = q.n2>=0?q.n2+npnt:-1;
-		if(q.type==2 || q.type==3)
-		{	q.n3 = q.n3>=0?q.n3+npnt:-1;	q.n4 = q.n4>=0?q.n4+npnt:-1;	}
-		if(q.type==4)
-		{	q.n4 = q.n4>=0?q.n4+nglf:-1;	q.s *= font_factor/(w<h?w:h);	}
-		if(q.type<5)	Prm.push_back(q);
-	}
-	mglTexture t;
-	for(i=0;i<l;i++)
-	{
-		int sm=0;	float a;
-		do {	if(!fgets(buf,512,fp))	*buf=0;	mgl_strtrim(buf);	} while(*buf=='#');
-		register size_t j,k=0;
-		for(j=0;buf[j];j++)
+		Pnt.reserve(n);	Prm.reserve(m);	Txt.reserve(l);	Glf.reserve(k);
+		mglPnt p;
+		for(i=0;i<n;i++)
 		{
-			if(buf[j]<=' ' && k)	{	sm++;	k=0;	}
-			if(buf[j]>' ')	k=1;
-			if(sm==2 && k)	break;
+			do {	if(!fgets(buf,512,fp))	*buf=0;	mgl_strtrim(buf);	} while(*buf=='#');
+			sscanf(buf,"%g%g%g%g%g%g%g%g%g%g%g%g%g", &p.xx, &p.yy, &p.zz, &p.c, &p.t, &p.ta, &p.u, &p.v, &p.w, &p.r, &p.g, &p.b, &p.a);
+			// rescale to current image size
+			p.xx *= Width/double(w);	p.yy *= Height/double(h);	p.zz *= Depth/double(d);
+			Pnt.push_back(p);
+		}
+		mglPrim q;
+		for(i=0;i<m;i++)
+		{
+			do {	if(!fgets(buf,512,fp))	*buf=0;	mgl_strtrim(buf);	} while(*buf=='#');
+			sscanf(buf,"%hd%ld%ld%ld%ld%d%g%g%g", &q.type, &q.n1, &q.n2, &q.n3, &q.n4, &q.id, &q.s, &q.w, &q.p);
+			q.n1 = q.n1>=0?q.n1+npnt:-1;
+			q.n2 = q.n2>=0?q.n2+npnt:-1;
+			if(q.type==2 || q.type==3)
+			{	q.n3 = q.n3>=0?q.n3+npnt:-1;	q.n4 = q.n4>=0?q.n4+npnt:-1;	}
+			if(q.type==4)
+			{	q.n4 = q.n4>=0?q.n4+nglf:-1;	q.s *= font_factor/(w<h?w:h);	}
+			if(q.type<5)	Prm.push_back(q);
+		}
+		mglTexture t;
+		for(i=0;i<l;i++)
+		{
+			int sm=0;	float a;
+			do {	if(!fgets(buf,512,fp))	*buf=0;	mgl_strtrim(buf);	} while(*buf=='#');
+			register size_t j,k=0;
+			for(j=0;buf[j];j++)
+			{
+				if(buf[j]<=' ' && k)	{	sm++;	k=0;	}
+				if(buf[j]>' ')	k=1;
+				if(sm==2 && k)	break;
+			}
+			sscanf(buf,"%d%g", &sm, &a);
+			t.Set(buf+j, sm, a);
+			Txt.push_back(t);
+		}
+		mglGlyph g;
+		for(i=0;i<k;i++)
+		{
+			do {	if(!fgets(buf,512,fp))	*buf=0;	mgl_strtrim(buf);	} while(*buf=='#' || *buf==0);
+			long nt=0,nl=0;
+			sscanf(buf,"%ld%ld", &nt, &nl);	g.Create(nt,nl);
+			register long j;
+			for(j=0;j<6*nt;j++)	fscanf(fp,"%hd",g.trig+j);
+			for(j=0;j<2*nl;j++)	fscanf(fp,"%hd",g.line+j);
+			Glf.push_back(g);
 		}
-		sscanf(buf,"%d%g", &sm, &a);
-		t.Set(buf+j, sm, a);
-		Txt.push_back(t);
-	}
-	mglGlyph g;
-	for(i=0;i<k;i++)
-	{
-		do {	if(!fgets(buf,512,fp))	*buf=0;	mgl_strtrim(buf);	} while(*buf=='#' || *buf==0);
-		long nt=0,nl=0;
-		sscanf(buf,"%ld%ld", &nt, &nl);	g.Create(nt,nl);
-		register long j;
-		for(j=0;j<6*nt;j++)	fscanf(fp,"%hd",g.trig+j);
-		for(j=0;j<2*nl;j++)	fscanf(fp,"%hd",g.line+j);
-		Glf.push_back(g);
 	}
 #if MGL_HAVE_PTHREAD
 	pthread_mutex_unlock(&mutexGlf);
@@ -871,14 +908,14 @@ void MGL_EXPORT mgl_import_mgld_(uintptr_t *gr, const char *fname, int *add, int
 			fprintf(fp,"l -1/%ld -3/%ld\n", i,i);	break;
 		case 'O':
 			for(long j=0;j<=20;j++)
-				fprintf(fp,"v %g %g %g\n",p.x+ss*cos(j*M_PI/10),p.y+ss*sin(j*M_PI/10),p.z);
+				fprintf(fp,"v %g %g %g\n",p.x+ss*mgl_cos[(j*36)%360],p.y+ss*mgl_cos[(270+j*36)%360],p.z);
 			for(long j=0;j<20;j++)
 				fprintf(fp,"f %ld/%ld %ld/%ld %ld/%ld\n", j-21,i, j-20,i, i,i);
 			break;
 		case 'C':	fprintf(fp,"p %ld\n", i);
 		case 'o':
 			for(long j=0;j<=20;j++)
-				fprintf(fp,"v %g %g %g\n",p.x+ss*cos(j*M_PI/10),p.y+ss*sin(j*M_PI/10),p.z);
+				fprintf(fp,"v %g %g %g\n",p.x+ss*mgl_cos[(j*36)%360],p.y+ss*mgl_cos[(270+j*36)%360],p.z);
 			for(long j=0;j<20;j++)
 				fprintf(fp,"l %ld/%ld %ld/%ld\n", j-21,i, j-20,i);
 			break;
@@ -972,7 +1009,7 @@ void MGL_EXPORT mgl_x3d_mdef(HMGL gr, void *fp, bool gz)
 	m_s=false,m_a=false,m_o=false,m_T=false,
 	m_V=false,m_S=false,m_D=false,m_Y=false,m_l=false,
 	m_L=false,m_r=false,m_R=false,m_X=false,m_P=false;
-	for(size_t i=0;i<gr->GetPrmNum();i++)
+	for(long i=0;i<gr->GetPrmNum();i++)
 	{
 		const mglPrim q = gr->GetPrm(i);
 		if(q.type>0)	continue;		if(q.n4=='+')	m_p = true;
@@ -1098,7 +1135,7 @@ void MGL_EXPORT mgl_x3d_prim(const mglPrim &q, const mglPnt &p, const long *pnt,
 			if(q.n3&4)	mgl_printf(fp, gz, "dr");
 			else	mgl_printf(fp, gz, "eofill");
 			mgl_printf(fp, gz, " grestore\n");
-		}*/	
+		}*/
 }
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_write_x3d(HMGL gr, const char *fname,const char *descr)
@@ -1124,12 +1161,11 @@ void MGL_EXPORT mgl_write_x3d(HMGL gr, const char *fname,const char *descr)
 
 	// 2. now find group for primitives
 	long m1=0,m2=0,m;
-	register size_t i,j;
-	for(i=0;i<gr->Grp.size();i++)	// prepare array of indirect indexing
+	for(size_t i=0;i<gr->Grp.size();i++)	// prepare array of indirect indexing
 	{	m = gr->Grp[i].Id;	if(m<m1) m1=m;	if(m>m2) m2=m;	}
 	long *ng = new long[m2-m1+1];
-	for(i=0;i<gr->Grp.size();i++)	ng[gr->Grp[i].Id-m1] = i;
-	for(i=0;i<gr->GetPrmNum();i++)	// collect data for groups
+	for(size_t i=0;i<gr->Grp.size();i++)	ng[gr->Grp[i].Id-m1] = i;
+	for(long i=0;i<gr->GetPrmNum();i++)	// collect data for groups
 	// it is rather expensive (extra 4b per primitive) but need for export to 3D
 	{
 		m = gr->GetPrm(i).id-m1;
@@ -1139,19 +1175,19 @@ void MGL_EXPORT mgl_write_x3d(HMGL gr, const char *fname,const char *descr)
 
 	// resort in creation order for proper drawing of lines and faces
 	gr->resort();
-	
+
 	// primitive definition in groups
 	long npnt = gr->GetPntNum(), k;
 	long *pnt=new long[npnt];
 	mglPrim q;
-	for(i=0;i<gr->Grp.size();i++)
+	for(size_t i=0;i<gr->Grp.size();i++)
 	{
 		mgl_printf(fp,gz,"<Group><!--%s-->\n",gr->Grp[i].Lbl.c_str());
 		std::vector<long> &p = gr->Grp[i].p;
 
 		// define coordinates, colors and so on
-		long line=-1, face=-1, other=-1;
-		for(j=0,k=0;j<p.size();j++)	// find points for this group
+		long line=-1, face=-1, other=-1;	k=0;
+		for(size_t j=0;j<p.size();j++)	// find points for this group
 		{
 			const mglPrim &q=gr->GetPrm(p[j]);
 			if(q.type==1)	line=q.n1;	// find kind of primitives in the group
@@ -1164,13 +1200,13 @@ void MGL_EXPORT mgl_write_x3d(HMGL gr, const char *fname,const char *descr)
 		{
 			mglColor c=gr->GetPntC(line);
 			bool same=true;	// check if there are the same colors for all line segments
-			for(j=0;j<p.size();j++)
+			for(size_t j=0;j<p.size();j++)
 			{
 				const mglPrim &q=gr->GetPrm(p[j]);
 				if(q.type==1 && c!=gr->GetPntC(q.n1))	same=false;
 			}
 			memset(pnt,-1,npnt*sizeof(long));
-			for(j=0,k=0;j<p.size();j++)	// rearrange points for this group
+			for(size_t j=0,k=0;j<p.size();j++)	// rearrange points for this group
 			{
 				const mglPrim &q=gr->GetPrm(p[j]);
 				if(q.type!=1)	continue;
@@ -1178,16 +1214,16 @@ void MGL_EXPORT mgl_write_x3d(HMGL gr, const char *fname,const char *descr)
 				if(q.n2>=0 && pnt[q.n2]<0)	{	pnt[q.n2]=k;	k++;	}
 			}
 			mgl_printf(fp, gz, "<Shape><Coordinate DEF='Lpnts_%ld' point='",i);
-			for(j=0;j<gr->GetPntNum();j++)	if(pnt[j]>=0)
+			for(long j=0;j<gr->GetPntNum();j++)	if(pnt[j]>=0)
 			{	const mglPnt &p=gr->GetPnt(j);	mgl_printf(fp, gz, "%g %g %g, ", p.x,p.y,p.z);	}
 			mgl_printf(fp, gz, "0.0 0.0 0.0'/>");
 			mgl_printf(fp, gz, "<Color DEF='Lclrs_%ld' color='",i);
-			for(j=0;j<gr->GetPntNum();j++)	if(pnt[j]>=0)
+			for(long j=0;j<gr->GetPntNum();j++)	if(pnt[j]>=0)
 			{	const mglPnt &p=gr->GetPnt(j);	mgl_printf(fp, gz, "%g %g %g, ", p.r,p.g,p.b);	}
 			mgl_printf(fp, gz, "0.0 0.0 0.0'/>");
 
 			// TODO save IndexedLineSet here + manual color is same==true
-			
+
 			mgl_printf(fp, gz, "</Shape>");
 		}
 
@@ -1196,13 +1232,13 @@ void MGL_EXPORT mgl_write_x3d(HMGL gr, const char *fname,const char *descr)
 		{
 			mglColor c=gr->GetPntC(face);
 			bool same=true;	// check if there are the same colors for all line segments
-			for(j=0;j<p.size();j++)
+			for(size_t j=0;j<p.size();j++)
 			{
 				const mglPrim &q=gr->GetPrm(p[j]);
 				if((q.type==2 || q.type==3) && c!=gr->GetPntC(q.n1))	same=false;
 			}
 			memset(pnt,-1,npnt*sizeof(long));
-			for(j=0,k=0;j<p.size();j++)	// rearrange points for this group
+			for(size_t j=0,k=0;j<p.size();j++)	// rearrange points for this group
 			{
 				const mglPrim &q=gr->GetPrm(p[j]);
 				if(q.type!=2 && q.type!=3)	continue;
@@ -1212,11 +1248,11 @@ void MGL_EXPORT mgl_write_x3d(HMGL gr, const char *fname,const char *descr)
 				if(q.type==3 && q.n4>=0 && pnt[q.n4]<0)	{	pnt[q.n4]=k;	k++;	}
 			}
 			mgl_printf(fp, gz, "<Shape><Coordinate DEF='Fpnts_%ld' point='",i);
-			for(j=0;j<gr->GetPntNum();j++)	if(pnt[j]>=0)
+			for(long j=0;j<gr->GetPntNum();j++)	if(pnt[j]>=0)
 			{	const mglPnt &p=gr->GetPnt(j);	mgl_printf(fp, gz, "%g %g %g, ", p.x,p.y,p.z);	}
 			mgl_printf(fp, gz, "0.0 0.0 0.0'/>");
 			mgl_printf(fp, gz, "<Color DEF='Fclrs_%ld' color='",i);
-			for(j=0;j<gr->GetPntNum();j++)	if(pnt[j]>=0)
+			for(long j=0;j<gr->GetPntNum();j++)	if(pnt[j]>=0)
 			{	const mglPnt &p=gr->GetPnt(j);	mgl_printf(fp, gz, "%g %g %g, ", p.r,p.g,p.b);	}
 			mgl_printf(fp, gz, "0.0 0.0 0.0'/>");
 
@@ -1253,7 +1289,7 @@ void MGL_EXPORT mgl_write_x3d(HMGL gr, const char *fname,const char *descr)
 		}
 		// no normals since mathgl ones are "signless" -- x3d should calculate it by itself
 
-		for(j=0;j<p.size();j++)
+		for(size_t j=0;j<p.size();j++)
 		{
 			const mglPrim &q=gr->GetPrm(p[j]);	// TODO: collect by type (quads,trig,line) and draw together???
 			mgl_x3d_prim(q, gr->GetPnt(q.n1), pnt, fp,gz, q.s*gr->FontFactor());
diff --git a/src/fft.cpp b/src/fft.cpp
index 486154d..8ab3dc8 100644
--- a/src/fft.cpp
+++ b/src/fft.cpp
@@ -19,6 +19,7 @@
  ***************************************************************************/
 #include "mgl2/datac.h"
 #include "mgl2/data.h"
+#include "mgl2/thread.h"
 #if MGL_HAVE_GSL
 #include <gsl/gsl_fft_complex.h>
 #include <gsl/gsl_dht.h>
@@ -53,115 +54,192 @@ void MGL_EXPORT mglStartThreadT(void *(*func)(void *), long n, void *a, double *
 	}
 }
 //-----------------------------------------------------------------------------
+struct mglFFTdata
+{
+	long wnx,wny,wnz;		// sizes for FFT
+	long hnx,hny,hnz;		// sizes for Hankel
+	void *wtx,*wty,*wtz;	// tables for FFT
+	void *htx,*hty,*htz;	// tables for Hankel
+	mglFFTdata()	{	memset(this,0,sizeof(mglFFTdata));	}
+	~mglFFTdata()	{	Clear();	}
+	void Clear()
+	{
+		if(wnx)	{	wnx=0;	mgl_fft_free(wtx,0,0);	}
+		if(wny)	{	wny=0;	mgl_fft_free(wty,0,0);	}
+		if(wnz)	{	wnz=0;	mgl_fft_free(wtz,0,0);	}
+#if MGL_HAVE_GSL
+		if(hnx)	{	hnx=0;	gsl_dht_free((gsl_dht*)htx);	}
+		if(hny)	{	hny=0;	gsl_dht_free((gsl_dht*)hty);	}
+		if(hnz)	{	hnz=0;	gsl_dht_free((gsl_dht*)htz);	}
+#endif
+	}
+} mgl_fft_data;
+void MGL_EXPORT mgl_clear_fft()	{	mgl_fft_data.Clear();	}
+//-----------------------------------------------------------------------------
+MGL_EXPORT void *mgl_fft_alloc_thr(long n)
+{
+#if MGL_HAVE_GSL
+	return gsl_fft_complex_workspace_alloc(n);
+#else
+	return new double[2*n];
+#endif
+}
+//-----------------------------------------------------------------------------
 MGL_EXPORT void *mgl_fft_alloc(long n, void **space, long nthr)
 {
+	if(space && nthr>0)	for(long i=0;i<nthr;i++)	space[i] = mgl_fft_alloc_thr(n);
 #if MGL_HAVE_GSL
-	for(long i=0;i<nthr;i++)	space[i] = gsl_fft_complex_workspace_alloc(n);
 	return gsl_fft_complex_wavetable_alloc(n);
 #else
-	register long i,j;
-	for(i=0;i<nthr;i++)	space[i] = new double[2*n];
 	double *c = new double[2*n*n];
-	for(i=0;i<n;i++)	for(j=0;j<n;j++)
+#pragma omp parallel for collapse(2)
+	for(long i=0;i<n;i++)	for(long j=0;j<n;j++)
 	{	c[2*(i+n*j)]=cos(2*M_PI*i*j/n);	c[2*(i+n*j)+1]=-sin(2*M_PI*i*j/n);	}
 	return c;
 #endif
 }
 //-----------------------------------------------------------------------------
+void MGL_EXPORT mgl_fft_free_thr(void *ws)
+{
+#if MGL_HAVE_GSL
+	gsl_fft_complex_workspace_free((gsl_fft_complex_workspace*)ws);
+#else
+	delete []((double*)ws);
+#endif
+}
+//-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_fft_free(void *wt, void **ws, long nthr)
 {
+	if(ws && nthr>0)	for(long i=0;i<nthr;i++)	mgl_fft_free_thr(ws[i]);
 #if MGL_HAVE_GSL
-	for(long i=0;i<nthr;i++)	gsl_fft_complex_workspace_free((gsl_fft_complex_workspace*)(ws[i]));
 	gsl_fft_complex_wavetable_free((gsl_fft_complex_wavetable*)wt);
 #else
 	delete []((double*)wt);
-	for(long i=0;i<nthr;i++)	delete []((double*)(ws[i]));
 #endif
 }
 //-----------------------------------------------------------------------------
-void MGL_EXPORT mgl_fft(double *x, long s, long n, const void *wt, void *ws, bool inv)
+void MGL_EXPORT mgl_fft(double *x, long s, long n, const void *wt, void *ws, int inv)
 {
 #if MGL_HAVE_GSL
-gsl_fft_complex_transform(x, s, n, (const gsl_fft_complex_wavetable*)wt, (gsl_fft_complex_workspace*)ws, inv?backward:forward);
+	if(inv)	gsl_fft_complex_inverse(x, s, n, (const gsl_fft_complex_wavetable*)wt, (gsl_fft_complex_workspace*)ws);
+	else	gsl_fft_complex_forward(x, s, n, (const gsl_fft_complex_wavetable*)wt, (gsl_fft_complex_workspace*)ws);
 #else	// NOTE this is VERY slow!
 	const double *c = (const double *)wt;
 	double *d = (double *)ws, f = inv?1./n:1;
 	memset(d,0,2*n*sizeof(double));
-	register long i,j,ii,jj;
-	if(inv)	for(i=0;i<n;i++)	for(j=0;j<n;j++)
-	{
-		ii = 2*(i+n*j);	jj = 2*j*s;
-		d[2*i] 	+= x[jj]*c[ii]+x[jj+1]*c[ii+1];
-		d[2*i+1]+= x[jj+1]*c[ii]-x[jj]*c[ii+1];
-	}
-	else	for(i=0;i<n;i++)	for(j=0;j<n;j++)
-	{
-		ii = 2*(i+n*j);	jj = 2*j*s;
-		d[2*i] 	+= x[jj]*c[ii]-x[jj+1]*c[ii+1];
-		d[2*i+1]+= x[jj+1]*c[ii]+x[jj]*c[ii+1];
-	}
-	for(j=0;j<n;j++)
-	{	jj = 2*j*s;	x[jj] = d[2*j]*f;	x[jj+1] = d[2*j+1]*f;	}
+	if(inv)
+//#pragma omp parallel for	// NOTE only 1st for can be used!
+		for(long i=0;i<n;i++)	for(long j=0;j<n;j++)
+		{
+			register long ii = 2*(i+n*j), jj = 2*j*s;
+			d[2*i] 	+= x[jj]*c[ii]+x[jj+1]*c[ii+1];
+			d[2*i+1]+= x[jj+1]*c[ii]-x[jj]*c[ii+1];
+		}
+	else
+//#pragma omp parallel for	// NOTE only 1st for can be used!
+		for(long i=0;i<n;i++)	for(long j=0;j<n;j++)
+		{
+			register long ii = 2*(i+n*j), jj = 2*j*s;
+			d[2*i] 	+= x[jj]*c[ii]-x[jj+1]*c[ii+1];
+			d[2*i+1]+= x[jj+1]*c[ii]+x[jj]*c[ii+1];
+		}
+//#pragma omp parallel for
+	for(long j=0;j<n;j++)
+	{	register long jj = 2*j*s;	x[jj] = d[2*j]*f;	x[jj+1] = d[2*j+1]*f;	}
 #endif
 }
 //-----------------------------------------------------------------------------
 MGL_NO_EXPORT void* mgl_fftx(void *par)
 {
 	mglThreadT *t=(mglThreadT *)par;
-	register long i,nx=t->p[0];
-	for(i=t->id;i<t->n;i+=mglNumThr)
-		mgl_fft(t->b+2*nx*i, 1, nx, t->v, t->w[t->id], t->p[3]);
+	long nx=t->p[0];
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel
+#endif
+	{
+		void *w = mgl_fft_alloc_thr(nx);
+#pragma omp for nowait
+		for(long i=t->id;i<t->n;i+=mglNumThr)
+			mgl_fft(t->b+2*nx*i, 1, nx, t->v, w, t->p[3]);
+		mgl_fft_free_thr(w);
+	}
 	return 0;
 }
 MGL_NO_EXPORT void* mgl_ffty(void *par)
 {
 	mglThreadT *t=(mglThreadT *)par;
 	register long i,nx=t->p[0],ny=t->p[1];
-	for(i=t->id;i<t->n;i+=mglNumThr)
-		mgl_fft(t->b+2*(i%nx)+2*nx*ny*(i/nx), nx, ny, t->v, t->w[t->id], t->p[3]);
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel
+#endif
+	{
+		void *w = mgl_fft_alloc_thr(nx);
+#pragma omp for nowait
+		for(i=t->id;i<t->n;i+=mglNumThr)
+			mgl_fft(t->b+2*(i%nx)+2*nx*ny*(i/nx), nx, ny, t->v, w, t->p[3]);
+		mgl_fft_free_thr(w);
+	}
 	return 0;
 }
 MGL_NO_EXPORT void* mgl_fftz(void *par)
 {
 	mglThreadT *t=(mglThreadT *)par;
 	register long i,nx=t->p[0],ny=t->p[1],nz=t->p[2];
-	for(i=t->id;i<t->n;i+=mglNumThr)
-		mgl_fft(t->b+2*i, nx*ny, nz, t->v, t->w[t->id], t->p[3]);
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel
+#endif
+	{
+		void *w = mgl_fft_alloc_thr(nx);
+#pragma omp for nowait
+		for(i=t->id;i<t->n;i+=mglNumThr)
+			mgl_fft(t->b+2*i, nx*ny, nz, t->v, w, t->p[3]);
+		mgl_fft_free_thr(w);
+	}
 	return 0;
 }
 void MGL_EXPORT mgl_datac_fft(HADT d, const char *dir)
 {
 	if(!dir || *dir==0)	return;
 	long nx = d->nx, ny = d->ny, nz = d->nz;
-	if(mglNumThr<1)	mgl_set_num_thr(0);	// manually set number of threads
-	void *wt=0, **ws=new void*[mglNumThr];
-	long par[4]={nx,ny,nz,strchr(dir,'i')!=0}, i;
+	void *wt=0;
+	bool clear=false;
+	long par[4]={nx,ny,nz,strchr(dir,'i')!=0};
 #if MGL_USE_DOUBLE
 	double *a = (double *)(d->a);
 #else
 	double *a = new double[2*nx*ny*nz];	// manually convert to double
-	for(i=0;i<nx*ny*nz;i++)
+#pragma omp parallel for
+	for(long i=0;i<nx*ny*nz;i++)
 	{	a[2*i] = real(d->a[i]);	a[2*i+1] = imag(d->a[i]);	}
 #endif
 	if(strchr(dir,'x') && nx>1)
 	{
-		wt = mgl_fft_alloc(nx,ws,mglNumThr);
-		mglStartThreadT(mgl_fftx,ny*nz,0,a,wt,ws,par);
+		if(mgl_fft_data.wnx==nx)	wt = mgl_fft_data.wtx;
+		else	{	clear = true;	wt = mgl_fft_alloc(nx,0,0);	}
+		mglStartThreadT(mgl_fftx,ny*nz,0,a,wt,0,par);
+		if(mgl_fft_data.wnx==0)
+		{	clear = false;	mgl_fft_data.wtx = wt;	mgl_fft_data.wnx=nx;	}
 	}
 	if(strchr(dir,'y') && ny>1)
 	{
-		wt = mgl_fft_alloc(ny,ws,mglNumThr);
-		mglStartThreadT(mgl_ffty,nx*nz,0,a,wt,ws,par);
+		if(mgl_fft_data.wny==ny)	wt = mgl_fft_data.wty;
+		else	{	clear = true;	wt = mgl_fft_alloc(ny,0,0);	}
+		mglStartThreadT(mgl_ffty,nx*nz,0,a,wt,0,par);
+		if(mgl_fft_data.wny==0)
+		{	clear = false;	mgl_fft_data.wty = wt;	mgl_fft_data.wny=ny;	}
 	}
 	if(strchr(dir,'z') && nz>1)
 	{
-		wt = mgl_fft_alloc(nz,ws,mglNumThr);
-		mglStartThreadT(mgl_fftz,nx*ny,0,a,wt,ws,par);
+		if(mgl_fft_data.wnz==nz)	wt = mgl_fft_data.wtz;
+		else	{	clear = true;	wt = mgl_fft_alloc(nz,0,0);	}
+		mglStartThreadT(mgl_fftz,nx*ny,0,a,wt,0,par);
+		if(mgl_fft_data.wnz==0)
+		{	clear = false;	mgl_fft_data.wtz = wt;	mgl_fft_data.wnz=nz;	}
 	}
-	if(wt)	mgl_fft_free(wt,ws,mglNumThr);
-	delete []ws;
+	if(clear)	mgl_fft_free(wt,0,0);
 #if !MGL_USE_DOUBLE
-	for(i=0;i<nx*ny*nz;i++)	d->a[i] = dual(a[2*i], a[2*i+1]);
+#pragma omp parallel for
+	for(long i=0;i<nx*ny*nz;i++)	d->a[i] = dual(a[2*i], a[2*i+1]);
 	delete []a;
 #endif
 }
@@ -171,427 +249,533 @@ void MGL_EXPORT mgl_data_fourier(HMDT re, HMDT im, const char *dir)
 	if(!dir || *dir==0)	return;
 	long nx = re->nx, ny = re->ny, nz = re->nz;
 	if(nx*ny*nz != im->nx*im->ny*im->nz || !dir || dir[0]==0)	return;
-	if(mglNumThr<1)	mgl_set_num_thr(0);	// manually set number of threads
-	void *wt=0, **ws=new void*[mglNumThr];
-	long par[4]={nx,ny,nz,strchr(dir,'i')!=0}, i;
+	bool clear=false;
+	void *wt=0;
+	long par[4]={nx,ny,nz,strchr(dir,'i')!=0};
 	double *a = new double[2*nx*ny*nz];
-	for(i=0;i<nx*ny*nz;i++)
+#pragma omp parallel for
+	for(long i=0;i<nx*ny*nz;i++)
 	{	a[2*i] = re->a[i];	a[2*i+1] = im->a[i];	}
 	if(strchr(dir,'x') && nx>1)
 	{
-		wt = mgl_fft_alloc(nx,ws,mglNumThr);
-		mglStartThreadT(mgl_fftx,ny*nz,0,a,wt,ws,par);
+		if(mgl_fft_data.wnx==nx)	wt = mgl_fft_data.wtx;
+		else	{	clear = true;	wt = mgl_fft_alloc(nx,0,0);	}
+		mglStartThreadT(mgl_fftx,ny*nz,0,a,wt,0,par);
+		if(mgl_fft_data.wnx==0)
+		{	mgl_fft_data.wtx = wt;	clear = false;	mgl_fft_data.wnx=nx;	}
 	}
 	if(strchr(dir,'y') && ny>1)
 	{
-		wt = mgl_fft_alloc(ny,ws,mglNumThr);
-		mglStartThreadT(mgl_ffty,nx*nz,0,a,wt,ws,par);
+		if(mgl_fft_data.wny==ny)	wt = mgl_fft_data.wty;
+		else	{	clear = true;	wt = mgl_fft_alloc(ny,0,0);	}
+		mglStartThreadT(mgl_ffty,nx*nz,0,a,wt,0,par);
+		if(mgl_fft_data.wny==0)
+		{	mgl_fft_data.wty = wt;	clear = false;	mgl_fft_data.wny=ny;	}
 	}
 	if(strchr(dir,'z') && nz>1)
 	{
-		wt = mgl_fft_alloc(nz,ws,mglNumThr);
-		mglStartThreadT(mgl_fftz,nx*ny,0,a,wt,ws,par);
+		if(mgl_fft_data.wnz==nz)	wt = mgl_fft_data.wtz;
+		else	{	clear = true;	wt = mgl_fft_alloc(nz,0,0);	}
+		mglStartThreadT(mgl_fftz,nx*ny,0,a,wt,0,par);
+		if(mgl_fft_data.wnz==0)
+		{	mgl_fft_data.wtz = wt;	clear = false;	mgl_fft_data.wnz=nz;	}
 	}
-	if(wt)	mgl_fft_free(wt,ws,mglNumThr);
-	for(i=0;i<nx*ny*nz;i++)
+	if(clear)	{	mgl_fft_free(wt,0,0);	}
+#pragma omp parallel for
+	for(long i=0;i<nx*ny*nz;i++)
 	{	re->a[i] = a[2*i];	im->a[i] = a[2*i+1];	}
-	delete []ws;	delete []a;
+	delete []a;
 }
 //-----------------------------------------------------------------------------
 MGL_NO_EXPORT void* mgl_envx(void *par)
 {
 	mglThreadT *t=(mglThreadT *)par;
-	register long i,j,nx=t->p[0],ny=t->p[1],nz=t->p[2];
-	double *b = t->b+2*nx*t->id;
+	long nx=t->p[0];
 	mreal *a = (mreal*)t->a;
-	for(i=t->id;i<t->n;i+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel
+#endif
 	{
-		for(j=0;j<nx;j++)	{	b[2*j] = a[j+i*nx];	b[2*j+1] = 0;	}
-		mgl_fft(b, 1, nx, t->v, t->w[t->id], false);
-		for(j=0;j<nx;j++)
-		{	b[j] /= nx/2.;	b[j+nx] = 0;	}
-		mgl_fft(b, 1, nx, t->v, t->w[t->id], true);
-		for(j=0;j<nx;j++)	a[j+i*nx] = hypot(b[2*j], b[2*j+1]);
+		double *b =	new double[2*nx];
+		void *w = mgl_fft_alloc_thr(nx);
+#pragma omp for nowait
+		for(long i=t->id;i<t->n;i+=mglNumThr)
+		{
+			for(long j=0;j<nx;j++)	{	b[2*j] = a[j+i*nx];	b[2*j+1] = 0;	}
+			mgl_fft(b, 1, nx, t->v, w, false);
+			for(long j=0;j<nx;j++)	{	b[j] *= 2.;	b[j+nx] = 0;	}
+			mgl_fft(b, 1, nx, t->v, w, true);
+			for(long j=0;j<nx;j++)	a[j+i*nx] = hypot(b[2*j], b[2*j+1]);
+		}
+		mgl_fft_free_thr(w);	delete []b;
 	}
 	return 0;
 }
 MGL_NO_EXPORT void* mgl_envy(void *par)
 {
 	mglThreadT *t=(mglThreadT *)par;
-	register long i,j,nx=t->p[0],ny=t->p[1],nz=t->p[2];
-	double *b = t->b+2*ny*t->id;
+	long nx=t->p[0],ny=t->p[1];
 	mreal *a = (mreal*)t->a;
-	for(i=t->id;i<t->n;i+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel
+#endif
 	{
-		for(j=0;j<ny;j++)	{	b[2*j] = a[(i%nx)+nx*(j+ny*(i/nx))];	b[2*j+1] = 0;	}
-		mgl_fft(b, 1, ny, t->v, t->w[t->id], false);
-		for(j=0;j<ny;j++)
-		{	b[j] /= ny/2.;	b[j+ny] = 0;	}
-		mgl_fft(b, 1, ny, t->v, t->w[t->id], true);
-		for(j=0;j<ny;j++)	a[(i%nx)+nx*(j+ny*(i/nx))] = hypot(b[2*j], b[2*j+1]);
+		double *b =	new double[2*ny];
+		void *w = mgl_fft_alloc_thr(ny);
+#pragma omp for nowait
+		for(long i=t->id;i<t->n;i+=mglNumThr)
+		{
+			for(long j=0;j<ny;j++)	{	b[2*j] = a[(i%nx)+nx*(j+ny*(i/nx))];	b[2*j+1] = 0;	}
+			mgl_fft(b, 1, ny, t->v, t->w[t->id], false);
+			for(long j=0;j<ny;j++)	{	b[j] *= 2.;	b[j+ny] = 0;	}
+			mgl_fft(b, 1, ny, t->v, t->w[t->id], true);
+			for(long j=0;j<ny;j++)	a[(i%nx)+nx*(j+ny*(i/nx))] = hypot(b[2*j], b[2*j+1]);
+		}
+		mgl_fft_free_thr(w);	delete []b;
 	}
 	return 0;
 }
 MGL_NO_EXPORT void* mgl_envz(void *par)
 {
 	mglThreadT *t=(mglThreadT *)par;
-	register long i,j,nx=t->p[0],ny=t->p[1],nz=t->p[2],k=nx*ny;
-	double *b = t->b+2*nz*t->id;
+	long nx=t->p[0],ny=t->p[1],nz=t->p[2],k=nx*ny;
 	mreal *a = (mreal*)t->a;
-	for(i=t->id;i<t->n;i+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel
+#endif
 	{
-		for(j=0;j<nz;j++)	{	b[2*j] = a[j*k+i];	b[2*j+1] = 0;	}
-		mgl_fft(b, 1, nz, t->v, t->w[t->id], false);
-		for(j=0;j<nz;j++)
-		{	b[j] /= nz/2.;	b[j+nz] = 0;	}
-		mgl_fft(b, 1, nz, t->v, t->w[t->id], true);
-		for(j=0;j<nz;j++)	a[j*k+i] = hypot(b[2*j], b[2*j+1]);
+		double *b =	new double[2*nz];
+		void *w = mgl_fft_alloc_thr(nz);
+#pragma omp for nowait
+		for(long i=t->id;i<t->n;i+=mglNumThr)
+		{
+			for(long j=0;j<nz;j++)	{	b[2*j] = a[j*k+i];	b[2*j+1] = 0;	}
+			mgl_fft(b, 1, nz, t->v, t->w[t->id], false);
+			for(long j=0;j<nz;j++)	{	b[j] *= 2.;	b[j+nz] = 0;	}
+			mgl_fft(b, 1, nz, t->v, t->w[t->id], true);
+			for(long j=0;j<nz;j++)	a[j*k+i] = hypot(b[2*j], b[2*j+1]);
+		}
+		mgl_fft_free_thr(w);	delete []b;
 	}
 	return 0;
 }
 void MGL_EXPORT mgl_data_envelop(HMDT d, char dir)
 {
-	register long i;
 	long nx=d->nx,ny=d->ny,nz=d->nz,par[3]={nx,ny,nz};
-	if(mglNumThr<1)	mgl_set_num_thr(0);	// manually set number of threads
-	void *wt=0, **ws=new void*[mglNumThr];
-	double *b = 0;
+	bool clear=false;
+	void *wt=0;
 	if(dir=='x' && nx>1)
 	{
-		wt = mgl_fft_alloc(nx,ws,mglNumThr);
-		b = new double[2*nx*mglNumThr];
-		mglStartThreadT(mgl_envx,ny*nz,d->a,b,wt,ws,par);
+		if(mgl_fft_data.wnx==nx)	wt = mgl_fft_data.wtx;
+		else	{	clear = true;	wt = mgl_fft_alloc(nx,0,0);	}
+		mglStartThreadT(mgl_envx,ny*nz,d->a,0,wt,0,par);
+		if(mgl_fft_data.wnx==0)
+		{	mgl_fft_data.wtx = wt;	clear = false;	mgl_fft_data.wnx=nx;	}
 	}
 	if(dir=='y' && ny>1)
 	{
-		wt = mgl_fft_alloc(ny,ws,mglNumThr);
-		b = new double[2*ny*mglNumThr];
-		mglStartThreadT(mgl_envy,nx*nz,d->a,b,wt,ws,par);
+		if( mgl_fft_data.wny==ny)	wt = mgl_fft_data.wty;
+		else	{	clear = true;	wt = mgl_fft_alloc(ny,0,0);	}
+		mglStartThreadT(mgl_envy,nx*nz,d->a,0,wt,0,par);
+		if(mgl_fft_data.wny==0)
+		{	mgl_fft_data.wty = wt;	clear = false;	mgl_fft_data.wny=ny;	}
 	}
 	if(dir=='z' && nz>1)
 	{
-		wt = mgl_fft_alloc(nz,ws,mglNumThr);
-		b = new double[2*nz*mglNumThr];
-		mglStartThreadT(mgl_envz,nx*ny,d->a,b,wt,ws,par);
+		if(mgl_fft_data.wnz==nz)	wt = mgl_fft_data.wtz;
+		else	{	clear = true;	wt = mgl_fft_alloc(nz,0,0);	}
+		mglStartThreadT(mgl_envz,nx*ny,d->a,0,wt,0,par);
+		if(mgl_fft_data.wnz==0)
+		{	mgl_fft_data.wtz = wt;	clear = false;	mgl_fft_data.wnz=nz;	}
 	}
-	for(i=0;i<nx*ny*nz;i++)	d->a[i] = hypot(b[2*i], b[2*i+1]);
-	if(b)	{	mgl_fft_free(wt,ws,mglNumThr);	delete []b;	}
-	delete []ws;
+	if(clear)	mgl_fft_free(wt,0,0);
 }
 //-----------------------------------------------------------------------------
 MGL_NO_EXPORT void* mgl_stfa1(void *par)
 {
 	mglThreadT *t=(mglThreadT *)par;
-	register long i,j,k,ii,i0,mx=t->p[0],my=t->p[1],mz=t->p[2],dn=t->p[3],dd=dn/2,ny=t->p[4];
-	double *a = t->b+4*dn*t->id,ff;
+	long mx=t->p[0],mz=t->p[2],dn=t->p[3],dd=dn/2,ny=t->p[4];
 	mreal *d = (mreal*)t->a;
 	HCDT re = (HCDT)t->re, im = (HCDT)t->im;
-	for(ii=t->id;ii<t->n;ii+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel
+#endif
 	{
-		i = ii%mx;	j = ii/mx;
-		for(k=0;k<2*dn;k++)
-		{
-			i0 = k-dd+j*dn;		ff = 1;
-			if(i0<0)	i0=0;	else if(i0>=ny)	i0=ny-1;
-			if(k<dd)
-			{	ff = 0.5*(k-dd/2.)/dd;		ff=0.5+ff*(3-ff*ff);	}
-			else if(k>=dn+dd)
-			{	ff = 0.5*(k-3.5*dd)/dd;	ff=0.5-ff*(3-ff*ff);	}
-			a[2*k] = re->v(i,i0)*ff;	a[2*k+1] = im->v(i,i0)*ff;
-		}
-		mgl_fft(a, 1, 2*dn, t->v, t->w[t->id], false);
-		for(k=0;k<dd;k++)
+		double *a = new double[4*dn], ff;
+		void *w = mgl_fft_alloc_thr(2*dn);
+#pragma omp for nowait
+		for(long ii=t->id;ii<t->n;ii+=mglNumThr)
 		{
-			i0 = i+mx*(j+mz*k);
-			d[i0+mx*mz*dd] = hypot(a[4*k],a[4*k+1])/dn;
-			d[i0] = hypot(a[4*k+2*dn],a[4*k+2*dn+1])/dn;
+			register long i = ii%mx, j = ii/mx, i0;
+			for(long k=0;k<2*dn;k++)
+			{
+				i0 = k-dd+j*dn;		ff = 1;
+				if(i0<0)	i0=0;	else if(i0>=ny)	i0=ny-1;
+				if(k<dd)
+				{	ff = 0.5*(k-dd/2.)/dd;		ff=0.5+ff*(3-ff*ff);	}
+				else if(k>=dn+dd)
+				{	ff = 0.5*(k-3.5*dd)/dd;	ff=0.5-ff*(3-ff*ff);	}
+				a[2*k] = re->v(i,i0)*ff;	a[2*k+1] = im->v(i,i0)*ff;
+			}
+			mgl_fft(a, 1, 2*dn, t->v, w, false);
+			for(long k=0;k<dd;k++)
+			{
+				i0 = i+mx*(j+mz*k);
+				d[i0+mx*mz*dd] = hypot(a[4*k],a[4*k+1])/dn;
+				d[i0] = hypot(a[4*k+2*dn],a[4*k+2*dn+1])/dn;
+			}
 		}
+		mgl_fft_free_thr(w);	delete []a;
 	}
 	return 0;
 }
 MGL_NO_EXPORT void* mgl_stfa2(void *par)
 {
 	mglThreadT *t=(mglThreadT *)par;
-	register long i,j,k,ii,i0,mx=t->p[0],my=t->p[1],mz=t->p[2],dn=t->p[3],dd=dn/2,nx=t->p[4];
-	double *a = t->b+4*dn*t->id,ff;
+	long mx=t->p[0],my=t->p[1],dn=t->p[3],dd=dn/2,nx=t->p[4];
 	mreal *d = (mreal*)t->a;
 	HCDT re = (HCDT)t->re, im = (HCDT)t->im;
-	for(ii=t->id;ii<t->n;ii+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel
+#endif
 	{
-		i = ii%my;	j = ii/mx;
-		for(k=0;k<2*dn;k++)
-		{
-			i0 = k-dd+i*dn;		ff = 1;
-			if(i0<0)	i0=0;	else if(i0>=nx)	i0=nx-1;
-			if(k<dd)
-			{	ff = 0.5*(k-dd/2.)/dd;	ff=0.5+ff*(3-ff*ff);	}
-			else if(k>=3*dd)
-			{	ff = 0.5*(k-3.5*dd)/dd;	ff=0.5-ff*(3-ff*ff);	}
-			a[2*k] = re->v(i0,j)*ff;	a[2*k+1] = im->v(i0,j)*ff;
-		}
-		mgl_fft(a, 1, 2*dn, t->v, t->w[t->id], false);
-		for(k=0;k<dd;k++)
+		double *a = new double[4*dn], ff;
+		void *w = mgl_fft_alloc_thr(2*dn);
+#pragma omp for nowait
+		for(long ii=t->id;ii<t->n;ii+=mglNumThr)
 		{
-			i0 = i+my*(k+mx*j);
-			d[i0+dd*my] = hypot(a[4*k],a[4*k+1])/dn;
-			d[i0] = hypot(a[4*k+2*dn],a[4*k+2*dn+1])/dn;
+			register long i = ii%my, j = ii/my, i0;
+			for(long k=0;k<2*dn;k++)
+			{
+				i0 = k-dd+i*dn;		ff = 1;
+				if(i0<0)	i0=0;	else if(i0>=nx)	i0=nx-1;
+				if(k<dd)
+				{	ff = 0.5*(k-dd/2.)/dd;	ff=0.5+ff*(3-ff*ff);	}
+				else if(k>=3*dd)
+				{	ff = 0.5*(k-3.5*dd)/dd;	ff=0.5-ff*(3-ff*ff);	}
+				a[2*k] = re->v(i0,j)*ff;	a[2*k+1] = im->v(i0,j)*ff;
+			}
+			mgl_fft(a, 1, 2*dn, t->v, w, false);
+			for(long k=0;k<dd;k++)
+			{
+				i0 = i+my*(k+mx*j);
+				d[i0+dd*my] = hypot(a[4*k],a[4*k+1])/dn;
+				d[i0] = hypot(a[4*k+2*dn],a[4*k+2*dn+1])/dn;
+			}
 		}
+		mgl_fft_free_thr(w);	delete []a;
 	}
 	return 0;
 }
 HMDT MGL_EXPORT mgl_data_stfa(HCDT re, HCDT im, long dn, char dir)
 {
-	mglData *d=new mglData;
-	if(dn<2)	return d;
+	if(dn<2)	return 0;
 	dn = 2*(dn/2);
 	long nx = re->GetNx(), ny = re->GetNy();
-	if(nx*ny!=im->GetNx()*im->GetNy())	return d;
-	register long i,j,k,i0,dd=dn/2;
-	if(mglNumThr<1)	mgl_set_num_thr(0);	// manually set number of threads
-	double *a = new double[4*dn*mglNumThr],ff;
-	void **ws=new void*[mglNumThr], *wt = mgl_fft_alloc(2*dn,ws,mglNumThr);
+	if(nx*ny!=im->GetNx()*im->GetNy())	return 0;
+	void *wt = mgl_fft_alloc(2*dn,0,0);
 	long mx,my,mz;
+	mglData *d=new mglData;
 	if(dir=='y')
 	{
 		mx = nx;	my = dn;	mz = ny/dn;
 		mgl_data_create(d, mx, mz, my);
 		long par[5]={mx,my,mz,dn,ny};
-		mglStartThreadT(mgl_stfa1,mx*mz,d->a,a,wt,ws,par,re,im);
+		mglStartThreadT(mgl_stfa1,mx*mz,d->a,0,wt,0,par,re,im);
 	}
 	else
 	{
 		mx = dn;	my = nx/dn;	mz = ny;
 		mgl_data_create(d, my, mx, mz);
 		long par[5]={mx,my,mz,dn,nx};
-		mglStartThreadT(mgl_stfa2,my*mz,d->a,a,wt,ws,par,re,im);
+		mglStartThreadT(mgl_stfa2,my*mz,d->a,0,wt,0,par,re,im);
 	}
-	mgl_fft_free(wt,ws,mglNumThr);
-	delete []ws;	delete []a;
+	mgl_fft_free(wt,0,0);
 	return d;
 }
 //-----------------------------------------------------------------------------
 MGL_NO_EXPORT void* mgl_sinx(void *par)
 {
 	mglThreadT *t=(mglThreadT *)par;
-	register long i,j,k,nx=t->p[0];
-	double *b = t->b+2*nx*t->id, f=sqrt(2./nx);
+	long nx=t->p[0];
 	mreal *a = (mreal*)t->a;
-	for(i=t->id;i<t->n;i+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel
+#endif
 	{
-		k = i*nx;	memset(b,0,2*nx*sizeof(double));
-		for(j=1;j<nx;j++)	b[2*j]=sin(M_PI*j/nx)*(a[j+k]+a[nx-j+k])+(a[j+k]-a[nx-j+k])*0.5;
-		mgl_fft(b,1,nx,t->v,t->w[t->id],false);
-		a[k]=0;	a[k+1]=b[0]*f/2;	// fill sinfft
-		for(j=1;j<nx/2;j++)
+		double *b = new double[2*nx], f=sqrt(2./nx);
+		void *w = mgl_fft_alloc_thr(nx);
+#pragma omp for nowait
+		for(long i=t->id;i<t->n;i+=mglNumThr)
 		{
-			a[k+2*j] = -b[2*j+1]*f;
-			a[k+2*j+1] = a[k+2*j-1]+b[2*j]*f;
+			register long k = i*nx;	memset(b,0,2*nx*sizeof(double));
+			for(long j=1;j<nx;j++)	b[2*j]=sin(M_PI*j/nx)*(a[j+k]+a[nx-j+k])+(a[j+k]-a[nx-j+k])*0.5;
+			mgl_fft(b,1,nx,t->v,w,false);
+			a[k]=0;	a[k+1]=b[0]*f/2;	// fill sinfft
+			for(long j=1;j<nx/2;j++)
+			{
+				a[k+2*j] = -b[2*j+1]*f;
+				a[k+2*j+1] = a[k+2*j-1]+b[2*j]*f;
+			}
+			if(nx%2)	a[nx-1] = -b[nx]*f;
 		}
-		if(nx%2)	a[nx-1] = -b[nx]*f;
+		mgl_fft_free_thr(w);	delete []b;
 	}
 	return 0;
 }
 MGL_NO_EXPORT void* mgl_siny(void *par)
 {
 	mglThreadT *t=(mglThreadT *)par;
-	register long ii,i,j,k,nx=t->p[0],ny=t->p[1],nz=t->p[2];
-	double *b = t->b+2*ny*t->id, f=sqrt(2./ny);
+	long nx=t->p[0],ny=t->p[1];
 	mreal *a = (mreal*)t->a;
-	for(ii=t->id;ii<t->n;ii+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel
+#endif
 	{
-		i = ii%nx;	k = ii/nx;	memset(b,0,2*ny*sizeof(double));
-		for(j=1;j<ny;j++)	b[2*j]=sin(M_PI*j/ny)*(a[i+nx*(ny*k+j)]+a[i+nx*(ny*k+ny-j)])+(a[i+nx*(ny*k+j)]-a[i+nx*(ny*k+ny-j)])*0.5;
-		mgl_fft(b,1,ny,t->v,t->w[t->id],false);
-		a[i+nx*ny*k]=0;	a[i+nx*(ny*k+1)]=b[0]*f/2;	// fill sinfft
-		for(j=1;j<ny/2;j++)
+		double *b = new double[2*ny], f=sqrt(2./ny);
+		void *w = mgl_fft_alloc_thr(ny);
+#pragma omp for nowait
+		for(long ii=t->id;ii<t->n;ii+=mglNumThr)
 		{
-			a[i+nx*(ny*k+2*j)] = -b[2*j+1]*f;
-			a[i+nx*(ny*k+2*j+1)] = a[i+nx*(ny*k+2*j-1)]+b[2*j]*f;
+			register long i = ii%nx, k = ii/nx;	memset(b,0,2*ny*sizeof(double));
+			for(long j=1;j<ny;j++)	b[2*j]=sin(M_PI*j/ny)*(a[i+nx*(ny*k+j)]+a[i+nx*(ny*k+ny-j)])+(a[i+nx*(ny*k+j)]-a[i+nx*(ny*k+ny-j)])*0.5;
+			mgl_fft(b,1,ny,t->v,w,false);
+			a[i+nx*ny*k]=0;	a[i+nx*(ny*k+1)]=b[0]*f/2;	// fill sinfft
+			for(long j=1;j<ny/2;j++)
+			{
+				a[i+nx*(ny*k+2*j)] = -b[2*j+1]*f;
+				a[i+nx*(ny*k+2*j+1)] = a[i+nx*(ny*k+2*j-1)]+b[2*j]*f;
+			}
+			if(ny%2)	a[i+nx*(ny*k+ny-1)] = -b[ny]*f;
 		}
-		if(ny%2)	a[i+nx*(ny*k+ny-1)] = -b[ny]*f;
+		mgl_fft_free_thr(w);	delete []b;
 	}
 	return 0;
 }
 MGL_NO_EXPORT void* mgl_sinz(void *par)
 {
 	mglThreadT *t=(mglThreadT *)par;
-	register long i,j,nx=t->p[0],ny=t->p[1],nz=t->p[2],k=nx*ny;
-	double *b = t->b+2*nz*t->id, f=sqrt(2./nz);
+	long nx=t->p[0],ny=t->p[1],nz=t->p[2],k=nx*ny;
 	mreal *a = (mreal*)t->a;
-	for(i=t->id;i<t->n;i+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel
+#endif
 	{
-		memset(b,0,2*nz*sizeof(double));
-		for(j=1;j<nz;j++)	b[2*j]=sin(M_PI*j/nz)*(a[i+k*j]+a[i+k*(nz-j)])+(a[i+k*j]-a[i+k*(nz-j)])*0.5;
-		mgl_fft(b,1,nz,t->v,t->w[t->id],false);
-		a[i]=0;	a[i+k]=b[0]*f/2;	// fill sinfft
-		for(j=1;j<nz/2;j++)
+		double *b = new double[2*nz], f=sqrt(2./nz);
+		void *w = mgl_fft_alloc_thr(nz);
+#pragma omp for nowait
+		for(long i=t->id;i<t->n;i+=mglNumThr)
 		{
-			a[i+k*2*j] = -b[2*j+1]*f;
-			a[i+k*(2*j+1)] = a[i+k*(2*j-1)]+b[2*j]*f;
+			memset(b,0,2*nz*sizeof(double));
+			for(long j=1;j<nz;j++)	b[2*j]=sin(M_PI*j/nz)*(a[i+k*j]+a[i+k*(nz-j)])+(a[i+k*j]-a[i+k*(nz-j)])*0.5;
+			mgl_fft(b,1,nz,t->v,w,false);
+			a[i]=0;	a[i+k]=b[0]*f/2;	// fill sinfft
+			for(long j=1;j<nz/2;j++)
+			{
+				a[i+k*2*j] = -b[2*j+1]*f;
+				a[i+k*(2*j+1)] = a[i+k*(2*j-1)]+b[2*j]*f;
+			}
+			if(nz%2)	a[i+k*nz-k] = -b[nz]*f;
 		}
-		if(nz%2)	a[i+k*nz-k] = -b[nz]*f;
+		mgl_fft_free_thr(w);	delete []b;
 	}
 	return 0;
 }
 void MGL_EXPORT mgl_data_sinfft(HMDT d, const char *dir)	// use DST-1
 {
 	if(!dir || *dir==0)	return;
-	double *b = 0;
-	if(mglNumThr<1)	mgl_set_num_thr(0);	// manually set number of threads
-	void *wt=0, **ws=new void*[mglNumThr];
-	long nx=d->nx, ny=d->ny, nz=d->nz;
-	long par[3]={nx,ny,nz}, i;
+	bool clear=false;
+	void *wt=0;
+	long nx=d->nx, ny=d->ny, nz=d->nz, par[3]={nx,ny,nz};
 	if(strchr(dir,'x') && nx>1)
 	{
-		wt = mgl_fft_alloc(nx,ws,mglNumThr);
-		b = new double[2*nx*mglNumThr];
-		mglStartThreadT(mgl_sinx,ny*nz,d->a,b,wt,ws,par);
+		if(mgl_fft_data.wnx==nx)	wt = mgl_fft_data.wtx;
+		else	{	clear = true;	wt = mgl_fft_alloc(nx,0,0);	}
+		mglStartThreadT(mgl_sinx,ny*nz,d->a,0,wt,0,par);
+		if(mgl_fft_data.wnx==0)
+		{	mgl_fft_data.wtx = wt;	clear = false;	mgl_fft_data.wnx=nx;	}
 	}
 	if(strchr(dir,'y') && ny>1)
 	{
-		wt = mgl_fft_alloc(ny,ws,mglNumThr);
-		b = new double[2*ny*mglNumThr];
-		mglStartThreadT(mgl_siny,nx*nz,d->a,b,wt,ws,par);
+		if(mgl_fft_data.wny==ny)	wt = mgl_fft_data.wty;
+		else	{	clear = true;	wt = mgl_fft_alloc(ny,0,0);	}
+		mglStartThreadT(mgl_siny,nx*nz,d->a,0,wt,0,par);
+		if(mgl_fft_data.wny==0)
+		{	mgl_fft_data.wty = wt;	clear = false;	mgl_fft_data.wny=ny;	}
 	}
 	if(strchr(dir,'z') && nz>1)
 	{
-		wt = mgl_fft_alloc(nz,ws,mglNumThr);
-		b = new double[2*nz*mglNumThr];
-		mglStartThreadT(mgl_sinz,nx*ny,d->a,b,wt,ws,par);
+		if(mgl_fft_data.wnz==nz)	wt = mgl_fft_data.wtz;
+		else	{	clear = true;	wt = mgl_fft_alloc(nz,0,0);	}
+		mglStartThreadT(mgl_sinz,nx*ny,d->a,0,wt,0,par);
+		if(mgl_fft_data.wnz==0)
+		{	mgl_fft_data.wtz = wt;	clear = false;	mgl_fft_data.wnz=nz;	}
 	}
-	if(b)	{	mgl_fft_free(wt,ws,mglNumThr);	delete []b;	}
-	delete []ws;
+	if(clear)	mgl_fft_free(wt,0,0);
 }
 //-----------------------------------------------------------------------------
 MGL_NO_EXPORT void* mgl_cosx(void *par)
 {
 	mglThreadT *t=(mglThreadT *)par;
-	register long i,j,k,nx=t->p[0],nn=nx-1;
-	double *b = t->b+2*nx*t->id, f=sqrt(2./nn);
+	long nx=t->p[0],nn=nx-1;
 	mreal *a = (mreal*)t->a;
-	for(i=t->id;i<t->n;i+=mglNumThr)
-	{
-		k = i*nx;	memset(b,0,2*nx*sizeof(double));
-		for(j=0;j<nn;j++)	b[2*j]=(a[j+k]+a[nn-j+k])*0.5-sin(M_PI*j/nn)*(a[j+k]-a[nn-j+k]);
-		mgl_fft(b,1,nn,t->v,t->w[t->id],false);
-		double f1=0.5*(a[k]-a[nn+k]), s=-1;
-		a[nn+k]=0.5*(a[k]+a[nn+k]*(nn%2?-1:1));
-		for(j=1;j<nn;j++)
-		{
-			f1 += a[j+k]*cos(M_PI*j/nn);
-			a[nn+k] += a[j+k]*s;	s = -s;
-		}
-		a[k]=b[0]*f;	a[1+k]=f1*f;	a[nn+k]*=f;	// fill cosfft
-		for(j=1;j<nn/2;j++)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel
+#endif
+	{
+		double *b = new double[2*nx], f=sqrt(2./nn);
+		void *w = mgl_fft_alloc_thr(nn);
+#pragma omp for nowait
+		for(long i=t->id;i<t->n;i+=mglNumThr)
 		{
-			a[2*j+k] = b[2*j]*f;
-			a[2*j+1+k] = a[2*j-1+k]-b[2*j+1]*f;
+			register long k = i*nx;	memset(b,0,2*nx*sizeof(double));
+			for(long j=0;j<nn;j++)	b[2*j]=(a[j+k]+a[nn-j+k])*0.5-sin(M_PI*j/nn)*(a[j+k]-a[nn-j+k]);
+			mgl_fft(b,1,nn,t->v,w,false);
+			double f1=0.5*(a[k]-a[nn+k]), s=-1;
+			a[nn+k]=0.5*(a[k]+a[nn+k]*(nn%2?-1:1));
+			for(long j=1;j<nn;j++)
+			{
+				f1 += a[j+k]*cos(M_PI*j/nn);
+				a[nn+k] += a[j+k]*s;	s = -s;
+			}
+			a[k]=b[0]*f;	a[1+k]=f1*f;	a[nn+k]*=f;	// fill cosfft
+			for(long j=1;j<nn/2;j++)
+			{
+				a[2*j+k] = b[2*j]*f;
+				a[2*j+1+k] = a[2*j-1+k]-b[2*j+1]*f;
+			}
+			if(nn%2)	a[nn-1+k] = b[nn-1]*f;
 		}
-		if(nn%2)	a[nn-1+k] = b[nn-1]*f;
+		mgl_fft_free_thr(w);
+		delete []b;
 	}
 	return 0;
 }
 MGL_NO_EXPORT void* mgl_cosy(void *par)
 {
 	mglThreadT *t=(mglThreadT *)par;
-	register long ii,i,j,k,nx=t->p[0],ny=t->p[1],nz=t->p[2],nn=ny-1;
-	double *b = t->b+2*ny*t->id, f=sqrt(2./nn);
+	long nx=t->p[0],ny=t->p[1],nn=ny-1;
 	mreal *a = (mreal*)t->a;
-	for(ii=t->id;ii<t->n;ii+=mglNumThr)
-	{
-		i = ii%nx;	k = ii/nx;	memset(b,0,2*ny*sizeof(double));
-		for(j=0;j<nn;j++)	b[2*j]=(a[i+nx*(ny*k+j)]+a[i+nx*(ny*k+nn-j)])*0.5-sin(M_PI*j/nn)*(a[i+nx*(ny*k+j)]-a[i+nx*(ny*k+nn-j)]);
-		mgl_fft(b,1,nn,t->v,t->w[t->id],false);
-		double f1=0.5*(a[i+nx*ny*k]-a[i+nx*(ny*k+nn)]), s=-1;
-		a[i+nx*(ny*k+nn)]=0.5*(a[i+nx*ny*k]+a[i+nx*(ny*k+nn)]*(nn%2?-1:1));
-		for(j=1;j<nn;j++)
-		{
-			f1 += a[i+nx*(ny*k+j)]*cos(M_PI*j/nn);
-			a[i+nx*(ny*k+nn)] += a[i+nx*(ny*k+j)]*s;	s = -s;
-		}
-		a[i+nx*ny*k]=b[0]*f;	a[i+nx*(ny*k+1)]=f1*f;	a[i+nx*(ny*k+nn)]*=f;	// fill cosfft
-		for(j=1;j<nn/2;j++)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel
+#endif
+	{
+		double *b = new double[2*ny], f=sqrt(2./nn);
+		void *w = mgl_fft_alloc_thr(nn);
+#pragma omp for nowait
+		for(long ii=t->id;ii<t->n;ii+=mglNumThr)
 		{
-			a[i+nx*(ny*k+2*j)] = b[2*j]*f;
-			a[i+nx*(ny*k+2*j+1)] = a[i+nx*(ny*k+2*j-1)]-b[2*j+1]*f;
+			register long i = ii%nx, k = ii/nx;	memset(b,0,2*ny*sizeof(double));
+			for(long j=0;j<nn;j++)	b[2*j]=(a[i+nx*(ny*k+j)]+a[i+nx*(ny*k+nn-j)])*0.5-sin(M_PI*j/nn)*(a[i+nx*(ny*k+j)]-a[i+nx*(ny*k+nn-j)]);
+			mgl_fft(b,1,nn,t->v,w,false);
+			double f1=0.5*(a[i+nx*ny*k]-a[i+nx*(ny*k+nn)]), s=-1;
+			a[i+nx*(ny*k+nn)]=0.5*(a[i+nx*ny*k]+a[i+nx*(ny*k+nn)]*(nn%2?-1:1));
+			for(long j=1;j<nn;j++)
+			{
+				f1 += a[i+nx*(ny*k+j)]*cos(M_PI*j/nn);
+				a[i+nx*(ny*k+nn)] += a[i+nx*(ny*k+j)]*s;	s = -s;
+			}
+			a[i+nx*ny*k]=b[0]*f;	a[i+nx*(ny*k+1)]=f1*f;	a[i+nx*(ny*k+nn)]*=f;	// fill cosfft
+			for(long j=1;j<nn/2;j++)
+			{
+				a[i+nx*(ny*k+2*j)] = b[2*j]*f;
+				a[i+nx*(ny*k+2*j+1)] = a[i+nx*(ny*k+2*j-1)]-b[2*j+1]*f;
+			}
+			if(nn%2)	a[i+nx*(ny*k+nn-1)] = b[nn-1]*f;
 		}
-		if(nn%2)	a[i+nx*(ny*k+nn-1)] = b[nn-1]*f;
+		mgl_fft_free_thr(w);
+		delete []b;
 	}
 	return 0;
 }
 MGL_NO_EXPORT void* mgl_cosz(void *par)
 {
 	mglThreadT *t=(mglThreadT *)par;
-	register long i,j,nx=t->p[0],ny=t->p[1],nz=t->p[2],k=nx*ny,nn=nz-1;
-	double *b = t->b+2*nz*t->id, f=sqrt(2./nn);
+	long nx=t->p[0],ny=t->p[1],nz=t->p[2],k=nx*ny,nn=nz-1;
 	mreal *a = (mreal*)t->a;
-	for(i=t->id;i<t->n;i+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel
+#endif
 	{
-		memset(b,0,2*nz*sizeof(double));
-
-		for(j=0;j<nn;j++)	b[2*j]=(a[i+k*j]+a[i+k*(nn-j)])*0.5-sin(M_PI*j/nn)*(a[i+k*j]-a[i+k*(nn-j)]);
-		mgl_fft(b,1,nn,t->v,t->w[t->id],false);
-		double f1=0.5*(a[i]-a[i+k*nn]), s=-1;
-		a[i+k*nn]=0.5*(a[i]+a[i+k*nn]*(nn%2?-1:1));
-		for(j=1;j<nn;j++)
+		double *b = new double[2*nz], f=sqrt(2./nn);
+		void *w = mgl_fft_alloc_thr(nn);
+#pragma omp for nowait
+		for(long i=t->id;i<t->n;i+=mglNumThr)
 		{
-			f1 += a[i+k*j]*cos(M_PI*j/nn);
-			a[i+k*nn] += a[i+k*j]*s;	s = -s;
+			memset(b,0,2*nz*sizeof(double));
+			for(long j=0;j<nn;j++)	b[2*j]=(a[i+k*j]+a[i+k*(nn-j)])*0.5-sin(M_PI*j/nn)*(a[i+k*j]-a[i+k*(nn-j)]);
+			mgl_fft(b,1,nn,t->v,w,false);
+			double f1=0.5*(a[i]-a[i+k*nn]), s=-1;
+			a[i+k*nn]=0.5*(a[i]+a[i+k*nn]*(nn%2?-1:1));
+			for(long j=1;j<nn;j++)
+			{
+				f1 += a[i+k*j]*cos(M_PI*j/nn);
+				a[i+k*nn] += a[i+k*j]*s;	s = -s;
+			}
+			a[i]=b[0]*f;	a[i+k]=f1*f;	a[i+k*nn]*=f;	// fill cosfft
+			for(long j=1;j<nn/2;j++)
+			{
+				a[i+k*2*j] = b[2*j]*f;
+				a[i+k*2*j+k] = a[i+k*2*j-k]-b[2*j+1]*f;
+			}
+			if(nn%2)	a[i+k*nn-k] = b[nn-1]*f;
 		}
-		a[i]=b[0]*f;	a[i+k]=f1*f;	a[i+k*nn]*=f;	// fill cosfft
-		for(j=1;j<nn/2;j++)
-		{
-			a[i+k*2*j] = b[2*j]*f;
-			a[i+k*2*j+k] = a[i+k*2*j-k]-b[2*j+1]*f;
-		}
-		if(nn%2)	a[i+k*nn-k] = b[nn-1]*f;
+		mgl_fft_free_thr(w);
+		delete []b;
 	}
 	return 0;
 }
 void MGL_EXPORT mgl_data_cosfft(HMDT d, const char *dir)
 {
 	if(!dir || *dir==0)	return;
-	double *b = 0;
-	if(mglNumThr<1)	mgl_set_num_thr(0);	// manually set number of threads
-	void *wt=0, **ws=new void*[mglNumThr];
-	long nx=d->nx, ny=d->ny, nz=d->nz;
-	long par[3]={nx,ny,nz}, i;
+	bool clear=false;
+	void *wt=0;
+	long nx=d->nx, ny=d->ny, nz=d->nz, par[3]={nx,ny,nz};
 	if(strchr(dir,'x') && nx>1)
 	{
-		wt = mgl_fft_alloc(nx-1,ws,mglNumThr);
-		b = new double[2*nx*mglNumThr];
-		mglStartThreadT(mgl_cosx,ny*nz,d->a,b,wt,ws,par);
+		if(mgl_fft_data.wnx==nx-1)	wt = mgl_fft_data.wtx;
+		else	{	clear = true;	wt = mgl_fft_alloc(nx-1,0,0);	}
+		mglStartThreadT(mgl_cosx,ny*nz,d->a,0,wt,0,par);
+		if(mgl_fft_data.wnx==0)
+		{	mgl_fft_data.wtx = wt;	clear = false;	mgl_fft_data.wnx=nx-1;	}
 	}
 	if(strchr(dir,'y') && ny>1)
 	{
-		wt = mgl_fft_alloc(ny-1,ws,mglNumThr);
-		b = new double[2*ny*mglNumThr];
-		mglStartThreadT(mgl_cosy,nx*nz,d->a,b,wt,ws,par);
+		if(mgl_fft_data.wny==ny-1)	wt = mgl_fft_data.wty;
+		else	{	clear = true;	wt = mgl_fft_alloc(ny-1,0,0);	}
+		mglStartThreadT(mgl_cosy,nx*nz,d->a,0,wt,0,par);
+		if(mgl_fft_data.wny==0)
+		{	mgl_fft_data.wty = wt;	clear = false;	mgl_fft_data.wny=ny-1;	}
 	}
 	if(strchr(dir,'z') && nz>1)
 	{
-		wt = mgl_fft_alloc(nz-1,ws,mglNumThr);
-		b = new double[2*nz*mglNumThr];
-		mglStartThreadT(mgl_cosz,nx*ny,d->a,b,wt,ws,par);
+		if(mgl_fft_data.wnz==nz-1)	wt = mgl_fft_data.wtz;
+		else	{	clear = true;	wt = mgl_fft_alloc(nz-1,0,0);	}
+		mglStartThreadT(mgl_cosz,nx*ny,d->a,0,wt,0,par);
+		if(mgl_fft_data.wnz==0)
+		{	mgl_fft_data.wtz = wt;	clear = false;	mgl_fft_data.wnz=nz-1;	}
 	}
-	if(b)	{	mgl_fft_free(wt,ws,mglNumThr);	delete []b;	}
-	delete []ws;
+	if(clear)	mgl_fft_free(wt,0,0);
 }
 //-----------------------------------------------------------------------------
 HMDT MGL_EXPORT mgl_transform_a(HCDT am, HCDT ph, const char *tr)
 {
 	long nx = am->GetNx(), ny = am->GetNy(), nz = am->GetNz();
 	if(nx*ny*nz != ph->GetNx()*ph->GetNy()*ph->GetNz() || !tr || tr[0]==0)
-		return (new mglData);
+		return 0;
 	mglData re(nx,ny,nz), im(nx,ny,nz);
 	const mglData *da=dynamic_cast<const mglData *>(am);
 	const mglData *dp=dynamic_cast<const mglData *>(ph);
-	if(da && dp)	for(long i=0;i<nx*ny*nz;i++)
-	{	re.a[i] = da->a[i]*cos(dp->a[i]);
-		im.a[i] = da->a[i]*sin(dp->a[i]);	}
-	else	for(long i=0;i<nx*ny*nz;i++)
-	{	re.a[i] = am->vthr(i)*cos(ph->vthr(i));
-		im.a[i] = am->vthr(i)*sin(ph->vthr(i));	}
+	if(da && dp)
+#pragma omp parallel for
+		for(long i=0;i<nx*ny*nz;i++)
+		{	re.a[i] = da->a[i]*cos(dp->a[i]);
+			im.a[i] = da->a[i]*sin(dp->a[i]);	}
+	else
+#pragma omp parallel for
+		for(long i=0;i<nx*ny*nz;i++)
+		{	re.a[i] = am->vthr(i)*cos(ph->vthr(i));
+			im.a[i] = am->vthr(i)*sin(ph->vthr(i));	}
 	return mgl_transform(&re, &im, tr);
 }
 //-----------------------------------------------------------------------------
@@ -600,7 +784,7 @@ HMDT MGL_EXPORT mgl_transform(HCDT re, HCDT im, const char *tr)
 	if(!tr || *tr==0)	return 0;
 	long nx = re->GetNx(), ny = re->GetNy(), nz = re->GetNz();
 	if(nx*ny*nz != im->GetNx()*im->GetNy()*im->GetNz() || !tr || tr[0]==0)
-		return (new mglData);
+		return 0;
 	mglData rr(re),ii(im);
 	if(strchr(tr,'i') && strchr(tr,'f'))	// general case
 	{
@@ -646,8 +830,8 @@ HMDT MGL_EXPORT mgl_transform(HCDT re, HCDT im, const char *tr)
 		if(tr[2]=='h')	{	rr.Hankel("z");	ii.Hankel("z");	}
 	}
 	mglData *d = new mglData(nx, ny, nz);
-	register long i;
-	for(i=0;i<nx*ny*nz;i++)	d->a[i] = hypot(rr.a[i],ii.a[i]);
+#pragma omp parallel for
+	for(long i=0;i<nx*ny*nz;i++)	d->a[i] = hypot(rr.a[i],ii.a[i]);
 	return d;
 }
 //-----------------------------------------------------------------------------
@@ -667,88 +851,114 @@ void MGL_EXPORT mgl_data_envelop_(uintptr_t *d, const char *dir, int)
 MGL_NO_EXPORT void* mgl_chnkx(void *par)
 {
 	mglThreadT *t=(mglThreadT *)par;
-	register long i,j,nx=t->p[0];
-	double *b = t->b+3*nx*t->id;
+	long nx=t->p[0];
 	dual *a = (dual*)t->a;
 	const gsl_dht *dht = (const gsl_dht*)t->v;
-
 	double mm = gsl_sf_bessel_zero_J0(nx+1);
-	for(i=t->id;i<t->n;i+=mglNumThr)
+
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel
+#endif
 	{
-		for(j=0;j<nx;j++)	b[j] = real(a[j+nx*i]);
-		gsl_dht_apply(dht,b,b+nx);
-		for(j=0;j<nx;j++)	b[j] = imag(a[j+nx*i]);
-		gsl_dht_apply(dht,b,b+2*nx);
-		for(j=0;j<nx;j++)	a[j+nx*i] = dual(b[j+nx],b[j+2*nx])*mreal(mm);
+		double *b = new double[3*nx];
+#pragma omp for nowait
+		for(long i=t->id;i<t->n;i+=mglNumThr)
+		{
+			for(long j=0;j<nx;j++)	b[j] = real(a[j+nx*i]);
+			gsl_dht_apply(dht,b,b+nx);
+			for(long j=0;j<nx;j++)	b[j] = imag(a[j+nx*i]);
+			gsl_dht_apply(dht,b,b+2*nx);
+			for(long j=0;j<nx;j++)	a[j+nx*i] = dual(b[j+nx]*mm,b[j+2*nx]*mm);
+		}
+		delete []b;
 	}
 	return 0;
 }
 MGL_NO_EXPORT void* mgl_chnky(void *par)
 {
 	mglThreadT *t=(mglThreadT *)par;
-	register long ii,i,j,k,nx=t->p[0],ny=t->p[1];
-	double *b = t->b+3*ny*t->id;
+	long nx=t->p[0],ny=t->p[1];
 	dual *a = (dual*)t->a;
 	const gsl_dht *dht = (const gsl_dht*)t->v;
-	
 	double mm = gsl_sf_bessel_zero_J0(ny+1);
-	for(ii=t->id;ii<t->n;ii+=mglNumThr)
+
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel
+#endif
 	{
-		i = ii%nx;	k = ii/nx;
-		for(j=0;j<ny;j++)	b[j] = real(a[i+nx*(j+ny*k)]);
-		gsl_dht_apply(dht,b,b+ny);
-		for(j=0;j<ny;j++)	b[j] = imag(a[i+nx*(j+ny*k)]);
-		gsl_dht_apply(dht,b,b+2*ny);
-		for(j=0;j<ny;j++)	a[i+nx*(j+ny*k)] = dual(b[j+ny],b[j+2*ny])*mreal(mm);
+		double *b = new double[3*ny];
+#pragma omp for nowait
+		for(long ii=t->id;ii<t->n;ii+=mglNumThr)
+		{
+			register long i = ii%nx, k = ii/nx;
+			for(long j=0;j<ny;j++)	b[j] = real(a[i+nx*(j+ny*k)]);
+			gsl_dht_apply(dht,b,b+ny);
+			for(long j=0;j<ny;j++)	b[j] = imag(a[i+nx*(j+ny*k)]);
+			gsl_dht_apply(dht,b,b+2*ny);
+			for(long j=0;j<ny;j++)	a[i+nx*(j+ny*k)] = dual(b[j+ny]*mm,b[j+2*ny]*mm);
+		}
+		delete []b;
 	}
 	return 0;
 }
 MGL_NO_EXPORT void* mgl_chnkz(void *par)
 {
 	mglThreadT *t=(mglThreadT *)par;
-	register long i,j,k=t->p[0]*t->p[1],nz=t->p[2];
-	double *b = t->b+3*nz*t->id;
+	long k=t->p[0]*t->p[1],nz=t->p[2];
 	dual *a = (dual*)t->a;
 	const gsl_dht *dht = (const gsl_dht*)t->v;
-	
 	double mm = gsl_sf_bessel_zero_J0(nz+1);
-	for(i=t->id;i<t->n;i+=mglNumThr)
+
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel
+#endif
 	{
-		for(j=0;j<nz;j++)	b[j] = real(a[i+j*k]);
-		gsl_dht_apply(dht,b,b+nz);
-		for(j=0;j<nz;j++)	b[j] = imag(a[i+j*k]);
-		gsl_dht_apply(dht,b,b+2*nz);
-		for(j=0;j<nz;j++)	a[i+j*k] = dual(b[j+nz],b[j+2*nz])*mreal(mm);
+		double *b = new double[3*nz];
+#pragma omp for nowait
+		for(long i=t->id;i<t->n;i+=mglNumThr)
+		{
+			for(long j=0;j<nz;j++)	b[j] = real(a[i+j*k]);
+			gsl_dht_apply(dht,b,b+nz);
+			for(long j=0;j<nz;j++)	b[j] = imag(a[i+j*k]);
+			gsl_dht_apply(dht,b,b+2*nz);
+			for(long j=0;j<nz;j++)	a[i+j*k] = dual(b[j+nz]*mm,b[j+2*nz]*mm);
+		}
+		delete []b;
 	}
 	return 0;
 }
 void MGL_EXPORT mgl_datac_hankel(HADT d, const char *dir)
 {
 	if(!dir || *dir==0)	return;
-	if(mglNumThr<1)	mgl_set_num_thr(0);	// manually set number of threads
 	gsl_dht *dht=0;
-	double *b=0;
+	bool clear = false;
 	long nx=d->nx, ny=d->ny, nz=d->nz;
 	long par[3]={nx,ny,nz};
 	if(strchr(dir,'x') && nx>1)
 	{
-		dht = gsl_dht_new(nx,0,1);
-		b = new double[3*nx*mglNumThr];
-		mglStartThreadT(mgl_chnkx,ny*nz,d->a,b,dht,0,par);
+		if(mgl_fft_data.hnx==nx)	dht = (gsl_dht *)mgl_fft_data.htx;
+		else	{	dht = gsl_dht_new(nx,0,1);	clear = true;	}
+		mglStartThreadT(mgl_chnkx,ny*nz,d->a,0,dht,0,par);
+		if(mgl_fft_data.hnx==0)
+		{	mgl_fft_data.htx = dht;	clear = false;	mgl_fft_data.hnx=nx;	}
 	}
 	if(strchr(dir,'y') && ny>1)
 	{
-		dht = gsl_dht_new(ny,0,1);
-		b = new double[3*ny*mglNumThr];
-		mglStartThreadT(mgl_chnky,nx*nz,d->a,b,dht,0,par);
+		if(mgl_fft_data.hny==ny)	dht = (gsl_dht *)mgl_fft_data.hty;
+		else	{	dht = gsl_dht_new(ny,0,1);	clear = true;	}
+		mglStartThreadT(mgl_chnky,nx*nz,d->a,0,dht,0,par);
+		if(mgl_fft_data.hny==0)
+		{	mgl_fft_data.hty = dht;	clear = false;	mgl_fft_data.hny=ny;	}
 	}
 	if(strchr(dir,'z') && nz>1)
 	{
-		dht = gsl_dht_new(nz,0,1);
-		b = new double[3*nz*mglNumThr];
-		mglStartThreadT(mgl_chnkz,nx*ny,d->a,b,dht,0,par);
+		if(mgl_fft_data.hnz==nz)	dht = (gsl_dht *)mgl_fft_data.htz;
+		else	{	dht = gsl_dht_new(nz,0,1);	clear = true;	}
+		mglStartThreadT(mgl_chnkz,nx*ny,d->a,0,dht,0,par);
+		if(mgl_fft_data.hnz==0)
+		{	mgl_fft_data.htz = dht;	clear = false;	mgl_fft_data.hnz=nz;	}
 	}
-	if(b)	{	delete []b;	gsl_dht_free(dht);	}
+	if(clear)	gsl_dht_free(dht);
 }
 #else
 void MGL_EXPORT mgl_datac_hankel(HADT , const char *){}
@@ -761,82 +971,108 @@ void MGL_EXPORT mgl_datac_hankel_(uintptr_t *d, const char *dir,int l)
 MGL_NO_EXPORT void* mgl_hnkx(void *par)
 {
 	mglThreadT *t=(mglThreadT *)par;
-	register long i,j,nx=t->p[0];
-	double *b = t->b+2*nx*t->id;
+	long nx=t->p[0];
 	mreal *a = (mreal*)t->a;
 	const gsl_dht *dht = (const gsl_dht*)t->v;
-	
 	double mm = gsl_sf_bessel_zero_J0(nx+1);
-	for(i=t->id;i<t->n;i+=mglNumThr)
+
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel
+#endif
 	{
-		for(j=0;j<nx;j++)	b[j] = a[j+nx*i];
-		gsl_dht_apply(dht,b,b+nx);
-		for(j=0;j<nx;j++)	a[j+nx*i] = b[j+nx]*mreal(mm);
+		double *b = new double[2*nx];
+#pragma omp for nowait
+		for(long i=t->id;i<t->n;i+=mglNumThr)
+		{
+			for(long j=0;j<nx;j++)	b[j] = a[j+nx*i];
+			gsl_dht_apply(dht,b,b+nx);
+			for(long j=0;j<nx;j++)	a[j+nx*i] = b[j+nx]*mm;
+		}
+		delete []b;
 	}
 	return 0;
 }
 MGL_NO_EXPORT void* mgl_hnky(void *par)
 {
 	mglThreadT *t=(mglThreadT *)par;
-	register long ii,i,j,k,nx=t->p[0],ny=t->p[1];
-	double *b = t->b+2*ny*t->id;
+	long nx=t->p[0],ny=t->p[1];
 	mreal *a = (mreal*)t->a;
 	const gsl_dht *dht = (const gsl_dht*)t->v;
-	
 	double mm = gsl_sf_bessel_zero_J0(ny+1);
-	for(ii=t->id;ii<t->n;ii+=mglNumThr)
+
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel
+#endif
 	{
-		i = ii%nx;	k = ii/nx;
-		for(j=0;j<ny;j++)	b[j] = a[i+nx*(j+ny*k)];
-		gsl_dht_apply(dht,b,b+ny);
-		for(j=0;j<ny;j++)a[i+nx*(j+ny*k)] = b[j+ny]*mreal(mm);
+		double *b = new double[2*ny];
+#pragma omp for nowait
+		for(long ii=t->id;ii<t->n;ii+=mglNumThr)
+		{
+			register long i = ii%nx, k = ii/nx;
+			for(long j=0;j<ny;j++)	b[j] = a[i+nx*(j+ny*k)];
+			gsl_dht_apply(dht,b,b+ny);
+			for(long j=0;j<ny;j++)a[i+nx*(j+ny*k)] = b[j+ny]*mm;
+		}
+		delete []b;
 	}
 	return 0;
 }
 MGL_NO_EXPORT void* mgl_hnkz(void *par)
 {
 	mglThreadT *t=(mglThreadT *)par;
-	register long i,j,k=t->p[0]*t->p[1],nz=t->p[2];
-	double *b = t->b+2*nz*t->id;
+	long k=t->p[0]*t->p[1],nz=t->p[2];
 	mreal *a = (mreal*)t->a;
 	const gsl_dht *dht = (const gsl_dht*)t->v;
-	
 	double mm = gsl_sf_bessel_zero_J0(nz+1);
-	for(i=t->id;i<t->n;i+=mglNumThr)
+
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel
+#endif
 	{
-		for(j=0;j<nz;j++)	b[j] = a[i+j*k];
-		gsl_dht_apply(dht,b,b+nz);
-		for(j=0;j<nz;j++)	a[i+j*k] = b[j+nz]*mreal(mm);
+		double *b = new double[2*nz];
+#pragma omp for nowait
+		for(long i=t->id;i<t->n;i+=mglNumThr)
+		{
+			for(long j=0;j<nz;j++)	b[j] = a[i+j*k];
+			gsl_dht_apply(dht,b,b+nz);
+			for(long j=0;j<nz;j++)	a[i+j*k] = b[j+nz]*mm;
+		}
+		delete []b;
 	}
 	return 0;
 }
 void MGL_EXPORT mgl_data_hankel(HMDT d, const char *dir)
 {
 	if(!dir || *dir==0)	return;
-	if(mglNumThr<1)	mgl_set_num_thr(0);	// manually set number of threads
+	bool clear = false;
 	gsl_dht *dht=0;
-	double *b=0;
 	long nx=d->nx, ny=d->ny, nz=d->nz;
 	long par[3]={nx,ny,nz};
 	if(strchr(dir,'x') && nx>1)
 	{
-		dht = gsl_dht_new(nx,0,1);
-		b = new double[2*nx*mglNumThr];
-		mglStartThreadT(mgl_hnkx,ny*nz,d->a,b,dht,0,par);
+		if(mgl_fft_data.hnx==nx)	dht = (gsl_dht *)mgl_fft_data.htx;
+		else	{	dht = gsl_dht_new(nx,0,1);	clear = true;	}
+		mglStartThreadT(mgl_hnkx,ny*nz,d->a,0,dht,0,par);
+		if(mgl_fft_data.hnx==0)
+		{	mgl_fft_data.htx = dht;	clear = false;	mgl_fft_data.hnx=nx;	}
 	}
 	if(strchr(dir,'y') && ny>1)
 	{
-		dht = gsl_dht_new(ny,0,1);
-		b = new double[2*ny*mglNumThr];
-		mglStartThreadT(mgl_hnky,nx*nz,d->a,b,dht,0,par);
+		if(mgl_fft_data.hny==ny)	dht = (gsl_dht *)mgl_fft_data.hty;
+		else	{	dht = gsl_dht_new(ny,0,1);	clear = true;	}
+		mglStartThreadT(mgl_hnky,nx*nz,d->a,0,dht,0,par);
+		if(mgl_fft_data.hny==0)
+		{	mgl_fft_data.hty = dht;	clear = false;	mgl_fft_data.hny=ny;	}
 	}
 	if(strchr(dir,'z') && nz>1)
 	{
-		dht = gsl_dht_new(nz,0,1);
-		b = new double[2*nz*mglNumThr];
-		mglStartThreadT(mgl_hnkz,nx*ny,d->a,b,dht,0,par);
+		if(mgl_fft_data.hnz==nz)	dht = (gsl_dht *)mgl_fft_data.htz;
+		else	{	dht = gsl_dht_new(nz,0,1);	clear = true;	}
+		mglStartThreadT(mgl_hnkz,nx*ny,d->a,0,dht,0,par);
+		if(mgl_fft_data.hnz==0)
+		{	mgl_fft_data.htz = dht;	clear = false;	mgl_fft_data.hnz=nz;	}
 	}
-	if(b)	{	delete []b;	gsl_dht_free(dht);	}
+	if(clear)	gsl_dht_free(dht);
 }
 #else
 void MGL_EXPORT mgl_data_hankel(HMDT , const char *){}
@@ -849,23 +1085,29 @@ void MGL_EXPORT mgl_data_fill_sample(HMDT d, const char *how)
 {
 	if(!how || *how==0)	return;
 	bool xx = strchr(how,'x');
-	register long i,n=d->nx;
+	long n=d->nx;
 	mreal *aa=d->a;
 	if(strchr(how,'h'))	// Hankel
 	{
 #if MGL_HAVE_GSL
 		gsl_dht *dht = gsl_dht_new(n,0,1);
-		for(i=0;i<n;i++)
+#pragma omp parallel for
+		for(long i=0;i<n;i++)
 			aa[i] = xx ? gsl_dht_x_sample(dht, i) : gsl_dht_k_sample(dht, i);
 		gsl_dht_free(dht);
 #endif
 	}
 	else	// Fourier
 	{
-		if(xx)	for(i=0;i<n;i++)	aa[i] = mreal(2*i-n)/n;
-		else	for(i=0;i<n;i++)	aa[i] = M_PI*(i<n/2 ? i:i-n);
+		if(xx)
+#pragma omp parallel for
+			for(long i=0;i<n;i++)	aa[i] = mreal(2*i-n)/n;
+		else
+#pragma omp parallel for
+			for(long i=0;i<n;i++)	aa[i] = M_PI*(i<n/2 ? i:i-n);
 	}
-	for(i=1;i<d->ny*d->nz;i++)	memcpy(aa+i*n,aa,n*sizeof(mreal));
+#pragma omp parallel for
+	for(long i=1;i<d->ny*d->nz;i++)	memcpy(aa+i*n,aa,n*sizeof(mreal));
 }
 void MGL_EXPORT mgl_data_fill_sample_(uintptr_t *d, const char *how,int l)
 {	char *s=new char[l+1];	memcpy(s,how,l);	s[l]=0;
@@ -886,3 +1128,184 @@ void MGL_EXPORT mgl_data_sinfft_(uintptr_t *d, const char *dir,int l)
 {	char *s=new char[l+1];	memcpy(s,dir,l);	s[l]=0;
 	mgl_data_sinfft(_DT_,s);	delete []s;	}
 //-----------------------------------------------------------------------------
+MGL_NO_EXPORT void* mgl_corx(void *par)
+{
+	mglThreadT *t=(mglThreadT *)par;
+	long nx=t->p[0];
+	double *a = (double *)t->a;
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel
+#endif
+	{
+		void *w = mgl_fft_alloc_thr(nx);
+#pragma omp for nowait
+		for(long i=t->id;i<t->n;i+=mglNumThr)
+		{
+			mgl_fft(t->b+2*nx*i, 1, nx, t->v, w, false);
+			mgl_fft(a+2*nx*i, 1, nx, t->v, w, false);
+			for(long j=0;j<nx;j++)
+			{
+				register long ii = 2*j+2*nx*i;
+				register double re = t->b[ii], im = t->b[ii+1];
+				t->b[ii]   = re*a[ii] + im*a[ii+1];
+				t->b[ii+1] = im*a[ii] - re*a[ii+1];
+			}
+			mgl_fft(t->b+2*nx*i, 1, nx, t->v, w, true);
+		}
+		mgl_fft_free_thr(w);
+	}
+	return 0;
+}
+MGL_NO_EXPORT void* mgl_cory(void *par)
+{
+	mglThreadT *t=(mglThreadT *)par;
+	long nx=t->p[0],ny=t->p[1];
+	double *a = (double *)t->a;
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel
+#endif
+	{
+		void *w = mgl_fft_alloc_thr(ny);
+#pragma omp for nowait
+		for(long i=t->id;i<t->n;i+=mglNumThr)
+		{
+			register long k = 2*(i%nx)+2*nx*ny*(i/nx);
+			mgl_fft(t->b+k, nx, ny, t->v, w, false);
+			mgl_fft(a+k, nx, ny, t->v, w, false);
+			for(long j=0;j<ny;j++)
+			{
+				register long ii = 2*nx*j+k;
+				register double re = t->b[ii], im = t->b[ii+1];
+				t->b[ii]   = re*a[ii] + im*a[ii+1];
+				t->b[ii+1] = im*a[ii] - re*a[ii+1];
+			}
+			mgl_fft(t->b+k, nx, ny, t->v, w, true);
+		}
+		mgl_fft_free_thr(w);
+	}
+	return 0;
+}
+MGL_NO_EXPORT void* mgl_corz(void *par)
+{
+	mglThreadT *t=(mglThreadT *)par;
+	long nx=t->p[0],ny=t->p[1],nz=t->p[2];
+	double *a = (double *)t->a;
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel
+#endif
+	{
+		void *w = mgl_fft_alloc_thr(nz);
+#pragma omp for nowait
+		for(long i=t->id;i<t->n;i+=mglNumThr)
+		{
+			mgl_fft(t->b+2*i, nx*ny, nz, t->v, w, false);
+			mgl_fft(a+2*i, nx*ny, nz, t->v, w, false);
+			for(long j=0;j<nz;j++)
+			{
+				register long ii = 2*nx*ny*j+2*i;
+				register double re = t->b[ii], im = t->b[ii+1];
+				t->b[ii]   = re*a[ii] + im*a[ii+1];
+				t->b[ii+1] = im*a[ii] - re*a[ii+1];
+			}
+			mgl_fft(t->b+2*i, nx*ny, nz, t->v, w, true);
+		}
+		mgl_fft_free_thr(w);
+	}
+	return 0;
+}
+MGL_NO_EXPORT double *mgl_d_correl(HCDT d1, HCDT d2, const char *dir)
+{
+	if(!dir || *dir==0)	return 0;
+	long nx = d1->GetNx(), ny = d1->GetNy(), nz = d1->GetNz(), nn=nx*ny*nz;
+	if(nx*ny*nz!=d2->GetNN())	return 0;
+	void *wt=0;
+	bool clear=false;
+	long par[3]={nx,ny,nz};
+
+	double *a = new double[2*nn];	memset(a,0,2*nn*sizeof(double));
+	double *b = new double[2*nn];	memset(b,0,2*nn*sizeof(double));
+	const mglDataC *dd1 = dynamic_cast<const mglDataC *>(d1);
+	const mglDataC *dd2 = dynamic_cast<const mglDataC *>(d2);
+	const mglData *rd1 = dynamic_cast<const mglData *>(d1);
+	const mglData *rd2 = dynamic_cast<const mglData *>(d2);
+	if(dd1)
+#pragma omp parallel for
+		for(long i=0;i<nn;i++)
+		{	a[2*i] = real(dd1->a[i]);	a[2*i+1] = imag(dd1->a[i]);	}
+	else if(rd1)
+#pragma omp parallel for
+		for(long i=0;i<nn;i++)	a[2*i] = rd1->a[i];
+	else
+#pragma omp parallel for
+		for(long i=0;i<nn;i++)	a[2*i] = d1->vthr(i);
+	if(dd2)
+#pragma omp parallel for
+		for(long i=0;i<nn;i++)
+		{	b[2*i] = real(dd2->a[i]);	b[2*i+1] = imag(dd2->a[i]);	}
+	else if(rd2)
+#pragma omp parallel for
+		for(long i=0;i<nn;i++)	b[2*i] = rd2->a[i];
+	else
+#pragma omp parallel for
+		for(long i=0;i<nn;i++)	b[2*i] = d2->vthr(i);
+
+	if(strchr(dir,'x') && nx>1)
+	{
+		if(mgl_fft_data.wnx==nx)	wt = mgl_fft_data.wtx;
+		else	{	clear = true;	wt = mgl_fft_alloc(nx,0,0);	}
+		mglStartThreadT(mgl_corx,ny*nz,b,a,wt,0,par);
+		if(mgl_fft_data.wnx==0)
+		{	mgl_fft_data.wtx = wt;	clear = false;	mgl_fft_data.wnx=nx;	}
+	}
+	if(strchr(dir,'y') && ny>1)
+	{
+		if(mgl_fft_data.wny==ny)	wt = mgl_fft_data.wty;
+		else	{	clear = true;	wt = mgl_fft_alloc(ny,0,0);	}
+		mglStartThreadT(mgl_cory,nx*nz,b,a,wt,0,par);
+		if(mgl_fft_data.wny==0)
+		{	mgl_fft_data.wty = wt;	clear = false;	mgl_fft_data.wny=ny;	}
+	}
+	if(strchr(dir,'z') && nz>1)
+	{
+		if(mgl_fft_data.wnz==nz)	wt = mgl_fft_data.wtz;
+		else	{	clear = true;	wt = mgl_fft_alloc(nz,0,0);	}
+		mglStartThreadT(mgl_corz,nx*ny,b,a,wt,0,par);
+		if(mgl_fft_data.wnz==0)
+		{	mgl_fft_data.wtz = wt;	clear = false;	mgl_fft_data.wnz=nz;	}
+	}
+	if(clear)	mgl_fft_free(wt,0,0);
+	return a;
+}
+//-----------------------------------------------------------------------------
+HADT MGL_EXPORT mgl_datac_correl(HCDT d1, HCDT d2, const char *dir)
+{
+	double *a = mgl_d_correl(d1,d2,dir);
+	if(!a)	return 0;
+	const long nx = d1->GetNx(), ny = d1->GetNy(), nz = d1->GetNz();
+	mglDataC *res = new mglDataC(nx,ny,nz);
+#pragma omp parallel for
+	for(long i=0;i<nx*ny*nz;i++)	res->a[i] = dual(a[2*i], a[2*i+1]);
+	delete []a;	return res;
+}
+uintptr_t MGL_EXPORT mgl_datac_correl_(uintptr_t *d1, uintptr_t *d2, const char *dir,int l)
+{	char *s=new char[l+1];	memcpy(s,dir,l);	s[l]=0;
+	uintptr_t res = uintptr_t(mgl_datac_correl(_DA_(d1),_DA_(d2),s));
+	delete []s;		return res;	}
+//-----------------------------------------------------------------------------
+HMDT MGL_EXPORT mgl_data_correl(HCDT d1, HCDT d2, const char *dir)
+{
+	double *a = mgl_d_correl(d1,d2,dir);	// NOTE: this is not so effective but straightforward way
+	if(!a)	return 0;
+	const long nx = d1->GetNx(), ny = d1->GetNy(), nz = d1->GetNz();
+	mglData *res = new mglData(nx,ny,nz);
+#pragma omp parallel for
+	for(long i=0;i<nx*ny*nz;i++)	res->a[i] = a[2*i];
+	delete []a;	return res;
+}
+uintptr_t MGL_EXPORT mgl_data_correl_(uintptr_t *d1, uintptr_t *d2, const char *dir,int l)
+{	char *s=new char[l+1];	memcpy(s,dir,l);	s[l]=0;
+	uintptr_t res = uintptr_t(mgl_datac_correl(_DA_(d1),_DA_(d2),s));
+	delete []s;		return res;	}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
diff --git a/src/fit.cpp b/src/fit.cpp
index e126789..8a869be 100644
--- a/src/fit.cpp
+++ b/src/fit.cpp
@@ -22,6 +22,7 @@
 #include "mgl2/prim.h"
 #include "mgl2/eval.h"
 #include "mgl2/data.h"
+#include "mgl2/base.h"
 
 #if MGL_HAVE_GSL
 #include <gsl/gsl_multifit_nlin.h>
@@ -66,15 +67,18 @@ struct mglFitData
 int	mgl_fit__f (const gsl_vector *x, void *data, gsl_vector *f)
 {
 	mglFitData *fd = (mglFitData *)data;
-	register long i;
-	mreal val[MGL_VS];
-	for(i=0;i<fd->m;i++)	val[fd->var[i]-'a'] = gsl_vector_get(x,i);
-	for(i=0;i<fd->n;i++)
+#pragma omp parallel
 	{
-		val['x'-'a'] = fd->x[i];
-		val['y'-'a'] = fd->y ? fd->y[i] : 0;
-		val['z'-'a'] = fd->z ? fd->z[i] : 0;
-		gsl_vector_set (f, i, (fd->eq->Calc(val) - fd->a[i])/fd->s[i]);
+		mreal val[MGL_VS];
+		for(long i=0;i<fd->m;i++)	val[fd->var[i]-'a'] = gsl_vector_get(x,i);
+#pragma omp for
+		for(long i=0;i<fd->n;i++)
+		{
+			val['x'-'a'] = fd->x[i];
+			val['y'-'a'] = fd->y ? fd->y[i] : 0;
+			val['z'-'a'] = fd->z ? fd->z[i] : 0;
+			gsl_vector_set (f, i, (fd->eq->Calc(val) - fd->a[i])/fd->s[i]);
+		}
 	}
 	return GSL_SUCCESS;
 }
@@ -82,16 +86,19 @@ int	mgl_fit__f (const gsl_vector *x, void *data, gsl_vector *f)
 int MGL_NO_EXPORT mgl_fit__df (const gsl_vector * x, void *data, gsl_matrix * J)
 {
 	mglFitData *fd = (mglFitData *)data;
-	register long i,j;
-	mreal val[MGL_VS],s;
-	for(i=0;i<fd->m;i++)	val[fd->var[i]-'a'] = gsl_vector_get(x,i);
-	for(i=0;i<fd->n;i++)
+#pragma omp parallel
 	{
-		val['x'-'a'] = fd->x[i];	s = fd->s[i];
-		val['y'-'a'] = fd->y ? fd->y[i] : 0;
-		val['z'-'a'] = fd->z ? fd->z[i] : 0;
-		for(j=0;j<fd->m;j++)
-			gsl_matrix_set (J, i, j, fd->eq->CalcD(val, fd->var[j])/s);
+		mreal val[MGL_VS],s;
+		for(long i=0;i<fd->m;i++)	val[fd->var[i]-'a'] = gsl_vector_get(x,i);
+#pragma omp for
+		for(long i=0;i<fd->n;i++)
+		{
+			val['x'-'a'] = fd->x[i];	s = fd->s[i];
+			val['y'-'a'] = fd->y ? fd->y[i] : 0;
+			val['z'-'a'] = fd->z ? fd->z[i] : 0;
+			for(long j=0;j<fd->m;j++)
+				gsl_matrix_set (J, i, j, fd->eq->CalcD(val, fd->var[j])/s);
+		}
 	}
 	return GSL_SUCCESS;
 }
@@ -149,7 +156,8 @@ void mglPrepareFitEq(mglBase *gr,mreal chi, const char *eq, const char *var, mre
 {
 	char buf[32]="";
 	snprintf(mglFitRes,1024,"chi=%g",chi);
-	for(int i=0;i<int(strlen(var));i++)
+	size_t i,k,len=strlen(var);
+	for(i=0;i<len;i++)
 	{
 		snprintf(buf,32,", %c=%g",var[i],par[i]);
 		strcat(mglFitRes,buf);
@@ -157,7 +165,7 @@ void mglPrepareFitEq(mglBase *gr,mreal chi, const char *eq, const char *var, mre
 	gr->SetWarn(-1,mglFitRes);
 
 	memset(mglFitRes, 0, 1024);	//mglFitRes[0] = 0;
-	register long i,k,len=strlen(eq);
+	len=strlen(eq);
 	for(i=k=0;i<len;i++)
 	{
 		const char *c = strchr(var,eq[i]);
@@ -223,31 +231,49 @@ HMDT MGL_EXPORT mgl_fit_ys(HMGL gr, HCDT y, HCDT s, const char *eq, const char *
 	return mgl_fit_xys(gr,&x,y,s,eq,var,ini,0);
 }
 //-----------------------------------------------------------------------------
+void MGL_NO_EXPORT mgl_fill_fit(HMGL gr, mglData &fit, mglData &in, mglFitData &fd, const char *var, long nx, long ny, long nz, long k)
+{
+	long nn = nx*ny*nz;
+	mreal dx = nx>1?(gr->Max.x-gr->Min.x)/(nx-1):0;
+	mreal dy = ny>1?(gr->Max.y-gr->Min.y)/(ny-1):0;
+	mreal dz = nz>1?(gr->Max.z-gr->Min.z)/(nz-1):0;
+#pragma omp parallel
+	{
+		mreal val[MGL_VS];	memset(val,0,MGL_VS*sizeof(mreal));
+		for(long j=0;j<fd.m;j++)	val[var[j]-'a'] = in.a[j];
+#pragma omp for collapse(3)
+		for(long jz=0;jz<nz;jz++)	for(long jy=0;jy<ny;jy++)	for(long jx=0;jx<nx;jx++)
+		{
+			val['x'-'a'] = gr->Min.x+jx*dx;
+			if(dy)	val['y'-'a'] = gr->Min.y+jy*dy;
+			if(dz)	val['z'-'a'] = gr->Min.z+jz*dz;
+			fit.a[jx+nx*(jy+ny*jz)+k*nn] = fd.eq->Calc(val);
+		}
+	}
+}
+//-----------------------------------------------------------------------------
 HMDT MGL_EXPORT mgl_fit_xys(HMGL gr, HCDT xx, HCDT yy, HCDT ss, const char *eq, const char *var, HMDT ini, const char *opt)
 {
-	mglData *fit=new mglData;
 	long m = yy->GetNx();
-	long nn = long(0.5+gr->SaveState(opt));
+	mreal rr = gr->SaveState(opt);
+	long nn = (mgl_isnan(rr) || rr<=0) ? mglFitPnts:long(rr+0.5);
 	if(xx->GetNx()!=m)
-	{	gr->SetWarn(mglWarnDim,"Fit[S]");	return fit;	}
+	{	gr->SetWarn(mglWarnDim,"Fit[S]");	return 0;	}
 	if(m<2)
-	{	gr->SetWarn(mglWarnLow,"Fit[S]");	return fit;	}
+	{	gr->SetWarn(mglWarnLow,"Fit[S]");	return 0;	}
 	if(ss->GetNx()*ss->GetNy()*ss->GetNz() != m*yy->GetNy()*yy->GetNz())
-	{	gr->SetWarn(mglWarnDim,"Fit[S]");	return fit;	}
+	{	gr->SetWarn(mglWarnDim,"Fit[S]");	return 0;	}
 	if(!var || *var==0)
-	{	gr->SetWarn(mglWarnNull,"Fit[S]");	return fit;	}
+	{	gr->SetWarn(mglWarnNull,"Fit[S]");	return 0;	}
 
-	if(nn<mglFitPnts)	nn = mglFitPnts;
 	mglData x(xx), y(yy), s(ss);
 	mglFitData fd;
 	fd.n = m;	fd.x = x.a;		fd.y = 0;
 	fd.z = 0;	fd.a = y.a;		fd.s = s.a;
 	fd.var = var;	fd.m = strlen(var);
 	fd.eq = new mglFormula(eq);
-	mglData in(fd.m);
-	fit->Create(nn, yy->GetNy(), yy->GetNz());
-	mreal val[MGL_VS],res=-1;
-	register long j;
+	mglData in(fd.m), *fit=new mglData(nn, yy->GetNy(), yy->GetNz());
+	mreal res=-1;
 	for(long i=0;i<yy->GetNy()*yy->GetNz();i++)
 	{
 		if(ini && ini->nx>=fd.m)	in.Set(ini->a,fd.m);
@@ -255,12 +281,7 @@ HMDT MGL_EXPORT mgl_fit_xys(HMGL gr, HCDT xx, HCDT yy, HCDT ss, const char *eq,
 		fd.a = y.a+i*m;		fd.x = x.a+(i%x.ny)*m;
 		fd.s = s.a+i*m;
 		res = mgl_fit_base(&fd,in.a);
-		for(j=0;j<fd.m;j++)	val[var[j]-'a'] = in.a[j];
-		for(j=0;j<nn;j++)
-		{
-			val['x'-'a'] = gr->Min.x+j*(gr->Max.x-gr->Min.x)/(nn-1);
-			fit->a[j+i*nn] = fd.eq->Calc(val);
-		}
+		mgl_fill_fit(gr,*fit,in,fd,var,nn,1,1,i);
 		if(ini && ini->nx>=fd.m)	memcpy(ini->a,in.a,fd.m*sizeof(mreal));
 	}
 	mglPrepareFitEq(gr,res,eq,var,in.a);
@@ -269,24 +290,23 @@ HMDT MGL_EXPORT mgl_fit_xys(HMGL gr, HCDT xx, HCDT yy, HCDT ss, const char *eq,
 //-----------------------------------------------------------------------------
 HMDT MGL_EXPORT mgl_fit_xyzs(HMGL gr, HCDT xx, HCDT yy, HCDT zz, HCDT ss, const char *eq, const char *var, HMDT ini, const char *opt)
 {
-	mglData *fit=new mglData;
 	long m=zz->GetNx(),n=zz->GetNy();
-	long nn = long(0.5+gr->SaveState(opt));
+	mreal rr = gr->SaveState(opt);
+	long nn = (mgl_isnan(rr) || rr<=0) ? mglFitPnts:long(rr+0.5);
 	if(xx->GetNx()!=m)
-	{	gr->SetWarn(mglWarnDim,"Fit[S]");	return fit;	}
+	{	gr->SetWarn(mglWarnDim,"Fit[S]");	return 0;	}
 	if(ss->GetNx()*ss->GetNy()*ss->GetNz() != m*n*zz->GetNz())
-	{	gr->SetWarn(mglWarnDim,"Fit[S]");	return fit;	}
+	{	gr->SetWarn(mglWarnDim,"Fit[S]");	return 0;	}
 	if(yy->GetNx()!=n && (xx->GetNy()!=n || yy->GetNx()!=m || yy->GetNy()!=n))
-	{	gr->SetWarn(mglWarnDim,"Fit[S]");	return fit;	}
+	{	gr->SetWarn(mglWarnDim,"Fit[S]");	return 0;	}
 	if(m<2|| n<2)
-	{	gr->SetWarn(mglWarnLow,"Fit[S]");	return fit;	}
+	{	gr->SetWarn(mglWarnLow,"Fit[S]");	return 0;	}
 	if(!var || *var==0)
-	{	gr->SetWarn(mglWarnNull,"Fit[S]");	return fit;	}
-	
-	if(nn<mglFitPnts)	nn = mglFitPnts;
+	{	gr->SetWarn(mglWarnNull,"Fit[S]");	return 0;	}
+
 	mglData x(m, n), y(m, n), z(zz), s(ss);
-	register long i,j;
-	for(i=0;i<m;i++)	for(j=0;j<n;j++)	// ñîçäàåì ìàññèâ òî÷åê
+#pragma omp parallel for collapse(2)
+	for(long i=0;i<m;i++)	for(long j=0;j<n;j++)	// ñîçäàåì ìàññèâ òî÷åê
 	{
 		x.a[i+m*j] = GetX(xx,i,j,0).x;
 		y.a[i+m*j] = GetY(yy,i,j,0).x;
@@ -296,22 +316,15 @@ HMDT MGL_EXPORT mgl_fit_xyzs(HMGL gr, HCDT xx, HCDT yy, HCDT zz, HCDT ss, const
 	fd.z = 0;		fd.a = z.a;	fd.s = s.a;
 	fd.var = var;	fd.m = strlen(var);
 	fd.eq = new mglFormula(eq);
-	mglData in(fd.m);
-	fit->Create(nn, nn, zz->GetNz());
-	mreal val[MGL_VS], res = -1;
-	for(i=0;i<zz->GetNz();i++)
+	mglData in(fd.m), *fit=new mglData(nn, nn, zz->GetNz());
+	mreal res = -1;
+	for(long i=0;i<zz->GetNz();i++)
 	{
 		if(ini && ini->nx>=fd.m)	in.Set(ini->a,fd.m);
 		else in.Fill(0.,0);
 		fd.a = z.a+i*m*n;		fd.s = s.a+i*m*n;
 		res = mgl_fit_base(&fd,in.a);
-		for(j=0;j<fd.m;j++)	val[var[j]-'a'] = in.a[j];
-		for(j=0;j<nn*nn;j++)
-		{
-			val['x'-'a'] = gr->Min.x+(j%nn)*(gr->Max.x-gr->Min.x)/(nn-1);
-			val['y'-'a'] = gr->Min.y+(j/nn)*(gr->Max.y-gr->Min.y)/(nn-1);
-			fit->a[j+i*nn*nn] = fd.eq->Calc(val);
-		}
+		mgl_fill_fit(gr,*fit,in,fd,var,nn,nn,1,i);
 		if(ini && ini->nx>=fd.m)	memcpy(ini->a,in.a,fd.m*sizeof(mreal));
 	}
 	mglPrepareFitEq(gr,res, eq,var,in.a);
@@ -320,26 +333,24 @@ HMDT MGL_EXPORT mgl_fit_xyzs(HMGL gr, HCDT xx, HCDT yy, HCDT zz, HCDT ss, const
 //-----------------------------------------------------------------------------
 HMDT MGL_EXPORT mgl_fit_xyzas(HMGL gr, HCDT xx, HCDT yy, HCDT zz, HCDT aa, HCDT ss, const char *eq, const char *var, HMDT ini, const char *opt)
 {
-	mglData *fit=new mglData;
-	register long i,j,k,i0;
-	long m=aa->GetNx(), n=aa->GetNy(), l=aa->GetNz();
-	i = n*m*l;
-	long nn = long(0.5+gr->SaveState(opt));
+	long m=aa->GetNx(), n=aa->GetNy(), l=aa->GetNz(), i = n*m*l;
+	mreal rr = gr->SaveState(opt);
+	long nn = (mgl_isnan(rr) || rr<=0) ? mglFitPnts:long(rr+0.5);
 	if(m<2 || n<2 || l<2)
-	{	gr->SetWarn(mglWarnLow,"Fit[S]");	return fit;	}
+	{	gr->SetWarn(mglWarnLow,"Fit[S]");	return 0;	}
 	if(ss->GetNx()*ss->GetNy()*ss->GetNz() != i)
-	{	gr->SetWarn(mglWarnDim,"Fit[S]");	return fit;	}
+	{	gr->SetWarn(mglWarnDim,"Fit[S]");	return 0;	}
 	bool both = xx->GetNx()*xx->GetNy()*xx->GetNz()==i && yy->GetNx()*yy->GetNy()*yy->GetNz()==i && zz->GetNx()*zz->GetNy()*zz->GetNz()==i;
 	if(!(both || (xx->GetNx()==m && yy->GetNx()==n && zz->GetNx()==l)))
-	{	gr->SetWarn(mglWarnDim,"Fit[S]");	return fit;	}
+	{	gr->SetWarn(mglWarnDim,"Fit[S]");	return 0;	}
 	if(!var || *var==0)
-	{	gr->SetWarn(mglWarnNull,"Fit[S]");	return fit;	}
-	
-	if(nn<mglFitPnts)	nn = mglFitPnts;
+	{	gr->SetWarn(mglWarnNull,"Fit[S]");	return 0;	}
+
 	mglData x(aa), y(aa), z(aa), a(aa), s(ss);
-	for(i=0;i<m;i++)	for(j=0;j<n;j++)	for(k=0;k<l;k++)	// ñîçäàåì ìàññèâ òî÷åê
+#pragma omp parallel for collapse(3)
+	for(long i=0;i<m;i++)	for(long j=0;j<n;j++)	for(long k=0;k<l;k++)	// ñîçäàåì ìàññèâ òî÷åê
 	{
-		i0 = i+m*(j+n*k);
+		register long i0 = i+m*(j+n*k);
 		x.a[i0] = GetX(xx,i,j,k).x;
 		y.a[i0] = GetY(yy,i,j,k).x;
 		z.a[i0] = GetZ(zz,i,j,k).x;
@@ -349,21 +360,13 @@ HMDT MGL_EXPORT mgl_fit_xyzas(HMGL gr, HCDT xx, HCDT yy, HCDT zz, HCDT aa, HCDT
 	fd.z = z.a;		fd.a = a.a;	fd.s = s.a;
 	fd.var = var;	fd.m = strlen(var);
 	fd.eq = new mglFormula(eq);
-	mglData in(fd.m);
-	fit->Create(nn, nn, nn);
-	mreal val[MGL_VS], res = -1;
+	mglData in(fd.m), *fit=new mglData(nn, nn, nn);
+	mreal res = -1;
 
 	if(ini && ini->nx>=fd.m)	in.Set(ini->a,fd.m);
 	else in.Fill(0.,0);
 	res = mgl_fit_base(&fd,in.a);
-	for(j=0;j<fd.m;j++)	val[var[j]-'a'] = in.a[j];
-	for(i=0;i<nn;i++)	for(j=0;j<nn*nn;j++)
-	{
-		val['x'-'a'] = gr->Min.x+(j%nn)*(gr->Max.x-gr->Min.x)/(nn-1);
-		val['y'-'a'] = gr->Min.y+(j/nn)*(gr->Max.y-gr->Min.y)/(nn-1);
-		val['z'-'a'] = gr->Min.z+i*(gr->Max.y-gr->Min.y)/(nn-1);
-		fit->a[j+nn*nn*i] = fd.eq->Calc(val);
-	}
+	mgl_fill_fit(gr,*fit,in,fd,var,nn,nn,nn,0);
 	if(ini && ini->nx>=fd.m)	memcpy(ini->a,in.a,fd.m*sizeof(mreal));
 
 	mglPrepareFitEq(gr,res, eq,var,in.a);
@@ -374,25 +377,28 @@ HMDT MGL_EXPORT mgl_hist_x(HMGL gr, HCDT x, HCDT a, const char *opt)
 {
 	long nn=a->GetNx()*a->GetNy()*a->GetNz();
 	if(nn!=x->GetNx()*x->GetNy()*x->GetNz())
-	{	gr->SetWarn(mglWarnDim,"Hist");	return (new mglData);	}
-	long n = long(0.5+gr->SaveState(opt));
-	if(n<mglFitPnts)	n = mglFitPnts;
+	{	gr->SetWarn(mglWarnDim,"Hist");	return 0;	}
+	mreal rr = gr->SaveState(opt);
+	long n = (mgl_isnan(rr) || rr<=0) ? mglFitPnts:long(rr+0.5);
 	mglData *res = new mglData(n);
-	register long i,j1;
 
 	const mglData *dx = dynamic_cast<const mglData *>(x);
 	const mglData *da = dynamic_cast<const mglData *>(a);
 	mreal vx = n/(gr->Max.x-gr->Min.x);
-	if(dx && da)	for(i=0;i<nn;i++)
-	{
-		j1 = long((dx->a[i]-gr->Min.x)*vx);
-		if(j1>=0 && j1<n)	res->a[j1] += da->a[i];
-	}
-	else	for(i=0;i<nn;i++)
-	{
-		j1 = long((x->vthr(i)-gr->Min.x)*vx);
-		if(j1>=0 && j1<n)	res->a[j1] += a->vthr(i);
-	}
+	if(dx && da)
+#pragma omp parallel for
+		for(long i=0;i<nn;i++)
+		{
+			register long j1 = long((dx->a[i]-gr->Min.x)*vx);
+			if(j1>=0 && j1<n)	res->a[j1] += da->a[i];
+		}
+	else
+#pragma omp parallel for
+		for(long i=0;i<nn;i++)
+		{
+			register long j1 = long((x->vthr(i)-gr->Min.x)*vx);
+			if(j1>=0 && j1<n)	res->a[j1] += a->vthr(i);
+		}
 	gr->LoadState();	return res;
 }
 //-----------------------------------------------------------------------------
@@ -400,28 +406,31 @@ HMDT MGL_EXPORT mgl_hist_xy(HMGL gr, HCDT x, HCDT y, HCDT a, const char *opt)
 {
 	long nn=a->GetNx()*a->GetNy()*a->GetNz();
 	if(nn!=x->GetNx()*x->GetNy()*x->GetNz() || nn!=y->GetNx()*y->GetNy()*y->GetNz())
-	{	gr->SetWarn(mglWarnDim,"Hist");	return (new mglData);	}
-	long n = long(0.5+gr->SaveState(opt));
-	if(n<mglFitPnts)	n = mglFitPnts;
+	{	gr->SetWarn(mglWarnDim,"Hist");	return 0;	}
+	mreal rr = gr->SaveState(opt);
+	long n = (mgl_isnan(rr) || rr<=0) ? mglFitPnts:long(rr+0.5);
 	mglData *res = new mglData(n, n);
-	register long i,j1,j2;
 	const mglData *dx = dynamic_cast<const mglData *>(x);
 	const mglData *dy = dynamic_cast<const mglData *>(y);
 	const mglData *da = dynamic_cast<const mglData *>(a);
 	mreal vx = n/(gr->Max.x-gr->Min.x);
 	mreal vy = n/(gr->Max.y-gr->Min.y);
-	if(dx && dy && da)	for(i=0;i<nn;i++)
-	{
-		j1 = long((dx->a[i]-gr->Min.x)*vx);
-		j2 = long((dy->a[i]-gr->Min.y)*vy);
-		if(j1>=0 && j1<n && j2>=0 && j2<n)	res->a[j1+n*j2] += da->a[i];
-	}
-	else	for(i=0;i<nn;i++)
-	{
-		j1 = long((x->vthr(i)-gr->Min.x)*vx);
-		j2 = long((y->vthr(i)-gr->Min.y)*vy);
-		if(j1>=0 && j1<n && j2>=0 && j2<n)	res->a[j1+n*j2] += a->vthr(i);
-	}
+	if(dx && dy && da)
+#pragma omp parallel for
+		for(long i=0;i<nn;i++)
+		{
+			register long j1 = long((dx->a[i]-gr->Min.x)*vx);
+			register long j2 = long((dy->a[i]-gr->Min.y)*vy);
+			if(j1>=0 && j1<n && j2>=0 && j2<n)	res->a[j1+n*j2] += da->a[i];
+		}
+	else
+#pragma omp parallel for
+		for(long i=0;i<nn;i++)
+		{
+			register long j1 = long((x->vthr(i)-gr->Min.x)*vx);
+			register long j2 = long((y->vthr(i)-gr->Min.y)*vy);
+			if(j1>=0 && j1<n && j2>=0 && j2<n)	res->a[j1+n*j2] += a->vthr(i);
+		}
 	gr->LoadState();	return res;
 }
 //-----------------------------------------------------------------------------
@@ -429,34 +438,37 @@ HMDT MGL_EXPORT mgl_hist_xyz(HMGL gr, HCDT x, HCDT y, HCDT z, HCDT a, const char
 {
 	long nn=a->GetNx()*a->GetNy()*a->GetNz();
 	if(nn!=x->GetNx()*x->GetNy()*x->GetNz() || nn!=y->GetNx()*y->GetNy()*y->GetNz() || nn!=z->GetNx()*z->GetNy()*z->GetNz())
-	{	gr->SetWarn(mglWarnDim,"Hist");	return (new mglData);	}
-	long n = long(0.5+gr->SaveState(opt));
-	if(n<mglFitPnts)	n = mglFitPnts;
+	{	gr->SetWarn(mglWarnDim,"Hist");	return 0;	}
+	mreal rr = gr->SaveState(opt);
+	long n = (mgl_isnan(rr) || rr<=0) ? mglFitPnts:long(rr+0.5);
 	mglData *res = new mglData(n, n, n);
-	register long i,j1,j2,j3;
 	const mglData *dx = dynamic_cast<const mglData *>(x);
 	const mglData *dy = dynamic_cast<const mglData *>(y);
 	const mglData *dz = dynamic_cast<const mglData *>(z);
 	const mglData *da = dynamic_cast<const mglData *>(a);
 	mreal vx = n/(gr->Max.x-gr->Min.x), vy = n/(gr->Max.y-gr->Min.y), vz = n/(gr->Max.z-gr->Min.z);
-	if(dx && dy && dz && da)	for(i=0;i<nn;i++)
-	{
-		j1 = long((dx->a[i]-gr->Min.x)*vx);
-		j2 = long((dy->a[i]-gr->Min.y)*vy);
-		j3 = long((dz->a[i]-gr->Min.z)*vz);
-		if(j1>=0 && j1<n && j2>=0 && j2<n && j3>=0 && j3<n)
-			res->a[j1+n*(j2+n*j3)] += da->a[i];
-	}
-	else	for(i=0;i<nn;i++)
-	{
-		if(gr->Stop)	{	res->Create(1,1,1);	return res;	}
-		j1 = long((x->vthr(i)-gr->Min.x)*vx);
-		j2 = long((y->vthr(i)-gr->Min.y)*vy);
-		j3 = long((z->vthr(i)-gr->Min.z)*vz);
-		if(j1>=0 && j1<n && j2>=0 && j2<n && j3>=0 && j3<n)
-			res->a[j1+n*(j2+n*j3)] += a->vthr(i);
-	}
-	gr->LoadState();	return res;
+	if(dx && dy && dz && da)
+#pragma omp parallel for
+		for(long i=0;i<nn;i++)
+		{
+			register long j1 = long((dx->a[i]-gr->Min.x)*vx);
+			register long j2 = long((dy->a[i]-gr->Min.y)*vy);
+			register long j3 = long((dz->a[i]-gr->Min.z)*vz);
+			if(j1>=0 && j1<n && j2>=0 && j2<n && j3>=0 && j3<n)
+				res->a[j1+n*(j2+n*j3)] += da->a[i];
+		}
+	else
+#pragma omp parallel for
+		for(long i=0;i<nn;i++)
+		{
+			if(gr->Stop)	continue;
+			register long j1 = long((x->vthr(i)-gr->Min.x)*vx);
+			register long j2 = long((y->vthr(i)-gr->Min.y)*vy);
+			register long j3 = long((z->vthr(i)-gr->Min.z)*vz);
+			if(j1>=0 && j1<n && j2>=0 && j2<n && j3>=0 && j3<n)
+				res->a[j1+n*(j2+n*j3)] += a->vthr(i);
+		}
+	gr->LoadState();	return gr->Stop?0:res;
 }
 //-----------------------------------------------------------------------------
 uintptr_t MGL_EXPORT mgl_hist_x_(uintptr_t* gr, uintptr_t* x, uintptr_t* a, const char *opt, int lo)
diff --git a/src/font.cpp b/src/font.cpp
index 3d1a9c4..504aea7 100644
--- a/src/font.cpp
+++ b/src/font.cpp
@@ -68,25 +68,17 @@ char mglGetStyle(const char *how, int *font, int *align)
 //-----------------------------------------------------------------------------
 float mglFont::Puts(const char *str,const char *how,float col) const
 {
-	int font=0, align=1;
+	int font=0, align=1;	float w=0;
 	char cc=mglGetStyle(how,&font,&align);
-	size_t size = mbstowcs(0,str,0)+1;
-	wchar_t *wcs = new wchar_t[size];
-	mbstowcs(wcs,str,size);
-	float w = Puts(wcs,font,align,cc?-cc:col);
-	delete []wcs;
+	MGL_TO_WCS(str,w = Puts(wcs,font,align,cc?-cc:col));
 	return w;
 }
 //-----------------------------------------------------------------------------
 float mglFont::Width(const char *str,const char *how) const
 {
-	int font=0;
+	int font=0;	float w=0;
 	mglGetStyle(how,&font);
-	size_t size = mbstowcs(0,str,0)+1;
-	wchar_t *wcs = new wchar_t[size];
-	mbstowcs(wcs,str,size);
-	float w = Width(wcs,font);
-	delete []wcs;
+	MGL_TO_WCS(str,w = Width(wcs,font));
 	return w;
 }
 //-----------------------------------------------------------------------------
@@ -108,7 +100,7 @@ float mglFont::Puts(const wchar_t *str,int font,int align, float col) const
 {
 	if(numg==0 || !str || *str==0)	return 0;
 	float ww=0,w=0,h = (align&4) ? 500./fact[0] : 0;
-	size_t size = wcslen(str)+1,i,num=0;
+	size_t size = mgl_wcslen(str)+1,i,num=0;
 	if(parse)
 	{
 		unsigned *wcs = new unsigned[size], *buf=wcs;
@@ -166,7 +158,7 @@ float mglFont::Width(const wchar_t *str,int font) const
 {
 	if(numg==0 || !str || *str==0)	return 0;
 	float ww=0,w=0;
-	size_t size = wcslen(str)+1,i;
+	size_t size = mgl_wcslen(str)+1,i;
 	if(parse)
 	{
 		unsigned *wcs = new unsigned[size], *buf=wcs;
@@ -553,48 +545,68 @@ void mglFont::mem_alloc()
 	id = new wchar_t[numg];
 	width[0] = new short[numg];	width[1] = new short[numg];
 	width[2] = new short[numg];	width[3] = new short[numg];
-	tr[0] = new unsigned[numg];	numt[0] = new short[numg];
-	tr[1] = new unsigned[numg];	numt[1] = new short[numg];
-	tr[2] = new unsigned[numg];	numt[2] = new short[numg];
-	tr[3] = new unsigned[numg];	numt[3] = new short[numg];
-	ln[0] = new unsigned[numg];	numl[0] = new short[numg];
-	ln[1] = new unsigned[numg];	numl[1] = new short[numg];
-	ln[2] = new unsigned[numg];	numl[2] = new short[numg];
-	ln[3] = new unsigned[numg];	numl[3] = new short[numg];
+	tr[0] = new int[numg];	numt[0] = new short[numg];
+	tr[1] = new int[numg];	numt[1] = new short[numg];
+	tr[2] = new int[numg];	numt[2] = new short[numg];
+	tr[3] = new int[numg];	numt[3] = new short[numg];
+	ln[0] = new int[numg];	numl[0] = new short[numg];
+	ln[1] = new int[numg];	numl[1] = new short[numg];
+	ln[2] = new int[numg];	numl[2] = new short[numg];
+	ln[3] = new int[numg];	numl[3] = new short[numg];
 }
 //-----------------------------------------------------------------------------
 // copy normal style as default for other styles
 void mglFont::main_copy()
 {
-	memcpy(numl[1],numl[0],numg*sizeof(short));
-	memcpy(numl[2],numl[0],numg*sizeof(short));
-	memcpy(numl[3],numl[0],numg*sizeof(short));
-	memcpy(ln[1],ln[0],numg*sizeof(unsigned));
-	memcpy(ln[2],ln[0],numg*sizeof(unsigned));
-	memcpy(ln[3],ln[0],numg*sizeof(unsigned));
-	memcpy(numt[1],numt[0],numg*sizeof(short));
-	memcpy(numt[2],numt[0],numg*sizeof(short));
-	memcpy(numt[3],numt[0],numg*sizeof(short));
-	memcpy(tr[1],tr[0],numg*sizeof(unsigned));
-	memcpy(tr[2],tr[0],numg*sizeof(unsigned));
-	memcpy(tr[3],tr[0],numg*sizeof(unsigned));
-	memcpy(width[1],width[0],numg*sizeof(short));
-	memcpy(width[2],width[0],numg*sizeof(short));
-	memcpy(width[3],width[0],numg*sizeof(short));
+#pragma omp parallel sections
+	{
+#pragma omp section
+		memcpy(numl[1],numl[0],numg*sizeof(short));
+#pragma omp section
+		memcpy(numl[2],numl[0],numg*sizeof(short));
+#pragma omp section
+		memcpy(numl[3],numl[0],numg*sizeof(short));
+#pragma omp section
+		memcpy(ln[1],ln[0],numg*sizeof(int));
+#pragma omp section
+		memcpy(ln[2],ln[0],numg*sizeof(int));
+#pragma omp section
+		memcpy(ln[3],ln[0],numg*sizeof(int));
+#pragma omp section
+		memcpy(numt[1],numt[0],numg*sizeof(short));
+#pragma omp section
+		memcpy(numt[2],numt[0],numg*sizeof(short));
+#pragma omp section
+		memcpy(numt[3],numt[0],numg*sizeof(short));
+#pragma omp section
+		memcpy(tr[1],tr[0],numg*sizeof(int));
+#pragma omp section
+		memcpy(tr[2],tr[0],numg*sizeof(int));
+#pragma omp section
+		memcpy(tr[3],tr[0],numg*sizeof(int));
+#pragma omp section
+		memcpy(width[1],width[0],numg*sizeof(short));
+#pragma omp section
+		memcpy(width[2],width[0],numg*sizeof(short));
+#pragma omp section
+		memcpy(width[3],width[0],numg*sizeof(short));
+	}
 }
 //-----------------------------------------------------------------------------
-bool mglFont::read_def(unsigned &cur)
+bool mglFont::read_def()
 {
-	numg = mgl_numg;	cur = mgl_cur;
+	numg = mgl_numg;
 	// copy default factor for other font styles;
 	fact[1] = fact[2] = fact[3] = fact[0] = mgl_fact*mgl_fgen;
-	Buf = (short *)malloc(cur*sizeof(short));	// prealocate buffer
-	memset(Buf,0,cur*sizeof(short));
+	Buf = new short[mgl_cur];	// prealocate buffer
+	memset(Buf,0,mgl_cur*sizeof(short));
 	// now allocate memory for all fonts
 	mem_alloc();
 	// and load symbols itself
-	register long i;
-	for(i=0;i<int(numg);i++)
+#ifndef WIN32	// win32 don't initialized threads before main()
+#pragma omp parallel for
+#endif
+	for(long i=0;i<int(numg);i++)
 	{
 		id[i] = mgl_gen_fnt[i][0];
 		width[0][i] = mgl_gen_fnt[i][1];
@@ -603,20 +615,36 @@ bool mglFont::read_def(unsigned &cur)
 		numt[0][i] = mgl_gen_fnt[i][4];
 		tr[0][i] = mgl_gen_fnt[i][5];
 	}
-	memcpy(Buf, mgl_buf_fnt, cur*sizeof(short));
-	numb = cur;
+	memcpy(Buf, mgl_buf_fnt, mgl_cur*sizeof(short));
+	numb = mgl_cur;
+#ifndef WIN32	// win32 don't initialized threads before main()
 	main_copy();	// copy normal style as default for other styles
+#else
+	memcpy(numl[1],numl[0],numg*sizeof(short));
+	memcpy(numl[2],numl[0],numg*sizeof(short));
+	memcpy(numl[3],numl[0],numg*sizeof(short));
+	memcpy(ln[1],ln[0],numg*sizeof(int));
+	memcpy(ln[2],ln[0],numg*sizeof(int));
+	memcpy(ln[3],ln[0],numg*sizeof(int));
+	memcpy(numt[1],numt[0],numg*sizeof(short));
+	memcpy(numt[2],numt[0],numg*sizeof(short));
+	memcpy(numt[3],numt[0],numg*sizeof(short));
+	memcpy(tr[1],tr[0],numg*sizeof(int));
+	memcpy(tr[2],tr[0],numg*sizeof(int));
+	memcpy(tr[3],tr[0],numg*sizeof(int));
+	memcpy(width[1],width[0],numg*sizeof(short));
+	memcpy(width[2],width[0],numg*sizeof(short));
+	memcpy(width[3],width[0],numg*sizeof(short));
+#endif
 	return true;
 }
 //-----------------------------------------------------------------------------
-bool mglFont::read_data(const char *fname, float *ff, short *wdt, short *lnum,
-						unsigned *posl, short *tnum, unsigned *post, unsigned &cur)
+bool mglFont::read_data(const char *fname, float *ff, short *wdt, short *lnum, int *posl, short *tnum, int *post, std::vector<short> &buf)	// TODO add buffer for input file?!
 {
 	gzFile fp;
 	char str[256];
-	int n, tmpw, tmpnl, tmpnt;
+	int n, tmpw, tmpnl, tmpnt, retVal;
 	unsigned s, tmpi, tmppl, tmppt;
-	register long i,j,ch,retVal;
 	fp = gzopen(fname,"r");	if(!fp)	return false;	// false if no file
 	// first string is comment (not used), second string have information
 	if(!gzgets(fp,str,256) || strncmp(str,"# font",6) || !gzgets(fp,str,256))
@@ -624,31 +652,27 @@ bool mglFont::read_data(const char *fname, float *ff, short *wdt, short *lnum,
 	retVal = sscanf(str, "%d%f%d", &n, ff, &s);
 	//Check sscanf read all data  (3 items)
 	if(retVal != 3)	{	gzclose(fp);	return false;	}
-	Buf = (short *)realloc(Buf, (cur+s)*sizeof(short));	// prealocate buffer
-	if(!Buf)		{	gzclose(fp);	return false;	}
 
-	for(i=0;i<n;i++)
+	for(int i=0;i<n;i++)
 	{
 		gzgets(fp,str,256);
 		retVal = sscanf(str,"%u%d%d%u%d%u", &tmpi, &tmpw, &tmpnl, &tmppl, &tmpnt, &tmppt);
-		if(retVal != 6)	{	gzclose(fp);	free(Buf);	return false;	}
-		j=Internal(unsigned(tmpi));	if(j<0)	continue;
+		if(retVal != 6)	{	gzclose(fp);	buf.clear();	return false;	}
+		long j=Internal(unsigned(tmpi));	if(j<0)	continue;
 		if(wdt)	wdt[j] = tmpw;
-		lnum[j] = tmpnl;	posl[j] = tmppl+cur;
-		tnum[j] = tmpnt;	post[j] = tmppt+cur;
+		lnum[j] = tmpnl;	posl[j] = -1-tmppl;
+		tnum[j] = tmpnt;	post[j] = -1-tmppt;
 	}
-	for(i=0;i<int(s);i++)
+	for(unsigned i=0;i<s;i++)
 	{
-		for(j=0;j<256;j++)
-		{	str[j] = ch = gzgetc(fp);	if(ch<=' ')	break;	}
-		Buf[i+cur] = atoi(str);
+		for(int j=0;j<256;j++)	if((str[j] = gzgetc(fp))<=' ')	break;
+		buf.push_back(atoi(str));
 	}
-	cur += s;
 	gzclose(fp);		// finish wire normal font
 	return true;
 }
 //-----------------------------------------------------------------------------
-bool mglFont::read_main(const char *fname, unsigned &cur)
+bool mglFont::read_main(const char *fname, std::vector<short> &buf)	// TODO add buffer for input file?!
 {
 	gzFile fp;
 	int tmpi, tmpw, tmpnl, tmpnt;
@@ -661,14 +685,10 @@ bool mglFont::read_main(const char *fname, unsigned &cur)
 	{	gzclose(fp);	return false;	}
 	sscanf(str, "%u%f%u", &numg, fact, &s);
 	fact[1] = fact[2] = fact[3] = fact[0];	// copy default factor for other font styles;
-	Buf = (short *)malloc(s*sizeof(short));	// preallocate buffer
-	memset(Buf,0,s*sizeof(short));
-	if(!Buf)	{	gzclose(fp);	numg=0;	return false;	}
 	// now allocate memory for all fonts
 	mem_alloc();
 	// and load symbols itself
-	register long i,j,ch;
-	for(i=0;i<int(numg);i++)
+	for(size_t i=0;i<numg;i++)
 	{
 		gzgets(fp,str,256);
 		sscanf(str,"%u%d%d%u%d%u", &tmpi, &tmpw, &tmpnl, &tmppl, &tmpnt, &tmppt);
@@ -676,14 +696,12 @@ bool mglFont::read_main(const char *fname, unsigned &cur)
 		numl[0][i] = tmpnl; ln[0][i] = tmppl;
 		numt[0][i] = tmpnt;	tr[0][i] = tmppt;
 	}
-	for(i=0;i<int(s);i++)
+	for(unsigned i=0;i<s;i++)
 	{
-		for(j=0;j<256;j++)
-		{	str[j] = ch = gzgetc(fp);	if(ch<=' ')	break;	}
-		Buf[i] = atoi(str);
+		for(int j=0;j<256;j++)	if((str[j] = gzgetc(fp))<=' ')	break;
+		buf.push_back(atoi(str));
 	}
 	gzclose(fp);	// finish wire normal font
-	cur += s;		numb = cur;
 	main_copy();	// copy normal style as default for other styles
 	return true;
 }
@@ -698,7 +716,6 @@ bool mglFont::Load(const char *base, const char *path)
 #endif
 	char str[256];
 	const char *oldLocale = setlocale(LC_NUMERIC,"C");
-	unsigned cur=0;
 	if(!path)	path = MGL_FONT_PATH;
 	if(base && *base)
 	{
@@ -714,34 +731,59 @@ bool mglFont::Load(const char *base, const char *path)
 	Clear();							// first clear old
 
 	snprintf(str,256,"%s%c%s.vfm",path,sep,base?base:"");
-	if(!(base && *base) || !read_main(str,cur))
+	std::vector<short> norm, bold, ital, both;
+	if(!(base && *base) || !read_main(str,norm))
 	{
 //		mglGlobalMess += "Load built-in font.\n";
-		read_def(cur);	setlocale(LC_NUMERIC,oldLocale);
+		read_def();	setlocale(LC_NUMERIC,oldLocale);
 		if(buf)	delete []buf;	return true;
 	}
+	fact[1] = fact[2] = fact[3] = fact[0];
 
-	//================== bold ===========================================
-	snprintf(str,256,"%s%c%s_b.vfm",path,sep,base);	// this file may absent
-	if(read_data(str, fact+1, width[1], numl[1], ln[1], numt[1], tr[1], cur))
+#pragma omp parallel sections
 	{
-		fact[3] = fact[1];		// copy default factor for bold-italic;
-		// copy normal style as default for other styles
-		memcpy(numl[3],numl[1],numg*sizeof(short));
-		memcpy(ln[3],ln[1],numg*sizeof(unsigned));
-		memcpy(numt[3],numt[1],numg*sizeof(short));
-		memcpy(tr[3],tr[1],numg*sizeof(unsigned));
-		memcpy(width[3],width[1],numg*sizeof(short));
-	}
+		//================== bold ===========================================
+#pragma omp section
+		{	char str[256];	snprintf(str,256,"%s%c%s_b.vfm",path,sep,base);	// this file may absent
+		read_data(str, fact+1, width[1], numl[1], ln[1], numt[1], tr[1], bold);	}
 
-	//================== italic =========================================
-	snprintf(str,256,"%s%c%s_i.vfm",path,sep,base);
-	read_data(str, fact+2, width[2], numl[2], ln[2], numt[2], tr[2], cur);
+		//================== italic =========================================
+#pragma omp section
+		{	char str[256];	snprintf(str,256,"%s%c%s_i.vfm",path,sep,base);
+		read_data(str, fact+2, width[2], numl[2], ln[2], numt[2], tr[2], ital);	}
 
-	//================== bold-italic ====================================
-	snprintf(str,256,"%s%c%s_bi.vfm",path,sep,base);
-	read_data(str, fact+3, width[3], numl[3], ln[3], numt[3], tr[3], cur);
-	numb = cur;
+		//================== bold-italic ====================================
+#pragma omp section
+		{	char str[256];	snprintf(str,256,"%s%c%s_bi.vfm",path,sep,base);
+		read_data(str, fact+3, width[3], numl[3], ln[3], numt[3], tr[3], both);	}
+	}
+
+	// now collect data
+	numb = norm.size()+bold.size()+ital.size()+both.size();
+	Buf = new short[numb];
+#pragma omp parallel for
+	for(long i=0;i<long(norm.size());i++)	Buf[i]=norm[i];
+	long cur = norm.size(), len = long(bold.size());
+	if(bold.size()>0)
+#pragma omp parallel for
+		for(long i=0;i<len;i++)	Buf[i+cur]=bold[i];
+#pragma omp parallel for
+	for(long i=0;i<numg;i++)	if(ln[1][i]<0)
+	{	ln[1][i] = cur-1-ln[1][i];	tr[1][i] = cur-1-tr[1][i];	}
+	cur += len;		len = long(ital.size());
+	if(ital.size()>0)
+#pragma omp parallel for
+		for(long i=0;i<len;i++)	Buf[i+cur]=ital[i];
+#pragma omp parallel for
+	for(long i=0;i<numg;i++)	if(ln[2][i]<0)
+	{	ln[2][i] = cur-1-ln[2][i];	tr[2][i] = cur-1-tr[2][i];	}
+	cur += len;		len = long(both.size());
+	if(both.size()>0)
+#pragma omp parallel for
+		for(long i=0;i<len;i++)	Buf[i+cur]=both[i];
+#pragma omp parallel for
+	for(long i=0;i<numg;i++)	if(ln[3][i]<0)
+	{	ln[3][i] = cur-1-ln[3][i];	tr[3][i] = cur-1-tr[3][i];	}
 
 	// Finally normalize all factors
 	fact[0] *= mgl_fgen;	fact[1] *= mgl_fgen;
@@ -751,13 +793,33 @@ bool mglFont::Load(const char *base, const char *path)
 	return true;
 }
 //-----------------------------------------------------------------------------
+#if MGL_HAVE_PTHREAD
+extern pthread_mutex_t mutexRnd;
+#endif
+//-----------------------------------------------------------------------------
+float mgl_cos[360];
+void MGL_NO_EXPORT mgl_init()
+{
+#if MGL_HAVE_PTHREAD
+	pthread_mutex_init(&mutexRnd,0);
+#endif
+#ifndef WIN32	// win32 don't initialized threads before main()
+#pragma omp parallel for
+#endif
+	for(long i=0;i<360;i++)	mgl_cos[i] = cos(i*M_PI/180.);
+}
+//-----------------------------------------------------------------------------
 mglFont::mglFont(const char *name, const char *path)
 {
 	parse = true;	numg=0;	gr=0;
 //	if(this==&mglDefFont)	Load(name, path);	else	Copy(&mglDefFont);
 	if(name && *name)	Load(name, path);
 	else if(this!=&mglDefFont)	Copy(&mglDefFont);
-	else	Load(MGL_DEF_FONT_NAME,0);
+	else
+	{
+		mgl_init();		// NOTE: this call init function for the library.
+		Load(MGL_DEF_FONT_NAME,0);
+	}
 }
 mglFont::~mglFont()	{	Clear();	}
 void mglFont::Restore()	{	Copy(&mglDefFont);	}
@@ -767,7 +829,7 @@ void mglFont::Clear()
 //	if(gr)	gr->Clf();
 	if(numg)
 	{
-		delete []id;		free(Buf);			numg = 0;
+		delete []id;	delete []Buf;	numg = 0;
 		delete [](width[0]);	delete [](width[1]);	delete [](width[2]);	delete [](width[3]);
 		delete [](tr[0]);		delete [](tr[1]);		delete [](tr[2]);		delete [](tr[3]);
 		delete [](ln[0]);		delete [](ln[1]);		delete [](ln[2]);		delete [](ln[3]);
@@ -783,30 +845,54 @@ void mglFont::Copy(mglFont *f)
 	numg = f->numg;		numb = f->numb;
 	mem_alloc();
 	// copy general data
-	memcpy(id,f->id,numg*sizeof(wchar_t));
-	memcpy(width[0],f->width[0],numg*sizeof(short));
-	memcpy(width[1],f->width[1],numg*sizeof(short));
-	memcpy(width[2],f->width[2],numg*sizeof(short));
-	memcpy(width[3],f->width[3],numg*sizeof(short));
-	memcpy(tr[0],f->tr[0],numg*sizeof(unsigned));
-	memcpy(tr[1],f->tr[1],numg*sizeof(unsigned));
-	memcpy(tr[2],f->tr[2],numg*sizeof(unsigned));
-	memcpy(tr[3],f->tr[3],numg*sizeof(unsigned));
-	memcpy(numt[0],f->numt[0],numg*sizeof(short));
-	memcpy(numt[1],f->numt[1],numg*sizeof(short));
-	memcpy(numt[2],f->numt[2],numg*sizeof(short));
-	memcpy(numt[3],f->numt[3],numg*sizeof(short));
-	memcpy(ln[0],f->ln[0],numg*sizeof(unsigned));
-	memcpy(ln[1],f->ln[1],numg*sizeof(unsigned));
-	memcpy(ln[2],f->ln[2],numg*sizeof(unsigned));
-	memcpy(ln[3],f->ln[3],numg*sizeof(unsigned));
-	memcpy(numl[0],f->numl[0],numg*sizeof(short));
-	memcpy(numl[1],f->numl[1],numg*sizeof(short));
-	memcpy(numl[2],f->numl[2],numg*sizeof(short));
-	memcpy(numl[3],f->numl[3],numg*sizeof(short));
-	memcpy(fact,f->fact,4*sizeof(float));
+#pragma omp parallel sections
+	{
+#pragma omp section
+		memcpy(id,f->id,numg*sizeof(wchar_t));
+#pragma omp section
+		memcpy(width[0],f->width[0],numg*sizeof(short));
+#pragma omp section
+		memcpy(width[1],f->width[1],numg*sizeof(short));
+#pragma omp section
+		memcpy(width[2],f->width[2],numg*sizeof(short));
+#pragma omp section
+		memcpy(width[3],f->width[3],numg*sizeof(short));
+#pragma omp section
+		memcpy(tr[0],f->tr[0],numg*sizeof(unsigned));
+#pragma omp section
+		memcpy(tr[1],f->tr[1],numg*sizeof(unsigned));
+#pragma omp section
+		memcpy(tr[2],f->tr[2],numg*sizeof(unsigned));
+#pragma omp section
+		memcpy(tr[3],f->tr[3],numg*sizeof(unsigned));
+#pragma omp section
+		memcpy(numt[0],f->numt[0],numg*sizeof(short));
+#pragma omp section
+		memcpy(numt[1],f->numt[1],numg*sizeof(short));
+#pragma omp section
+		memcpy(numt[2],f->numt[2],numg*sizeof(short));
+#pragma omp section
+		memcpy(numt[3],f->numt[3],numg*sizeof(short));
+#pragma omp section
+		memcpy(ln[0],f->ln[0],numg*sizeof(unsigned));
+#pragma omp section
+		memcpy(ln[1],f->ln[1],numg*sizeof(unsigned));
+#pragma omp section
+		memcpy(ln[2],f->ln[2],numg*sizeof(unsigned));
+#pragma omp section
+		memcpy(ln[3],f->ln[3],numg*sizeof(unsigned));
+#pragma omp section
+		memcpy(numl[0],f->numl[0],numg*sizeof(short));
+#pragma omp section
+		memcpy(numl[1],f->numl[1],numg*sizeof(short));
+#pragma omp section
+		memcpy(numl[2],f->numl[2],numg*sizeof(short));
+#pragma omp section
+		memcpy(numl[3],f->numl[3],numg*sizeof(short));
+#pragma omp section
+		memcpy(fact,f->fact,4*sizeof(float));
+	}
 	// now copy symbols descriptions
-	Buf = (short *)malloc(numb*sizeof(short));
-	memcpy(Buf, f->Buf, numb*sizeof(short));
+	Buf = new short[numb];	memcpy(Buf, f->Buf, numb*sizeof(short));
 }
 //-----------------------------------------------------------------------------
diff --git a/src/interp.hpp b/src/interp.hpp
new file mode 100644
index 0000000..4b19e6c
--- /dev/null
+++ b/src/interp.hpp
@@ -0,0 +1,384 @@
+//-----------------------------------------------------------------------------
+template <class Treal> void mglFillP(long x,long y, const Treal *a,long nx,long ny,Treal _p[4][4])
+{
+	Treal sx[4]={0,0,0,0},sy[4]={0,0,0,0},f[4]={0,0,0,0},d[4]={0,0,0,0};
+	if(x<0 || y<0 || x>nx-2 || y>ny-2)
+	{
+		memset(_p[0],0,4*sizeof(Treal));
+		memset(_p[1],0,4*sizeof(Treal));
+		memset(_p[2],0,4*sizeof(Treal));
+		memset(_p[3],0,4*sizeof(Treal));
+		return;
+	}
+	// �������� �������
+	f[0]=a[x+nx*y];		f[1]=a[x+nx*(y+1)];
+	if(nx>1)	{	f[2]=a[x+1+nx*y];	f[3]=a[x+1+nx*(y+1)];	}
+	else		{	f[2] = f[0];	f[3] = f[1];	}
+	// ����������� �� x
+	if(nx>1)
+	{
+		if(x==0)
+		{
+			sx[0]=a[x+1+y*nx]-a[x+nx*y];
+			sx[1]=a[x+1+nx*(y+1)]-a[x+nx*(y+1)];
+		}
+		else
+		{
+			sx[0]=(a[x+1+nx*y]-a[x-1+nx*y])/mreal(2);
+			sx[1]=(a[x+1+nx*(y+1)]-a[x-1+nx*(y+1)])/mreal(2);
+		}
+	}
+	if(x==nx-2)
+	{
+		sx[2]=a[x+1+nx*y]-a[x+nx*y];
+		sx[3]=a[x+1+nx*(y+1)]-a[x+nx*(y+1)];
+	}
+	else
+	{
+		sx[2]=(a[x+2+nx*y]-a[x+nx*y])/mreal(2);
+		sx[3]=(a[x+2+nx*(y+1)]-a[x+nx*(y+1)])/mreal(2);
+	}
+	// ����������� �� y
+	if(y==0)
+	{
+		sy[0]=a[x+nx*(y+1)]-a[x+nx*y];
+		sy[2]=a[x+1+nx*(y+1)]-a[x+1+nx*y];
+	}
+	else
+	{
+		sy[0]=(a[x+nx*(y+1)]-a[x+nx*(y-1)])/mreal(2);
+		sy[2]=(a[x+1+nx*(y+1)]-a[x+1+nx*(y-1)])/mreal(2);
+	}
+	if(y==ny-2)
+	{
+		sy[1]=a[x+nx*(y+1)]-a[x+nx*y];
+		sy[3]=a[x+1+nx*(y+1)]-a[x+1+nx*y];
+	}
+	else
+	{
+		sy[1]=(a[x+nx*(y+2)]-a[x+nx*y])/mreal(2);
+		sy[3]=(a[x+1+nx*(y+2)]-a[x+1+nx*y])/mreal(2);
+	}
+	// ������������ �����������
+	if(nx>1)
+	{
+		// ������ d[0]
+		if(y==0 && x==0)
+			d[0]=(a[x+1+nx*(y+1)]-a[x+nx*(y+1)]-a[x+1+nx*y]+a[x+nx*y]);
+		else if(y==0)
+			d[0]=(a[x+1+nx*(y+1)]-a[x-1+nx*(y+1)]-a[x+1+nx*y]+a[x-1+nx*y])/mreal(2);
+		else if(x==0)
+			d[0]=(a[x+1+nx*(y+1)]-a[x+nx*(y+1)]-a[x+1+nx*(y-1)]+a[x+nx*(y-1)])/mreal(2);
+		else
+			d[0]=(a[x+1+nx*(y+1)]-a[x-1+nx*(y+1)]-a[x+1+nx*(y-1)]+a[x-1+nx*(y-1)])/mreal(4);
+		// ������ d[1]
+		if(y==ny-2 && x==0)
+			d[1]=(a[x+1+nx*(y+1)]-a[x+nx*(y+1)]-a[x+1+nx*y]+a[x+nx*y]);
+		else if(y==ny-2)
+			d[1]=(a[x+1+nx*(y+1)]-a[x-1+nx*(y+1)]-a[x+1+nx*y]+a[x-1+nx*y])/mreal(2);
+		else if(x==0)
+			d[1]=(a[x+1+nx*(y+2)]-a[x+nx*(y+2)]-a[x+1+nx*y]+a[x+nx*y])/mreal(2);
+		else
+			d[1]=(a[x+1+nx*(y+2)]-a[x-1+nx*(y+2)]-a[x+1+nx*y]+a[x-1+nx*y])/mreal(4);
+		// ������ d[2]
+		if(y==0 && x==nx-2)
+			d[2]=(a[x+1+nx*(y+1)]-a[x+nx*(y+1)]-a[x+1+nx*y]+a[x+nx*y]);
+		else if(y==0)
+			d[2]=(a[x+2+nx*(y+1)]-a[x+nx*(y+1)]-a[x+2+nx*y]+a[x+nx*y])/mreal(2);
+		else if(x==nx-2)
+			d[2]=(a[x+1+nx*(y+1)]-a[x+nx*(y+1)]-a[x+1+nx*(y-1)]+a[x+nx*(y-1)])/mreal(2);
+		else
+			d[2]=(a[x+2+nx*(y+1)]-a[x+nx*(y+1)]-a[x+2+nx*(y-1)]+a[x+nx*(y-1)])/mreal(4);
+		// ������ d[3]
+		if(y==ny-2 && x==nx-2)
+			d[3]=(a[x+1+nx*(y+1)]-a[x+nx*(y+1)]-a[x+1+nx*y]+a[x+nx*y]);
+		else if(y==ny-2)
+			d[3]=(a[x+2+nx*(y+1)]-a[x+nx*(y+1)]-a[x+2+nx*y]+a[x+nx*y])/mreal(2);
+		else if(x==nx-2)
+			d[3]=(a[x+1+nx*(y+2)]-a[x+nx*(y+2)]-a[x+1+nx*y]+a[x+nx*y])/mreal(2);
+		else
+			d[3]=(a[x+2+nx*(y+2)]-a[x+nx*(y+2)]-a[x+2+nx*y]+a[x+nx*y])/mreal(4);
+	}
+	// ��������� ������������ ��������
+	_p[0][0]=f[0];		_p[1][0]=sx[0];
+	_p[2][0]=mreal(3)*(f[2]-f[0])-mreal(2)*sx[0]-sx[2];
+	_p[3][0]=sx[0]+sx[2]+mreal(2)*(f[0]-f[2]);
+	_p[0][1]=sy[0];		_p[1][1]=d[0];
+	_p[2][1]=mreal(3)*(sy[2]-sy[0])-mreal(2)*d[0]-d[2];
+	_p[3][1]=d[0]+d[2]+mreal(2)*(sy[0]-sy[2]);
+	_p[0][2]=mreal(3)*(f[1]-f[0])-mreal(2)*sy[0]-sy[1];
+	_p[1][2]=mreal(3)*(sx[1]-sx[0])-mreal(2)*d[0]-d[1];
+	_p[2][2]=mreal(9)*(f[0]-f[1]-f[2]+f[3])+mreal(6)*(sy[0]-sy[2]+sx[0]-sx[1])+
+		mreal(3)*(sx[2]-sx[3]+sy[1]-sy[3])+mreal(2)*(d[1]+d[2])+mreal(4)*d[0]+d[3];
+	_p[3][2]=mreal(6)*(f[1]+f[2]-f[0]-f[3])+mreal(3)*(sx[1]-sx[0]+sx[3]-sx[2])+
+		mreal(4)*(sy[2]-sy[0])+mreal(2)*(sy[3]-sy[1]-d[0]-d[2])-d[1]-d[3];
+	_p[0][3]=mreal(2)*(f[0]-f[1])+sy[0]+sy[1];
+	_p[1][3]=mreal(2)*(sx[0]-sx[1])+d[0]+d[1];
+	_p[2][3]=mreal(6)*(f[1]+f[2]-f[0]-f[3])+mreal(3)*(sy[2]-sy[1]+sy[3]-sy[0])+
+		mreal(4)*(sx[1]-sx[0])+mreal(2)*(sx[3]-sx[2]-d[0]-d[1])-d[2]-d[3];
+	_p[3][3]=d[0]+d[1]+d[2]+d[3]+mreal(4)*(f[0]-f[1]-f[2]+f[3])+
+		mreal(2)*(sx[0]-sx[1]+sx[2]-sx[3]+sy[0]-sy[2]+sy[1]-sy[3]);
+}
+//-----------------------------------------------------------------------------
+template <class Treal> void mglFillP(long x, const Treal *a,long nx,Treal _p[4])
+{
+	if(x<0 || x>nx-2)
+	{
+		memset(_p,0,4*sizeof(Treal));
+		return;
+	}
+	Treal s[2],f[2];
+	// �������� �������
+	f[0]=a[x];		f[1]=a[x+1];
+	// ����������� �� x
+	if(x==0)	s[0]=a[x+1]-a[x];
+	else		s[0]=(a[x+1]-a[x-1])/mreal(2);
+	if(x==nx-2)	s[1]=a[x+1]-a[x];
+	else		s[1]=(a[x+2]-a[x])/mreal(2);
+	// ��������� ������������ ��������
+	_p[0]=f[0];		_p[1]=s[0];
+	_p[2]=mreal(3)*(f[1]-f[0])-mreal(2)*s[0]-s[1];
+	_p[3]=s[0]+s[1]+mreal(2)*(f[0]-f[1]);
+}
+//-----------------------------------------------------------------------------
+template <class Treal> Treal mglLineart(const Treal *a, long nx, long ny, long nz, mreal x, mreal y, mreal z)
+{
+	if(!a || nx<1 || ny<1 || nz<1)	return 0;
+	register long i0;
+	long kx,ky,kz;
+	Treal b=0,dx,dy,dz,b1,b0;
+	if(x<0 || y<0 || z<0 || x>nx-1 || y>ny-1 || z>nz-1)
+		return 0;
+	if(nz>1 && z!=floor(z))		// 3d interpolation
+	{
+		kx=long(x);	ky=long(y);	kz=long(z);
+		dx = x-mreal(kx);	dy = y-mreal(ky);	dz = z-mreal(kz);
+
+		i0 = kx+nx*(ky+ny*kz);
+		b0 = a[i0]*(mreal(1)-dx-dy+dx*dy) + dx*(mreal(1)-dy)*a[i0+1] +
+			dy*(mreal(1)-dx)*a[i0+nx] + dx*dy*a[i0+nx+1];
+		i0 = kx+nx*(ky+ny*(kz+1));
+		b1 = a[i0]*(mreal(1)-dx-dy+dx*dy) + dx*(mreal(1)-dy)*a[i0+1] +
+			dy*(mreal(1)-dx)*a[i0+nx] + dx*dy*a[i0+nx+1];
+		b = b0 + dz*(b1-b0);
+	}
+	else if(ny>1 && y!=floor(y))	// 2d interpolation
+	{
+		kx=long(x);	ky=long(y);
+		dx = x-kx;	dy=y-ky;
+		i0 = kx+nx*ky;
+		b = a[i0]*(mreal(1)-dx-dy+dx*dy) + dx*(mreal(1)-dy)*a[i0+1] +
+			dy*(mreal(1)-dx)*a[i0+nx] + dx*dy*a[i0+nx+1];
+	}
+	else if(nx>1 && x!=floor(x))	// 1d interpolation
+	{
+		kx = long(x);
+		b = a[kx] + (x-kx)*(a[kx+1]-a[kx]);
+	}
+	else						// no interpolation
+		b = a[long(x+nx*(y+ny*z))];
+	return b;
+}
+//-----------------------------------------------------------------------------
+template <class Treal> Treal mglSpline3t(const Treal *a, long nx, long ny, long nz, mreal x, mreal y, mreal z, Treal *dx=0, Treal *dy=0, Treal *dz=0)
+{
+	if(!a || nx<1 || ny<1 || nz<1)	return 0;
+	Treal _p[4][4];
+	register long i,j;
+	register Treal fx=1, fy=1;
+	long kx=long(x),ky=long(y),kz=long(z);
+	Treal b=0;
+	x = x>0 ?(x<nx-1 ? x:nx-1):0;
+	y = y>0 ?(y<ny-1 ? y:ny-1):0;
+	z = z>0 ?(z<nz-1 ? z:nz-1):0;
+	//	if(x<0 || y<0 || z<0 || x>nx-1 || y>ny-1 || z>nz-1)		return 0;
+	if(dx)	*dx=0;	if(dy)	*dy=0;	if(dz)	*dz=0;
+	if(kx>nx-2)	kx = nx-2;	if(kx<0) 	kx = 0;
+	if(ky>ny-2)	ky = ny-2;	if(ky<0) 	ky = 0;
+	if(kz>nz-2)	kz = nz-2;	if(kz<0) 	kz = 0;
+//	if(nz>1 && z!=kz)		// 3d interpolation
+	if(nz>1)		// 3d interpolation
+	{
+		Treal b1[4]={0,0,0,0},  x1[4]={0,0,0,0},  y1[4]={0,0,0,0};
+		long kk=1;
+		if(kz==0)	{	kk=0;	}
+		else if(nz>3 && kz==nz-2)	{	kk=2;	}
+		for(long k=0;k<4;k++)
+		{
+			if(kz+k-kk<nz && kz+k-kk>=0)
+				mglFillP(kx, ky, a+(kz+k-kk)*nx*ny, nx, ny, _p);
+			else
+			{
+				memset(_p[0],0,4*sizeof(Treal));
+				memset(_p[1],0,4*sizeof(Treal));
+				memset(_p[2],0,4*sizeof(Treal));
+				memset(_p[3],0,4*sizeof(Treal));
+			}
+			for(i=0,fx=1;i<4;i++)
+			{
+				for(j=0,fy=1;j<4;j++)
+				{	b1[k] += fy*fx*_p[i][j];	fy *= y-ky;	}
+				for(j=1,fy=1;j<4;j++)
+				{	y1[k] += mreal(j)*fy*fx*_p[i][j];	fy *= y-ky;	}
+				fx *= x-kx;
+			}
+			for(i=1,fx=1;i<4;i++)
+			{
+				for(j=0,fy=1;j<4;j++)
+				{	x1[k] += mreal(i)*fy*fx*_p[i][j];	fy *= y-ky;	}
+				fx *= x-kx;
+			}
+		}
+		mglFillP(kk, b1, nz>3 ? 4:3, _p[0]);
+		mglFillP(kk, x1, nz>3 ? 4:3, _p[1]);
+		mglFillP(kk, y1, nz>3 ? 4:3, _p[2]);
+		for(i=0,fx=1,b=0;i<4;i++)
+		{
+			b += fx*_p[0][i];
+			if(dx)	*dx += fx*_p[1][i];
+			if(dy)	*dy += fx*_p[2][i];
+			fx *= z-kz;
+		}
+		if(dz)	for(i=1,fx=1;i<4;i++)
+		{	*dz += mreal(i)*fx*_p[0][i];	fx *= z-kz;	}
+	}
+//	else if(ny>1 && y!=ky)	// 2d interpolation
+	else if(ny>1)	// 2d interpolation
+	{
+		mglFillP(kx, ky, a+kz*nx*ny, nx, ny, _p);
+		for(i=0,fx=1,b=0;i<4;i++)
+		{
+			for(j=0,fy=1;j<4;j++)
+			{	b += fy*fx*_p[i][j];	fy *= y-ky;	}
+			if(dy)	for(j=1,fy=1;j<4;j++)
+			{	*dy+= mreal(j)*fy*fx*_p[i][j];	fy *= y-ky;	}
+			fx *= x-kx;
+		}
+		if(dx)	for(i=1,fx=1;i<4;i++)
+		{
+			for(j=0,fy=1;j<4;j++)
+			{	*dx+= mreal(i)*fy*fx*_p[i][j];	fy *= y-ky;	}
+			fx *= x-kx;
+		}
+	}
+//	else if(nx>1 && x!=kx)	// 1d interpolation
+	else if(nx>1)	// 1d interpolation
+	{
+		mglFillP(kx, a+(ky+ny*kz)*nx, nx, _p[0]);
+		for(i=0,fx=1,b=0;i<4;i++)
+		{	b += fx*_p[0][i];	fx *= x-kx;	}
+		if(dx)	for(i=1,fx=1;i<4;i++)
+		{	*dx+= mreal(i)*fx*_p[0][i];	fx *= x-kx;	}
+	}
+	else					// no interpolation
+		b = a[kx+nx*(ky+ny*kz)];
+	return b;
+}
+//-----------------------------------------------------------------------------
+template <class Treal> Treal mglSpline3st(const Treal *a, long nx, long ny, long nz, mreal x, mreal y, mreal z)
+{
+	if(!a || nx<1 || ny<1 || nz<1)	return 0;
+	Treal _p[4][4];
+	register long i,j;
+	register Treal fx=1, fy=1;
+	long kx=long(x),ky=long(y),kz=long(z);
+	Treal b=0;
+	x = x>0 ?(x<nx-1 ? x:nx-1):0;
+	y = y>0 ?(y<ny-1 ? y:ny-1):0;
+	z = z>0 ?(z<nz-1 ? z:nz-1):0;
+	//	if(x<0 || y<0 || z<0 || x>nx-1 || y>ny-1 || z>nz-1)		return 0;
+	if(kx>nx-2)	kx = nx-2;	if(kx<0) 	kx = 0;
+	if(ky>ny-2)	ky = ny-2;	if(ky<0) 	ky = 0;
+	if(kz>nz-2)	kz = nz-2;	if(kz<0) 	kz = 0;
+//	if(nz>1 && z!=kz)		// 3d interpolation
+	if(nz>1)		// 3d interpolation
+	{
+		Treal b1[4]={0,0,0,0},  x1[4]={0,0,0,0},  y1[4]={0,0,0,0};
+		long kk=1;
+		if(kz==0)	{	kk=0;	}
+		else if(nz>3 && kz==nz-2)	{	kk=2;	}
+		for(long k=0;k<4;k++)
+		{
+			if(kz+k-kk<nz && kz+k-kk>=0)
+				mglFillP(kx, ky, a+(kz+k-kk)*nx*ny, nx, ny, _p);
+			else
+			{
+				memset(_p[0],0,4*sizeof(Treal));
+				memset(_p[1],0,4*sizeof(Treal));
+				memset(_p[2],0,4*sizeof(Treal));
+				memset(_p[3],0,4*sizeof(Treal));
+			}
+			for(i=0,fx=1;i<4;i++)
+			{
+				for(j=0,fy=1;j<4;j++)
+				{	b1[k] += fy*fx*_p[i][j];	fy *= y-ky;	}
+				fx *= x-kx;
+			}
+		}
+		mglFillP(kk, b1, nz>3 ? 4:3, _p[0]);
+		mglFillP(kk, x1, nz>3 ? 4:3, _p[1]);
+		mglFillP(kk, y1, nz>3 ? 4:3, _p[2]);
+		for(i=0,fx=1,b=0;i<4;i++)
+		{
+			b += fx*_p[0][i];
+			fx *= z-kz;
+		}
+	}
+//	else if(ny>1 && y!=ky)	// 2d interpolation
+	else if(ny>1)	// 2d interpolation
+	{
+		mglFillP(kx, ky, a+kz*nx*ny, nx, ny, _p);
+		for(i=0,fx=1,b=0;i<4;i++)
+		{
+			for(j=0,fy=1;j<4;j++)
+			{	b += fy*fx*_p[i][j];	fy *= y-ky;	}
+			fx *= x-kx;
+		}
+	}
+//	else if(nx>1 && x!=kx)	// 1d interpolation
+	else if(nx>1)	// 1d interpolation
+	{
+		mglFillP(kx, a+(ky+ny*kz)*nx, nx, _p[0]);
+		for(i=0,fx=1,b=0;i<4;i++)
+		{	b += fx*_p[0][i];	fx *= x-kx;	}
+	}
+	else					// no interpolation
+		b = a[kx+nx*(ky+ny*kz)];
+	return b;
+}
+//-----------------------------------------------------------------------------
+template <class Treal> Treal mglSpline1t(const Treal *a, long nx, mreal x, Treal *dx=0)
+{
+	Treal _p[4];
+	long kx=long(x);
+	Treal b=0;
+	x = x>0 ?(x<nx-1 ? x:nx-1):0;
+	if(kx>nx-2)	kx = nx-2;	if(kx<0) 	kx = 0;
+	if(nx>1)	// 1d interpolation
+	{
+		mglFillP(kx, a, nx, _p);
+		b = _p[0]+(x-kx)*(_p[1]+(x-kx)*(_p[2]+(x-kx)*_p[3]));
+		if(dx)	*dx = _p[1]+(x-kx)*(mreal(2)*_p[2]+mreal(3)*(x-kx)*_p[3]);
+	}
+	else		// no interpolation
+	{	b = a[0];	if(dx)	*dx=0;	}
+	return b;
+}
+//-----------------------------------------------------------------------------
+template <class Treal> Treal mglSpline1st(const Treal *a, long nx, mreal x)
+{
+	Treal _p[4];
+	long kx=long(x);
+	Treal b=0;
+	x = x>0 ?(x<nx-1 ? x:nx-1):0;
+	if(kx>nx-2)	kx = nx-2;	if(kx<0) 	kx = 0;
+	if(nx>1)	// 1d interpolation
+	{
+		mglFillP(kx, a, nx, _p);
+		b = _p[0]+(x-kx)*(_p[1]+(x-kx)*(_p[2]+(x-kx)*_p[3]));
+	}
+	else		// no interpolation
+		b = a[0];
+	return b;
+}
+//-----------------------------------------------------------------------------
diff --git a/src/mpi.cpp b/src/mpi.cpp
index 28b4c71..47ff410 100644
--- a/src/mpi.cpp
+++ b/src/mpi.cpp
@@ -27,12 +27,14 @@ void MGL_EXPORT mgl_mpi_recv(HMGL gr, int id)
 	MPI_Recv(zz,3*n,MPI_FLOAT,id,TAG_DATA_Z,MCW,&status);
 	MPI_Recv(cc,12*n,MPI_CHAR,id,TAG_DATA_C,MCW,&status);
 	MPI_Recv(oi,n,MPI_INT,id,TAG_DATA_C,MCW,&status);
-	// TODO check status for errors
-	register long i,j,k;
-	for(k=0;k<n;k++)
+	// NOTE: No need for check errors. The matter is MPI docs:
+	// "All MPI routines return an error value. Before the value is returned,
+	// the current MPI error handler is called. By default, this error handler aborts the MPI job."
+#pragma omp parallel for
+	for(long k=0;k<n;k++)
 	{	// i0=x+Width*(Height-1-y)
-		i = k%w;	j = h-1-(k/w);
-		if(g->GetQuality()&2)
+		register long i = k%w, j = h-1-(k/w);
+		if(g->GetQuality()&MGL_DRAW_NORM)
 		{
 			g->pnt_plot(i,j,zz[3*k+2],cc+12*k+8,oi[k]);
 			g->pnt_plot(i,j,zz[3*k+1],cc+12*k+4,oi[k]);
diff --git a/src/obj.cpp b/src/obj.cpp
index 46ee9b0..5f76abc 100644
--- a/src/obj.cpp
+++ b/src/obj.cpp
@@ -35,10 +35,6 @@ void MGL_NO_EXPORT mgl_printf(void *fp, bool gz, const char *str, ...);
 #include <string>
 #include <vector>
 #include <deque>
-#include <list>
-#ifdef __GNUC__
-#include <ext/slist>
-#endif
 #include <map>
 #include <iostream>
 
diff --git a/src/opengl.cpp b/src/opengl.cpp
index 66bf29f..fe305d0 100644
--- a/src/opengl.cpp
+++ b/src/opengl.cpp
@@ -21,11 +21,11 @@ mglCanvasGL::mglCanvasGL() : mglCanvas(1,1)	{}
 //-----------------------------------------------------------------------------
 mglCanvasGL::~mglCanvasGL(){}
 //-----------------------------------------------------------------------------
-void mglCanvasGL::Finish(bool fast)
+void mglCanvasGL::Finish()
 {
 	if(Prm.size()>0)
 	{
-		PreparePrim(fast);
+		PreparePrim(0);
 		glVertexPointer(3, GL_FLOAT, sizeof(mglPnt), &(Pnt[0].x));
 		glNormalPointer(GL_FLOAT, sizeof(mglPnt), &(Pnt[0].u));
 		glColorPointer(4, GL_FLOAT, sizeof(mglPnt), &(Pnt[0].r));
@@ -127,9 +127,9 @@ bool mglCanvasGL::Light(bool enable)
 	return mglCanvas::Light(enable);
 }
 //-----------------------------------------------------------------------------
-void mglCanvasGL::LightScale()
+void mglCanvasGL::LightScale(const mglMatrix *M)
 {
-	mglCanvas::LightScale();
+	mglCanvas::LightScale(M);
 	GLenum ll[8] = {GL_LIGHT0,GL_LIGHT1,GL_LIGHT2,GL_LIGHT3,GL_LIGHT4,
 			GL_LIGHT5,GL_LIGHT6,GL_LIGHT7};
 	float pos[4]={0,0,0,0};
@@ -174,10 +174,17 @@ void mglCanvasGL::Fog(mreal d, mreal)
 void mglCanvasGL::Clf(mglColor Back)
 {
 	mglCanvas::Clf(Back);
+	if(Back==NC)	Back = mglColor(BDef[0]/255.,BDef[1]/255.,BDef[2]/255.);
+	gl_clf(Back);
+}
+//-----------------------------------------------------------------------------
+void mglCanvasGL::gl_clf(mglColor Back)
+{
+	if(Back!=NC)	Back = WC;
 //	glDepthFunc(GL_LESS);
 	glDepthFunc(GL_GREATER);
 //	back[0]=Back.r;	back[1]=Back.g;	back[2]=Back.b;
-	glClearColor(Back.r,Back.g,Back.b,0.);
+	glClearColor(Back.r,Back.g,Back.b,1.);
 	glClearDepth(-10.);
 	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 	glEnable(GL_COLOR_MATERIAL);
@@ -201,7 +208,7 @@ void mglCanvasGL::set_pen(unsigned style,mreal width)
 	else			glLineWidth(1);
 }
 //-----------------------------------------------------------------------------
-void mglCanvasGL::EndFrame()
+/*void mglCanvasGL::EndFrame()
 {
 //	mglGraph::EndFrame();
 	glEndList();
@@ -213,7 +220,7 @@ int mglCanvasGL::NewFrame()
 	glNewList(CurFrameId,GL_COMPILE);
 	CurFrameId++;
 	return CurFrameId-1;
-}
+}*/
 //-----------------------------------------------------------------------------
 unsigned char **mglCanvasGL::GetRGBLines(long &width, long &height, unsigned char *&f, bool alpha)
 {
@@ -258,7 +265,7 @@ void mglCanvasGL::line_draw(long k1, long k2)
 	glEnd();
 }
 //-----------------------------------------------------------------------------
-void mglCanvasGL::quad_draw(const mglPnt &p1, const mglPnt &p2, const mglPnt &p3, const mglPnt &p4, mglDrawReg *)
+void mglCanvasGL::quad_draw(const mglPnt &p1, const mglPnt &p2, const mglPnt &p3, const mglPnt &p4, const mglDrawReg *)
 {
 	glBegin(GL_QUADS);
 	glNormal3f(p1.u,p1.v,p1.w);	glColor4f(p1.r,p1.g,p1.b,p1.a);	glVertex3f(p1.x,p1.y,p1.z);
@@ -268,7 +275,7 @@ void mglCanvasGL::quad_draw(const mglPnt &p1, const mglPnt &p2, const mglPnt &p3
 	glEnd();
 }
 //-----------------------------------------------------------------------------
-void mglCanvasGL::trig_draw(const mglPnt &p1, const mglPnt &p2, const mglPnt &p3, bool, mglDrawReg *)
+void mglCanvasGL::trig_draw(const mglPnt &p1, const mglPnt &p2, const mglPnt &p3, bool, const mglDrawReg *)
 {
 	glBegin(GL_TRIANGLES);
 	glNormal3f(p1.u,p1.v,p1.w);	glColor4f(p1.r,p1.g,p1.b,p1.a);	glVertex3f(p1.x,p1.y,p1.z);
@@ -277,7 +284,7 @@ void mglCanvasGL::trig_draw(const mglPnt &p1, const mglPnt &p2, const mglPnt &p3
 	glEnd();
 }
 //-----------------------------------------------------------------------------
-void mglCanvasGL::line_draw(const mglPnt &p1, const mglPnt &p2, mglDrawReg *)
+void mglCanvasGL::line_draw(const mglPnt &p1, const mglPnt &p2, const mglDrawReg *)
 {
 	if(PDef==0)	return;
 	set_pen(PDef,PenWidth);
@@ -287,11 +294,152 @@ void mglCanvasGL::line_draw(const mglPnt &p1, const mglPnt &p2, mglDrawReg *)
 	glEnd();
 }
 //-----------------------------------------------------------------------------
-void mglCanvasGL::pnt_draw(const mglPnt &p1, mglDrawReg *)
+void mglCanvasGL::pnt_draw(const mglPnt &p1, const mglDrawReg *)
 {
 	glBegin(GL_POINTS);
 	glColor4f(p1.r,p1.g,p1.b,p1.a);	glVertex3f(p1.x,p1.y,p1.z);
 	glEnd();
 }
 //-----------------------------------------------------------------------------
+void mglCanvasGL::mark_draw(const mglPnt &q, char type, mreal size, mglDrawReg *d)
+{
+	mglPnt p0=q,p1=q,p2=q,p3=q;
+	mreal ss=fabs(size);
 
+	if(type=='.' || ss==0)
+	{
+		if(d)	d->PenWidth = ss?ss:sqrt(font_factor/400);
+		pnt_draw(q,d);
+	}
+	else
+	{
+		if(d)
+		{
+			d->PDef = MGL_SOLID_MASK;	d->angle = 0;
+			d->PenWidth*=fabs(50*size);
+			if(d->PenWidth<1)	d->PenWidth=1;
+		}
+		if(!strchr("xsSoO",type))	ss *= 1.1;
+		switch(type)
+		{
+		case 'P':
+			p0.x = q.x-ss;	p0.y = q.y-ss;	p1.x = q.x+ss;	p1.y = q.y-ss;
+			p2.x = q.x+ss;	p2.y = q.y+ss;	p3.x = q.x-ss;	p3.y = q.y+ss;
+			line_draw(p0,p1,d);	line_draw(p1,p2,d);
+			line_draw(p2,p3,d);	line_draw(p3,p0,d);
+		case '+':
+			p0.x = q.x-ss;	p0.y = q.y;	p1.x = q.x+ss;	p1.y = q.y;	line_draw(p0,p1,d);
+			p2.x = q.x;	p2.y = q.y-ss;	p3.x = q.x;	p3.y = q.y+ss;	line_draw(p2,p3,d);
+			break;
+		case 'X':
+			p0.x = q.x-ss;	p0.y = q.y-ss;	p1.x = q.x+ss;	p1.y = q.y-ss;
+			p2.x = q.x+ss;	p2.y = q.y+ss;	p3.x = q.x-ss;	p3.y = q.y+ss;
+			line_draw(p0,p1,d);	line_draw(p1,p2,d);
+			line_draw(p2,p3,d);	line_draw(p3,p0,d);
+		case 'x':
+			p0.x = q.x-ss;	p0.y = q.y-ss;	p1.x = q.x+ss;	p1.y = q.y+ss;	line_draw(p0,p1,d);
+			p2.x = q.x+ss;	p2.y = q.y-ss;	p3.x = q.x-ss;	p3.y = q.y+ss;	line_draw(p2,p3,d);
+			break;
+		case 'S':
+			p0.x = q.x-ss;	p0.y = q.y-ss;	p1.x = q.x-ss;	p1.y = q.y+ss;
+			p2.x= q.x+ss;	p2.y= q.y+ss;	p3.x = q.x+ss;	p3.y = q.y-ss;
+			quad_draw(p0,p1,p3,p2,d);
+		case 's':
+			p0.x = q.x-ss;	p0.y = q.y-ss;	p1.x = q.x+ss;	p1.y = q.y-ss;
+			p2.x = q.x+ss;	p2.y = q.y+ss;	p3.x = q.x-ss;	p3.y = q.y+ss;
+			line_draw(p0,p1,d);	line_draw(p1,p2,d);
+			line_draw(p2,p3,d);	line_draw(p3,p0,d);
+			break;
+		case 'D':
+			p0.x = q.x;	p0.y = q.y-ss;	p1.x = q.x+ss;	p1.y = q.y;
+			p2.x= q.x;	p2.y= q.y+ss;	p3.x = q.x-ss;	p3.y = q.y;
+			quad_draw(p0,p1,p3,p2,d);
+		case 'd':
+			p0.x = q.x;	p0.y = q.y-ss;	p1.x = q.x+ss;	p1.y = q.y;
+			p2.x = q.x;	p2.y = q.y+ss;	p3.x = q.x-ss;	p3.y = q.y;
+			line_draw(p0,p1,d);	line_draw(p1,p2,d);
+			line_draw(p2,p3,d);	line_draw(p3,p0,d);
+			break;
+		case 'Y':
+			p1.x = q.x;	p1.y = q.y-ss;	line_draw(q,p1,d);
+			p2.x = q.x-0.8*ss;	p2.y = q.y+0.6*ss;	line_draw(q,p2,d);
+			p3.x = q.x+0.8*ss;	p3.y = q.y+0.6*ss;	line_draw(q,p3,d);
+			break;
+		case '*':
+			p0.x = q.x-ss;		p0.y = q.y;
+			p1.x = q.x+ss;		p1.y = q.y;	line_draw(p0,p1,d);
+			p0.x = q.x-0.6*ss;	p0.y = q.y-0.8*ss;
+			p1.x = q.x+0.6*ss;	p1.y = q.y+0.8*ss;	line_draw(p0,p1,d);
+			p0.x = q.x-0.6*ss;	p0.y = q.y+0.8*ss;
+			p1.x = q.x+0.6*ss;	p1.y = q.y-0.8*ss;	line_draw(p0,p1,d);
+			break;
+		case 'T':
+			p0.x = q.x-ss;	p0.y = q.y-ss/2;
+			p1.x = q.x+ss;	p1.y = q.y-ss/2;
+			p2.x= q.x;		p2.y= q.y+ss;
+			trig_draw(p0,p1,p2,false,d);
+		case '^':
+			p0.x = q.x-ss;	p0.y = q.y-ss/2;
+			p1.x = q.x+ss;	p1.y = q.y-ss/2;
+			p2.x= q.x;		p2.y= q.y+ss;
+			line_draw(p0,p1,d);	line_draw(p1,p2,d);
+			line_draw(p2,p0,d);	break;
+		case 'V':
+			p0.x = q.x-ss;	p0.y = q.y+ss/2;
+			p1.x = q.x+ss;	p1.y = q.y+ss/2;
+			p2.x= q.x;		p2.y= q.y-ss;
+			trig_draw(p0,p1,p2,false,d);
+		case 'v':
+			p0.x = q.x-ss;	p0.y = q.y+ss/2;
+			p1.x = q.x+ss;	p1.y = q.y+ss/2;
+			p2.x= q.x;		p2.y= q.y-ss;
+			line_draw(p0,p1,d);	line_draw(p1,p2,d);
+			line_draw(p2,p0,d);	break;
+		case 'L':
+			p0.x = q.x+ss/2;	p0.y = q.y+ss;
+			p1.x = q.x+ss/2;	p1.y = q.y-ss;
+			p2.x= q.x-ss;		p2.y= q.y;
+			trig_draw(p0,p1,p2,false,d);
+		case '<':
+			p0.x = q.x+ss/2;	p0.y = q.y+ss;
+			p1.x = q.x+ss/2;	p1.y = q.y-ss;
+			p2.x= q.x-ss;		p2.y= q.y;
+			line_draw(p0,p1,d);	line_draw(p1,p2,d);
+			line_draw(p2,p0,d);	break;
+		case 'R':
+			p0.x = q.x-ss/2;	p0.y = q.y+ss;
+			p1.x = q.x-ss/2;	p1.y = q.y-ss;
+			p2.x= q.x+ss;		p2.y= q.y;
+			trig_draw(p0,p1,p2,false,d);
+		case '>':
+			p0.x = q.x-ss/2;	p0.y = q.y+ss;
+			p1.x = q.x-ss/2;	p1.y = q.y-ss;
+			p2.x= q.x+ss;		p2.y= q.y;
+			line_draw(p0,p1,d);	line_draw(p1,p2,d);
+			line_draw(p2,p0,d);	break;
+		case 'O':
+/*			for(long j=long(-ss);j<=long(ss);j++)	for(long i=long(-ss);i<=long(ss);i++)
+			{
+				register long x=long(q.x)+i, y=long(q.y)+j;
+				if(i*i+j*j>=ss*ss || !d || x<d->x1 || x>d->x2 || y<d->y1 || y>d->y2)	continue;
+				pnt_plot(x,y,q.z+1,cs,d->ObjId);
+			}*/
+		case 'o':
+			for(long i=0;i<=20;i++)	// TODO copy from mark_pix()?!
+			{
+				p0 = p1;	p1.x = q.x+ss*cos(i*M_PI/10);	p1.y = q.y+ss*sin(i*M_PI/10);
+				if(i>0)	line_draw(p0,p1,d);
+			}
+			break;
+		case 'C':
+			pnt_draw(q,d);
+			for(long i=0;i<=20;i++)
+			{
+				p0 = p1;	p1.x = q.x+ss*cos(i*M_PI/10);	p1.y = q.y+ss*sin(i*M_PI/10);
+				if(i>0)	line_draw(p0,p1,d);
+			}
+			break;
+		}
+	}
+}
+//-----------------------------------------------------------------------------
diff --git a/src/other.cpp b/src/other.cpp
index 230f548..4a267ff 100644
--- a/src/other.cpp
+++ b/src/other.cpp
@@ -22,6 +22,7 @@
 #include "mgl2/cont.h"
 #include "mgl2/eval.h"
 #include "mgl2/data.h"
+#include "mgl2/base.h"
 //-----------------------------------------------------------------------------
 //
 //	DensX, DensY, DensZ series
@@ -29,7 +30,7 @@
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_dens_x(HMGL gr, HCDT a, const char *sch, double sv, const char *opt)
 {
-	register long i,j,k,n=a->GetNx(),m=a->GetNy(),l=a->GetNz();
+	long n=a->GetNx(),m=a->GetNy(),l=a->GetNz();
 	if(mgl_isnan(sv))	sv = gr->GetOrgX('x');
 	if(n<2 || m<2)	{	gr->SetWarn(mglWarnLow,"DensX");	return;	}
 	if(sv<gr->Min.x || sv>gr->Max.x)	{	gr->SetWarn(mglWarnSlc,"DensX");	return;	}
@@ -40,14 +41,18 @@ void MGL_EXPORT mgl_dens_x(HMGL gr, HCDT a, const char *sch, double sv, const ch
 	{
 		aa.Create(m,l);	xx.Create(m,l);	yy.Create(m,l);	zz.Create(m,l);
 		mreal d = (n-1)*(sv - gr->Min.x)/(gr->Max.x - gr->Min.x);
-		k = long(d);	d = d - k;
+		long k = long(d);	d = d - k;
 		if(k>n-2)	{	k=n-2;	d=1;	}
 		if(k<0)		{	k=0;	d=0;	}
 		const mglData *ma=dynamic_cast<const mglData *>(a);
-		if(ma)	for(j=0;j<l;j++)	for(i=0;i<m;i++)
-			aa.a[i+m*j] = ma->a[k+n*(i+m*j)]*(1-d) + d*ma->a[k+1+n*(i+m*j)];
-		else	for(j=0;j<l;j++)	for(i=0;i<m;i++)
-			aa.a[i+m*j] = a->v(k,i,j)*(1-d) + d*a->v(k+1,i,j);
+		if(ma)
+#pragma omp parallel for collapse(2)
+			for(long j=0;j<l;j++)	for(long i=0;i<m;i++)
+				aa.a[i+m*j] = ma->a[k+n*(i+m*j)]*(1-d) + d*ma->a[k+1+n*(i+m*j)];
+		else
+#pragma omp parallel for collapse(2)
+			for(long j=0;j<l;j++)	for(long i=0;i<m;i++)
+				aa.a[i+m*j] = a->v(k,i,j)*(1-d) + d*a->v(k+1,i,j);
 		a = &aa;
 	}
 	else
@@ -60,7 +65,7 @@ void MGL_EXPORT mgl_dens_x(HMGL gr, HCDT a, const char *sch, double sv, const ch
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_dens_y(HMGL gr, HCDT a, const char *sch, double sv, const char *opt)
 {
-	register long i,j,k,n=a->GetNx(),m=a->GetNy(),l=a->GetNz();
+	long n=a->GetNx(),m=a->GetNy(),l=a->GetNz();
 	if(mgl_isnan(sv))	sv = gr->GetOrgX('x');
 	if(n<2 || m<2)	{	gr->SetWarn(mglWarnLow,"DensY");	return;	}
 	if(sv<gr->Min.x || sv>gr->Max.x)	{	gr->SetWarn(mglWarnSlc,"DensY");	return;	}
@@ -71,14 +76,18 @@ void MGL_EXPORT mgl_dens_y(HMGL gr, HCDT a, const char *sch, double sv, const ch
 	{
 		aa.Create(n,l);	xx.Create(n,l);	yy.Create(n,l);	zz.Create(n,l);
 		mreal d = (m-1)*(sv - gr->Min.y)/(gr->Max.y - gr->Min.y);
-		k = long(d);	d = d - k;
+		long k = long(d);	d = d - k;
 		if(k>m-2)	{	k=m-2;	d=1;	}
 		if(k<0)		{	k=0;	d=0;	}
 		const mglData *ma=dynamic_cast<const mglData *>(a);
-		if(ma)	for(j=0;j<l;j++)	for(i=0;i<n;i++)
-			aa.a[i+n*j] = ma->a[i+n*(k+m*j)]*(1-d) + d*ma->a[i+n+n*(k+m*j)];
-		else	for(j=0;j<l;j++)	for(i=0;i<n;i++)
-			aa.a[i+n*j] = a->v(i,k,j)*(1-d) + d*a->v(i,k+1,j);
+		if(ma)
+#pragma omp parallel for collapse(2)
+			for(long j=0;j<l;j++)	for(long i=0;i<n;i++)
+				aa.a[i+n*j] = ma->a[i+n*(k+m*j)]*(1-d) + d*ma->a[i+n+n*(k+m*j)];
+		else
+#pragma omp parallel for collapse(2)
+			for(long j=0;j<l;j++)	for(long i=0;i<n;i++)
+				aa.a[i+n*j] = a->v(i,k,j)*(1-d) + d*a->v(i,k+1,j);
 		a = &aa;
 	}
 	else
@@ -91,7 +100,7 @@ void MGL_EXPORT mgl_dens_y(HMGL gr, HCDT a, const char *sch, double sv, const ch
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_dens_z(HMGL gr, HCDT a, const char *sch, double sv, const char *opt)
 {
-	register long i,j,k,n=a->GetNx(),m=a->GetNy(),l=a->GetNz();
+	long n=a->GetNx(),m=a->GetNy(),l=a->GetNz();
 	if(mgl_isnan(sv))	sv = gr->GetOrgX('x');
 	if(n<2 || m<2)	{	gr->SetWarn(mglWarnLow,"DensZ");	return;	}
 	if(sv<gr->Min.x || sv>gr->Max.x)	{	gr->SetWarn(mglWarnSlc,"DensZ");	return;	}
@@ -103,14 +112,18 @@ void MGL_EXPORT mgl_dens_z(HMGL gr, HCDT a, const char *sch, double sv, const ch
 	{
 		aa.Create(n,m);
 		mreal d = (l-1)*(sv - gr->Min.z)/(gr->Max.z - gr->Min.z);
-		k = long(d);	d = d - k;
+		long k = long(d);	d = d - k;
 		if(k>l-2)	{	k=l-2;	d=1;	}
 		if(k<0)		{	k=0;	d=0;	}
 		const mglData *ma=dynamic_cast<const mglData *>(a);
-		if(ma)	for(j=0;j<m;j++)	for(i=0;i<n;i++)
-			aa.a[i+n*j] = ma->a[i+n*(j+m*k)]*(1-d) + d*ma->a[i+n*m+n*(j+m*k)];
-		else	for(j=0;j<m;j++)	for(i=0;i<n;i++)
-			aa.a[i+n*j] = a->v(i,j,k)*(1-d) + d*a->v(i,j,k+1);
+		if(ma)
+#pragma omp parallel for collapse(2)
+			for(long j=0;j<m;j++)	for(long i=0;i<n;i++)
+				aa.a[i+n*j] = ma->a[i+n*(j+m*k)]*(1-d) + d*ma->a[i+n*m+n*(j+m*k)];
+		else
+#pragma omp parallel for collapse(2)
+			for(long j=0;j<m;j++)	for(long i=0;i<n;i++)
+				aa.a[i+n*j] = a->v(i,j,k)*(1-d) + d*a->v(i,j,k+1);
 		a = &aa;
 	}
 	zz.Fill(sv, sv);
@@ -143,7 +156,7 @@ void MGL_EXPORT mgl_dens_z_(uintptr_t *gr, uintptr_t *a, const char *sch, mreal
 void MGL_EXPORT mgl_cont_gen(HMGL gr, mreal val, HCDT a, HCDT x, HCDT y, HCDT z, mreal c, int text,long ak);
 void MGL_EXPORT mgl_cont_x_val(HMGL gr, HCDT v, HCDT a, const char *sch, double sv, const char *opt)
 {
-	register long i,j,k,n=a->GetNx(),m=a->GetNy(),l=a->GetNz();
+	long n=a->GetNx(),m=a->GetNy(),l=a->GetNz();
 	if(mgl_isnan(sv))	sv = gr->GetOrgX('x');
 	if(n<2 || m<2)	{	gr->SetWarn(mglWarnLow,"ContX");	return;	}
 	if(sv<gr->Min.x || sv>gr->Max.x)	{	gr->SetWarn(mglWarnSlc,"ContX");	return;	}
@@ -159,14 +172,18 @@ void MGL_EXPORT mgl_cont_x_val(HMGL gr, HCDT v, HCDT a, const char *sch, double
 	{
 		aa.Create(m,l);	xx.Create(m,l);	yy.Create(m,l);	zz.Create(m,l);
 		mreal d = (n-1)*(sv - gr->Min.x)/(gr->Max.x - gr->Min.x);
-		k = long(d);	d = d - k;
+		long k = long(d);	d = d - k;
 		if(k>n-2)	{	k=n-2;	d=1;	}
 		if(k<0)		{	k=0;	d=0;	}
 		const mglData *ma=dynamic_cast<const mglData *>(a);
-		if(ma)	for(j=0;j<l;j++)	for(i=0;i<m;i++)
-			aa.a[i+m*j] = ma->a[k+n*(i+m*j)]*(1-d) + d*ma->a[k+1+n*(i+m*j)];
-		else	for(j=0;j<l;j++)	for(i=0;i<m;i++)
-			aa.a[i+m*j] = a->v(k,i,j)*(1-d) + d*a->v(k+1,i,j);
+		if(ma)
+#pragma omp parallel for collapse(2)
+			for(long j=0;j<l;j++)	for(long i=0;i<m;i++)
+				aa.a[i+m*j] = ma->a[k+n*(i+m*j)]*(1-d) + d*ma->a[k+1+n*(i+m*j)];
+		else
+#pragma omp parallel for collapse(2)
+			for(long j=0;j<l;j++)	for(long i=0;i<m;i++)
+				aa.a[i+m*j] = a->v(k,i,j)*(1-d) + d*a->v(k+1,i,j);
 		a = &aa;
 	}
 	else
@@ -174,7 +191,8 @@ void MGL_EXPORT mgl_cont_x_val(HMGL gr, HCDT v, HCDT a, const char *sch, double
 	xx.Fill(sv, sv);
 	yy.Fill(gr->Min.y, gr->Max.y,'x');
 	zz.Fill(gr->Min.z, gr->Max.z,'y');
-	for(i=0;i<v->GetNx();i++)
+#pragma omp parallel for
+	for(long i=0;i<v->GetNx();i++)
 	{
 		register mreal v0 = v->v(i);
 		mgl_cont_gen(gr,v0,a,&xx,&yy,&zz,gr->GetC(ss,v0),text,0);
@@ -184,7 +202,7 @@ void MGL_EXPORT mgl_cont_x_val(HMGL gr, HCDT v, HCDT a, const char *sch, double
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_cont_y_val(HMGL gr, HCDT v, HCDT a, const char *sch, double sv, const char *opt)
 {
-	register long i,j,k,n=a->GetNx(),m=a->GetNy(),l=a->GetNz();
+	long n=a->GetNx(),m=a->GetNy(),l=a->GetNz();
 	if(mgl_isnan(sv))	sv = gr->GetOrgX('x');
 	if(n<2 || m<2)	{	gr->SetWarn(mglWarnLow,"ContY");	return;	}
 	if(sv<gr->Min.x || sv>gr->Max.x)	{	gr->SetWarn(mglWarnSlc,"ContY");	return;	}
@@ -200,14 +218,18 @@ void MGL_EXPORT mgl_cont_y_val(HMGL gr, HCDT v, HCDT a, const char *sch, double
 	{
 		aa.Create(n,l);	xx.Create(n,l);	yy.Create(n,l);	zz.Create(n,l);
 		mreal d = (m-1)*(sv - gr->Min.y)/(gr->Max.y - gr->Min.y);
-		k = long(d);	d = d - k;
+		long k = long(d);	d = d - k;
 		if(k>m-2)	{	k=m-2;	d=1;	}
 		if(k<0)		{	k=0;	d=0;	}
 		const mglData *ma=dynamic_cast<const mglData *>(a);
-		if(ma)	for(j=0;j<l;j++)	for(i=0;i<n;i++)
-			aa.a[i+n*j] = ma->a[i+n*(k+m*j)]*(1-d) + d*ma->a[i+n+n*(k+m*j)];
-		else	for(j=0;j<l;j++)	for(i=0;i<n;i++)
-			aa.a[i+n*j] = a->v(i,k,j)*(1-d) + d*a->v(i,k+1,j);
+		if(ma)
+#pragma omp parallel for collapse(2)
+			for(long j=0;j<l;j++)	for(long i=0;i<n;i++)
+				aa.a[i+n*j] = ma->a[i+n*(k+m*j)]*(1-d) + d*ma->a[i+n+n*(k+m*j)];
+		else
+#pragma omp parallel for collapse(2)
+			for(long j=0;j<l;j++)	for(long i=0;i<n;i++)
+				aa.a[i+n*j] = a->v(i,k,j)*(1-d) + d*a->v(i,k+1,j);
 		a = &aa;
 	}
 	else
@@ -215,7 +237,8 @@ void MGL_EXPORT mgl_cont_y_val(HMGL gr, HCDT v, HCDT a, const char *sch, double
 	yy.Fill(sv, sv);
 	xx.Fill(gr->Min.x, gr->Max.x,'x');
 	zz.Fill(gr->Min.z, gr->Max.z,'y');
-	for(i=0;i<v->GetNx();i++)
+#pragma omp parallel for
+	for(long i=0;i<v->GetNx();i++)
 	{
 		register mreal v0 = v->v(i);
 		mgl_cont_gen(gr,v0,a,&xx,&yy,&zz,gr->GetC(ss,v0),text,0);
@@ -225,7 +248,7 @@ void MGL_EXPORT mgl_cont_y_val(HMGL gr, HCDT v, HCDT a, const char *sch, double
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_cont_z_val(HMGL gr, HCDT v, HCDT a, const char *sch, double sv, const char *opt)
 {
-	register long i,j,k,n=a->GetNx(),m=a->GetNy(),l=a->GetNz();
+	long n=a->GetNx(),m=a->GetNy(),l=a->GetNz();
 	if(mgl_isnan(sv))	sv = gr->GetOrgX('x');
 	if(n<2 || m<2)	{	gr->SetWarn(mglWarnLow,"ContZ");	return;	}
 	if(sv<gr->Min.x || sv>gr->Max.x)	{	gr->SetWarn(mglWarnSlc,"ContZ");	return;	}
@@ -242,20 +265,25 @@ void MGL_EXPORT mgl_cont_z_val(HMGL gr, HCDT v, HCDT a, const char *sch, double
 	{
 		aa.Create(n,m);
 		mreal d = (l-1)*(sv - gr->Min.z)/(gr->Max.z - gr->Min.z);
-		k = long(d);	d = d - k;
+		long k = long(d);	d = d - k;
 		if(k>l-2)	{	k=l-2;	d=1;	}
 		if(k<0)		{	k=0;	d=0;	}
 		const mglData *ma=dynamic_cast<const mglData *>(a);
-		if(ma)	for(j=0;j<m;j++)	for(i=0;i<n;i++)
-			aa.a[i+n*j] = ma->a[i+n*(j+m*k)]*(1-d) + d*ma->a[i+n*m+n*(j+m*k)];
-		else	for(j=0;j<m;j++)	for(i=0;i<n;i++)
-			aa.a[i+n*j] = a->v(i,j,k)*(1-d) + d*a->v(i,j,k+1);
+		if(ma)
+#pragma omp parallel for collapse(2)
+			for(long j=0;j<m;j++)	for(long i=0;i<n;i++)
+				aa.a[i+n*j] = ma->a[i+n*(j+m*k)]*(1-d) + d*ma->a[i+n*m+n*(j+m*k)];
+		else
+#pragma omp parallel for collapse(2)
+			for(long j=0;j<m;j++)	for(long i=0;i<n;i++)
+				aa.a[i+n*j] = a->v(i,j,k)*(1-d) + d*a->v(i,j,k+1);
 		a = &aa;
 	}
 	zz.Fill(sv, sv);
 	yy.Fill(gr->Min.y, gr->Max.y,'y');
 	xx.Fill(gr->Min.x, gr->Max.x,'x');
-	for(i=0;i<v->GetNx();i++)
+#pragma omp parallel for
+	for(long i=0;i<v->GetNx();i++)
 	{
 		register mreal v0 = v->v(i);
 		mgl_cont_gen(gr,v0,a,&xx,&yy,&zz,gr->GetC(ss,v0),text,0);
@@ -330,7 +358,7 @@ void MGL_EXPORT mgl_cont_z_val_(uintptr_t *gr, uintptr_t *v, uintptr_t *a, const
 void MGL_EXPORT mgl_contf_gen(HMGL gr, mreal v1, mreal v2, HCDT a, HCDT x, HCDT y, HCDT z, mreal c, long ak);
 void MGL_EXPORT mgl_contf_x_val(HMGL gr, HCDT v, HCDT a, const char *sch, double sv, const char *opt)
 {
-	register long i,j,k,n=a->GetNx(),m=a->GetNy(),l=a->GetNz();
+	long n=a->GetNx(),m=a->GetNy(),l=a->GetNz();
 	if(mgl_isnan(sv))	sv = gr->GetOrgX('x');
 	if(n<2 || m<2)	{	gr->SetWarn(mglWarnLow,"ContFX");	return;	}
 	if(sv<gr->Min.x || sv>gr->Max.x)	{	gr->SetWarn(mglWarnSlc,"ContFX");	return;	}
@@ -343,14 +371,18 @@ void MGL_EXPORT mgl_contf_x_val(HMGL gr, HCDT v, HCDT a, const char *sch, double
 	{
 		aa.Create(m,l);	xx.Create(m,l);	yy.Create(m,l);	zz.Create(m,l);
 		mreal d = (n-1)*(sv - gr->Min.x)/(gr->Max.x - gr->Min.x);
-		k = long(d);	d = d - k;
+		long k = long(d);	d = d - k;
 		if(k>n-2)	{	k=n-2;	d=1;	}
 		if(k<0)		{	k=0;	d=0;	}
 		const mglData *ma=dynamic_cast<const mglData *>(a);
-		if(ma)	for(j=0;j<l;j++)	for(i=0;i<m;i++)
-			aa.a[i+m*j] = ma->a[k+n*(i+m*j)]*(1-d) + d*ma->a[k+1+n*(i+m*j)];
-		else	for(j=0;j<l;j++)	for(i=0;i<m;i++)
-			aa.a[i+m*j] = a->v(k,i,j)*(1-d) + d*a->v(k+1,i,j);
+		if(ma)
+#pragma omp parallel for collapse(2)
+			for(long j=0;j<l;j++)	for(long i=0;i<m;i++)
+				aa.a[i+m*j] = ma->a[k+n*(i+m*j)]*(1-d) + d*ma->a[k+1+n*(i+m*j)];
+		else
+#pragma omp parallel for collapse(2)
+			for(long j=0;j<l;j++)	for(long i=0;i<m;i++)
+				aa.a[i+m*j] = a->v(k,i,j)*(1-d) + d*a->v(k+1,i,j);
 		a = &aa;
 	}
 	else
@@ -358,7 +390,8 @@ void MGL_EXPORT mgl_contf_x_val(HMGL gr, HCDT v, HCDT a, const char *sch, double
 	xx.Fill(sv, sv);
 	yy.Fill(gr->Min.y, gr->Max.y,'x');
 	zz.Fill(gr->Min.z, gr->Max.z,'y');
-	for(i=0;i<v->GetNx()-1;i++)
+#pragma omp parallel for
+	for(long i=0;i<v->GetNx()-1;i++)
 	{
 		register mreal v0 = v->v(i);
 		mgl_contf_gen(gr,v0,v->v(i+1),a,&xx,&yy,&zz,gr->GetC(ss,v0),0);
@@ -368,7 +401,7 @@ void MGL_EXPORT mgl_contf_x_val(HMGL gr, HCDT v, HCDT a, const char *sch, double
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_contf_y_val(HMGL gr, HCDT v, HCDT a, const char *sch, double sv, const char *opt)
 {
-	register long i,j,k,n=a->GetNx(),m=a->GetNy(),l=a->GetNz();
+	long n=a->GetNx(),m=a->GetNy(),l=a->GetNz();
 	if(mgl_isnan(sv))	sv = gr->GetOrgX('x');
 	if(n<2 || m<2)	{	gr->SetWarn(mglWarnLow,"ContFY");	return;	}
 	if(sv<gr->Min.x || sv>gr->Max.x)	{	gr->SetWarn(mglWarnSlc,"ContFY");	return;	}
@@ -381,14 +414,18 @@ void MGL_EXPORT mgl_contf_y_val(HMGL gr, HCDT v, HCDT a, const char *sch, double
 	{
 		aa.Create(n,l);	xx.Create(n,l);	yy.Create(n,l);	zz.Create(n,l);
 		mreal d = (m-1)*(sv - gr->Min.y)/(gr->Max.y - gr->Min.y);
-		k = long(d);	d = d - k;
+		long k = long(d);	d = d - k;
 		if(k>m-2)	{	k=m-2;	d=1;	}
 		if(k<0)		{	k=0;	d=0;	}
 		const mglData *ma=dynamic_cast<const mglData *>(a);
-		if(ma)	for(j=0;j<l;j++)	for(i=0;i<n;i++)
-			aa.a[i+n*j] = ma->a[i+n*(k+m*j)]*(1-d) + d*ma->a[i+n+n*(k+m*j)];
-		else	for(j=0;j<l;j++)	for(i=0;i<n;i++)
-			aa.a[i+n*j] = a->v(i,k,j)*(1-d) + d*a->v(i,k+1,j);
+		if(ma)
+#pragma omp parallel for collapse(2)
+			for(long j=0;j<l;j++)	for(long i=0;i<n;i++)
+				aa.a[i+n*j] = ma->a[i+n*(k+m*j)]*(1-d) + d*ma->a[i+n+n*(k+m*j)];
+		else
+#pragma omp parallel for collapse(2)
+			for(long j=0;j<l;j++)	for(long i=0;i<n;i++)
+				aa.a[i+n*j] = a->v(i,k,j)*(1-d) + d*a->v(i,k+1,j);
 		a = &aa;
 	}
 	else
@@ -396,7 +433,8 @@ void MGL_EXPORT mgl_contf_y_val(HMGL gr, HCDT v, HCDT a, const char *sch, double
 	yy.Fill(sv, sv);
 	xx.Fill(gr->Min.x, gr->Max.x,'x');
 	zz.Fill(gr->Min.z, gr->Max.z,'y');
-	for(i=0;i<v->GetNx()-1;i++)
+#pragma omp parallel for
+	for(long i=0;i<v->GetNx()-1;i++)
 	{
 		register mreal v0 = v->v(i);
 		mgl_contf_gen(gr,v0,v->v(i+1),a,&xx,&yy,&zz,gr->GetC(ss,v0),0);
@@ -406,7 +444,7 @@ void MGL_EXPORT mgl_contf_y_val(HMGL gr, HCDT v, HCDT a, const char *sch, double
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_contf_z_val(HMGL gr, HCDT v, HCDT a, const char *sch, double sv, const char *opt)
 {
-	register long i,j,k,n=a->GetNx(),m=a->GetNy(),l=a->GetNz();
+	long n=a->GetNx(),m=a->GetNy(),l=a->GetNz();
 	if(mgl_isnan(sv))	sv = gr->GetOrgX('x');
 	if(n<2 || m<2)	{	gr->SetWarn(mglWarnLow,"ContFZ");	return;	}
 	if(sv<gr->Min.x || sv>gr->Max.x)	{	gr->SetWarn(mglWarnSlc,"ContFZ");	return;	}
@@ -420,20 +458,25 @@ void MGL_EXPORT mgl_contf_z_val(HMGL gr, HCDT v, HCDT a, const char *sch, double
 	{
 		aa.Create(n,m);
 		mreal d = (l-1)*(sv - gr->Min.z)/(gr->Max.z - gr->Min.z);
-		k = long(d);	d = d - k;
+		long k = long(d);	d = d - k;
 		if(k>l-2)	{	k=l-2;	d=1;	}
 		if(k<0)		{	k=0;	d=0;	}
 		const mglData *ma=dynamic_cast<const mglData *>(a);
-		if(ma)	for(j=0;j<m;j++)	for(i=0;i<n;i++)
-			aa.a[i+n*j] = ma->a[i+n*(j+m*k)]*(1-d) + d*ma->a[i+n*m+n*(j+m*k)];
-		else	for(j=0;j<m;j++)	for(i=0;i<n;i++)
-			aa.a[i+n*j] = a->v(i,j,k)*(1-d) + d*a->v(i,j,k+1);
+		if(ma)
+#pragma omp parallel for collapse(2)
+			for(long j=0;j<m;j++)	for(long i=0;i<n;i++)
+				aa.a[i+n*j] = ma->a[i+n*(j+m*k)]*(1-d) + d*ma->a[i+n*m+n*(j+m*k)];
+		else
+#pragma omp parallel for collapse(2)
+			for(long j=0;j<m;j++)	for(long i=0;i<n;i++)
+				aa.a[i+n*j] = a->v(i,j,k)*(1-d) + d*a->v(i,j,k+1);
 		a = &aa;
 	}
 	zz.Fill(sv, sv);
 	yy.Fill(gr->Min.y, gr->Max.y,'y');
 	xx.Fill(gr->Min.x, gr->Max.x,'x');
-	for(i=0;i<v->GetNx()-1;i++)
+#pragma omp parallel for
+	for(long i=0;i<v->GetNx()-1;i++)
 	{
 		register mreal v0 = v->v(i);
 		mgl_contf_gen(gr,v0,v->v(i+1),a,&xx,&yy,&zz,gr->GetC(ss,v0),0);
diff --git a/src/parser.cpp b/src/parser.cpp
index 8924f7a..4bb4124 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -20,6 +20,7 @@
 #include <ctype.h>
 #include "mgl2/parser.h"
 #include "mgl2/canvas_cf.h"
+#include "mgl2/base.h"
 //-----------------------------------------------------------------------------
 #ifdef WIN32
 #include <io.h>
@@ -33,38 +34,22 @@ void MGL_EXPORT mgl_ask_gets(const wchar_t *quest, wchar_t *res)
 {	printf("%ls\n",quest);	if(!fgetws(res,1024,stdin))	*res=0;	}
 //-----------------------------------------------------------------------------
 mglFunc::mglFunc(const mglFunc &f)
-{	pos=f.pos;	narg=f.narg;	wcsncpy(func,f.func,64);	}
+{	pos=f.pos;	narg=f.narg;	func=f.func;	}
 mglFunc::mglFunc(long p, const wchar_t *f)
 {
-	pos = p;
-	register size_t i;
-	for(i=0;(isalnum(f[i]) || f[i]=='_') && i<63;i++)	func[i]=f[i];
-	func[i]=0;	narg = wcstol(f+i+1,0,0);
+	pos = p;	func = f;
+	size_t i;
+	for(i=0;(isalnum(f[i]) || f[i]=='_');i++);
+	narg = wcstol(f+i+1,0,0);	func = func.substr(0,i);
 	if(narg<0 || narg>9)	narg=0;
 }
 //-----------------------------------------------------------------------------
-size_t mglParser::GetParLen()
+long mglParser::IsFunc(const std::wstring &name, int *na)
 {
-	register size_t i,s=0,t;
-	for(i=0;i<40;i++)
-	{	t = par[i].length();	s = s<t?t:s;	}
-	return s;
-}
-//-----------------------------------------------------------------------------
-size_t mglParser::GetParLen(const wchar_t *str)
-{
-	register size_t nump=0, is;
-	for(is=0;is<wcslen(str);is++)	if(str[is]=='$')	nump++;
-	return nump*GetParLen();
-}
-//-----------------------------------------------------------------------------
-long mglParser::IsFunc(const wchar_t *name, int *na)
-{
-	register size_t i;
-	for(i=0;i<func.size();i++)
+	for(size_t i=0;i<func.size();i++)
 	{
 		const mglFunc &f = func[i];
-		if(!wcscmp(f.func, name))
+		if(f.func==name)
 		{	if(na)	*na=f.narg;	return f.pos;	}
 	}
 	return 0;
@@ -84,11 +69,10 @@ void mglParser::ScanFunc(const wchar_t *line)
 //-----------------------------------------------------------------------------
 MGL_NO_EXPORT wchar_t *mgl_str_copy(const char *s)
 {
-	wchar_t *str = new wchar_t[strlen(s)+1];
-	register long i;
-	for(i=0;i<int(strlen(s));i++)	str[i] = s[i];
-	str[i] = 0;
-	return str;
+	register size_t i,l=strlen(s);
+	wchar_t *str = new wchar_t[l+1];
+	for(i=0;i<l;i++)	str[i] = s[i];
+	str[i] = 0;	return str;
 }
 //-----------------------------------------------------------------------------
 int MGL_NO_EXPORT mgl_cmd_cmp(const void *a, const void *b)
@@ -98,9 +82,9 @@ int MGL_NO_EXPORT mgl_cmd_cmp(const void *a, const void *b)
 	return strcmp(aa->name, bb->name);
 }
 //-----------------------------------------------------------------------------
-bool check_for_name(const wchar_t *s)
+bool mgl_check_for_name(const std::wstring &s)
 {
-	return !isalpha(s[0])||wcschr(s,'.')||wcschr(s,':')||wcschr(s,'(')||wcschr(s,')');
+	return !isalpha(s[0])||s.find_first_of(L".:()")!=std::wstring::npos;
 }
 //-----------------------------------------------------------------------------
 mglCommand *mglParser::FindCommand(const char *com)
@@ -117,13 +101,13 @@ mglCommand *mglParser::FindCommand(const char *com)
 //-----------------------------------------------------------------------------
 mglCommand *mglParser::FindCommand(const wchar_t *com)
 {
-	size_t s = 15<wcslen(com)?15:wcslen(com);
+	size_t s = 15<mgl_wcslen(com)?15:mgl_wcslen(com);
 	char cmd[16];	wcstombs(cmd,com,s+1);	cmd[s]=0;
 	return FindCommand(cmd);
 }
 //-----------------------------------------------------------------------------
 // return values : 0 -- OK, 1 -- wrong arguments, 2 -- wrong command, 3 -- unclosed string
-int mglParser::Exec(mglGraph *gr, const wchar_t *com, long n, mglArg *a, const wchar_t *var, const wchar_t *opt)
+int mglParser::Exec(mglGraph *gr, const wchar_t *com, long n, mglArg *a, const std::wstring &var, const wchar_t *opt)
 {
 	int i;
 	const char *id="dsn";
@@ -137,8 +121,8 @@ int mglParser::Exec(mglGraph *gr, const wchar_t *com, long n, mglArg *a, const w
 	if(!rts || rts->type==6)	return 2;
 	if(rts->type == 4)
 	{
-		if(n<1 || check_for_name(var))	return 2;
-		mglVar *v = AddVar(var);
+		if(n<1 || mgl_check_for_name(var))	return 2;
+		mglVar *v = AddVar(var.c_str());
 		v->Create(1,1,1);
 		a[0].type = 0;	a[0].d = v;
 		a[0].w = var;	k[0] = 'd';
@@ -146,7 +130,7 @@ int mglParser::Exec(mglGraph *gr, const wchar_t *com, long n, mglArg *a, const w
 	char *o=0;
 	if(opt && *opt)	// TODO: parse arguments of options
 	{
-		long len = wcslen(opt);
+		long len = mgl_wcslen(opt);
 		o = new char[len+1];
 		for(i=0;i<len+1;i++)	o[i]=opt[i];
 	}
@@ -186,14 +170,12 @@ mglParser::mglParser(bool setsize)
 	Cmd = mgls_base_cmd;
 	AllowSetSize=setsize;	AllowFileIO=true;
 	Once = true;
-	op1 = new wchar_t[4096];	op2 = new wchar_t[4096];
 	fval = new mglData[40];
 }
 //-----------------------------------------------------------------------------
 mglParser::~mglParser()
 {
-	DeleteAll();
-	delete []op1;	delete []op2;	delete []fval;
+	DeleteAll();	delete []fval;
 	if(Cmd && Cmd!=mgls_base_cmd)	delete []Cmd;
 }
 //-----------------------------------------------------------------------------
@@ -213,60 +195,42 @@ void mglParser::DeleteAll()
 //-----------------------------------------------------------------------------
 void mglParser::AddParam(int n, const char *str)
 {
-	unsigned s = mbstowcs(0,str,0)+1;
-	wchar_t *wcs = new wchar_t[s];
-	mbstowcs(wcs,str,s);
-	AddParam(n,wcs);
-	delete []wcs;
+	MGL_TO_WCS(str,AddParam(n,wcs));
 }
 //-----------------------------------------------------------------------------
 int mglParser::Parse(mglGraph *gr, const char *str, long pos)
 {
-	size_t s = mbstowcs(0,str,0)+1;
-	wchar_t *wcs = new wchar_t[s];
-	mbstowcs(wcs,str,s);
-	int r = Parse(gr,wcs,pos);
-	delete []wcs;	return r;
+	int r=0;
+	MGL_TO_WCS(str,r = Parse(gr,wcs,pos));
+	return r;
 }
 //-----------------------------------------------------------------------------
 mglVar *mglParser::AddVar(const char *str)
 {
-	size_t s = mbstowcs(0,str,0)+1;
-	wchar_t *wcs = new wchar_t[s];
-	mbstowcs(wcs,str,s);
-	mglVar *v = AddVar(wcs);
-	delete []wcs;
+	mglVar *v=0;
+	MGL_TO_WCS(str,v = AddVar(wcs));
 	return v;
 }
 //-----------------------------------------------------------------------------
 mglVar *mglParser::FindVar(const char *str)
 {
 	if(!str || *str==0) 	return DataList;
-	size_t s = mbstowcs(0,str,0)+1;
-	wchar_t *wcs = new wchar_t[s];
-	mbstowcs(wcs,str,s);
-	mglVar *v = FindVar(wcs);
-	delete []wcs;
+	mglVar *v=DataList;
+	MGL_TO_WCS(str,v = FindVar(wcs));
 	return v;
 }
 //-----------------------------------------------------------------------------
 mglNum *mglParser::AddNum(const char *str)
 {
-	size_t s = mbstowcs(0,str,0)+1;
-	wchar_t *wcs = new wchar_t[s];
-	mbstowcs(wcs,str,s);
-	mglNum *v = AddNum(wcs);
-	delete []wcs;
+	mglNum *v=0;
+	MGL_TO_WCS(str,v = AddNum(wcs));
 	return v;
 }
 //-----------------------------------------------------------------------------
 mglNum *mglParser::FindNum(const char *str)
 {
-	size_t s = mbstowcs(0,str,0)+1;
-	wchar_t *wcs = new wchar_t[s];
-	mbstowcs(wcs,str,s);
-	mglNum *v = FindNum(wcs);
-	delete []wcs;
+	mglNum *v=0;
+	MGL_TO_WCS(str,v = FindNum(wcs));
 	return v;
 }
 //-----------------------------------------------------------------------------
@@ -319,10 +283,10 @@ mglNum *mglParser::AddNum(const wchar_t *name)
 	return v;
 }
 //-----------------------------------------------------------------------------
-int mglFindArg(const wchar_t *str)
+int mglFindArg(const std::wstring &str)
 {
-	register long l=0,k=0,i;//,j,len=strlen(lst);
-	for(i=0;i<long(wcslen(str));i++)
+	register long l=0,k=0,i;
+	for(i=0;i<long(str.length());i++)
 	{
 		if(str[i]=='\'') l++;
 		if(str[i]=='{') k++;
@@ -336,86 +300,53 @@ int mglFindArg(const wchar_t *str)
 	return 0;
 }
 //-----------------------------------------------------------------------------
-bool mgls_suffix(const wchar_t *p, mglData *d, mreal *v)
-{
-	mreal x,y,z,k;
-	bool ok=false;
-	if(!wcscmp(p,L"a"))			{	ok = true;	*v = d->a[0];	}
-	else if(!wcscmp(p,L"fst"))	{	ok = true;	long i=-1,j=-1,l=-1;	*v = d->Find(0,i,j,l);	}
-	else if(!wcscmp(p,L"lst"))	{	ok = true;	long i=-1,j=-1,l=-1;	*v = d->Last(0,i,j,l);	}
-	else if(!wcscmp(p,L"nx"))	{	ok = true;	*v=d->nx;	}
-	else if(!wcscmp(p,L"ny"))	{	ok = true;	*v=d->ny;	}
-	else if(!wcscmp(p,L"nz"))	{	ok = true;	*v=d->nz;	}
-	else if(!wcscmp(p,L"max"))	{	ok = true;	*v=d->Maximal();	}
-	else if(!wcscmp(p,L"min"))	{	ok = true;	*v=d->Minimal();	}
-	else if(!wcscmp(p,L"sum"))	{	ok = true;	*v=d->Momentum('x',x,y);	}
-	else if(!wcscmp(p,L"mx"))	{	ok = true;	d->Maximal(x,y,z);		*v=x/d->nx;	}
-	else if(!wcscmp(p,L"my"))	{	ok = true;	d->Maximal(x,y,z);		*v=y/d->ny;	}
-	else if(!wcscmp(p,L"mz"))	{	ok = true;	d->Maximal(x,y,z);		*v=z/d->nz;	}
-	else if(!wcscmp(p,L"ax"))	{	ok = true;	d->Momentum('x',x,y);	*v=x/d->nx;	}
-	else if(!wcscmp(p,L"ay"))	{	ok = true;	d->Momentum('y',x,y);	*v=x/d->ny;	}
-	else if(!wcscmp(p,L"az"))	{	ok = true;	d->Momentum('z',x,y);	*v=x/d->nz;	}
-	else if(!wcscmp(p,L"wx"))	{	ok = true;	d->Momentum('x',x,y);	*v=y/d->nx;	}
-	else if(!wcscmp(p,L"wy"))	{	ok = true;	d->Momentum('y',x,y);	*v=y/d->ny;	}
-	else if(!wcscmp(p,L"wz"))	{	ok = true;	d->Momentum('z',x,y);	*v=y/d->nz;	}
-	else if(!wcscmp(p,L"sx"))	{	ok = true;	d->Momentum('x',x,y,z,k);	*v=z/d->nx;	}
-	else if(!wcscmp(p,L"sy"))	{	ok = true;	d->Momentum('y',x,y,z,k);	*v=z/d->ny;	}
-	else if(!wcscmp(p,L"sz"))	{	ok = true;	d->Momentum('z',x,y,z,k);	*v=z/d->nz;	}
-	else if(!wcscmp(p,L"kx"))	{	ok = true;	d->Momentum('x',x,y,z,k);	*v=k/d->nx;	}
-	else if(!wcscmp(p,L"ky"))	{	ok = true;	d->Momentum('y',x,y,z,k);	*v=k/d->ny;	}
-	else if(!wcscmp(p,L"kz"))	{	ok = true;	d->Momentum('z',x,y,z,k);	*v=k/d->nz;	}
-	else if(!wcscmp(p,L"aa"))	{	ok = true;	d->Momentum('a',x,y);	*v=x;	}
-	else if(!wcscmp(p,L"wa"))	{	ok = true;	d->Momentum('a',x,y);	*v=y;	}
-	else if(!wcscmp(p,L"sa"))	{	ok = true;	d->Momentum('a',x,y,z,k);*v=z;	}
-	else if(!wcscmp(p,L"ka"))	{	ok = true;	d->Momentum('a',x,y,z,k);*v=k;	}
-	return ok;
-}
-//-----------------------------------------------------------------------------
 // convert substrings to arguments
-mglData mglFormulaCalc(const wchar_t *string, mglParser *arg);
-void mglParser::FillArg(mglGraph *gr, int k, wchar_t **arg, mglArg *a)
+mglData MGL_NO_EXPORT mglFormulaCalc(std::wstring str, mglParser *arg);
+void mglParser::FillArg(mglGraph *gr, int k, std::wstring *arg, mglArg *a)
 {
 	register long n;
 	for(n=1;n<k;n++)
 	{
-		mglVar *v, *u;
-		mglNum *f;
+		mglVar *v, *u;	mglNum *f;
 		a[n-1].type = -1;
 		if(arg[n][0]=='|')	a[n-1].type = -1;
-		else if(arg[n][0]=='\'')
-		{	// this is string (simplest case)
+		else if(arg[n][0]=='\'')	// this is string (simplest case)
+		{
 			a[n-1].type = 1;
-			wchar_t *w=arg[n],ch,*f,buf[32];
-			long i,l,ll=wcslen(w);
-			for(l=i=1;i<ll;i++)
+			std::wstring &w=arg[n],f;
+			wchar_t buf[32];
+			long i,i1,ll=w.length();
+			for(i=1;i<ll;i++)
 			{
 				if(w[i]=='\'')
 				{
 					if(i==ll-1)	continue;
-					i++;	f = w+i;
+					i++;	i1 = i;
+					if(w[i1]==',')	i1++;
+					if(w[i1]==0)	continue;
 					for(;i<ll && w[i]!='\'';i++);
-					ch=w[i];	w[i]=0;
-					if(*f==',')	f++;
-					if(*f==0)	continue;
-					mglData d = mglFormulaCalc(f, this);	w[i]=ch;
-					mglprintf(buf,32,L"%g",d.a[0]);	a[n-1].w += buf;
+					if(i>i1)
+					{
+						mglData d = mglFormulaCalc(w.substr(i1,i-i1-(w[i]=='\''?1:0)), this);
+						mglprintf(buf,32,L"%g",d.a[0]);	a[n-1].w += buf;
+					}
 				}
 				else	a[n-1].w += w[i];
 			}
 		}
 		else if(arg[n][0]=='{')
 		{	// this is temp data
-			arg[n][wcslen(arg[n])-1] = 0;
 			u=new mglVar;	u->temp=true;
-			a[n-1].w = L"/*"+std::wstring(arg[n]+1)+L"*/";
+			std::wstring s = arg[n].substr(1,arg[n].length()-2);
+			a[n-1].w = L"/*"+s+L"*/";
 			if(DataList)	u->MoveAfter(DataList);
 			else			DataList = u;
 			a[n-1].type = 0;	a[n-1].d = u;
-			ParseDat(gr, arg[n]+1, *u);
+			ParseDat(gr, s, *u);
 		}
-		else if((v = FindVar(arg[n]))!=0)	// have to find normal variables (for data creation)
+		else if((v = FindVar(arg[n].c_str()))!=0)	// have to find normal variables (for data creation)
 		{	a[n-1].type=0;	a[n-1].d=v;	a[n-1].w=v->s;	}
-		else if((f = FindNum(arg[n]))!=0)	// have to find normal variables (for data creation)
+		else if((f = FindNum(arg[n].c_str()))!=0)	// have to find normal variables (for data creation)
 		{	a[n-1].type=2;	a[n-1].d=0;	a[n-1].v=f->d;	a[n-1].w = f->s;	}
 		else
 		{	// parse all numbers and formulas by unified way
@@ -425,7 +356,7 @@ void mglParser::FillArg(mglGraph *gr, int k, wchar_t **arg, mglArg *a)
 			else
 			{
 				u=new mglVar;	u->temp=true;	u->Set(d);
-				a[n-1].w = L"/*"+std::wstring(arg[n])+L"*/";
+				a[n-1].w = L"/*"+arg[n]+L"*/";
 				if(DataList)	u->MoveAfter(DataList);
 				else			DataList = u;
 				a[n-1].type = 0;	a[n-1].d = u;
@@ -435,18 +366,17 @@ void mglParser::FillArg(mglGraph *gr, int k, wchar_t **arg, mglArg *a)
 }
 //-----------------------------------------------------------------------------
 // return values: 0 - not found, 1 - OK, 2 - wrong arguments, 3 - wrong command, 4 - string too long
-int mglParser::PreExec(mglGraph *, long k, wchar_t **arg, mglArg *a)
+int mglParser::PreExec(mglGraph *, long k, std::wstring *arg, mglArg *a)
 {
 	long n=0;
 	mglVar *v;
-	if(!wcscmp(L"delete",arg[0]))	// parse command "delete"
+	if(!arg[0].compare(L"delete") && k==2)	// parse command "delete"
 	{
-		if(k<2)	return 2;
-		DeleteVar(arg[1]);	n=1;
+		DeleteVar(arg[1].c_str());	n=1;
 	}
-	else if(!wcscmp(L"list",arg[0]))	// parse command "list"
+	else if(!arg[0].compare(L"list"))	// parse command "list"
 	{
-		if(k<3 || check_for_name(arg[1]))	return 2;
+		if(k<3 || mgl_check_for_name(arg[1]))	return 2;
 		long nx=0, ny=1,j=0,i,t=0;
 		char ch;
 		for(i=2;i<k;i++)
@@ -465,7 +395,7 @@ int mglParser::PreExec(mglGraph *, long k, wchar_t **arg, mglArg *a)
 			}
 			if(ch=='|' && t==1)		{	nx = j>nx ? j:nx;	j=0;	ny++;	}
 		}
-		v = AddVar(arg[1]);
+		v = AddVar(arg[1].c_str());
 		if(t==1)	nx = j>nx ? j:nx;
 		if(t==1)	// list of numeric values
 		{
@@ -513,135 +443,133 @@ int mglParser::PreExec(mglGraph *, long k, wchar_t **arg, mglArg *a)
 	return n;
 }
 //-----------------------------------------------------------------------------
-void mglParser::PutArg(const wchar_t *string, wchar_t *str, bool def)
+void mglParser::PutArg(std::wstring &str, bool def)
 {
-	wchar_t *sb = new wchar_t[wcslen(string)+1], *t;
-	if(def)	str = str+10;
-	register long n;
-	while((t=wcschr(str,'$'))!=0)
+	size_t pos = str.find('$',def?10:0);
+	while(pos<str.length())
 	{
-		wcscpy(sb,t+2);	t[0]=0;
-		n = t[1]-'0';	if(n>=0 && n<=9)	wcscat(str,par[n].c_str());
-		n = t[1]-'a';	if(n>=0 && n<='z'-'a')	wcscat(str,par[n+10].c_str());
-		if(t[1]=='$')	wcscat(str,L"\xffff");
-		wcscat(str,sb);
+		wchar_t ch = str[pos+1];
+		if(ch>='0' && ch<='9')	str.replace(pos,2,par[ch-'0']);
+		if(ch>='a' && ch<='z')	str.replace(pos,2,par[ch-'a'+10]);
+		if(ch=='$')	str.replace(pos,2,L"\xffff");
+		pos = str.find('$',def?10:0);
 	}
-	delete []sb;
-	while((t=wcschr(str,L'\xffff'))!=0)	*t='$';
+	while((pos = str.find(L'\xffff'))<str.length())	str[pos]='$';
 }
 //-----------------------------------------------------------------------------
-// return values: 0 - OK, 1 - wrong arguments, 2 - wrong command, 3 - string too long, 4 -- unclosed string
-int mglParser::Parse(mglGraph *gr, const wchar_t *string, long pos)
+std::wstring mgl_trim_ws(const std::wstring &str)
 {
-	if(Stop)	return 0;
-	size_t lstr = wcslen(string)+2+GetParLen(string);
-	wchar_t *str, *arg[1024],*t;
-	wchar_t *s = new wchar_t[lstr];
-	memset(s,0,lstr*sizeof(wchar_t));
-	wcscpy(s,string);	mgl_wcstrim(s);	str = s;
-	long n,k=0,m=0,mm=0;
-	// try parse ':' -- several commands in line
-	for(n=0;n<long(wcslen(str));n++)
-	{
-		if(str[n]=='\'' && (n==0 || str[n-1]!='\\'))	k++;
-		if(k%2)	continue;
-		if(str[n]=='(')	m++;
-		if(str[n]==')')	m--;
-		if(str[n]=='{')	mm++;
-		if(str[n]=='}')	mm--;
-		if(str[n]=='#')	break;
-		if((str[n]==':' || str[n]=='\n') && k%2==0 && m==0 && mm==0)
-		{
-			str[n]=0;
-			int res=Parse(gr,str,pos);
-			if(!res)	res=Parse(gr,str+n+1,pos);
-			delete []s;	return res;
-		}
-	}
-	if(k%2 || m || mm)	return 4;	// strings is not closed
-	// define parameters or start cycle
-	if(!skip() && !wcsncmp(str,L"def",3) && (str[6]==' ' || str[6]=='\t'))
+	size_t n=str.length(), k, i;
+	for(k=0;k<n;k++)	if(str[k]>' ')	break;
+	for(i=n;i>k;i--)	if(str[i-1]>' ')	break;
+	return str.substr(k,i-k);
+}
+//-----------------------------------------------------------------------------
+int mglParser::ParseDef(std::wstring &str)
+{
+	if(!skip() && !str.compare(0,3,L"def") && (str[6]==' ' || str[6]=='\t'))
 	{
-		PutArg(string,str,true);
-		if(!wcsncmp(str+3,L"ine",3))
+		int res = 1;	mreal d;
+		PutArg(str,true);
+		const std::wstring s = mgl_trim_ws(str.substr(7));
+		if(!str.compare(3,3,L"ine"))
 		{
-			str += 7;	mgl_wcstrim(str);//	int res = 1;
-			int nn = str[1]<='9' ? str[1]-'0' : (str[1]>='a' ? str[1]-'a'+10:-1);
-			if(*str=='$' && nn>=0 && nn<='z'-'a'+10)
+			int nn = s[1]<='9' ? s[1]-'0' : (s[1]>='a' ? s[1]-'a'+10:-1);
+			if(s[0]=='$' && nn>=0 && nn<='z'-'a'+10)
 			{
-				str +=2;	mgl_wcstrim(str);
-				AddParam(nn, str);	delete []s;	return 0;
+				AddParam(nn, mgl_trim_ws(s.substr(2)).c_str());	return 1;
 			}
-			else	str -= 7;
 		}
-		if(!wcsncmp(str+3,L"num",3))
+		if(!str.compare(3,3,L"num"))
 		{
-			str += 7;	mgl_wcstrim(str);	int res = 1;
-			int nn = str[1]<='9' ? str[1]-'0' : (str[1]>='a' ? str[1]-'a'+10:-1);
-			if(*str=='$' && nn>=0 && nn<='z'-'a'+10)
+			int nn = s[1]<='9' ? s[1]-'0' : (s[1]>='a' ? s[1]-'a'+10:-1);
+			if(s[0]=='$' && nn>=0 && nn<='z'-'a'+10)
 			{
-				res = 0;	str +=2;	mgl_wcstrim(str);
-				mreal d = mglFormulaCalc(str, this).a[0];
-				char *buf=new char[128];
-				snprintf(buf,128,"%g",d);
-				AddParam(nn, buf);	delete []buf;
+				res = 0;
+				d = mglFormulaCalc(mgl_trim_ws(s.substr(2)), this).a[0];
+				char buf[32];	snprintf(buf,32,"%g",d);	AddParam(nn, buf);
 			}
-			delete []s;	return res;
+			return res+1;
 		}
-		if(!wcsncmp(str+3,L"chr",3))
+		if(!str.compare(3,3,L"chr"))
 		{
-			str += 7;	mgl_wcstrim(str);	int res = 1;
-			int nn = str[1]<='9' ? str[1]-'0' : (str[1]>='a' ? str[1]-'a'+10:-1);
-			if(*str=='$' && nn>=0 && nn<='z'-'a'+10)
+			int nn = s[1]<='9' ? s[1]-'0' : (s[1]>='a' ? s[1]-'a'+10:-1);
+			if(s[0]=='$' && nn>=0 && nn<='z'-'a'+10)
 			{
-				res = 0;	str +=2;	mgl_wcstrim(str);
-				mreal d=mglFormulaCalc(str, this).a[0];
-				wchar_t buf[2]={0,0};	buf[0] = wchar_t(d);
-				AddParam(nn, buf);
+				res = 0;
+				d=mglFormulaCalc(mgl_trim_ws(s.substr(2)), this).a[0];
+				wchar_t buf[2]={0,0};	buf[0] = wchar_t(d);	AddParam(nn, buf);
 			}
-			delete []s;	return res;
+			return res+1;
 		}
 	}
-	if(!skip() && !wcsncmp(str,L"ask",3) && (str[3]==' ' || str[3]=='\t'))
+	if(!skip() && !str.compare(0,3,L"ask") && (str[3]==' ' || str[3]=='\t'))
 	{
-		PutArg(string,str,true);
-		str += 4;	mgl_wcstrim(str);//	int res = 1;
-		int nn = str[1]<='9' ? str[1]-'0' : (str[1]>='a' ? str[1]-'a'+10:-1);
-		if(*str=='$' && nn>=0 && nn<='z'-'a'+10)
+		PutArg(str,true);
+		std::wstring s = mgl_trim_ws(str.substr(4));
+		int nn = s[1]<='9' ? s[1]-'0' : (s[1]>='a' ? s[1]-'a'+10:-1);
+		if(s[0]=='$' && nn>=0 && nn<='z'-'a'+10)
 		{
 			static wchar_t res[1024];
-			str +=2;	mgl_wcstrim(str);
-			if(*str=='\'')	{	str++;	str[wcslen(str)-1]=0;	}
+			s = mgl_trim_ws(s.substr(2));
+			if(s[0]=='\'')	s=s.substr(1,s.length()-2);
 			if(mgl_ask_func)
-			{	mgl_ask_func(str,res);	if(*res)	AddParam(nn, res);	}
-			delete []s;	return mgl_ask_func?0:1;
+			{	mgl_ask_func(s.c_str(),res);	if(*res)	AddParam(nn, res);	}
+			return mgl_ask_func?1:2;
 		}
-		else	return 1;
+		else	return 2;
 	}
-	wcscpy(str,string);			mgl_wcstrim(str);
-	if(!skip() && !wcsncmp(str,L"for",3) && (str[3]==' ' || str[3]=='\t'))
+	if(!skip() && !str.compare(0,3,L"for") && (str[3]==' ' || str[3]=='\t'))
 	{
-		for(t=str+4;*t<=' ';t++);
+		size_t i;
+		for(i=4;str[i]<=' ';i++);
 		// if command have format 'for $N ...' then change it to 'for N ...'
-		if(*t=='$' && t[1]>='0' && t[1]<='9')	*t = ' ';
-		if(*t=='$' && t[1]>='a' && t[1]<='z')	*t = ' ';
+		if(str[i]=='$' && str[i+1]>='0' && str[i+1]<='9')	str[i] = ' ';
+		if(str[i]=='$' && str[i+1]>='a' && str[i+1]<='z')	str[i] = ' ';
 	}
-
+	return 0;
+}
+//-----------------------------------------------------------------------------
+// return values: 0 - OK, 1 - wrong arguments, 2 - wrong command, 3 - string too long, 4 -- unclosed string
+int mglParser::Parse(mglGraph *gr, std::wstring str, long pos)
+{
+	if(Stop)	return 0;
+	std::wstring arg[1024];
+	str=mgl_trim_ws(str);
+	long n,k=0,m=0,mm=0,res;
+	// try parse ':' -- several commands in line
+	for(n=0;n<long(str.length());n++)
+	{
+		if(str[n]=='\'' && (n==0 || str[n-1]!='\\'))	k++;
+		if(k%2)	continue;
+		if(str[n]=='(')	m++;	if(str[n]==')')	m--;
+		if(str[n]=='{')	mm++;	if(str[n]=='}')	mm--;
+		if(str[n]=='#')	break;
+		if((str[n]==':' || str[n]=='\n') && k%2==0 && m==0 && mm==0)
+		{
+			res=Parse(gr,str.substr(0,n),pos);
+			if(!res)	res=Parse(gr,str.substr(n+1),pos);
+			return res;
+		}
+	}
+	if(k%2 || m || mm)	return 4;	// strings is not closed
+	// define parameters or start cycle
+	res = ParseDef(str);	if(res)	return res-1;
 	// parse arguments (parameters $1, ..., $9)
-	PutArg(string,str,false);	mgl_wcstrim(str);
+	PutArg(str,false);	str=mgl_trim_ws(str);
 
-	wchar_t *opt=0;
+	std::wstring opt;
 	for(k=0;k<1024;k++)	// parse string to substrings (by spaces)
 	{
 		n = mglFindArg(str);
 		if(n<1)	// this is option
 		{
-			if(str[-n]==';')	opt = str-n+1;
-			if(n<0)	str[-n]=0;
+			if(str[-n]==';')	opt = str.substr(-n+1);
+			if(n<0)	str = str.substr(0,-n);
 			break;
 		}
-		str[n]=0;	arg[k] = str;//	k++;
-		str = str+n+1;	mgl_wcstrim(str);
+		arg[k] = str.substr(0,n);
+		str = mgl_trim_ws(str.substr(n+1));
 	}
 	// try to find last argument
 	if(str[0]!=0 && str[0]!='#' && str[0]!=';')	{	arg[k] = str;	k++;	}
@@ -652,23 +580,23 @@ int mglParser::Parse(mglGraph *gr, const wchar_t *string, long pos)
 		mglArg *a = new mglArg[k];
 		FillArg(gr, k, arg, a);
 		// execute first special (program-flow-control) commands
-		if(!skip() && !wcscmp(arg[0],L"stop"))
-		{	Stop = true;	delete []s;	delete []a;	return 0;	}
-		if(!wcscmp(arg[0],L"func"))
-		{	delete []s;	delete []a;	return 0;	}
-		n = FlowExec(gr, arg[0],k-1,a);
-		if(n)		{	delete []s;	delete []a;	return n-1;	}
-		if(skip())	{	delete []s;	delete []a;	return 0;	}
-		if(!wcscmp(arg[0],L"define"))
+		if(!skip() && !arg[0].compare(L"stop"))
+		{	Stop = true;	delete []a;	return 0;	}
+		if(!arg[0].compare(L"func"))
+		{	delete []a;	return 0;	}
+		n = FlowExec(gr, arg[0].c_str(),k-1,a);
+		if(n)		{	delete []a;	return n-1;	}
+		if(skip())	{	delete []a;	return 0;	}
+		if(!arg[0].compare(L"define"))
 		{
 			if(k==3)
 			{
-				mglNum *v=AddNum(arg[1]);
+				mglNum *v=AddNum(arg[1].c_str());
 				v->d = mglFormulaCalc(arg[2],this).a[0];
 			}
-			delete []s;	delete []a;	return k==3?0:1;
+			delete []a;	return k==3?0:1;
 		}
-		if(!wcscmp(arg[0],L"call"))
+		if(!arg[0].compare(L"call"))
 		{
 			n = 1;
 			if(a[0].type==1)
@@ -687,7 +615,7 @@ int mglParser::Parse(mglGraph *gr, const wchar_t *string, long pos)
 				{
 					mglFnStack fn;			fn.pos = pos;
 					for(int i=0;i<10;i++)	{	fn.par[i] = par[i];	par[i]=L"";	}
-					for(int i=1;i<k-1;i++)	AddParam(i,arg[i+1]);
+					for(int i=1;i<k-1;i++)	AddParam(i,arg[i+1].c_str());
 					fn_stack.push_back(fn);	n--;
 				}
 				else if(AllowFileIO)	// disable external scripts if AllowFileIO=false
@@ -708,9 +636,9 @@ int mglParser::Parse(mglGraph *gr, const wchar_t *string, long pos)
 					else	n=1;
 				}
 			}
-			delete []s;	delete []a;	return n;
+			delete []a;	return n;
 		}
-		if(!wcscmp(arg[0],L"for"))
+		if(!arg[0].compare(L"for"))
 		{
 			n = 1;
 			char ch = arg[1][0];
@@ -744,13 +672,13 @@ int mglParser::Parse(mglGraph *gr, const wchar_t *string, long pos)
 					AddParam(r, buf);	fval[r].ny = 1;
 				}
 			}
-			delete []s;	delete []a;	return n;
+			delete []a;	return n;
 		}
 		// alocate new arrays and execute the command itself
 		n = PreExec(gr, k, arg, a);
 		if(n>0)	n--;
-		else if(!wcscmp(L"setsize",arg[0]) && !AllowSetSize)	n = 2;
-		else	n = Exec(gr, arg[0],k-1,a, arg[1], opt);
+		else if(!arg[0].compare(L"setsize") && !AllowSetSize)	n = 2;
+		else	n = Exec(gr, arg[0].c_str(),k-1,a, arg[1].c_str(), opt.c_str());
 		delete []a;
 	}
 	mglVar *v = DataList, *u;
@@ -760,25 +688,24 @@ int mglParser::Parse(mglGraph *gr, const wchar_t *string, long pos)
 		if(v->temp)	{	if(DataList==v)	DataList = v->next;		delete v;	}
 		v = u;
 	}
-	delete []s;	return n;
+	return n;
 }
 //-----------------------------------------------------------------------------
 // return values: 0 - OK, 1 - wrong arguments, 2 - wrong command, 3 - string too long, 4 -- unclosed string
-int mglParser::ParseDat(mglGraph *gr, const wchar_t *string, mglData &res)
+int mglParser::ParseDat(mglGraph *gr, std::wstring str, mglData &res)
 {
-	wchar_t *str, *s = new wchar_t[wcslen(string)+1+GetParLen(string)],*arg[32];
-	str = s;
-	wcscpy(str,string);	mgl_wcstrim(str);
+	std::wstring arg[32];
+	mgl_trim_ws(str);
 	long n,k=0;
 	for(k=0;k<32;k++)	// parse string to substrings (by spaces)
 	{
 		n = mglFindArg(str);
-		if(n<1)	{	if(n<0)	str[-n]=0;	break;	}
-		str[n]=0;	arg[k] = str;//	k++;
-		str = str+n+1;	mgl_wcstrim(str);
+		if(n<1)	{	if(n<0)	str=str.substr(0,-n);	break;	}
+		arg[k] = str.substr(0,n);//	k++;
+		str = str.substr(n+1);	mgl_trim_ws(str);
 	}
 	// try to find last argument
-	if(str[0]!=0 && str[0]!='#' && str[0]!=';')	{	arg[k] = str;	k++;	}
+	if(!str.empty())	{	arg[k] = str;	k++;	}
 	if(k<1) n =0;
 	else
 	{	// fill arguments by its values
@@ -793,18 +720,18 @@ int mglParser::ParseDat(mglGraph *gr, const wchar_t *string, mglData &res)
 			kk += id[a[i].type];
 			a[i].s.assign(a[i].w.begin(),a[i].w.end());
 		}
-		mglCommand *rts=FindCommand(arg[0]);
+		mglCommand *rts=FindCommand(arg[0].c_str());
 		if(!rts || rts->type!=4)	n = 2;
 		else n = rts->exec(gr, k, a, kk.c_str(), 0);
 		delete []a;
 	}
-	delete []s;	return n;
+	return n;
 }
 //-----------------------------------------------------------------------------
-int mglParser::FlowExec(mglGraph *, const wchar_t *com, long m, mglArg *a)
+int mglParser::FlowExec(mglGraph *, const std::wstring &com, long m, mglArg *a)
 {
 	int n=-1;
-	if(!ifskip() && !wcscmp(com,L"once"))
+	if(!ifskip() && !com.compare(L"once"))
 	{
 		if(a[0].type==2)
 		{
@@ -814,7 +741,7 @@ int mglParser::FlowExec(mglGraph *, const wchar_t *com, long m, mglArg *a)
 		}
 		else n = 1;
 	}
-	else if(!Skip && !wcscmp(com,L"if"))
+	else if(!Skip && !com.compare(L"if"))
 	{
 		int cond;
 		if(a[0].type==2)
@@ -828,15 +755,15 @@ int mglParser::FlowExec(mglGraph *, const wchar_t *com, long m, mglArg *a)
 		if(n==0)
 		{	if_stack[if_pos] = cond;	if_pos = if_pos<39 ? if_pos+1 : 39;	}
 	}
-	else if(!Skip && !wcscmp(com,L"endif"))
+	else if(!Skip && !com.compare(L"endif"))
 	{	if_pos = if_pos>0 ? if_pos-1 : 0;	n = 0;	}
-	else if(!Skip && !wcscmp(com,L"else"))
+	else if(!Skip && !com.compare(L"else"))
 	{
 		if(if_pos>0)
 		{	n=0; if_stack[if_pos-1] = (if_stack[if_pos-1]&2)?2:3;	}
 		else n = 1;
 	}
-	else if(!Skip && !wcscmp(com,L"elseif"))
+	else if(!Skip && !com.compare(L"elseif"))
 	{
 		int cond;
 		if(if_pos<1 || m<1)	n = 1;
@@ -851,18 +778,18 @@ int mglParser::FlowExec(mglGraph *, const wchar_t *com, long m, mglArg *a)
 		else n = 1;
 		if(n==0)	if_stack[if_pos-1] = cond;
 	}
-	else if(!ifskip() && !Skip && !wcscmp(com,L"break"))
+	else if(!ifskip() && !Skip && !com.compare(L"break"))
 	{
 		if(if_pos==if_for[0])	if_pos = if_pos>0 ? if_pos-1 : 0;
 	}
-	else if(!skip() && !wcscmp(com, L"return"))	// parse command "delete"
+	else if(!skip() && !com.compare(L"return"))
 	{
 		if(fn_stack.size()<1)	return 2;
 		const mglFnStack &fn=fn_stack.back();
 		for(int i=0;i<10;i++)	par[i]=fn.par[i];
 		n = -fn.pos-1;	fn_stack.pop_back();
 	}
-	else if(!ifskip() && !Skip && !wcscmp(com,L"next"))
+	else if(!ifskip() && !Skip && !com.compare(L"next"))
 	{
 		if(if_pos==if_for[0])	if_pos = if_pos>0 ? if_pos-1 : 0;
 		int r = for_stack[0]-1;
@@ -883,7 +810,7 @@ int mglParser::FlowExec(mglGraph *, const wchar_t *com, long m, mglArg *a)
 			}
 		}
 	}
-	else if(!ifskip() && !Skip && !wcscmp(com,L"continue"))
+	else if(!ifskip() && !Skip && !com.compare(L"continue"))
 	{
 		if(if_pos==if_for[0])	if_pos = if_pos>0 ? if_pos-1 : 0;
 		int r = for_stack[0]-1;
@@ -917,7 +844,7 @@ void mglParser::Execute(mglGraph *gr, FILE *fp, bool print)
 void mglParser::Execute(mglGraph *gr, int n, const wchar_t **text)
 {
 	if(n<1 || text==0)	return;
-	long i, r;
+	long i, r, res=0;
 	char buf[64];
 	for_br=Skip=false;	if_pos=0;	ScanFunc(0);	fn_stack.clear();
 	for(i=0;i<n;i++)	ScanFunc(text[i]);
@@ -934,22 +861,24 @@ void mglParser::Execute(mglGraph *gr, int n, const wchar_t **text)
 		else if(gr->GetWarn()>0)	snprintf(buf,64," in line %ld\n", i+1);
 		else *buf=0;
 		if(*buf)	gr->SetWarn(-2,buf);
+		if(r>0 && r<5)	res=r;
 	}
+	int code[]={mglScrArg,	mglScrCmd,	mglScrLong,	mglScrStr};
+	if(res>0)	gr->SetWarn(code[res-1],"MGL Parser");
 }
 //-----------------------------------------------------------------------------
 void mglParser::Execute(mglGraph *gr, const wchar_t *text)
 {
-	size_t s = wcslen(text)+1;
+	size_t s = mgl_wcslen(text)+1, n=1;
 	wchar_t *wcs = new wchar_t[s];
 	const wchar_t **str;
-	register size_t i, n=1;
-	for(i=0;i<s;i++)	if(text[i]=='\n')	n++;
+	for(size_t i=0;i<s;i++)	if(text[i]=='\n')	n++;
 	str = (const wchar_t **)malloc(n*sizeof(wchar_t *));
 	memcpy(wcs, text, s*sizeof(wchar_t));
 	str[0] = wcs;	n=1;
 	long next=0;
 	Stop = false;
-	for(i=0;i<s;i++)
+	for(size_t i=0;i<s;i++)
 	{
 		if(text[i]=='\\')	next = i;
 		else if(text[i]>' ')next = 0;
@@ -970,12 +899,7 @@ void mglParser::Execute(mglGraph *gr, const wchar_t *text)
 //-----------------------------------------------------------------------------
 void mglParser::Execute(mglGraph *gr, const char *text)
 {
-	size_t s = mbstowcs(0,text,0)+1;
-	wchar_t *wcs = new wchar_t[s];
-	memset(wcs,0,s*sizeof(wchar_t));
-	mbstowcs(wcs,text,s);
-	Execute(gr, wcs);
-	delete []wcs;
+	MGL_TO_WCS(text,	Execute(gr, wcs));
 }
 //-----------------------------------------------------------------------------
 void mglParser::DeleteVar(mglVar *v)
@@ -1097,11 +1021,9 @@ long MGL_EXPORT mgl_parser_cmd_num(HMPR pr)
 //---------------------------------------------------------------------------
 HMDT MGL_EXPORT mgl_parser_calc(HMPR pr, const char *formula)
 {
-	size_t s = mbstowcs(0,formula,0)+1;
-	wchar_t *wcs = new wchar_t[s];
-	mbstowcs(wcs,formula,s);
-	HMDT d = mgl_parser_calcw(pr,wcs);
-	delete []wcs;	return d;	
+	HMDT d=0;
+	MGL_TO_WCS(formula,d = mgl_parser_calcw(pr,wcs));
+	return d;
 }
 HMDT MGL_EXPORT mgl_parser_calcw(HMPR pr, const wchar_t *formula)
 {	mglData *d = new mglData(mglFormulaCalc(formula,pr)); 	return d;	}
diff --git a/src/pde.cpp b/src/pde.cpp
index 7d4c391..448da41 100644
--- a/src/pde.cpp
+++ b/src/pde.cpp
@@ -19,8 +19,8 @@
  ***************************************************************************/
 #include "mgl2/data.h"
 #include "mgl2/eval.h"
-#include <complex>
-#define dual	std::complex<double>
+#include "mgl2/thread.h"
+#include "mgl2/base.h"
 #define GAMMA	0.1
 //-----------------------------------------------------------------------------
 struct mgl_pde_ham
@@ -36,38 +36,49 @@ MGL_NO_EXPORT void *mgl_pde_hprep(void *par)
 	mglThreadD *t=(mglThreadD *)par;
 	const mgl_pde_ham *f = (const mgl_pde_ham *)t->v;
 	mglFormula *eqs = f->eqs;
-	register long i,j,i0, nx=2*f->nx, ny=2*f->ny;
-	mreal var[MGL_VS];
-	dual *a = f->a,*h;
-	memset(var,0,('z'-'a')*sizeof(mreal));
-	var['z'-'a'] = f->zz;
-	for(i0=t->id,h=f->hxy;i0<t->n;i0+=mglNumThr)
-	{
-		i = i0%nx;	j = i0/nx;			var['u'-'a'] = abs(a[i0]);
-		var['x'-'a'] = f->xx+f->dx*i;	var['p'-'a'] = 0;
-		var['y'-'a'] = f->yy+f->dy*j;	var['q'-'a'] = 0;
-		h[i0] = dual(-eqs->CalcD(var,'i'), eqs->Calc(var))*f->dd;
-	}
-	if(f->ny>2)	for(i0=t->id,h=f->huy;i0<t->n;i0+=mglNumThr)	// step 3/2
-	{
-		i = i0%nx;	j = i0/nx;			var['u'-'a'] = abs(a[i0]);
-		var['x'-'a'] = f->xs;			var['p'-'a'] = f->dp*(i<nx/2 ? i:nx-i);
-		var['y'-'a'] = f->yy+f->dy*j;	var['q'-'a'] = 0;
-		h[i0] = dual(-eqs->CalcD(var,'i'), eqs->Calc(var))*f->dd;
-	}
-	for(i0=t->id,h=f->huv;i0<t->n;i0+=mglNumThr)	// step 2
-	{
-		i = i0%nx;	j = i0/nx;			var['u'-'a'] = abs(a[i0]);
-		var['x'-'a'] = f->xs;			var['p'-'a'] = f->dp*(i<nx/2 ? i:nx-i);
-		var['y'-'a'] = f->ys;			var['q'-'a'] = f->dq*(j<ny/2 ? j:ny-j);
-		h[i0] = dual(-eqs->CalcD(var,'i'), eqs->Calc(var))*f->dd;
-	}
-	if(f->ny>2)	for(i0=t->id,h=f->hxv;i0<t->n;i0+=mglNumThr)	// step 3/2
+	long nx=2*f->nx, ny=2*f->ny;
+	dual *a = f->a;
+
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel
+#endif
 	{
-		i = i0%nx;	j = i0/nx;			var['u'-'a'] = abs(a[i0]);
-		var['x'-'a'] = f->xx+f->dx*i;	var['p'-'a'] = 0;
-		var['y'-'a'] = f->ys;			var['q'-'a'] = f->dq*(j<ny/2 ? j:ny-j);
-		h[i0] = dual(-eqs->CalcD(var,'i'), eqs->Calc(var))*f->dd;
+		mreal var[MGL_VS];	memset(var,0,MGL_VS*sizeof(mreal));
+		var['z'-'a'] = f->zz;
+#pragma omp for nowait
+		for(long i0=t->id;i0<t->n;i0+=mglNumThr)
+		{
+			register long i = i0%nx, j = i0/nx;		var['u'-'a'] = abs(a[i0]);
+			var['x'-'a'] = f->xx+f->dx*i;	var['p'-'a'] = 0;
+			var['y'-'a'] = f->yy+f->dy*j;	var['q'-'a'] = 0;
+			f->hxy[i0] = dual(-eqs->CalcD(var,'i'), eqs->Calc(var))*f->dd;
+		}
+		if(f->ny>2)
+#pragma omp for nowait
+			for(long i0=t->id;i0<t->n;i0+=mglNumThr)	// step 3/2
+			{
+				register long i = i0%nx, j = i0/nx;		var['u'-'a'] = abs(a[i0]);
+				var['x'-'a'] = f->xs;			var['p'-'a'] = f->dp*(i<nx/2 ? i:nx-i);
+				var['y'-'a'] = f->yy+f->dy*j;	var['q'-'a'] = 0;
+				f->huy[i0] = dual(-eqs->CalcD(var,'i'), eqs->Calc(var))*f->dd;
+			}
+#pragma omp for nowait
+		for(long i0=t->id;i0<t->n;i0+=mglNumThr)	// step 2
+		{
+			register long i = i0%nx, j = i0/nx;		var['u'-'a'] = abs(a[i0]);
+			var['x'-'a'] = f->xs;			var['p'-'a'] = f->dp*(i<nx/2 ? i:nx-i);
+			var['y'-'a'] = f->ys;			var['q'-'a'] = f->dq*(j<ny/2 ? j:ny-j);
+			f->huv[i0] = dual(-eqs->CalcD(var,'i'), eqs->Calc(var))*f->dd;
+		}
+		if(f->ny>2)
+#pragma omp for nowait
+			for(long i0=t->id;i0<t->n;i0+=mglNumThr)	// step 3/2
+			{
+				register long i = i0%nx, j = i0/nx;		var['u'-'a'] = abs(a[i0]);
+				var['x'-'a'] = f->xx+f->dx*i;	var['p'-'a'] = 0;
+				var['y'-'a'] = f->ys;			var['q'-'a'] = f->dq*(j<ny/2 ? j:ny-j);
+				f->hxv[i0] = dual(-eqs->CalcD(var,'i'), eqs->Calc(var))*f->dd;
+			}
 	}
 	return 0;
 }
@@ -76,14 +87,12 @@ HMDT MGL_EXPORT mgl_pde_solve(HMGL gr, const char *ham, HCDT ini_re, HCDT ini_im
 {
 	gr->SaveState(opt);
 	mglPoint Min=gr->Min, Max=gr->Max;
-	mglData *res=new mglData;
-	int nx=ini_re->GetNx(), ny=ini_re->GetNy();
-	int nz = int((Max.z-Min.z)/dz)+1;
+	long nx=ini_re->GetNx(), ny=ini_re->GetNy(), nz = long((Max.z-Min.z)/dz)+1;
 	if(nx<2 || nz<2 || Max.x==Min.x)			// Too small data
-	{	gr->SetWarn(mglWarnLow,"PDE");	return res;	}
+	{	gr->SetWarn(mglWarnLow,"PDE");	return 0;	}
 	if(ini_im->GetNx()*ini_im->GetNy() != nx*ny)// Wrong dimensions
-	{	gr->SetWarn(mglWarnDim,"PDE");	return res;	}
-	mgl_data_create(res, nz, nx, ny);
+	{	gr->SetWarn(mglWarnDim,"PDE");	return 0;	}
+	mglData *res=new mglData(nz, nx, ny);
 
 	mglFormula eqs(ham);
 	dual *a = new dual[4*nx*ny], hh0;	// Add "damping" area
@@ -93,17 +102,18 @@ HMDT MGL_EXPORT mgl_pde_solve(HMGL gr, const char *ham, HCDT ini_re, HCDT ini_im
 	dual *hy = new dual[2*ny], *hu = new dual[2*nx];
 	mreal *dmp = new mreal[4*nx*ny];
 	memset(a,0,4*nx*ny*sizeof(dual));
-	register int i,j,k,i0;
-	for(j=0;j<ny;j++)	for(i=0;i<nx;i++)	// Initial conditions
+	memset(dmp,0,4*nx*ny*sizeof(mreal));
+#pragma omp parallel for collapse(2)
+	for(long j=0;j<ny;j++)	for(long i=0;i<nx;i++)	// Initial conditions
 	{
-		i0 = i+nx/2+2*nx*(j+ny/2);
+		register long i0 = i+nx/2+2*nx*(j+ny/2);
 		a[i0] = dual(ini_re->v(i,j), ini_im->v(i,j));
 		res->a[nz*(i+nx*j)] = abs(a[i0]);
 	}
-	memset(dmp,0,4*nx*ny*sizeof(mreal));
-	for(j=0;j<2*ny;j++)	for(i=0;i<2*nx;i++)	// step 1
+#pragma omp parallel for collapse(2)
+	for(long j=0;j<2*ny;j++)	for(long i=0;i<2*nx;i++)	// step 1
 	{
-		i0 = i+2*nx*j;
+		register long i0 = i+2*nx*j;
 		if(i<nx/2)		dmp[i0] += GAMMA*mgl_ipow((nx/2-i)/(nx/2.),2);
 		if(i>3*nx/2)	dmp[i0] += GAMMA*mgl_ipow((i-3*nx/2-1)/(nx/2.),2);
 		if(j<ny/2)		dmp[i0] += GAMMA*mgl_ipow((ny/2-j)/(ny/2.),2);
@@ -113,7 +123,7 @@ HMDT MGL_EXPORT mgl_pde_solve(HMGL gr, const char *ham, HCDT ini_re, HCDT ini_im
 	mreal dp = M_PI/(Max.x-Min.x)/k0, dq = M_PI/(Max.y-Min.y)/k0;
 	mreal xs=(Min.x+Max.x)/2, ys=(Min.y+Max.y)/2;
 //	double xx = Min.x - dx*nx/2, yy = Min.x - dy*ny/2;
-	double ff = ny>1?4*nx*ny:2*nx, dd = k0*dz;
+	double dd = k0*dz;
 
 	mgl_pde_ham tmp;tmp.eqs = &eqs;
 	tmp.nx = nx;	tmp.ny = ny;	tmp.a=a;		tmp.hxy=hxy;
@@ -124,41 +134,50 @@ HMDT MGL_EXPORT mgl_pde_solve(HMGL gr, const char *ham, HCDT ini_re, HCDT ini_im
 	// prepare fft. NOTE: slow procedures due to unknown nx, ny.
 	void *wsx, *wtx = mgl_fft_alloc(2*nx,&wsx,1);
 	void *wsy, *wty = mgl_fft_alloc(2*ny,&wsy,1);
-	for(k=1;k<nz;k++)
+	for(long k=1;k<nz;k++)
 	{
-		if(gr->Stop)
-		{
-			mgl_fft_free(wtx,&wsx,1);	mgl_fft_free(wty,&wsy,1);
-			delete []a;		delete []dmp;	delete []hxy;	delete []hxv;
-			delete []huy;	delete []huv;	delete []hx;	delete []hy;
-			delete []hu;	delete []hv;	return 0;
-		}
+		if(gr->Stop)	continue;
 		tmp.zz = Min.z+dz*k;
 		memset(hxy,0,4*nx*ny*sizeof(dual));	memset(hxv,0,4*nx*ny*sizeof(dual));
 		memset(huv,0,4*nx*ny*sizeof(dual));	memset(huy,0,4*nx*ny*sizeof(dual));
 		mglStartThread(mgl_pde_hprep,0,4*nx*ny,0,0,0,0,&tmp);
-		for(i=0;i<2*nx;i++)	{	hx[i] = hxv[i];			hu[i] = huv[i];		}
-		for(j=0;j<2*ny;j++)	{	hy[j] = huy[2*nx*j];	hv[j] = huv[2*nx*j];}
+#pragma omp parallel for
+		for(long i=0;i<2*nx;i++)	{	hx[i] = hxv[i];			hu[i] = huv[i];		}
+#pragma omp parallel for
+		for(long j=0;j<2*ny;j++)	{	hy[j] = huy[2*nx*j];	hv[j] = huv[2*nx*j];}
 		// rearrange arrays
 		hh0=hu[0]/2.;
-		if(ny>1)	for(i=0;i<2*nx;i++) for(j=0;j<2*ny;j++)
-		{
-			i0 = i+2*nx*j;
-			huy[i0] -= (hu[i]+hy[j]-hh0)/2.;	huv[i0] -= (hu[i]+hv[j]-hh0)/2.;
-			hxy[i0] -= (hx[i]+hy[j]-hh0)/2.;	hxv[i0] -= (hx[i]+hv[j]-hh0)/2.;
-		}
+		if(ny>1)
+#pragma omp parallel for collapse(2)
+			for(long i=0;i<2*nx;i++) for(long j=0;j<2*ny;j++)
+			{
+				register long i0 = i+2*nx*j;
+				huy[i0] -= (hu[i]+hy[j]-hh0)/2.;	huv[i0] -= (hu[i]+hv[j]-hh0)/2.;
+				hxy[i0] -= (hx[i]+hy[j]-hh0)/2.;	hxv[i0] -= (hx[i]+hv[j]-hh0)/2.;
+			}
 		// solve equation
-		for(i=0;i<4*nx*ny;i++)	a[i] *= exp(hxy[i])*exp(-double(dmp[i]*dz))/ff;
-		for(i=0;i<2*ny;i++)		mgl_fft((double *)(a+i*2*nx), 1, 2*nx, wtx, wsx, false);
-		for(i=0;i<4*nx*ny;i++)	a[i] *= exp(huy[i]);
-		if(ny>1) for(i=0;i<2*nx;i++)	mgl_fft((double *)(a+i), 2*nx, 2*ny, wty, wsy, false);
-		for(i=0;i<4*nx*ny;i++)	a[i] *= exp(huv[i]);
-		for(i=0;i<2*ny;i++)		mgl_fft((double *)(a+2*i*nx), 1, 2*nx, wtx, wsx, true);
-		for(i=0;i<4*nx*ny;i++)	a[i] *= exp(hxv[i]);
-		if(ny>1) for(i=0;i<2*nx;i++)	mgl_fft((double *)(a+i), 2*nx, 2*ny, wty, wsy, true);
-		for(i=0;i<nx;i++)	for(j=0;j<ny;j++)	// save result
+#pragma omp parallel for
+		for(long i=0;i<4*nx*ny;i++)	a[i] *= exp(hxy[i])*exp(-double(dmp[i]*dz));
+//#pragma omp parallel for	// NOTE I need separate wsx for each thread, but it is too slow to allocate/dealocate it each step
+		for(long i=0;i<2*ny;i++)	mgl_fft((double *)(a+i*2*nx), 1, 2*nx, wtx, wsx, false);
+#pragma omp parallel for
+		for(long i=0;i<4*nx*ny;i++)	a[i] *= exp(huy[i]);
+		if(ny>1)
+//#pragma omp parallel for
+			for(long i=0;i<2*nx;i++)	mgl_fft((double *)(a+i), 2*nx, 2*ny, wty, wsy, false);
+#pragma omp parallel for
+		for(long i=0;i<4*nx*ny;i++)	a[i] *= exp(huv[i]);
+//#pragma omp parallel for
+		for(long i=0;i<2*ny;i++)	mgl_fft((double *)(a+2*i*nx), 1, 2*nx, wtx, wsx, true);
+#pragma omp parallel for
+		for(long i=0;i<4*nx*ny;i++)	a[i] *= exp(hxv[i]);
+		if(ny>1)
+//#pragma omp parallel for
+			for(long i=0;i<2*nx;i++)	mgl_fft((double *)(a+i), 2*nx, 2*ny, wty, wsy, true);
+#pragma omp parallel for collapse(2)
+		for(long i=0;i<nx;i++)	for(long j=0;j<ny;j++)	// save result
 		{
-			i0 = i+nx/2+2*nx*(j+ny/2);
+			register long i0 = i+nx/2+2*nx*(j+ny/2);
 			res->a[k+nz*(i+nx*j)] = abs(a[i0]);
 		}
 	}
@@ -172,10 +191,9 @@ HMDT MGL_EXPORT mgl_pde_solve(HMGL gr, const char *ham, HCDT ini_re, HCDT ini_im
 //-----------------------------------------------------------------------------
 HMDT MGL_EXPORT mgl_ode_solve(void (*func)(const mreal *x, mreal *dx, void *par), int n, mreal *x0, mreal dt, mreal tmax, void *par)
 {
-	mglData *res=new mglData;
-	if(tmax<dt)	return res;	// nothing to do
+	if(tmax<dt)	return 0;	// nothing to do
 	int nt = int(tmax/dt)+1;
-	mgl_data_create(res,n,nt,1);
+	mglData *res=new mglData(n,nt);
 	mreal *x=new mreal[n], *k1=new mreal[n], *k2=new mreal[n], *k3=new mreal[n], *v=new mreal[n], hh=dt/2;
 	register long i,k;
 	// initial conditions
@@ -295,16 +313,18 @@ MGL_NO_EXPORT void *mgl_qo2d_hprep(void *par)
 	mglThreadD *t=(mglThreadD *)par;
 	mgl_qo2d_ham *f = (mgl_qo2d_ham *)t->v;
 	mgl_ap *ra = f->ra;
-	
+
 	const mreal *r = f->r;
-	mreal tt, x1, hh;
-	register long i, nx=t->n;
-	for(i=t->id;i<nx;i+=mglNumThr)
+	long nx=t->n;
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i=t->id;i<nx;i+=mglNumThr)
 	{
 		// x terms
-		x1 = (2*i-nx+1)*f->dr;	hh = 1 - ra->t1*x1;
+		register mreal x1 = (2*i-nx+1)*f->dr, hh = 1 - ra->t1*x1;
 		hh = sqrt(sqrt(0.041+hh*hh*hh*hh));
-		tt = (ra->pt + ra->d1*x1)/hh - ra->pt;
+		register mreal tt = (ra->pt + ra->d1*x1)/hh - ra->pt;
 		f->hx[i] = f->ham(abs(f->a[i]), r[0]+ra->x1*x1, r[1]+ra->y1*x1, r[3]+ra->x0*tt, r[4]+ra->y0*tt, f->par) - f->h0/2.;
 		// u-y terms
 		x1 = f->dk/2*(i<nx/2 ? i:i-nx);
@@ -320,27 +340,26 @@ MGL_NO_EXPORT void *mgl_qo2d_hprep(void *par)
 //-----------------------------------------------------------------------------
 HMDT MGL_EXPORT mgl_qo2d_func(dual (*ham)(mreal u, mreal x, mreal y, mreal px, mreal py, void *par), void *par, HCDT ini_re, HCDT ini_im, HCDT ray_dat, mreal r, mreal k0, HMDT xx, HMDT yy)
 {
-	mglData *res=new mglData;
 	const mglData *ray=dynamic_cast<const mglData *>(ray_dat);	// NOTE: Ray must be mglData!
-	if(!ray)	return res;
-	int nx=ini_re->GetNx(), nt=ray->ny, n7=ray->nx;
-	if(nx<2 || ini_im->GetNx()!=nx || nt<2)	return res;
-	mgl_data_create(res,nx,nt,1);
+	if(!ray)	return 0;
+	long nx=ini_re->GetNx(), nt=ray->ny, n7=ray->nx;
+	if(nx<2 || ini_im->GetNx()!=nx || nt<2)	return 0;
+	mglData *res=new mglData(nx,nt,1);
 
 	dual *a=new dual[2*nx], *hu=new dual[2*nx],  *hx=new dual[2*nx];
 	double *dmp=new double[2*nx];
 	mgl_ap *ra = new mgl_ap[nt];	mgl_init_ra(nt, n7, ray->a, ra);	// ray
-	register int i;
-
-	mreal dr = r/(nx-1), dk = M_PI*(nx-1)/(k0*r*nx), tt, x1, hh, B1, pt0;
 
+	mreal dr = r/(nx-1), dk = M_PI*(nx-1)/(k0*r*nx);
 	memset(dmp,0,2*nx*sizeof(double));
-	for(i=0;i<nx/2;i++)	// prepare damping
+#pragma omp parallel for
+	for(long i=0;i<nx/2;i++)	// prepare damping
 	{
-		x1 = (nx/2-i)/(nx/2.);
+		register mreal x1 = (nx/2-i)/(nx/2.);
 		dmp[2*nx-1-i] = dmp[i] = 30*GAMMA*x1*x1/k0;
 	}
-	for(i=0;i<nx;i++)	a[i+nx/2] = dual(ini_re->v(i),ini_im->v(i));	// init
+#pragma omp parallel for
+	for(long i=0;i<nx;i++)	a[i+nx/2] = dual(ini_re->v(i),ini_im->v(i));	// init
 	void *wsx, *wtx = mgl_fft_alloc(2*nx,&wsx,1);
 	if(xx && yy)	{	xx->Create(nx,nt);	yy->Create(nx,nt);	}
 
@@ -348,25 +367,30 @@ HMDT MGL_EXPORT mgl_qo2d_func(dual (*ham)(mreal u, mreal x, mreal y, mreal px, m
 	tmp.hx=hx;	tmp.hu=hu;	tmp.dmp=dmp;	tmp.par=par;
 	tmp.dr=dr;	tmp.dk=dk;	tmp.ham=ham;	tmp.a=a;
 	// start calculation
-	for(int k=0;k<nt;k++)
+	for(long k=0;k<nt;k++)
 	{
-		for(i=0;i<nx;i++)	// "save"
+#pragma omp parallel for
+		for(long i=0;i<nx;i++)	// "save"
 			res->a[i+k*nx]=abs(a[i+nx/2])*sqrt(ra[0].ch/ra[k].ch);
-		if(xx && yy)	for(i=0;i<nx;i++)	// prepare xx, yy
-		{
-			x1 = (2*i-nx+1)*dr;
-			xx->a[i+k*nx] = ray->a[n7*k] + ra[k].x1*x1;	// new coordinates
-			yy->a[i+k*nx] = ray->a[n7*k+1] + ra[k].y1*x1;
-		}
+		if(xx && yy)
+#pragma omp parallel for
+			for(long i=0;i<nx;i++)	// prepare xx, yy
+			{
+				register mreal x1 = (2*i-nx+1)*dr;
+				xx->a[i+k*nx] = ray->a[n7*k] + ra[k].x1*x1;	// new coordinates
+				yy->a[i+k*nx] = ray->a[n7*k+1] + ra[k].y1*x1;
+			}
 		tmp.r=ray->a+n7*k;	tmp.ra=ra+k;
-		hh = ra[k].pt*(1/sqrt(sqrt(1.041))-1);	// 0.041=0.45^4 -- minimal value of h
+		mreal hh = ra[k].pt*(1/sqrt(sqrt(1.041))-1);	// 0.041=0.45^4 -- minimal value of h
 		tmp.h0 = ham(0, tmp.r[0], tmp.r[1], tmp.r[3]+ra[k].x0*hh, tmp.r[4]+ra[k].x0*hh, par);
 		mglStartThread(mgl_qo2d_hprep,0,2*nx,0,0,0,0,&tmp);
 		// Step for field
 		dual dt = dual(0, -ra[k].dt*k0);
-		for(i=0;i<2*nx;i++)		a[i] *= exp(hx[i]*dt);
+#pragma omp parallel for
+		for(long i=0;i<2*nx;i++)	a[i] *= exp(hx[i]*dt);
 		mgl_fft((double *)a, 1, 2*nx, wtx, wsx, false);
-		for(i=0;i<2*nx;i++)		a[i] *= exp(hu[i]*dt)/(2.*nx);
+#pragma omp parallel for
+		for(long i=0;i<2*nx;i++)	a[i] *= exp(hu[i]*dt);
 		mgl_fft((double *)a, 1, 2*nx, wtx, wsx, true);
 
 /*		// Calculate B1			// TODO make more general scheme later!!!
@@ -432,17 +456,18 @@ MGL_NO_EXPORT void *mgl_qo3d_hprep(void *par)
 	mglThreadD *t=(mglThreadD *)par;
 	mgl_qo3d_ham *f = (mgl_qo3d_ham *)t->v;
 	mgl_ap *ra = f->ra;
-
 	const mreal *r = f->r;
-	mreal tt, x1, x2, hh;
-	register long ii,i,j, nx=t->n;
-	for(ii=t->id;ii<nx*nx;ii+=mglNumThr)
+	long nx=t->n;
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long ii=t->id;ii<nx*nx;ii+=mglNumThr)
 	{
-		i = ii%nx;	j = ii/nx;
+		register long i = ii%nx, j = ii/nx;
 		// x-y terms
-		x1 = (2*i-nx+1)*f->dr;	x2 = (2*j-nx+1)*f->dr;	hh = 1-ra->t1*x1-ra->t2*x2;
+		register mreal x1 = (2*i-nx+1)*f->dr, x2 = (2*j-nx+1)*f->dr, hh = 1-ra->t1*x1-ra->t2*x2;
 		hh = sqrt(sqrt(0.041+hh*hh*hh*hh));
-		tt = (ra->pt + ra->d1*x1 + ra->d2*x2)/hh - ra->pt;
+		register mreal tt = (ra->pt + ra->d1*x1 + ra->d2*x2)/hh - ra->pt;
 		f->hxy[ii] = f->ham(abs(f->a[i]), r[0]+ra->x1*x1+ra->x2*x2, r[1]+ra->y1*x1+ra->y2*x2, r[2]+ra->z1*x1+ra->z2*x2, r[3]+ra->x0*tt, r[4]+ra->y0*tt, r[5]+ra->z0*tt, f->par);
 		// x-v terms
 		x1 = (2*i-nx+1)*f->dr;	x2 = f->dk/2*(j<nx/2 ? j:j-nx);	hh = 1-ra->t1*x1;
@@ -465,11 +490,13 @@ MGL_NO_EXPORT void *mgl_qo3d_post(void *par)
 {
 	mglThreadD *t=(mglThreadD *)par;
 	mgl_qo3d_ham *f = (mgl_qo3d_ham *)t->v;
-	
-	register long ii,i,j, nx=t->n;
-	for(ii=t->id;ii<nx*nx;ii+=mglNumThr)
+	long nx=t->n;
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long ii=t->id;ii<nx*nx;ii+=mglNumThr)
 	{
-		i = ii%nx;	j = ii/nx;
+		register long i = ii%nx, j = ii/nx;
 		f->hxy[ii] -= (f->hx[i]+f->hy[j]-f->h0/2.)/2.;
 		if(imag(f->hxy[ii])>0)	f->hxy[ii] = f->hxy[ii].real();
 		f->hxv[ii] -= (f->hx[i]+f->hv[j]-f->h0/2.)/2.;
@@ -486,31 +513,30 @@ MGL_NO_EXPORT void *mgl_qo3d_post(void *par)
 //-----------------------------------------------------------------------------
 HMDT MGL_EXPORT mgl_qo3d_func(dual (*ham)(mreal u, mreal x, mreal y, mreal z, mreal px, mreal py, mreal pz, void *par), void *par, HCDT ini_re, HCDT ini_im, HCDT ray_dat, mreal r, mreal k0, HMDT xx, HMDT yy, HMDT zz)
 {
-	mglData *res=new mglData;
 	const mglData *ray=dynamic_cast<const mglData *>(ray_dat);	// NOTE: Ray must be mglData!
-	if(!ray)	return res;
-	int nx=ini_re->GetNx(), nt=ray->ny, n7=ray->nx;	// NOTE: only square grids are supported now (for simplicity)
-	if(nx<2 || ini_re->GetNx()!=nx || ini_im->GetNx()*ini_im->GetNy()!=nx*nx || nt<2)	return res;
-	mgl_data_create(res,nx,nx,nt);
+	if(!ray)	return 0;
+	long nx=ini_re->GetNx(), nt=ray->ny, n7=ray->nx;	// NOTE: only square grids are supported now (for simplicity)
+	if(nx<2 || ini_re->GetNx()!=nx || ini_im->GetNx()*ini_im->GetNy()!=nx*nx || nt<2)	return 0;
+	mglData *res=new mglData(nx,nx,nt);
 
 	dual *a=new dual[4*nx*nx], *huv=new dual[4*nx*nx],  *hxy=new dual[4*nx*nx], *huy=new dual[4*nx*nx],  *hxv=new dual[4*nx*nx];
 	dual *hu=new dual[2*nx],  *hx=new dual[2*nx], *hy=new dual[2*nx],  *hv=new dual[2*nx];
 	mreal *dmp=new mreal[4*nx*nx];
 	mgl_ap *ra = new mgl_ap[nt];
 	mgl_init_ra(nt, n7, ray->a, ra);	// prepare ray
-	register int i,j,ii;
-
-	mreal dr = r/(nx-1), dk = M_PI*(nx-1)/(k0*r*nx), tt, x1, x2, hh, B1, pt0;
 
+	mreal dr = r/(nx-1), dk = M_PI*(nx-1)/(k0*r*nx);
 	memset(dmp,0,4*nx*nx*sizeof(mreal));
-	for(i=0;i<nx/2;i++)	for(j=0;j<nx/2;j++)	// prepare damping
+#pragma omp parallel for collapse(2)
+	for(long i=0;i<nx/2;i++)	for(long j=0;j<nx/2;j++)	// prepare damping
 	{
-		x1 = (nx/2-i)/(nx/2.);	x2 = (nx/2-j)/(nx/2.);
+		register mreal x1 = (nx/2-i)/(nx/2.), x2 = (nx/2-j)/(nx/2.);
 		dmp[2*nx-1-i] = dmp[i] = 30*GAMMA*x1*x1/k0;
 		dmp[(2*nx-1-j)*2*nx] += 30*GAMMA*x2*x2/k0;
 		dmp[j*2*nx] += 30*GAMMA*x2*x2/k0;
 	}
-	for(i=0;i<nx;i++)	for(j=0;j<nx;j++)	// init
+#pragma omp parallel for collapse(2)
+	for(long i=0;i<nx;i++)	for(long j=0;j<nx;j++)	// init
 		a[i+nx/2+2*nx*(j+nx/2)] = dual(ini_re->v(i,j),ini_im->v(i,j));
 	void *wsx, *wtx = mgl_fft_alloc(2*nx,&wsx,1);
 	if(xx && yy && zz)	{	xx->Create(nx,nx,nt);	yy->Create(nx,nx,nt);	zz->Create(nx,nx,nt);	}
@@ -521,20 +547,24 @@ HMDT MGL_EXPORT mgl_qo3d_func(dual (*ham)(mreal u, mreal x, mreal y, mreal z, mr
 	tmp.dmp=dmp;	tmp.par=par;
 	tmp.dr=dr;	tmp.dk=dk;	tmp.ham=ham;	tmp.a=a;
 	// start calculation
-	for(int k=0;k<nt;k++)
+	for(long k=0;k<nt;k++)
 	{
-		for(i=0;i<nx;i++)	for(j=0;j<nx;j++)	// "save"
+#pragma omp parallel for collapse(2)
+		for(long i=0;i<nx;i++)	for(long j=0;j<nx;j++)	// "save"
 			res->a[i+nx*(j+k*nx)]=abs(a[i+nx/2+2*nx*(j+nx/2)])*sqrt(ra[0].ch/ra[k].ch);
-		if(xx && yy && zz)	for(i=0;i<nx;i++)	for(j=0;j<nx;j++)	// prepare xx, yy, zz
-		{
-			x1 = (2*i-nx+1)*dr;	x2 = (2*j-nx+1)*dr;
-			xx->a[i+nx*(j+k*nx)] = ray->a[n7*k] + ra[k].x1*x1 + ra[k].x2*x2;	// new coordinates
-			yy->a[i+nx*(j+k*nx)] = ray->a[n7*k+1] + ra[k].y1*x1 + ra[k].y2*x2;
-			zz->a[i+nx*(j+k*nx)] = ray->a[n7*k+2] + ra[k].z1*x1 + ra[k].z2*x2;
-		}
+		if(xx && yy && zz)
+#pragma omp parallel for collapse(2)
+			for(long i=0;i<nx;i++)	for(long j=0;j<nx;j++)	// prepare xx, yy, zz
+			{
+				register mreal x1 = (2*i-nx+1)*dr, x2 = (2*j-nx+1)*dr;
+				xx->a[i+nx*(j+k*nx)] = ray->a[n7*k] + ra[k].x1*x1 + ra[k].x2*x2;	// new coordinates
+				yy->a[i+nx*(j+k*nx)] = ray->a[n7*k+1] + ra[k].y1*x1 + ra[k].y2*x2;
+				zz->a[i+nx*(j+k*nx)] = ray->a[n7*k+2] + ra[k].z1*x1 + ra[k].z2*x2;
+			}
 		tmp.r=ray->a+n7*k;	tmp.ra=ra+k;
 		mglStartThread(mgl_qo3d_hprep,0,2*nx,0,0,0,0,&tmp);	tmp.h0 = huv[0];
-		for(i=0;i<2*nx;i++)	// fill intermediate arrays
+#pragma omp parallel for
+		for(long i=0;i<2*nx;i++)	// fill intermediate arrays
 		{
 			tmp.hx[i] = hxv[i];	tmp.hy[i] = huy[i*2*nx];
 			tmp.hv[i] = huv[i];	tmp.hu[i] = huv[i*2*nx];
@@ -542,19 +572,23 @@ HMDT MGL_EXPORT mgl_qo3d_func(dual (*ham)(mreal u, mreal x, mreal y, mreal z, mr
 		mglStartThread(mgl_qo3d_post,0,2*nx,0,0,0,0,&tmp);
 		// Step for field
 		dual dt = dual(0, -ra[k].dt*k0);	// TODO: this part can be paralleled
-		for(i=0;i<4*nx*nx;i++)	a[i] *= exp(hxy[i]*dt);		// x-y
-		for(i=0;i<2*nx;i++)	// x->u
+#pragma omp parallel for
+		for(long i=0;i<4*nx*nx;i++)	a[i] *= exp(hxy[i]*dt);		// x-y
+		for(long i=0;i<2*nx;i++)	// x->u
 			mgl_fft((double *)(a+i*2*nx), 1, 2*nx, wtx, wsx, false);
-		for(i=0;i<4*nx*nx;i++)	a[i] *= exp(huy[i]*dt);		// u-y
-		for(i=0;i<2*nx;i++)	// y->v
+#pragma omp parallel for
+		for(long i=0;i<4*nx*nx;i++)	a[i] *= exp(huy[i]*dt);		// u-y
+		for(long i=0;i<2*nx;i++)	// y->v
 			mgl_fft((double *)(a+i), 2*nx, 2*nx, wtx, wsx, false);
-		for(i=0;i<4*nx*nx;i++)	a[i] *= exp(huv[i]*dt)/(4.*nx*nx);	// u-v
-		for(i=0;i<2*nx;i++)	// u->x
+#pragma omp parallel for
+		for(long i=0;i<4*nx*nx;i++)	a[i] *= exp(huv[i]*dt);		// u-v
+		for(long i=0;i<2*nx;i++)	// u->x
 			mgl_fft((double *)(a+i*2*nx), 1, 2*nx, wtx, wsx, true);
-		for(i=0;i<4*nx*nx;i++)	a[i] *= exp(hxv[i]*dt);		// x-v
-		for(i=0;i<2*nx;i++)	// v->y
+#pragma omp parallel for
+		for(long i=0;i<4*nx*nx;i++)	a[i] *= exp(hxv[i]*dt);		// x-v
+		for(long i=0;i<2*nx;i++)	// v->y
 			mgl_fft((double *)(a+i), 2*nx, 2*nx, wtx, wsx, true);
-		
+
 /*		// Calculate B1			// TODO make more general scheme later!!!
 		hh = ra[k].pt*(1/sqrt(sqrt(1.041))-1);
 		var['x'-'a'] = ray->a[n7*k];	// new coordiantes
@@ -603,14 +637,17 @@ HMDT MGL_EXPORT mgl_qo3d_solve(const char *ham, HCDT ini_re, HCDT ini_im, HCDT r
 MGL_NO_EXPORT void *mgl_jacob2(void *par)
 {
 	mglThreadD *t=(mglThreadD *)par;
-	register long i,j,i0,ip,im,jp,jm, nx=t->p[0], ny=t->p[1];
+	long nx=t->p[0], ny=t->p[1];
 	mreal *r=t->a;
 	const mreal *x=t->b, *y=t->c;
-	for(i0=t->id;i0<t->n;i0+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i0=t->id;i0<t->n;i0+=mglNumThr)
 	{
-		i=i0%nx;	j=i0/nx;
-		ip = i<nx-1 ? 1:0;	jp = j<ny-1 ? nx:0;
-		im = i>0 ? -1:0;	jm = j>0 ? -nx:0;
+		register long i=i0%nx, j=i0/nx;
+		register long ip = i<nx-1 ? 1:0, jp = j<ny-1 ? nx:0;
+		register long im = i>0 ? -1:0, jm = j>0 ? -nx:0;
 		r[i0] = (x[i0+ip]-x[i0+im])*(y[i0+jp]-y[i0+jm]) -
 				(y[i0+ip]-y[i0+im])*(x[i0+jp]-x[i0+jm]);
 		r[i0] *= mreal((nx-1)*(ny-1)) / ((ip-im)*(jp-jm));
@@ -620,9 +657,8 @@ MGL_NO_EXPORT void *mgl_jacob2(void *par)
 HMDT MGL_EXPORT mgl_jacobian_2d(HCDT x, HCDT y)
 {
 	int nx = x->GetNx(), ny=x->GetNy();
-	mglData *r=new mglData;
-	if(nx!=y->GetNx() || ny!=y->GetNy() || nx<2 || ny<2)	return	r;
-	mgl_data_create(r,nx,ny,1);
+	if(nx!=y->GetNx() || ny!=y->GetNy() || nx<2 || ny<2)	return	0;
+	mglData *r=new mglData(nx,ny,1);
 	const mglData *xx=dynamic_cast<const mglData *>(x);
 	const mglData *yy=dynamic_cast<const mglData *>(y);
 	if(xx && yy)
@@ -632,11 +668,11 @@ HMDT MGL_EXPORT mgl_jacobian_2d(HCDT x, HCDT y)
 	}
 	else	// slow variant
 	{
-		register long i,j,ip,im,jp,jm;
-		for(j=0;j<ny;j++)	for(i=0;i<nx;i++)
+#pragma omp parallel for collapse(2)
+		for(long j=0;j<ny;j++)	for(long i=0;i<nx;i++)
 		{
-			im = i>0 ? i-1:i;	ip = i<nx-1 ? i+1:i;
-			jm = j>0 ? j-1:j;	jp = j<ny-1 ? j+1:j;
+			register long im = i>0 ? i-1:i, ip = i<nx-1 ? i+1:i;
+			register long jm = j>0 ? j-1:j, jp = j<ny-1 ? j+1:j;
 			r->a[i+nx*j] = (x->v(ip,j)-x->v(im,j))*(y->v(i,jp)-y->v(i,jm)) -
 						(y->v(ip,j)-y->v(im,j))*(x->v(i,jp)-x->v(i,jm));
 			r->a[i+nx*j] *= mreal((nx-1)*(ny-1)) / ((ip-im)*(jp-jm));
@@ -648,14 +684,17 @@ HMDT MGL_EXPORT mgl_jacobian_2d(HCDT x, HCDT y)
 MGL_NO_EXPORT void *mgl_jacob3(void *par)
 {
 	mglThreadD *t=(mglThreadD *)par;
-	register long i,j,k,i0,ip,im,jp,jm,kp,km, nx=t->p[0], ny=t->p[1], nz=t->p[2];
+	long nx=t->p[0], ny=t->p[1], nz=t->p[2];
 	mreal *r=t->a;
 	const mreal *x=t->b, *y=t->c, *z=t->d;
-	for(i0=t->id;i0<t->n;i0+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i0=t->id;i0<t->n;i0+=mglNumThr)
 	{
-		i=i0%nx;	j=(i0/nx)%ny;	k=i0/(nx*ny);
-		ip = i<nx-1 ? 1:0;	jp = j<ny-1 ? nx:0;	kp = k<nz-1 ? nx*ny:0;
-		im = i>0 ? -1:0;	jm = j>0 ? -nx:0;	km = k>0 ? -nx*ny:0;
+		register long i=i0%nx, j=(i0/nx)%ny, k=i0/(nx*ny);
+		register long ip = i<nx-1 ? 1:0, jp = j<ny-1 ? nx:0, kp = k<nz-1 ? nx*ny:0;
+		register long im = i>0 ? -1:0, jm = j>0 ? -nx:0, km = k>0 ? -nx*ny:0;
 		r[i0] = (x[i0+ip]-x[i0+im])*(y[i0+jp]-y[i0+jm])*(z[i0+kp]-z[i0+km]) -
 				(x[i0+ip]-x[i0+im])*(y[i0+kp]-y[i0+km])*(z[i0+jp]-z[i0+jm]) -
 				(x[i0+jp]-x[i0+jm])*(y[i0+ip]-y[i0+im])*(z[i0+kp]-z[i0+km]) +
@@ -669,10 +708,9 @@ MGL_NO_EXPORT void *mgl_jacob3(void *par)
 HMDT MGL_EXPORT mgl_jacobian_3d(HCDT x, HCDT y, HCDT z)
 {
 	int nx = x->GetNx(), ny=x->GetNy(), nz=x->GetNz(), nn = nx*ny*nz;
-	mglData *r=new mglData;
-	if(nx<2 || ny<2 || nz<2)	return	r;
-	if(nn!=y->GetNx()*y->GetNy()*y->GetNz() || nn!=z->GetNx()*z->GetNy()*z->GetNz())	return r;
-	mgl_data_create(r,nx,ny,nz);
+	if(nx<2 || ny<2 || nz<2)	return 0;
+	if(nn!=y->GetNx()*y->GetNy()*y->GetNz() || nn!=z->GetNx()*z->GetNy()*z->GetNz())	return 0;
+	mglData *r=new mglData(nx,ny,nz);
 	const mglData *xx=dynamic_cast<const mglData *>(x);
 	const mglData *yy=dynamic_cast<const mglData *>(y);
 	const mglData *zz=dynamic_cast<const mglData *>(z);
@@ -683,13 +721,13 @@ HMDT MGL_EXPORT mgl_jacobian_3d(HCDT x, HCDT y, HCDT z)
 	}
 	else	// slow variant
 	{
-		register long i,j,k,ip,im,jp,jm,kp,km,i0;
-		for(k=0;k<nz;k++)	for(j=0;j<ny;j++)	for(i=0;i<nx;i++)
+#pragma omp parallel for collapse(3)
+		for(long k=0;k<nz;k++)	for(long j=0;j<ny;j++)	for(long i=0;i<nx;i++)
 		{
-			im = i>0 ? i-1:i;	ip = i<nx-1 ? i+1:i;
-			jm = j>0 ? j-1:j;	jp = j<ny-1 ? j+1:j;
-			km = k>0 ? k-1:k;	kp = k<nz-1 ? k+1:k;
-			i0 = i+nx*(j+ny*k);
+			register long im = i>0 ? i-1:i, ip = i<nx-1 ? i+1:i;
+			register long jm = j>0 ? j-1:j, jp = j<ny-1 ? j+1:j;
+			register long km = k>0 ? k-1:k, kp = k<nz-1 ? k+1:k;
+			register long i0 = i+nx*(j+ny*k);
 			r->a[i0] = (x->v(ip,j,k)-x->v(im,j,k))*(y->v(i,jp,k)-y->v(i,jm,k))*(z->v(i,j,kp)-z->v(i,j,km)) -
 					(x->v(ip,j,k)-x->v(im,j,k))*(y->v(i,j,kp)-y->v(i,j,km))*(z->v(i,jp,k)-z->v(i,jm,k)) -
 					(x->v(i,jp,k)-x->v(i,jm,k))*(y->v(ip,j,k)-y->v(im,j,k))*(z->v(i,j,kp)-z->v(i,j,km)) +
diff --git a/src/pixel.cpp b/src/pixel.cpp
index fb312c2..a50c84c 100644
--- a/src/pixel.cpp
+++ b/src/pixel.cpp
@@ -19,6 +19,7 @@
  ***************************************************************************/
 #include <algorithm>
 #include "mgl2/canvas.h"
+#include "mgl2/thread.h"
 //-----------------------------------------------------------------------------
 void mglCanvas::SetSize(int w,int h)
 {
@@ -35,7 +36,8 @@ void mglCanvas::SetSize(int w,int h)
 //-----------------------------------------------------------------------------
 void mglDrawReg::set(mglCanvas *gr, int nx, int ny, int m)
 {
-	int mx = m%nx, my = m/nx;
+	int mx = m%nx, my = m/nx;	ObjId = gr->ObjId;
+	PDef = gr->mask;	angle = gr->MaskAn;
 	x1 = gr->GetWidth()*mx/nx;		y1 = gr->GetHeight()-gr->GetHeight()*(my+1)/ny;
 	x2 = gr->GetWidth()*(mx+1)/nx-1;	y2 = gr->GetHeight()-gr->GetHeight()*my/ny-1;
 }
@@ -54,24 +56,24 @@ void mglCanvas::PutDrawReg(mglDrawReg *d, const mglCanvas *gr)
 	}
 }
 //-----------------------------------------------------------------------------
-void mglCanvas::PostScale(mglPoint &p) const
+void mglCanvas::PostScale(const mglMatrix *M, mglPoint &p) const
 {
-	mglPoint q=p/(2*B.pf);
-	p.x = B.x + q.x*B.b[0] + q.y*B.b[1] + q.z*B.b[2];
-	p.y = B.y + q.x*B.b[3] + q.y*B.b[4] + q.z*B.b[5];
-	p.z = B.z + q.x*B.b[6] + q.y*B.b[7] + q.z*B.b[8];
+	mglPoint q=p/(2*M->pf);
+	p.x = M->x + q.x*M->b[0] + q.y*M->b[1] + q.z*M->b[2];
+	p.y = M->y + q.x*M->b[3] + q.y*M->b[4] + q.z*M->b[5];
+	p.z = M->z + q.x*M->b[6] + q.y*M->b[7] + q.z*M->b[8];
 }
 //-----------------------------------------------------------------------------
-bool mglCanvas::ScalePoint(mglPoint &p, mglPoint &n, bool use_nan) const
+bool mglCanvas::ScalePoint(const mglMatrix *M, mglPoint &p, mglPoint &n, bool use_nan) const
 {
-	bool res = get(MGL_DISABLE_SCALE) || mglBase::ScalePoint(p,n,use_nan);
+	bool res = get(MGL_DISABLE_SCALE) || mglBase::ScalePoint(M,p,n,use_nan);
 //	if(TernAxis&4)	return res;
-	PostScale(p);
+	PostScale(M,p);
 
 	mglPoint y=n;
-	n.x = y.x*B.b[0] + y.y*B.b[1] + y.z*B.b[2];	// simpler for rotation only
-	n.y = y.x*B.b[3] + y.y*B.b[4] + y.z*B.b[5];
-	n.z = y.x*B.b[6] + y.y*B.b[7] + y.z*B.b[8];
+	n.x = y.x*M->b[0] + y.y*M->b[1] + y.z*M->b[2];	// simpler for rotation only
+	n.y = y.x*M->b[3] + y.y*M->b[4] + y.z*M->b[5];
+	n.z = y.x*M->b[6] + y.y*M->b[7] + y.z*M->b[8];
 	n.Normalize();
 	return res;
 }
@@ -96,14 +98,14 @@ long mglCanvas::ProjScale(int nf, long id, bool text)
 	return CopyProj(id,p,text?n:nn);
 }
 //-----------------------------------------------------------------------------
-void mglCanvas::LightScale()
+void mglCanvas::LightScale(const mglMatrix *M)
 {
-	register long i;
-	for(i=0;i<10;i++)
+//#pragma omp parallel for
+	for(long i=0;i<10;i++)
 	{
 		if(!light[i].n)	continue;
 		light[i].p=light[i].d;	light[i].q=light[i].r;
-		ScalePoint(light[i].q,light[i].p,false);
+		ScalePoint(M,light[i].q,light[i].p,false);
 		light[i].p /= light[i].p.norm();
 	}
 }
@@ -174,7 +176,7 @@ mglPoint mglCanvas::CalcXYZ(int xs, int ys, bool real) const
 void mglCanvas::CalcScr(mglPoint p, int *xs, int *ys) const
 {
 	mglPoint n;
-	ScalePoint(p,n);
+	ScalePoint(GetB(),p,n);
 	if(xs)	*xs=int(p.x);
 	if(ys)	*ys=int(p.y);
 }
@@ -206,7 +208,7 @@ bool operator>(const mglPrim &a, const mglPrim &b)
 //-----------------------------------------------------------------------------
 MGL_NO_EXPORT void *mgl_canvas_thr(void *par)
 {	mglThreadG *t=(mglThreadG *)par;	(t->gr->*(t->f))(t->id, t->n, t->p);	return NULL;	}
-void mglStartThread(void (mglCanvas::*func)(size_t i, size_t n, const void *p), mglCanvas *gr, size_t n, const void *p=NULL)
+void mglStartThread(void (mglCanvas::*func)(long i, long n, const void *p), mglCanvas *gr, long n, const void *p=NULL)
 {
 	if(!func || !gr)	return;
 #if MGL_HAVE_PTHREAD
@@ -215,7 +217,7 @@ void mglStartThread(void (mglCanvas::*func)(size_t i, size_t n, const void *p),
 	{
 		pthread_t *tmp=new pthread_t[mglNumThr];
 		mglThreadG *par=new mglThreadG[mglNumThr];
-		register int i;
+		register long i;
 		for(i=0;i<mglNumThr;i++)	// put parameters into the structure
 		{	par[i].gr=gr;	par[i].f=func;	par[i].n=n;	par[i].p=p;	par[i].id=i;	}
 		for(i=0;i<mglNumThr;i++)	pthread_create(tmp+i, 0, mgl_canvas_thr, par+i);
@@ -227,32 +229,45 @@ void mglStartThread(void (mglCanvas::*func)(size_t i, size_t n, const void *p),
 	{	mglNumThr = 1;	(gr->*func)(0,n,p);	}
 }
 //-----------------------------------------------------------------------------
-void mglCanvas::pxl_combine(size_t id, size_t n, const void *)
+void mglCanvas::pxl_combine(long id, long n, const void *)
 {
 	unsigned char c[4],*cc;
-	for(size_t i=id;i<n;i+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for private(c,cc)
+#endif
+	for(long i=id;i<n;i+=mglNumThr)
 	{	cc = C+12*i;		memcpy(c,BDef,4);
 		combine(c,cc+8);	combine(c,cc+4);
 		combine(c,cc);		memcpy(G4+4*i,c,4);	}
 }
 //-----------------------------------------------------------------------------
-void mglCanvas::pxl_memcpy(size_t id, size_t n, const void *)
-{	for(size_t i=id;i<n;i+=mglNumThr)	memcpy(G4+4*i,C+12*i,4);	}
+void mglCanvas::pxl_memcpy(long id, long n, const void *)
+{
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i=id;i<n;i+=mglNumThr)	memcpy(G4+4*i,C+12*i,4);
+}
 //-----------------------------------------------------------------------------
-void mglCanvas::pxl_backgr(size_t id, size_t n, const void *)
+void mglCanvas::pxl_backgr(long id, long n, const void *)
 {
 	unsigned char c[4];
-	for(size_t i=id;i<n;i+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for private(c)
+#endif
+	for(long i=id;i<n;i+=mglNumThr)
 	{	memcpy(c,BDef,4);	combine(c,G4+4*i);	memcpy(G+3*i,c,3);	}
 }
 //-----------------------------------------------------------------------------
-void mglCanvas::pxl_transform(size_t id, size_t n, const void *)
+void mglCanvas::pxl_transform(long id, long n, const void *)
 {
-	register float x,y,z;
-	for(size_t i=id;i<n;i+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i=id;i<n;i+=mglNumThr)
 	{
 		mglPnt &p=Pnt[i];
-		x = p.xx-Width/2.;	y = p.yy-Height/2.;	z = p.zz-Depth/2.;
+		register float x = p.xx-Width/2., y = p.yy-Height/2., z = p.zz-Depth/2.;
 		p.x = Bp.b[0]*x + Bp.b[1]*y + Bp.b[2]*z - Bp.x*Width/2;
 		p.y = Bp.b[3]*x + Bp.b[4]*y + Bp.b[5]*z - Bp.y*Height/2;
 		p.z = Bp.b[6]*x + Bp.b[7]*y + Bp.b[8]*z + Depth/2.;
@@ -261,9 +276,12 @@ void mglCanvas::pxl_transform(size_t id, size_t n, const void *)
 	}
 }
 //-----------------------------------------------------------------------------
-void mglCanvas::pxl_setz_adv(size_t id, size_t n, const void *)
+void mglCanvas::pxl_setz_adv(long id, long n, const void *)
 {
-	for(size_t i=id;i<n;i+=mglNumThr)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i=id;i<n;i+=mglNumThr)
 	{
 		mglPrim &q=Prm[i];	q.z = Pnt[q.n1].z;
 		if(q.type==1)	q.z = (q.z + Pnt[q.n2].z)/2;
@@ -272,87 +290,225 @@ void mglCanvas::pxl_setz_adv(size_t id, size_t n, const void *)
 	}
 }
 //-----------------------------------------------------------------------------
-void mglCanvas::pxl_setz(size_t id, size_t n, const void *)
+void mglCanvas::pxl_prmcol(long id, long n, const void *)
+{
+	prm_col.resize(n);
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i=id;i<n;i+=mglNumThr)
+		prm_col[i] = GetColor(Prm[i]);
+}
+//-----------------------------------------------------------------------------
+uint32_t mglCanvas::GetColor(const mglPrim &p)
+{
+	mglRGBA res, c1,c2,c3,c4;
+	c1.c=pnt_col[p.type==1?p.n2:p.n1];
+	unsigned r=c1.r[0], g=c1.r[1], b=c1.r[2], a=c1.r[3];
+	switch(p.type)
+	{
+	case 2:
+		c2.c=pnt_col[p.n2];	c3.c=pnt_col[p.n3];
+		res.r[0]=(r+c2.r[0]+c3.r[0])/3;
+		res.r[1]=(g+c2.r[1]+c3.r[1])/3;
+		res.r[2]=(b+c2.r[2]+c3.r[2])/3;
+		res.r[3]=(a+c2.r[3]+c3.r[3])/3;	break;
+	case 3:
+		c2.c=pnt_col[p.n2];	c3.c=pnt_col[p.n3];	c4.c=pnt_col[p.n4];
+		res.r[0]=(r+c2.r[0]+c3.r[0]+c4.r[0])/4;
+		res.r[1]=(g+c2.r[1]+c3.r[1]+c4.r[1])/4;
+		res.r[2]=(b+c2.r[2]+c3.r[2]+c4.r[2])/4;
+		res.r[3]=(a+c2.r[3]+c3.r[3]+c4.r[3])/4;	break;
+	case 6:
+		res.r[0]=p.n2&0xff;	res.r[1]=(p.n2/256)&0xff;	res.r[2]=(p.n2/65536)&0xff;	res.r[3]=255;	break;
+//		res.c=p.n2;	break;
+	default:
+		res.c = c1.c;	break;
+	}
+	// add fog into resulting color
+	float zf = FogDist*(p.z/Depth-0.5-FogDz);
+	if(zf<0)	// add fog
+	{
+		unsigned char d = (unsigned char)(255*(1.-exp(5*zf)));
+		unsigned char cb[4] = {BDef[0], BDef[1], BDef[2], d};
+		if(d<255)	combine(res.r,cb);
+	}
+	return res.c;
+}
+//-----------------------------------------------------------------------------
+void mglCanvas::pxl_pntcol(long id, long n, const void *)
 {
-	for(size_t i=id;i<n;i+=mglNumThr)
+	mglRGBA c;
+	pnt_col.resize(n);
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for private(c)
+#endif
+	for(long i=id;i<n;i+=mglNumThr)
+	{	col2int(Pnt[i],c.r,-1);	pnt_col[i]=c.c;	}
+}
+//-----------------------------------------------------------------------------
+void mglCanvas::pxl_setz(long id, long n, const void *)
+{
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i=id;i<n;i+=mglNumThr)
 	{	mglPrim &q=Prm[i];	q.z = Pnt[q.n1].z;	}
 }
 //-----------------------------------------------------------------------------
-void mglCanvas::PreparePrim(bool fast)
+void mglCanvas::PreparePrim(int fast)
 {
-	mglStartThread(&mglCanvas::pxl_transform,this,Pnt.size());
-	if(fast)	mglStartThread(&mglCanvas::pxl_setz,this,Prm.size());
-	else	mglStartThread(&mglCanvas::pxl_setz_adv,this,Prm.size());
-	mglCreationOrder = false;
-	std::sort(Prm.begin(), Prm.end());
+	if(fast!=2)
+	{
+		mglStartThread(&mglCanvas::pxl_transform,this,Pnt.size());
+		if(fast==0)	mglStartThread(&mglCanvas::pxl_setz,this,Prm.size());
+		else	mglStartThread(&mglCanvas::pxl_setz_adv,this,Prm.size());
+		mglCreationOrder = false;
+		std::sort(Prm.begin(), Prm.end());
+	}
+	if(fast>0)
+	{
+		mglStartThread(&mglCanvas::pxl_pntcol,this,Pnt.size());
+		mglStartThread(&mglCanvas::pxl_prmcol,this,Prm.size());
+	}
 }
 //-----------------------------------------------------------------------------
 void mglBase::resort()
 {
-	mglCreationOrder = true;
-	std::sort(Prm.begin(), Prm.end());
-	mglCreationOrder = false;
-	clr(MGL_FINISHED);
+#pragma omp critical
+	{
+		mglCreationOrder = true;
+		std::sort(Prm.begin(), Prm.end());
+		mglCreationOrder = false;
+		clr(MGL_FINISHED);
+	}
 }
 //-----------------------------------------------------------------------------
-void mglCanvas::pxl_primdr(size_t id, size_t , const void *)
+void mglCanvas::pxl_primdr(long id, long , const void *)
 {
-	int nx=1,ny=1;
-	register size_t i;
-	if(id<unsigned(mglNumThr))
+#define Q	4	// should be >= sqrt(2*num_thr) ???
+	int nx=Q,ny=Q;		// TODO find dependence on Q for 1, 2, 4, 8 threads. Try to select optimal
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+	for(long i=id;i<nx*ny;i+=mglNumThr)
 	{
-		for(i=1;i<=unsigned(sqrt(double(mglNumThr))+0.5);i++)
-			if(mglNumThr%i==0)	ny=i;
-		nx = mglNumThr/ny;
+		mglDrawReg d;	d.set(this,nx,ny,i);
+		for(size_t k=0;k<Prm.size();k++)
+		{
+			if(Stop)	continue;
+			const mglPrim &p=Prm[k];
+			d.PDef = p.n3;	d.pPos = p.s;
+			d.ObjId = p.id;	d.PenWidth=p.w;
+			d.angle = p.angl;
+			if(p.type==2 || p.type==3) d.PDef = p.m;
+			switch(p.type)
+			{
+			case 0:	mark_draw(Pnt[p.n1],p.n4,p.s,&d);	break;
+			case 1:	line_draw(Pnt[p.n1],Pnt[p.n2],&d);	break;
+			case 2:	trig_draw(Pnt[p.n1],Pnt[p.n2],Pnt[p.n3],true,&d);	break;
+			case 3:	quad_draw(Pnt[p.n1],Pnt[p.n2],Pnt[p.n3],Pnt[p.n4],&d);	break;
+			case 4:	glyph_draw(p,&d);	break;
+			}
+		}
 	}
-	else 	{	nx=ny=1;	id=0;	}
-	mglDrawReg d;	d.set(this,nx,ny,id);
-
-	for(i=0;i<Prm.size();i++)
+}
+//-----------------------------------------------------------------------------
+void mglCanvas::pxl_primpx(long id, long n, const void *)	// NOTE this variant is too slow ... may be later in CUDA???
+{
+	mglDrawReg d;	d.set(this,1,1,id);
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for firstprivate(d)
+#endif
+	for(long ii=0;ii<n;ii+=mglNumThr)
 	{
-		if(Stop)	return;
-		const mglPrim &p=Prm[i];
-		d.PDef = p.n3;	d.pPos = p.s;
-		d.ObjId = p.id;	d.PenWidth=p.w;
-		switch(p.type)
+		register long i=ii%Width, j=ii/Width;
+		for(size_t k=0;k<Prm.size();k++)
 		{
-		case 0:	mark_draw(Pnt[p.n1],p.n4,p.s,&d);	break;
-		case 1:	line_draw(Pnt[p.n1],Pnt[p.n2],&d);		break;
-		case 2:	trig_draw(Pnt[p.n1],Pnt[p.n2],Pnt[p.n3],true,&d);	break;
-		case 3:	quad_draw(Pnt[p.n1],Pnt[p.n2],Pnt[p.n3],Pnt[p.n4],&d);	break;
-		case 4:	glyph_draw(p,&d);	break;
+			if(Stop)	continue;
+			const mglPrim &p=Prm[k];
+			d.PDef = p.n3;	d.pPos = p.s;
+			d.ObjId = p.id;	d.PenWidth=p.w;
+			d.angle = p.angl;
+			if(p.type==2 || p.type==3) d.PDef = p.m;
+			switch(p.type)
+			{
+			case 0:	mark_pix(i,j,Pnt[p.n1],p.n4,p.s,&d);	break;
+			case 1:	line_pix(i,j,Pnt[p.n1],Pnt[p.n2],&d);	break;
+			case 2:	trig_pix(i,j,Pnt[p.n1],Pnt[p.n2],Pnt[p.n3],true,&d);	break;
+			case 3:	quad_pix(i,j,Pnt[p.n1],Pnt[p.n2],Pnt[p.n3],Pnt[p.n4],&d);	break;
+			case 4:	glyph_pix(i,j,p,&d);	break;
+			}
 		}
 	}
 }
 //-----------------------------------------------------------------------------
-void mglCanvas::Finish(bool fast)
+void mglCanvas::pxl_dotsdr(long id, long n, const void *)
+{
+	unsigned char r[4]={0,0,0,255};
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for firstprivate(r)
+#endif
+	for(long i=id;i<n;i+=mglNumThr)
+	{
+		const mglPnt &p=Pnt[i];
+		register float x = p.xx-Width/2., y = p.yy-Height/2., z = p.zz-Depth/2.,xx,yy,zz;
+		xx = Bp.b[0]*x + Bp.b[1]*y + Bp.b[2]*z - Bp.x*Width/2;
+		yy = Bp.b[3]*x + Bp.b[4]*y + Bp.b[5]*z - Bp.y*Height/2;
+		zz = Bp.b[6]*x + Bp.b[7]*y + Bp.b[8]*z + Depth/2.;
+		register float d = (1-Bp.pf)/(1-Bp.pf*zz/Depth);
+		xx = Width/2 + d*xx;	yy = Height/2 + d*yy;
+
+		r[0] = (unsigned char)(255*p.r);
+		r[1] = (unsigned char)(255*p.g);
+		r[2] = (unsigned char)(255*p.b);
+		register long i0=long(xx)+Width*(Height-1-long(yy));
+		if(i0>=0 && i0<Width*Height && zz>Z[3*i0])
+		{	Z[3*i0]=z;	memcpy(C+12*i0,r,4);	OI[i0]=-1;	}
+	}
+}
+//-----------------------------------------------------------------------------
+void mglCanvas::Finish()
 {
+	if(Quality==MGL_DRAW_DOTS)
+	{
+		mglStartThread(&mglCanvas::pxl_dotsdr,this,Pnt.size());
+		mglStartThread(&mglCanvas::pxl_memcpy,this,Width*Height);
+		mglStartThread(&mglCanvas::pxl_backgr,this,Width*Height);
+		return;
+	}
 	static mglMatrix bp;
-	if(Quality&4)	clr(MGL_FINISHED);
-	if(memcmp(&Bp,&bp,sizeof(mglMatrix)) && !(Quality&4) && Prm.size()>0)
+	if(Quality==MGL_DRAW_NONE)	return;
+	if(Quality&MGL_DRAW_LMEM)	clr(MGL_FINISHED);
+	if(memcmp(&Bp,&bp,sizeof(mglMatrix)) && !(Quality&MGL_DRAW_LMEM) && Prm.size()>0)
 		clr(MGL_FINISHED);
 	if(get(MGL_FINISHED))	return;	// nothing to do
-	if(!(Quality&4) && Prm.size()>0)
+/*	static bool working=false;
+	if(working)	return;
+	working = true;*/
+	if(!(Quality&MGL_DRAW_LMEM) && Prm.size()>0)
 	{
-		PreparePrim(fast);	bp=Bp;
+		PreparePrim(0);	bp=Bp;
 		clr(MGL_FINISHED);
 		mglStartThread(&mglCanvas::pxl_primdr,this,Prm.size());
 	}
 	size_t n=Width*Height;
 	BDef[3] = (Flag&3)!=2 ? 0:255;
-	if(Quality&2)	mglStartThread(&mglCanvas::pxl_combine,this,n);
+	if(Quality&MGL_DRAW_NORM)	mglStartThread(&mglCanvas::pxl_combine,this,n);
 	else 			mglStartThread(&mglCanvas::pxl_memcpy,this,n);
 	BDef[3] = 255;
 	mglStartThread(&mglCanvas::pxl_backgr,this,n);
 	set(MGL_FINISHED);
+//	working = false;
 }
 //-----------------------------------------------------------------------------
 void mglCanvas::ClfZB(bool force)
 {
-	if(!force && (Quality&4))	return;
-	register long i,n=Width*Height;
+	if(!force && (Quality&MGL_DRAW_LMEM))	return;
+	register long n=Width*Height;
 	memset(C,0,12*n);	memset(OI,0,n*sizeof(int));
-	for(i=0;i<3*n;i++)	Z[i] = -1e20f;
+#pragma omp parallel for
+	for(long i=0;i<3*n;i++)	Z[i] = -1e20f;
 	clr(MGL_FINISHED);
 }
 //-----------------------------------------------------------------------------
@@ -361,34 +517,47 @@ void mglCanvas::Clf(mglColor Back)
 	Fog(0);		PDef = 0xffff;	pPos = 0;	StartAutoGroup(NULL);
 	Pnt.clear();	Prm.clear();	Ptx.clear();	Glf.clear();
 	Sub.clear();	Leg.clear();	Grp.clear();	Act.clear();
+	pnt_col.clear();	prm_col.clear();
+
+#pragma omp critical(txt)
+	{
+		Txt.clear();	Txt.reserve(3);
+		mglTexture t1(MGL_DEF_PAL,-1), t2(MGL_DEF_SCH,1);
+		MGL_PUSH(Txt,t1,mutexTxt);
+		MGL_PUSH(Txt,t2,mutexTxt);
+	}
 
-	Txt.clear();	Txt.reserve(3);
-	MGL_PUSH(Txt,mglTexture(MGL_DEF_PAL,-1),mutexTxt);
-	MGL_PUSH(Txt,mglTexture(MGL_DEF_SCH,1),mutexTxt);
-	
-	if(Back==0)		Back = 'w';
-	if((Flag&3)==2)	Back = 'k';
-	BDef[0]=Back.r*255;	BDef[1]=Back.g*255;BDef[2]=Back.b*255;	BDef[3]=0;
+//	if(Back==NC)		Back = mglColor(1,1,1);
+	if((Flag&3)==2)	Back = mglColor(0,0,0);
+	if(Back!=NC)
+	{	BDef[0]=Back.r*255;	BDef[1]=Back.g*255;BDef[2]=Back.b*255;	BDef[3]=0;	}
 	ClfZB(true);
 }
 //-----------------------------------------------------------------------------
-void mglCanvas::pxl_other(size_t id, size_t n, const void *p)
+void mglCanvas::pxl_other(long id, long n, const void *p)
 {
-	size_t i,j,k;
 	const mglCanvas *gr = (const mglCanvas *)p;
 	if(!gr)	return;
-	if(Quality&2)	for(k=id;k<n;k+=mglNumThr)
-	{
-		i = k%Width;	j = Height-1-(k/Width);
-		pnt_plot(i,j,gr->Z[3*k+2],gr->C+12*k+8,gr->OI[k]);
-		pnt_plot(i,j,gr->Z[3*k+1],gr->C+12*k+4,gr->OI[k]);
-		pnt_plot(i,j,gr->Z[3*k],gr->C+12*k,gr->OI[k]);
-	}
-	else	for(k=id;k<n;k+=mglNumThr)
-	{
-		i = k%Width;	j = Height-1-(k/Width);
-		pnt_plot(i,j,gr->Z[3*k],gr->C+12*k,gr->OI[k]);
-	}
+	if(Quality&MGL_DRAW_NORM)
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+		for(long k=id;k<n;k+=mglNumThr)
+		{
+			register long i = k%Width, j = Height-1-(k/Width);
+			pnt_plot(i,j,gr->Z[3*k+2],gr->C+12*k+8,gr->OI[k]);
+			pnt_plot(i,j,gr->Z[3*k+1],gr->C+12*k+4,gr->OI[k]);
+			pnt_plot(i,j,gr->Z[3*k],gr->C+12*k,gr->OI[k]);
+		}
+	else
+#if !MGL_HAVE_PTHREAD
+#pragma omp parallel for
+#endif
+		for(long k=id;k<n;k+=mglNumThr)
+		{
+			register long i = k%Width, j = Height-1-(k/Width);
+			pnt_plot(i,j,gr->Z[3*k],gr->C+12*k,gr->OI[k]);
+		}
 }
 //-----------------------------------------------------------------------------
 void mglCanvas::Combine(const mglCanvas *gr)
@@ -411,7 +580,7 @@ void mglCanvas::pnt_plot(long x,long y,mreal z,const unsigned char ci[4], int ob
 		if(d==255)	return;
 		combine(c,cb);
 	}
-	if(Quality&2)
+	if(Quality&MGL_DRAW_NORM)
 	{
 		if(z>=zz[1])	// shift point on slice down and paste new point
 		{
@@ -439,59 +608,51 @@ void mglCanvas::pnt_plot(long x,long y,mreal z,const unsigned char ci[4], int ob
 unsigned char* mglCanvas::col2int(const mglPnt &p,unsigned char *r, int obj_id)
 {
 	if(!r)	return r;
-	if(p.a<=0)	{	memset(r,0,4*sizeof(unsigned char));	return r;	}
+	if(p.a<=0)	{	memset(r,0,4);	return r;	}
 	register float b0=0,b1=0,b2=0, ar,ag,ab;
 	ar = ag = ab = AmbBr;
 
-//	if(get(MGL_ENABLE_LIGHT) && !mgl_isnan(p.u))
-	if(!mgl_isnan(p.u))
+//	if(get(MGL_ENABLE_LIGHT) && mgl_isnum(p.u))
+	if(mgl_isnum(p.u+p.v+p.w))
 	{
 		float d0,d1,d2,nn;
 		register long i;
 		for(i=0;i<10;i++)
 		{
-			if(!light[i].n)	continue;
-			if(mgl_isnan(light[i].q.x))		// source at infinity
+			const mglLight &ll=light[i];
+			if(!ll.n)	continue;
+			if(mgl_isnan(ll.q.x))		// source at infinity
 			{
-				nn = 2*(p.u*light[i].p.x+p.v*light[i].p.y+p.w*light[i].p.z) / (p.u*p.u+p.v*p.v+p.w*p.w+1e-6);
-				d0 = light[i].p.x - p.u*nn;
-				d1 = light[i].p.y - p.v*nn;
-				d2 = light[i].p.z - p.w*nn;
+				nn = 2*(p.u*ll.p.x+p.v*ll.p.y+p.w*ll.p.z) / (p.u*p.u+p.v*p.v+p.w*p.w+1e-6);
+				d0 = ll.p.x - p.u*nn;
+				d1 = ll.p.y - p.v*nn;
+				d2 = ll.p.z - p.w*nn;
 				nn = 1 + d2/sqrt(d0*d0+d1*d1+d2*d2+1e-6);
 
-				nn = exp(-light[i].a*nn)*light[i].b*2;
-				b0 += nn*light[i].c.r;
-				b1 += nn*light[i].c.g;
-				b2 += nn*light[i].c.b;
-			}
-			else if(get(MGL_DIFFUSIVE))		// diffuse light
-			{
-				d0 = light[i].q.x-p.x;	// direction to light source
-				d1 = light[i].q.y-p.y;
-				d2 = light[i].q.z-p.z;
-				nn = 2*(d0*light[i].p.x+d1*light[i].p.y+d2*light[i].p.z)/(d0*d0+d1*d1+d2*d2+1e-6);
-				nn = exp(-light[i].a*nn)*light[i].b*2;
-				ar += nn*light[i].c.r;
-				ag += nn*light[i].c.g;
-				ab += nn*light[i].c.b;
+				nn = exp(-ll.a*nn)*ll.b*2;
+				b0 += nn*ll.c.r;
+				b1 += nn*ll.c.g;
+				b2 += nn*ll.c.b;
 			}
-			else						// specular light
+			else		// diffuse and specular light
 			{
-				d0 = light[i].q.x-p.x;	// direction to light source
-				d1 = light[i].q.y-p.y;
-				d2 = light[i].q.z-p.z;
-				nn = d0*d0 + d1*d1 + d2*d2 + 1e-6;
-				float bb = 2*(d0*light[i].p.x+d1*light[i].p.y+d2*light[i].p.z)/nn;
-//				bb = exp(-light[i].a*nn)*light[i].b*2;
-				// now difference for angles between normale and direction to light
-				nn = 2*(p.u*d0+p.v*d1+p.w*d2)/(p.u*p.u+p.v*p.v+p.w*p.w+1e-6)/nn;
+				d0 = ll.q.x-p.x;	// direction to light source
+				d1 = ll.q.y-p.y;
+				d2 = ll.q.z-p.z;
+				nn = 1+(d0*ll.p.x+d1*ll.p.y+d2*ll.p.z)/sqrt(d0*d0+d1*d1+d2*d2+1e-6);
+				float bb = exp(-3*ll.a*nn);	nn = bb*DifBr*2;
+				ar += nn*ll.c.r;
+				ag += nn*ll.c.g;
+				ab += nn*ll.c.b;
+
+				nn = 2*(p.u*d0+p.v*d1+p.w*d2) / (p.u*p.u+p.v*p.v+p.w*p.w+1e-6);
 				d0 -= p.u*nn;	d1 -= p.v*nn;	d2 -= p.w*nn;
 				nn = 1 + d2/sqrt(d0*d0+d1*d1+d2*d2+1e-6);
-				// NOTE: here should be another aperture, but for simplicity I use the same
-				nn = exp(-light[i].a*nn)*bb;
-				b0 += nn*light[i].c.r;
-				b1 += nn*light[i].c.g;
-				b2 += nn*light[i].c.b;
+
+				nn = exp(-ll.a*nn)*bb*ll.b*2;
+				b0 += nn*ll.c.r;
+				b1 += nn*ll.c.g;
+				b2 += nn*ll.c.b;
 			}
 		}
 		b0 += (ar>1 ? 1:ar)*p.r;	// diffuse light
@@ -509,7 +670,7 @@ unsigned char* mglCanvas::col2int(const mglPnt &p,unsigned char *r, int obj_id)
 	r[1] = (unsigned char)(255*b1);
 	r[2] = (unsigned char)(255*b2);
 //	r[3] = get(MGL_ENABLE_ALPHA) ? (unsigned char)(255*p.a) : 255;
-	r[3] = (unsigned char)(255*p.a);
+	r[3] = (unsigned char)((Quality&MGL_DRAW_NORM)?255*p.a:255);
 	return r;
 }
 //-----------------------------------------------------------------------------
@@ -549,30 +710,41 @@ unsigned char **mglCanvas::GetRGBLines(long &w, long &h, unsigned char *&f, bool
 	unsigned char **p;
 	Finish();
 	p = (unsigned char **)malloc(Height * sizeof(unsigned char *));
+#pragma omp parallel for
 	for(long i=0;i<Height;i++)	p[i] = (alpha?G4:G)+d*Width*i;
 	w = Width;	h = Height;		f = 0;
 	return p;
 }
 //-----------------------------------------------------------------------------
+bool visible(long i, long j, const unsigned char m[8], mreal pw, int a)	// Check if pixel visible
+{
+	register float c = mgl_cos[(a+360)%360], s = mgl_cos[(a+450)%360];
+	register int ii = long(0.5+(i*c+j*s)/pw)%8, jj = long(0.5+(j*c-i*s)/pw)%8;
+	if(ii<0)	ii+=8;	if(jj<0)	jj+=8;
+	return m[jj] & (1<<ii);
+}
+//-----------------------------------------------------------------------------
 /* Bilinear interpolation r(u,v) = r0 + (r1-r0)*u + (r2-r0)*v + (r3+r0-r1-r2)*u*v
 	is used (where r is one of {x,y,z,R,G,B,A}. Variables u,v are determined
 	for each point (x,y) and selected one pair which 0<u<1 and 0<v<1.*/
-void mglCanvas::quad_draw(const mglPnt &p1, const mglPnt &p2, const mglPnt &p3, const mglPnt &p4, mglDrawReg *d)
+void mglCanvas::quad_draw(const mglPnt &p1, const mglPnt &p2, const mglPnt &p3, const mglPnt &p4, const mglDrawReg *d)
 {
 	if(!(Quality&3))
 	{
-		fast_draw(p1,p2,d);	fast_draw(p1,p3,d);
-		fast_draw(p4,p2,d);	fast_draw(p4,p3,d);	return;
+//		fast_draw(p1,p2,d);	fast_draw(p1,p3,d);
+//		fast_draw(p4,p2,d);	fast_draw(p4,p3,d);
+		fast_draw(p1,p4,d);	fast_draw(p2,p3,d);
+		return;
 	}
 	unsigned char r[4];
 	long y1,x1,y2,x2;
 	float dd,dsx,dsy;
 	mglPnt d1=p2-p1, d2=p3-p1, d3=p4+p1-p2-p3, p;
 
-	x1 = long(fmin(fmin(p1.x,p2.x),fmin(p3.x,p4.x)));	// bounding box
-	y1 = long(fmin(fmin(p1.y,p2.y),fmin(p3.y,p4.y)));
-	x2 = long(fmax(fmax(p1.x,p2.x),fmax(p3.x,p4.x)));
-	y2 = long(fmax(fmax(p1.y,p2.y),fmax(p3.y,p4.y)));
+	x1 = long(fmin(p1.x<p2.x?p1.x:p2.x, p3.x<p4.x?p3.x:p4.x));	// bounding box
+	y1 = long(fmin(p1.y<p2.y?p1.y:p2.y, p3.y<p4.y?p3.y:p4.y));
+	x2 = long(fmax(p1.x>p2.x?p1.x:p2.x, p3.x>p4.x?p3.x:p4.x));
+	y2 = long(fmax(p1.y>p2.y?p1.y:p2.y, p3.y>p4.y?p3.y:p4.y));
 	x1=x1>d->x1?x1:d->x1;	x2=x2<d->x2?x2:d->x2;
 	y1=y1>d->y1?y1:d->y1;	y2=y2<d->y2?y2:d->y2;
 	if(x1>x2 || y1>y2)	return;
@@ -581,26 +753,24 @@ void mglCanvas::quad_draw(const mglPnt &p1, const mglPnt &p2, const mglPnt &p3,
 	dsx =-4*(d2.y*d3.x - d2.x*d3.y)*d1.y;
 	dsy = 4*(d2.y*d3.x - d2.x*d3.y)*d1.x;
 
-	if((d1.x==0 && d1.y==0) || (d2.x==0 && d2.y==0) || !(Quality&2))
+	if((d1.x==0 && d1.y==0) || (d2.x==0 && d2.y==0) || !(Quality&MGL_DRAW_NORM))
 	{	trig_draw(p1,p2,p4,true,d);	trig_draw(p1,p3,p4,true,d);	return;	}
 
 	mglPoint n1 = mglPoint(p2.x-p1.x,p2.y-p1.y,p2.z-p1.z)^mglPoint(p3.x-p1.x,p3.y-p1.y,p3.z-p1.z);
 	mglPoint n2 = mglPoint(p2.x-p4.x,p2.y-p4.y,p2.z-p4.z)^mglPoint(p3.x-p4.x,p3.y-p4.y,p3.z-p4.z);
 	mglPoint nr = (n1+n2)*0.5;
 
-	register long i,j;
-	register float u,v,s,xx,yy,qu,qv;
 	float x0 = p1.x, y0 = p1.y;
-	for(i=x1;i<=x2;i++)	for(j=y1;j<=y2;j++)
+	for(long i=x1;i<=x2;i++)	for(long j=y1;j<=y2;j++)
 	{
-		xx = (i-x0);	yy = (j-y0);
+		if(!visible(i,j,d->m, d->PenWidth,d->angle))	continue;
+		register float xx = (i-x0), yy = (j-y0), s;
 		s = dsx*xx + dsy*yy + (dd+d3.y*xx-d3.x*yy)*(dd+d3.y*xx-d3.x*yy);
 		if(s<0)	continue;	// no solution
 		s = sqrt(s);
-		qu = d3.x*yy - d3.y*xx + dd + s;
-		qv = d3.y*xx - d3.x*yy + dd + s;
-		u = v = -1.f;
-		if(qu && qv)
+		register float qu = d3.x*yy - d3.y*xx + dd + s, u=-1;
+		register float qv = d3.y*xx - d3.x*yy + dd + s, v=-1;
+//		if(qu && qv)
 		{
 			u = 2.f*(d2.y*xx - d2.x*yy)/qu;
 			v = 2.f*(d1.x*yy - d1.y*xx)/qv;
@@ -610,7 +780,7 @@ void mglCanvas::quad_draw(const mglPnt &p1, const mglPnt &p2, const mglPnt &p3,
 			qu = d3.x*yy - d3.y*xx + dd - s;
 			qv = d3.y*xx - d3.x*yy + dd - s;
 			u = v = -1.f;
-			if(qu && qv)
+//			if(qu && qv)
 			{
 				u = 2.f*(d2.y*xx - d2.x*yy)/qu;
 				v = 2.f*(d1.x*yy - d1.y*xx)/qv;
@@ -618,16 +788,59 @@ void mglCanvas::quad_draw(const mglPnt &p1, const mglPnt &p2, const mglPnt &p3,
 			if(u*(1.f-u)<0.f || v*(1.f-v)<0.f)	continue;	// second root bad
 		}
 		p = p1+d1*u+d2*v+d3*(u*v);
-		if(mgl_isnan(p.u) && !mgl_isnan(p.v))
+		if(mgl_isnan(p.u) && mgl_isnum(p.v))
 		{	p.u = nr.x;	p.v = nr.y;	p.w = nr.z;	}
 		pnt_plot(i,j,p.z,col2int(p,r,d->ObjId),d->ObjId);
 	}
 }
 //-----------------------------------------------------------------------------
+void mglCanvas::quad_pix(long i, long j, const mglPnt &p1, const mglPnt &p2, const mglPnt &p3, const mglPnt &p4, const mglDrawReg *d)
+{
+	if(!visible(i,j,d->m, d->PenWidth,d->angle))	return;
+	mglPnt d1=p2-p1, d2=p3-p1, d3=p4+p1-p2-p3;
+	register float dd = d1.x*d2.y-d1.y*d2.x;
+	register float dsx =-4*(d2.y*d3.x - d2.x*d3.y)*d1.y;
+	register float dsy = 4*(d2.y*d3.x - d2.x*d3.y)*d1.x;
+	register float xx = (i-p1.x), yy = (j-p1.y), s;
+	s = dsx*xx + dsy*yy + (dd+d3.y*xx-d3.x*yy)*(dd+d3.y*xx-d3.x*yy);
+	if(s<0)	return;	// no solution
+	s = sqrt(s);
+	register float qu = d3.x*yy - d3.y*xx + dd + s, u=-1;
+	register float qv = d3.y*xx - d3.x*yy + dd + s, v=-1;
+	if(qu && qv)
+	{
+		u = 2.f*(d2.y*xx - d2.x*yy)/qu;
+		v = 2.f*(d1.x*yy - d1.y*xx)/qv;
+	}
+	if(u*(1.f-u)<0.f || v*(1.f-v)<0.f)	// first root bad
+	{
+		qu = d3.x*yy - d3.y*xx + dd - s;
+		qv = d3.y*xx - d3.x*yy + dd - s;
+		u = v = -1.f;
+		if(qu && qv)
+		{
+			u = 2.f*(d2.y*xx - d2.x*yy)/qu;
+			v = 2.f*(d1.x*yy - d1.y*xx)/qv;
+		}
+		if(u*(1.f-u)<0.f || v*(1.f-v)<0.f)	return;	// second root bad
+	}
+	mglPnt p = p1+d1*u+d2*v+d3*(u*v);
+	if(mgl_isnan(p.u) && mgl_isnum(p.v))
+	{
+		mglPoint n1 = mglPoint(p2.x-p1.x,p2.y-p1.y,p2.z-p1.z)^mglPoint(p3.x-p1.x,p3.y-p1.y,p3.z-p1.z);
+		mglPoint n2 = mglPoint(p2.x-p4.x,p2.y-p4.y,p2.z-p4.z)^mglPoint(p3.x-p4.x,p3.y-p4.y,p3.z-p4.z);
+		p.u = (n1.x+n2.x)*0.5;
+		p.v = (n1.y+n2.y)*0.5;
+		p.w = (n1.z+n2.z)*0.5;
+	}
+	unsigned char r[4];
+	pnt_plot(i,j,p.z,col2int(p,r,d->ObjId),d->ObjId);
+}
+//-----------------------------------------------------------------------------
 /* Linear interpolation r(u,v) = r0 + (r1-r0)*u + (r2-r0)*v is used, where r is
 	one of {x,y,z,R,G,B,A}. Variables u,v are determined for each point (x,y).
 	Point plotted is u>0 and v>0 and u+v<1.*/
-void mglCanvas::trig_draw(const mglPnt &p1, const mglPnt &p2, const mglPnt &p3, bool anorm, mglDrawReg *d)
+void mglCanvas::trig_draw(const mglPnt &p1, const mglPnt &p2, const mglPnt &p3, bool anorm, const mglDrawReg *d)
 {
 	if(!(Quality&3) && anorm)
 	{
@@ -644,41 +857,61 @@ void mglCanvas::trig_draw(const mglPnt &p1, const mglPnt &p2, const mglPnt &p3,
 	dyv =-d1.x/dxu;	dxv = d1.y/dxu;
 	dyu = d2.x/dxu;	dxu =-d2.y/dxu;
 
-	x1 = long(fmin(fmin(p1.x,p2.x),p3.x));	// bounding box
-	y1 = long(fmin(fmin(p1.y,p2.y),p3.y));
-	x2 = long(fmax(fmax(p1.x,p2.x),p3.x));
-	y2 = long(fmax(fmax(p1.y,p2.y),p3.y));
+	x1 = long(fmin(p1.x<p2.x?p1.x:p2.x, p3.x));	// bounding box
+	y1 = long(fmin(p1.y<p2.y?p1.y:p2.y, p3.y));
+	x2 = long(fmax(p1.x>p2.x?p1.x:p2.x, p3.x));
+	y2 = long(fmax(p1.y>p2.y?p1.y:p2.y, p3.y));
 	x1=x1>d->x1?x1:d->x1;	x2=x2<d->x2?x2:d->x2;
 	y1=y1>d->y1?y1:d->y1;	y2=y2<d->y2?y2:d->y2;
 	if(x1>x2 || y1>y2)	return;
 	// default normale
 	mglPoint nr = mglPoint(p2.x-p1.x,p2.y-p1.y,p2.z-p1.z)^mglPoint(p3.x-p1.x,p3.y-p1.y,p3.z-p1.z);
-
-	register float u,v,xx,yy;
-	register long i,j;
 	float x0 = p1.x, y0 = p1.y;
-	if(Quality&2)	for(i=x1;i<=x2;i++)	for(j=y1;j<=y2;j++)
+	if(Quality&MGL_DRAW_NORM)	for(long i=x1;i<=x2;i++)	for(long j=y1;j<=y2;j++)
 	{
-		xx = (i-x0);	yy = (j-y0);
-		u = dxu*xx+dyu*yy;	v = dxv*xx+dyv*yy;
+		if(!visible(i,j,d->m, d->PenWidth,d->angle))	continue;
+		register float xx = (i-x0), yy = (j-y0);
+		register float u = dxu*xx+dyu*yy, v = dxv*xx+dyv*yy;
 		if(u<0 || v<0 || u+v>1)	continue;
 		p = p1+d1*u+d2*v;
-		if(mgl_isnan(p.u) && !mgl_isnan(p.v) && anorm)
+		if(mgl_isnan(p.u) && mgl_isnum(p.v) && anorm)
 		{	p.u = nr.x;	p.v = nr.y;	p.w = nr.z;	}
 		pnt_plot(i,j,p.z,col2int(p,r,d->ObjId),d->ObjId);
 	}
-	else	for(i=x1;i<=x2;i++)	for(j=y1;j<=y2;j++)
+	else	for(long i=x1;i<=x2;i++)	for(long j=y1;j<=y2;j++)
 	{
-		xx = (i-x0);	yy = (j-y0);
-		u = dxu*xx+dyu*yy;	v = dxv*xx+dyv*yy;
+		if(!visible(i,j,d->m, d->PenWidth,d->angle))	continue;
+		register float xx = (i-x0), yy = (j-y0);
+		register float u = dxu*xx+dyu*yy, v = dxv*xx+dyv*yy;
 		if(u<0 || v<0 || u+v>1)	continue;
 		pnt_plot(i,j,p1.z,col2int(p1,r,d->ObjId),d->ObjId);
 	}
 }
 //-----------------------------------------------------------------------------
-void mglCanvas::line_draw(const mglPnt &p1, const mglPnt &p2, mglDrawReg *dr)
+void mglCanvas::trig_pix(long i, long j, const mglPnt &p1, const mglPnt &p2, const mglPnt &p3, bool anorm, const mglDrawReg *d)
 {
-	if(!(Quality&3))	{	fast_draw(p1,p2,dr);	return;	}
+	if(!visible(i,j,d->m, d->PenWidth,d->angle))	return;
+	mglPnt d1=p2-p1, d2=p3-p1;
+	register float dd = d2.x*d1.y - d1.x*d2.y;
+	if(fabs(dd)<1e-5)	return;		// points lies on the same line
+	register float dyv =-d1.x/dd, dxv = d1.y/dd, dyu = d2.x/dd, dxu =-d2.y/dd;
+	register float xx = (i-p1.x), yy = (j-p1.y);
+	register float u = dxu*xx+dyu*yy, v = dxv*xx+dyv*yy;
+	if(u<0 || v<0 || u+v>1)	return;
+	mglPnt p = p1+d1*u+d2*v;
+	if(mgl_isnan(p.u) && mgl_isnum(p.v) && anorm)
+	{	mglPoint nr = mglPoint(p2.x-p1.x,p2.y-p1.y,p2.z-p1.z)^mglPoint(p3.x-p1.x,p3.y-p1.y,p3.z-p1.z);
+		p.u = nr.x;	p.v = nr.y;	p.w = nr.z;	}
+	unsigned char r[4];
+	pnt_plot(i,j,p.z,col2int(p,r,d->ObjId),d->ObjId);
+}
+//-----------------------------------------------------------------------------
+//#define mgl_sline(c,x)	(unsigned char)((c)/cosh(x))
+inline unsigned char mgl_sline(unsigned char c,float x)
+{	x*=x/2;	return (unsigned char)((c)/(1+x+x*x/5));	}
+void mglCanvas::line_draw(const mglPnt &p1, const mglPnt &p2, const mglDrawReg *dr)
+{
+	if((Quality&3)<2)	{	fast_draw(p1,p2,dr);	return;	}
 	unsigned char r[4];
 	long y1,x1,y2,x2;
 
@@ -689,8 +922,8 @@ void mglCanvas::line_draw(const mglPnt &p1, const mglPnt &p2, mglDrawReg *dr)
 	mglPnt d=p2-p1, p;
 	bool hor = fabs(d.x)>fabs(d.y);
 
-	x1 = long(fmin(p1.x,p2.x));	y1 = long(fmin(p1.y,p2.y));	// bounding box
-	x2 = long(fmax(p1.x,p2.x));	y2 = long(fmax(p1.y,p2.y));
+	x1 = long(p1.x<p2.x?p1.x:p2.x);	y1 = long(p1.y<p2.y?p1.y:p2.y);	// bounding box
+	x2 = long(p1.x>p2.x?p1.x:p2.x);	y2 = long(p1.y>p2.y?p1.y:p2.y);
 	x1 -= pw+3.5;	x2 += pw+3.5;
 	y1 -= pw+3.5;	y2 += pw+3.5;
 	x1=x1>dr->x1?x1:dr->x1;	x2=x2<dr->x2?x2:dr->x2;
@@ -701,124 +934,533 @@ void mglCanvas::line_draw(const mglPnt &p1, const mglPnt &p2, mglDrawReg *dr)
 	dxv = d.y/dd;	dyv =-d.x/dd;
 	dxu = d.x/dd;	dyu = d.y/dd;
 
-	bool aa=get(MGL_ENABLE_ALPHA);
-	register float u,v,xx,yy;
-	register long i,j;
-	set(MGL_ENABLE_ALPHA);
-	if(hor)	for(i=x1;i<=x2;i++)
+	if(hor)	for(long i=x1;i<=x2;i++)
 	{
 		y1 = int(p1.y+d.y*(i-p1.x)/d.x - pw - 3.5);
 		y2 = int(p1.y+d.y*(i-p1.x)/d.x + pw + 3.5);
 		y1=y1>dr->y1?y1:dr->y1;	y2=y2<dr->y2?y2:dr->y2;
 		if(y1>y2)	continue;
-		for(j=y1;j<=y2;j++)
+		for(long j=y1;j<=y2;j++)
 		{
-			xx = (i-p1.x);	yy = (j-p1.y);
-			u = dxu*xx+dyu*yy;	v = dxv*xx+dyv*yy;	v = v*v;
+			register float xx = (i-p1.x), yy = (j-p1.y);
+			register float u = dxu*xx+dyu*yy, v = dxv*xx+dyv*yy;	v = v*v;
 			if(u<0)			v += u*u;
 			else if(u>dd)	v += (u-dd)*(u-dd);
 			if(v>pw*pw)		continue;
 			if(!(dr->PDef & ( 1<<long(fmod(dr->pPos+u/pw/1.5, 16)) ) ))	continue;
 			p = p1+d*(u/dd);	col2int(p,r,dr->ObjId);
-			r[3] = v<(pw-1)*(pw-1)/4 ? 255 : (unsigned char)(255/cosh(dpw*(sqrt(v)+(1-pw)/2)));
+			r[3] = v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
 			pnt_plot(i,j,p.z+dz,r,dr->ObjId);
 		}
 	}
-	else	for(j=y1;j<=y2;j++)
+	else	for(long j=y1;j<=y2;j++)
 	{
 		x1 = int(p1.x+d.x*(j-p1.y)/d.y - pw - 3.5);
 		x2 = int(p1.x+d.x*(j-p1.y)/d.y + pw + 3.5);
 		x1=x1>dr->x1?x1:dr->x1;	x2=x2<dr->x2?x2:dr->x2;
 		if(x1>x2)	continue;
 
-		for(i=x1;i<=x2;i++)
+		for(long i=x1;i<=x2;i++)
 		{
-			xx = (i-p1.x);	yy = (j-p1.y);
-			u = dxu*xx+dyu*yy;	v = dxv*xx+dyv*yy;	v = v*v;
+			register float xx = (i-p1.x), yy = (j-p1.y);
+			register float u = dxu*xx+dyu*yy, v = dxv*xx+dyv*yy;	v = v*v;
 			if(u<0)			v += u*u;
 			else if(u>dd)	v += (u-dd)*(u-dd);
 			if(v>pw*pw)		continue;
 			if(!(dr->PDef & (1<<long(fmod(dr->pPos+u/pw/1.5, 16)))))		continue;
 			p = p1+d*(u/dd);	col2int(p,r,dr->ObjId);
-			r[3] = v<(pw-1)*(pw-1)/4 ? 255 : (unsigned char)(255/cosh(dpw*(sqrt(v)+(1-pw)/2)));
+			r[3] = v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
 			pnt_plot(i,j,p.z+dz,r,dr->ObjId);
 		}
 	}
-	set(aa,MGL_ENABLE_ALPHA);
 }
 //-----------------------------------------------------------------------------
-void mglCanvas::fast_draw(const mglPnt &p1, const mglPnt &p2, mglDrawReg *dr)
+void mglCanvas::pnt_fast(long x,long y,mreal z,const unsigned char ci[4], int obj_id)
+{
+	register long i0=x+Width*(Height-1-y);
+	if(ci[3]!=0 && z>Z[3*i0])	// point upper the background
+	{	Z[3*i0]=z;	memcpy(C+12*i0,ci,4);	OI[i0]=obj_id;	}
+}
+//-----------------------------------------------------------------------------
+void mglCanvas::fast_draw(const mglPnt &p1, const mglPnt &p2, const mglDrawReg *dr)
 {
+	if(p1.x==p2.x && p1.y==p2.y) return;
 	mglPnt d=p2-p1;
 	unsigned char r[4];	col2int(p1,r,dr->ObjId);
 	long y1,x1,y2,x2;
 
 	bool hor = fabs(d.x)>fabs(d.y);
 
-	x1 = long(fmin(p1.x,p2.x));	y1 = long(fmin(p1.y,p2.y));	// bounding box
-	x2 = long(fmax(p1.x,p2.x));	y2 = long(fmax(p1.y,p2.y));
-	x1=x1>dr->x1?x1:dr->x1;	x2=x2<dr->x2?x2:dr->x2-1;
-	y1=y1>dr->y1?y1:dr->y1;	y2=y2<dr->y2?y2:dr->y2-1;
+	x1 = long(p1.x<p2.x?p1.x:p2.x);	y1 = long(p1.y<p2.y?p1.y:p2.y);	// bounding box
+	x2 = long(p1.x>p2.x?p1.x:p2.x);	y2 = long(p1.y>p2.y?p1.y:p2.y);
+	x1=x1>dr->x1?x1:dr->x1;	x2=x2<dr->x2?x2:dr->x2;
+	y1=y1>dr->y1?y1:dr->y1;	y2=y2<dr->y2?y2:dr->y2;
 	if(x1>x2 || y1>y2)	return;
+	float dz = Width>2 ? 1 : 1e-5*Width;		// provide additional height to be well visible on the surfaces
 
-	register long i, c;
-	if(hor && d.x!=0)	for(i=x1;i<=x2;i++)
+	if(hor)	for(long i=x1;i<=x2;i++)
 	{
-		c = long(p1.y+d.y*(i-p1.x)/d.x);
+		register long c = long(p1.y+d.y*(i-p1.x)/d.x);
 		if(c>=y1 && c<=y2)
-			pnt_plot(i, c, p1.z+d.z*(i-p1.x)/d.x, r,dr->ObjId);
+			pnt_fast(i, c, p1.z+d.z*(i-p1.x)/d.x+dz, r,dr->ObjId);
 	}
-	else if(d.y!=0)		for(i=y1;i<=y2;i++)
+	else	for(long i=y1;i<=y2;i++)
 	{
-		c = long(p1.x+d.x*(i-p1.y)/d.y);
+		register long c = long(p1.x+d.x*(i-p1.y)/d.y);
 		if(c>=x1 && c<=x2)
-			pnt_plot(c, i, p1.z+d.z*(i-p1.y)/d.y, r,dr->ObjId);
+			pnt_fast(c, i, p1.z+d.z*(i-p1.y)/d.y+dz, r,dr->ObjId);
 	}
 }
 //-----------------------------------------------------------------------------
-void mglCanvas::pnt_draw(const mglPnt &p, mglDrawReg *dr)
+void mglCanvas::line_pix(long i, long j, const mglPnt &p1, const mglPnt &p2, const mglDrawReg *dr)
+{
+	register float xx = (i-p1.x), yy = (j-p1.y);
+	mglPnt d=p2-p1;
+	register float dd = hypot(d.x, d.y);
+	register float dxv = d.y/dd, dyv =-d.x/dd, dxu = d.x/dd, dyu = d.y/dd;
+	register float u = dxu*xx+dyu*yy, v = dxv*xx+dyv*yy;	v = v*v;
+	if(u<0)			v += u*u;
+	else if(u>dd)	v += (u-dd)*(u-dd);
+	register float pw=dr->PenWidth, dpw=3;
+	if(dr->ObjId==HighId)	{	pw *= 2;	dpw=2;	}
+	if(v>pw*pw || !(dr->PDef & ( 1<<long(fmod(dr->pPos+u/pw/1.5, 16)) ) ))	return;
+	mglPnt p = p1+d*(u/dd);
+	unsigned char r[4];
+	col2int(p,r,dr->ObjId);
+	r[3] = v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+	register float dz = Width>2 ? 1 : 1e-5*Width;		// provide additional height to be well visible on the surfaces
+	pnt_plot(i,j,p.z+dz,r,dr->ObjId);
+}
+//-----------------------------------------------------------------------------
+void mglCanvas::pnt_draw(const mglPnt &p, const mglDrawReg *dr)
 {
 //	if(k<0 || !dr)	return;
-	register long i,j;
-	register float v,pw=3*dr->PenWidth,dpw=3;
+	float pw=3*dr->PenWidth,dpw=3;
 	if(dr->ObjId==HighId)	{	pw *= 2;	dpw=2;	}
 	unsigned char cs[4], cc;
 	col2int(p,cs,dr->ObjId);	cc = cs[3];
 	if(cc==0)	return;
 	long s = long(5.5+fabs(pw));
 	long i1=fmax(-s,dr->x1-p.x),i2=fmin(s,dr->x2-p.x), j1=fmax(-s,dr->y1-p.y),j2=fmin(s,dr->y2-p.y);
-	if(!(Quality&3))	for(j=j1;j<=j2;j++)	for(i=i1;i<=i2;i++)	// fast draw
+	if(!(Quality&3))	for(long j=j1;j<=j2;j++)	for(long i=i1;i<=i2;i++)	// fast draw
 	{
-		v = i*i+j*j;
+		register float v = i*i+j*j;
 		if(v>1+(pw-1)*(pw-1)/4)	continue;
 		pnt_plot(p.x+i,p.y+j,p.z,cs,dr->ObjId);
 	}
-	else	for(j=j1;j<=j2;j++)	for(i=i1;i<=i2;i++)
+	else	for(long j=j1;j<=j2;j++)	for(long i=i1;i<=i2;i++)
 	{
-		v = i*i+j*j;
-		cs[3] = v<(pw-1)*(pw-1)/4 ? cc : (unsigned char)(cc/cosh(dpw*(sqrt(v)+(1-pw)/2)));
-//		cs[3] = (unsigned char)(cc*exp(-6*v));
+		register float v = i*i+j*j;
+		cs[3] = v<(pw-1)*(pw-1)/4 ? cc : mgl_sline(cc,dpw*(sqrt(v)+(1-pw)/2));
 		pnt_plot(p.x+i,p.y+j,p.z,cs,dr->ObjId);
 	}
 }
 //-----------------------------------------------------------------------------
+void mglCanvas::pnt_pix(long i, long j, const mglPnt &p, const mglDrawReg *dr)
+{
+	register float pw=3*dr->PenWidth,dpw=3;
+	if(dr->ObjId==HighId)	{	pw *= 2;	dpw=2;	}
+	unsigned char cs[4];
+	col2int(p,cs,dr->ObjId);
+	register float xx = (i-p.x), yy = (j-p.y), v = xx*xx+yy*yy;
+	if(cs[3]==0 || v>(5.5+pw)*(5.5+pw))	return;
+	if(v<(pw-1)*(pw-1)/4)	cs[3] = mgl_sline(cs[3],dpw*(sqrt(v)+(1-pw)/2));
+	pnt_plot(i,j,p.z,cs,dr->ObjId);
+}
+//-----------------------------------------------------------------------------
 void mglCanvas::mark_draw(const mglPnt &q, char type, mreal size, mglDrawReg *d)
 {
+	unsigned char cs[4], ca;	col2int(q,cs,d->ObjId);	ca = cs[3];// = size>0 ? 255 : 255*q.t;
+	mreal ss=fabs(size), pw=1,dpw=3;
+
+	if(type=='.' || ss==0)
+	{
+		if(d)	pw = 3*(ss?ss:sqrt(font_factor/400));
+		register mreal dd = pw+3.5;
+		long x1 = long(q.x-dd), y1 = long(q.y-dd);	// bounding box
+		long x2 = long(q.x+dd), y2 = long(q.y+dd);
+		x1=x1>d->x1?x1:d->x1;	x2=x2<d->x2?x2:d->x2;
+		y1=y1>d->y1?y1:d->y1;	y2=y2<d->y2?y2:d->y2;
+		if(x1>x2 || y1>y2)	return;
+
+		if(d->ObjId==HighId)	{	pw *= 2;	dpw=2;	}
+		for(long j=y1;j<=y2;j++)	for(long i=x1;i<=x2;i++)
+		{
+			register float dx=i-q.x, dy=j-q.y, v=dx*dx+dy*dy;
+			register int sum = v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+			cs[3] = ca*sum/255;
+			pnt_plot(i,j,q.z+1,cs,d->ObjId);
+		}
+	}
+	else
+	{
+		if(d)
+		{
+			d->PDef = MGL_SOLID_MASK;	d->angle = 0;
+			pw = d->PenWidth*fabs(50*size);
+			if(pw<1)	pw=1;
+		}
+		if(!strchr("xsSoO",type))	ss *= 1.1;
+		if(d->ObjId==HighId)	{	pw *= 2;	dpw=2;	}
+
+		register mreal dd = ss+pw+3.5;
+		long x1 = long(q.x-dd), y1 = long(q.y-dd);	// bounding box
+		long x2 = long(q.x+dd), y2 = long(q.y+dd);
+		x1=x1>d->x1?x1:d->x1;	x2=x2<d->x2?x2:d->x2;
+		y1=y1>d->y1?y1:d->y1;	y2=y2<d->y2?y2:d->y2;
+		if(x1>x2 || y1>y2)	return;
+
+		switch(type)
+		{
+		case 'P':
+			for(long j=y1;j<=y2;j++)	for(long i=x1;i<=x2;i++)
+			{
+				register float dx=i-q.x, dy=j-q.y, v,u;
+				register int sum=0;
+				u = fabs(dy)-ss;	v = (dx-ss)*(dx-ss)+(u<0?0:u*u);
+				sum += v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+				u = fabs(dy)-ss;	v = (dx+ss)*(dx+ss)+(u<0?0:u*u);
+				sum += v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+				u = fabs(dy)-ss;	v = dx*dx+(u<0?0:u*u);
+				sum += v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+				u = fabs(dx)-ss;	v = (dy-ss)*(dy-ss)+(u<0?0:u*u);
+				sum += v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+				u = fabs(dx)-ss;	v = (dy+ss)*(dy+ss)+(u<0?0:u*u);
+				sum += v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+				u = fabs(dx)-ss;	v = dy*dy+(u<0?0:u*u);
+				sum += v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+				sum = sum>255?255:sum;	cs[3] = ca*sum/255;
+				pnt_plot(i,j,q.z+1,cs,d->ObjId);
+			}
+			break;
+		case '+':
+			for(long j=y1;j<=y2;j++)	for(long i=x1;i<=x2;i++)
+			{
+				register float dx=i-q.x, dy=j-q.y, v,u;
+				register int sum=0;
+				u = fabs(dy)-ss;	v = dx*dx+(u<0?0:u*u);
+				sum += v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+				u = fabs(dx)-ss;	v = dy*dy+(u<0?0:u*u);
+				sum += v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+				sum = sum>255?255:sum;	cs[3] = ca*sum/255;
+				pnt_plot(i,j,q.z+1,cs,d->ObjId);
+			}
+			break;
+		case 'X':
+			for(long j=y1;j<=y2;j++)	for(long i=x1;i<=x2;i++)
+			{
+				register float dx=i-q.x, dy=j-q.y, v,u;
+				register int sum=0;
+				u = fabs(dy)-ss;	v = (dx-ss)*(dx-ss)+(u<0?0:u*u);
+				sum += v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+				u = fabs(dy)-ss;	v = (dx+ss)*(dx+ss)+(u<0?0:u*u);
+				sum += v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+				u = fabs(dx)-ss;	v = (dy-ss)*(dy-ss)+(u<0?0:u*u);
+				sum += v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+				u = fabs(dx)-ss;	v = (dy+ss)*(dy+ss)+(u<0?0:u*u);
+				sum += v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+
+				u = fabs(dx+dy)-2*ss;	v = dx-dy;	v = v*v+(u<0?0:u*u);
+				sum += v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+				u = fabs(dx-dy)-2*ss;	v = dx+dy;	v = v*v+(u<0?0:u*u);
+				sum += v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+
+				sum = sum>255?255:sum;	cs[3] = ca*sum/255;
+				pnt_plot(i,j,q.z+1,cs,d->ObjId);
+			}
+			break;
+		case 'x':
+			for(long j=y1;j<=y2;j++)	for(long i=x1;i<=x2;i++)
+			{
+				register float dx=i-q.x, dy=j-q.y, v,u;
+				register int sum=0;
+				u = fabs(dx+dy)-2*ss;	v = dx-dy;	v = v*v+(u<0?0:u*u);
+				sum += v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+				u = fabs(dx-dy)-2*ss;	v = dx+dy;	v = v*v+(u<0?0:u*u);
+				sum += v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+				sum = sum>255?255:sum;	cs[3] = ca*sum/255;
+				pnt_plot(i,j,q.z+1,cs,d->ObjId);
+			}
+			break;
+		case 'S':
+			for(long j=y1;j<=y2;j++)	for(long i=x1;i<=x2;i++)
+			{
+				register float dx=i-q.x, dy=j-q.y, v,u;
+				u = fabs(dy)-ss;	if(u<0)	u=0;
+				v = fabs(dx)-ss;	if(v<0)	v=0;	v = u*u+v*v;
+				register int sum = v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+				cs[3] = ca*sum/255;
+				pnt_plot(i,j,q.z+1,cs,d->ObjId);
+			}
+			break;
+		case 's':
+			for(long j=y1;j<=y2;j++)	for(long i=x1;i<=x2;i++)
+			{
+				register float dx=i-q.x, dy=j-q.y, v,u;
+				register int sum=0;
+				u = fabs(dy)-ss;	v = (dx-ss)*(dx-ss)+(u<0?0:u*u);
+				sum += v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+				u = fabs(dy)-ss;	v = (dx+ss)*(dx+ss)+(u<0?0:u*u);
+				sum += v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+				u = fabs(dx)-ss;	v = (dy-ss)*(dy-ss)+(u<0?0:u*u);
+				sum += v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+				u = fabs(dx)-ss;	v = (dy+ss)*(dy+ss)+(u<0?0:u*u);
+				sum += v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+				sum = sum>255?255:sum;	cs[3] = ca*sum/255;
+				pnt_plot(i,j,q.z+1,cs,d->ObjId);
+			}
+			break;
+		case 'D':
+			for(long j=y1;j<=y2;j++)	for(long i=x1;i<=x2;i++)
+			{
+				register float dx=i-q.x, dy=j-q.y, v,u;
+				u = fabs(dx-dy)-ss;	if(u<0)	u=0;
+				v = fabs(dx+dy)-ss;	if(v<0)	v=0;	v = u*u+v*v;
+				register int sum = v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+				cs[3] = ca*sum/255;
+				pnt_plot(i,j,q.z+1,cs,d->ObjId);
+			}
+			break;
+		case 'd':
+			for(long j=y1;j<=y2;j++)	for(long i=x1;i<=x2;i++)
+			{
+				register float dx=i-q.x, dy=j-q.y, v,u;
+				register int sum=0;
+				u = fabs(dx+dy)-ss;	v = (dx-dy-ss)*(dx-dy-ss)+(u<0?0:u*u);
+				sum += v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+				u = fabs(dx+dy)-ss;	v = (dx-dy+ss)*(dx-dy+ss)+(u<0?0:u*u);
+				sum += v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+				u = fabs(dx-dy)-ss;	v = (dx+dy-ss)*(dx+dy-ss)+(u<0?0:u*u);
+				sum += v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+				u = fabs(dx-dy)-ss;	v = (dx+dy+ss)*(dx+dy+ss)+(u<0?0:u*u);
+				sum += v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+				sum = sum>255?255:sum;	cs[3] = ca*sum/255;
+				pnt_plot(i,j,q.z+1,cs,d->ObjId);
+			}
+			break;
+		case 'Y':
+			for(long j=y1;j<=y2;j++)	for(long i=x1;i<=x2;i++)
+			{
+				register float dx=i-q.x, dy=j-q.y, v,u;
+				register int sum=0;
+				u = fabs(dy+ss/2)-ss/2;	v = dx*dx+(u<0?0:u*u);
+				sum += v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+				u = fabs(0.87*dx+0.5*dy-ss/2)-ss/2;	v = (0.5*dx-0.87*dy)*(0.5*dx-0.87*dy)+(u<0?0:u*u);
+				sum += v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+				u = fabs(-0.87*dx+0.5*dy-ss/2)-ss/2;	v = (0.5*dx+0.87*dy)*(0.5*dx+0.87*dy)+(u<0?0:u*u);
+				sum += v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+				sum = sum>255?255:sum;	cs[3] = ca*sum/255;
+				pnt_plot(i,j,q.z+1,cs,d->ObjId);
+			}
+			break;
+		case '*':
+			for(long j=y1;j<=y2;j++)	for(long i=x1;i<=x2;i++)
+			{
+				register float dx=i-q.x, dy=j-q.y, v,u;
+				register int sum=0;
+				u = fabs(dy)-ss;	v = dx*dx+(u<0?0:u*u);
+				sum += v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+				u = fabs(0.87*dx+0.5*dy)-ss;	v = (0.5*dx-0.87*dy)*(0.5*dx-0.87*dy)+(u<0?0:u*u);
+				sum += v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+				u = fabs(-0.87*dx+0.5*dy)-ss;	v = (0.5*dx+0.87*dy)*(0.5*dx+0.87*dy)+(u<0?0:u*u);
+				sum += v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+				sum = sum>255?255:sum;	cs[3] = ca*sum/255;
+				pnt_plot(i,j,q.z+1,cs,d->ObjId);
+			}
+			break;
+		case 'T':
+			for(long j=y1;j<=y2;j++)	for(long i=x1;i<=x2;i++)
+			{
+				register float dx=i-q.x, dy=j-q.y, v,u;
+				u=dy/1.5+ss/3;	v=(dx+ss-u)/2;
+				if(u>0 && v>0 && u+v<ss)	cs[3]=ca;
+				else
+				{
+					register int sum=0;
+					u = fabs(dx)-ss;	v = dy+ss/2;	v = v*v+(u<0?0:u*u);
+					sum += v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+					u = fabs(0.55*dx+0.83*dy)-0.9*ss;	v = 0.83*dx-0.55*dy+0.55*ss;	v = v*v+(u<0?0:u*u);
+					sum += v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+					u = fabs(0.55*dx-0.83*dy)-0.9*ss;	v = 0.83*dx+0.55*dy-0.55*ss;	v = v*v+(u<0?0:u*u);
+					sum += v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+					sum = sum>255?255:sum;	cs[3] = ca*sum/255;
+				}
+				pnt_plot(i,j,q.z+1,cs,d->ObjId);
+			}
+			break;
+		case '^':
+			for(long j=y1;j<=y2;j++)	for(long i=x1;i<=x2;i++)
+			{
+				register float dx=i-q.x, dy=j-q.y, v,u;
+				register int sum=0;
+				u = fabs(dx)-ss;	v = dy+ss/2;	v = v*v+(u<0?0:u*u);
+				sum += v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+				u = fabs(0.55*dx+0.83*dy)-0.9*ss;	v = 0.83*dx-0.55*dy+0.55*ss;	v = v*v+(u<0?0:u*u);
+				sum += v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+				u = fabs(0.55*dx-0.83*dy)-0.9*ss;	v = 0.83*dx+0.55*dy-0.55*ss;	v = v*v+(u<0?0:u*u);
+				sum += v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+				sum = sum>255?255:sum;	cs[3] = ca*sum/255;
+				pnt_plot(i,j,q.z+1,cs,d->ObjId);
+			}
+			break;
+		case 'V':
+			for(long j=y1;j<=y2;j++)	for(long i=x1;i<=x2;i++)
+			{
+				register float dx=i-q.x, dy=j-q.y, v,u;
+				u=-dy/1.5+ss/3;	v=(dx+ss-u)/2;
+				if(u>0 && v>0 && u+v<ss)	cs[3]=ca;
+				else
+				{
+					register int sum=0;
+					u = fabs(dx)-ss;	v = dy-ss/2;	v = v*v+(u<0?0:u*u);
+					sum += v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+					u = fabs(0.55*dx+0.83*dy)-0.9*ss;	v = 0.83*dx-0.55*dy-0.55*ss;	v = v*v+(u<0?0:u*u);
+					sum += v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+					u = fabs(0.55*dx-0.83*dy)-0.9*ss;	v = 0.83*dx+0.55*dy+0.55*ss;	v = v*v+(u<0?0:u*u);
+					sum += v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+					sum = sum>255?255:sum;	cs[3] = ca*sum/255;
+				}
+				pnt_plot(i,j,q.z+1,cs,d->ObjId);
+			}
+			break;
+		case 'v':
+			for(long j=y1;j<=y2;j++)	for(long i=x1;i<=x2;i++)
+			{
+				register float dx=i-q.x, dy=j-q.y, v,u;
+				register int sum=0;
+				u = fabs(dx)-ss;	v = dy-ss/2;	v = v*v+(u<0?0:u*u);
+				sum += v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+				u = fabs(0.55*dx+0.83*dy)-0.9*ss;	v = 0.83*dx-0.55*dy-0.55*ss;	v = v*v+(u<0?0:u*u);
+				sum += v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+				u = fabs(0.55*dx-0.83*dy)-0.9*ss;	v = 0.83*dx+0.55*dy+0.55*ss;	v = v*v+(u<0?0:u*u);
+				sum += v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+				sum = sum>255?255:sum;	cs[3] = ca*sum/255;
+				pnt_plot(i,j,q.z+1,cs,d->ObjId);
+			}
+			break;
+		case 'L':
+			for(long j=y1;j<=y2;j++)	for(long i=x1;i<=x2;i++)
+			{
+				register float dx=i-q.x, dy=j-q.y, v,u;
+				u=-dx/1.5+ss/3;	v=(dy+ss-u)/2;
+				if(u>0 && v>0 && u+v<ss)	cs[3]=ca;
+				else
+				{
+					register int sum=0;
+					u = fabs(dy)-ss;	v = dx-ss/2;	v = v*v+(u<0?0:u*u);
+					sum += v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+					u = fabs(0.55*dy+0.83*dx)-0.9*ss;	v = 0.83*dy-0.55*dx-0.55*ss;	v = v*v+(u<0?0:u*u);
+					sum += v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+					u = fabs(0.55*dy-0.83*dx)-0.9*ss;	v = 0.83*dy+0.55*dx+0.55*ss;	v = v*v+(u<0?0:u*u);
+					sum += v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+					sum = sum>255?255:sum;	cs[3] = ca*sum/255;
+				}
+				pnt_plot(i,j,q.z+1,cs,d->ObjId);
+			}
+			break;
+		case '<':
+			for(long j=y1;j<=y2;j++)	for(long i=x1;i<=x2;i++)
+			{
+				register float dx=i-q.x, dy=j-q.y, v,u;
+				register int sum=0;
+				u = fabs(dy)-ss;	v = dx-ss/2;	v = v*v+(u<0?0:u*u);
+				sum += v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+				u = fabs(0.55*dy+0.83*dx)-0.9*ss;	v = 0.83*dy-0.55*dx-0.55*ss;	v = v*v+(u<0?0:u*u);
+				sum += v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+				u = fabs(0.55*dy-0.83*dx)-0.9*ss;	v = 0.83*dy+0.55*dx+0.55*ss;	v = v*v+(u<0?0:u*u);
+				sum += v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+				sum = sum>255?255:sum;	cs[3] = ca*sum/255;
+				pnt_plot(i,j,q.z+1,cs,d->ObjId);
+			}
+			break;
+		case 'R':
+			for(long j=y1;j<=y2;j++)	for(long i=x1;i<=x2;i++)
+			{
+				register float dx=i-q.x, dy=j-q.y, v,u;
+				u=dx/1.5+ss/3;	v=(dy+ss-u)/2;
+				if(u>0 && v>0 && u+v<ss)	cs[3]=ca;
+				else
+				{
+					register int sum=0;
+					u = fabs(dy)-ss;	v = dx+ss/2;	v = v*v+(u<0?0:u*u);
+					sum += v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+					u = fabs(0.55*dy+0.83*dx)-0.9*ss;	v = 0.83*dy-0.55*dx+0.55*ss;	v = v*v+(u<0?0:u*u);
+					sum += v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+					u = fabs(0.55*dy-0.83*dx)-0.9*ss;	v = 0.83*dy+0.55*dx-0.55*ss;	v = v*v+(u<0?0:u*u);
+					sum += v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+					sum = sum>255?255:sum;	cs[3] = ca*sum/255;
+				}
+				pnt_plot(i,j,q.z+1,cs,d->ObjId);
+			}
+			break;
+		case '>':
+			for(long j=y1;j<=y2;j++)	for(long i=x1;i<=x2;i++)
+			{
+				register float dx=i-q.x, dy=j-q.y, v,u;
+				register int sum=0;
+				u = fabs(dy)-ss;	v = dx+ss/2;	v = v*v+(u<0?0:u*u);
+				sum += v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+				u = fabs(0.55*dy+0.83*dx)-0.9*ss;	v = 0.83*dy-0.55*dx+0.55*ss;	v = v*v+(u<0?0:u*u);
+				sum += v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+				u = fabs(0.55*dy-0.83*dx)-0.9*ss;	v = 0.83*dy+0.55*dx-0.55*ss;	v = v*v+(u<0?0:u*u);
+				sum += v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+				sum = sum>255?255:sum;	cs[3] = ca*sum/255;
+				pnt_plot(i,j,q.z+1,cs,d->ObjId);
+			}
+			break;
+		case 'O':
+			for(long j=y1;j<=y2;j++)	for(long i=x1;i<=x2;i++)
+			{
+				register float dx=i-q.x, dy=j-q.y, v;
+				v = hypot(dx,dy)-ss;	v=v<0?0:v*v;
+				register int sum = v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+				cs[3] = ca*sum/255;
+				pnt_plot(i,j,q.z+1,cs,d->ObjId);
+			}
+			break;
+		case 'o':
+			for(long j=y1;j<=y2;j++)	for(long i=x1;i<=x2;i++)
+			{
+				register float dx=i-q.x, dy=j-q.y, v;
+				v = hypot(dx,dy)-ss;	v=v*v;
+				register int sum = v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+				cs[3] = ca*sum/255;
+				pnt_plot(i,j,q.z+1,cs,d->ObjId);
+			}
+			break;
+		case 'C':
+			for(long j=y1;j<=y2;j++)	for(long i=x1;i<=x2;i++)
+			{
+				register float dx=i-q.x, dy=j-q.y, v;
+				v = hypot(dx,dy)-ss;	v=v*v;
+				register int sum = v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
+				v = dx*dx+dy*dy;
+				sum += v<(2*pw-1)*(2*pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-2*pw)/2));
+				sum = sum>255?255:sum;	cs[3] = ca*sum/255;		cs[3] = ca*sum/255;
+				pnt_plot(i,j,q.z+1,cs,d->ObjId);
+			}
+			break;
+		}
+	}
+}
+//-----------------------------------------------------------------------------
+void mglCanvas::mark_pix(long i, long j, const mglPnt &q, char type, mreal size, mglDrawReg *d)
+{
 	unsigned char cs[4];	col2int(q,cs,d->ObjId);	cs[3] = size>0 ? 255 : 255*q.t;
 	mglPnt p0=q,p1=q,p2=q,p3=q;
 	mreal ss=fabs(size);
-	register long i,j;
 
 	if(type=='.' || ss==0)
 	{
 		if(d)	d->PenWidth = ss?ss:sqrt(font_factor/400);
-		pnt_draw(q,d);
+		pnt_pix(i,j,q,d);
 	}
 	else
 	{
 		if(d)
 		{
-			d->PDef = 0xffff;	d->PenWidth*=fabs(50*size);
+			d->PDef = MGL_SOLID_MASK;	d->angle = 0;
+			d->PenWidth*=fabs(50*size);
 			if(d->PenWidth<1)	d->PenWidth=1;
 		}
 		if(!strchr("xsSoO",type))	ss *= 1.1;
@@ -827,118 +1469,126 @@ void mglCanvas::mark_draw(const mglPnt &q, char type, mreal size, mglDrawReg *d)
 		case 'P':
 			p0.x = q.x-ss;	p0.y = q.y-ss;	p1.x = q.x+ss;	p1.y = q.y-ss;
 			p2.x = q.x+ss;	p2.y = q.y+ss;	p3.x = q.x-ss;	p3.y = q.y+ss;
-			line_draw(p0,p1,d);	line_draw(p1,p2,d);
-			line_draw(p2,p3,d);	line_draw(p3,p0,d);
+			line_pix(i,j,p0,p1,d);	line_pix(i,j,p1,p2,d);
+			line_pix(i,j,p2,p3,d);	line_pix(i,j,p3,p0,d);
 		case '+':
-			p0.x = q.x-ss;	p0.y = q.y;	p1.x = q.x+ss;	p1.y = q.y;	line_draw(p0,p1,d);
-			p2.x = q.x;	p2.y = q.y-ss;	p3.x = q.x;	p3.y = q.y+ss;	line_draw(p2,p3,d);
+			p0.x = q.x-ss;	p0.y = q.y;	p1.x = q.x+ss;	p1.y = q.y;	line_pix(i,j,p0,p1,d);
+			p2.x = q.x;	p2.y = q.y-ss;	p3.x = q.x;	p3.y = q.y+ss;	line_pix(i,j,p2,p3,d);
 			break;
 		case 'X':
 			p0.x = q.x-ss;	p0.y = q.y-ss;	p1.x = q.x+ss;	p1.y = q.y-ss;
 			p2.x = q.x+ss;	p2.y = q.y+ss;	p3.x = q.x-ss;	p3.y = q.y+ss;
-			line_draw(p0,p1,d);	line_draw(p1,p2,d);
-			line_draw(p2,p3,d);	line_draw(p3,p0,d);
+			line_pix(i,j,p0,p1,d);	line_pix(i,j,p1,p2,d);
+			line_pix(i,j,p2,p3,d);	line_pix(i,j,p3,p0,d);
 		case 'x':
-			p0.x = q.x-ss;	p0.y = q.y-ss;	p1.x = q.x+ss;	p1.y = q.y+ss;	line_draw(p0,p1,d);
-			p2.x = q.x+ss;	p2.y = q.y-ss;	p3.x = q.x-ss;	p3.y = q.y+ss;	line_draw(p2,p3,d);
+			p0.x = q.x-ss;	p0.y = q.y-ss;	p1.x = q.x+ss;	p1.y = q.y+ss;	line_pix(i,j,p0,p1,d);
+			p2.x = q.x+ss;	p2.y = q.y-ss;	p3.x = q.x-ss;	p3.y = q.y+ss;	line_pix(i,j,p2,p3,d);
 			break;
 		case 'S':
 			p0.x = q.x-ss;	p0.y = q.y-ss;	p1.x = q.x-ss;	p1.y = q.y+ss;
 			p2.x= q.x+ss;	p2.y= q.y+ss;	p3.x = q.x+ss;	p3.y = q.y-ss;
-			quad_draw(p0,p1,p3,p2,d);
+			quad_pix(i,j,p0,p1,p3,p2,d);
 		case 's':
 			p0.x = q.x-ss;	p0.y = q.y-ss;	p1.x = q.x+ss;	p1.y = q.y-ss;
 			p2.x = q.x+ss;	p2.y = q.y+ss;	p3.x = q.x-ss;	p3.y = q.y+ss;
-			line_draw(p0,p1,d);	line_draw(p1,p2,d);
-			line_draw(p2,p3,d);	line_draw(p3,p0,d);
+			line_pix(i,j,p0,p1,d);	line_pix(i,j,p1,p2,d);
+			line_pix(i,j,p2,p3,d);	line_pix(i,j,p3,p0,d);
 			break;
 		case 'D':
 			p0.x = q.x;	p0.y = q.y-ss;	p1.x = q.x+ss;	p1.y = q.y;
 			p2.x= q.x;	p2.y= q.y+ss;	p3.x = q.x-ss;	p3.y = q.y;
-			quad_draw(p0,p1,p3,p2,d);
+			quad_pix(i,j,p0,p1,p3,p2,d);
 		case 'd':
 			p0.x = q.x;	p0.y = q.y-ss;	p1.x = q.x+ss;	p1.y = q.y;
 			p2.x = q.x;	p2.y = q.y+ss;	p3.x = q.x-ss;	p3.y = q.y;
-			line_draw(p0,p1,d);	line_draw(p1,p2,d);
-			line_draw(p2,p3,d);	line_draw(p3,p0,d);
+			line_pix(i,j,p0,p1,d);	line_pix(i,j,p1,p2,d);
+			line_pix(i,j,p2,p3,d);	line_pix(i,j,p3,p0,d);
 			break;
 		case 'Y':
-			p1.x = q.x;	p1.y = q.y-ss;	line_draw(q,p1,d);
-			p2.x = q.x-0.8*ss;	p2.y = q.y+0.6*ss;	line_draw(q,p2,d);
-			p3.x = q.x+0.8*ss;	p3.y = q.y+0.6*ss;	line_draw(q,p3,d);
+			p1.x = q.x;	p1.y = q.y-ss;	line_pix(i,j,q,p1,d);
+			p2.x = q.x-0.8*ss;	p2.y = q.y+0.6*ss;	line_pix(i,j,q,p2,d);
+			p3.x = q.x+0.8*ss;	p3.y = q.y+0.6*ss;	line_pix(i,j,q,p3,d);
 			break;
 		case '*':
 			p0.x = q.x-ss;		p0.y = q.y;
-			p1.x = q.x+ss;		p1.y = q.y;	line_draw(p0,p1,d);
+			p1.x = q.x+ss;		p1.y = q.y;	line_pix(i,j,p0,p1,d);
 			p0.x = q.x-0.6*ss;	p0.y = q.y-0.8*ss;
-			p1.x = q.x+0.6*ss;	p1.y = q.y+0.8*ss;	line_draw(p0,p1,d);
+			p1.x = q.x+0.6*ss;	p1.y = q.y+0.8*ss;	line_pix(i,j,p0,p1,d);
 			p0.x = q.x-0.6*ss;	p0.y = q.y+0.8*ss;
-			p1.x = q.x+0.6*ss;	p1.y = q.y-0.8*ss;	line_draw(p0,p1,d);
+			p1.x = q.x+0.6*ss;	p1.y = q.y-0.8*ss;	line_pix(i,j,p0,p1,d);
 			break;
 		case 'T':
 			p0.x = q.x-ss;	p0.y = q.y-ss/2;
 			p1.x = q.x+ss;	p1.y = q.y-ss/2;
 			p2.x= q.x;		p2.y= q.y+ss;
-			trig_draw(p0,p1,p2,false,d);
+			trig_pix(i,j,p0,p1,p2,false,d);
 		case '^':
 			p0.x = q.x-ss;	p0.y = q.y-ss/2;
 			p1.x = q.x+ss;	p1.y = q.y-ss/2;
 			p2.x= q.x;		p2.y= q.y+ss;
-			line_draw(p0,p1,d);	line_draw(p1,p2,d);
-			line_draw(p2,p0,d);	break;
+			line_pix(i,j,p0,p1,d);	line_pix(i,j,p1,p2,d);
+			line_pix(i,j,p2,p0,d);	break;
 		case 'V':
 			p0.x = q.x-ss;	p0.y = q.y+ss/2;
 			p1.x = q.x+ss;	p1.y = q.y+ss/2;
 			p2.x= q.x;		p2.y= q.y-ss;
-			trig_draw(p0,p1,p2,false,d);
+			trig_pix(i,j,p0,p1,p2,false,d);
 		case 'v':
 			p0.x = q.x-ss;	p0.y = q.y+ss/2;
 			p1.x = q.x+ss;	p1.y = q.y+ss/2;
 			p2.x= q.x;		p2.y= q.y-ss;
-			line_draw(p0,p1,d);	line_draw(p1,p2,d);
-			line_draw(p2,p0,d);	break;
+			line_pix(i,j,p0,p1,d);	line_pix(i,j,p1,p2,d);
+			line_pix(i,j,p2,p0,d);	break;
 		case 'L':
 			p0.x = q.x+ss/2;	p0.y = q.y+ss;
 			p1.x = q.x+ss/2;	p1.y = q.y-ss;
 			p2.x= q.x-ss;		p2.y= q.y;
-			trig_draw(p0,p1,p2,false,d);
+			trig_pix(i,j,p0,p1,p2,false,d);
 		case '<':
 			p0.x = q.x+ss/2;	p0.y = q.y+ss;
 			p1.x = q.x+ss/2;	p1.y = q.y-ss;
 			p2.x= q.x-ss;		p2.y= q.y;
-			line_draw(p0,p1,d);	line_draw(p1,p2,d);
-			line_draw(p2,p0,d);	break;
+			line_pix(i,j,p0,p1,d);	line_pix(i,j,p1,p2,d);
+			line_pix(i,j,p2,p0,d);	break;
 		case 'R':
 			p0.x = q.x-ss/2;	p0.y = q.y+ss;
 			p1.x = q.x-ss/2;	p1.y = q.y-ss;
 			p2.x= q.x+ss;		p2.y= q.y;
-			trig_draw(p0,p1,p2,false,d);
+			trig_pix(i,j,p0,p1,p2,false,d);
 		case '>':
 			p0.x = q.x-ss/2;	p0.y = q.y+ss;
 			p1.x = q.x-ss/2;	p1.y = q.y-ss;
 			p2.x= q.x+ss;		p2.y= q.y;
-			line_draw(p0,p1,d);	line_draw(p1,p2,d);
-			line_draw(p2,p0,d);	break;
+			line_pix(i,j,p0,p1,d);	line_pix(i,j,p1,p2,d);
+			line_pix(i,j,p2,p0,d);	break;
 		case 'O':
-			for(j=long(-ss);j<=long(ss);j++)	for(i=long(-ss);i<=long(ss);i++)
 			{
-				register long x=long(q.x)+i, y=long(q.y)+j;
-				if(i*i+j*j>=ss*ss || !d || x<d->x1 || x>d->x2 || y<d->y1 || y>d->y2)	continue;
-				pnt_plot(x,y,q.z+1,cs,d->ObjId);
+				register float xx = (i-q.x), yy = (j-q.y);
+				register float dz = Width>2 ? 1 : 1e-5*Width;		// provide additional height to be well visible on the surfaces
+				if(xx*xx+yy*yy<ss*ss)	pnt_plot(i,j,q.z+dz,cs,d->ObjId);
+				// TODO add edge smoothing here?
 			}
 		case 'o':
-			for(i=0;i<=20;i++)
 			{
-				p0 = p1;	p1.x = q.x+ss*cos(i*M_PI/10);	p1.y = q.y+ss*sin(i*M_PI/10);
-				if(i>0)	line_draw(p0,p1,d);
+				register float pw=d->PenWidth, dpw=2;
+				register float xx = (i-q.x), yy = (j-q.y), v = hypot(xx,yy);
+				v = (v-ss)*(v-ss);
+				if(v>pw*pw)	return;
+				if(v>(pw-1)*(pw-1)/4)	cs[3] = mgl_sline(cs[3],dpw*(sqrt(v)+(1-pw)/2));
+				register float dz = Width>2 ? 1 : 1e-5*Width;		// provide additional height to be well visible on the surfaces
+				pnt_plot(i,j,q.z+dz,cs,d->ObjId);
 			}
 			break;
 		case 'C':
-			pnt_draw(q,d);
-			for(i=0;i<=20;i++)
+			pnt_pix(i,j,q,d);
 			{
-				p0 = p1;	p1.x = q.x+ss*cos(i*M_PI/10);	p1.y = q.y+ss*sin(i*M_PI/10);
-				if(i>0)	line_draw(p0,p1,d);
+				register float pw=d->PenWidth, dpw=2;
+				register float xx = (i-q.x), yy = (j-q.y), v = hypot(xx,yy);
+				v = (v-ss)*(v-ss);
+				if(v>pw*pw)	return;
+				if(v>(pw-1)*(pw-1)/4)	cs[3] = mgl_sline(cs[3],dpw*(sqrt(v)+(1-pw)/2));
+				register float dz = Width>2 ? 1 : 1e-5*Width;		// provide additional height to be well visible on the surfaces
+				pnt_plot(i,j,q.z+dz,cs,d->ObjId);
 			}
 			break;
 		}
@@ -972,63 +1622,57 @@ void mglCanvas::glyph_draw(const mglPrim &P, mglDrawReg *d)
 	float phi = GetGlyphPhi(Pnt[P.n2],P.w);
 	if(mgl_isnan(phi))	return;
 
+	if(d)	{	d->PDef = MGL_SOLID_MASK;	d->angle = 0;	d->PenWidth=0.6;	}
 	mglPnt p=Pnt[P.n1];
 	mreal pf=sqrt((Bp.b[0]*Bp.b[0]+Bp.b[1]*Bp.b[1]+Bp.b[3]*Bp.b[3]+Bp.b[4]*Bp.b[4])/2), f = P.p*pf;
-#if MGL_HAVE_PTHREAD
-	pthread_mutex_lock(&mutexPnt);
-#endif
-	Push();		B.clear();
-	B.b[0] = B.b[4] = B.b[8] = P.s;
-	RotateN(phi,0,0,1);
-	B.x=p.x;	B.y=p.y;	B.z=p.z;	B.pf = 1;
+
+	mglMatrix M;
+	M.b[0] = M.b[4] = M.b[8] = P.s;
+	M.RotateN(phi,0,0,1);
+	M.x=p.x;	M.y=p.y;	M.z=p.z;	M.pf = 1;
 	p.u *= pf;	p.v *= pf;
 
 	const mglGlyph &g = Glf[P.n4];
 	if(P.n3&8)
 	{
-		if(!(P.n3&4))	glyph_line(p,f,true, d);
-		glyph_line(p,f,false, d);
+		if(!(P.n3&4))	glyph_line(&M,p,f,true, d);
+		glyph_line(&M,p,f,false, d);
 	}
 	else
 	{
-		if(!(P.n3&4))	glyph_fill(p,f,g, d);
-		glyph_wire(p,f,g, d);
+		if(!(P.n3&4))	glyph_fill(&M,p,f,g, d);
+		glyph_wire(&M,p,f,g, d);
 	}
-	Pop();
-#if MGL_HAVE_PTHREAD
-	pthread_mutex_unlock(&mutexPnt);
-#endif
 }
 //-----------------------------------------------------------------------------
-void mglCanvas::glyph_fill(const mglPnt &pp, mreal f, const mglGlyph &g, mglDrawReg *d)
+void mglCanvas::glyph_fill(const mglMatrix *M, const mglPnt &pp, mreal f, const mglGlyph &g, const mglDrawReg *d)
 {
 	if(!g.trig || g.nt<=0)	return;
-	long ik,ii;
 	mglPnt q0=pp, q1=pp, q2=pp;
 	q0.u=q0.v=q1.u=q1.v=q2.u=q2.v=NAN;
-	mglPoint p1,p2,p3;
-	for(ik=0;ik<g.nt;ik++)
+	for(long ik=0;ik<g.nt;ik++)
 	{
-		ii = 6*ik;	p1 = mglPoint(f*g.trig[ii]+pp.u,f*g.trig[ii+1]+pp.v,0);	PostScale(p1);
-		ii+=2;		p2 = mglPoint(f*g.trig[ii]+pp.u,f*g.trig[ii+1]+pp.v,0);	PostScale(p2);
-		ii+=2;		p3 = mglPoint(f*g.trig[ii]+pp.u,f*g.trig[ii+1]+pp.v,0);	PostScale(p3);
-		q0.x = p1.x;	q0.y = p1.y;	q0.z = p1.z;
-		q1.x = p2.x;	q1.y = p2.y;	q1.z = p2.z;
-		q2.x = p3.x;	q2.y = p3.y;	q2.z = p3.z;
+		register long ii = 6*ik;	mglPoint p;
+		p = mglPoint(f*g.trig[ii]+pp.u,f*g.trig[ii+1]+pp.v,0);
+		PostScale(M,p);	q0.x = p.x;	q0.y = p.y;	q0.z = p.z;
+		ii+=2;	p = mglPoint(f*g.trig[ii]+pp.u,f*g.trig[ii+1]+pp.v,0);
+		PostScale(M,p);	q1.x = p.x;	q1.y = p.y;	q1.z = p.z;
+		ii+=2;	p = mglPoint(f*g.trig[ii]+pp.u,f*g.trig[ii+1]+pp.v,0);
+		PostScale(M,p);	q2.x = p.x;	q2.y = p.y;	q2.z = p.z;
 		trig_draw(q0,q1,q2,false,d);
 	}
 }
 //-----------------------------------------------------------------------------
-void mglCanvas::glyph_wire(const mglPnt &pp, mreal f, const mglGlyph &g, mglDrawReg *d)
+void mglCanvas::glyph_wire(const mglMatrix *M, const mglPnt &pp, mreal f, const mglGlyph &g, const mglDrawReg *d)
 {
 	if(!g.line || g.nl<=0)	return;
-	long ik,ii,il=0;
+	long il=0;
 	mglPnt q0=pp, q1=pp;	q0.u=q0.v=q1.u=q1.v=NAN;
-	if(d)	{	d->PDef = 0xffff;	d->PenWidth=0.75;	}
 	mglPoint p1,p2;
-	for(ik=0;ik<g.nl;ik++)
+//#pragma omp parallel for firstprivate(q0,q1,i1) private(p1,p2)
+	for(long ik=0;ik<g.nl;ik++)
 	{
-		ii = 2*ik;
+		register long ii = 2*ik;
 		if(g.line[ii]==0x3fff && g.line[ii+1]==0x3fff)	// line breakthrough
 		{	il = ik+1;	continue;	}
 		else if(ik==g.nl-1 || (g.line[ii+2]==0x3fff && g.line[ii+3]==0x3fff))
@@ -1041,25 +1685,24 @@ void mglCanvas::glyph_wire(const mglPnt &pp, mreal f, const mglGlyph &g, mglDraw
 			p1 = mglPoint(f*g.line[ii]+pp.u,f*g.line[ii+1]+pp.v,0);	ii+=2;
 			p2 = mglPoint(f*g.line[ii]+pp.u,f*g.line[ii+1]+pp.v,0);
 		}
-		PostScale(p1);	PostScale(p2);
+		PostScale(M,p1);	PostScale(M,p2);
 		q0.x = p1.x;	q0.y = p1.y;	q0.z = p1.z;
 		q1.x = p2.x;	q1.y = p2.y;	q1.z = p2.z;
 		line_draw(q0,q1,d);
 	}
 }
 //-----------------------------------------------------------------------------
-void mglCanvas::glyph_line(const mglPnt &pp, mreal f, bool solid, mglDrawReg *d)
+void mglCanvas::glyph_line(const mglMatrix *M, const mglPnt &pp, mreal f, bool solid, const mglDrawReg *d)
 {
 	mglPnt q0=pp,q1=pp,q2=pp,q3=pp;
 	q0.u=q0.v=q1.u=q1.v=q2.u=q2.v=q3.u=q3.v=NAN;
-	if(d)	{	d->PDef = 0xffff;	d->PenWidth=1;	}
 	mglPoint p1,p2,p3,p4;
 
 	mreal dy = 0.004;
-	p1 = mglPoint(pp.u,pp.v-dy,0);	PostScale(p1);
-	p2 = mglPoint(pp.u,pp.v+dy,0);	PostScale(p2);
-	p3 = mglPoint(fabs(f)+pp.u,pp.v+dy,0);	PostScale(p3);
-	p4 = mglPoint(fabs(f)+pp.u,pp.v-dy,0);	PostScale(p4);
+	p1 = mglPoint(pp.u,pp.v-dy,0);	PostScale(M,p1);
+	p2 = mglPoint(pp.u,pp.v+dy,0);	PostScale(M,p2);
+	p3 = mglPoint(fabs(f)+pp.u,pp.v+dy,0);	PostScale(M,p3);
+	p4 = mglPoint(fabs(f)+pp.u,pp.v-dy,0);	PostScale(M,p4);
 
 	q0.x = p1.x;	q0.y = p1.y;	q0.z = p1.z;
 	q1.x = p2.x;	q1.y = p2.y;	q1.z = p2.z;
@@ -1074,27 +1717,129 @@ void mglCanvas::glyph_line(const mglPnt &pp, mreal f, bool solid, mglDrawReg *d)
 	}
 }
 //-----------------------------------------------------------------------------
+void mglCanvas::glyph_pix(long i, long j, const mglPrim &P, mglDrawReg *d)
+{
+	float phi = GetGlyphPhi(Pnt[P.n2],P.w);
+	if(mgl_isnan(phi))	return;
+
+	if(d)	{	d->PDef = MGL_SOLID_MASK;	d->angle = 0;	d->PenWidth=1;	}
+	mglPnt p=Pnt[P.n1];
+	mreal pf=sqrt((Bp.b[0]*Bp.b[0]+Bp.b[1]*Bp.b[1]+Bp.b[3]*Bp.b[3]+Bp.b[4]*Bp.b[4])/2), f = P.p*pf;
+
+	mglMatrix M;
+	M.b[0] = M.b[4] = M.b[8] = P.s;
+	M.RotateN(phi,0,0,1);
+	M.x=p.x;	M.y=p.y;	M.z=p.z;	M.pf = 1;
+	p.u *= pf;	p.v *= pf;
+
+	const mglGlyph &g = Glf[P.n4];
+	if(P.n3&8)
+	{
+		if(!(P.n3&4))	glyph_lpix(i,j,&M,p,f,true, d);
+		glyph_lpix(i,j,&M,p,f,false, d);
+	}
+	else
+	{
+		if(!(P.n3&4))	glyph_fpix(i,j,&M,p,f,g, d);
+		glyph_wpix(i,j,&M,p,f,g, d);
+	}
+}
+//-----------------------------------------------------------------------------
+void mglCanvas::glyph_fpix(long i, long j, const mglMatrix *M, const mglPnt &pp, mreal f, const mglGlyph &g, const mglDrawReg *d)
+{
+	if(!g.trig || g.nt<=0)	return;
+	mglPnt q0=pp, q1=pp, q2=pp;
+	q0.u=q0.v=q1.u=q1.v=q2.u=q2.v=NAN;
+	for(long ik=0;ik<g.nt;ik++)
+	{
+		register long ii = 6*ik;	mglPoint p;
+		p = mglPoint(f*g.trig[ii]+pp.u,f*g.trig[ii+1]+pp.v,0);
+		PostScale(M,p);	q0.x = p.x;	q0.y = p.y;	q0.z = p.z;
+		ii+=2;	p = mglPoint(f*g.trig[ii]+pp.u,f*g.trig[ii+1]+pp.v,0);
+		PostScale(M,p);	q1.x = p.x;	q1.y = p.y;	q1.z = p.z;
+		ii+=2;	p = mglPoint(f*g.trig[ii]+pp.u,f*g.trig[ii+1]+pp.v,0);
+		PostScale(M,p);	q2.x = p.x;	q2.y = p.y;	q2.z = p.z;
+		trig_pix(i,j,q0,q1,q2,false,d);
+	}
+}
+//-----------------------------------------------------------------------------
+void mglCanvas::glyph_wpix(long i, long j, const mglMatrix *M, const mglPnt &pp, mreal f, const mglGlyph &g, const mglDrawReg *d)
+{
+	if(!g.line || g.nl<=0)	return;
+	long il=0;
+	mglPnt q0=pp, q1=pp;	q0.u=q0.v=q1.u=q1.v=NAN;
+	mglPoint p1,p2;
+//#pragma omp parallel for firstprivate(q0,q1,i1) private(p1,p2)	// mostly useless here
+	for(long ik=0;ik<g.nl;ik++)
+	{
+		register long ii = 2*ik;
+		if(g.line[ii]==0x3fff && g.line[ii+1]==0x3fff)	// line breakthrough
+		{	il = ik+1;	continue;	}
+		else if(ik==g.nl-1 || (g.line[ii+2]==0x3fff && g.line[ii+3]==0x3fff))
+		{	// enclose the circle. May be in future this block should be commented
+			p1 = mglPoint(f*g.line[ii]+pp.u,f*g.line[ii+1]+pp.v,0);	ii=2*il;
+			p2 = mglPoint(f*g.line[ii]+pp.u,f*g.line[ii+1]+pp.v,0);
+		}
+		else
+		{	// normal line
+			p1 = mglPoint(f*g.line[ii]+pp.u,f*g.line[ii+1]+pp.v,0);	ii+=2;
+			p2 = mglPoint(f*g.line[ii]+pp.u,f*g.line[ii+1]+pp.v,0);
+		}
+		PostScale(M,p1);	PostScale(M,p2);
+		q0.x = p1.x;	q0.y = p1.y;	q0.z = p1.z;
+		q1.x = p2.x;	q1.y = p2.y;	q1.z = p2.z;
+		line_pix(i,j,q0,q1,d);
+	}
+}
+//-----------------------------------------------------------------------------
+void mglCanvas::glyph_lpix(long i, long j, const mglMatrix *M, const mglPnt &pp, mreal f, bool solid, const mglDrawReg *d)
+{
+	mglPnt q0=pp,q1=pp,q2=pp,q3=pp;
+	q0.u=q0.v=q1.u=q1.v=q2.u=q2.v=q3.u=q3.v=NAN;
+	mglPoint p1,p2,p3,p4;
+
+	mreal dy = 0.004;
+	p1 = mglPoint(pp.u,pp.v-dy,0);	PostScale(M,p1);
+	p2 = mglPoint(pp.u,pp.v+dy,0);	PostScale(M,p2);
+	p3 = mglPoint(fabs(f)+pp.u,pp.v+dy,0);	PostScale(M,p3);
+	p4 = mglPoint(fabs(f)+pp.u,pp.v-dy,0);	PostScale(M,p4);
+
+	q0.x = p1.x;	q0.y = p1.y;	q0.z = p1.z;
+	q1.x = p2.x;	q1.y = p2.y;	q1.z = p2.z;
+	q2.x = p3.x;	q2.y = p3.y;	q2.z = p3.z;
+	q3.x = p4.x;	q3.y = p4.y;	q3.z = p4.z;
+
+	if(solid)	quad_pix(i,j,q0,q1,q3,q2,d);
+	else
+	{
+		line_pix(i,j,q0,q1,d);	line_pix(i,j,q2,q1,d);
+		line_pix(i,j,q0,q3,d);	line_pix(i,j,q2,q3,d);
+	}
+}
+//-----------------------------------------------------------------------------
 long mglCanvas::setPp(mglPnt &q, const mglPoint &p)
 {
 	q.xx=q.x=p.x;	q.yy=q.y=p.y;	q.zz=q.z=p.z;
-	MGL_PUSH(Pnt,q,mutexPnt);
-	return Pnt.size()-1;
+	long k;
+#pragma omp critical(pnt)
+	{MGL_PUSH(Pnt,q,mutexPnt);	k=Pnt.size()-1;}
+	return k;
 }
 //-----------------------------------------------------------------------------
 void mglCanvas::arrow_draw(long n1, long n2, char st, float ll)
 {
 	const mglPnt &p1=Pnt[n1], &p2=Pnt[n2];
 	mglPnt q=p1; 	//q.u=q.v=q.w=0;
-	
+
 	mglPoint kl=mglPoint(p1.x-p2.x,p1.y-p2.y,p1.z-p2.z), kt, p0=mglPoint(p1.x,p1.y,p1.z), p;
 	mreal d = hypot(kl.x,kl.y);
 	if(d==0)	return;
 	kl /= d;	kt = !kl;
 	kl *= ll;	kt *= ll;
-	
+
 	Reserve(8);
 	long k1,k2,k3,k4;
-	
+
 	switch(st)	// S,D -- cube, T -- sq.pyramid, I -- square, O -- sphere???, A,K,V -- cone???
 	{
 		case 'I':
@@ -1135,15 +1880,15 @@ void mglCanvas::arrow_plot_3d(long n1, long n2, char st, float ll)
 {
 	const mglPnt &p1=Pnt[n1], &p2=Pnt[n2];
 	mglPnt q=p1; 	//q.u=q.v=q.w=0;
-	
+
 	mglPoint kl=mglPoint(p1.x-p2.x,p1.y-p2.y,p1.z-p2.z), kt, kz, p0=mglPoint(p1.x,p1.y,p1.z), p;
 	if(kl.norm()==0)	return;
 	kl.Normalize();	kt = !kl;	kz = kl^kt;
 	kl *= ll;	kt *= ll;	kz *= ll;
-	
+
 	Reserve(8);
 	long k1,k2,k3,k4,k5, k6,k7,k8;
-	
+
 	switch(st)	// S,D -- cube, T -- sq.pyramid, I -- square, O -- sphere???, A,K,V -- cone???
 	{
 		case 'I':
diff --git a/src/plot.cpp b/src/plot.cpp
index 9eb448d..6bc7316 100644
--- a/src/plot.cpp
+++ b/src/plot.cpp
@@ -20,6 +20,7 @@
 #include "mgl2/plot.h"
 #include "mgl2/eval.h"
 #include "mgl2/data.h"
+#include "mgl2/base.h"
 //-----------------------------------------------------------------------------
 //
 //	Plot by formulas series
@@ -35,18 +36,32 @@ void MGL_EXPORT mgl_fplot(HMGL gr, const char *eqY, const char *pen, const char
 	mreal *x = (mreal *)malloc(n*sizeof(mreal));
 	mreal *y = (mreal *)malloc(n*sizeof(mreal));
 	mglFormula *eq = new mglFormula(eqY);
-	register int i;
-	mreal d = (gr->Max.x - gr->Min.x)/(n-1.), xs, ys, yr, ym=fabs(gr->Max.y - gr->Min.y)/nd;
+	mreal xs, ys, yr, ym=fabs(gr->Max.y - gr->Min.y)/nd;
 #define islog(a, b) (((a)>0 && (b)>10*(a)) || ((b)<0 && (a)<10*(b)))
 	// initial data filling
-	if(gr->Min.x>0 && gr->Max.x>100*gr->Min.x)	for(i=0,d=log(2*gr->Max.x/gr->Min.x)/(n-1);i<n;i++)
-	{	x[i]=2*gr->Max.x*exp(d*i)/(2*gr->Max.x/gr->Min.x+exp(d*i));	y[i]=eq->Calc(x[i]);	}
-	else if(gr->Max.x<0 && gr->Min.x<100*gr->Max.x)	for(i=0,d=log(2*gr->Min.x/gr->Max.x)/n;i<n;i++)
-	{	x[i]=2*gr->Min.x*exp(d*i)/(2*gr->Min.x/gr->Max.x+exp(d*i));	y[i]=eq->Calc(x[i]);	}
-	else for(i=0;i<n;i++)
-	{	x[i]=gr->Min.x + i*d;	y[i]=eq->Calc(x[i]);	}
+	if(gr->Min.x>0 && gr->Max.x>100*gr->Min.x)
+	{
+		mreal d = log(2*gr->Max.x/gr->Min.x)/(n-1);
+#pragma omp parallel for
+		for(long i=0;i<n;i++)
+		{	x[i]=2*gr->Max.x*exp(d*i)/(2*gr->Max.x/gr->Min.x+exp(d*i));	y[i]=eq->Calc(x[i]);	}
+	}
+	else if(gr->Max.x<0 && gr->Min.x<100*gr->Max.x)
+	{
+		mreal d = log(2*gr->Min.x/gr->Max.x)/(n-1);
+#pragma omp parallel for
+		for(long i=0;i<n;i++)
+		{	x[i]=2*gr->Min.x*exp(d*i)/(2*gr->Min.x/gr->Max.x+exp(d*i));	y[i]=eq->Calc(x[i]);	}
+	}
+	else
+	{
+		mreal d = (gr->Max.x - gr->Min.x)/(n-1.);
+#pragma omp parallel for
+		for(long i=0;i<n;i++)
+		{	x[i]=gr->Min.x + i*d;	y[i]=eq->Calc(x[i]);	}
+	}
 
-	for(i=0;i<n-1 && n<nm;)
+	for(long i=0;i<n-1 && n<nm;)
 	{
 		if(gr->Stop)	{	free(x);	free(y);	delete eq;	return;	}
 		xs=(x[i]+x[i+1])/2;
@@ -82,22 +97,18 @@ void MGL_EXPORT mgl_fplot_xyz(HMGL gr, const char *eqX, const char *eqY, const c
 	ex = new mglFormula(eqX ? eqX : "0");
 	ey = new mglFormula(eqY ? eqY : "0");
 	ez = new mglFormula(eqZ ? eqZ : "0");
-	register int i;
 	mreal ts, xs, ys, zs, xr, yr, zr, xm=fabs(gr->Max.x - gr->Min.x)/1000, ym=fabs(gr->Max.y - gr->Min.y)/1000, zm=fabs(gr->Max.z - gr->Min.z)/1000;
-	for(i=0;i<n;i++)	// initial data filling
+#pragma omp parallel for
+	for(long i=0;i<n;i++)	// initial data filling
 	{
-		if(gr->Stop)
-		{
-			free(x);	free(y);	free(z);	free(t);
-			delete ex;	delete ey;	delete ez;	return;
-		}
+		if(gr->Stop)	continue;
 		t[i] = i/(n-1.);
 		x[i] = ex->Calc(0,0,t[i]);
 		y[i] = ey->Calc(0,0,t[i]);
 		z[i] = ez->Calc(0,0,t[i]);
 	}
 
-	for(i=0;i<n-1 && n<10000;)
+	for(long i=0;i<n-1 && n<10000;)
 	{
 		if(gr->Stop)
 		{
@@ -157,14 +168,17 @@ void MGL_EXPORT mgl_radar(HMGL gr, HCDT a, const char *pen, const char *opt)
 	mglData x(n+1,ny), y(n+1,ny);
 	mreal m=a->Minimal(), r=gr->SaveState(opt);
 	if(mgl_isnan(r) || r<0)	r = m<0 ? -m:0;
-	register long i,j;
-	for(j=0;j<ny;j++)
+	mreal *co=new mreal[2*n];
+#pragma omp parallel for
+	for(long i=0;i<n;i++)	{	co[i]=cos(2*i*M_PI/n);	co[i+n]=sin(2*i*M_PI/n);	}
+	for(long j=0;j<ny;j++)
 	{
-		for(i=0;i<n;i++)
+#pragma omp parallel for
+		for(long i=0;i<n;i++)
 		{
 			register mreal v = a->v(i,j);
-			x.a[i+(n+1)*j] = (r+v)*cos(2*i*M_PI/n);
-			y.a[i+(n+1)*j] = (r+v)*sin(2*i*M_PI/n);
+			x.a[i+(n+1)*j] = (r+v)*co[i];
+			y.a[i+(n+1)*j] = (r+v)*co[i+n];
 		}
 		x.a[n+(n+1)*j] = r+a->v(0,j);	y.a[n+(n+1)*j] = 0;
 	}
@@ -173,20 +187,21 @@ void MGL_EXPORT mgl_radar(HMGL gr, HCDT a, const char *pen, const char *opt)
 	{
 		m = 1.1*(a->Maximal()+r);
 		x.Create(2);	y.Create(2);
-		for(i=0;i<n;i++)
+		for(long i=0;i<n;i++)
 		{
-			x.a[1]=m*cos(2*i*M_PI/n);
-			y.a[1]=m*sin(2*i*M_PI/n);
+			x.a[1]=m*co[i];		y.a[1]=m*co[i+n];
 			mgl_plot_xy(gr,&x,&y,"k",0);
 		}
 		if(r>0)
 		{
 			x.Create(101);	y.Create(101);
-			for(i=0;i<101;i++)
-			{	x.a[i]=r*cos(2*i*M_PI/100);	y.a[i]=r*sin(2*i*M_PI/100);	}
+#pragma omp parallel for
+			for(long i=0;i<91;i++)
+			{	x.a[i]=r*mgl_cos[(4*i)%360];	y.a[i]=r*mgl_cos[(270+4*i)%360];	}
 			mgl_plot_xy(gr,&x,&y,"k",0);
 		}
 	}
+	delete []co;
 }
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_radar_(uintptr_t *gr, uintptr_t *a, const char *pen, const char *opt, int l,int lo)
@@ -200,7 +215,7 @@ void MGL_EXPORT mgl_radar_(uintptr_t *gr, uintptr_t *a, const char *pen, const c
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_candle_xyv(HMGL gr, HCDT x, HCDT v1, HCDT v2, HCDT y1, HCDT y2, const char *pen, const char *opt)
 {
-	long i,n=v1->GetNx(),pal,nx=x->GetNx();
+	long n=v1->GetNx(),pal,nx=x->GetNx();
 	if(n<2)	{	gr->SetWarn(mglWarnLow,"Candle");	return;	}
 	if(nx<n || v2->GetNx()!=n)	{	gr->SetWarn(mglWarnDim,"Candle");	return;	}
 	bool d1=false,d2=false;
@@ -213,31 +228,34 @@ void MGL_EXPORT mgl_candle_xyv(HMGL gr, HCDT x, HCDT v1, HCDT v2, HCDT y1, HCDT
 	gr->NextColor(pal);	gr->Reserve(8*n);
 	bool sh = mglchr(pen,'!');
 
-	long n1,n2,n3,n4;
-	mreal m1,m2,xx,x1,x2,d;
+	mreal dv=nx>n?1:0;
+	if(mglchr(pen,'<'))	dv = 1;
+	if(mglchr(pen,'^'))	dv = 0;
+	if(mglchr(pen,'>'))	dv = -1;
 	mreal zm = gr->AdjustZMin();
-	for(i=0;i<n;i++)
+#pragma omp parallel for
+	for(long i=0;i<n;i++)
 	{
-		if(gr->Stop)	{	if(d1)	delete y1;	if(d2)	delete y2;	return;	}
-		m1=v1->v(i);	m2 = v2->v(i);	xx = x->v(i);
-		d = i<nx-1 ? x->v(i+1)-xx : xx-x->v(i-1);
-		x1 = xx + d/2*(1-gr->BarWidth);
-		x2 = x1 + gr->BarWidth*d;	xx = (x1+x2)/2;
-		n1 = gr->AddPnt(mglPoint(xx,y1->v(i),zm));
-		n2 = gr->AddPnt(mglPoint(xx,m1,zm));
+		if(gr->Stop)	continue;
+		mreal m1=v1->v(i),	m2 = v2->v(i),	xx = x->v(i);
+		mreal d = i<nx-1 ? x->v(i+1)-xx : xx-x->v(i-1);
+		mreal x1 = xx + d/2*(dv-gr->BarWidth);
+		mreal x2 = x1 + gr->BarWidth*d;	xx = (x1+x2)/2;
+		mreal c = sh ? gr->NextColor(pal,i):gr->CDef;
+		long n1 = gr->AddPnt(mglPoint(xx,y1->v(i),zm),c);
+		long n2 = gr->AddPnt(mglPoint(xx,m1,zm),c);
 		gr->line_plot(n1,n2);
-		n3 = gr->AddPnt(mglPoint(xx,y2->v(i),zm));
-		n4 = gr->AddPnt(mglPoint(xx,m2,zm));
+		long n3 = gr->AddPnt(mglPoint(xx,y2->v(i),zm),c);
+		long n4 = gr->AddPnt(mglPoint(xx,m2,zm),c);
 		gr->line_plot(n3,n4);
 
-		n1 = gr->AddPnt(mglPoint(x1,m1,zm));
-		n2 = gr->AddPnt(mglPoint(x2,m1,zm));
-		n3 = gr->AddPnt(mglPoint(x1,m2,zm));
-		n4 = gr->AddPnt(mglPoint(x2,m2,zm));
+		n1 = gr->AddPnt(mglPoint(x1,m1,zm),c);
+		n2 = gr->AddPnt(mglPoint(x2,m1,zm),c);
+		n3 = gr->AddPnt(mglPoint(x1,m2,zm),c);
+		n4 = gr->AddPnt(mglPoint(x2,m2,zm),c);
 		gr->line_plot(n1,n2);	gr->line_plot(n1,n3);
 		gr->line_plot(n4,n2);	gr->line_plot(n4,n3);
 		if(m1>m2)	gr->quad_plot(n1,n2,n3,n4);
-		if(sh)	gr->NextColor(pal);
 	}
 	if(d1)	delete y1;	if(d2)	delete y2;
 	gr->EndGroup();
@@ -295,8 +313,8 @@ void MGL_EXPORT mgl_plot_xyz(HMGL gr, HCDT x, HCDT y, HCDT z, const char *pen, c
 
 	for(j=0;j<m;j++)
 	{
-		mx = j<x->GetNy() ? j:0;		my = j<y->GetNy() ? j:0;
-		mz = j<z->GetNy() ? j:0;		gr->NextColor(pal);
+		mx = j<x->GetNy() ? j:0;	my = j<y->GetNy() ? j:0;
+		mz = j<z->GetNy() ? j:0;	gr->NextColor(pal);
 		t1 = t2 = false;
 		register long i;
 		for(i=0;i<n;i++)
@@ -304,7 +322,8 @@ void MGL_EXPORT mgl_plot_xyz(HMGL gr, HCDT x, HCDT y, HCDT z, const char *pen, c
 			if(gr->Stop)	return;
 			if(i>0)	{	n2=n1;	p2 = p1;	t2=t1;	}
 			p1 = mglPoint(x->v(i,mx), y->v(i,my), z->v(i,mz));
-			n1 = gr->AddPnt(p1);	t1 = n1>=0;
+			mreal c = sh ? gr->NextColor(pal,i):gr->CDef;
+			n1 = gr->AddPnt(p1,c);	t1 = n1>=0;
 			if(mk && t1)	gr->mark_plot(n1,mk);
 			if(t1 && t2)
 			{
@@ -322,15 +341,14 @@ void MGL_EXPORT mgl_plot_xyz(HMGL gr, HCDT x, HCDT y, HCDT z, const char *pen, c
 					pt.x = p1.x*ii+p2.x*(1-ii);
 					pt.y = p1.y*ii+p2.y*(1-ii);
 					pt.z = p1.z*ii+p2.z*(1-ii);	p=pt;
-					t3 = gr->ScalePoint(p,q,false);
+					t3 = gr->ScalePoint(gr->GetB(),p,q,false);
 					if((t1 && t3) || (t2 && !t3))	i2 = ii;
 					else	i1 = ii;
 				} while(fabs(i2-i1)>1e-3);
-				n3 = gr->AddPnt(pt,-1,q,-1,2);
+				n3 = gr->AddPnt(pt,c,q,-1,2);
 				if(t2)	gr->line_plot(n3,n2);
 				else 	gr->line_plot(n1,n3);
 			}
-			if(sh)	gr->NextColor(pal);
 		}
 	}
 	gr->EndGroup();
@@ -420,7 +438,7 @@ void MGL_EXPORT mgl_tens_xyz(HMGL gr, HCDT x, HCDT y, HCDT z, HCDT c, const char
 					pt.y = p1.y*ii+p2.y*(1-ii);
 					pt.z = p1.z*ii+p2.z*(1-ii);	p=pt;
 					pt.c = p1.c*ii+p2.c*(1-ii);
-					t3 = gr->ScalePoint(p,q,false);
+					t3 = gr->ScalePoint(gr->GetB(),p,q,false);
 					if((t1 && t3) || (t2 && !t3))	i2 = ii;
 					else	i1 = ii;
 				} while(fabs(i2-i1)>1e-3);
@@ -498,21 +516,21 @@ void MGL_EXPORT mgl_area_xyz(HMGL gr, HCDT x, HCDT y, HCDT z, const char *pen, c
 
 		nn = mglPoint(-y->dvx(0,my),x->dvx(0,mx));
 		mglPoint p = mglPoint(x->v(0,mx),y->v(0,my),z->v(0,mz));
-		n1 = gr->AddPnt(p,c1,nn);	p.z = z0;	n2 = gr->AddPnt(p,c2,nn);
+		n1 = gr->AddPnt(p,c1,nn,-1,11);	p.z = z0;	n2 = gr->AddPnt(p,c2,nn,-1,11);
 		for(i=1;i<n;i++)
 		{
 			if(gr->Stop)	return;
 			n3=n1;	n4=n2;
 			nn = mglPoint(-y->dvx(i,my),x->dvx(i,mx));
 			p = mglPoint(x->v(i,mx),y->v(i,my),z->v(i,mz));
-			n1 = gr->AddPnt(p,c1,nn);	p.z = z0;	n2 = gr->AddPnt(p,c2,nn);
+			if(sh)	c2=c1=gr->NextColor(pal,i);
+			n1 = gr->AddPnt(p,c1,nn,-1,11);	p.z = z0;	n2 = gr->AddPnt(p,c2,nn,-1,11);
 			if(wire)
 			{
 				gr->line_plot(n1,n2);	gr->line_plot(n3,n4);
 				gr->line_plot(n1,n3);	gr->line_plot(n4,n2);
 			}
 			else	gr->quad_plot(n1,n2,n3,n4);
-			if(sh)	c2=c1=gr->NextColor(pal);
 		}
 	}
 	gr->EndGroup();
@@ -543,20 +561,20 @@ void MGL_EXPORT mgl_area_xy(HMGL gr, HCDT x, HCDT y, const char *pen, const char
 		z0 = zm + (m-1-j)*(gr->Max.z-zm)/m;
 
 		mglPoint p = mglPoint(x->v(0,mx),y->v(0,my),z0);
-		n1 = gr->AddPnt(p,c1,nn);	p.y = y0;	n2 = gr->AddPnt(p,c2,nn);
+		n1 = gr->AddPnt(p,c1,nn,-1,11);	p.y = y0;	n2 = gr->AddPnt(p,c2,nn,-1,11);
 		for(i=1;i<n;i++)
 		{
 			if(gr->Stop)	return;
 			n3=n1;	n4=n2;
 			p = mglPoint(x->v(i,mx),y->v(i,my),z0);
-			n1 = gr->AddPnt(p,c1,nn);	p.y = y0;	n2 = gr->AddPnt(p,c2,nn);
+			if(sh)	c2=c1=gr->NextColor(pal,i);
+			n1 = gr->AddPnt(p,c1,nn,-1,11);	p.y = y0;	n2 = gr->AddPnt(p,c2,nn,-1,11);
 			if(wire)
 			{
 				gr->line_plot(n1,n2);	gr->line_plot(n3,n4);
 				gr->line_plot(n1,n3);	gr->line_plot(n4,n2);
 			}
 			else	gr->quad_plot(n1,n2,n3,n4);
-			if(sh)	c2=c1=gr->NextColor(pal);
 		}
 	}
 	gr->EndGroup();
@@ -616,17 +634,17 @@ void MGL_EXPORT mgl_region_xy(HMGL gr, HCDT x, HCDT y1, HCDT y2, const char *pen
 		mreal z0 = zm + (m-1-j)*(gr->Max.z-zm)/m;
 
 		f1 = y1->v(0,j);	f2 = y2->v(0,j);	xx = x->v(0,mx);
-		n1 = gr->AddPnt(mglPoint(xx,f1,z0),c1,nn);
-		n2 = gr->AddPnt(mglPoint(xx,f2,z0),c2,nn);
+		n1 = gr->AddPnt(mglPoint(xx,f1,z0),c1,nn,-1,11);
+		n2 = gr->AddPnt(mglPoint(xx,f2,z0),c2,nn,-1,11);
 		for(i=1;i<n;i++)
 		{
 			if(gr->Stop)	return;
 			n3=n1;	n4=n2;	f3=f1;	f4=f2;
 			f1 = y1->v(i,j);	f2 = y2->v(i,j);	xx = x->v(i,mx);
-			n1 = gr->AddPnt(mglPoint(xx,f1,z0),c1,nn);
-			n2 = gr->AddPnt(mglPoint(xx,f2,z0),c2,nn);
+			if(sh)	c2=c1=gr->NextColor(pal,i);
+			n1 = gr->AddPnt(mglPoint(xx,f1,z0),c1,nn,-1,11);
+			n2 = gr->AddPnt(mglPoint(xx,f2,z0),c2,nn,-1,11);
 			if(!inside || (f2>f1 && f4>f3))	gr->quad_plot(n1,n2,n3,n4);
-			if(sh)	c2=c1=gr->NextColor(pal);
 		}
 	}
 	gr->EndGroup();
@@ -679,15 +697,15 @@ void MGL_EXPORT mgl_step_xyz(HMGL gr, HCDT x, HCDT y, HCDT z, const char *pen, c
 			if(gr->Stop)	return;
 			n2 = n1;	// horizontal
 			p = mglPoint(x->v(i,mx), y->v(i,my), z->v(i-1,mz));
-			n1 = gr->AddPnt(p);	gr->line_plot(n1,n2);
+			mreal c = sh ? gr->NextColor(pal,i):gr->CDef;
+			n1 = gr->AddPnt(p,c);	gr->line_plot(n1,n2);
 			if(i==1)	gr->arrow_plot(n2,n1,gr->Arrow1);
 
 			n2 = n1;	// vertical
-			p.z = z->v(i,mz);	n1 = gr->AddPnt(p);
+			p.z = z->v(i,mz);	n1 = gr->AddPnt(p,c);
 			if(mk)	gr->mark_plot(n1,mk);
 			gr->line_plot(n1,n2);
 			if(i==n-1)	gr->arrow_plot(n1,n2,gr->Arrow2);
-			if(sh)	gr->NextColor(pal);
 		}
 	}
 	gr->EndGroup();
@@ -718,15 +736,15 @@ void MGL_EXPORT mgl_step_xy(HMGL gr, HCDT x, HCDT y, const char *pen, const char
 			if(gr->Stop)	return;
 			n2 = n1;	// horizontal
 			p = mglPoint(x->v(i,mx), y->v(i-1,my), zVal);
-			n1 = gr->AddPnt(p);		gr->line_plot(n1,n2);
+			mreal c = sh ? gr->NextColor(pal,i):gr->CDef;
+			n1 = gr->AddPnt(p,c);	gr->line_plot(n1,n2);
 			if(i==1)	gr->arrow_plot(n2,n1,gr->Arrow1);
 
 			n2 = n1;	// vertical
-			p.y = y->v(i,my);		n1 = gr->AddPnt(p);
+			p.y = y->v(i,my);		n1 = gr->AddPnt(p,c);
 			if(mk)	gr->mark_plot(n1,mk);
 			gr->line_plot(n1,n2);
 			if(i==n-1)	gr->arrow_plot(n1,n2,gr->Arrow2);
-			if(sh)	gr->NextColor(pal);
 		}
 	}
 	gr->EndGroup();
@@ -762,7 +780,7 @@ void MGL_EXPORT mgl_step_(uintptr_t *gr, uintptr_t *y,	const char *pen, const ch
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_stem_xyz(HMGL gr, HCDT x, HCDT y, HCDT z, const char *pen, const char *opt)
 {
-	long i,j,m,mx,my,mz,n=y->GetNx(), pal;
+	long m,mx,my,mz,n=y->GetNx(), pal;
 	if(mgl_check_dim1(gr,x,y,z,0,"Stem"))	return;
 
 	gr->SaveState(opt);
@@ -772,19 +790,19 @@ void MGL_EXPORT mgl_stem_xyz(HMGL gr, HCDT x, HCDT y, HCDT z, const char *pen, c
 
 	mreal z0=gr->GetOrgZ('x');
 	char mk=gr->SetPenPal(pen,&pal);	gr->Reserve(2*n*m);
-	long n1,n2;
-	for(j=0;j<m;j++)
+	for(long j=0;j<m;j++)
 	{
 		mx = j<x->GetNy() ? j:0;	my = j<y->GetNy() ? j:0;
 		mz = j<z->GetNy() ? j:0;	gr->NextColor(pal);
-		for(i=0;i<n;i++)
+#pragma omp parallel for
+		for(long i=0;i<n;i++)
 		{
-			if(gr->Stop)	return;
-			n1 = gr->AddPnt(mglPoint(x->v(i,mx), y->v(i,my), z->v(i,mz)));
+			if(gr->Stop)	continue;
+			mreal c = sh ? gr->NextColor(pal,i):gr->CDef;
+			long n1 = gr->AddPnt(mglPoint(x->v(i,mx), y->v(i,my), z->v(i,mz)),c);
 			if(mk)	gr->mark_plot(n1,mk);
-			n2 = gr->AddPnt(mglPoint(x->v(i,mx), y->v(i,my), z0));
+			long n2 = gr->AddPnt(mglPoint(x->v(i,mx), y->v(i,my), z0),c);
 			gr->line_plot(n1,n2);
-			if(sh)	gr->NextColor(pal);
 		}
 	}
 	gr->EndGroup();
@@ -792,7 +810,7 @@ void MGL_EXPORT mgl_stem_xyz(HMGL gr, HCDT x, HCDT y, HCDT z, const char *pen, c
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_stem_xy(HMGL gr, HCDT x, HCDT y, const char *pen, const char *opt)
 {
-	long i,j,m,mx,my,n=y->GetNx(), pal;
+	long m,mx,my,n=y->GetNx(), pal;
 	if(mgl_check_dim1(gr,x,y,0,0,"Stem"))	return;
 
 	gr->SaveState(opt);
@@ -800,22 +818,22 @@ void MGL_EXPORT mgl_stem_xy(HMGL gr, HCDT x, HCDT y, const char *pen, const char
 	m = x->GetNy() > y->GetNy() ? x->GetNy() : y->GetNy();
 	bool sh = mglchr(pen,'!');
 
-	mreal zVal = gr->AdjustZMin(), y0=gr->GetOrgY('x'), vv;
+	mreal zVal = gr->AdjustZMin(), y0=gr->GetOrgY('x');
 	char mk=gr->SetPenPal(pen,&pal);	gr->Reserve(2*n*m);
-	long n1,n2;
-	for(j=0;j<m;j++)
+	for(long j=0;j<m;j++)
 	{
 		mx = j<x->GetNy() ? j:0;	my = j<y->GetNy() ? j:0;
 		gr->NextColor(pal);
-		for(i=0;i<n;i++)
+#pragma omp parallel for
+		for(long i=0;i<n;i++)
 		{
-			if(gr->Stop)	return;
-			vv = x->v(i,mx);
-			n1 = gr->AddPnt(mglPoint(vv, y->v(i,my), zVal));
+			if(gr->Stop)	continue;
+			mreal vv = x->v(i,mx);
+			mreal c = sh ? gr->NextColor(pal,i):gr->CDef;
+			long n1 = gr->AddPnt(mglPoint(vv, y->v(i,my), zVal),c);
 			if(mk)	gr->mark_plot(n1,mk);
-			n2 = gr->AddPnt(mglPoint(vv, y0, zVal));
+			long n2 = gr->AddPnt(mglPoint(vv, y0, zVal),c);
 			gr->line_plot(n1,n2);
-			if(sh)	gr->NextColor(pal);
 		}
 	}
 	gr->EndGroup();
@@ -851,7 +869,7 @@ void MGL_EXPORT mgl_stem_(uintptr_t *gr, uintptr_t *y,	const char *pen, const ch
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_bars_xyz(HMGL gr, HCDT x, HCDT y, HCDT z, const char *pen, const char *opt)
 {
-	long i,j,m,mx,my,mz,n=z->GetNx(), pal,nx=x->GetNx(),ny=y->GetNx();
+	long m,mx,my,mz,n=z->GetNx(), pal,nx=x->GetNx(),ny=y->GetNx();
 	if(mgl_check_dim1(gr,x,z,y,0,"Bars",true))	return;
 
 	gr->SaveState(opt);
@@ -863,27 +881,30 @@ void MGL_EXPORT mgl_bars_xyz(HMGL gr, HCDT x, HCDT y, HCDT z, const char *pen, c
 	bool wire = mglchr(pen,'#');
 	bool above = mglchr(pen,'a'), fall = mglchr(pen,'f');
 	if(above)	fall = false;
-	mreal c1,c2,c;
-	mglPoint p1,p2,p3,p4,nn;
-	long n1,n2,n3,n4;
-	mreal *dd=new mreal[n], x1,x2,y1,y2,z0,zz,zp,d,vv;
+	mreal c1,c2;
+	mreal *dd=new mreal[n], z0,zp,dv=nx>n?1:0;
+	if(mglchr(pen,'<'))	dv = 1;
+	if(mglchr(pen,'^'))	dv = 0;
+	if(mglchr(pen,'>'))	dv = -1;
 	memset(dd,0,n*sizeof(mreal));
 
 	gr->SetPenPal(pen,&pal);
 	if(wire)	gr->Reserve(4*n*m);	else	gr->Reserve(4*n*m);
-	for(j=0;j<m;j++)
+	for(long j=0;j<m;j++)
 	{
 		c2=c1=gr->NextColor(pal);
 		if(gr->GetNumPal(pal)==2*m && !sh)	c2 = gr->NextColor(pal);
 		mx = j<x->GetNy() ? j:0;	my = j<y->GetNy() ? j:0;	mz = j<z->GetNy() ? j:0;
 		zp = z0 = gr->GetOrgZ('x');
-		for(i=0;i<n;i++)
+#pragma omp parallel for ordered
+		for(long i=0;i<n;i++)
 		{
-			if(gr->Stop)	{	delete []dd;	return;	}
-			vv = x->v(i,mx);	d = i<nx-1 ? x->v(i+1,mx)-vv : vv-x->v(i-1,mx);
-			x1 = vv + d/2*(1-gr->BarWidth);	x2 = x1 + gr->BarWidth*d;
+			if(gr->Stop)	continue;
+			if(sh)	c2=c1=gr->NextColor(pal,i);
+			mreal vv = x->v(i,mx), d = i<nx-1 ? x->v(i+1,mx)-vv : vv-x->v(i-1,mx), zz;
+			mreal x1 = vv + d/2*(dv-gr->BarWidth), x2 = x1 + gr->BarWidth*d;
 			vv = y->v(i,my);	d = i<ny-1 ? y->v(i+1,my)-vv : vv-y->v(i-1,my);
-			y1 = vv + d/2*(1-gr->BarWidth);	y2 = y1 + gr->BarWidth*d;
+			mreal y1 = vv + d/2*(dv-gr->BarWidth), y2 = y1 + gr->BarWidth*d;
 			vv = zz = z->v(i,mz);
 			if(!above)
 			{
@@ -891,27 +912,24 @@ void MGL_EXPORT mgl_bars_xyz(HMGL gr, HCDT x, HCDT y, HCDT z, const char *pen, c
 				y2 = (y2-y1)/m;		y1 += j*y2;		y2 += y1;
 			}
 			else
+#pragma omp ordered
 			{	z0 = gr->GetOrgZ('x') + dd[i];	dd[i] += zz;	zz += z0;	}
-			if(fall)	{	z0 = zp;	zz += z0;	zp = zz;	}
+			if(fall)
+#pragma omp ordered
+			{	z0 = zp;	zz += z0;	zp = zz;	}
 
-			c = vv<0 ? c1 : c2;
-			nn = mglPoint(-y->dvx(i,my),x->dvx(i,mx));
-			p1 = mglPoint(x1,y1,zz);	p2 = mglPoint(x1,y1,z0);
-			p3 = mglPoint(x2,y2,z0);	p4 = mglPoint(x2,y2,zz);
+			mreal c = vv<0 ? c1 : c2;
+			mglPoint nn = mglPoint(-y->dvx(i,my),x->dvx(i,mx));
+			long n1 = gr->AddPnt(mglPoint(x1,y1,zz),c,nn);
+			long n2 = gr->AddPnt(mglPoint(x1,y1,z0),c,nn);
+			long n3 = gr->AddPnt(mglPoint(x2,y2,z0),c,nn);
+			long n4 = gr->AddPnt(mglPoint(x2,y2,zz),c,nn);
 			if(wire)
 			{
-				n1 = gr->AddPnt(p1,c);	n2 = gr->AddPnt(p2,c);
-				n3 = gr->AddPnt(p3,c);	n4 = gr->AddPnt(p4,c);
 				gr->line_plot(n1,n2);	gr->line_plot(n1,n4);
 				gr->line_plot(n3,n2);	gr->line_plot(n3,n4);
 			}
-			else
-			{
-				n1 = gr->AddPnt(p1,c,nn);	n2 = gr->AddPnt(p2,c,nn);
-				n3 = gr->AddPnt(p3,c,nn);	n4 = gr->AddPnt(p4,c,nn);
-				gr->quad_plot(n1,n2,n4,n3);
-			}
-			if(sh)	c2=c1=gr->NextColor(pal);
+			else	gr->quad_plot(n1,n2,n4,n3);
 		}
 	}
 	gr->EndGroup();	delete []dd;
@@ -919,7 +937,7 @@ void MGL_EXPORT mgl_bars_xyz(HMGL gr, HCDT x, HCDT y, HCDT z, const char *pen, c
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_bars_xy(HMGL gr, HCDT x, HCDT y, const char *pen, const char *opt)
 {
-	long i,j,m,mx,my,n=y->GetNx(),pal;
+	long m,mx,my,n=y->GetNx(),nx=x->GetNx(),pal;
 	if(mgl_check_dim1(gr,x,y,0,0,"Bars",true))	return;
 
 	gr->SaveState(opt);
@@ -930,44 +948,50 @@ void MGL_EXPORT mgl_bars_xy(HMGL gr, HCDT x, HCDT y, const char *pen, const char
 	bool wire = mglchr(pen,'#');
 	bool above = mglchr(pen,'a'), fall = mglchr(pen,'f');
 	if(above)	fall = false;
-	mreal c1,c2,c;
-	long n1,n2,n3,n4;
-	mreal *dd=new mreal[n], x1,x2,yy,y0,yp,d,vv;
+	mreal c1,c2;
+	mreal *dd=new mreal[n], y0,yp,dv=nx>n?1:0;
+	if(mglchr(pen,'<'))	dv = 1;
+	if(mglchr(pen,'^'))	dv = 0;
+	if(mglchr(pen,'>'))	dv = -1;
 	mreal zm = gr->AdjustZMin();
 	memset(dd,0,n*sizeof(mreal));
 
 	gr->SetPenPal(pen,&pal);
 	if(wire)	gr->Reserve(4*n*m);	else	gr->Reserve(4*n*m);
-	for(j=0;j<m;j++)
+	for(long j=0;j<m;j++)
 	{
 		c2=c1=gr->NextColor(pal);
 		if(gr->GetNumPal(pal)==2*m && !sh)	c2 = gr->NextColor(pal);
 		mx = j<x->GetNy() ? j:0;	my = j<y->GetNy() ? j:0;
 		yp = y0 = gr->GetOrgY('x');
-		for(i=0;i<n;i++)
+#pragma omp parallel for ordered
+		for(long i=0;i<n;i++)
 		{
-			if(gr->Stop)	{	delete []dd;	return;	}
-			vv = x->v(i,mx);	d = i<n-1 ? x->v(i+1,mx)-vv : vv-x->v(i-1,mx);
-			x1 = vv + d/2*(1-gr->BarWidth);	x2 = x1 + gr->BarWidth*d;
+			if(gr->Stop)	continue;
+			if(sh)	c2=c1=gr->NextColor(pal,i);
+			mreal vv = x->v(i,mx), d = i<nx-1 ? x->v(i+1,mx)-vv : vv-x->v(i-1,mx), yy;
+			mreal x1 = vv + d/2*(dv-gr->BarWidth), x2 = x1 + gr->BarWidth*d;
 			vv = yy = y->v(i,my);
 			if(!above)
 			{	x2 = (x2-x1)/m;		x1 += j*x2;		x2 += x1;	}
 			else
+#pragma omp ordered
 			{	y0 = gr->GetOrgY('x') + dd[i];	dd[i] += yy;	yy += y0;	}
-			if(fall)	{	y0 = yp;	yy += y0;	yp = yy;	}
+			if(fall)
+#pragma omp ordered
+			{	y0 = yp;	yy += y0;	yp = yy;	}
 
-			c = vv<0 ? c1 : c2;
-			n1 = gr->AddPnt(mglPoint(x1,yy,zm),c);
-			n2 = gr->AddPnt(mglPoint(x1,y0,zm),c);
-			n3 = gr->AddPnt(mglPoint(x2,y0,zm),c);
-			n4 = gr->AddPnt(mglPoint(x2,yy,zm),c);
+			mreal c = vv<0 ? c1 : c2;
+			long n1 = gr->AddPnt(mglPoint(x1,yy,zm),c);
+			long n2 = gr->AddPnt(mglPoint(x1,y0,zm),c);
+			long n3 = gr->AddPnt(mglPoint(x2,y0,zm),c);
+			long n4 = gr->AddPnt(mglPoint(x2,yy,zm),c);
 			if(wire)
 			{
 				gr->line_plot(n1,n2);	gr->line_plot(n1,n4);
 				gr->line_plot(n3,n2);	gr->line_plot(n3,n4);
 			}
 			else	gr->quad_plot(n1,n2,n4,n3);
-			if(sh)	c2=c1=gr->NextColor(pal);
 		}
 	}
 	gr->EndGroup();	delete []dd;
@@ -1003,7 +1027,7 @@ void MGL_EXPORT mgl_bars_(uintptr_t *gr, uintptr_t *y,	const char *pen, const ch
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_barh_yx(HMGL gr, HCDT y, HCDT v, const char *pen, const char *opt)
 {
-	long i,j,m,mx,my,n=v->GetNx(),pal;
+	long m,mx,my,n=v->GetNx(),ny=y->GetNx(),pal;
 	if(mgl_check_dim1(gr,y,v,0,0,"Barh",true))	return;
 
 	gr->SaveState(opt);
@@ -1014,44 +1038,50 @@ void MGL_EXPORT mgl_barh_yx(HMGL gr, HCDT y, HCDT v, const char *pen, const char
 	bool wire = mglchr(pen,'#');
 	bool above = mglchr(pen,'a'), fall = mglchr(pen,'f');
 	if(above)	fall = false;
-	mreal c1,c2,c;
-	long n1,n2,n3,n4;
-	mreal *dd=new mreal[n], y1,y2,xx,x0,xp,d,vv;
+	mreal c1,c2;
+	mreal *dd=new mreal[n], x0,xp,dv=ny>n?1:0;
+	if(mglchr(pen,'<'))	dv = 1;
+	if(mglchr(pen,'^'))	dv = 0;
+	if(mglchr(pen,'>'))	dv = -1;
 	mreal zm = gr->AdjustZMin();
 	memset(dd,0,n*sizeof(mreal));
 
 	gr->SetPenPal(pen,&pal);
 	if(wire)	gr->Reserve(4*n*m);	else	gr->Reserve(4*n*m);
-	for(j=0;j<m;j++)
+	for(long j=0;j<m;j++)
 	{
 		c2=c1=gr->NextColor(pal);
 		if(gr->GetNumPal(pal)==2*m && !sh)	c2 = gr->NextColor(pal);
 		mx = j<v->GetNy() ? j:0;	my = j<y->GetNy() ? j:0;
 		xp = x0 = gr->GetOrgX('y');
-		for(i=0;i<n;i++)
+#pragma omp parallel for ordered
+		for(long i=0;i<n;i++)
 		{
-			if(gr->Stop)	{	delete []dd;	return;	}
-			vv = y->v(i,my);	d = i<n-1 ? y->v(i+1,my)-vv : vv-y->v(i-1,my);
-			y1 = vv + d/2*(1-gr->BarWidth);	y2 = y1 + gr->BarWidth*d;
+			if(gr->Stop)	continue;
+			if(sh)	c2=c1=gr->NextColor(pal,i);
+			mreal vv = y->v(i,my), d = i<ny-1 ? y->v(i+1,my)-vv : vv-y->v(i-1,my), xx;
+			mreal y1 = vv + d/2*(dv-gr->BarWidth), y2 = y1 + gr->BarWidth*d;
 			vv = xx = v->v(i,mx);
 			if(!above)
 			{	y2 = (y2-y1)/m;		y1 += j*y2;		y2 += y1;	}
 			else
+#pragma omp ordered
 			{	x0 = gr->GetOrgX('y') + dd[i];	dd[i] += xx;	xx += x0;	}
-			if(fall)	{	x0 = xp;	xx += x0;	xp = xx;	}
+			if(fall)
+#pragma omp ordered
+			{	x0 = xp;	xx += x0;	xp = xx;	}
 
-			c = vv<0 ? c1 : c2;
-			n1 = gr->AddPnt(mglPoint(xx,y1,zm),c);
-			n2 = gr->AddPnt(mglPoint(xx,y2,zm),c);
-			n3 = gr->AddPnt(mglPoint(x0,y2,zm),c);
-			n4 = gr->AddPnt(mglPoint(x0,y1,zm),c);
+			mreal c = vv<0 ? c1 : c2;
+			long n1 = gr->AddPnt(mglPoint(xx,y1,zm),c);
+			long n2 = gr->AddPnt(mglPoint(xx,y2,zm),c);
+			long n3 = gr->AddPnt(mglPoint(x0,y2,zm),c);
+			long n4 = gr->AddPnt(mglPoint(x0,y1,zm),c);
 			if(wire)
 			{
 				gr->line_plot(n1,n2);	gr->line_plot(n1,n4);
 				gr->line_plot(n3,n2);	gr->line_plot(n3,n4);
 			}
 			else	gr->quad_plot(n1,n2,n4,n3);
-			if(sh)	c2=c1=gr->NextColor(pal);
 		}
 	}
 	gr->EndGroup();	delete []dd;
@@ -1077,6 +1107,75 @@ void MGL_EXPORT mgl_barh_(uintptr_t *gr, uintptr_t *v,	const char *pen, const ch
 	mgl_barh(_GR_,_DA_(v),s,o);	delete []o;	delete []s;	}
 //-----------------------------------------------------------------------------
 //
+//	OHLC series
+//
+//-----------------------------------------------------------------------------
+void MGL_EXPORT mgl_ohlc_x(HMGL gr, HCDT x, HCDT open, HCDT high, HCDT low, HCDT close, const char *pen, const char *opt)
+{
+	long n=open->GetNx(), nx=x->GetNx(), m=open->GetNy(), mx;
+	if(nx<n || n*m!=high->GetNx()*high->GetNy() || n*m!=low->GetNx()*low->GetNy() || n*m!=close->GetNx()*close->GetNy())
+	{	gr->SetWarn(mglWarnDim,"OHLC");	return;	}
+	gr->SaveState(opt);
+	static int cgid=1;	gr->StartGroup("OHLC",cgid++);
+	mreal dv=nx>n?1:0,dd,vv,x1,x2,cc;
+	if(mglchr(pen,'<'))	dv = 1;
+	if(mglchr(pen,'^'))	dv = 0;
+	if(mglchr(pen,'>'))	dv = -1;
+	mreal zVal = gr->AdjustZMin();
+	bool sh = mglchr(pen,'!');
+
+	long pal;
+	gr->SetPenPal(pen,&pal);	gr->Reserve(6*n*m);
+	for(long j=0;j<m;j++)
+	{
+		cc=gr->NextColor(pal);
+		mx = j<x->GetNy() ? j:0;
+#pragma omp parallel for private(vv,dd,x1,x2)
+		for(long i=0;i<n;i++)
+		{
+			if(gr->Stop)	continue;
+			vv = x->v(i,mx);	dd = i<nx-1 ? x->v(i+1)-vv : vv-x->v(i-1);
+			x1 = vv + dd/2*(dv-gr->BarWidth);	x2 = x1 + gr->BarWidth*dd;
+			x2 = (x2-x1)/m;		x1 += j*x2;		x2 += x1;	vv = (x2+x1)/2;
+			mreal c = sh ? gr->NextColor(pal,i):cc;
+			register long n1,n2;
+
+			dd = open->v(i,j);
+			n1=gr->AddPnt(mglPoint(x1,dd,zVal),c);
+			n2=gr->AddPnt(mglPoint(vv,dd,zVal),c);
+			gr->line_plot(n1,n2);
+			dd = close->v(i,j);
+			n1=gr->AddPnt(mglPoint(vv,dd,zVal),c);
+			n2=gr->AddPnt(mglPoint(x2,dd,zVal),c);
+			gr->line_plot(n1,n2);
+			n1=gr->AddPnt(mglPoint(vv,low->v(i,j),zVal),c);
+			n2=gr->AddPnt(mglPoint(vv,high->v(i,j),zVal),c);
+			gr->line_plot(n1,n2);
+		}
+	}
+	gr->EndGroup();
+}
+//-----------------------------------------------------------------------------
+void MGL_EXPORT mgl_ohlc(HMGL gr, HCDT open, HCDT high, HCDT low, HCDT close, const char *pen, const char *opt)
+{
+	gr->SaveState(opt);
+	mglData x(open->GetNx()+1);
+	x.Fill(gr->Min.x,gr->Max.x);
+	mgl_ohlc_x(gr,&x,open,high,low,close,pen,0);
+	gr->LoadState();
+}
+//-----------------------------------------------------------------------------
+void MGL_EXPORT mgl_ohlc_y_(uintptr_t *gr, uintptr_t *x, uintptr_t *open, uintptr_t *high, uintptr_t *low, uintptr_t *close, const char *pen, const char *opt,int l,int lo)
+{	char *s=new char[l+1];	memcpy(s,pen,l);	s[l]=0;
+	char *o=new char[lo+1];	memcpy(o,opt,lo);	o[lo]=0;
+	mgl_ohlc_x(_GR_,_DA_(x),_DA_(open),_DA_(high),_DA_(low),_DA_(close),s,o);	delete []o;	delete []s;	}
+//-----------------------------------------------------------------------------
+void MGL_EXPORT mgl_ohlc_(uintptr_t *gr, uintptr_t *open, uintptr_t *high, uintptr_t *low, uintptr_t *close, const char *pen, const char *opt,int l,int lo)
+{	char *s=new char[l+1];	memcpy(s,pen,l);	s[l]=0;
+	char *o=new char[lo+1];	memcpy(o,opt,lo);	o[lo]=0;
+	mgl_ohlc(_GR_,_DA_(open),_DA_(high),_DA_(low),_DA_(close),s,o);	delete []o;	delete []s;	}
+//-----------------------------------------------------------------------------
+//
 //	BoxPlot series
 //
 //-----------------------------------------------------------------------------
@@ -1091,61 +1190,80 @@ int MGL_NO_EXPORT mgl_cmp_flt(const void *a, const void *b)
 void MGL_EXPORT mgl_boxplot_xy(HMGL gr, HCDT x, HCDT y, const char *pen, const char *opt)
 {
 	long n=y->GetNx(), m=y->GetNy(), nx=x->GetNx();
-	if(nx<n || nx<2)	{	gr->SetWarn(mglWarnDim,"BoxPlot");	return;	}
+	if(nx<n || nx<2 || m<2)	{	gr->SetWarn(mglWarnDim,"BoxPlot");	return;	}
 	gr->SaveState(opt);
 	static int cgid=1;	gr->StartGroup("BoxPlot",cgid++);
-	mreal *b = new mreal[5*n], *d = new mreal[m], x1, x2, dd;
+	mreal *b = new mreal[5*n], x1, x2, dd, dv=nx>n?1:0;
+	if(mglchr(pen,'<'))	dv = 1;
+	if(mglchr(pen,'^'))	dv = 0;
+	if(mglchr(pen,'>'))	dv = -1;
 	mreal zVal = gr->AdjustZMin(), vv;
 	bool sh = mglchr(pen,'!');
-	register long i,j;
-	for(i=0;i<n;i++)	// find quartiles by itself
+#pragma omp parallel
 	{
-		if(gr->Stop)	{	delete []d;	delete []b;	return;	}
-		register long mm,k;
-		for(mm=j=0;j<m;j++)
+		mreal *d = new mreal[m];
+#pragma omp for
+		for(long i=0;i<n;i++)	// find quartiles by itself
 		{
-			vv = y->v(i,j);
-			if(!mgl_isnan(vv))	{	d[mm]=vv;	mm++;	}
+			if(gr->Stop)	continue;
+			register long mm,k,j;
+			for(mm=j=0;j<m;j++)
+			{
+				mreal vv = y->v(i,j);
+				if(mgl_isnum(vv))	{	d[mm]=vv;	mm++;	}
+			}
+//			if(m==0)	{	b[i]=NAN;	break;	}
+			qsort(d, mm, sizeof(mreal), mgl_cmp_flt);
+			b[i] = d[0];	b[i+4*n] = d[mm-1];		k = mm/4;
+			b[i+n] = (mm%4) ? d[k] : (d[k]+d[k-1])/2.;
+			b[i+2*n] = (mm%2) ? d[mm/2] : (d[mm/2]+d[mm/2-1])/2.;
+			b[i+3*n] = (mm%4) ? d[mm-k-1] : (d[mm-k-1]+d[mm-k])/2.;
 		}
-		if(m==0)	{	b[i]=NAN;	break;	}
-		qsort(d, mm, sizeof(mreal), mgl_cmp_flt);
-		b[i] = d[0];	b[i+4*n] = d[mm-1];		k = mm/4;
-		b[i+n] = (mm%4) ? d[k] : (d[k]+d[k-1])/2.;
-		b[i+2*n] = (mm%2) ? d[mm/2] : (d[mm/2]+d[mm/2-1])/2.;
-		b[i+3*n] = (mm%4) ? d[mm-k-1] : (d[mm-k-1]+d[mm-k])/2.;
+		delete []d;
 	}
-	delete []d;
 
-	mglPoint p1,p2;
-	long n1,n2,pal;
+	long pal;
 	gr->SetPenPal(pen,&pal);	gr->NextColor(pal);	gr->Reserve(18*n);
-	for(i=0;i<n;i++)
+#pragma omp parallel for private(vv,dd,x1,x2)
+	for(long i=0;i<n;i++)
 	{
-		if(gr->Stop)	{	delete []b;	return;	}
+		if(gr->Stop)	continue;
 		vv = x->v(i);
 		dd = i<nx-1 ? x->v(i+1)-vv : vv-x->v(i-1);
-		x1 = vv + dd/2*(1-gr->BarWidth);
+		x1 = vv + dd/2*(dv-gr->BarWidth);
 		x2 = x1 + gr->BarWidth*dd;
-		for(j=0;j<5;j++)	// horizontal lines
-		{
-			p1=mglPoint(x1,b[i+j*n],zVal);	n1=gr->AddPnt(p1);
-			p2=mglPoint(x2,b[i+j*n],zVal);	n2=gr->AddPnt(p2);
-			gr->line_plot(n1,n2);
-		}
+		mreal c = sh ? gr->NextColor(pal,i):gr->CDef;
+		register long n1,n2;
+		// TODO why boxplot fail if I use for()
+		n1=gr->AddPnt(mglPoint(x1,b[i],zVal),c);	// horizontal lines
+		n2=gr->AddPnt(mglPoint(x2,b[i],zVal),c);
+		gr->line_plot(n1,n2);
+		n1=gr->AddPnt(mglPoint(x1,b[i+n],zVal),c);
+		n2=gr->AddPnt(mglPoint(x2,b[i+n],zVal),c);
+		gr->line_plot(n1,n2);
+		n1=gr->AddPnt(mglPoint(x1,b[i+2*n],zVal),c);
+		n2=gr->AddPnt(mglPoint(x2,b[i+2*n],zVal),c);
+		gr->line_plot(n1,n2);
+		n1=gr->AddPnt(mglPoint(x1,b[i+3*n],zVal),c);
+		n2=gr->AddPnt(mglPoint(x2,b[i+3*n],zVal),c);
+		gr->line_plot(n1,n2);
+		n1=gr->AddPnt(mglPoint(x1,b[i+4*n],zVal),c);
+		n2=gr->AddPnt(mglPoint(x2,b[i+4*n],zVal),c);
+		gr->line_plot(n1,n2);
+
 		//vertical lines
-		p1=mglPoint(x1,b[i+n],zVal);		n1=gr->AddPnt(p1);
-		p2=mglPoint(x1,b[i+3*n],zVal);		n2=gr->AddPnt(p2);
+		n1=gr->AddPnt(mglPoint(x1,b[i+n],zVal),c);
+		n2=gr->AddPnt(mglPoint(x1,b[i+3*n],zVal),c);
 		gr->line_plot(n1,n2);
-		p1=mglPoint(x2,b[i+n],zVal);		n1=gr->AddPnt(p1);
-		p2=mglPoint(x2,b[i+3*n],zVal);		n2=gr->AddPnt(p2);
+		n1=gr->AddPnt(mglPoint(x2,b[i+n],zVal),c);
+		n2=gr->AddPnt(mglPoint(x2,b[i+3*n],zVal),c);
 		gr->line_plot(n1,n2);
-		p1=mglPoint((x1+x2)/2,b[i],zVal);	n1=gr->AddPnt(p1);
-		p2=mglPoint((x1+x2)/2,b[i+n],zVal);	n2=gr->AddPnt(p2);
+		n1=gr->AddPnt(mglPoint((x1+x2)/2,b[i],zVal),c);
+		n2=gr->AddPnt(mglPoint((x1+x2)/2,b[i+n],zVal),c);
 		gr->line_plot(n1,n2);
-		p1=mglPoint((x1+x2)/2,b[i+3*n],zVal);	n1=gr->AddPnt(p1);
-		p2=mglPoint((x1+x2)/2,b[i+4*n],zVal);	n2=gr->AddPnt(p2);
+		n1=gr->AddPnt(mglPoint((x1+x2)/2,b[i+3*n],zVal),c);
+		n2=gr->AddPnt(mglPoint((x1+x2)/2,b[i+4*n],zVal),c);
 		gr->line_plot(n1,n2);
-		if(sh)	gr->NextColor(pal);
 	}
 	delete []b;	gr->EndGroup();
 }
@@ -1175,7 +1293,7 @@ void MGL_EXPORT mgl_boxplot_(uintptr_t *gr, uintptr_t *y,	const char *pen, const
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_error_exy(HMGL gr, HCDT x, HCDT y, HCDT ex, HCDT ey, const char *pen, const char *opt)
 {
-	long i,j,k,m,mx,my,m1,m2,n=ey->GetNx(),pal;
+	long m,mx,my,m1,m2,n=ey->GetNx(),pal;
 	if(mgl_check_dim1(gr,x,y,ey,ex,"Error"))	return;
 
 	gr->SaveState(opt);
@@ -1187,12 +1305,12 @@ void MGL_EXPORT mgl_error_exy(HMGL gr, HCDT x, HCDT y, HCDT ex, HCDT ey, const c
 
 	bool ma = mglchr(pen,'@');
 	char mk = gr->SetPenPal(pen,&pal);
-	mreal zVal=gr->AdjustZMin(), vx, vy, ve, vf;
+	mreal zVal=gr->AdjustZMin();
 	gr->Reserve(5*n*m);
 	if(ma && (mk==0 || !strchr("PXsSdD+xoOC",mk) ))	mk = 'S';
-	long n1,n2,n3,n4;
+	gr->ResetMask();
 	mglPoint q(NAN,NAN);
-	for(j=0;j<m;j++)
+	for(long j=0;j<m;j++)
 	{
 		if(gr->Stop)	return;
 		mx = j<x->GetNy() ? j:0;	my = j<y->GetNy() ? j:0;
@@ -1200,117 +1318,136 @@ void MGL_EXPORT mgl_error_exy(HMGL gr, HCDT x, HCDT y, HCDT ex, HCDT ey, const c
 		gr->NextColor(pal);
 		if(ma)
 		{
-			if(strchr("PXsS",mk))	for(i=0;i<n;i++)	// boundary of square
-			{
-				vx=x->v(i,mx);	ve=ex->v(i,m1);	vy=y->v(i,my);	vf=ey->v(i,m2);
-				n1 = gr->AddPnt(mglPoint(vx-ve, vy+vf, zVal),-1,q,-1,11);
-				n2 = gr->AddPnt(mglPoint(vx-ve, vy-vf, zVal),-1,q,-1,11);
-				n3 = gr->AddPnt(mglPoint(vx+ve, vy+vf, zVal),-1,q,-1,11);
-				n4 = gr->AddPnt(mglPoint(vx+ve, vy-vf, zVal),-1,q,-1,11);
-				gr->line_plot(n1,n2);	gr->line_plot(n1,n3);
-				gr->line_plot(n4,n2);	gr->line_plot(n4,n3);
-				if(sh)	gr->NextColor(pal);
-			}
-			if(strchr("dD",mk))	for(i=0;i<n;i++)	// boundary of rhomb
-			{
-				vx=x->v(i,mx);	ve=ex->v(i,m1);	vy=y->v(i,my);	vf=ey->v(i,m2);
-				n1 = gr->AddPnt(mglPoint(vx, vy+vf, zVal),-1,q,-1,11);
-				n2 = gr->AddPnt(mglPoint(vx-ve, vy, zVal),-1,q,-1,11);
-				n3 = gr->AddPnt(mglPoint(vx, vy-vf, zVal),-1,q,-1,11);
-				n4 = gr->AddPnt(mglPoint(vx+ve, vy, zVal),-1,q,-1,11);
-				gr->line_plot(n1,n2);	gr->line_plot(n2,n3);
-				gr->line_plot(n3,n4);	gr->line_plot(n4,n1);
-				if(sh)	gr->NextColor(pal);
-			}
-			if(strchr("oOC",mk))	for(i=0;i<n;i++)	// circle
-			{
-				vx=x->v(i,mx);	ve=ex->v(i,m1);	vy=y->v(i,my);	vf=ey->v(i,m2);
-				for(k=0,n2=-1;k<=40;k++)
+			if(strchr("PXsS",mk))
+#pragma omp parallel for
+				for(long i=0;i<n;i++)	// boundary of square
 				{
-					n1 = n2;
-					n2 = gr->AddPnt(mglPoint(vx+ve*cos(k*M_PI/20),
-							vy+vf*sin(k*M_PI/20), zVal),-1,q,-1,11);
-					if(k>0)	gr->line_plot(n1,n2);
+					mreal vx=x->v(i,mx), ve=ex->v(i,m1), vy=y->v(i,my), vf=ey->v(i,m2);
+					mreal c = sh ? gr->NextColor(pal,i):gr->CDef;
+					long n1 = gr->AddPnt(mglPoint(vx-ve, vy+vf, zVal),c,q,-1,11);
+					long n2 = gr->AddPnt(mglPoint(vx-ve, vy-vf, zVal),c,q,-1,11);
+					long n3 = gr->AddPnt(mglPoint(vx+ve, vy+vf, zVal),c,q,-1,11);
+					long n4 = gr->AddPnt(mglPoint(vx+ve, vy-vf, zVal),c,q,-1,11);
+					gr->line_plot(n1,n2);	gr->line_plot(n1,n3);
+					gr->line_plot(n4,n2);	gr->line_plot(n4,n3);
+				}
+			if(strchr("dD",mk))
+#pragma omp parallel for
+				for(long i=0;i<n;i++)	// boundary of rhomb
+				{
+					mreal vx=x->v(i,mx), ve=ex->v(i,m1), vy=y->v(i,my), vf=ey->v(i,m2);
+					mreal c = sh ? gr->NextColor(pal,i):gr->CDef;
+					long n1 = gr->AddPnt(mglPoint(vx, vy+vf, zVal),c,q,-1,11);
+					long n2 = gr->AddPnt(mglPoint(vx-ve, vy, zVal),c,q,-1,11);
+					long n3 = gr->AddPnt(mglPoint(vx, vy-vf, zVal),c,q,-1,11);
+					long n4 = gr->AddPnt(mglPoint(vx+ve, vy, zVal),c,q,-1,11);
+					gr->line_plot(n1,n2);	gr->line_plot(n2,n3);
+					gr->line_plot(n3,n4);	gr->line_plot(n4,n1);
+				}
+			if(strchr("oOC",mk))
+#pragma omp parallel for
+				for(long i=0;i<n;i++)	// circle
+				{
+					mreal vx=x->v(i,mx), ve=ex->v(i,m1), vy=y->v(i,my), vf=ey->v(i,m2);
+					mreal c = sh ? gr->NextColor(pal,i):gr->CDef;
+					long n1,n2,k;
+					for(k=0,n2=-1;k<=40;k++)
+					{
+						n1 = n2;
+						n2 = gr->AddPnt(mglPoint(vx+ve*mgl_cos[(18*k)%360],
+								vy+vf*mgl_cos[(270+18*k)%360], zVal),c,q,-1,11);
+						if(k>0)	gr->line_plot(n1,n2);
+					}
 				}
-				if(sh)	gr->NextColor(pal);
-			}
 			switch(mk)
 			{
-			case 'P':	case '+':	for(i=0;i<n;i++)
-			{
-				vx=x->v(i,mx);	ve=ex->v(i,m1);	vy=y->v(i,my);	vf=ey->v(i,m2);
-				n1 = gr->AddPnt(mglPoint(vx, vy+vf, zVal),-1,q,-1,11);
-				n2 = gr->AddPnt(mglPoint(vx-ve, vy, zVal),-1,q,-1,11);
-				n3 = gr->AddPnt(mglPoint(vx, vy-vf, zVal),-1,q,-1,11);
-				n4 = gr->AddPnt(mglPoint(vx+ve, vy, zVal),-1,q,-1,11);
-				gr->line_plot(n1,n3);	gr->line_plot(n2,n4);
-				if(sh)	gr->NextColor(pal);
-			}	break;
-			case 'X':	case 'x':	for(i=0;i<n;i++)
-			{
-				vx=x->v(i,mx);	ve=ex->v(i,m1);	vy=y->v(i,my);	vf=ey->v(i,m2);
-				n1 = gr->AddPnt(mglPoint(vx-ve, vy+vf, zVal),-1,q,-1,11);
-				n2 = gr->AddPnt(mglPoint(vx-ve, vy-vf, zVal),-1,q,-1,11);
-				n3 = gr->AddPnt(mglPoint(vx+ve, vy+vf, zVal),-1,q,-1,11);
-				n4 = gr->AddPnt(mglPoint(vx+ve, vy-vf, zVal),-1,q,-1,11);
-				gr->line_plot(n1,n3);	gr->line_plot(n2,n4);
-				if(sh)	gr->NextColor(pal);
-			}	break;
-			case 'S':	for(i=0;i<n;i++)
-			{
-				vx=x->v(i,mx);	ve=ex->v(i,m1);	vy=y->v(i,my);	vf=ey->v(i,m2);
-				n1 = gr->AddPnt(mglPoint(vx-ve, vy+vf, zVal),-1,q,-1,11);
-				n2 = gr->AddPnt(mglPoint(vx-ve, vy-vf, zVal),-1,q,-1,11);
-				n3 = gr->AddPnt(mglPoint(vx+ve, vy+vf, zVal),-1,q,-1,11);
-				n4 = gr->AddPnt(mglPoint(vx+ve, vy-vf, zVal),-1,q,-1,11);
-				gr->quad_plot(n1,n2,n3,n4);
-				if(sh)	gr->NextColor(pal);
-			}	break;
-			case 'D':	for(i=0;i<n;i++)
-			{
-				vx=x->v(i,mx);	ve=ex->v(i,m1);	vy=y->v(i,my);	vf=ey->v(i,m2);
-				n1 = gr->AddPnt(mglPoint(vx, vy+vf, zVal),-1,q,-1,11);
-				n2 = gr->AddPnt(mglPoint(vx-ve, vy, zVal),-1,q,-1,11);
-				n3 = gr->AddPnt(mglPoint(vx, vy-vf, zVal),-1,q,-1,11);
-				n4 = gr->AddPnt(mglPoint(vx+ve, vy, zVal),-1,q,-1,11);
-				gr->quad_plot(n1,n2,n3,n4);
-				if(sh)	gr->NextColor(pal);
-			}	break;
-			case 'O':	for(i=0;i<n;i++)
-			{
-				vx=x->v(i,mx);	ve=ex->v(i,m1);	vy=y->v(i,my);	vf=ey->v(i,m2);
-				n3 = gr->AddPnt(mglPoint(vx,vy,zVal));
-				for(k=0,n2=-1;k<=40;k++)
+			case 'P':	case '+':
+#pragma omp parallel for
+				for(long i=0;i<n;i++)
 				{
-					n1 = n2;
-					n2 = gr->AddPnt(mglPoint(vx+ve*cos(k*M_PI/20),
-							vy+vf*sin(k*M_PI/20), zVal),-1,q,-1,11);
-					if(k>0)	gr->trig_plot(n1,n2,n3);
+					mreal vx=x->v(i,mx), ve=ex->v(i,m1), vy=y->v(i,my), vf=ey->v(i,m2);
+					mreal c = sh ? gr->NextColor(pal,i):gr->CDef;
+					long n1 = gr->AddPnt(mglPoint(vx, vy+vf, zVal),c,q,-1,11);
+					long n2 = gr->AddPnt(mglPoint(vx-ve, vy, zVal),c,q,-1,11);
+					long n3 = gr->AddPnt(mglPoint(vx, vy-vf, zVal),c,q,-1,11);
+					long n4 = gr->AddPnt(mglPoint(vx+ve, vy, zVal),c,q,-1,11);
+					gr->line_plot(n1,n3);	gr->line_plot(n2,n4);
+				}	break;
+			case 'X':	case 'x':
+#pragma omp parallel for
+				for(long i=0;i<n;i++)
+				{
+					mreal vx=x->v(i,mx), ve=ex->v(i,m1), vy=y->v(i,my), vf=ey->v(i,m2);
+					mreal c = sh ? gr->NextColor(pal,i):gr->CDef;
+					long n1 = gr->AddPnt(mglPoint(vx-ve, vy+vf, zVal),c,q,-1,11);
+					long n2 = gr->AddPnt(mglPoint(vx-ve, vy-vf, zVal),c,q,-1,11);
+					long n3 = gr->AddPnt(mglPoint(vx+ve, vy+vf, zVal),c,q,-1,11);
+					long n4 = gr->AddPnt(mglPoint(vx+ve, vy-vf, zVal),c,q,-1,11);
+					gr->line_plot(n1,n4);	gr->line_plot(n2,n3);
+				}	break;
+			case 'S':
+#pragma omp parallel for
+				for(long i=0;i<n;i++)
+				{
+					mreal vx=x->v(i,mx), ve=ex->v(i,m1), vy=y->v(i,my), vf=ey->v(i,m2);
+					mreal c = sh ? gr->NextColor(pal,i):gr->CDef;
+					long n1 = gr->AddPnt(mglPoint(vx-ve, vy+vf, zVal),c,q,-1,11);
+					long n2 = gr->AddPnt(mglPoint(vx-ve, vy-vf, zVal),c,q,-1,11);
+					long n3 = gr->AddPnt(mglPoint(vx+ve, vy+vf, zVal),c,q,-1,11);
+					long n4 = gr->AddPnt(mglPoint(vx+ve, vy-vf, zVal),c,q,-1,11);
+					gr->quad_plot(n1,n2,n3,n4);
+				}	break;
+			case 'D':
+#pragma omp parallel for
+				for(long i=0;i<n;i++)
+				{
+					mreal vx=x->v(i,mx), ve=ex->v(i,m1), vy=y->v(i,my), vf=ey->v(i,m2);
+					mreal c = sh ? gr->NextColor(pal,i):gr->CDef;
+					long n1 = gr->AddPnt(mglPoint(vx, vy+vf, zVal),c,q,-1,11);
+					long n2 = gr->AddPnt(mglPoint(vx-ve, vy, zVal),c,q,-1,11);
+					long n3 = gr->AddPnt(mglPoint(vx, vy-vf, zVal),c,q,-1,11);
+					long n4 = gr->AddPnt(mglPoint(vx+ve, vy, zVal),c,q,-1,11);
+					gr->quad_plot(n1,n4,n2,n3);
+				}	break;
+			case 'O':
+#pragma omp parallel for
+				for(long i=0;i<n;i++)
+				{
+					mreal vx=x->v(i,mx), ve=ex->v(i,m1), vy=y->v(i,my), vf=ey->v(i,m2);
+					mreal c = sh ? gr->NextColor(pal,i):gr->CDef;
+					long n1, n2, n3 = gr->AddPnt(mglPoint(vx,vy,zVal),c),k;
+					for(k=0,n2=-1;k<=40;k++)
+					{
+						n1 = n2;
+						n2 = gr->AddPnt(mglPoint(vx+ve*mgl_cos[(18*k)%360],
+								vy+vf*mgl_cos[(270+18*k)%360], zVal),c,q,-1,11);
+						if(k>0)	gr->trig_plot(n1,n2,n3);
+					}
+				}	break;
+			case 'C':
+				for(long i=0;i<n;i++)
+				{
+					gr->mark_plot(gr->AddPnt(mglPoint(x->v(i,mx),y->v(i,my),zVal),-1,q,-1,3), '.');
+					if(sh)	gr->NextColor(pal);
 				}
-				if(sh)	gr->NextColor(pal);
-			}	break;
-			case 'C':	for(i=0;i<n;i++)
-			{
-				vx=x->v(i,mx);	vy=y->v(i,my);
-				gr->mark_plot(gr->AddPnt(mglPoint(vx,vy,zVal),-1,q,-1,3), '.');
-				if(sh)	gr->NextColor(pal);
-			}
 			}
 		}
-		else	for(i=0;i<n;i++)
-		{
-			vx=x->v(i,mx);	ve=ex->v(i,m1);	vy=y->v(i,my);	vf=ey->v(i,m2);
-			if(mk)	gr->mark_plot(gr->AddPnt(mglPoint(vx,vy,zVal)), mk);
+		else
+#pragma omp parallel for
+			for(long i=0;i<n;i++)
+			{
+				mreal vx=x->v(i,mx), ve=ex->v(i,m1), vy=y->v(i,my), vf=ey->v(i,m2);
+				mreal c = sh ? gr->NextColor(pal,i):gr->CDef;
+				if(mk)	gr->mark_plot(gr->AddPnt(mglPoint(vx,vy,zVal),c), mk);
 
-			n1 = gr->AddPnt(mglPoint(vx, vy+vf, zVal),-1,q,-1,11);
-			n2 = gr->AddPnt(mglPoint(vx, vy-vf, zVal),-1,q,-1,11);
-			gr->line_plot(n1,n2);	gr->arrow_plot(n1,n2,'I');	gr->arrow_plot(n2,n1,'I');
+				long n1 = gr->AddPnt(mglPoint(vx, vy+vf, zVal),c,q,-1,11);
+				long n2 = gr->AddPnt(mglPoint(vx, vy-vf, zVal),c,q,-1,11);
+				gr->line_plot(n1,n2);	gr->arrow_plot(n1,n2,'I');	gr->arrow_plot(n2,n1,'I');
 
-			n1 = gr->AddPnt(mglPoint(vx+ve, vy, zVal),-1,q,-1,11);
-			n2 = gr->AddPnt(mglPoint(vx-ve, vy, zVal),-1,q,-1,11);
-			gr->line_plot(n1,n2);	gr->arrow_plot(n1,n2,'I');	gr->arrow_plot(n2,n1,'I');
-			if(sh)	gr->NextColor(pal);
-		}
+				n1 = gr->AddPnt(mglPoint(vx+ve, vy, zVal),-1,q,c,11);
+				n2 = gr->AddPnt(mglPoint(vx-ve, vy, zVal),-1,q,c,11);
+				gr->line_plot(n1,n2);	gr->arrow_plot(n1,n2,'I');	gr->arrow_plot(n2,n1,'I');
+			}
 	}
 	gr->EndGroup();
 }
@@ -1356,18 +1493,18 @@ void MGL_EXPORT mgl_error_exy_(uintptr_t *gr, uintptr_t *x, uintptr_t *y, uintpt
 void face_plot(mglBase *gr, mglPoint o, mglPoint d1, mglPoint d2, mreal c, bool wire)
 {
 	const int num=10;
-	mglPoint p,nn=d1^d2;
+	mglPoint nn=d1^d2;
 	d1 = d1/num;	d2 = d2/num;
-	register long i,j,i0,n=num+1;
-	long *id=new long[n*n];
+	long n=num+1, *id=new long[n*n];
 	gr->Reserve(n*n);
-	for(j=0;j<n;j++)	for(i=0;i<n;i++)
-	{	p = o+d1*i+d2*j;	id[i+n*j] = gr->AddPnt(p,c,nn);	}
-	for(i=0;i<num;i++)	for(j=0;j<num;j++)
+#pragma omp parallel for collapse(2)
+	for(long j=0;j<n;j++)	for(long i=0;i<n;i++)
+		id[i+n*j] = gr->AddPnt(o+d1*i+d2*j,c,nn);
+#pragma omp parallel for collapse(2)
+	for(long j=0;j<num;j++)	for(long i=0;i<num;i++)
 	{
-		if(gr->Stop)	{	delete []id;	return;	}
-		i0 = i+n*j;
-		gr->quad_plot(id[i0],id[i0+1],id[i0+n],id[i0+n+1]);
+		long *ii = id+i+n*j;
+		gr->quad_plot(ii[0],ii[1],ii[n],ii[n+1]);
 	}
 	if(wire)
 	{
@@ -1375,9 +1512,8 @@ void face_plot(mglBase *gr, mglPoint o, mglPoint d1, mglPoint d2, mreal c, bool
 		long *jj=id+n+1;
 		jj[0] = jj[1] = gr->CopyNtoC(id[0],gr->CDef);
 		jj[2] = jj[3] = gr->CopyNtoC(id[n*n-1],gr->CDef);
-		for(i=1;i<n;i++)
+		for(long i=1;i<n;i++)
 		{
-			if(gr->Stop)	{	delete []id;	return;	}
 			memcpy(jj+4,jj,4*sizeof(long));
 			jj[0] = gr->CopyNtoC(id[i],gr->CDef);
 			jj[1] = gr->CopyNtoC(id[n*i],gr->CDef);
@@ -1398,17 +1534,17 @@ void MGL_EXPORT mgl_chart(HMGL gr, HCDT a, const char *cols, const char *opt)
 	gr->SaveState(opt);
 	static int cgid=1;	gr->StartGroup("Chart",cgid++);
 	bool wire = mglchr(cols,'#');	// draw edges
-	register long n=a->GetNx(),i,j=0;
-	if(cols)	for(i=0;i<long(strlen(cols));i++)
+	register long n=a->GetNx(),i,j=0,len=cols?long(strlen(cols)):0;
+	if(cols)	for(i=0;i<len;i++)
 		if(strchr(MGL_COLORS,cols[i]) || cols[i]==' ')	j++;
-	if(j==0)	cols = MGL_DEF_PAL;
-	mreal *c = new mreal[strlen(cols)+1],cc;
+	if(j==0)	{	cols = MGL_DEF_PAL;	len=long(strlen(cols));	}
+	mreal *c = new mreal[len+1],cc;
 	long nc=0;			// number of colors
-	for(i=0;i<long(strlen(cols));i++)
+	for(i=0;i<len;i++)
 		if(strchr(MGL_COLORS,cols[i]) || cols[i]==' ')
 		{	c[nc]=gr->AddTexture(cols[i]);	nc++;	}
 	// NOTE: nc>0 since j>0 or MGL_DEF_PAL is not empty
-	
+
 	mreal dy = (gr->Max.y-gr->Min.y)/a->GetNy(), dx, ss, cs, x1, y1, dz=gr->Max.z-gr->Min.z, vv;
 	mglPoint d1,d2,o;
 
@@ -1469,8 +1605,8 @@ void MGL_EXPORT mgl_mark_xyz(HMGL gr, HCDT x, HCDT y, HCDT z, HCDT r, const char
 		for(int i=0;i<n;i++)
 		{
 			if(gr->Stop)	return;
-			gr->mark_plot(gr->AddPnt(mglPoint(x->v(i,mx),y->v(i,my),z->v(i,mz))), mk, fabs(r->v(i,mr)));
-			if(sh)	gr->NextColor(pal);
+			mreal c = sh ? gr->NextColor(pal,i):gr->CDef;
+			gr->mark_plot(gr->AddPnt(mglPoint(x->v(i,mx),y->v(i,my),z->v(i,mz)),c), mk, fabs(r->v(i,mr)));
 		}
 	}
 	gr->EndGroup();
@@ -1529,7 +1665,7 @@ void MGL_EXPORT mgl_tube_xyzr(HMGL gr, HCDT x, HCDT y, HCDT z, HCDT r, const cha
 	bool sh = mglchr(pen,'!');
 	bool wire = mglchr(pen,'#');
 
-	const int num=24;
+	int num=!(gr->GetQuality()&3)?13:25;
 	gr->SetPenPal(pen,&pal);
 	gr->Reserve(n*m*num);
 	mglPoint p,l,t,u,q,d;
@@ -1540,25 +1676,25 @@ void MGL_EXPORT mgl_tube_xyzr(HMGL gr, HCDT x, HCDT y, HCDT z, HCDT r, const cha
 		gr->NextColor(pal);
 		mx = j<x->GetNy() ? j:0;	my = j<y->GetNy() ? j:0;
 		mz = j<z->GetNy() ? j:0;	mr = j<r->GetNy() ? j:0;
-		register long i,k;
-		for(i=0;i<n;i++)
+		for(long i=0;i<n;i++)
 		{
 			l = mglPoint(x->dvx(i,mx),y->dvx(i,my),z->dvx(i,mz));
 			t = !l;		t.Normalize();	u = t^l;	u.Normalize();
 			q = mglPoint(x->v(i,mx),y->v(i,my),z->v(i,mz));
-			mreal si,co,ff, rr=r->v(i,mr), dr=r->dvx(i,mr);
-			for(k=0;k<num;k++)
+			mreal rr=r->v(i,mr), dr=r->dvx(i,mr);
+			mreal c = sh ? gr->NextColor(pal,i):gr->CDef;
+			for(long k=0;k<num;k++)
 			{
 				if(gr->Stop)	{	delete []nn;	return;	}
-				ff = k*2*M_PI/(num-1);	co = cos(ff);	si = sin(ff);
+				register int kk = k*360/(num-1);
+				register float  co = mgl_cos[(kk)%360], si = mgl_cos[(270+kk)%360];
 				p = q + t*(rr*co) + u*(rr*si);
 				d = (t*si - u*co)^(l + t*(dr*co) + u*(dr*si));
-				nn[k+num]=nn[k];	nn[k] = gr->AddPnt(p,gr->CDef,wire?mglPoint(NAN,NAN):d,-1,3);
+				nn[k+num]=nn[k];	nn[k] = gr->AddPnt(p,c,wire?mglPoint(NAN,NAN):d,-1,3);
 				if(i*k>0 && !wire)	gr->quad_plot(nn[k],nn[k-1],nn[k+num],nn[k+num-1]);
 				if(i*k>0 && wire && k%4==0)	gr->line_plot(nn[k],nn[k+num]);
 				if(k>0 && wire)		gr->line_plot(nn[k],nn[k-1]);
 			}
-			if(sh)	gr->NextColor(pal);
 		}
 	}
 	delete []nn;	gr->EndGroup();
@@ -1696,6 +1832,7 @@ void MGL_EXPORT mgl_tape_xyz(HMGL gr, HCDT x, HCDT y, HCDT z, const char *pen, c
 			l = p2-p1;		l /= mgl_norm(l);
 			q1 -= l*(l*q1);	q1/= mgl_norm(q1);	q2 = (q1^l);
 			m1 = n1;	m2 = n2;	m3 = n3;	m4 = n4;
+			if(sh)	c2=c1=gr->NextColor(pal,i);
 			if(p2>gr->Min && p2<gr->Max)
 			{
 				if(xo)
@@ -1713,7 +1850,6 @@ void MGL_EXPORT mgl_tape_xyz(HMGL gr, HCDT x, HCDT y, HCDT z, const char *pen, c
 					else		gr->quad_plot(n3,n4,m3,m4);
 				}
 			}
-			if(sh)	c2=c1=gr->NextColor(pal);
 		}
 	}
 	gr->EndGroup();
diff --git a/src/prc/writePRC.h b/src/prc/writePRC.h
index 92a8215..59457b1 100644
--- a/src/prc/writePRC.h
+++ b/src/prc/writePRC.h
@@ -24,9 +24,6 @@
 #include <vector>
 #include <deque>
 #include <list>
-#ifdef __GNUC__
-#include <ext/slist>
-#endif
 #include <map>
 #include <iostream>
 #include <algorithm>
@@ -224,11 +221,7 @@ class PRCAttribute : public PRCAttributeEntry
   void addKey(const PRCSingleAttribute &key) { attribute_keys.push_back(key); }
   std::deque<PRCSingleAttribute> attribute_keys;
 };
-#ifdef __GNUC__
-typedef __gnu_cxx::slist<PRCAttribute> PRCAttributeList;
-#else
 typedef std::list<PRCAttribute> PRCAttributeList;
-#endif
 
 class PRCAttributes
 {
diff --git a/src/prim.cpp b/src/prim.cpp
index 1bf0f5f..15b93b2 100644
--- a/src/prim.cpp
+++ b/src/prim.cpp
@@ -32,7 +32,7 @@ void MGL_EXPORT mgl_mark(HMGL gr, double x, double y, double z,const char *mark)
 	if(mgl_isnan(z))	z=2*gr->Max.z-gr->Min.z;
 	static int cgid=1;	gr->StartGroup("MarkS",cgid++);
 	long k = gr->AddPnt(mglPoint(x,y,z),gr->CDef,mglPoint(NAN),-1,3);
-	gr->mark_plot(k,mk); 	gr->AddActive(k);
+	gr->mark_plot(k,mk,gr->GetPenWidth()); 	gr->AddActive(k);
 	gr->EndGroup();
 }
 //-----------------------------------------------------------------------------
@@ -153,7 +153,7 @@ void MGL_EXPORT mgl_face(HMGL gr, double x0, double y0, double z0, double x1, do
 	if(mgl_isnan(z2))	z2 = zz;	if(mgl_isnan(z3))	z3 = zz;
 	mglPoint p1(x0,y0,z0), p2(x1,y1,z1), p3(x2,y2,z2), p4(x3,y3,z3);
 	if(gr->GetNumPal(pal)>=4)
-	{	c2=gr->NextColor(pal);	c3=gr->NextColor(pal);	c4=gr->NextColor(pal);	}
+	{	c2=gr->NextColor(pal,1);	c3=gr->NextColor(pal,2);	c4=gr->NextColor(pal,3);	}
 	mglPoint q1,q2,q3,q4;
 	q1 = (p2-p1)^(p3-p1);	q4 = (p2-p4)^(p3-p4);
 	q2 = (p1-p2)^(p4-p2);	q3 = (p1-p3)^(p4-p3);
@@ -213,10 +213,10 @@ void MGL_EXPORT mgl_cone(HMGL gr, double x1, double y1, double z1, double x2, do
 	if(r1==0 && r2==0)	return;
 
 	static int cgid=1;	gr->StartGroup("Cone",cgid++);
-	mglPoint p1(x1,y1,z1), p2(x2,y2,z2), p,q, d=p2-p1,a,b;
+	mglPoint p1(x1,y1,z1), p2(x2,y2,z2), p,q(NAN,NAN),t(NAN,NAN), d=p2-p1,a,b;
 	a=!d;	a.Normalize();		b=d^a;	b.Normalize();
 	long ss=gr->AddTexture(stl);
-	mreal c1=gr->GetC(ss,p1.z), c2=gr->GetC(ss,p2.z);
+	mreal c1=gr->GetC(ss,p1.z), c2=gr->GetC(ss,p2.z), dr=r2-r1;
 	long *kk=new long[164],k1=-1,k2=-1;
 	bool edge = mglchr(stl,'@');
 	bool wire = mglchr(stl,'#');
@@ -226,39 +226,47 @@ void MGL_EXPORT mgl_cone(HMGL gr, double x1, double y1, double z1, double x2, do
 		k1=gr->AddPnt(p1,c1,d,-1,3);
 		k2=gr->AddPnt(p2,c2,d,-1,3);
 	}
-	mreal f,si,co, dr=r2-r1;
-	register long i;
-	for(i=0;i<(wire?13:41);i++)
+	long n=wire?6:18;	//wire?6:18;
+	if(mglchr(stl,'4'))	n=2;
+	else if(mglchr(stl,'6'))	n=3;
+	else if(mglchr(stl,'8'))	n=4;
+	bool refr = n>6;
+	if(refr)	t=d;
+
+#pragma omp parallel for firstprivate(p,q)
+	for(long i=0;i<2*n+1;i++)
 	{
-		if(gr->Stop)	{	delete []kk;	return;	}
-		f = i*M_PI/(wire?6:20);	co = cos(f);	si = sin(f);
+		if(gr->Stop)	continue;
+		register int f = n!=4?(2*i+1)*90/n:45*i;
+		register mreal co = mgl_cos[f%360], si = mgl_cos[(f+270)%360];
 		p = p1+(r1*co)*a+(r1*si)*b;
-		q = (si*a-co*b)^(d + (dr*co)*a + (dr*si)*b);
-		if(wire)	q.x=q.y=NAN;
+		if(refr)	q = (si*a-co*b)^(d + (dr*co)*a + (dr*si)*b);
 		kk[i] = gr->AddPnt(p,c1,q,-1,3);
-		if(edge && !wire)	kk[i+82] = gr->AddPnt(p,c1,d,-1,3);
+		if(edge && !wire)	kk[i+82] = gr->AddPnt(p,c1,t,-1,3);
 		p = p2+(r2*co)*a+(r2*si)*b;
-		kk[i+(wire?13:41)] = gr->AddPnt(p,c2,q,-1,3);
-		if(edge && !wire)	kk[i+123] = gr->AddPnt(p,c2,d,-1,3);
-	}
-	if(wire)	for(i=0;i<12;i++)
-	{
-		if(gr->Stop)	{	delete []kk;	return;	}
-		gr->line_plot(kk[i],kk[i+1]);
-		gr->line_plot(kk[i],kk[i+13]);
-		gr->line_plot(kk[i+14],kk[i+1]);
-		gr->line_plot(kk[i+14],kk[i+13]);
+		kk[i+2*n+1] = gr->AddPnt(p,c2,q,-1,3);
+		if(edge && !wire)	kk[i+123] = gr->AddPnt(p,c2,t,-1,3);
 	}
-	else	for(i=0;i<40;i++)
-	{
-		if(gr->Stop)	{	delete []kk;	return;	}
-		gr->quad_plot(kk[i],kk[i+1],kk[i+41],kk[i+42]);
-		if(edge)
+	if(wire)
+//#pragma omp parallel for		// useless
+		for(long i=0;i<2*n;i++)
 		{
-			gr->trig_plot(k1,kk[i+82],kk[i+83]);
-			gr->trig_plot(k2,kk[i+123],kk[i+124]);
+			gr->line_plot(kk[i],kk[i+1]);
+			gr->line_plot(kk[i],kk[i+2*n+1]);
+			gr->line_plot(kk[i+2*n+2],kk[i+1]);
+			gr->line_plot(kk[i+2*n+2],kk[i+2*n+1]);
+		}
+	else
+#pragma omp parallel for
+		for(long i=0;i<2*n;i++)
+		{
+			gr->quad_plot(kk[i],kk[i+1],kk[i+2*n+1],kk[i+2*n+2]);
+			if(edge)
+			{
+				gr->trig_plot(k1,kk[i+82],kk[i+83]);
+				gr->trig_plot(k2,kk[i+123],kk[i+124]);
+			}
 		}
-	}
 	gr->EndGroup();	delete []kk;
 }
 //-----------------------------------------------------------------------------
@@ -272,7 +280,7 @@ void MGL_EXPORT mgl_cone_(uintptr_t* gr, mreal *x1, mreal *y1, mreal *z1, mreal
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_cones_xyz(HMGL gr, HCDT x, HCDT y, HCDT z, const char *pen, const char *opt)
 {
-	long i,j,m,mx,my,mz,n=z->GetNx(),nx=x->GetNx(), nz=z->GetNy(), pal;
+	long i=5,j,m,mx,my,mz,n=z->GetNx(),nx=x->GetNx(), nz=z->GetNy(), pal;
 	if(mgl_check_dim1(gr,x,z,y,0,"Cones",true))	return;
 
 	gr->SaveState(opt);
@@ -281,12 +289,20 @@ void MGL_EXPORT mgl_cones_xyz(HMGL gr, HCDT x, HCDT y, HCDT z, const char *pen,
 
 	bool above= mglchr(pen,'a');
 	bool wire = mglchr(pen,'#');
-	mreal *dd=new mreal[2*n], x1,z0,zz,d, vx,vy,vz,v0,v1;
+	bool tube = mglchr(pen,'t');
+	mreal *dd=new mreal[2*n], x1,z0,zz,d, vx,vy,vz,v0,v1,dv=nx>n?1:0;
+	if(mglchr(pen,'<'))	dv = 1;
+	if(mglchr(pen,'^'))	dv = 0;
+	if(mglchr(pen,'>'))	dv = -1;
 
 	gr->SetPenPal(pen,&pal);
-	char c1[7];	memset(c1,0,7);	c1[0] ='@';
-	char c2[7];	memset(c2,0,7);	c2[0] ='@';
-	if(wire)	c1[5]=c2[5]='#';
+	char c1[8];	memset(c1,0,8);	c1[0] ='@';
+	char c2[8];	memset(c2,0,8);	c2[0] ='@';
+	if(wire)	{	c1[5]=c2[5]='#';	i++;	}
+	if(mglchr(pen,'&'))	c1[i]=c2[i]='4';
+	else if(mglchr(pen,'4'))	c1[i]=c2[i]='4';
+	else if(mglchr(pen,'6'))	c1[i]=c2[i]='6';
+	else if(mglchr(pen,'8'))	c1[i]=c2[i]='8';
 	memset(dd,0,2*n*sizeof(mreal));
 	z0 = gr->GetOrgZ('x');
 	for(i=0;i<n;i++)	for(j=0;j<m;j++)	dd[i] += z->v(i, j<nz ? j:0);
@@ -295,7 +311,7 @@ void MGL_EXPORT mgl_cones_xyz(HMGL gr, HCDT x, HCDT y, HCDT z, const char *pen,
 		gr->NextColor(pal);		memcpy(c1+1,gr->last_line(),4);
 		if(gr->GetNumPal(pal)==2*m)
 		{	gr->NextColor(pal);	memcpy(c2+1,gr->last_line(),4);	}
-		else	memcpy(c2,c1,7);
+		else	memcpy(c2,c1,8);
 		mx = j<x->GetNy() ? j:0;	my = j<y->GetNy() ? j:0;	mz = j<nz ? j:0;
 		for(i=0;i<n;i++)
 		{
@@ -303,15 +319,16 @@ void MGL_EXPORT mgl_cones_xyz(HMGL gr, HCDT x, HCDT y, HCDT z, const char *pen,
 			vx=x->v(i,mx);	vy=y->v(i,my);	vz=z->v(i,mz);
 			v0=y->v(i,0);	v1=i<nx-1 ? x->v(i+1,mx):x->v(i-1,mx);
 			d = i<nx-1 ? v1-vx : vx-v1;
-			x1 = (n<nx ? (vx+v1)/2 : vx) + d/2*(1-0.7*gr->BarWidth);
+			x1 = vx + d/2*(dv-0.*gr->BarWidth);	// TODO
+			d *= 0.7*gr->BarWidth;
 			if(above)
 			{
 				zz = j>0?dd[i+n]:z0;	dd[i+n] += vz;
 				mgl_cone(gr, x1,v0,zz, x1,v0,dd[i+n],
-						 0.7*gr->BarWidth*d*(dd[i]-zz)/(dd[i]-z0),
-						 0.7*gr->BarWidth*d*(dd[i]-dd[i+n])/(dd[i]-z0), c1);
+						 tube?d:d*(dd[i]-zz)/(dd[i]-z0),
+						 tube?d:d*(dd[i]-dd[i+n])/(dd[i]-z0), c1);
 			}
-			else	mgl_cone(gr, x1,vy,z0, x1,vy,vz, 0.7*gr->BarWidth*d,0, vz<0?c1:c2);
+			else	mgl_cone(gr, x1,vy,z0, x1,vy,vz, d,tube?d:0, vz<0?c1:c2);
 		}
 	}
 	gr->EndGroup();	delete []dd;
@@ -378,8 +395,8 @@ void MGL_EXPORT mgl_ellipse(HMGL gr, double x1, double y1, double z1, double x2,
 	for(long i=0;i<n;i++)
 	{
 		if(gr->Stop)	return;
-		mreal t = i*2*M_PI/(n-1.);
-		p = s+v*cos(t)+u*sin(t);
+		register int t=i*360/(n-1);
+		p = s+v*mgl_cos[t%360]+u*mgl_cos[(270+t)%360];
 		n2 = n1;	n1 = gr->AddPnt(p,c,q,-1,11);
 		if(i==n/4)	gr->AddActive(n1,2);
 		m2 = m1;	m1 = gr->CopyNtoC(n1,k);
@@ -446,32 +463,32 @@ void MGL_EXPORT mgl_drop(HMGL gr, mglPoint p, mglPoint q, double r, double c, do
 	q.Normalize();	p1 = !q;	p2 = q^p1;	r /= 2;
 
 	static int cgid=1;	gr->StartGroup("Drop",cgid++);
-	const int n = 24, m = n/2;
-	register long i,j;
+	const int m=12, n=2*m+1;
 	gr->Reserve(n*m);
 	long *nn=new long[2*n],n1,n2;
-	mreal u,v,x,y,z,rr,dr, co,si;
+	mreal x,y,z,rr,dr;
 
 	z = r*(1+sh)*(1+sh);	n1 = gr->AddPnt(p + q*z,c,q,-1,3);
 	z = r*(1+sh)*(sh-1);	n2 = gr->AddPnt(p + q*z,c,q,-1,3);
 
-	for(i=0;i<m;i++)	for(j=0;j<n;j++)
+	for(long i=0;i<=m;i++)	for(long j=0;j<n;j++)	// NOTE use prev.points => not for omp
 	{
-		if(gr->Stop)	{	delete []nn;	return;	}
-		if(i>0 && i<m-1)
+		if(gr->Stop)	continue;
+		if(i>0 && i<m)
 		{
-			u = i*M_PI/(m-1.);	v = 2*M_PI*j/(n-1.)-1;
-			si = sin(u);	co = cos(u);
+			register int u=i*180/m, v=180*j/m+202;
+			register float co=mgl_cos[u%360], si=mgl_cos[(u+270)%360];
+			register float cv=mgl_cos[v%360], sv=mgl_cos[(v+270)%360];
 			rr = r*a*si*(1.+sh*co)/(1+sh);
 			dr = r*a/(1+sh)*(co*(1.+sh*co) - sh*si*si);
-			x = rr*cos(v);	y = rr*sin(v);
+			x = rr*cv;	y = rr*sv;
 			z = r*(1+sh)*(co+sh);
 			pp = p + p1*x + p2*y + q*z;
-			qq = (p1*sin(v)-p2*cos(v))^(p1*(dr*cos(v)) + p2*(dr*sin(v)) - q*(r*(1+sh)*si));
+			qq = (p1*sv-p2*cv)^(p1*(dr*cv) + p2*(dr*sv) - q*(r*(1+sh)*si));
 			nn[j+n]=nn[j];	nn[j]=gr->AddPnt(pp,c,qq,-1,3);
 		}
 		else if(i==0)	nn[j] = n1;
-		else if(i==m-1)	{	nn[j+n]=nn[j];	nn[j]=n2;	}
+		else if(i==m)	{	nn[j+n]=nn[j];	nn[j]=n2;	}
 		if(i*j>0)	gr->quad_plot(nn[j-1], nn[j], nn[j+n-1], nn[j+n]);
 	}
 	delete []nn;	gr->EndGroup();
@@ -493,43 +510,48 @@ void MGL_EXPORT mgl_drop_(uintptr_t* gr, mreal *x1, mreal *y1, mreal *z1, mreal
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_dew_xy(HMGL gr, HCDT x, HCDT y, HCDT ax, HCDT ay, const char *sch, const char *opt)
 {
-	long i,j,n=ax->GetNx(),m=ax->GetNy(),k;
+	long n=ax->GetNx(),m=ax->GetNy();
 	if(mgl_check_dim2(gr,x,y,ax,ay,"Dew"))	return;
 
 	gr->SaveState(opt);
 	static int cgid=1;	gr->StartGroup("DewXY",cgid++);
 
-	mreal xm,ym,dx,dy,dd;
 	long ss = gr->AddTexture(sch);
 	bool inv = mglchr(sch,'i');
-	mreal	zVal = gr->Min.z;
+	mreal zVal = gr->Min.z, xm=0;
 	long tx=1,ty=1;
 	if(gr->MeshNum>1)	{	tx=(n-1)/(gr->MeshNum-1);	ty=(m-1)/(gr->MeshNum-1);	}
 	if(tx<1)	tx=1;	if(ty<1)	ty=1;
 
-	for(k=0,xm=0;k<ax->GetNz();k++)	for(j=0;j<m;j++)	for(i=0;i<n;i++)
+#pragma omp parallel
 	{
-		ym = sqrt(ax->v(i,j,k)*ax->v(i,j,k)+ay->v(i,j,k)*ay->v(i,j,k));
-		xm = xm>ym ? xm : ym;
+		register mreal xm1=0,ym;
+#pragma omp for nowait collapse(3)
+		for(long k=0;k<ax->GetNz();k++)	for(long j=0;j<m;j++)	for(long i=0;i<n;i++)
+		{
+			ym = sqrt(ax->v(i,j,k)*ax->v(i,j,k)+ay->v(i,j,k)*ay->v(i,j,k));
+			xm1 = xm1>ym ? xm1 : ym;
+		}
+#pragma omp critical(max_vec)
+		{xm = xm>xm1 ? xm:xm1;}
 	}
 	xm = 1./MGL_FEPSILON/(xm==0 ? 1:xm);
-	mglPoint q;
 
-	for(k=0;k<ax->GetNz();k++)
+	for(long k=0;k<ax->GetNz();k++)
 	{
 		if(ax->GetNz()>1)	zVal = gr->Min.z+(gr->Max.z-gr->Min.z)*mreal(k)/(ax->GetNz()-1);
-		for(i=0;i<n;i+=tx)	for(j=0;j<m;j+=ty)
+//#pragma omp parallel for collapse(2)	// gain looks negligible?!?
+		for(long i=0;i<n;i+=tx)	for(long j=0;j<m;j+=ty)
 		{
-			if(gr->Stop)	return;
-			mreal xx=GetX(x,i,j,k).x, yy=GetY(y,i,j,k).x;
-			dx = i<n-1 ? (GetX(x,i+1,j,k).x-xx) : (xx-GetX(x,i-1,j,k).x);
-			dy = j<m-1 ? (GetY(y,i,j+1,k).x-yy) : (yy-GetY(y,i,j-1,k).x);
+			if(gr->Stop)	continue;
+			register mreal xx=GetX(x,i,j,k).x, yy=GetY(y,i,j,k).x, dd;
+			register mreal dx = i<n-1 ? (GetX(x,i+1,j,k).x-xx) : (xx-GetX(x,i-1,j,k).x);
+			register mreal dy = j<m-1 ? (GetY(y,i,j+1,k).x-yy) : (yy-GetY(y,i,j-1,k).x);
 			dx *= tx;	dy *= ty;
 
-			q = mglPoint(ax->v(i,j,k),ay->v(i,j,k));	dd = q.norm();
+			mglPoint q = mglPoint(ax->v(i,j,k),ay->v(i,j,k));	dd = q.norm();
 			if(inv)	q = -q;
-			mreal ccc = gr->GetC(ss,dd*xm,false);
-			mgl_drop(gr,mglPoint(xx, yy, zVal),q,(dx<dy?dx:dy)/2,ccc,dd*xm,1);
+			mgl_drop(gr,mglPoint(xx, yy, zVal),q,(dx<dy?dx:dy)/2,gr->GetC(ss,dd*xm,false),dd*xm,1);
 		}
 	}
 	gr->EndGroup();
@@ -566,11 +588,7 @@ void MGL_EXPORT mgl_putsw(HMGL gr, double x, double y, double z,const wchar_t *t
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_puts_dir(HMGL gr, double x, double y, double z, double dx, double dy, double dz, const char *text, const char *font, double size)
 {
-	long len = mbstowcs(0,text,0)+1;
-	wchar_t *buf = new wchar_t[len+1];
-	mbstowcs(buf,text,len);
-	mgl_putsw_dir(gr, x, y, z, dx, dy, dz, buf, font, size);
-	delete []buf;
+	MGL_TO_WCS(text,mgl_putsw_dir(gr, x, y, z, dx, dy, dz, wcs, font, size));
 }
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_putsw_dir(HMGL gr, double x, double y, double z, double dx, double dy, double dz, const wchar_t *text, const char *font, double size)
@@ -614,7 +632,7 @@ void MGL_EXPORT mgl_puts_dir_(uintptr_t *gr, mreal *x, mreal *y, mreal *z, mreal
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_textmarkw_xyzr(HMGL gr, HCDT x, HCDT y, HCDT z, HCDT r, const wchar_t *text, const char *fnt, const char *opt)
 {
-	long j,m,mx,my,mz,mr,n=y->GetNx();
+	long m,mx,my,mz,mr,n=y->GetNx();
 	if(mgl_check_dim0(gr,x,y,z,r,"TextMark"))	return;
 
 	gr->SaveState(opt);
@@ -625,16 +643,16 @@ void MGL_EXPORT mgl_textmarkw_xyzr(HMGL gr, HCDT x, HCDT y, HCDT z, HCDT r, cons
 	gr->Reserve(n*m);
 
 	mglPoint p,q(NAN);
-	for(j=0;j<m;j++)
+	for(long j=0;j<m;j++)
 	{
 		mx = j<x->GetNy() ? j:0;	my = j<y->GetNy() ? j:0;
 		mz = j<z->GetNy() ? j:0;	mr = j<r->GetNy() ? j:0;
-		register long i,k;
-		for(i=0;i<n;i++)
+#pragma omp parallel for private(p)	// NOTE this should be useless ?!?
+		for(long i=0;i<n;i++)
 		{
-			if(gr->Stop)	return;
+			if(gr->Stop)	continue;
 			p = mglPoint(x->v(i,mx), y->v(i,my), z->v(i,mz));
-			k = gr->AddPnt(p,-1,q);
+			register long k = gr->AddPnt(p,-1,q);
 			gr->text_plot(k, text, fnt, -0.5*fabs(r->v(i,mr)));
 		}
 	}
@@ -671,20 +689,16 @@ void MGL_EXPORT mgl_textmarkw(HMGL gr, HCDT y, const wchar_t *text, const char *
 }
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_textmark_xyzr(HMGL gr, HCDT x, HCDT y, HCDT z, HCDT r, const char *str, const char *fnt, const char *opt)
-{	long s = mbstowcs(0,str,0)+1;	wchar_t *wcs = new wchar_t[s];	mbstowcs(wcs,str,s);
-	mgl_textmarkw_xyzr(gr, x, y, z, r, wcs, fnt, opt);	delete []wcs;	}
+{	MGL_TO_WCS(str,mgl_textmarkw_xyzr(gr, x, y, z, r, wcs, fnt, opt));	}
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_textmark_xyr(HMGL gr, HCDT x, HCDT y, HCDT r, const char *str, const char *fnt, const char *opt)
-{	long s = mbstowcs(0,str,0)+1;	wchar_t *wcs = new wchar_t[s];	mbstowcs(wcs,str,s);
-	mgl_textmarkw_xyr(gr, x, y, r, wcs, fnt, opt);	delete []wcs;	}
+{	MGL_TO_WCS(str,mgl_textmarkw_xyr(gr, x, y, r, wcs, fnt, opt));	}
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_textmark_yr(HMGL gr, HCDT y, HCDT r, const char *str, const char *fnt, const char *opt)
-{	long s = mbstowcs(0,str,0)+1;	wchar_t *wcs = new wchar_t[s];	mbstowcs(wcs,str,s);
-	mgl_textmarkw_yr(gr, y, r, wcs, fnt, opt);	delete []wcs;	}
+{	MGL_TO_WCS(str,mgl_textmarkw_yr(gr, y, r, wcs, fnt, opt));	}
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_textmark(HMGL gr, HCDT y, const char *str, const char *fnt, const char *opt)
-{	long s = mbstowcs(0,str,0)+1;	wchar_t *wcs = new wchar_t[s];	mbstowcs(wcs,str,s);
-	mgl_textmarkw(gr, y, wcs, fnt, opt);	delete []wcs;	}
+{	MGL_TO_WCS(str,mgl_textmarkw(gr, y, wcs, fnt, opt));	}
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_textmark_xyzr_(uintptr_t *gr, uintptr_t *x, uintptr_t *y, uintptr_t *z, uintptr_t *r, const char *text, const char *fnt, const char *opt, int l,int n,int lo)
 {	wchar_t *s=new wchar_t[l+1];	memcpy(s,text,l);	s[l]=0;
@@ -718,25 +732,24 @@ void MGL_EXPORT mgl_textmark_(uintptr_t *gr, uintptr_t *y, const char *text, con
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_labelw_xyz(HMGL gr, HCDT x, HCDT y, HCDT z, const wchar_t *text, const char *fnt, const char *opt)
 {
-	long j,m,mx,my,mz,n=y->GetNx();
+	long m,mx,my,mz,n=y->GetNx();
 	if(mgl_check_dim1(gr,x,y,z,0,"Label"))	return;
 
 	gr->SaveState(opt);
 	static int cgid=1;	gr->StartGroup("Label",cgid++);
 	m = x->GetNy() > y->GetNy() ? x->GetNy() : y->GetNy();	m = z->GetNy() > m ? z->GetNy() : m;
 
-	register long i,k,kk,l,nn;
-	mglPoint p,q(NAN);
+	mglPoint q(NAN);
 	wchar_t tmp[32];
-	for(j=0;j<m;j++)
+	for(long j=0;j<m;j++)
 	{
 		mx = j<x->GetNy() ? j:0;	my = j<y->GetNy() ? j:0;	mz = j<z->GetNy() ? j:0;
-		for(i=0;i<n;i++)
+#pragma omp parallel for private(tmp)
+		for(long i=0;i<n;i++)
 		{
-			if(gr->Stop)	return;
+			if(gr->Stop)	continue;
 			mreal xx=x->v(i,mx), yy=y->v(i,my), zz=z->v(i,mz);
-			p = mglPoint(xx,yy,zz);
-			kk = gr->AddPnt(p,-1,q);
+			register long kk = gr->AddPnt(mglPoint(xx,yy,zz),-1,q),k,l;
 			std::wstring buf;
 			for(k=l=0;text[k];k++)
 			{
@@ -776,16 +789,13 @@ void MGL_EXPORT mgl_labelw_y(HMGL gr, HCDT y, const wchar_t *text, const char *f
 }
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_label_xyz(HMGL gr, HCDT x, HCDT y, HCDT z, const char *str, const char *fnt, const char *opt)
-{	long s = mbstowcs(0,str,0)+1;	wchar_t *wcs = new wchar_t[s];	mbstowcs(wcs,str,s);
-	mgl_labelw_xyz(gr, x, y, z, wcs, fnt, opt);	delete []wcs;	}
+{	MGL_TO_WCS(str,mgl_labelw_xyz(gr, x, y, z, wcs, fnt, opt));	}
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_label_xy(HMGL gr, HCDT x, HCDT y, const char *str, const char *fnt, const char *opt)
-{	long s = mbstowcs(0,str,0)+1;	wchar_t *wcs = new wchar_t[s];	mbstowcs(wcs,str,s);
-	mgl_labelw_xy(gr, x, y, wcs, fnt, opt);	delete []wcs;	}
+{	MGL_TO_WCS(str,mgl_labelw_xy(gr, x, y, wcs, fnt, opt));	}
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_label_y(HMGL gr, HCDT y, const char *str, const char *fnt, const char *opt)
-{	long s = mbstowcs(0,str,0)+1;	wchar_t *wcs = new wchar_t[s];	mbstowcs(wcs,str,s);
-	mgl_labelw_y(gr, y, wcs, fnt, opt);	delete []wcs;	}
+{	MGL_TO_WCS(str,mgl_labelw_y(gr, y, wcs, fnt, opt));	}
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_label_xyz_(uintptr_t *gr, uintptr_t *x, uintptr_t *y, uintptr_t *z, const char *text, const char *fnt, const char *opt, int l,int n,int lo)
 {	wchar_t *s=new wchar_t[l+1];	mbstowcs(s,text,l);	s[l]=0;
@@ -819,9 +829,7 @@ void MGL_EXPORT mgl_tablew(HMGL gr, double x, double y, HCDT val, const wchar_t
 void MGL_EXPORT mgl_table(HMGL gr, double x, double y, HCDT val, const char *text, const char *fnt, const char *opt)
 {
 	if(!text)	mgl_tablew(gr,x,y,val,L"",fnt,opt);
-	else
-	{	long s = mbstowcs(0,text,0)+1;	wchar_t *wcs = new wchar_t[s];	mbstowcs(wcs,text,s);
-		mgl_tablew(gr, x, y, val, wcs, fnt, opt);	delete []wcs;	}
+	else	MGL_TO_WCS(text,mgl_tablew(gr, x, y, val, wcs, fnt, opt));
 }
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_table_(uintptr_t *gr, mreal *x, mreal *y, uintptr_t *val, const char *text, const char *fnt, const char *opt,int l,int n,int lo)
diff --git a/src/surf.cpp b/src/surf.cpp
index 6e2b5b1..b17c1cb 100644
--- a/src/surf.cpp
+++ b/src/surf.cpp
@@ -21,33 +21,39 @@
 #include "mgl2/surf.h"
 #include "mgl2/data.h"
 #include "mgl2/eval.h"
+#include "mgl2/base.h"
 //-----------------------------------------------------------------------------
 void MGL_NO_EXPORT mgl_mesh_plot(mglBase *gr, long *pos, long n, long m, int how)
 {
 	int d = gr->MeshNum>0 ? gr->MeshNum+1 : n*m, dx = n>d?n/d:1, dy = m>d?m/d:1;
-	register long i,j,s;
 	// NOTE: number of lines in each direction can be reduced too
-	if(how&1)	for(j=0;j<m;j+=dy)
-	{
-		for(s=i=0;i<n-1;i++)	if(pos[n*j+i]>=0 && pos[n*j+i+1]>=0)	s++;
-		d = gr->FaceNum>0 ? gr->FaceNum+1 : n;	s = s>d?s/d:1;
-		for(i=0;i<n-s;i+=s)
-			gr->line_plot(pos[n*j+i],pos[n*j+i+s]);
+	if(how&1)
+#pragma omp parallel for
+		for(long j=0;j<m;j+=dy)
+		{
+			register long s,i;
+			for(s=i=0;i<n-1;i++)	if(pos[n*j+i]>=0 && pos[n*j+i+1]>=0)	s++;
+			d = gr->FaceNum>0 ? gr->FaceNum+1 : n;	s = s>d?s/d:1;
+			for(i=0;i<n-s;i+=s)
+				gr->line_plot(pos[n*j+i],pos[n*j+i+s]);
 
-	}
-	if(how&2)	for(i=0;i<n;i+=dx)
-	{
-		for(s=j=0;j<m-1;j++)	if(pos[n*j+i]>=0 && pos[n*j+i+n]>=0)	s++;
-		d = gr->FaceNum>0 ? gr->FaceNum+1 : n;	s = s>d?s/d:1;
-		for(j=0;j<m-s;j+=s)
-			gr->line_plot(pos[n*j+i],pos[n*j+i+s*n]);
-	}
+		}
+	if(how&2)
+#pragma omp parallel for
+		for(long i=0;i<n;i+=dx)
+		{
+			register long s,j;
+			for(s=j=0;j<m-1;j++)	if(pos[n*j+i]>=0 && pos[n*j+i+n]>=0)	s++;
+			d = gr->FaceNum>0 ? gr->FaceNum+1 : n;	s = s>d?s/d:1;
+			for(j=0;j<m-s;j+=s)
+				gr->line_plot(pos[n*j+i],pos[n*j+i+s*n]);
+		}
 }
 //-----------------------------------------------------------------------------
 void MGL_NO_EXPORT mgl_surf_plot(mglBase *gr, long *pos, long n, long m)
 {
-	register long i,j,s=0;
-	for(j=0;j<m-1;j++)	for(i=0;i<n-1;i++)
+	long s=0;
+	for(long j=0;j<m-1;j++)	for(long i=0;i<n-1;i++)
 		if(pos[n*j+i]>=0 && pos[n*j+i+1]>=0 && pos[n*j+i+n]>=0 && pos[n*j+i+n+1]>=0)
 			s++;
 	long dx=1,dy=1;
@@ -56,7 +62,8 @@ void MGL_NO_EXPORT mgl_surf_plot(mglBase *gr, long *pos, long n, long m)
 		int d = gr->FaceNum+1,ns=n*s/((n-1)*(m-1)),ms=m*s/((n-1)*(m-1));
 		dx = ns>d?ns/d:1;		dy = ms>d?ms/d:1;
 	}
-	for(j=0;j<m-dy;j+=dy)	for(i=0;i<n-dx;i+=dx)
+#pragma omp parallel for collapse(2)
+	for(long j=0;j<m-dy;j+=dy)	for(long i=0;i<n-dx;i+=dx)
 		gr->quad_plot(pos[n*j+i],pos[n*j+i+dx],pos[n*j+i+n*dy],pos[n*j+i+n*dy+dx]);
 }
 //-----------------------------------------------------------------------------
@@ -71,11 +78,11 @@ void MGL_EXPORT mgl_fsurf(HMGL gr, const char *eqZ, const char *sch, const char
 	long n = (mgl_isnan(r) || r<=0) ? 100:long(r+0.5);
 	mglData z(n,n);
 	mglFormula *eq = new mglFormula(eqZ);
-	register int i,j;
 	mreal dx = (gr->Max.x - gr->Min.x)/(n-1.), dy = (gr->Max.y - gr->Min.y)/(n-1.);
-	for(j=0;j<n;j++)	for(i=0;i<n;i++)
+#pragma omp parallel for collapse(2)
+	for(long j=0;j<n;j++)	for(long i=0;i<n;i++)
 	{
-		if(gr->Stop)	{	delete eq;	return;	}
+		if(gr->Stop)	continue;
 		z.a[i+n*j] = eq->Calc(gr->Min.x+i*dx, gr->Min.y+j*dy);
 	}
 	mgl_surf(gr, &z, sch,0);
@@ -93,12 +100,11 @@ void MGL_EXPORT mgl_fsurf_xyz(HMGL gr, const char *eqX, const char *eqY, const c
 	ex = new mglFormula(eqX ? eqX : "u");
 	ey = new mglFormula(eqY ? eqY : "v");
 	ez = new mglFormula(eqZ);
-	register int i,j;
-	register mreal u,v;
-	for(j=0;j<n;j++)	for(i=0;i<n;i++)
+#pragma omp parallel for collapse(2)
+	for(long j=0;j<n;j++)	for(long i=0;i<n;i++)
 	{
-		if(gr->Stop)	{	delete ex;	delete ey;	delete ez;	return;	}
-		v = i/(n-1.);	u = j/(n-1.);
+		if(gr->Stop)	continue;
+		register mreal u = j/(n-1.), v = i/(n-1.);
 		x.a[i+n*j] = ex->Calc(0,v,0,u);
 		y.a[i+n*j] = ey->Calc(0,v,0,u);
 		z.a[i+n*j] = ez->Calc(0,v,0,u);
@@ -130,25 +136,24 @@ void MGL_EXPORT mgl_fsurf_xyz_(uintptr_t *gr, const char *fx, const char *fy, co
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_mesh_xy(HMGL gr, HCDT x, HCDT y, HCDT z, const char *sch, const char *opt)
 {
-	register long i,j,k,n=z->GetNx(),m=z->GetNy();
+	long n=z->GetNx(),m=z->GetNy();
 	if(mgl_check_dim2(gr,x,y,z,0,"Mesh"))	return;
 
 	gr->SaveState(opt);
 	static int cgid=1;	gr->StartGroup("Mesh",cgid++);
-	gr->SetPenPal("-");
+	gr->SetPenPal(sch,0,false);
 	long ss = gr->AddTexture(sch);
-	long *pos = new long[n*m];
+	long *pos = new long[n*m];	memset(pos,-1L,n*m*sizeof(long));
 	gr->Reserve(n*m*z->GetNz());
 
-	mglPoint p;
-	mreal c;
-	for(k=0;k<z->GetNz();k++)
+	for(long k=0;k<z->GetNz();k++)
 	{
-		for(j=0;j<m;j++)	for(i=0;i<n;i++)
+#pragma omp parallel for collapse(2)
+		for(long j=0;j<m;j++)	for(long i=0;i<n;i++)
 		{
-			if(gr->Stop)	{	delete []pos;	return;	}
-			p = mglPoint(GetX(x,i,j,k).x, GetY(y,i,j,k).x, z->v(i,j,k));
-			c = gr->GetC(ss,p.z);		pos[i+n*j] = gr->AddPnt(p,c);
+			if(gr->Stop)	continue;
+			register mreal zz = z->v(i,j,k);
+			pos[i+n*j] = gr->AddPnt(mglPoint(GetX(x,i,j,k).x, GetY(y,i,j,k).x, zz),gr->GetC(ss,zz));
 		}
 		mgl_mesh_plot(gr,pos,n,m,3);
 	}
@@ -181,25 +186,24 @@ void MGL_EXPORT mgl_mesh_(uintptr_t *gr, uintptr_t *a, const char *sch, const ch
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_fall_xy(HMGL gr, HCDT x, HCDT y, HCDT z, const char *sch, const char *opt)
 {
-	register long i,j,k,n=z->GetNx(),m=z->GetNy();
+	long n=z->GetNx(),m=z->GetNy();
 	if(mgl_check_dim2(gr,x,y,z,0,"Fall"))	return;
 
 	gr->SaveState(opt);
 	static int cgid=1;	gr->StartGroup("Fall",cgid++);
-	gr->SetPenPal("-");
+	gr->SetPenPal(sch,0,false);
 	long ss = gr->AddTexture(sch);
 	long *pos = new long[n*m];
 	gr->Reserve(n*m*z->GetNz());
 
-	mglPoint p;
-	mreal c;
-	for(k=0;k<z->GetNz();k++)
+	for(long k=0;k<z->GetNz();k++)
 	{
-		for(j=0;j<m;j++)	for(i=0;i<n;i++)
+#pragma omp parallel for collapse(2)
+		for(long j=0;j<m;j++)	for(long i=0;i<n;i++)
 		{
-			if(gr->Stop)	{	delete []pos;	return;	}
-			p = mglPoint(GetX(x,i,j,k).x, GetY(y,i,j,k).x, z->v(i,j,k));
-			c = gr->GetC(ss,p.z);	pos[i+n*j] = gr->AddPnt(p,c);
+			if(gr->Stop)	continue;
+			register mreal zz = z->v(i,j,k);
+			pos[i+n*j] = gr->AddPnt(mglPoint(GetX(x,i,j,k).x, GetY(y,i,j,k).x, zz),gr->GetC(ss,zz));
 		}
 		mgl_mesh_plot(gr,pos,n,m, (mglchr(sch,'x')) ? 2:1);
 	}
@@ -232,7 +236,7 @@ void MGL_EXPORT mgl_fall_(uintptr_t *gr, uintptr_t *a, const char *sch, const ch
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_grid_xy(HMGL gr, HCDT x, HCDT y, HCDT z, const char *sch, const char *opt)
 {
-	register long i,j,k,n=z->GetNx(),m=z->GetNy();
+	long n=z->GetNx(),m=z->GetNy();
 	if(mgl_check_dim2(gr,x,y,z,0,"Grid"))	return;
 
 	gr->SaveState(opt);
@@ -242,15 +246,14 @@ void MGL_EXPORT mgl_grid_xy(HMGL gr, HCDT x, HCDT y, HCDT z, const char *sch, co
 	long *pos = new long[n*m];
 	gr->Reserve(n*m*z->GetNz());
 
-	mglPoint p;
-	for(k=0;k<z->GetNz();k++)
+	for(long k=0;k<z->GetNz();k++)
 	{
 		if(z->GetNz()>1)	zVal = gr->Min.z+(gr->Max.z-gr->Min.z)*mreal(k)/(z->GetNz()-1);
-		for(j=0;j<m;j++)	for(i=0;i<n;i++)
+#pragma omp parallel for collapse(2)
+		for(long j=0;j<m;j++)	for(long i=0;i<n;i++)
 		{
-			if(gr->Stop)	{	delete []pos;	return;	}
-			p = mglPoint(GetX(x,i,j,k).x, GetY(y,i,j,k).x, zVal);
-			pos[i+n*j] = gr->AddPnt(p,gr->CDef);
+			if(gr->Stop)	continue;
+			pos[i+n*j] = gr->AddPnt(mglPoint(GetX(x,i,j,k).x, GetY(y,i,j,k).x, zVal),gr->CDef);
 		}
 		mgl_mesh_plot(gr,pos,n,m,3);
 	}
@@ -283,7 +286,7 @@ void MGL_EXPORT mgl_grid_(uintptr_t *gr, uintptr_t *a,const char *sch, const cha
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_surf_xy(HMGL gr, HCDT x, HCDT y, HCDT z, const char *sch, const char *opt)
 {
-	register long i,j,k,n=z->GetNx(),m=z->GetNy();
+	long n=z->GetNx(),m=z->GetNy();
 	if(mgl_check_dim2(gr,x,y,z,0,"Surf"))	return;
 
 	gr->SaveState(opt);
@@ -294,25 +297,27 @@ void MGL_EXPORT mgl_surf_xy(HMGL gr, HCDT x, HCDT y, HCDT z, const char *sch, co
 	gr->Reserve(n*m*z->GetNz()*(wire?2:1));
 
 	mglPoint p,q,s,xx,yy;
-	mreal c;
-	for(k=0;k<z->GetNz();k++)
+	for(long k=0;k<z->GetNz();k++)
 	{
-		for(j=0;j<m;j++)	for(i=0;i<n;i++)
+#pragma omp parallel for private(p,q,s,xx,yy) collapse(2)
+		for(long j=0;j<m;j++)	for(long i=0;i<n;i++)
 		{
-			if(gr->Stop)	{	delete []pos;	return;	}
+			if(gr->Stop)	continue;
 			xx = GetX(x,i,j,k);		yy = GetY(y,i,j,k);
 			p = mglPoint(xx.x, yy.x, z->v(i,j,k));
 			q = mglPoint(xx.y, yy.y, z->dvx(i,j,k));
 			s = mglPoint(xx.z, yy.z, z->dvy(i,j,k));
-			c = gr->GetC(ss,p.z);
-			pos[i+n*j] = gr->AddPnt(p,c,q^s);
+			pos[i+n*j] = gr->AddPnt(p,gr->GetC(ss,p.z),q^s);
 		}
-		if(sch && mglchr(sch,'.'))	for(i=0;i<n*m;i++)	gr->mark_plot(pos[i],'.');
+		if(sch && mglchr(sch,'.'))
+#pragma omp parallel for
+			for(long i=0;i<n*m;i++)	gr->mark_plot(pos[i],'.');
 		else	mgl_surf_plot(gr,pos,n,m);
-		if(wire)
+		if(wire && !gr->Stop)
 		{
 			gr->SetPenPal("k-");
-			for(i=0;i<n*m;i++)	pos[i] = gr->CopyNtoC(pos[i],gr->CDef);
+#pragma omp parallel for
+			for(long i=0;i<n*m;i++)	pos[i] = gr->CopyNtoC(pos[i],gr->CDef);
 			mgl_mesh_plot(gr,pos,n,m,3);
 		}
 	}
@@ -345,7 +350,7 @@ void MGL_EXPORT mgl_surf_(uintptr_t *gr, uintptr_t *a, const char *sch, const ch
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_belt_xy(HMGL gr, HCDT x, HCDT y, HCDT z, const char *sch, const char *opt)
 {
-	register long i,j,k,n=z->GetNx(),m=z->GetNy();
+	long n=z->GetNx(),m=z->GetNy();
 	if(mgl_check_dim2(gr,x,y,z,0,"Belt"))	return;
 
 	gr->SaveState(opt);
@@ -357,35 +362,36 @@ void MGL_EXPORT mgl_belt_xy(HMGL gr, HCDT x, HCDT y, HCDT z, const char *sch, co
 	bool how = !mglchr(sch,'x');
 
 	mglPoint p1,p2,q,s,xx,yy;
-	mreal c;
-	for(k=0;k<z->GetNz();k++)
+	for(long k=0;k<z->GetNz();k++)
 	{
-		if(how)	for(i=0;i<n-dx;i+=dx)
+		if(how)	for(long i=0;i<n-dx;i+=dx)
 		{
-			for(j=0;j<m;j++)
+#pragma omp parallel for private(p1,p2,xx,yy,q,s)
+			for(long j=0;j<m;j++)
 			{
-				if(gr->Stop)	{	delete []pos;	return;	}
+				if(gr->Stop)	continue;
 				xx = GetX(x,i,j,k);		yy = GetY(y,i,j,k);
 				p1 = mglPoint(xx.x, yy.x, z->v(i,j,k));
 				s = mglPoint(xx.z, yy.z, z->dvy(i,j,k));
 				q = mglPoint(xx.y, yy.y, 0);	s = q^s;
-				c = gr->GetC(ss,p1.z);
+				register mreal c = gr->GetC(ss,p1.z);
 				p2 = mglPoint(GetX(x,i+dx,j,k).x,GetY(y,i+dx,j,k).x,p1.z);
 				pos[2*j] = gr->AddPnt(p1,c,s);
 				pos[2*j+1]=gr->AddPnt(p2,c,s);
 			}
 			mgl_surf_plot(gr,pos,2,m);
 		}
-		else	for(j=0;j<m-dy;j+=dy)
+		else	for(long j=0;j<m-dy;j+=dy)
 		{
-			for(i=0;i<n;i++)	// ñîçäàåì ìàññèâ òî÷åê
+#pragma omp parallel for private(p1,p2,xx,yy,q,s)
+			for(long i=0;i<n;i++)	// ñîçäàåì ìàññèâ òî÷åê
 			{
-				if(gr->Stop)	{	delete []pos;	return;	}
+				if(gr->Stop)	continue;
 				xx = GetX(x,i,j,k);		yy = GetY(y,i,j,k);
 				p1 = mglPoint(xx.x, yy.x, z->v(i,j,k));
 				q = mglPoint(xx.y, yy.y, z->dvx(i,j,k));
 				s = mglPoint(xx.z, yy.z, 0);	s = q^s;
-				c = gr->GetC(ss,p1.z);
+				register mreal c = gr->GetC(ss,p1.z);
 				p2 = mglPoint(GetX(x,i,j+dy,k).x,GetY(y,i,j+dy,k).x,p1.z);
 				pos[2*i] = gr->AddPnt(p1,c,s);
 				pos[2*i+1]=gr->AddPnt(p2,c,s);
@@ -422,7 +428,7 @@ void MGL_EXPORT mgl_belt_(uintptr_t *gr, uintptr_t *a, const char *sch, const ch
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_dens_xy(HMGL gr, HCDT x, HCDT y, HCDT z, const char *sch, const char *opt)
 {
-	register long i,j,k,n=z->GetNx(),m=z->GetNy();
+	long n=z->GetNx(),m=z->GetNy();
 	if(mgl_check_dim2(gr,x,y,z,0,"Dens"))	return;
 
 	gr->SaveState(opt);
@@ -435,25 +441,28 @@ void MGL_EXPORT mgl_dens_xy(HMGL gr, HCDT x, HCDT y, HCDT z, const char *sch, co
 
 	mglPoint p,s=mglPoint(0,0,1);
 	mreal zz, c;
-	for(k=0;k<z->GetNz();k++)
+	for(long k=0;k<z->GetNz();k++)
 	{
 		if(z->GetNz()>1)
 			zVal = gr->Min.z+(gr->Max.z-gr->Min.z)*mreal(k)/(z->GetNz()-1);
-		for(j=0;j<m;j++)	for(i=0;i<n;i++)	// ñîçäàåì ìàññèâ òî÷åê
+#pragma omp parallel for private(p,c,zz) collapse(2)
+		for(long j=0;j<m;j++)	for(long i=0;i<n;i++)	// ñîçäàåì ìàññèâ òî÷åê
 		{
-			if(gr->Stop)	{	delete []pos;	return;	}
+			if(gr->Stop)	continue;
 			p = mglPoint(GetX(x,i,j,k).x, GetY(y,i,j,k).x, zVal);
 			zz = z->v(i,j,k);	c = gr->GetC(ss,zz);
 			if(mgl_isnan(zz))	p.x = NAN;
 			pos[i+n*j] = gr->AddPnt(p,c,s);
 		}
-		if(sch && mglchr(sch,'.'))	for(i=0;i<n*m;i++)	gr->mark_plot(pos[i],'.');
+		if(sch && mglchr(sch,'.'))
+#pragma omp parallel for
+			for(long i=0;i<n*m;i++)	gr->mark_plot(pos[i],'.');
 		else	mgl_surf_plot(gr,pos,n,m);
-		if(mglchr(sch,'#'))
+		if(mglchr(sch,'#') && !gr->Stop)
 		{
 			gr->Reserve(n*m);	gr->SetPenPal("k-");
-			for(i=0;i<n*m;i++)
-				pos[i] = gr->CopyNtoC(pos[i],gr->CDef);
+#pragma omp parallel for
+			for(long i=0;i<n*m;i++)	pos[i] = gr->CopyNtoC(pos[i],gr->CDef);
 			mgl_mesh_plot(gr,pos,n,m,3);
 		}
 	}
@@ -506,7 +515,7 @@ void MGL_EXPORT mgl_stfa_(uintptr_t *gr, uintptr_t *re, uintptr_t *im, int *dn,
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_surfc_xy(HMGL gr, HCDT x, HCDT y, HCDT z, HCDT c, const char *sch, const char *opt)
 {
-	register long i,j,k,n=z->GetNx(),m=z->GetNy();
+	long n=z->GetNx(),m=z->GetNy();
 	if(mgl_check_dim2(gr,x,y,z,c,"SurfC"))	return;
 
 	gr->SaveState(opt);
@@ -514,27 +523,29 @@ void MGL_EXPORT mgl_surfc_xy(HMGL gr, HCDT x, HCDT y, HCDT z, HCDT c, const char
 	long ss = gr->AddTexture(sch);
 	long *pos = new long[n*m];
 	gr->Reserve(n*m*z->GetNz());
-	mreal col;
 
 	mglPoint p,q,s,xx,yy;
-	for(k=0;k<z->GetNz();k++)
+	for(long k=0;k<z->GetNz();k++)
 	{
-		for(j=0;j<m;j++)	for(i=0;i<n;i++)
+#pragma omp parallel for private(p,xx,yy,q,s) collapse(2)
+		for(long j=0;j<m;j++)	for(long i=0;i<n;i++)
 		{
-			if(gr->Stop)	{	delete []pos;	return;	}
+			if(gr->Stop)	continue;
 			xx = GetX(x,i,j,k);		yy = GetY(y,i,j,k);
 			p = mglPoint(xx.x, yy.x, z->v(i,j,k));
 			q = mglPoint(xx.y, yy.y, z->dvx(i,j,k));
 			s = mglPoint(xx.z, yy.z, z->dvy(i,j,k));
-			col = gr->GetC(ss,c->v(i,j,k));
-			pos[i+n*j] = gr->AddPnt(p,col,q^s);
+			pos[i+n*j] = gr->AddPnt(p,gr->GetC(ss,c->v(i,j,k)),q^s);
 		}
-		if(sch && mglchr(sch,'.'))	for(i=0;i<n*m;i++)	gr->mark_plot(pos[i],'.');
+		if(sch && mglchr(sch,'.'))
+#pragma omp parallel for
+			for(long i=0;i<n*m;i++)	gr->mark_plot(pos[i],'.');
 		else	mgl_surf_plot(gr,pos,n,m);
-		if(mglchr(sch,'#'))
+		if(mglchr(sch,'#') && !gr->Stop)
 		{
 			gr->Reserve(n*m);	gr->SetPenPal("k-");
-			for(i=0;i<n*m;i++)	pos[i] = gr->CopyNtoC(pos[i],gr->CDef);
+#pragma omp parallel for
+			for(long i=0;i<n*m;i++)	pos[i] = gr->CopyNtoC(pos[i],gr->CDef);
 			mgl_mesh_plot(gr,pos,n,m,3);
 		}
 	}
@@ -567,7 +578,6 @@ void MGL_EXPORT mgl_surfc_(uintptr_t *gr, uintptr_t *z, uintptr_t *a, const char
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_surfa_xy(HMGL gr, HCDT x, HCDT y, HCDT z, HCDT c, const char *sch, const char *opt)
 {
-	register long i,j;
 	long k,n=z->GetNx(),m=z->GetNy();
 	if(mgl_check_dim2(gr,x,y,z,c,"SurfA"))	return;
 
@@ -580,21 +590,25 @@ void MGL_EXPORT mgl_surfa_xy(HMGL gr, HCDT x, HCDT y, HCDT z, HCDT c, const char
 	mglPoint p,q,s,xx,yy;
 	for(k=0;k<z->GetNz();k++)
 	{
-		for(j=0;j<m;j++)	for(i=0;i<n;i++)
+#pragma omp parallel for private(p,xx,yy,q,s) collapse(2)
+		for(long j=0;j<m;j++)	for(long i=0;i<n;i++)
 		{
-			if(gr->Stop)	{	delete []pos;	return;	}
+			if(gr->Stop)	continue;
 			xx = GetX(x,i,j,k);		yy = GetY(y,i,j,k);
 			mreal vv = z->v(i,j,k);	p = mglPoint(xx.x, yy.x, vv);
 			q = mglPoint(xx.y, yy.y, z->dvx(i,j,k));
 			s = mglPoint(xx.z, yy.z, z->dvy(i,j,k));
 			pos[i+n*j] = gr->AddPnt(p,gr->GetC(ss,vv),q^s,gr->GetA(c->v(i,j,k)));
 		}
-		if(sch && mglchr(sch,'.'))	for(i=0;i<n*m;i++)	gr->mark_plot(pos[i],'.');
+		if(sch && mglchr(sch,'.'))
+#pragma omp parallel for
+			for(long i=0;i<n*m;i++)	gr->mark_plot(pos[i],'.');
 		else	mgl_surf_plot(gr,pos,n,m);
 		if(mglchr(sch,'#'))
 		{
 			gr->Reserve(n*m);	gr->SetPenPal("k-");
-			for(i=0;i<n*m;i++)	pos[i] = gr->CopyNtoC(pos[i],gr->CDef);
+#pragma omp parallel for
+			for(long i=0;i<n*m;i++)	pos[i] = gr->CopyNtoC(pos[i],gr->CDef);
 			mgl_mesh_plot(gr,pos,n,m,3);
 		}
 	}
@@ -647,7 +661,7 @@ void MGL_EXPORT mgl_boxs_xy(HMGL gr, HCDT x, HCDT y, HCDT z, const char *sch, co
 	{
 		for(i=0;i<n;i+=dx)	for(j=0;j<m;j+=dy)
 		{
-			if(gr->Stop)	return;
+			if(gr->Stop)	continue;
 			zz = z->v(i,j,k);		c  = gr->GetC(ss,zz);
 			xx = GetX(x,i,j,k);		yy = GetY(y,i,j,k);
 			x1 = i<lx-dx ? GetX(x,i+dx,j,k).x:NAN;
@@ -735,7 +749,7 @@ void MGL_EXPORT mgl_boxs_(uintptr_t *gr, uintptr_t *a, const char *sch, const ch
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_tile_xy(HMGL gr, HCDT x, HCDT y, HCDT z, const char *sch, const char *opt)
 {
-	register long i,j,k,n=z->GetNx(),m=z->GetNy();
+	long n=z->GetNx(),m=z->GetNy();
 	if(mgl_check_dim2(gr,x,y,z,0,"Tile",true))	return;
 
 	gr->SaveState(opt);
@@ -746,26 +760,25 @@ void MGL_EXPORT mgl_tile_xy(HMGL gr, HCDT x, HCDT y, HCDT z, const char *sch, co
 	long ss = gr->AddTexture(sch);
 	gr->Reserve(4*n*m*z->GetNz());
 
-	mglPoint p1,p2,p3,p4,s=mglPoint(0,0,1);
-	mreal zz,x0,y0,x1,y1,x2,y2,x3,y3,c;
-	long k1,k2,k3,k4;
-	for(k=0;k<z->GetNz();k++)
+	mglPoint s=mglPoint(0,0,1);
+	for(long k=0;k<z->GetNz();k++)
 	{
-		for(j=0;j<m;j+=dx)	for(i=0;i<n;i+=dy)
+#pragma omp parallel for collapse(2)
+		for(long j=0;j<m;j+=dx)	for(long i=0;i<n;i+=dy)
 		{
-			if(gr->Stop)	return;
-			zz = z->v(i,j,k);		c = gr->GetC(ss,zz);
-			x0 = GetX(x,i,j,k).x;	y0 = GetY(y,i,j,k).x;
-			x1 = i<lx-dx ? GetX(x,i+dx,j,k).x:NAN;
-			y1 = i<lx-dx ? GetY(y,i+dx,j,k).x:NAN;
-			x2 = j<ly-dy ? GetX(x,i,j+dy,k).x:NAN;
-			y2 = j<ly-dy ? GetY(y,i,j+dy,k).x:NAN;
-			x3 = i<lx-dx && j<ly-dy ? GetX(x,i+dx,j+dy,k).x:NAN;
-			y3 = i<lx-dx && j<ly-dy ? GetY(y,i+dx,j+dy,k).x:NAN;
-			p1 = mglPoint(x0,y0,zz);	k1 = gr->AddPnt(p1,c,s);
-			p2 = mglPoint(x1,y1,zz);	k2 = gr->AddPnt(p2,c,s);
-			p3 = mglPoint(x2,y2,zz);	k3 = gr->AddPnt(p3,c,s);
-			p4 = mglPoint(x3,y3,zz);	k4 = gr->AddPnt(p4,c,s);
+			if(gr->Stop)	continue;
+			register mreal zz = z->v(i,j,k), c = gr->GetC(ss,zz);
+			register mreal xx = GetX(x,i,j,k).x, yy = GetY(y,i,j,k).x;
+			register long k1 = gr->AddPnt(mglPoint(xx,yy,zz),c,s);
+			xx = i<lx-dx ? GetX(x,i+dx,j,k).x:NAN;
+			yy = i<lx-dx ? GetY(y,i+dx,j,k).x:NAN;
+			register long k2 = gr->AddPnt(mglPoint(xx,yy,zz),c,s);
+			xx = j<ly-dy ? GetX(x,i,j+dy,k).x:NAN;
+			yy = j<ly-dy ? GetY(y,i,j+dy,k).x:NAN;
+			register long k3 = gr->AddPnt(mglPoint(xx,yy,zz),c,s);
+			xx = i<lx-dx && j<ly-dy ? GetX(x,i+dx,j+dy,k).x:NAN;
+			yy = i<lx-dx && j<ly-dy ? GetY(y,i+dx,j+dy,k).x:NAN;
+			register long k4 = gr->AddPnt(mglPoint(xx,yy,zz),c,s);
 			gr->quad_plot(k1,k2,k3,k4);
 		}
 	}
@@ -798,7 +811,7 @@ void MGL_EXPORT mgl_tile_(uintptr_t *gr, uintptr_t *a, const char *sch, const ch
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_tiles_xy(HMGL gr, HCDT x, HCDT y, HCDT z, HCDT s, const char *sch, const char *opt)
 {
-	register long i,j,k,n=z->GetNx(),m=z->GetNy();
+	long n=z->GetNx(),m=z->GetNy();
 	if(mgl_check_dim2(gr,x,y,z,s,"TileS",true))	return;
 
 	gr->SaveState(opt);
@@ -809,16 +822,16 @@ void MGL_EXPORT mgl_tiles_xy(HMGL gr, HCDT x, HCDT y, HCDT z, HCDT s, const char
 	long cc = gr->AddTexture(sch);
 	gr->Reserve(4*n*m*z->GetNz());
 
-	mglPoint p1,p2,p3,p4,t=mglPoint(0,0,1);
-	mreal zz,x1,x2,x3,x4,y1,y2,y3,y4,ss,sm,c;
-	long k1,k2,k3,k4;
-	for(k=0;k<z->GetNz();k++)
+	mglPoint t=mglPoint(0,0,1);
+	mreal x1,x2,x3,x4,y1,y2,y3,y4;
+	for(long k=0;k<z->GetNz();k++)
 	{
-		for(j=0;j<m;j+=dx)	for(i=0;i<n;i+=dy)
+#pragma omp parallel for private(x1,x2,x3,x4,y1,y2,y3,y4) collapse(2)
+		for(long j=0;j<m;j+=dx)	for(long i=0;i<n;i+=dy)
 		{
-			if(gr->Stop)	return;
-			zz = z->v(i,j,k);	c = gr->GetC(cc,zz);
-			ss = (1-gr->GetA(s->v(i,j,k)))/2;	sm = 1-ss;
+			if(gr->Stop)	continue;
+			register mreal zz = z->v(i,j,k), c = gr->GetC(cc,zz);
+			register mreal ss = (1-gr->GetA(s->v(i,j,k)))/2, sm = 1-ss;
 
 			x1 = GetX(x,i,j,k).x;	y1 = GetY(y,i,j,k).x;
 			x2 = x3 = x4 = y2 = y3 = y4 = NAN;
@@ -830,14 +843,10 @@ void MGL_EXPORT mgl_tiles_xy(HMGL gr, HCDT x, HCDT y, HCDT z, HCDT s, const char
 			{	x3 = GetX(x,i+dx,j+dy,k).x-x2-x4-x1;
 				y3 = GetY(y,i+dx,j+dy,k).x-y2-y4-y1;	}
 
-			p1 = mglPoint(x1+x2*ss+x4*ss+x3*ss*ss, y1+y2*ss+y4*ss+y3*ss*ss, zz);
-			k1 = gr->AddPnt(p1,c,t);
-			p2 = mglPoint(x1+x2*sm+x4*ss+x3*ss*sm, y1+y2*sm+y4*ss+y3*ss*sm, zz);
-			k2 = gr->AddPnt(p2,c,t);
-			p3 = mglPoint(x1+x2*ss+x4*sm+x3*ss*sm, y1+y2*ss+y4*sm+y3*ss*sm, zz);
-			k3 = gr->AddPnt(p3,c,t);
-			p4 = mglPoint(x1+x2*sm+x4*sm+x3*sm*sm, y1+y2*sm+y4*sm+y3*sm*sm, zz);
-			k4 = gr->AddPnt(p4,c,t);
+			register long k1 = gr->AddPnt(mglPoint(x1+x2*ss+x4*ss+x3*ss*ss, y1+y2*ss+y4*ss+y3*ss*ss, zz),c,t);
+			register long k2 = gr->AddPnt(mglPoint(x1+x2*sm+x4*ss+x3*ss*sm, y1+y2*sm+y4*ss+y3*ss*sm, zz),c,t);
+			register long k3 = gr->AddPnt(mglPoint(x1+x2*ss+x4*sm+x3*ss*sm, y1+y2*ss+y4*sm+y3*ss*sm, zz),c,t);
+			register long k4 = gr->AddPnt(mglPoint(x1+x2*sm+x4*sm+x3*sm*sm, y1+y2*sm+y4*sm+y3*sm*sm, zz),c,t);
 			gr->quad_plot(k1,k2,k3,k4);
 		}
 	}
@@ -870,7 +879,7 @@ void MGL_EXPORT mgl_tiles_(uintptr_t *gr, uintptr_t *a, uintptr_t *r, const char
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_map_xy(HMGL gr, HCDT x, HCDT y, HCDT ax, HCDT ay, const char *sch, const char *opt)
 {
-	register long i,j,n=ax->GetNx(),m=ax->GetNy();
+	long n=ax->GetNx(),m=ax->GetNy();
 	if(mgl_check_dim2(gr,x,y,ax,ay,"Map"))	return;
 
 	bool both = x->GetNx()==n && y->GetNx()==n && x->GetNy()==m && y->GetNy()==m;
@@ -878,25 +887,25 @@ void MGL_EXPORT mgl_map_xy(HMGL gr, HCDT x, HCDT y, HCDT ax, HCDT ay, const char
 	static int cgid=1;	gr->StartGroup("Map",cgid++);
 
 	long ss = gr->AddTexture(mgl_have_color(sch)?sch:"rgb",2);
-	long s = both ? n:1, s1, s2;
+	long s = both ? n:1;
 
-	mreal xdy,xdx,ydx,ydy,xx,yy;
-	mglPoint p,t=mglPoint(NAN);
+	mglPoint t=mglPoint(NAN);
 	long *pos = new long[n*m];
 	gr->Reserve(n*m);
 
-	for(j=0;j<m;j++)	for(i=0;i<n;i++)
+#pragma omp parallel for collapse(2)
+	for(long j=0;j<m;j++)	for(long i=0;i<n;i++)
 	{
-		if(gr->Stop)	{	delete []pos;	return;	}
-		s1 = i>0 ? 1:0;		s2 = i<n-1 ? 1:0;
-		xdx = (ax->v(i+s2,j)-ax->v(i-s1,j))/(GetX(x,i+s2,j).x-GetX(x,i-s1,j).x);
-		ydx = (ay->v(i+s2,j)-ay->v(i-s1,j))/(GetX(x,i+s2,j).x-GetX(x,i-s1,j).x);
+		if(gr->Stop)	continue;
+		register long s1 = i>0 ? 1:0, s2 = i<n-1 ? 1:0;
+		register mreal xdx = (ax->v(i+s2,j)-ax->v(i-s1,j))/(GetX(x,i+s2,j).x-GetX(x,i-s1,j).x);
+		register mreal ydx = (ay->v(i+s2,j)-ay->v(i-s1,j))/(GetX(x,i+s2,j).x-GetX(x,i-s1,j).x);
 		s1 = j>0 ? s:0;		s2 = j<m-1 ? s:0;
-		xdy = (ax->v(i,j+s2)-ax->v(i,j-s1))/(GetY(y,i,j+s2).x-GetY(y,i,j-s1).x);
-		ydy = (ay->v(i,j+s2)-ay->v(i,j-s1))/(GetY(y,i,j+s2).x-GetY(y,i,j-s1).x);
+		register mreal xdy = (ax->v(i,j+s2)-ax->v(i,j-s1))/(GetY(y,i,j+s2).x-GetY(y,i,j-s1).x);
+		register mreal ydy = (ay->v(i,j+s2)-ay->v(i,j-s1))/(GetY(y,i,j+s2).x-GetY(y,i,j-s1).x);
 		xdx = xdx*ydy - xdy*ydx;	// Jacobian
+		register mreal xx,yy;
 
-		p = mglPoint(ax->v(i,j), ay->v(i,j), xdx);
 		if(both)
 		{
 			xx = (x->v(i,j) - gr->Min.x)/(gr->Max.x - gr->Min.x);
@@ -909,9 +918,11 @@ void MGL_EXPORT mgl_map_xy(HMGL gr, HCDT x, HCDT y, HCDT ax, HCDT ay, const char
 		}
 		if(xx<0)	xx=0;	if(xx>=1)	xx=1/MGL_FEPSILON;
 		if(yy<0)	yy=0;	if(yy>=1)	yy=1/MGL_FEPSILON;
-		pos[i+n*j] = gr->AddPnt(p,gr->GetC(ss,xx,false),t,yy);
+		pos[i+n*j] = gr->AddPnt(mglPoint(ax->v(i,j), ay->v(i,j), xdx),gr->GetC(ss,xx,false),t,yy);
 	}
-	if(sch && mglchr(sch,'.'))	for(i=0;i<n*m;i++)	gr->mark_plot(pos[i],'.');
+	if(sch && mglchr(sch,'.'))
+#pragma omp parallel for
+		for(long i=0;i<n*m;i++)	gr->mark_plot(pos[i],'.');
 	else	mgl_surf_plot(gr,pos,n,m);
 	delete []pos;	gr->EndGroup();
 }
diff --git a/src/vect.cpp b/src/vect.cpp
index 3dae76d..878444a 100644
--- a/src/vect.cpp
+++ b/src/vect.cpp
@@ -20,6 +20,7 @@
 #include "mgl2/vect.h"
 #include "mgl2/eval.h"
 #include "mgl2/data.h"
+#include "mgl2/base.h"
 //-----------------------------------------------------------------------------
 //
 //	Traj series
@@ -40,7 +41,6 @@ void MGL_EXPORT mgl_traj_xyz(HMGL gr, HCDT x, HCDT y, HCDT z, HCDT ax, HCDT ay,
 	m = x->GetNy()>y->GetNy() ? x->GetNy():y->GetNy();		if(i>m)	m=i;	if(j>m)	m=j;
 	gr->SetPenPal(sch,&pal);	gr->Reserve(4*n*m);
 
-	mreal dx,dy,dz,dd,da;
 	mglPoint p1,p2;
 /*	for(j=0;j<m;j++)	for(i=0;i<n;i++)	// find maximal amplitude of vector field
 	{
@@ -52,26 +52,26 @@ void MGL_EXPORT mgl_traj_xyz(HMGL gr, HCDT x, HCDT y, HCDT z, HCDT ax, HCDT ay,
 	for(j=0;j<m;j++) // start prepare arrows
 	{
 		gr->NextColor(pal);
-		for(i=0;i<n;i++)
+		nx = j<x->GetNy() ? j:0;	ny = j<y->GetNy() ? j:0;	nz = j<z->GetNy() ? j:0;
+		mx = j<ax->GetNy() ? j:0;	my = j<ay->GetNy() ? j:0;	mz = j<az->GetNy() ? j:0;
+#pragma omp parallel for private(p1,p2)
+		for(long i=0;i<n;i++)
 		{
-			if(gr->Stop)	return;
-			nx = j<x->GetNy() ? j:0;	ny = j<y->GetNy() ? j:0;	nz = j<z->GetNy() ? j:0;
-			mx = j<ax->GetNy() ? j:0;	my = j<ay->GetNy() ? j:0;	mz = j<az->GetNy() ? j:0;
+			if(gr->Stop)	continue;
 			p1 = mglPoint(x->v(i,nx), y->v(i,ny), z->v(i,nz));
 			p2 = mglPoint(ax->v(i,mx),ay->v(i,my),az->v(i,mz));
-			da = p2.norm();
+			mreal dd = p2.norm();
 			if(len==0)
 			{
+				register mreal dx,dy,dz;
 				if(i<n-1)
 				{	dx=x->v(i+1,nx)-p1.x;	dy=y->v(i+1,ny)-p1.y;	dz=z->v(i+1,nz)-p1.z;	}
 				else
 				{	dx=p1.x-x->v(i-1,nx);	dy=p1.y-y->v(i-1,ny);	dz=p1.z-z->v(i-1,nz);	}
-				dd = da ? 1/da : 0;		dd *= sqrt(dx*dx+dy*dy+dz*dz);
+				dd = dd ? sqrt(dx*dx+dy*dy+dz*dz)/dd : 0;
 			}
 			else dd = len;
-
-			nx = gr->AddPnt(p1);	ny = gr->AddPnt(p1+dd*p2,-1,mglPoint(NAN),-1,2);
-			gr->vect_plot(nx,ny);
+			gr->vect_plot(gr->AddPnt(p1), gr->AddPnt(p1+dd*p2,-1,mglPoint(NAN),-1,2));
 		}
 	}
 	gr->EndGroup();
@@ -102,7 +102,7 @@ void MGL_EXPORT mgl_traj_xyz_(uintptr_t *gr, uintptr_t *x, uintptr_t *y, uintptr
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_vect_xy(HMGL gr, HCDT x, HCDT y, HCDT ax, HCDT ay, const char *sch, const char *opt)
 {
-	long i,j,n=ax->GetNx(),m=ax->GetNy(),l=ax->GetNz(),k;
+	long n=ax->GetNx(),m=ax->GetNy(),l=ax->GetNz();
 	if(mgl_check_dim2(gr,x,y,ax,ay,"Vect"))	return;
 
 	gr->SaveState(opt);
@@ -122,44 +122,49 @@ void MGL_EXPORT mgl_vect_xy(HMGL gr, HCDT x, HCDT y, HCDT ax, HCDT ay, const cha
 	if(tx<1)	tx=1;	if(ty<1)	ty=1;
 
 	mreal xm=0,cm=0,ca=0;
-	mreal dd,dm=(fabs(gr->Max.c)+fabs(gr->Min.c))*1e-5;
+	mreal dm=(fabs(gr->Max.c)+fabs(gr->Min.c))*1e-5;
 	// use whole array for determining maximal vectors length
-	mglPoint p1,p2, v, d;
-	mreal c1,c2,xx;
-	
-	for(k=0;k<l;k++)	for(i=0;i<n;i+=tx)	for(j=0;j<m;j+=ty)
+	mglPoint p1,p2,v,d;
+
+#pragma omp parallel private(p1,p2,v,d)
 	{
-		d = mglPoint(GetX(x,i,j,k).x, GetY(y,i,j,k).x);
-		v = mglPoint(ax->v(i,j,k),ay->v(i,j,k));
-		c1 = v.norm();	xm = xm<c1 ? c1:xm;	// handle NAN values
-		p1 = i<n-1 ? mglPoint(GetX(x,i+tx,j,k).x, GetY(y,i+tx,j,k).x)-d : d-mglPoint(GetX(x,i-tx,j,k).x, GetY(y,i-tx,j,k).x);
-		c1 = fabs(v*p1);	xx = p1.norm();	c1 *= xx?1/(xx*xx):0;
-		p1 = j<m-1 ? mglPoint(GetX(x,i,j+ty,k).x, GetY(y,i,j+ty,k).x)-d : d-mglPoint(GetX(x,i,j-ty,k).x, GetY(y,i,j-ty,k).x);
-		c2 = fabs(v*p1);	xx = p1.norm();	c2 *= xx?1/(xx*xx):0;
-		c1 = c1<c2 ? c2:c1;	ca+=c1;	cm = cm<c1 ? c1:cm;
+		mreal xm1=0,cm1=0,xx,c1,c2;
+#pragma omp for nowait collapse(3) reduction(+:ca)
+		for(long k=0;k<l;k++)	for(long j=0;j<m;j+=ty)	for(long i=0;i<n;i+=tx)
+		{
+			d = mglPoint(GetX(x,i,j,k).x, GetY(y,i,j,k).x);
+			v = mglPoint(ax->v(i,j,k),ay->v(i,j,k));
+			c1 = v.norm();	xm1 = xm1<c1 ? c1:xm1;	// handle NAN values
+			p1 = i<n-1 ? mglPoint(GetX(x,i+tx,j,k).x, GetY(y,i+tx,j,k).x)-d : d-mglPoint(GetX(x,i-tx,j,k).x, GetY(y,i-tx,j,k).x);
+			c1 = fabs(v*p1);	xx = p1.norm();	c1 *= xx?1/(xx*xx):0;
+			p1 = j<m-1 ? mglPoint(GetX(x,i,j+ty,k).x, GetY(y,i,j+ty,k).x)-d : d-mglPoint(GetX(x,i,j-ty,k).x, GetY(y,i,j-ty,k).x);
+			c2 = fabs(v*p1);	xx = p1.norm();	c2 *= xx?1/(xx*xx):0;
+			c1 = c1<c2 ? c2:c1;	ca+=c1;	cm1 = cm1<c1 ? c1:cm1;
+		}
+#pragma omp critical(max_vec)
+		{cm = cm<cm1 ? cm1:cm;	xm = xm<xm1 ? xm1:xm;}
 	}
 	ca /= (n*m*l)/(tx*ty);
-//	if(cm>2*ca)	cm = 2*ca;	// disable too narrow grid steps TODO: decide later
 	xm = xm?1./xm:0;	cm = cm?1./cm:0;
 
-
-	long n1,n2;
-	for(k=0;k<l;k++)
+	for(long k=0;k<l;k++)
 	{
 		if(ax->GetNz()>1)	zVal = gr->Min.z+(gr->Max.z-gr->Min.z)*mreal(k)/(ax->GetNz()-1);
-		for(i=0;i<n;i+=tx)	for(j=0;j<m;j+=ty)
+#pragma omp parallel for private(d,v,p1,p2) collapse(2)
+		for(long j=0;j<m;j+=ty)	for(long i=0;i<n;i+=tx)
 		{
-			if(gr->Stop)	return;
+			if(gr->Stop)	continue;
 			d = mglPoint(GetX(x,i,j,k).x, GetY(y,i,j,k).x, zVal);
 			v = mglPoint(ax->v(i,j,k),ay->v(i,j,k));
-			dd = v.norm();	v *= cm*(fix?(dd>dm ? 1./dd : 0) : xm);
-			
+			mreal dd = v.norm(), c1, c2;
+			v *= cm*(fix?(dd>dm ? 1./dd : 0) : xm);
+
 			if(end)		{	p1 = d-v;	p2 = d;	}
 			else if(beg)	{	p1 = d;	p2 = d+v;	}
 			else		{	p1=d-v/2.;	p2=d+v/2.;	}
 			if(grd)	{	c1=gr->GetC(ss,dd*xm-0.5,false);	c2=gr->GetC(ss,dd*xm,false);}
 			else	c1 = c2 = gr->GetC(ss,dd*xm,false);
-			n1=gr->AddPnt(p1,c1);	n2=gr->AddPnt(p2,c2);
+			long n1=gr->AddPnt(p1,c1),	n2=gr->AddPnt(p2,c2);
 			// allow vectors outside bounding box
 			if(n1<0 && n2>=0)	n1=gr->AddPnt(p1,c1,mglPoint(NAN),-1,2);
 			if(n2<0 && n1>=0)	n2=gr->AddPnt(p2,c2,mglPoint(NAN),-1,2);
@@ -197,7 +202,7 @@ void MGL_EXPORT mgl_vect_2d_(uintptr_t *gr, uintptr_t *ax, uintptr_t *ay, const
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_vect_xyz(HMGL gr, HCDT x, HCDT y, HCDT z, HCDT ax, HCDT ay, HCDT az, const char *sch, const char *opt)
 {
-	register long i,j,n=ax->GetNx(),m=ax->GetNy(),l=ax->GetNz(),k;
+	register long n=ax->GetNx(),m=ax->GetNy(),l=ax->GetNz();
 	if(mgl_check_vec3(gr,x,y,z,ax,ay,az,"Vect_3d"))	return;
 
 	gr->SaveState(opt);
@@ -216,43 +221,49 @@ void MGL_EXPORT mgl_vect_xyz(HMGL gr, HCDT x, HCDT y, HCDT z, HCDT ax, HCDT ay,
 	if(tx<1)	tx=1;	if(ty<1)	ty=1;	if(tz<1)	tz=1;
 
 	mreal xm=0,cm=0,ca=0;
-	mreal dd,dm=(fabs(gr->Max.c)+fabs(gr->Min.c))*1e-5;
+	mreal dm=(fabs(gr->Max.c)+fabs(gr->Min.c))*1e-5;
 	// use whole array for determining maximal vectors length
-	mglPoint p1,p2,p3, v, d;
-	mreal c1,c2,c3,xx;
-	
-	for(k=0;k<l;k+=tz)	for(i=0;i<n;i+=tx)	for(j=0;j<m;j+=ty)
+	mglPoint p1,p2, v, d;
+
+#pragma omp parallel private(p1,p2,v,d)
 	{
-		d = mglPoint(GetX(x,i,j,k).x, GetY(y,i,j,k).x, GetZ(z,i,j,k).x);
-		v = mglPoint(ax->v(i,j,k),ay->v(i,j,k),az->v(i,j,k));
-		c1 = v.norm();	xm = xm<c1 ? c1:xm;	// handle NAN values
-		p1 = i<n-1 ? mglPoint(GetX(x,i+tx,j,k).x, GetY(y,i+tx,j,k).x, GetZ(z,i+tx,j,k).x)-d : d-mglPoint(GetX(x,i-tx,j,k).x, GetY(y,i-tx,j,k).x, GetZ(z,i-tx,j,k).x);
-		c1 = fabs(v*p1);	xx = p1.norm();	c1 *= xx?1/(xx*xx):0;
-		p1 = j<m-1 ? mglPoint(GetX(x,i,j+ty,k).x, GetY(y,i,j+ty,k).x, GetZ(z,i,j+ty,k).x)-d : d-mglPoint(GetX(x,i,j-ty,k).x, GetY(y,i,j-ty,k).x, GetZ(z,i,j-ty,k).x);
-		c2 = fabs(v*p1);	xx = p1.norm();	c2 *= xx?1/(xx*xx):0;
-		p1 = k<l-1 ? mglPoint(GetX(x,i,j,k+tz).x, GetY(y,i,j,k+tz).x, GetZ(z,i,j,k+tz).x)-d : d-mglPoint(GetX(x,i,j,k-tz).x, GetY(y,i,j,k-tz).x, GetZ(z,i,j,k-tz).x);
-		c3 = fabs(v*p1);	xx = p1.norm();	c3 *= xx?1/(xx*xx):0;
-		c1 = c1<c2 ? c2:c1;	c1 = c1<c3 ? c3:c1;
-		ca+=c1;	cm = cm<c1 ? c1:cm;
+		mreal c1,c2,c3, xm1=0,cm1=0,xx;
+#pragma omp for nowait collapse(3) reduction(+:ca)
+		for(long k=0;k<l;k+=tz)	for(long i=0;i<n;i+=tx)	for(long j=0;j<m;j+=ty)
+		{
+			d = mglPoint(GetX(x,i,j,k).x, GetY(y,i,j,k).x, GetZ(z,i,j,k).x);
+			v = mglPoint(ax->v(i,j,k),ay->v(i,j,k),az->v(i,j,k));
+			c1 = v.norm();	xm1 = xm1<c1 ? c1:xm1;	// handle NAN values
+			p1 = i<n-1 ? mglPoint(GetX(x,i+tx,j,k).x, GetY(y,i+tx,j,k).x, GetZ(z,i+tx,j,k).x)-d : d-mglPoint(GetX(x,i-tx,j,k).x, GetY(y,i-tx,j,k).x, GetZ(z,i-tx,j,k).x);
+			c1 = fabs(v*p1);	xx = p1.norm();	c1 *= xx?1/(xx*xx):0;
+			p1 = j<m-1 ? mglPoint(GetX(x,i,j+ty,k).x, GetY(y,i,j+ty,k).x, GetZ(z,i,j+ty,k).x)-d : d-mglPoint(GetX(x,i,j-ty,k).x, GetY(y,i,j-ty,k).x, GetZ(z,i,j-ty,k).x);
+			c2 = fabs(v*p1);	xx = p1.norm();	c2 *= xx?1/(xx*xx):0;
+			p1 = k<l-1 ? mglPoint(GetX(x,i,j,k+tz).x, GetY(y,i,j,k+tz).x, GetZ(z,i,j,k+tz).x)-d : d-mglPoint(GetX(x,i,j,k-tz).x, GetY(y,i,j,k-tz).x, GetZ(z,i,j,k-tz).x);
+			c3 = fabs(v*p1);	xx = p1.norm();	c3 *= xx?1/(xx*xx):0;
+			c1 = c1<c2 ? c2:c1;	c1 = c1<c3 ? c3:c1;
+			ca+=c1;	cm1 = cm1<c1 ? c1:cm1;
+		}
+#pragma omp critical(max_vec)
+		{cm = cm<cm1 ? cm1:cm;	xm = xm<xm1 ? xm1:xm;}
 	}
 	ca /= (n*m*l)/(tx*ty*tz);
-//	if(cm>2*ca)	cm = 2*ca;	// disable too narrow grid steps. TODO: decide later
 	xm = xm?1./xm:0;	cm = cm?1./cm:0;
 
-	long n1,n2;
-	for(k=0;k<l;k+=tz)	for(i=0;i<n;i+=tx)	for(j=0;j<m;j+=ty)
+#pragma omp parallel for private(d,v,p1,p2) collapse(3)
+	for(long k=0;k<l;k+=tz)	for(long i=0;i<n;i+=tx)	for(long j=0;j<m;j+=ty)
 	{
-		if(gr->Stop)	return;
+		if(gr->Stop)	continue;
 		d=mglPoint(GetX(x,i,j,k).x, GetY(y,i,j,k).x, GetZ(z,i,j,k).x);
 		v = mglPoint(ax->v(i,j,k),ay->v(i,j,k),az->v(i,j,k));
-		dd = v.norm();	v *= cm*(fix?(dd>dm ? 1./dd : 0) : xm);
-		
+		mreal dd = v.norm(),c1,c2;
+		v *= cm*(fix?(dd>dm ? 1./dd : 0) : xm);
+
 		if(end)		{	p1 = d-v;	p2 = d;	}
 		else if(beg)	{	p1 = d;	p2 = d+v;	}
 		else		{	p1=d-v/2.;	p2=d+v/2.;	}
 		if(grd)	{	c1=gr->GetC(ss,dd*xm-0.5,false);	c2=gr->GetC(ss,dd*xm,false);	}
 		else	c1 = c2 = gr->GetC(ss,dd*xm,false);
-		n1=gr->AddPnt(p1,c1);	n2=gr->AddPnt(p2,c2);
+		long n1=gr->AddPnt(p1,c1),	n2=gr->AddPnt(p2,c2);
 		// allow vectors outside bounding box
 		if(n1<0 && n2>=0)	n1=gr->AddPnt(p1,c1,mglPoint(NAN),-1,2);
 		if(n2<0 && n1>=0)	n2=gr->AddPnt(p2,c2,mglPoint(NAN),-1,2);
@@ -292,7 +303,7 @@ struct _mgl_vec_slice	{	mglData x,y,z,ax,ay,az;	};
 //-----------------------------------------------------------------------------
 void MGL_NO_EXPORT mgl_get_slice(_mgl_vec_slice &s, HCDT x, HCDT y, HCDT z, HCDT ax, HCDT ay, HCDT az, char dir, mreal d, bool both)
 {
-	register long i,j,i0,n=ax->GetNx(),m=ax->GetNy(),l=ax->GetNz(), nx=1,ny=1,p;
+	long n=ax->GetNx(),m=ax->GetNy(),l=ax->GetNz(), nx=1,ny=1,p;
 
 	if(dir=='x')	{	nx = m;	ny = l;	if(d<0)	d = n/2.;	}
 	if(dir=='y')	{	nx = n;	ny = l;	if(d<0)	d = m/2.;	}
@@ -303,49 +314,55 @@ void MGL_NO_EXPORT mgl_get_slice(_mgl_vec_slice &s, HCDT x, HCDT y, HCDT z, HCDT
 	if(dir=='x' && p>=n-1)	{	d+=p-n+2;	p=n-2;	}
 	if(dir=='y' && p>=m-1)	{	d+=p-m+2.;	p=m-2;	}
 	if(dir=='z' && p>=l-1)	{	d+=p-l+2;	p=l-2;	}
-	mreal v;
 
 	if(both)
 	{
-		if(dir=='x')	for(j=0;j<ny;j++)	for(i=0;i<nx;i++)
-		{
-			i0 = i+nx*j;
-			s.x.a[i0] = x->v(p,i,j)*(1-d) + x->v(p+1,i,j)*d;
-			s.y.a[i0] = y->v(p,i,j)*(1-d) + y->v(p+1,i,j)*d;
-			s.z.a[i0] = z->v(p,i,j)*(1-d) + z->v(p+1,i,j)*d;
-			s.ax.a[i0] = ax->v(p,i,j)*(1-d) + ax->v(p+1,i,j)*d;
-			s.ay.a[i0] = ay->v(p,i,j)*(1-d) + ay->v(p+1,i,j)*d;
-			s.az.a[i0] = az->v(p,i,j)*(1-d) + az->v(p+1,i,j)*d;
-		}
-		if(dir=='y')	for(j=0;j<ny;j++)	for(i=0;i<nx;i++)
-		{
-			i0 = i+nx*j;
-			s.x.a[i0] = x->v(i,p,j)*(1-d) + x->v(i,p+1,j)*d;
-			s.y.a[i0] = y->v(i,p,j)*(1-d) + y->v(i,p+1,j)*d;
-			s.z.a[i0] = z->v(i,p,j)*(1-d) + z->v(i,p+1,j)*d;
-			s.ax.a[i0] = ax->v(i,p,j)*(1-d) + ax->v(i,p+1,j)*d;
-			s.ay.a[i0] = ay->v(i,p,j)*(1-d) + ay->v(i,p+1,j)*d;
-			s.az.a[i0] = az->v(i,p,j)*(1-d) + az->v(i,p+1,j)*d;
-		}
-		if(dir=='z')	for(j=0;j<ny;j++)	for(i=0;i<nx;i++)
-		{
-			i0 = i+nx*j;
-			s.x.a[i0] = x->v(i,j,p)*(1-d) + x->v(i,j,p+1)*d;
-			s.y.a[i0] = y->v(i,j,p)*(1-d) + y->v(i,j,p+1)*d;
-			s.z.a[i0] = z->v(i,j,p)*(1-d) + z->v(i,j,p+1)*d;
-			s.ax.a[i0] = ax->v(i,j,p)*(1-d) + ax->v(i,j,p+1)*d;
-			s.ay.a[i0] = ay->v(i,j,p)*(1-d) + ay->v(i,j,p+1)*d;
-			s.az.a[i0] = az->v(i,j,p)*(1-d) + az->v(i,j,p+1)*d;
-		}
+		if(dir=='x')
+#pragma omp parallel for collapse(2)
+			for(long j=0;j<ny;j++)	for(long i=0;i<nx;i++)
+			{
+				register long i0 = i+nx*j;
+				s.x.a[i0] = x->v(p,i,j)*(1-d) + x->v(p+1,i,j)*d;
+				s.y.a[i0] = y->v(p,i,j)*(1-d) + y->v(p+1,i,j)*d;
+				s.z.a[i0] = z->v(p,i,j)*(1-d) + z->v(p+1,i,j)*d;
+				s.ax.a[i0] = ax->v(p,i,j)*(1-d) + ax->v(p+1,i,j)*d;
+				s.ay.a[i0] = ay->v(p,i,j)*(1-d) + ay->v(p+1,i,j)*d;
+				s.az.a[i0] = az->v(p,i,j)*(1-d) + az->v(p+1,i,j)*d;
+			}
+		if(dir=='y')
+#pragma omp parallel for collapse(2)
+			for(long j=0;j<ny;j++)	for(long i=0;i<nx;i++)
+			{
+				register long i0 = i+nx*j;
+				s.x.a[i0] = x->v(i,p,j)*(1-d) + x->v(i,p+1,j)*d;
+				s.y.a[i0] = y->v(i,p,j)*(1-d) + y->v(i,p+1,j)*d;
+				s.z.a[i0] = z->v(i,p,j)*(1-d) + z->v(i,p+1,j)*d;
+				s.ax.a[i0] = ax->v(i,p,j)*(1-d) + ax->v(i,p+1,j)*d;
+				s.ay.a[i0] = ay->v(i,p,j)*(1-d) + ay->v(i,p+1,j)*d;
+				s.az.a[i0] = az->v(i,p,j)*(1-d) + az->v(i,p+1,j)*d;
+			}
+		if(dir=='z')
+#pragma omp parallel for collapse(2)
+			for(long j=0;j<ny;j++)	for(long i=0;i<nx;i++)
+			{
+				register long i0 = i+nx*j;
+				s.x.a[i0] = x->v(i,j,p)*(1-d) + x->v(i,j,p+1)*d;
+				s.y.a[i0] = y->v(i,j,p)*(1-d) + y->v(i,j,p+1)*d;
+				s.z.a[i0] = z->v(i,j,p)*(1-d) + z->v(i,j,p+1)*d;
+				s.ax.a[i0] = ax->v(i,j,p)*(1-d) + ax->v(i,j,p+1)*d;
+				s.ay.a[i0] = ay->v(i,j,p)*(1-d) + ay->v(i,j,p+1)*d;
+				s.az.a[i0] = az->v(i,j,p)*(1-d) + az->v(i,j,p+1)*d;
+			}
 	}
 	else	// x, y, z -- vectors
 	{
 		if(dir=='x')
 		{
-			v = x->v(p)*(1-d)+x->v(p+1)*d;
-			for(j=0;j<ny;j++)	for(i=0;i<nx;i++)
+			mreal v = x->v(p)*(1-d)+x->v(p+1)*d;
+#pragma omp parallel for collapse(2)
+			for(long j=0;j<ny;j++)	for(long i=0;i<nx;i++)
 			{
-				i0 = i+nx*j;	s.x.a[i0] = v;
+				register long i0 = i+nx*j;	s.x.a[i0] = v;
 				s.y.a[i0] = y->v(i);	s.z.a[i0] = z->v(j);
 				s.ax.a[i0] = ax->v(p,i,j)*(1-d) + ax->v(p+1,i,j)*d;
 				s.ay.a[i0] = ay->v(p,i,j)*(1-d) + ay->v(p+1,i,j)*d;
@@ -354,10 +371,11 @@ void MGL_NO_EXPORT mgl_get_slice(_mgl_vec_slice &s, HCDT x, HCDT y, HCDT z, HCDT
 		}
 		if(dir=='y')
 		{
-			v = y->v(p)*(1-d)+y->v(p+1)*d;
-			for(j=0;j<ny;j++)	for(i=0;i<nx;i++)
+			mreal v = y->v(p)*(1-d)+y->v(p+1)*d;
+#pragma omp parallel for collapse(2)
+			for(long j=0;j<ny;j++)	for(long i=0;i<nx;i++)
 			{
-				i0 = i+nx*j;	s.y.a[i0] = v;
+				register long i0 = i+nx*j;	s.y.a[i0] = v;
 				s.x.a[i0] = x->v(i);	s.z.a[i0] = z->v(j);
 				s.ax.a[i0] = ax->v(i,p,j)*(1-d) + ax->v(i,p+1,j)*d;
 				s.ay.a[i0] = ay->v(i,p,j)*(1-d) + ay->v(i,p+1,j)*d;
@@ -366,10 +384,11 @@ void MGL_NO_EXPORT mgl_get_slice(_mgl_vec_slice &s, HCDT x, HCDT y, HCDT z, HCDT
 		}
 		if(dir=='z')
 		{
-			v = z->v(p)*(1-d)+z->v(p+1)*d;
-			for(j=0;j<ny;j++)	for(i=0;i<nx;i++)
+			mreal v = z->v(p)*(1-d)+z->v(p+1)*d;
+#pragma omp parallel for collapse(2)
+			for(long j=0;j<ny;j++)	for(long i=0;i<nx;i++)
 			{
-				i0 = i+nx*j;	s.z.a[i0] = v;
+				register long i0 = i+nx*j;	s.z.a[i0] = v;
 				s.x.a[i0] = x->v(i);	s.y.a[i0] = y->v(j);
 				s.ax.a[i0] = ax->v(i,j,p)*(1-d) + ax->v(i,j,p+1)*d;
 				s.ay.a[i0] = ay->v(i,j,p)*(1-d) + ay->v(i,j,p+1)*d;
@@ -381,7 +400,7 @@ void MGL_NO_EXPORT mgl_get_slice(_mgl_vec_slice &s, HCDT x, HCDT y, HCDT z, HCDT
 //-----------------------------------------------------------------------------
 void MGL_NO_EXPORT mgl_get_slice_md(_mgl_vec_slice &s, const mglData *x, const mglData *y, const mglData *z, const mglData *ax, const mglData *ay, const mglData *az, char dir, mreal d, bool both)
 {
-	register long i,j,i0,i1,n=ax->nx,m=ax->ny,l=ax->nz, nx=1,ny=1,p;
+	long n=ax->nx,m=ax->ny,l=ax->nz, nx=1,ny=1,p;
 
 	if(dir=='x')	{	nx = m;	ny = l;	if(d<0)	d = n/2.;	}
 	if(dir=='y')	{	nx = n;	ny = l;	if(d<0)	d = m/2.;	}
@@ -392,49 +411,55 @@ void MGL_NO_EXPORT mgl_get_slice_md(_mgl_vec_slice &s, const mglData *x, const m
 	if(dir=='x' && p>=n-1)	{	d+=p-n+2;	p=n-2;	}
 	if(dir=='y' && p>=m-1)	{	d+=p-m+2.;	p=m-2;	}
 	if(dir=='z' && p>=l-1)	{	d+=p-l+2;	p=l-2;	}
-	mreal v;
 
 	if(both)
 	{
-		if(dir=='x')	for(j=0;j<ny;j++)	for(i=0;i<nx;i++)
-		{
-			i0 = i+nx*j;	i1 = p+n*(i+m*j);
-			s.x.a[i0] = x->a[i1]*(1-d) + x->a[i1+1]*d;
-			s.y.a[i0] = y->a[i1]*(1-d) + y->a[i1+1]*d;
-			s.z.a[i0] = z->a[i1]*(1-d) + z->a[i1+1]*d;
-			s.ax.a[i0] = ax->a[i1]*(1-d) + ax->a[i1+1]*d;
-			s.ay.a[i0] = ay->a[i1]*(1-d) + ay->a[i1+1]*d;
-			s.az.a[i0] = az->a[i1]*(1-d) + az->a[i1+1]*d;
-		}
-		if(dir=='y')	for(j=0;j<ny;j++)	for(i=0;i<nx;i++)
-		{
-			i0 = i+nx*j;	i1 = i+n*(p+m*j);
-			s.x.a[i0] = x->a[i1]*(1-d) + x->a[i1+n]*d;
-			s.y.a[i0] = y->a[i1]*(1-d) + y->a[i1+n]*d;
-			s.z.a[i0] = z->a[i1]*(1-d) + z->a[i1+n]*d;
-			s.ax.a[i0] = ax->a[i1]*(1-d) + ax->a[i1+n]*d;
-			s.ay.a[i0] = ay->a[i1]*(1-d) + ay->a[i1+n]*d;
-			s.az.a[i0] = az->a[i1]*(1-d) + az->a[i1+n]*d;
-		}
-		if(dir=='z')	for(j=0;j<ny;j++)	for(i=0;i<nx;i++)
-		{
-			i0 = i+nx*j;	i1 = i+n*(j+m*p);
-			s.x.a[i0] = x->a[i1]*(1-d) + x->a[i1+n*m]*d;
-			s.y.a[i0] = y->a[i1]*(1-d) + y->a[i1+n*m]*d;
-			s.z.a[i0] = z->a[i1]*(1-d) + z->a[i1+n*m]*d;
-			s.ax.a[i0] = ax->a[i1]*(1-d) + ax->a[i1+n*m]*d;
-			s.ay.a[i0] = ay->a[i1]*(1-d) + ay->a[i1+n*m]*d;
-			s.az.a[i0] = az->a[i1]*(1-d) + az->a[i1+n*m]*d;
-		}
+		if(dir=='x')
+#pragma omp parallel for collapse(2)
+			for(long j=0;j<ny;j++)	for(long i=0;i<nx;i++)
+			{
+				register long i0 = i+nx*j, i1 = p+n*(i+m*j);
+				s.x.a[i0] = x->a[i1]*(1-d) + x->a[i1+1]*d;
+				s.y.a[i0] = y->a[i1]*(1-d) + y->a[i1+1]*d;
+				s.z.a[i0] = z->a[i1]*(1-d) + z->a[i1+1]*d;
+				s.ax.a[i0] = ax->a[i1]*(1-d) + ax->a[i1+1]*d;
+				s.ay.a[i0] = ay->a[i1]*(1-d) + ay->a[i1+1]*d;
+				s.az.a[i0] = az->a[i1]*(1-d) + az->a[i1+1]*d;
+			}
+		if(dir=='y')
+#pragma omp parallel for collapse(2)
+			for(long j=0;j<ny;j++)	for(long i=0;i<nx;i++)
+			{
+				register long i0 = i+nx*j, i1 = i+n*(p+m*j);
+				s.x.a[i0] = x->a[i1]*(1-d) + x->a[i1+n]*d;
+				s.y.a[i0] = y->a[i1]*(1-d) + y->a[i1+n]*d;
+				s.z.a[i0] = z->a[i1]*(1-d) + z->a[i1+n]*d;
+				s.ax.a[i0] = ax->a[i1]*(1-d) + ax->a[i1+n]*d;
+				s.ay.a[i0] = ay->a[i1]*(1-d) + ay->a[i1+n]*d;
+				s.az.a[i0] = az->a[i1]*(1-d) + az->a[i1+n]*d;
+			}
+		if(dir=='z')
+#pragma omp parallel for collapse(2)
+			for(long j=0;j<ny;j++)	for(long i=0;i<nx;i++)
+			{
+				register long i0 = i+nx*j, i1 = i+n*(j+m*p);
+				s.x.a[i0] = x->a[i1]*(1-d) + x->a[i1+n*m]*d;
+				s.y.a[i0] = y->a[i1]*(1-d) + y->a[i1+n*m]*d;
+				s.z.a[i0] = z->a[i1]*(1-d) + z->a[i1+n*m]*d;
+				s.ax.a[i0] = ax->a[i1]*(1-d) + ax->a[i1+n*m]*d;
+				s.ay.a[i0] = ay->a[i1]*(1-d) + ay->a[i1+n*m]*d;
+				s.az.a[i0] = az->a[i1]*(1-d) + az->a[i1+n*m]*d;
+			}
 	}
 	else	// x, y, z -- vectors
 	{
 		if(dir=='x')
 		{
-			v = x->a[p]*(1-d)+x->a[p+1]*d;
-			for(j=0;j<ny;j++)	for(i=0;i<nx;i++)
+			mreal v = x->a[p]*(1-d)+x->a[p+1]*d;
+#pragma omp parallel for collapse(2)
+			for(long j=0;j<ny;j++)	for(long i=0;i<nx;i++)
 			{
-				i0 = i+nx*j;	s.x.a[i0] = v;	i1 = p+n*(i+m*j);
+				register long i0 = i+nx*j, i1 = p+n*(i+m*j);	s.x.a[i0] = v;
 				s.y.a[i0] = y->a[i];	s.z.a[i0] = z->a[j];
 				s.ax.a[i0] = ax->a[i1]*(1-d) + ax->a[i1+1]*d;
 				s.ay.a[i0] = ay->a[i1]*(1-d) + ay->a[i1+1]*d;
@@ -443,10 +468,11 @@ void MGL_NO_EXPORT mgl_get_slice_md(_mgl_vec_slice &s, const mglData *x, const m
 		}
 		if(dir=='y')
 		{
-			v = y->a[p]*(1-d)+y->a[p+1]*d;
-			for(j=0;j<ny;j++)	for(i=0;i<nx;i++)
+			mreal v = y->a[p]*(1-d)+y->a[p+1]*d;
+#pragma omp parallel for collapse(2)
+			for(long j=0;j<ny;j++)	for(long i=0;i<nx;i++)
 			{
-				i0 = i+nx*j;	s.y.a[i0] = v;	i1 = i+n*(p+m*j);
+				register long i0 = i+nx*j, i1 = i+n*(p+m*j);	s.y.a[i0] = v;
 				s.x.a[i0] = x->a[i];	s.z.a[i0] = z->a[j];
 				s.ax.a[i0] = ax->a[i1]*(1-d) + ax->a[i1+n]*d;
 				s.ay.a[i0] = ay->a[i1]*(1-d) + ay->a[i1+n]*d;
@@ -455,10 +481,11 @@ void MGL_NO_EXPORT mgl_get_slice_md(_mgl_vec_slice &s, const mglData *x, const m
 		}
 		if(dir=='z')
 		{
-			v = z->a[p]*(1-d)+z->a[p+1]*d;
-			for(j=0;j<ny;j++)	for(i=0;i<nx;i++)
+			mreal v = z->a[p]*(1-d)+z->a[p+1]*d;
+#pragma omp parallel for collapse(2)
+			for(long j=0;j<ny;j++)	for(long i=0;i<nx;i++)
 			{
-				i0 = i+nx*j;	s.z.a[i0] = v;	i1 = i+n*(j+m*p);
+				register long i0 = i+nx*j, i1 = i+n*(j+m*p);	s.z.a[i0] = v;
 				s.x.a[i0] = x->a[i];	s.y.a[i0] = y->a[j];
 				s.ax.a[i0] = ax->a[i1]*(1-d) + ax->a[i1+n*m]*d;
 				s.ay.a[i0] = ay->a[i1]*(1-d) + ay->a[i1+n*m]*d;
@@ -498,49 +525,55 @@ void MGL_EXPORT mgl_vect3_xyz(HMGL gr, HCDT x, HCDT y, HCDT z, HCDT ax, HCDT ay,
 	else
 		mgl_get_slice(s,x,y,z,ax,ay,az,dir,sVal,both);
 
-	long i,j,n=s.ax.nx,m=s.ax.ny;
-	long tx=1,ty=1;
+	long n=s.ax.nx,m=s.ax.ny, tx=1,ty=1;
 	if(gr->MeshNum>1)	{	tx=(n-1)/(gr->MeshNum-1);	ty=(m-1)/(gr->MeshNum-1);	}
 	if(tx<1)	tx=1;	if(ty<1)	ty=1;
 	mreal xm=0,cm=0,ca=0;
-	mreal dd,dm=(fabs(gr->Max.c)+fabs(gr->Min.c))*1e-5;
-	// use whole array for determining maximal vectors length 
+	mreal dm=(fabs(gr->Max.c)+fabs(gr->Min.c))*1e-5;
+	// use whole array for determining maximal vectors length
 	mglPoint p1,p2, v, d=(gr->Max-gr->Min)/mglPoint(1./ax->GetNx(),1./ax->GetNy(),1./ax->GetNz());
-	mreal c1,c2, xx,yy,zz;
 
-	register long i0, tn=ty*n;
-	for(i=0;i<n;i+=tx)	for(j=0;j<m;j+=ty)
+	long tn=ty*n;
+#pragma omp parallel private(p1,p2,v)
 	{
-		i0 = i+n*j;	xx = s.x.a[i0];	yy = s.y.a[i0];	zz = s.z.a[i0];
-		p1 = i<n-1 ? mglPoint(s.x.a[i0+tx]-xx, s.y.a[i0+tx]-yy, s.z.a[i0+tx]-zz) : mglPoint(xx-s.x.a[i0-tx], yy-s.y.a[i0-tx], zz-s.z.a[i0-tx]);
-		p2 = j<m-1 ? mglPoint(s.x.a[i0+tn]-xx, s.y.a[i0+tn]-yy, s.z.a[i0+tn]-zz) : mglPoint(xx-s.x.a[i0-tn], yy-s.y.a[i0-tn], zz-s.z.a[i0-tn]);
-		v = mglPoint(s.ax.a[i0], s.ay.a[i0], s.az.a[i0]);
-		c1 = v.norm();	xm = xm<c1 ? c1:xm;	// handle NAN values
-		yy = fabs(v*d);	xx = d.norm();	yy *= xx?1/(xx*xx):0;
-		c1 = fabs(v*p1);	xx = p1.norm();	c1 *= xx?1/(xx*xx):0;
-		c2 = fabs(v*p2);	xx = p2.norm();	c2 *= xx?1/(xx*xx):0;
-		c1 = c1<c2 ? c2:c1;	c1 = c1<yy ? yy:c1;
-		ca+=c1;	cm = cm<c1 ? c1:cm;
+		mreal xm1=0,cm1=0, xx,yy,zz, c1,c2;
+#pragma omp for nowait collapse(2) reduction(+:ca)
+		for(long i=0;i<n;i+=tx)	for(long j=0;j<m;j+=ty)
+		{
+			register long i0 = i+n*j;
+			xx = s.x.a[i0];	yy = s.y.a[i0];	zz = s.z.a[i0];
+			p1 = i<n-1 ? mglPoint(s.x.a[i0+tx]-xx, s.y.a[i0+tx]-yy, s.z.a[i0+tx]-zz) : mglPoint(xx-s.x.a[i0-tx], yy-s.y.a[i0-tx], zz-s.z.a[i0-tx]);
+			p2 = j<m-1 ? mglPoint(s.x.a[i0+tn]-xx, s.y.a[i0+tn]-yy, s.z.a[i0+tn]-zz) : mglPoint(xx-s.x.a[i0-tn], yy-s.y.a[i0-tn], zz-s.z.a[i0-tn]);
+			v = mglPoint(s.ax.a[i0], s.ay.a[i0], s.az.a[i0]);
+			c1 = v.norm();	xm1 = xm1<c1 ? c1:xm1;	// handle NAN values
+			yy = fabs(v*d);	xx = d.norm();	yy *= xx?1/(xx*xx):0;
+			c1 = fabs(v*p1);	xx = p1.norm();	c1 *= xx?1/(xx*xx):0;
+			c2 = fabs(v*p2);	xx = p2.norm();	c2 *= xx?1/(xx*xx):0;
+			c1 = c1<c2 ? c2:c1;	c1 = c1<yy ? yy:c1;
+			ca+=c1;	cm1 = cm1<c1 ? c1:cm1;
+		}
+#pragma omp critical(max_vec)
+		{cm = cm<cm1 ? cm1:cm;	xm = xm<xm1 ? xm1:xm;}
 	}
 	ca /= (n*m)/(tx*ty);
-//	if(cm>2*ca)	cm = 2*ca;	// disable too narrow grid steps TODO: decide later
 	xm = xm?1./xm:0;	cm = cm?1./cm:0;
 
-	long n1,n2;
-	for(i=0;i<n;i+=tx)	for(j=0;j<m;j+=ty)
+#pragma omp parallel for private(d,v,p1,p2) collapse(2)
+	for(long i=0;i<n;i+=tx)	for(long j=0;j<m;j+=ty)
 	{
-		if(gr->Stop)	return;
-		i0 = i+n*j;
+		if(gr->Stop)	continue;
+		register long i0 = i+n*j;
 		d = mglPoint(s.x.a[i0], s.y.a[i0], s.z.a[i0]);
 		v = mglPoint(s.ax.a[i0], s.ay.a[i0], s.az.a[i0]);
-		dd = v.norm();	v *= cm*(fix?(dd>dm ? 1./dd : 0) : xm);
+		mreal dd = v.norm(),c1,c2;
+		v *= cm*(fix?(dd>dm ? 1./dd : 0) : xm);
 
 		if(end)		{	p1 = d-v;	p2 = d;	}
 		else if(beg)	{	p1 = d;	p2 = d+v;	}
 		else		{	p1=d-v/2.;	p2=d+v/2.;	}
 		if(grd)	{	c1=gr->GetC(ss,dd*xm-0.5,false);	c2=gr->GetC(ss,dd*xm,false);}
 		else	c1 = c2 = gr->GetC(ss,dd*xm,false);
-		n1=gr->AddPnt(p1,c1);	n2=gr->AddPnt(p2,c2);
+		long n1=gr->AddPnt(p1,c1),	n2=gr->AddPnt(p2,c2);
 		// allow vectors outside bounding box
 		if(n1<0 && n2>=0)	n1=gr->AddPnt(p1,c1,mglPoint(NAN),-1,2);
 		if(n2<0 && n1>=0)	n2=gr->AddPnt(p2,c2,mglPoint(NAN),-1,2);
@@ -653,29 +686,24 @@ void MGL_EXPORT mgl_flow_xy(HMGL gr, HCDT x, HCDT y, HCDT ax, HCDT ay, const cha
 	for(long k=0;k<ax->GetNz();k++)
 	{
 		if(ax->GetNz()>1)	zVal = gr->Min.z+(gr->Max.z-gr->Min.z)*mreal(k)/(ax->GetNz()-1);
-		for(long i=0;i<num;i++)
+#pragma omp parallel for private(u,v) collapse(2)
+		for(long i=0;i<num;i++)	for(int s=-1;s<=1;s+=2)
 		{
-			if(gr->Stop)	return;
+			if(gr->Stop)	continue;
 			u = 0;	v = (i+1.)/(num+1.);
-			flow(gr, zVal, u, v, xx, yy, bx, by,ss,vv);
-			flow(gr, zVal, -u, -v, xx, yy, bx, by,ss,vv);
+			flow(gr, zVal, s*u, s*v, xx, yy, bx, by,ss,vv);
 			u = 1;	v = (i+1.)/(num+1.);
-			flow(gr, zVal, u, v, xx, yy, bx, by,ss,vv);
-			flow(gr, zVal, -u, -v, xx, yy, bx, by,ss,vv);
+			flow(gr, zVal, s*u, s*v, xx, yy, bx, by,ss,vv);
 			u = (i+1.)/(num+1.);	v = 0;
-			flow(gr, zVal, u, v, xx, yy, bx, by,ss,vv);
-			flow(gr, zVal, -u, -v, xx, yy, bx, by,ss,vv);
+			flow(gr, zVal, s*u, s*v, xx, yy, bx, by,ss,vv);
 			u = (i+1.)/(num+1.);	v = 1;
-			flow(gr, zVal, u, v, xx, yy, bx, by,ss,vv);
-			flow(gr, zVal, -u, -v, xx, yy, bx, by,ss,vv);
+			flow(gr, zVal, s*u, s*v, xx, yy, bx, by,ss,vv);
 			if(cnt)
 			{
 				u = 0.5;	v = (i+1.)/(num+1.);
-				flow(gr, zVal, u, v, xx, yy, bx, by,ss,vv);
-				flow(gr, zVal, -u, -v, xx, yy, bx, by,ss,vv);
+				flow(gr, zVal, s*u, s*v, xx, yy, bx, by,ss,vv);
 				u = (i+1.)/(num+1.);	v = 0.5;
-				flow(gr, zVal, u, v, xx, yy, bx, by,ss,vv);
-				flow(gr, zVal, -u, -v, xx, yy, bx, by,ss,vv);
+				flow(gr, zVal, s*u, s*v, xx, yy, bx, by,ss,vv);
 			}
 		}
 	}
@@ -857,7 +885,6 @@ void flow(mglBase *gr, double u, double v, double w, const mglData &x, const mgl
 void MGL_EXPORT mgl_flow_xyz(HMGL gr, HCDT x, HCDT y, HCDT z, HCDT ax, HCDT ay, HCDT az, const char *sch, const char *opt)
 {
 	mreal u,v,w;
-	long i,j;
 	if(mgl_check_vec3(gr,x,y,z,ax,ay,az,"Flow3"))	return;
 
 	mreal r = gr->SaveState(opt);
@@ -868,38 +895,30 @@ void MGL_EXPORT mgl_flow_xyz(HMGL gr, HCDT x, HCDT y, HCDT z, HCDT ax, HCDT ay,
 	bool vv = mglchr(sch,'v'), xo = mglchr(sch,'x'), zo = mglchr(sch,'z');
 
 	mglData xx(x), yy(y), zz(z), bx(ax), by(ay), bz(az);
-	for(i=0;i<num;i++)	for(j=0;j<num;j++)
+#pragma omp parallel for private(u,v,w) collapse(3)
+	for(long i=0;i<num;i++)	for(long j=0;j<num;j++)	for(int s=-1;s<=1;s+=2)
 	{
-		if(gr->Stop)	return;
+		if(gr->Stop)	continue;
 		u = (i+1.)/(num+1.);	v = (j+1.)/(num+1.);	w = 0;
-		flow(gr, u, v, w, xx, yy, zz, bx, by, bz,ss,vv,xo,zo);
-		flow(gr,-u,-v,-w, xx, yy, zz, bx, by, bz,ss,vv,xo,zo);
+		flow(gr, s*u, s*v, s*w, xx, yy, zz, bx, by, bz,ss,vv,xo,zo);
 		u = (i+1.)/(num+1.);	v = (j+1.)/(num+1.);	w = 1;
-		flow(gr, u, v, w, xx, yy, zz, bx, by, bz,ss,vv,xo,zo);
-		flow(gr,-u,-v,-w, xx, yy, zz, bx, by, bz,ss,vv,xo,zo);
+		flow(gr, s*u, s*v, s*w, xx, yy, zz, bx, by, bz,ss,vv,xo,zo);
 		u = 0;	v = (j+1.)/(num+1.);	w = (i+1.)/(num+1.);
-		flow(gr, u, v, w, xx, yy, zz, bx, by, bz,ss,vv,xo,zo);
-		flow(gr,-u,-v,-w, xx, yy, zz, bx, by, bz,ss,vv,xo,zo);
+		flow(gr, s*u, s*v, s*w, xx, yy, zz, bx, by, bz,ss,vv,xo,zo);
 		u = 1;	v = (j+1.)/(num+1.);	w = (i+1.)/(num+1.);
-		flow(gr, u, v, w, xx, yy, zz, bx, by, bz,ss,vv,xo,zo);
-		flow(gr,-u,-v,-w, xx, yy, zz, bx, by, bz,ss,vv,xo,zo);
+		flow(gr, s*u, s*v, s*w, xx, yy, zz, bx, by, bz,ss,vv,xo,zo);
 		u = (i+1.)/(num+1.);	v = 0;	w = (j+1.)/(num+1.);
-		flow(gr, u, v, w, xx, yy, zz, bx, by, bz,ss,vv,xo,zo);
-		flow(gr,-u,-v,-w, xx, yy, zz, bx, by, bz,ss,vv,xo,zo);
+		flow(gr, s*u, s*v, s*w, xx, yy, zz, bx, by, bz,ss,vv,xo,zo);
 		u = (i+1.)/(num+1.);	v = 1;	w = (j+1.)/(num+1.);
-		flow(gr, u, v, w, xx, yy, zz, bx, by, bz,ss,vv,xo,zo);
-		flow(gr,-u,-v,-w, xx, yy, zz, bx, by, bz,ss,vv,xo,zo);
+		flow(gr, s*u, s*v, s*w, xx, yy, zz, bx, by, bz,ss,vv,xo,zo);
 		if(cnt)
 		{
 			u = (i+1.)/(num+1.);	v = (j+1.)/(num+1.);	w = 0.5;
-			flow(gr, u, v, w, xx, yy, zz, bx, by, bz,ss,vv,xo,zo);
-			flow(gr,-u,-v,-w, xx, yy, zz, bx, by, bz,ss,vv,xo,zo);
+			flow(gr, s*u, s*v, s*w, xx, yy, zz, bx, by, bz,ss,vv,xo,zo);
 			u = 0.5;	v = (j+1.)/(num+1.);	w = (i+1.)/(num+1.);
-			flow(gr, u, v, w, xx, yy, zz, bx, by, bz,ss,vv,xo,zo);
-			flow(gr,-u,-v,-w, xx, yy, zz, bx, by, bz,ss,vv,xo,zo);
+			flow(gr, s*u, s*v, s*w, xx, yy, zz, bx, by, bz,ss,vv,xo,zo);
 			u = (i+1.)/(num+1.);	v = 0.5;	w = (j+1.)/(num+1.);
-			flow(gr, u, v, w, xx, yy, zz, bx, by, bz,ss,vv,xo,zo);
-			flow(gr,-u,-v,-w, xx, yy, zz, bx, by, bz,ss,vv,xo,zo);
+			flow(gr, s*u, s*v, s*w, xx, yy, zz, bx, by, bz,ss,vv,xo,zo);
 		}
 	}
 	gr->EndGroup();
@@ -1013,12 +1032,12 @@ void MGL_EXPORT mgl_grad_xyz(HMGL gr, HCDT x, HCDT y, HCDT z, HCDT phi, const ch
 	if(x->GetNx()*x->GetNy()*x->GetNz()==nn && y->GetNx()*y->GetNy()*y->GetNz()==nn && x->GetNx()*x->GetNy()*x->GetNz()==nn)
 	{	xx.Set(x);	yy.Set(y);	zz.Set(z);	}	// nothing to do
 	else if(x->GetNx()==n && y->GetNx()==m && z->GetNx()==l)
-	{	// prepare data
-		register long i,j,k,i0;
-		for(i=0;i<n;i++)	for(j=0;j<m;j++)	for(k=0;k<l;k++)
-		{	i0 = i+n*(j+m*k);	xx.a[i0] = x->v(i);
-			yy.a[i0] = y->v(j);	zz.a[i0] = z->v(k);	}
-	}
+#pragma omp parallel for collapse(3)
+		for(long i=0;i<n;i++)	for(long j=0;j<m;j++)	for(long k=0;k<l;k++)
+		{
+			register long i0 = i+n*(j+m*k);
+			xx.a[i0] = x->v(i);	yy.a[i0] = y->v(j);	zz.a[i0] = z->v(k);
+		}
 	else	{	gr->SetWarn(mglWarnDim,"Grad");	return;	}
 	ax.Diff(xx,yy,zz);	ay.Diff(yy,xx,zz);	az.Diff(zz,xx,yy);
 	mgl_flow_xyz(gr,&xx,&yy,&zz,&ax,&ay,&az,sch,opt);
@@ -1031,11 +1050,9 @@ void MGL_EXPORT mgl_grad_xy(HMGL gr, HCDT x, HCDT y, HCDT phi, const char *sch,
 	long n = phi->GetNx(), m=phi->GetNy(), nn=n*m;
 	if(x->GetNx()*x->GetNy()==nn && y->GetNx()*y->GetNy()==nn)	{	xx.Set(x);	yy.Set(y);	}
 	else if(x->GetNx()==n && y->GetNx()==m)
-	{
-		register long i,j,i0;
-		for(i=0;i<n;i++)	for(j=0;j<m;j++)
-		{	i0 = i+n*j;	xx.a[i0] = x->v(i);	yy.a[i0] = y->v(j);	}
-	}
+#pragma omp parallel for collapse(2)
+		for(long i=0;i<n;i++)	for(long j=0;j<m;j++)
+		{	register long i0 = i+n*j;	xx.a[i0] = x->v(i);	yy.a[i0] = y->v(j);	}
 	else	{	gr->SetWarn(mglWarnDim,"Grad");	return;	}
 	ax.Diff(xx,yy);	ay.Diff(yy,xx);
 	mgl_flow_xy(gr,&xx,&yy,&ax,&ay,sch,opt);
@@ -1114,30 +1131,32 @@ void MGL_NO_EXPORT flowr(mglBase *gr, double zVal, double u, double v, const mgl
 	} while(!end);
 	if(k>1)
 	{
-		const int num=24;
-		long i,j,*id=new long[2*num];
+		int num=!(gr->GetQuality()&3)?13:25;
+		long *id=new long[2*num];
 		mglPoint p,l=pp[1]-pp[0],t,q,d;
 		t = !l;	t.Normalize();	q = t^l;	q.Normalize();
-		mreal si,co,fi, rr=pp[0].c,dr=l.c;
+		mreal rr=pp[0].c,dr=l.c;
 		gr->Reserve(num*k);
 
-		for(j=0;j<num;j++)
+		for(long j=0;j<num;j++)
 		{
-			fi = j*2*M_PI/(num-1);	co = cos(fi);	si = sin(fi);
+			register int fi=j*360/(num-1);
+			register float co = mgl_cos[fi%360], si = mgl_cos[(270+fi)%360];
 			p = pp[0] + t*(rr*co) + q*(rr*si);
 			d = (t*si - q*co)^(l + t*(dr*co) + q*(dr*si));
 			id[j] = gr->AddPnt(p,cc[0],d);
 		}
-		for(i=1;i<k;i++)
+		for(long i=1;i<k;i++)
 		{
 			if(i<k-1)	l = pp[i+1]-pp[i-1];
 			else	l = pp[i]-pp[i-1];
 			t = !l;	t.Normalize();	q = t^l;	q.Normalize();
 			rr=pp[i].c;	dr=l.c;
 			memcpy(id+num,id,num*sizeof(long));
-			for(j=0;j<num;j++)
+			for(long j=0;j<num;j++)
 			{
-				fi = j*2*M_PI/(num-1);	co = cos(fi);	si = sin(fi);
+				register int fi=j*360/(num-1);
+				register float co = mgl_cos[fi%360], si = mgl_cos[(270+fi)%360];
 				p = pp[i] + t*(rr*co) + q*(rr*si);
 				d = (t*si - q*co)^(l + t*(dr*co) + q*(dr*si));
 				id[j] = gr->AddPnt(p,cc[i],d);
@@ -1168,29 +1187,24 @@ void MGL_EXPORT mgl_pipe_xy(HMGL gr, HCDT x, HCDT y, HCDT ax, HCDT ay, const cha
 	for(long k=0;k<ax->GetNz();k++)
 	{
 		if(ax->GetNz()>1)	zVal = gr->Min.z+(gr->Max.z-gr->Min.z)*mreal(k)/(ax->GetNz()-1);
-		for(long i=0;i<num;i++)
+#pragma omp parallel for private(u,v) collapse(2)
+		for(long i=0;i<num;i++)	for(int s=-1;s<=1;s+=2)
 		{
-			if(gr->Stop)	return;
+			if(gr->Stop)	continue;
 			u = 0;	v = (i+1.)/(num+1.);
-			flowr(gr, zVal, u, v, xx, yy, bx, by,r0,ss);
-			flowr(gr, zVal, -u, -v, xx, yy, bx, by,r0,ss);
+			flowr(gr, zVal, s*u, s*v, xx, yy, bx, by,r0,ss);
 			u = 1;	v = (i+1.)/(num+1.);
-			flowr(gr, zVal, u, v, xx, yy, bx, by,r0,ss);
-			flowr(gr, zVal, -u, -v, xx, yy, bx, by,r0,ss);
+			flowr(gr, zVal, s*u, s*v, xx, yy, bx, by,r0,ss);
 			u = (i+1.)/(num+1.);	v = 0;
-			flowr(gr, zVal, u, v, xx, yy, bx, by,r0,ss);
-			flowr(gr, zVal, -u, -v, xx, yy, bx, by,r0,ss);
+			flowr(gr, zVal, s*u, s*v, xx, yy, bx, by,r0,ss);
 			u = (i+1.)/(num+1.);	v = 1;
-			flowr(gr, zVal, u, v, xx, yy, bx, by,r0,ss);
-			flowr(gr, zVal, -u, -v, xx, yy, bx, by,r0,ss);
+			flowr(gr, zVal, s*u, s*v, xx, yy, bx, by,r0,ss);
 			if(cnt)
 			{
 				u = 0.5;	v = (i+1.)/(num+1.);
-				flowr(gr, zVal, u, v, xx, yy, bx, by,r0,ss);
-				flowr(gr, zVal, -u, -v, xx, yy, bx, by,r0,ss);
+				flowr(gr, zVal, s*u, s*v, xx, yy, bx, by,r0,ss);
 				u = (i+1.)/(num+1.);	v = 0.5;
-				flowr(gr, zVal, u, v, xx, yy, bx, by,r0,ss);
-				flowr(gr, zVal, -u, -v, xx, yy, bx, by,r0,ss);
+				flowr(gr, zVal, s*u, s*v, xx, yy, bx, by,r0,ss);
 			}
 		}
 	}
@@ -1273,29 +1287,31 @@ void flowr(mglBase *gr, double u, double v, double w, const mglData &x, const mg
 	if(k>1)
 	{
 		const int num=24;
-		long i,j,*id=new long[2*num];
+		long *id=new long[2*num];
 		mglPoint p,l=pp[1]-pp[0],t,q,d;
 		t = !l;	t.Normalize();	q = t^l;	q.Normalize();
-		mreal si,co,fi, rr=pp[0].c,dr=l.c;
+		mreal rr=pp[0].c,dr=l.c;
 		gr->Reserve(num*k);
 
-		for(j=0;j<num;j++)
+		for(long j=0;j<num;j++)
 		{
-			fi = j*2*M_PI/(num-1);	co = cos(fi);	si = sin(fi);
+			register int fi=j*360/(num-1);
+			register float co = mgl_cos[fi%360], si = mgl_cos[(270+fi)%360];
 			p = pp[0] + t*(rr*co) + q*(rr*si);
 			d = (t*si - q*co)^(l + t*(dr*co) + q*(dr*si));
 			id[j] = gr->AddPnt(p,cc[0],d);
 		}
-		for(i=1;i<k;i++)
+		for(long i=1;i<k;i++)
 		{
 			if(i<k-1)	l = pp[i+1]-pp[i-1];
 			else	l = pp[i]-pp[i-1];
 			t = !l;	t.Normalize();	q = t^l;	q.Normalize();
 			rr=pp[i].c;	dr=l.c;
 			memcpy(id+num,id,num*sizeof(long));
-			for(j=0;j<num;j++)
+			for(long j=0;j<num;j++)
 			{
-				fi = j*2*M_PI/(num-1);	co = cos(fi);	si = sin(fi);
+				register int fi=j*360/(num-1);
+				register float co = mgl_cos[fi%360], si = mgl_cos[(270+fi)%360];
 				p = pp[i] + t*(rr*co) + q*(rr*si);
 				d = (t*si - q*co)^(l + t*(dr*co) + q*(dr*si));
 				id[j] = gr->AddPnt(p,cc[i],d);
@@ -1310,7 +1326,6 @@ void flowr(mglBase *gr, double u, double v, double w, const mglData &x, const mg
 void MGL_EXPORT mgl_pipe_xyz(HMGL gr, HCDT x, HCDT y, HCDT z, HCDT ax, HCDT ay, HCDT az, const char *sch, double r0, const char *opt)
 {
 	mreal u,v,w;
-	long i,j;
 	if(mgl_check_vec3(gr,x,y,z,ax,ay,az,"Vect"))	return;
 
 	mreal r = gr->SaveState(opt);
@@ -1322,38 +1337,30 @@ void MGL_EXPORT mgl_pipe_xyz(HMGL gr, HCDT x, HCDT y, HCDT z, HCDT ax, HCDT ay,
 	bool cnt=!mglchr(sch,'#');
 
 	mglData xx(x), yy(y), zz(z), bx(ax), by(ay), bz(az);
-	for(i=0;i<num;i++)	for(j=0;j<num;j++)
+#pragma omp parallel for private(u,v,w) collapse(3)
+	for(long i=0;i<num;i++)	for(long j=0;j<num;j++)	for(int s=-1;s<=1;s+=2)
 	{
-		if(gr->Stop)	return;
+		if(gr->Stop)	continue;
 		u = (i+1.)/(num+1.);	v = (j+1.)/(num+1.);	w = 0;
-		flowr(gr, u, v, w, xx, yy, zz, bx, by, bz,r0,ss);
-		flowr(gr,-u,-v,-w, xx, yy, zz, bx, by, bz,r0,ss);
+		flowr(gr, s*u, s*v, s*w, xx, yy, zz, bx, by, bz,r0,ss);
 		u = (i+1.)/(num+1.);	v = (j+1.)/(num+1.);	w = 1;
-		flowr(gr, u, v, w, xx, yy, zz, bx, by, bz,r0,ss);
-		flowr(gr,-u,-v,-w, xx, yy, zz, bx, by, bz,r0,ss);
+		flowr(gr, s*u, s*v, s*w, xx, yy, zz, bx, by, bz,r0,ss);
 		u = 0;	v = (j+1.)/(num+1.);	w = (i+1.)/(num+1.);
-		flowr(gr, u, v, w, xx, yy, zz, bx, by, bz,r0,ss);
-		flowr(gr,-u,-v,-w, xx, yy, zz, bx, by, bz,r0,ss);
+		flowr(gr, s*u, s*v, s*w, xx, yy, zz, bx, by, bz,r0,ss);
 		u = 1;	v = (j+1.)/(num+1.);	w = (i+1.)/(num+1.);
-		flowr(gr, u, v, w, xx, yy, zz, bx, by, bz,r0,ss);
-		flowr(gr,-u,-v,-w, xx, yy, zz, bx, by, bz,r0,ss);
+		flowr(gr, s*u, s*v, s*w, xx, yy, zz, bx, by, bz,r0,ss);
 		u = (i+1.)/(num+1.);	v = 0;	w = (j+1.)/(num+1.);
-		flowr(gr, u, v, w, xx, yy, zz, bx, by, bz,r0,ss);
-		flowr(gr,-u,-v,-w, xx, yy, zz, bx, by, bz,r0,ss);
+		flowr(gr, s*u, s*v, s*w, xx, yy, zz, bx, by, bz,r0,ss);
 		u = (i+1.)/(num+1.);	v = 1;	w = (j+1.)/(num+1.);
-		flowr(gr, u, v, w, xx, yy, zz, bx, by, bz,r0,ss);
-		flowr(gr,-u,-v,-w, xx, yy, zz, bx, by, bz,r0,ss);
+		flowr(gr, s*u, s*v, s*w, xx, yy, zz, bx, by, bz,r0,ss);
 		if(cnt)
 		{
 			u = (i+1.)/(num+1.);	v = (j+1.)/(num+1.);	w = 0.5;
-			flowr(gr, u, v, w, xx, yy, zz, bx, by, bz,r0,ss);
-			flowr(gr,-u,-v,-w, xx, yy, zz, bx, by, bz,r0,ss);
+			flowr(gr, s*u, s*v, s*w, xx, yy, zz, bx, by, bz,r0,ss);
 			u = 0.5;	v = (j+1.)/(num+1.);	w = (i+1.)/(num+1.);
-			flowr(gr, u, v, w, xx, yy, zz, bx, by, bz,r0,ss);
-			flowr(gr,-u,-v,-w, xx, yy, zz, bx, by, bz,r0,ss);
+			flowr(gr, s*u, s*v, s*w, xx, yy, zz, bx, by, bz,r0,ss);
 			u = (i+1.)/(num+1.);	v = 0.5;	w = (j+1.)/(num+1.);
-			flowr(gr, u, v, w, xx, yy, zz, bx, by, bz,r0,ss);
-			flowr(gr,-u,-v,-w, xx, yy, zz, bx, by, bz,r0,ss);
+			flowr(gr, s*u, s*v, s*w, xx, yy, zz, bx, by, bz,r0,ss);
 		}
 	}
 	gr->EndGroup();
diff --git a/src/volume.cpp b/src/volume.cpp
index e47316a..1e01b98 100644
--- a/src/volume.cpp
+++ b/src/volume.cpp
@@ -21,7 +21,8 @@
 #include "mgl2/volume.h"
 #include "mgl2/data.h"
 #include "mgl2/eval.h"
-#include <vector>
+#include "mgl2/base.h"
+//#include <vector>
 //-----------------------------------------------------------------------------
 //
 //	CloudQ series
@@ -30,8 +31,7 @@
 void MGL_EXPORT mgl_cloud_xyz(HMGL gr, HCDT x, HCDT y, HCDT z, HCDT a, const char *sch, const char *opt)
 {
 	if(!(gr->GetQuality()&3))	return;	// do nothing in fast_draw
-	long i,j,k,n=a->GetNx(),m=a->GetNy(),l=a->GetNz();
-	register long i0;
+	long n=a->GetNx(),m=a->GetNy(),l=a->GetNz();
 	bool both = mgl_isboth(x,y,z,a);
 	if(mgl_check_dim3(gr,both,x,y,z,a,0,"Cloud"))	return;
 
@@ -50,7 +50,6 @@ void MGL_EXPORT mgl_cloud_xyz(HMGL gr, HCDT x, HCDT y, HCDT z, HCDT a, const cha
 	bool inv = mglchr(sch,'i');
 	bool dot = mglchr(sch,'.');
 	alpha /= pow(n/tx*m/ty*l/tz,1./3)/20;
-	mreal aa,bb;
 	if(alpha>1)	alpha = 1;
 	long ss = gr->AddTexture(sch);
 
@@ -58,24 +57,29 @@ void MGL_EXPORT mgl_cloud_xyz(HMGL gr, HCDT x, HCDT y, HCDT z, HCDT a, const cha
 	n /= tx;	m /= ty;	l /= tz;
 	long *pos=new long[n*m*l];
 	gr->Reserve(n*m*l);
-	mglPoint p,q=mglPoint(NAN);
-	for(k=0;k<l;k++)	for(j=0;j<m;j++)	for(i=0;i<n;i++)
+	mglPoint q=mglPoint(NAN);
+#pragma omp parallel for collapse(3)
+	for(long k=0;k<l;k++)	for(long j=0;j<m;j++)	for(long i=0;i<n;i++)
 	{
-		if(gr->Stop)	{	delete []pos;	return;	}
-		p = both ? mglPoint(x->v(i*tx,j*ty,k*tz),y->v(i*tx,j*ty,k*tz),z->v(i*tx,j*ty,k*tz)) : mglPoint(x->v(i*tx),y->v(j*ty),z->v(k*tz));
-		aa = gr->GetA(a->v(i*tx,j*ty,k*tz));
-		bb = inv ? (1-aa)*(1-aa)*alpha : aa*aa*alpha;
+		if(gr->Stop)	continue;
+		mglPoint p = both ? mglPoint(x->v(i*tx,j*ty,k*tz),y->v(i*tx,j*ty,k*tz),z->v(i*tx,j*ty,k*tz)) : mglPoint(x->v(i*tx),y->v(j*ty),z->v(k*tz));
+		mreal aa = gr->GetA(a->v(i*tx,j*ty,k*tz));
+		mreal bb = inv ? (1-aa)*(1-aa)*alpha : aa*aa*alpha;
 		pos[i+n*(j+m*k)] = gr->AddPnt(p,gr->GetC(ss,aa,false),q,bb);
 	}
-	if(dot)	for(i=0;i<n*m*l;i++)	gr->mark_plot(pos[i],'.');
-	else	for(i=0;i<n;i++)	for(j=0;j<m;j++)	for(k=0;k<l;k++)
-	{
-		if(gr->Stop)	{	delete []pos;	return;	}
-		i0 = i+n*(j+m*k);
-		if(i<n-1 && j<m-1)	gr->quad_plot(pos[i0],pos[i0+1],pos[i0+n],pos[i0+n+1]);
-		if(i<n-1 && k<l-1)	gr->quad_plot(pos[i0],pos[i0+1],pos[i0+n*m],pos[i0+n*m+1]);
-		if(k<l-1 && j<m-1)	gr->quad_plot(pos[i0],pos[i0+n],pos[i0+n*m],pos[i0+n+n*m]);
-	}
+	if(dot)
+#pragma omp parallel for
+		for(long i=0;i<n*m*l;i++)	gr->mark_plot(pos[i],'.');
+	else
+#pragma omp parallel for collapse(3)
+		for(long k=0;k<l;k++)	for(long j=0;j<m;j++)	for(long i=0;i<n;i++)
+		{
+			if(gr->Stop)	continue;
+			register long i0 = i+n*(j+m*k);
+			if(i<n-1 && j<m-1)	gr->quad_plot(pos[i0],pos[i0+1],pos[i0+n],pos[i0+n+1]);
+			if(i<n-1 && k<l-1)	gr->quad_plot(pos[i0],pos[i0+1],pos[i0+n*m],pos[i0+n*m+1]);
+			if(k<l-1 && j<m-1)	gr->quad_plot(pos[i0],pos[i0+n],pos[i0+n*m],pos[i0+n+n*m]);
+		}
 	delete []pos;	gr->EndGroup();
 }
 //-----------------------------------------------------------------------------
@@ -154,15 +158,15 @@ inline mreal MGL_NO_EXPORT mgl_cos_pp(const mglPoint *kk,long i0,long i1,long i2
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_surf3_plot(HMGL gr, long n,long m,long *kx1,long *kx2,long *ky1,long *ky2, long *kz, std::vector<mglPoint> kk, int wire)
 {
-	register long i,j,k,i0,ii,jj;
 	long id[12],us[12],pd[12],ni;
 	mglPoint pp[12];
 	mreal d,d0;
 
-	for(i=0;i<n-1;i++)	for(j=0;j<m-1;j++)
+#pragma omp parallel for private(id,us,pd,pp,ni,d,d0) collapse(2)
+	for(long j=0;j<m-1;j++)	for(long i=0;i<n-1;i++)
 	{
-		if(gr->Stop)	return;
-		i0 = i+n*j;
+		if(gr->Stop)	continue;
+		register long i0 = i+n*j,ii,jj,k;
 		// find ID of points of Surf3 intersection with cell i0
 		memset(id,-1,12*sizeof(long));	ni = 0;
 		if(kx1[i0]>=0)		id[ni++] = kx1[i0];
@@ -253,7 +257,7 @@ void MGL_EXPORT mgl_surf3_xyz_val(HMGL gr, double val, HCDT x, HCDT y, HCDT z, H
 	kz  = new long[n*m];
 	mreal c=gr->GetC(ss,val);
 	std::vector<mglPoint> kk;
-	kk.reserve(n*m*l);
+//	kk.reserve(n*m*l);
 
 	mglPoint p,q,u, p0;
 	mreal a0;
@@ -263,10 +267,10 @@ void MGL_EXPORT mgl_surf3_xyz_val(HMGL gr, double val, HCDT x, HCDT y, HCDT z, H
 		memcpy(ky1,ky2,n*m*sizeof(long));	memset(ky2,-1,n*m*sizeof(long));
 		memset(kz ,-1,n*m*sizeof(long));
 		gr->Reserve(n*m);	gr->Reserve(n*m);
+//#pragma omp parallel for collapse(2)	// NOTE: this part require a lot of memory for OpenMP. Omit it.
 		for(j=0;j<m;j++)	for(i=0;i<n;i++)
 		{
-			if(gr->Stop)	{	delete []kx1;	delete []kx2;	delete []ky1;
-								delete []ky2;	delete []kz;	return;	}
+			if(gr->Stop)	continue;
 			i1 = i+n*j;		a0 = a->v(i,j,k);
 			p0 = both?mglPoint(x->v(i,j,k), y->v(i,j,k), z->v(i,j,k)) : mglPoint(x->v(i), y->v(j), z->v(k));
 			if(i<n-1)
@@ -414,6 +418,7 @@ void MGL_EXPORT mgl_surf3a_xyz_val(HMGL gr, double val, HCDT x, HCDT y, HCDT z,
 		memcpy(ky1,ky2,n*m*sizeof(long));	memset(ky2,-1,n*m*sizeof(long));
 		memset(kz ,-1,n*m*sizeof(long));
 		gr->Reserve(n*m);	gr->Reserve(n*m);
+//#pragma omp parallel for collapse(2)	// NOTE: this part require a lot of memory for OpenMP. Omit it.
 		for(j=0;j<m;j++)	for(i=0;i<n;i++)
 		{
 			if(gr->Stop)	{	delete []kx1;	delete []kx2;	delete []ky1;
@@ -582,6 +587,7 @@ void MGL_EXPORT mgl_surf3c_xyz_val(HMGL gr, double val, HCDT x, HCDT y, HCDT z,
 		memcpy(ky1,ky2,n*m*sizeof(long));	memset(ky2,-1,n*m*sizeof(long));
 		memset(kz ,-1,n*m*sizeof(long));
 		gr->Reserve(n*m);	gr->Reserve(n*m);
+//#pragma omp parallel for collapse(2)	// NOTE: this part require a lot of memory for OpenMP. Omit it.
 		for(j=0;j<m;j++)	for(i=0;i<n;i++)
 		{
 			if(gr->Stop)	{	delete []kx1;	delete []kx2;	delete []ky1;
@@ -719,29 +725,32 @@ void MGL_NO_EXPORT mgl_beam_md(HMGL gr, double val, const mglData *tr, const mgl
 	if(tr->nx<3 || tr->ny<n || g1->nx<3 || g1->ny<n || g2->nx<3 || g2->ny<n)
 	{	gr->SetWarn(mglWarnDim,"Beam");	return;	}
 	mglData x(a),y(a),z(a),b(a);
-	register long i,j,k,i0;
-	mreal asum=1, asum0=1, amax, aa;
+	mreal asum=1, asum0=0, amax, aa;
 	r = fabs(r);
-	if(flag & 4)	for(j=0;j<m*l;j++)	asum0 += a->a[j]*a->a[j];
+	if(flag & 4)
+#pragma omp parallel for reduction(+:asum0)
+		for(long j=0;j<m*l;j++)	asum0 += a->a[j]*a->a[j];
 	if(asum0==0)	{	gr->SetWarn(mglWarnZero,"Beam");	return;	}
-	for(i=0;i<n;i++)
+	for(long i=0;i<n;i++)
 	{
 		asum=amax=0;
 		if(flag & 4)
 		{
-			for(j=0;j<m*l;j++)
+			for(long j=0;j<m*l;j++)
 			{
 				aa = a->a[j+m*l*i];
 				asum += aa*aa;
 				amax = amax>aa ? amax : aa;
 			}
 			if(amax==0)	{	asum=0;	amax=1;	}
-			for(j=0;j<m*l;j++)	b.a[j+m*l*i] = b.a[j+m*l*i]*sqrt(asum/asum0)/amax;
+#pragma omp parallel for
+			for(long j=0;j<m*l;j++)	b.a[j+m*l*i] = b.a[j+m*l*i]*sqrt(asum/asum0)/amax;
 		}
-		for(j=0;j<m;j++)	for(k=0;k<l;k++)
+#pragma omp parallel for collapse(2)
+		for(long k=0;k<l;k++)	for(long j=0;j<m;j++)
 		{
-			if(gr->Stop)	return;
-			i0 = j+m*(k+l*i);
+			if(gr->Stop)	continue;
+			register long i0 = j+m*(k+l*i);
 			if(flag & 1)
 			{
 				x.a[i0] = 2*j/(m-1.)-1;
diff --git a/src/window.cpp b/src/window.cpp
index 80e7249..57c2dfa 100644
--- a/src/window.cpp
+++ b/src/window.cpp
@@ -95,6 +95,7 @@ void mglCanvasWnd::SetDrawFunc(int (*draw)(mglBase *gr, void *p), void *par, voi
 	LoadFunc = reload;
 
 	if(mgl_is_frames(this))	EndFrame();
+	if(n>=0)	SetCurFig(0);
 	setlocale(LC_NUMERIC, "");
 }
 //-----------------------------------------------------------------------------
diff --git a/texinfo/CMakeLists.txt b/texinfo/CMakeLists.txt
index d316608..20ad882 100644
--- a/texinfo/CMakeLists.txt
+++ b/texinfo/CMakeLists.txt
@@ -1,14 +1,14 @@
-if(MGL_HAVE_DOC)
+	set(MGL_EXTRA light)
 	set(MGL_PNG alpha area aspect axial axis barh bars belt boxplot
 		box boxs candle chart cloud colorbar combined cones conta contd
 		contfa contf contf_xyz cont contv cont_xyz curvcoor cut dat_diff
-		dat_extra densa dens dens_xyz dew dots error fall fit flow fonts
+		dat_extra densa dens dens_xyz dew dots error error2 fall fit flow fonts
 		fog grad hist inplot label legend loglog map mark mesh mirror
 		molecule parser pde pipe plot primitives projection qo2d radar region schemes
 		several_light solve stem step stereo stfa style surf3a surf3c surf3
 		surfa surfc surf table tape tens ternary textmark text ticks tile tiles
 		torus traj triangulation triplot tube type0 type1 type2 vect vecta venn
-		projection5 param1 param2 param3 paramv )
+		projection5 mask correl refill ohlc )
 	set(MGL_PNG_N )
 	set(MGL_PNG_S )
 	set(MGL_PNG_J )
@@ -22,9 +22,9 @@ if(MGL_HAVE_DOC)
 	file(MAKE_DIRECTORY ${MGL_OUT}/json)
 	file(MAKE_DIRECTORY ${MGL_OUT}/pdf)
 	file(COPY ${MGL_TEX}/qt.png ${MGL_TEX}/fltk.png ${MGL_TEX}/classes.png ${MGL_TEX}/emblem_sm.png ${MGL_TEX}/datadvance.png DESTINATION ${MGL_OUT})
-	file(COPY ${MGL_TEX}/toc_ru.html ${MGL_TEX}/toc_fr.html ${MGL_TEX}/toc_en.html ${MGL_TEX}/title.html ${MGL_TEX}/index.html ${MGL_TEX}/json.html ${MGL_TEX}/mathgl.js ${MGL_TEX}/gunzip.min.js ${MGL_TEX}/inflate.min.js DESTINATION ${MGL_OUT})
+	file(COPY ${MGL_TEX}/index.html ${MGL_TEX}/json.html ${MGL_TEX}/mathgl.js DESTINATION ${MGL_OUT})
 
-	set(UDAV_IMG udav_arg.png udav_calc.png udav_cmd.png udav_data.png 
+	set(UDAV_IMG udav_arg.png udav_calc.png udav_cmd.png udav_data.png
 		udav_gen_set.png udav_help.png udav_light.png udav_main.png udav_opt.png
 		udav_pen.png udav_prop.png udav_sch.png udav_txt.png udav_var.png)
 	foreach(SAMPLE ${UDAV_IMG})
@@ -34,7 +34,7 @@ if(MGL_HAVE_DOC)
 	foreach(SAMPLE ${MGL_PNG})
 		set(MGL_PNG_N ${MGL_PNG_N} ${MGL_OUT}/png/${SAMPLE}.png)
 		add_custom_command(OUTPUT ${MGL_OUT}/png/${SAMPLE}.png
-			COMMAND mgl_example -kind=${SAMPLE}
+			COMMAND mgl_example -kind=${SAMPLE} -web
 			DEPENDS mgl_example
 			WORKING_DIRECTORY ${MGL_OUT}/png )
 		set(MGL_PNG_S ${MGL_PNG_S} ${MGL_OUT}/small/${SAMPLE}-sm.png)
@@ -42,134 +42,158 @@ if(MGL_HAVE_DOC)
 			COMMAND mgl_example -kind=${SAMPLE} -mini
 			DEPENDS mgl_example
 			WORKING_DIRECTORY ${MGL_OUT}/small )
+if(MGL_HAVE_DOC_JSON)
 		set(MGL_PNG_J ${MGL_PNG_J} ${MGL_OUT}/json/${SAMPLE}.json)
 		add_custom_command(OUTPUT ${MGL_OUT}/json/${SAMPLE}.json
 			COMMAND mgl_example -json -kind=${SAMPLE}
 #			COMMAND ${CMAKE_BINARY_DIR}/examples/mgl_example -json -kind=${SAMPLE}
 			DEPENDS mgl_example
 			WORKING_DIRECTORY ${MGL_OUT}/json )
-if(MGL_HAVE_PDF)
+endif(MGL_HAVE_DOC_JSON)
+if(MGL_HAVE_DOC_PRC)
 		set(MGL_PNG_D ${MGL_PNG_D} ${MGL_OUT}/pdf/${SAMPLE}.pdf)
 		add_custom_command(OUTPUT ${MGL_OUT}/pdf/${SAMPLE}.pdf
 			COMMAND mgl_example -pdf -kind=${SAMPLE}
 			DEPENDS mgl_example
 			WORKING_DIRECTORY ${MGL_OUT}/pdf )
-endif(MGL_HAVE_PDF)
+endif(MGL_HAVE_DOC_PRC)
 	endforeach(SAMPLE)
 
-	set(list_texi_files_en overview_en.texi example_en.texi ex_mgl_en.texi parse_en.texi formats_en.texi udav_en.texi symbols_en.texi
-		core_en.texi concept_en.texi widget_en.texi data_en.texi other_en.texi appendix_en.texi fdl.texi )
-	set(list_texi_files_ru overview_ru.texi example_ru.texi ex_mgl_ru.texi parse_ru.texi formats_ru.texi udav_ru.texi symbols_ru.texi
-		core_ru.texi concept_ru.texi widget_ru.texi data_ru.texi other_ru.texi appendix_ru.texi fdl.texi )
+	foreach(SAMPLE ${MGL_EXTRA})
+		set(MGL_PNG_N ${MGL_PNG_N} ${MGL_OUT}/png/${SAMPLE}.png)
+		add_custom_command(OUTPUT ${MGL_OUT}/png/${SAMPLE}.png
+			COMMAND mgl_example -kind=${SAMPLE} -web
+			DEPENDS mgl_example
+			WORKING_DIRECTORY ${MGL_OUT}/png )
+		set(MGL_PNG_S ${MGL_PNG_S} ${MGL_OUT}/small/${SAMPLE}-sm.png)
+		add_custom_command(OUTPUT ${MGL_OUT}/small/${SAMPLE}-sm.png
+			COMMAND mgl_example -kind=${SAMPLE} -mini
+			DEPENDS mgl_example
+			WORKING_DIRECTORY ${MGL_OUT}/small )
+	endforeach(SAMPLE)
 
-# 	add_custom_command(OUTPUT ${MGL_OUT}/web_en/web_en.html
-# 		COMMAND ${findth} -I=${MGL_OUT}/png --split=section -o web_en ${MGL_TEX}/web_en.texi
-# 		DEPENDS web_en.texi ${MGL_PNG_S} ${MGL_PNG_J}
-# 		WORKING_DIRECTORY ${MGL_OUT}
-# 	)
+	set(list_texi_files_en overview_en.texi example_en.texi ex_mgl_en.texi parse_en.texi formats_en.texi udav_en.texi symbols_en.texi core_en.texi concept_en.texi widget_en.texi data_en.texi other_en.texi appendix_en.texi fdl.texi version.texi time.texi time_big.texi )
+	set(list_texi_files_ru overview_ru.texi example_ru.texi ex_mgl_ru.texi parse_ru.texi formats_ru.texi udav_ru.texi symbols_ru.texi core_ru.texi concept_ru.texi widget_ru.texi data_ru.texi other_ru.texi appendix_ru.texi fdl.texi version.texi time.texi time_big.texi )
 
 	add_custom_command(OUTPUT ${MGL_OUT}/mathgl_en.info
-		COMMAND ${findmi} --no-validate ${MGL_TEX}/mathgl_en.texi
+		COMMAND ${findmi} ${MGL_TEX}/mathgl_en.texi
 		DEPENDS ${list_texi_files_en} mathgl_en.texi ${MGL_PNG_N}
 		WORKING_DIRECTORY ${MGL_OUT}
 	)
-	add_custom_command(OUTPUT ${MGL_OUT}/mathgl_en/mathgl_en.html
-		COMMAND ${findth} -I=${MGL_OUT}/png --split=section -o mathgl_en ${MGL_TEX}/mathgl_en.texi
-		DEPENDS ${list_texi_files_en} mathgl_en.texi ${MGL_PNG_N}
+	add_custom_command(OUTPUT ${MGL_OUT}/mathgl_ru.info
+		COMMAND ${findmi} ${MGL_TEX}/mathgl_ru.texi
+		DEPENDS ${list_texi_files_ru} mathgl_ru.texi ${MGL_PNG_N}
 		WORKING_DIRECTORY ${MGL_OUT}
 	)
-	add_custom_command(OUTPUT ${MGL_OUT}/doc_en/doc_en.html
-		COMMAND ${findth} -I=${MGL_OUT}/png --split=section --frames -o doc_en ${MGL_TEX}/doc_en.texi
-		DEPENDS ${list_texi_files_en} doc_en.texi ${MGL_PNG_N} web_en.texi ${MGL_PNG_S} ${MGL_PNG_J} ${MGL_PNG_D}
+
+	add_custom_command(OUTPUT ${MGL_OUT}/mathgl_en.html
+		COMMAND ${findth} ${th_opt} -I ${MGL_OUT} --no-split ${MGL_TEX}/mathgl_en.texi
+		DEPENDS ${list_texi_files_en} mathgl_en.texi ${MGL_PNG_N}
 		WORKING_DIRECTORY ${MGL_OUT}
 	)
 	add_custom_command(OUTPUT ${MGL_OUT}/mgl_en.html
-		COMMAND ${findth} -I=${MGL_OUT} --split=no -o mgl_en.html ${MGL_TEX}/mgl_en.texi
+		COMMAND ${findth} ${th_opt} -I ${MGL_OUT} --no-split ${MGL_TEX}/mgl_en.texi
 		DEPENDS ${list_texi_files_en} mgl_en.texi ${MGL_PNG_N}
 		WORKING_DIRECTORY ${MGL_OUT}
 	)
-
-	add_custom_command(OUTPUT ${MGL_OUT}/mathgl_en.pdf
-		COMMAND ${findtp} -I ${MGL_OUT}/png ${MGL_TEX}/mathgl_en.texi
-		COMMAND ${findtp} -I ${MGL_OUT}/png ${MGL_TEX}/mathgl_en.texi
-		COMMAND ${findtp} -I ${MGL_OUT}/png ${MGL_TEX}/mathgl_en.texi
-		DEPENDS ${list_texi_files_en} mathgl_en.texi ${MGL_PNG_N}
+	add_custom_command(OUTPUT ${MGL_OUT}/mathgl_ru.html
+		COMMAND ${findth} ${th_opt} -I=${MGL_OUT} --no-split ${MGL_TEX}/mathgl_ru.texi
+		DEPENDS ${list_texi_files_ru} mathgl_ru.texi ${MGL_PNG_N}
 		WORKING_DIRECTORY ${MGL_OUT}
 	)
-
-	add_custom_command(OUTPUT ${MGL_OUT}/mgl_en.pdf
-		COMMAND ${findtp} -I ${MGL_OUT}/png ${MGL_TEX}/mgl_en.texi
-		COMMAND ${findtp} -I ${MGL_OUT}/png ${MGL_TEX}/mgl_en.texi
-		COMMAND ${findtp} -I ${MGL_OUT}/png ${MGL_TEX}/mgl_en.texi
-		DEPENDS ${list_texi_files_en} mgl_en.texi ${MGL_PNG_N}
+	add_custom_command(OUTPUT ${MGL_OUT}/mgl_ru.html
+		COMMAND ${findth} ${th_opt} -I=${MGL_OUT} --no-split ${MGL_TEX}/mgl_ru.texi
+		DEPENDS ${list_texi_files_ru} mgl_ru.texi ${MGL_PNG_N}
 		WORKING_DIRECTORY ${MGL_OUT}
 	)
 
-# 	add_custom_command(OUTPUT ${MGL_OUT}/web_ru/web_ru.html
-# 		COMMAND ${findth} -I=${MGL_OUT}/png --split=section -o web_ru ${MGL_TEX}/web_ru.texi
-# 		DEPENDS web_ru.texi ${MGL_PNG_S} ${MGL_PNG_J}
-# 		WORKING_DIRECTORY ${MGL_OUT}
-# 	)
-
-	add_custom_command(OUTPUT ${MGL_OUT}/mathgl_ru.info
-		COMMAND ${findmi} --no-validate ${MGL_TEX}/mathgl_ru.texi
-		DEPENDS ${list_texi_files_ru} mathgl_ru.texi ${MGL_PNG_N}
+	add_custom_command(OUTPUT ${site_en}
+		COMMAND ${findth} ${th_opt} -I=${MGL_OUT}/png --split=node -o doc_en ${MGL_TEX}/doc_en.texi
+		DEPENDS ${list_texi_files_en} doc_en.texi ${MGL_PNG_N} web_en.texi ${MGL_PNG_S} ${MGL_PNG_J} ${MGL_PNG_D}
 		WORKING_DIRECTORY ${MGL_OUT}
 	)
-	add_custom_command(OUTPUT ${MGL_OUT}/mathgl_ru/mathgl_ru.html
-		COMMAND ${findth} -I=${MGL_OUT}/png --split=section -o mathgl_ru ${MGL_TEX}/mathgl_ru.texi
-		DEPENDS ${list_texi_files_ru} mathgl_ru.texi ${MGL_PNG_N}
+	add_custom_command(OUTPUT ${site_ru}
+		COMMAND ${findth} ${th_opt} -I=${MGL_OUT}/png --split=node -o doc_ru ${MGL_TEX}/doc_ru.texi
+		DEPENDS ${list_texi_files_ru} doc_ru.texi ${MGL_PNG_N} web_ru.texi ${MGL_PNG_S} ${MGL_PNG_J} ${MGL_PNG_D}
 		WORKING_DIRECTORY ${MGL_OUT}
 	)
-	add_custom_command(OUTPUT ${MGL_OUT}/doc_ru/doc_ru.html
-		COMMAND ${findth} -I=${MGL_OUT}/png --split=section --frames -o doc_ru ${MGL_TEX}/doc_ru.texi
-		DEPENDS ${list_texi_files_ru} doc_ru.texi ${MGL_PNG_N} web_ru.texi ${MGL_PNG_S} ${MGL_PNG_J} ${MGL_PNG_D}
+
+	add_custom_command(OUTPUT ${MGL_OUT}/mathgl_en.pdf
+		COMMAND ${findtp} ${MGL_TEX}/mathgl_en.texi
+		COMMAND ${findtp} ${MGL_TEX}/mathgl_en.texi
+		COMMAND ${findtp} ${MGL_TEX}/mathgl_en.texi
+		DEPENDS ${list_texi_files_en} mathgl_en.texi ${MGL_PNG_N}
 		WORKING_DIRECTORY ${MGL_OUT}
 	)
-	add_custom_command(OUTPUT ${MGL_OUT}/mgl_ru.html
-		COMMAND ${findth} -I=${MGL_OUT} --split=no -o mgl_ru.html ${MGL_TEX}/mgl_ru.texi
-		DEPENDS ${list_texi_files_ru} mgl_ru.texi ${MGL_PNG_N}
+	add_custom_command(OUTPUT ${MGL_OUT}/mgl_en.pdf
+		COMMAND ${findtp} ${MGL_TEX}/mgl_en.texi
+		COMMAND ${findtp} ${MGL_TEX}/mgl_en.texi
+		COMMAND ${findtp} ${MGL_TEX}/mgl_en.texi
+		DEPENDS ${list_texi_files_en} mgl_en.texi ${MGL_PNG_N}
 		WORKING_DIRECTORY ${MGL_OUT}
 	)
 
 	add_custom_command(OUTPUT ${MGL_OUT}/mathgl_ru.pdf
-		COMMAND ${findtp} -I ${MGL_OUT}/png ${MGL_TEX}/mathgl_ru.texi
-		COMMAND ${findtp} -I ${MGL_OUT}/png ${MGL_TEX}/mathgl_ru.texi
-		COMMAND ${findtp} -I ${MGL_OUT}/png ${MGL_TEX}/mathgl_ru.texi
+		COMMAND ${findtp} ${MGL_TEX}/mathgl_ru.texi
+		COMMAND ${findtp} ${MGL_TEX}/mathgl_ru.texi
+		COMMAND ${findtp} ${MGL_TEX}/mathgl_ru.texi
 		DEPENDS ${list_texi_files_ru} mathgl_ru.texi ${MGL_PNG_N}
 		WORKING_DIRECTORY ${MGL_OUT}
 	)
+	add_custom_command(OUTPUT ${MGL_OUT}/mgl_ru.pdf
+		COMMAND ${findtp} ${MGL_TEX}/mgl_ru.texi
+		COMMAND ${findtp} ${MGL_TEX}/mgl_ru.texi
+		COMMAND ${findtp} ${MGL_TEX}/mgl_ru.texi
+		DEPENDS ${list_texi_files_en} mgl_ru.texi ${MGL_PNG_N}
+		WORKING_DIRECTORY ${MGL_OUT}
+	)
 
-	add_custom_target(documentation ALL
-		DEPENDS ${MGL_OUT}/mathgl_en.info
-		DEPENDS ${MGL_OUT}/mgl_en.pdf
-		DEPENDS ${MGL_OUT}/mathgl_en.pdf
+	if(MGL_HAVE_DOC_INFO)
+		add_custom_target(doc_info ALL
+			DEPENDS ${MGL_OUT}/mathgl_en.info
+			DEPENDS ${MGL_OUT}/mathgl_ru.info
+		)
+# TODO: try to install all mathgl*.info* in future!!!
+		install(FILES ${MGL_OUT}/mathgl_en.info ${MGL_OUT}/mathgl_en.info-1 ${MGL_OUT}/mathgl_en.info-2 ${MGL_OUT}/mathgl_en.info-3 DESTINATION ${MGL_INFO_PATH})
+	endif(MGL_HAVE_DOC_INFO)
+	
+	if(MGL_HAVE_DOC_HTML)
+		add_custom_target(doc_html ALL
 		DEPENDS ${MGL_OUT}/mgl_en.html
-		DEPENDS ${MGL_OUT}/mathgl_en/mathgl_en.html
+		DEPENDS ${MGL_OUT}/mathgl_en.html
+		DEPENDS ${MGL_OUT}/mgl_ru.html
+		DEPENDS ${MGL_OUT}/mathgl_ru.html
+		)
+		install(FILES ${MGL_TEX}/qt.png ${MGL_TEX}/fltk.png ${MGL_TEX}/classes.png ${MGL_TEX}/datadvance.png DESTINATION ${MGL_DOC_PATH})
+		install(FILES ${MGL_OUT}/mathgl_en.html ${MGL_OUT}/mgl_en.html ${MGL_OUT}/mathgl_ru.html ${MGL_OUT}/mgl_ru.html DESTINATION ${MGL_DOC_PATH})
+		install(DIRECTORY ${MGL_OUT}/png DESTINATION ${MGL_DOC_PATH})
+		install(DIRECTORY ${MGL_OUT}/udav DESTINATION ${MGL_DOC_PATH})
+	endif(MGL_HAVE_DOC_HTML)
 
-		DEPENDS ${MGL_OUT}/doc_en/doc_en.html
-# 		DEPENDS ${MGL_OUT}/web_en/web_en.html
+	if(MGL_HAVE_DOC_SITE)
+		add_custom_target(doc_site ALL
+		DEPENDS ${site_en}
+		DEPENDS ${site_ru}
+		)
+	endif(MGL_HAVE_DOC_SITE)
 
-# 		DEPENDS ${MGL_OUT}/mathgl_ru.info
-# 		DEPENDS ${MGL_OUT}/mathgl_ru.pdf
-		DEPENDS ${MGL_OUT}/mgl_ru.html
-		DEPENDS ${MGL_OUT}/mathgl_ru/mathgl_ru.html
+	if(MGL_HAVE_DOC_PDF_EN)
+		add_custom_target(doc_en ALL
+			DEPENDS ${MGL_OUT}/mgl_en.pdf
+			DEPENDS ${MGL_OUT}/mathgl_en.pdf
+		)
+		install(FILES ${MGL_OUT}/mathgl_en.pdf DESTINATION ${MGL_DOC_PATH})
+	endif(MGL_HAVE_DOC_PDF_EN)
+	
+	if(MGL_HAVE_DOC_PDF_RU)
+		add_custom_target(doc_ru ALL
+#			DEPENDS ${MGL_OUT}/mgl_ru.pdf
+#			DEPENDS ${MGL_OUT}/mathgl_ru.pdf
+		)
+#		install(FILES ${MGL_OUT}/mathgl_ru.pdf DESTINATION ${MGL_DOC_PATH})
+	endif(MGL_HAVE_DOC_PDF_RU)
+
+	set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "doc_en;doc_ru;./mathgl*.*;./mgl*.*")
 
-		DEPENDS ${MGL_OUT}/doc_ru/doc_ru.html
-# 		DEPENDS ${MGL_OUT}/web_ru/web_ru.html
-	)
-# 	add_custom_target(clean
-# 		COMMAND rm -f * */*
-# 		WORKING_DIRECTORY ${MGL_OUT}
-# 	)
-	set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "doc_en;mathgl_en;web_en;./mathgl*.*;small/*.*;png/*.*;json/*.*")
-	install(FILES ${MGL_TEX}/qt.png ${MGL_TEX}/fltk.png ${MGL_TEX}/classes.png ${MGL_TEX}/datadvance.png DESTINATION ${MGL_DOC_PATH})
-	install(FILES ${MGL_OUT}/mathgl_en.pdf ${MGL_OUT}/mgl_en.html DESTINATION ${MGL_DOC_PATH})
-	install(DIRECTORY ${MGL_OUT}/mathgl_en DESTINATION ${MGL_DOC_PATH})
-	install(DIRECTORY ${MGL_OUT}/png DESTINATION ${MGL_DOC_PATH})
-	install(DIRECTORY ${MGL_OUT}/udav DESTINATION ${MGL_DOC_PATH})
 	install(FILES ${MGL_TEX}/mglconv.1 ${MGL_TEX}/mglview.1 ${MGL_TEX}/udav.1 ${MGL_TEX}/mgl.cgi.1 DESTINATION ${MGL_MAN_PATH}/man1)
 	install(FILES ${MGL_TEX}/mgl.5 DESTINATION ${MGL_MAN_PATH}/man5)
-# TODO: try to install all mathgl*.info* in future!!!
-	install(FILES ${MGL_OUT}/mathgl_en.info ${MGL_OUT}/mathgl_en.info-1 ${MGL_OUT}/mathgl_en.info-2 DESTINATION ${MGL_INFO_PATH})
-endif(MGL_HAVE_DOC)
diff --git a/texinfo/appendix_en.texi b/texinfo/appendix_en.texi
index 7841b66..ed1cb27 100644
--- a/texinfo/appendix_en.texi
+++ b/texinfo/appendix_en.texi
@@ -1,3 +1,5 @@
+ at nav{}
+
 The full list of TeX-like commands recognizable by MathGL is shown below. If command is not recognized then it will be printed as is by ommitting @samp{\} symbol. For example, @samp{\#} produce ``#'', @samp{\\} produce ``\'', @samp{\qq} produce ``qq''.
 @c All commands are typed without @samp{\} sign.
 
diff --git a/texinfo/appendix_ru.texi b/texinfo/appendix_ru.texi
index beb6c26..16c4c34 100644
--- a/texinfo/appendix_ru.texi
+++ b/texinfo/appendix_ru.texi
@@ -1,3 +1,5 @@
+ at nav{}
+
 Ниже приведен полный список TeX-их команд, распознаваемых MathGL. Если команда была не распознана, то она будет напечатана как есть с пропущенным символом @samp{\}. Например, @samp{\#} выдаст ``#'', @samp{\\} выдаст ``\'', @samp{\qq} выдаст ``qq''.
 
 @strong{Положение символов}: _, ^, @@.
diff --git a/texinfo/concept_en.texi b/texinfo/concept_en.texi
index 0adc01e..455d49b 100644
--- a/texinfo/concept_en.texi
+++ b/texinfo/concept_en.texi
@@ -1,4 +1,5 @@
 @chapter General concepts
+ at nav{}
 
 The set of MathGL features is rather rich -- just the number of basic graphics types
 is larger than 50. Also there are functions for data handling, plot setup and so on. In spite of it I tried to keep a similar style in function names and in the order of arguments. Mostly it is
@@ -37,6 +38,7 @@ In addition to the general concepts I want to comment on some non-trivial or les
 @external{}
 @node Coordinate axes, Color styles, , General concepts
 @section Coordinate axes
+ at nav{}
 
 Two axis representations are used in MathGL. The first one consists of normalizing coordinates of data points in a box @var{Min}x at var{Max} (see @ref{Axis settings}). If @code{SetCut()} is @code{true} then the outlier points are omitted, otherwise they are projected to the bounding box (see @ref{Cutting}). Also, the point will be omitted if it lies inside the box defined by @code{SetCutBox()} or if the value of formula @code{CutOff()} is nonzero for its coordinates. After that, transforma [...]
 
@@ -50,6 +52,7 @@ The form (appearence) of tick labels is controlled by @code{SetTicks()} function
 @external{}
 @node Color styles, Line styles, Coordinate axes, General concepts
 @section Color styles
+ at nav{}
 
 Base colors are defined by one of symbol @samp{wkrgbcymhRGBCYMHWlenupqLENUPQ}.
 @ifhtml
@@ -63,7 +66,7 @@ The color types are: @samp{k} -- black, @samp{r} -- red, @samp{R} -- dark red, @
 
 You can also use ``bright'' colors. The ``bright'' color contain 2 symbols in brackets @samp{@{cN@}}: first one is the usual symbol for color id, the second one is a digit for its brightness. The digit can be in range @samp{1}... at samp{9}. Number @samp{5} corresponds to a normal color, @samp{1} is a very dark version of the color (practically black), and @samp{9} is a very bright version of the color (practically white). For example, the colors can be @samp{@{b2@}} @samp{@{b7@}} @samp{@{r [...]
 
-Finally, you can specify RGB or RGBA values of a color using format @samp{@{xRRGGBB@}} or @samp{@{xRRGGBBAA@}} correspondingly. For example, @samp{@{xFF9966@}} give you 
+Finally, you can specify RGB or RGBA values of a color using format @samp{@{xRRGGBB@}} or @samp{@{xRRGGBBAA@}} correspondingly. For example, @samp{@{xFF9966@}} give you
 @ifhtml
 @html
 <span style="color: rgb(255, 153, 102);">melone</span> color.
@@ -77,6 +80,7 @@ melone color.
 @external{}
 @node Line styles, Color scheme, Color styles, General concepts
 @section Line styles
+ at nav{}
 
 @cindex Line style
 @cindex Mark style
@@ -106,6 +110,7 @@ One may specify to draw a special symbol (an arrow) at the beginning and at the
 @external{}
 @node Color scheme, Font styles, Line styles, General concepts
 @section Color scheme
+ at nav{}
 
 @cindex Color scheme
 
@@ -122,10 +127,23 @@ For more precise coloring, you can change default (equidistant) position of colo
 When coloring by @emph{coordinate} (used in @ref{map}), the final color is determined by the position of the point in 3d space and is calculated from formula c=x*c[1] + y*c[2]. Here, c[1], c[2] are the first two elements of color array; x, y are normalized to axis range coordinates of the point.
 @c This type of coloring is useful for isosurface plot where color may show the exact position of a piece of surface.
 
+Additionally, MathGL can apply mask to face filling at bitmap rendering. The kind of mask is specified by one of symbols @samp{-+=;oOsS~<>jdD*^} in color scheme. Mask can be rotated by arbitrary angle by command @ref{mask} or by three predefined values +45, -45 and 90 degree by symbols @samp{\/I} correspondingly. Examples of predefined masks are shown on the figure below.
+
+ at pfig{mask, Example of masks for face coloring.}
+
+However, you can redefine mask for one symbol by specifying new matrix of size 8*8 as second argument for @ref{mask} command. For example, the right-down subplot on the figure above is produced by code@*
+ at ifclear UDAV
+ at code{gr->SetMask('+', "ff00182424f80000");	gr->Dens(a,"3+");}
+ at end ifclear
+ at ifset UDAV
+ at code{mask '+' 'ff00182424f80000':dens a '3+'}
+ at end ifset
+
 @c ------------------------------------------------------------------
 @external{}
 @node Font styles, Textual formulas, Color scheme, General concepts
 @section Font styles
+ at nav{}
 
 @cindex Font styles
 
@@ -166,6 +184,7 @@ The font size can be defined explicitly (if @var{size}>0) or relatively to a bas
 @external{}
 @node Textual formulas, Command options, Font styles, General concepts
 @section Textual formulas
+ at nav{}
 
 @cindex Textual formulas
 
@@ -218,6 +237,7 @@ There is no difference between lower or upper case in formulas. If argument valu
 @external{}
 @node  Command options, Interfaces, Textual formulas, General concepts
 @section Command options
+ at nav{}
 
 Command options allow the easy setup of the selected plot by changing global settings only for this plot. Each option start from symbol @samp{;}. Options work so that MathGL remember the current settings, change settings as it being set in the option, execute function and return the original settings back. So, the options are most usable for plotting functions.
 
@@ -279,6 +299,7 @@ Set the value to be used as additional numeric parameter in plotting command.
 @external{}
 @node Interfaces, , Command options, General concepts
 @section Interfaces
+ at nav{}
 
 @ifset UDAV
 You can use @code{mglParse} class for executing MGL scripts from different languages.
@@ -297,9 +318,10 @@ Finally, a special command language MGL (see @ref{MGL scripts}) was written for
 * C++ interface::
 @end menu
 
- at comment  @external{}
+ at external{}
 @node C interface, C++ interface, , Interfaces
 @subsection C/Fortran interface
+ at nav{}
 
 The C interface is a base for many other interfaces. It contains the pure C functions for most of the methods of MathGL classes. In distinction to C++ classes, C functions must have an argument HMGL (for graphics) and/or HMDT (for data arrays), which specifies the object for drawing or manipulating (changing). So, firstly, the user has to create this object by the function @code{mgl_create_*()} and has to delete it after the use by function @code{mgl_delete_*()}.
 
@@ -308,21 +330,30 @@ All C functions are described in the header file @code{#include <mgl2/mgl_cf.h>}
 @item
 @code{HMGL} --- Pointer to class @code{mglGraph} (@pxref{MathGL core}).
 @item
- at code{HMDT} --- Pointer to class @code{mglData} (@pxref{Data processing}).
+ at code{HCDT} --- Pointer to class @code{const mglDataA} (@pxref{Data processing}) --- constant data array.
+ at item
+ at code{HMDT} --- Pointer to class @code{mglData} (@pxref{Data processing}) --- data array of real numbers.
+ at item
+ at code{HADT} --- Pointer to class @code{mglDataC} (@pxref{Data processing}) --- data array of complex numbers.
+ at item
+ at code{HMPR} --- Pointer to class @code{mglParse} (@pxref{mglParse class}) --- MGL script parsing.
 @item
- at code{HMPR} --- Pointer to class @code{mglParse} (@pxref{mglParse class}).
+ at code{HMEX} --- Pointer to class @code{mglExpr} (@pxref{Evaluate expression}) --- textual formulas for real numbers.
+ at item
+ at code{HMAX} --- Pointer to class @code{mglExprC} (@pxref{Evaluate expression}) --- textual formulas for complex numbers.
 @end itemize
 These variables contain identifiers for graphics drawing objects and for the data objects.
 
-Fortran functions/subroutines have the same names as C functions. However, there is a difference. Variable of type @code{HMGL, HMDT} must be an integer with sufficient size (@code{integer*4} in the 32-bit operating system or @code{integer*8} in the 64-bit operating system). All C functions are subroutines in Fortran, which are called by operator @code{call}. The exceptions are functions, which return variables of types @code{HMGL} or @code{HMDT}. These functions should be declared as int [...]
+Fortran functions/subroutines have the same names as C functions. However, there is a difference. Variable of type @code{HMGL, HMDT} must be an integer with sufficient size (@code{integer*4} in the 32-bit operating system or @code{integer*8} in the 64-bit operating system). All C functions of type @code{void} are subroutines in Fortran, which are called by operator @code{call}. The exceptions are functions, which return variables of types @code{HMGL} or @code{HMDT}. These functions shoul [...]
 
- at comment  @external{}
+ at external{}
 @node C++ interface, , C interface, Interfaces
 @subsection C++/Python interface
+ at nav{}
 
 MathGL provides the interface to a set of languages via SWIG library. Some of these languages support classes. The typical example is Python -- which is named in this chapter's title. Exactly the same classes are used for high-level C++ API. Its feature is using only inline member-functions what make high-level API to be independent on compiler even for binary build.
 
-There are 3 classes in:
+There are 3 main classes in:
 @itemize
 @item @code{mglGraph}
 -- provide most plotting functions (see @ref{MathGL core}).
@@ -352,4 +383,3 @@ This becomes useful if you create many @code{mglData} objects, for example.
 @end ifclear
 
 @external{}
-
diff --git a/texinfo/concept_ru.texi b/texinfo/concept_ru.texi
index dc6030f..0e81550 100644
--- a/texinfo/concept_ru.texi
+++ b/texinfo/concept_ru.texi
@@ -1,4 +1,5 @@
 @chapter Основные принципы
+ at nav{}
 
 Возможности библиотеки MathGL довольно богаты -- число только основных типов графиков превышает 50 видов. Кроме того, есть функции для обработки данных, настройки вида графика и пр. и пр. Тем не менее, я старался придерживаться единого стиля в порядке аргументов функций и способе их ``настройки''. В основном все ниже сказанное относится к функциям рисования различных графиков.
 
@@ -35,6 +36,7 @@
 @external{}
 @node Coordinate axes, Color styles, , General concepts
 @section Оси координат
+ at nav{}
 
 Представление системы координат в MathGL состоит из двух частей. Вначале координаты нормируются в интервал @var{Min}x at var{Max} (@pxref{Axis settings}). Если флаг @code{SetCut()} установлен, то точки вне интервала отбрасываются, в противном случае, они проецируются на ограничивающий параллелепипед (см. @ref{Cutting}). Кроме того, отбрасываются точки внутри границ, определенных переменными @var{CutMin}x at var{CutMax} и точки, для которых значение функции @code{CutOff}() не равно нулю. После  [...]
 
@@ -48,6 +50,7 @@
 @external{}
 @node Color styles, Line styles, Coordinate axes, General concepts
 @section Цвета
+ at nav{}
 
 Base colors are defined by one of symbol @samp{wkrgbcymhRGBCYMHWlenupqLENUPQ}.
 @ifhtml
@@ -75,12 +78,13 @@ Base colors are defined by one of symbol @samp{wkrgbcymhRGBCYMHWlenupqLENUPQ}.
 @external{}
 @node Line styles, Color scheme, Color styles, General concepts
 @section Стиль линий
+ at nav{}
 
 @cindex Стиль линий
 @cindex Стиль маркеров
 @cindex Стиль стрелок
 
-Стиль линии задается строкой, которая может содержать символ цвета (@samp{wkrgbcymhRGBCYMHWlenupqLENUPQ}), тип пунктира (@samp{-|;:ji} или пробел), ширину линии (@samp{0123456789}) и тип маркера (@samp{o+xsd.^v} и модификатор @samp{#}). Если пропущен цвет или тип пунктира, то используется значение по умолчанию с последним указанным цветом или значение из палитры (для @pxref{1D plotting}). 
+Стиль линии задается строкой, которая может содержать символ цвета (@samp{wkrgbcymhRGBCYMHWlenupqLENUPQ}), тип пунктира (@samp{-|;:ji} или пробел), ширину линии (@samp{0123456789}) и тип маркера (@samp{o+xsd.^v} и модификатор @samp{#}). Если пропущен цвет или тип пунктира, то используется значение по умолчанию с последним указанным цветом или значение из палитры (для @pxref{1D plotting}).
 @ifhtml
 @html
 По умолчанию палитры содержит следующие цвета: <span style="color: rgb(76, 76, 76);">темно серый</span> ‘<samp>H</samp>’, <span style="color: rgb(0, 0, 255);">синий</span> ‘<samp>b</samp>’, <span style="color: rgb(0, 255, 0);">зеленый</span> ‘<samp>g</samp>’, <span style="color: rgb(255, 0, 0);">красный</span> ‘<samp>r</samp>’, <span style="color: rgb(0, 255, 255);">голубой</span> ‘<samp>c</samp>’, <span style="color: rgb(255, 0 [...]
@@ -104,6 +108,7 @@ Base colors are defined by one of symbol @samp{wkrgbcymhRGBCYMHWlenupqLENUPQ}.
 @external{}
 @node Color scheme, Font styles, Line styles, General concepts
 @section Цветовая схема
+ at nav{}
 
 @cindex Цветовая схема
 
@@ -120,10 +125,24 @@ Base colors are defined by one of symbol @samp{wkrgbcymhRGBCYMHWlenupqLENUPQ}.
 При определении цвета по @emph{положению точки в пространстве} (используется в @ref{map}) окончательный цвет определяется по формуле c=x*c[1] + y*c[2]. Здесь c[1], c[2] -- первые три цвета в цветовом массиве; x, y -- координаты точки, нормированные на @var{Min}x at var{Max}.
 @c Такой тип определения цвета полезен, например, при построении поверхностей уровня, когда цвет дает представление о положении точки в пространстве.
 
+
+Дополнительно, MathGL может наложить маску при закраске граней для создания растрового изображения. Тип маски задается одним из символов @samp{-+=;oOsS~<>jdD*^} в цветовой схеме. Маску можно повернуть на произвольный угол командой @ref{mask} или на один из улов +45, -45 или 90 градусов, используя символы @samp{\/I} соответственно. Примеры масок по умолчанию показаны на рисунке ниже.
+
+ at pfig{mask, Example of masks for face coloring.}
+
+Однако, вы можете задать собственную маску (как матрицу 8*8) для любого из этих символов, используя второй аргумент команды @ref{mask}. Например, маска на правом нижнем подрисунке получается кодом@*
+ at ifclear UDAV
+ at code{gr->SetMask('+', "ff00182424f80000");	gr->Dens(a,"3+");}
+ at end ifclear
+ at ifset UDAV
+ at code{mask '+' 'ff00182424f80000':dens a '3+'}
+ at end ifset
+
 @c ------------------------------------------------------------------
 @external{}
 @node Font styles, Textual formulas, Color scheme, General concepts
 @section Стиль текста
+ at nav{}
 
 @cindex Стиль текста
 
@@ -131,7 +150,7 @@ Base colors are defined by one of symbol @samp{wkrgbcymhRGBCYMHWlenupqLENUPQ}.
 
 Начертания шрифта: @samp{r} -- прямой шрифт, @samp{i} -- курсив, @samp{b} -- жирный. По умолчанию используется прямой шрифт. Типы выравнивания текста: @samp{L} -- по левому краю (по умолчанию), @samp{C} -- по центру, @samp{R} -- по правому краю. Дополнительные эффекты шрифта: @samp{w} -- контурный, @samp{o} -- надчеркнутый, @samp{u} -- подчеркнутый.
 
-Синтаксический разбор LaTeX-их команд по умолчанию включен. Это команды смены стиля текста (например, \b для жирного текста): \a или \overline -- надчеркивание, \b или \textbf -- жирный, \i или \textit -- курсив, \r или \textrm -- прямой (отменяет стили жирного и курсива), \u или \underline -- подчеркнутый, \w или \wire -- контурный, \big -- большего размера, @@ -- меньшего размера. Нижний и верхний индексы задаются символами @samp{_} и @samp{^}. При этом изменение стиля применяется толь [...]
+Синтаксический разбор LaTeX-их команд по умолчанию включен. Это команды смены стиля текста (например, \b для жирного текста): \a или \overline -- надчеркивание, \b или \textbf -- жирный, \i или \textit -- курсив, \r или \textrm -- прямой (отменяет стили жирного и курсива), \u или \underline -- подчеркнутый, \w или \wire -- контурный, \big -- большего размера, @@ -- меньшего размера. Нижний и верхний индексы задаются символами @samp{_} и @samp{^}. При этом изменение стиля применяется толь [...]
 @ifhtml
 @html
 α.
@@ -155,7 +174,7 @@ Base colors are defined by one of symbol @samp{wkrgbcymhRGBCYMHWlenupqLENUPQ}.
 @ifnothtml
 В частности, распознаются греческие буквы: @math{\alpha} -- \alpha, @math{\beta} -- \beta, @math{\gamma} -- \gamma, @math{\delta} -- \delta, @math{\epsilon} -- \epsilon, @math{\eta} -- \eta, @math{\iota} -- \iota, @math{\chi} -- \chi, @math{\kappa} -- \kappa, @math{\lambda} -- \lambda, @math{\mu} -- \mu, @math{\nu} -- \nu, @math{o} -- \o, @math{\omega} -- \omega, @math{\phi} -- \phi, @math{\pi} -- \pi, @math{\psi} -- \psi, @math{\rho} -- \rho, @math{\sigma} -- \sigma, @math{\theta} -- \t [...]
 
-Еще примеры наиболее общеупотребительных TeX-их символов: @math{\angle} -- \angle, @math{\aleph} -- \aleph, @math{\cdot} -- \cdot, @math{\clubsuit} -- \clubsuit, @math{\cup} -- \cup, @math{\cap} -- \cap, @math{\diamondsuit} -- \diamondsuit, @math{\diamond} -- \diamond, @math{\div} -- \div, @math{\downarrow} -- \downarrow, @math{\dag} -- \dag, @math{\ddag} -- \ddag, @math{\equiv} -- \equiv, @math{\exists} -- \exists, @math{\frown} -- \frown, @math{\flat} -- \flat, @math{\ge} -- \ge, @math [...]
+Еще примеры наиболее общеупотребительных TeX-их символов: @math{\angle} -- \angle, @math{\aleph} -- \aleph, @math{\cdot} -- \cdot, @math{\clubsuit} -- \clubsuit, @math{\cup} -- \cup, @math{\cap} -- \cap, @math{\diamondsuit} -- \diamondsuit, @math{\diamond} -- \diamond, @math{\div} -- \div, @math{\downarrow} -- \downarrow, @math{\dag} -- \dag, @math{\ddag} -- \ddag, @math{\equiv} -- \equiv, @math{\exists} -- \exists, @math{\frown} -- \frown, @math{\flat} -- \flat, @math{\ge} -- \ge, @math [...]
 @end ifnothtml
 
 Размер текста может быть задан явно (если @var{size}>0) или относительно базового размера шрифта для рисунка |@var{size}|*@var{FontSize} при @var{size}<0. Значение @var{size}=0 указывает, что соответствующая строка выводиться не будет. Базовый размер шрифта измеряется во внутренних единицах. Специальные функции @code{SetFontSizePT(), SetFontSizeCM(), SetFontSizeIN()} позволяют задавать его в более ``привычных'' единицах.
@@ -173,7 +192,7 @@ MathGL имеет быстрый парсер текстовых формул
 @end ifclear
 , понимающий большое число функций и операций. Базовые операции: @samp{+} -- сложение, @samp{-} -- вычитание, @samp{*} -- умножение, @samp{/} -- деление, @samp{^} -- возведение в целосичленную степень. Также есть логические операции: @samp{<} -- истина если if x<y, @samp{>} -- истина если x>y, @samp{=} -- истина если x=y, @samp{&} -- истина если x и y оба не равны нулю, @samp{|} -- истина если x или y не нуль. Логические операции имеют наинизший приоритет и возвращают 1 если истина или 0 [...]
 
-Базовые функции: @samp{sqrt(x)} -- квадратный корень из @var{x}, @samp{pow(x,y)} -- @var{x} в степени @var{y}, @samp{ln(x)} -- натуральный логарифм @var{x}, @samp{lg(x)} -- десятичный логарифм @var{x}, @samp{log(a,x)} -- логарифм по основанию @var{a} от @var{x}, @samp{abs(x)} -- модуль @var{x}, @samp{sign(x)} -- знак @var{x}, @samp{mod(x,y)} -- остаток от деления x на y, @samp{step(x)} -- ступенчатая функция, @samp{int(x)} -- целая часть @var{x}, @samp{rnd} -- случайное число, @samp{pi}  [...]
+Базовые функции: @samp{sqrt(x)} -- квадратный корень из @var{x}, @samp{pow(x,y)} -- @var{x} в степени @var{y}, @samp{ln(x)} -- натуральный логарифм @var{x}, @samp{lg(x)} -- десятичный логарифм @var{x}, @samp{log(a,x)} -- логарифм по основанию @var{a} от @var{x}, @samp{abs(x)} -- модуль @var{x}, @samp{sign(x)} -- знак @var{x}, @samp{mod(x,y)} -- остаток от деления x на y, @samp{step(x)} -- ступенчатая функция, @samp{int(x)} -- целая часть @var{x}, @samp{rnd} -- случайное число, @samp{pi}  [...]
 @ifhtml
 @html
 π = 3.1415926…
@@ -208,7 +227,7 @@ MathGL имеет быстрый парсер текстовых формул
 
 Функции Якоби: @samp{sn(u,m)}, @samp{cn(u,m)}, @samp{dn(u,m)}, @samp{sc(u,m)}, @samp{sd(u,m)}, @samp{ns(u,m)}, @samp{cs(u,m)}, @samp{cd(u,m)}, @samp{nc(u,m)}, @samp{ds(u,m)}, @samp{dc(u,m)}, @samp{nd(u,m)}.
 
-Некоторые из функций могут быть недоступны если не была включена поддержка GSL при компиляции библиотеки MathGL. 
+Некоторые из функций могут быть недоступны если не была включена поддержка GSL при компиляции библиотеки MathGL.
 
 При разборе формул нет различия между верхним и нижним регистром. Если аргумент лежит вне области определения функции, то возвращается NaN.
 
@@ -216,6 +235,7 @@ MathGL имеет быстрый парсер текстовых формул
 @external{}
 @node  Command options, Interfaces, Textual formulas, General concepts
 @section Опции команд
+ at nav{}
 
 Опции команд позволяют легко настроить вид отдельного графика не меняя глобальных настроек для все рисунка. Каждая опция отделяется от предыдущей символом @samp{;}. Опции работают так, что запоминают текущие настройки рисунка, применяют собственные настройки, выполняют команду и возвращают глобальные настройки обратно. Поэтому использование опций для команд обработки данных или настройки графика бесполезно.
 
@@ -277,79 +297,86 @@ MathGL имеет быстрый парсер текстовых формул
 @external{}
 @node Interfaces, , Command options, General concepts
 @section Интерфейсы
-
- at c TODO Translate it!!!
+ at nav{}
 
 @ifset UDAV
-You can use @code{mglParse} class for executing MGL scripts from different languages.
+Вы можете использовать класс @code{mglParse} для выполнения MGL скриптов из других языков программирования.
 @end ifset
 
 @ifclear UDAV
 
-The MathGL library has interfaces for a set of languages. Most of them are based on the C interface via SWIG tool. There are Python, Java, Octave, Lisp, C#, Guile, Lua, Modula 3, Ocaml, Perl, PHP, Pike, R, Ruby, and Tcl interfaces. Also there is a Fortran interface which has a similar set of functions, but slightly different types of arguments (integers instead of pointers). These functions are marked as [C function].
+Библиотека MathGL имеет интерфейсы к ряду языков программирования. Большинство из них основано на С интерфейсе с использованием SWIG. Это Python, Java, Octave, Lisp, C#, Guile, Lua, Modula 3, Ocaml, Perl, PHP, Pike, R, Ruby, и Tcl интерфейсы. Также есть Fortran интерфейс, который имеет схожий набор функций, но слегка различающиеся типы аргументов (целые вместо указателей). Эти функции отмечены как [C function].
 
-Some of the languages listed above support classes (like C++ or Python). The name of functions for them is the same as in C++ (see @ref{MathGL core} and @ref{Data processing}) and marked like [Method on mglGraph].
+Некоторые языки поддерживают классы (подобно C++ или Python). Имена функций для них такие же как в С++ (см. @ref{MathGL core} и @ref{Data processing}) и отмечены, например, так [Method on mglGraph].
 
-Finally, a special command language MGL (see @ref{MGL scripts}) was written for a faster access to plotting functions. Corresponding scripts can be executed separately (by UDAV, mglconv, mglview and so on) or from the C/C++/Python/... code (@pxref{mglParse class}).
+Наконец, специальный командный язык MGL (см. @ref{MGL scripts}) был создан для быстрого доступа к функциям рисования. Соответствующие скрипты могут быть выполнены самостоятельно (с помощью UDAV, mglconv, mglview и т.д.) или из программы на языке C/C++/Python/... (см. @ref{mglParse class}).
 
 @menu
 * C interface::
 * C++ interface::
 @end menu
 
- at comment  @external{}
+ at external{}
 @node C interface, C++ interface, , Interfaces
- at subsection C/Fortran interface
+ at subsection C/Fortran интерфейс
+ at nav{}
 
-The C interface is a base for many other interfaces. It contains the pure C functions for most of the methods of MathGL classes. In distinction to C++ classes, C functions must have an argument HMGL (for graphics) and/or HMDT (for data arrays), which specifies the object for drawing or manipulating (changing). So, firstly, the user has to create this object by the function @code{mgl_create_*()} and has to delete it after the use by function @code{mgl_delete_*()}.
+C интерфейс -- основа для многих других интерфейсов. Он содержит функции С для всех методов MathGL. В отличие от C++ классов, C функции содержат обязательный(ые) аргумент(ы) типа HMGL (для графики) и/или HCDT/HMDT/HADT (для массивов данных), который указывают на объект для рисования или изменения. Поэтому перед использованием их необходимо создать с помощью функции @code{mgl_create_*()}, и удалить после использования (или в конце программы) с помощью функции @code{mgl_delete_*()}.
 
-All C functions are described in the header file @code{#include <mgl2/mgl_cf.h>} and use variables of the following types:
+Все C функции описаны в заголовочном файле @code{#include <mgl2/mgl_cf.h>} и используют переменные следующих типов:
 @itemize
 @item
- at code{HMGL} --- Pointer to class @code{mglGraph} (@pxref{MathGL core}).
+ at code{HMGL} --- Указатель на класс @code{mglGraph} (см. @ref{MathGL core}).
+ at item
+ at code{HCDT} --- Указатель на класс @code{const mglDataA} (см. @ref{Data processing}) --- неизменяемые массивы данных.
+ at item
+ at code{HMDT} --- Указатель на класс @code{mglData} (см. @ref{Data processing}) --- массивы данных с действительными числами.
 @item
- at code{HMDT} --- Pointer to class @code{mglData} (@pxref{Data processing}).
+ at code{HADT} --- Указатель на класс @code{mglDataC} (см. @ref{Data processing}) --- массивы данных с комплексными числами.
 @item
- at code{HMPR} --- Pointer to class @code{mglParse} (@pxref{mglParse class}).
+ at code{HMPR} --- Указатель на класс @code{mglParse} (см. @ref{mglParse class}) --- выполнение MGL скриптов.
+ at item
+ at code{HMEX} --- Указатель на класс @code{mglExpr} (см. @ref{Evaluate expression}) --- текстовые формулы для действительных чисел.
+ at item
+ at code{HMAX} --- Указатель на класс @code{mglExprC} (см. @ref{Evaluate expression}) --- текстовые формулы для комплексных чисел.
 @end itemize
-These variables contain identifiers for graphics drawing objects and for the data objects.
 
-Fortran functions/subroutines have the same names as C functions. However, there is a difference. Variable of type @code{HMGL, HMDT} must be an integer with sufficient size (@code{integer*4} in the 32-bit operating system or @code{integer*8} in the 64-bit operating system). All C functions are subroutines in Fortran, which are called by operator @code{call}. The exceptions are functions, which return variables of types @code{HMGL} or @code{HMDT}. These functions should be declared as int [...]
+Фортрановские функции и подпрограммы имеют такие же имена как функции С. Однако есть отличие. Переменные типов @code{HMGL, HCDT, HMDT, ...} должны быть целыми с достаточной разрядностью (@code{integer*4} для 32-битной операционной системы или @code{integer*8} для 64-битной). Все C функции типа @code{void} --- подпрограммы на Фортране и должны вызываться оператором @code{call}. Прочие функции, возвращающие тип @code{HMGL} или @code{HMDT} и т.п. должны быть объявлены в Фортране как возвращ [...]
 
- at comment  @external{}
+ at external{}
 @node C++ interface, , C interface, Interfaces
- at subsection C++/Python interface
+ at subsection C++/Python интерфейс
+ at nav{}
 
-MathGL provides the interface to a set of languages via SWIG library. Some of these languages support classes. The typical example is Python -- which is named in this chapter's title. Exactly the same classes are used for high-level C++ API. Its feature is using only inline member-functions what make high-level API to be independent on compiler even for binary build.
+MathGL имеет интерфейс на основе классов (объектов с членами-функциями) с использованием библиотеки SWIG. Типичный пример -- Python, имя которого использовано в заголовке раздела. В точности те же классы используются и в C++ API. Отмечу, что С++ классы содержат только inline члены-функции, что делает С++ API независимым от компилятора даже для бинарной версии.
 
-There are 3 classes in:
+Есть 3 основных класса:
 @itemize
 @item @code{mglGraph}
--- provide most plotting functions (see @ref{MathGL core}).
+-- обеспечивает вывод графики (см. @ref{MathGL core}).
 @item @code{mglData}
--- provide base data processing (see @ref{Data processing}). It have an additional feature to access data values. You can use a construct like this: @code{dat[i]=sth;} or @code{sth=dat[i]} where flat representation of data is used (i.e., @var{i} can be in range 0...nx*nx*nz-1). You can also import NumPy arrays as input arguments in Python: @code{mgl_dat = mglData(numpy_dat);}.
+-- обеспечивает обработку данных (см. @ref{Data processing}). Класс имеет возможность прямого доступа к данным с помощью конструкции вида: @code{dat[i]=sth;} или @code{sth=dat[i]}, где используется "плоское" представление данных (т.е., @var{i} может быть в диапазоне 0...nx*nx*nz-1). Также можно импортировать массивы NumPy в Python: @code{mgl_dat = mglData(numpy_dat);}.
 @item @code{mglParse}
--- provide functions for parsing MGL scripts (see @ref{MGL scripts}).
+-- обеспечивает выполнение скриптов MGL (см. @ref{MGL scripts}).
 @end itemize
 
 
-To use Python classes just execute @samp{import mathgl}. The simplest example will be:
+Для использования в Python достаточно выполнить @samp{import mathgl}. Простейший пример имеет вид:
 @verbatim
 import mathgl
 a=mathgl.mglGraph()
 a.Box()
 a.WritePNG("test.png")
 @end verbatim
-Alternatively you can import all classes from @code{mathgl} module and easily access MathGL classes like this:
+Также можно импортировать все классы из модуля @code{mathgl} и обеспечить более легкий доступ к MathGL:
 @verbatim
 from mathgl import *
 a=mglGraph()
 a.Box()
 a.WritePNG("test.png")
 @end verbatim
-This becomes useful if you create many @code{mglData} objects, for example.
+Это становится более полезным если, например, вы создаете много объектов данных @code{mglData}.
 
 @end ifclear
 
 @external{}
-
diff --git a/texinfo/core_en.texi b/texinfo/core_en.texi
index a772779..239fd79 100644
--- a/texinfo/core_en.texi
+++ b/texinfo/core_en.texi
@@ -1,5 +1,6 @@
 @c ------------------------------------------------------------------
 @chapter MathGL core
+ at nav{}
 @cindex mglGraph
 
 @ifset UDAV
@@ -35,6 +36,7 @@ The core of MathGL is @strong{mglGraph} class defined in @code{#include <mgl2/mg
 @external{}
 @node Constructor, Graphics setup, , MathGL core
 @section Create and delete objects
+ at nav{}
 
 @ifclear UDAV
 @deftypefn {Constructor on @code{mglGraph}} {} mglGraph (@code{int} kind=@code{0}, @code{int} width=@code{600}, @code{int} height=@code{400})
@@ -63,6 +65,7 @@ You don't need to create canvas object in MGL.
 @external{}
 @node Graphics setup, Axis settings, Constructor, MathGL core
 @section Graphics setup
+ at nav{}
 @cindex MathGL setup
 
 Functions and variables in this group influences on overall graphics appearance. So all of them should be placed @emph{before} any actual plotting function calls.
@@ -82,13 +85,15 @@ Restore initial values for all of parameters.
 * Cutting::
 * Font settings::
 * Palette and colors::
+* Masks::
 * Error handling::
 @end menu
 
 @c ==================================================================
- at comment  @external{}
+ at external{}
 @node Transparency, Lighting, , Graphics setup
 @subsection Transparency
+ at nav{}
 @cindex Alpha
 @ifclear UDAV
 @cindex SetAlphaDef
@@ -136,9 +141,10 @@ Lamp-like transparency (@samp{2}) -- below and upper things are commutable and a
 @end deftypefn
 
 @c ==================================================================
- at comment  @external{}
+ at external{}
 @node Lighting, Fog, Transparency, Graphics setup
 @subsection Lighting
+ at nav{}
 @ifclear UDAV
 @cindex SetAmbient
 @cindex AddLight
@@ -178,12 +184,13 @@ The function adds a light source with identification @var{n} in direction @var{d
 @end deftypefn
 
 @anchor{diffuse}
+ at deftypefn {MGL command} {} diffuse @code{val}
 @ifclear UDAV
- at deftypefn {Method on @code{mglGraph}} @code{void} SetDifLight (@code{bool} enable)
- at deftypefnx {C function} @code{void} mgl_set_light_dif (@code{HMGL} gr, @code{int} enable)
-Set on/off to use diffusive light (only for local light sources).
- at end deftypefn
+ at deftypefnx {Method on @code{mglGraph}} @code{void} SetDiffuse (@code{mreal} bright)
+ at deftypefnx {C function} @code{void} mgl_set_difbr (@code{HMGL} gr, @code{mreal} bright)
 @end ifclear
+Set brightness of diffusive light (only for local light sources).
+ at end deftypefn
 
 @anchor{ambient}
 @deftypefn {MGL command} {} ambient @code{val}
@@ -195,9 +202,10 @@ Sets the brightness of ambient light. The value should be in range [0,1].
 @end deftypefn
 
 @c ==================================================================
- at comment  @external{}
+ at external{}
 @node Fog, Default sizes, Lighting, Graphics setup
 @subsection Fog
+ at nav{}
 @cindex Fog
 
 @anchor{fog}
@@ -210,9 +218,10 @@ Function imitate a fog in the plot. Fog start from relative distance @var{dz} fr
 @end deftypefn
 
 @c ==================================================================
- at comment  @external{}
+ at external{}
 @node Default sizes, Cutting, Fog, Graphics setup
 @subsection Default sizes
+ at nav{}
 @ifclear UDAV
 @cindex SetBarWidth
 @cindex SetMarkSize
@@ -233,7 +242,7 @@ These variables control the default (initial) values for most graphics parameter
 @deftypefnx {Method on @code{mglGraph}} @code{void} SetBarWidth ( @code{mreal} val)
 @deftypefnx {C function} @code{void} mgl_set_bar_width (@code{HMGL} gr, @code{mreal} val)
 @end ifclear
-Sets relative width of rectangles in @ref{bars}, @ref{barh}, @ref{boxplot}, @ref{candle}. Default value is @code{0.7}.
+Sets relative width of rectangles in @ref{bars}, @ref{barh}, @ref{boxplot}, @ref{candle}, @ref{ohlc}. Default value is @code{0.7}.
 @end deftypefn
 
 @anchor{marksize}
@@ -290,9 +299,10 @@ Gets default name @var{id} as filename for saving (in FLTK window for example).
 @end ifclear
 
 @c ==================================================================
- at comment  @external{}
+ at external{}
 @node Cutting, Font settings, Default sizes, Graphics setup
 @subsection Cutting
+ at nav{}
 @ifclear UDAV
 @cindex SetCut
 @cindex SetCutBox
@@ -328,9 +338,10 @@ Sets the cutting off condition by formula @var{cond}. This condition determine w
 @end deftypefn
 
 @c ==================================================================
- at comment  @external{}
+ at external{}
 @node Font settings, Palette and colors, Cutting, Graphics setup
 @subsection Font settings
+ at nav{}
 @ifclear UDAV
 @cindex SetFontSize
 @cindex SetFontDef
@@ -404,16 +415,17 @@ Copy font data from another @code{mglGraph} object.
 Restore font data to default typeface.
 @end deftypefn
 
- at deftypefn {Функция С} @code{void} mgl_def_font (@code{const char *}name, @code{const char *}path)
+ at deftypefn {C function} @code{void} mgl_def_font (@code{const char *}name, @code{const char *}path)
 Load default font typeface (for all newly created HMGL/mglGraph objects) from @var{path}/@var{name}.
 @end deftypefn
 
 @end ifclear
 
 @c ==================================================================
- at comment  @external{}
- at node Palette and colors, Error handling, Font settings, Graphics setup
+ at external{}
+ at node Palette and colors, Masks, Font settings, Graphics setup
 @subsection Palette and colors
+ at nav{}
 @ifclear UDAV
 @cindex SetPalette
 @end ifclear
@@ -434,21 +446,52 @@ Sets the palette as selected colors. Default value is @code{"Hbgrcmyhlnqeup"} th
 Sets the @var{sch} as default color scheme. Default value is @code{"BbcyrR"}.
 @end deftypefn
 
- at deftypefn {C function} @code{void} mgl_set_color (@code{char} id, @code{mreal} r, @code{mreal} g, @code{mreal} b)
-Sets RGB values for color with given @var{id}.
+ at deftypefn {Method on @code{mglGraph}} @code{void} SetColor (@code{char} id, @code{mreal} r, @code{mreal} g, @code{mreal} b) static
+ at deftypefnx {C function} @code{void} mgl_set_color (@code{char} id, @code{mreal} r, @code{mreal} g, @code{mreal} b)
+Sets RGB values for color with given @var{id}. This is global setting which influence on any later usage of symbol @var{id}.
 @end deftypefn
 @end ifclear
 
+
 @c ==================================================================
- at comment  @external{}
- at node Error handling, , Palette and colors, Graphics setup
+ at external{}
+ at node Masks, Error handling, Palette and colors, Graphics setup
+ at subsection Masks
+ at nav{}
+ at cindex SetMask
+ at cindex SetMaskAngle
+
+ at anchor{mask}
+ at deftypefn {MGL command} {} mask 'id' 'hex'
+ at ifclear UDAV
+ at deftypefnx {Method on @code{mglGraph}} @code{void} SetMask (@code{char} id, @code{const char *}hex)
+ at deftypefnx {Method on @code{mglGraph}} @code{void} SetMask (@code{char} id, @code{uint64_t} hex)
+ at deftypefnx {C function} @code{void} mgl_set_mask (@code{HMGL} gr, @code{const char *}hex)
+ at deftypefnx {C function} @code{void} mgl_set_mask_val (@code{HMGL} gr, @code{uint64_t} hex)
+ at end ifclear
+Sets new bit matrix @var{hex} of size 8*8 for mask with given @var{id}. This is global setting which influence on any later usage of symbol @var{id}. The predefined masks are (see @ref{Color scheme}): @samp{-} is 000000FF00000000, @samp{+} is 080808FF08080808,	@samp{=} is 0000FF00FF000000,	@samp{;} is 0000007700000000, @samp{o} is 0000182424180000,	@samp{O} is 0000183C3C180000,	@samp{s} is 00003C24243C0000,	@samp{S} is 00003C3C3C3C0000, @samp{~} is 0000060990600000,	@samp{<} is 006058465 [...]
+ at end deftypefn
+
+ at deftypefn {MGL command} {} mask angle
+ at ifclear UDAV
+ at deftypefnx {Method on @code{mglGraph}} @code{void} SetMaskAngle (@code{int} angle)
+ at deftypefnx {C function} @code{void} mgl_set_mask_angle (@code{HMGL} gr, @code{int} angle)
+ at end ifclear
+Sets the default rotation angle (in degrees) for masks. Note, you can use symbols @samp{\}, @samp{/}, @samp{I} in color scheme for setting rotation angles as 45, -45 and 90 degrees correspondingly.
+ at end deftypefn
+
+
+ at c ==================================================================
+ at external{}
+ at node Error handling, , Masks, Graphics setup
 @subsection Error handling
+ at nav{}
 @ifclear UDAV
 @cindex Message
 @cindex SetWarn
 @cindex GetWarn
 
-Normally user should set it to zero by @code{SetWarn(0);} before plotting and check if @code{GetWarnCode()} or @code{Message()} return non zero after plotting. Only last warning will be saved. All warnings/errors produced by MathGL is not critical -- the plot just will not be drawn.
+Normally user should set it to zero by @code{SetWarn(0);} before plotting and check if @code{GetWarn()} or @code{Message()} return non zero after plotting. Only last warning will be saved. All warnings/errors produced by MathGL is not critical -- the plot just will not be drawn.
 
 @deftypefn {Method on @code{mglGraph}} @code{void} SetWarn (@code{int} code, @code{const char *}info=@code{""})
 @deftypefnx {C function} @code{void} mgl_set_warn (@code{HMGL} gr, @code{int} code, @code{const char *}info)
@@ -460,8 +503,8 @@ Set warning code. Normally you should call this function only for clearing the w
 Return messages about matters why some plot are not drawn. If returned string is empty then there are no messages.
 @end deftypefn
 
- at deftypefn {Method on @code{mglGraph}} @code{int} GetWarnCode ()
- at deftypefnx {C function} @code{int} mgl_get_warn_code (@code{HMGL} gr)
+ at deftypefn {Method on @code{mglGraph}} @code{int} GetWarn ()
+ at deftypefnx {C function} @code{int} mgl_get_warn (@code{HMGL} gr)
 Return the numerical ID of warning about the not drawn plot. Possible values are:
 @table @code
 @item mglWarnNone=0
@@ -478,8 +521,6 @@ No file or wrong data dimensions
 Not enough memory
 @item mglWarnZero
 Data values are zero
- at item mglWarnLegA
-Too many legend entries
 @item mglWarnLeg
 No legend entries
 @item mglWarnSlc
@@ -494,17 +535,31 @@ Light: ID is out of range
 Setsize: size(s) is zero or negative
 @item mglWarnFmt
 Format is not supported for that build
+ at item mglWarnTern
+Axis ranges are incompatible
+ at item mglWarnNull
+Pointer is NULL
+ at item mglWarnSpc
+Not enough space for plot
+ at item mglScrArg
+Wrong argument(s) of a command in MGL script
+ at item mglScrCmd
+Wrong command in MGL script
+ at item mglScrLong
+Too long line in MGL script
+ at item mglScrStr
+Unbalanced ' in MGL script
 @end table
 @end deftypefn
 @end ifclear
 
-
 @c ==================================================================
 @external{}
 @node Axis settings, Subplots and rotation, Graphics setup, MathGL core
 @section Axis settings
+ at nav{}
 
-These large set of variables and functions control how the axis and ticks will be drawn. Note that there is 3-step transformation of data coordinates are performed. Firstly, coordinates are projected if @code{Cut=true} (see @ref{Cutting}), after it transformation formulas are applied, and finally the data was normalized in bounding box.
+These large set of variables and functions control how the axis and ticks will be drawn. Note that there is 3-step transformation of data coordinates are performed. Firstly, coordinates are projected if @code{Cut=true} (see @ref{Cutting}), after it transformation formulas are applied, and finally the data was normalized in bounding box. Note, that MathGL will produce warning if axis range and transformation formulas are not compatible.
 
 @menu
 * Ranges (bounding box)::
@@ -513,9 +568,10 @@ These large set of variables and functions control how the axis and ticks will b
 @end menu
 
 @c ------------------------------------------------------------------
- at comment  @external{}
+ at external{}
 @node Ranges (bounding box), Curved coordinates, , Axis settings
 @subsection Ranges (bounding box)
+ at nav{}
 @cindex CRange
 @cindex XRange
 @cindex YRange
@@ -604,9 +660,10 @@ Additionally extend axis range for any settings made by @code{SetRange} or @code
 
 
 @c ------------------------------------------------------------------
- at comment  @external{}
+ at external{}
 @node Curved coordinates, Ticks, Ranges (bounding box), Axis settings
 @subsection Curved coordinates
+ at nav{}
 @cindex Axis
 @ifclear UDAV
 @cindex SetFunc
@@ -638,7 +695,7 @@ Sets one of the predefined transformation formulas for curvilinear coordinate. P
 @end ifclear
 The function sets to draws Ternary (@var{tern}=@code{1}), Quaternary (@var{tern}=@code{2}) plot or projections (@var{tern}=@code{4,5,6}).
 
-Ternary plot is special plot for 3 dependent coordinates (components) @var{a}, @var{b}, @var{c} so that @var{a}+ at var{b}+ at var{c}=1. MathGL uses only 2 independent coordinates @var{a}=x and @var{b}=y since it is enough to plot everything. At this third coordinate z act as another parameter to produce contour lines, surfaces and so on. 
+Ternary plot is special plot for 3 dependent coordinates (components) @var{a}, @var{b}, @var{c} so that @var{a}+ at var{b}+ at var{c}=1. MathGL uses only 2 independent coordinates @var{a}=x and @var{b}=y since it is enough to plot everything. At this third coordinate z act as another parameter to produce contour lines, surfaces and so on.
 
 Correspondingly, Quaternary plot is plot for 4 dependent coordinates @var{a}, @var{b}, @var{c} and @var{d} so that @var{a}+ at var{b}+ at var{c}+ at var{d}=1. MathGL uses only 3 independent coordinates @var{a}=x, @var{b}=y and @var{d}=z since it is enough to plot everything.
 
@@ -648,9 +705,10 @@ Use @code{Ternary(0)} for returning to usual axis. @sref{Ternary axis} @sref{Axi
 @end deftypefn
 
 @c ------------------------------------------------------------------
- at comment  @external{}
+ at external{}
 @node Ticks, , Curved coordinates, Axis settings
 @subsection Ticks
+ at nav{}
 @cindex AxisStl
 @cindex TickLen
 @cindex Adjust
@@ -745,7 +803,7 @@ Gets number of seconds from 1970 year to specified date/time @var{str}. The form
 @deftypefnx {Method on @code{mglGraph}} @code{void} SetTuneTicks (@code{int} tune, @code{mreal} pos=@code{1.15})
 @deftypefnx {C function} @code{void} mgl_tune_ticks (@code{HMGL} gr, @code{int} tune, @code{mreal} pos)
 @end ifclear
-Switch on/off ticks enhancing by factoring common multiplier (for small, like from 0.001 to 0.002, or large, like from 1000 to 2000, coordinate values -- enabled if @var{tune}&1 is nonzero) or common component (for narrow range, like from 0.999 to 1.000 -- enabled if @var{tune}&2 is nonzero). Also set the position @var{pos} of common multiplier/component on the axis: =0 at minimal axis value, =1 at maximal axis value. Default value is 1.15.
+Switch on/off ticks enhancing by factoring common multiplier (for small, like from 0.001 to 0.002, or large, like from 1000 to 2000, coordinate values -- enabled if @var{tune}&1 is nonzero) or common component (for narrow range, like from 0.999 to 1.000 -- enabled if @var{tune}&2 is nonzero). Also set the position @var{pos} of common multiplier/component on the axis: =0 at minimal axis value, =1 at maximal axis value. Default value is 1.15. If @var{tune}&4 is nonzero then zeros will be a [...]
 @end deftypefn
 
 @anchor{tickshift}
@@ -805,6 +863,7 @@ The line style of axis (@var{stl}), ticks (@var{tck}) and subticks (@var{sub}).
 @external{}
 @node Subplots and rotation, Export picture, Axis settings, MathGL core
 @section Subplots and rotation
+ at nav{}
 @cindex Aspect
 @cindex Rotate
 @cindex RotateN
@@ -921,7 +980,7 @@ Parameter @var{size} set font size. This function set off any aspects or rotatio
 @end deftypefn
 
 @anchor{rotate}
- at deftypefn {MGL command} {} rotate @code{tetz tetx [tety=0]}
+ at deftypefn {MGL command} {} rotate @code{tetx tetz [tety=0]}
 @ifclear UDAV
 @deftypefnx {Method on @code{mglGraph}} @code{void} Rotate (@code{mreal} TetX, @code{mreal} TetZ, @code{mreal} TetY=@code{0})
 @deftypefnx {C function} @code{void} mgl_rotate (@code{HMGL} gr, @code{mreal} TetX, @code{mreal} TetZ, @code{mreal} TetY)
@@ -998,6 +1057,7 @@ The function changes the scale of graphics that correspond to zoom in/out of the
 @external{}
 @node Export picture, Primitives, Subplots and rotation, MathGL core
 @section Export picture
+ at nav{}
 @cindex SetSize
 
 Functions in this group save or give access to produced picture. So, usually they should be called after plotting is done.
@@ -1017,13 +1077,13 @@ Sets size of picture in pixels. This function @strong{must be} called before any
 @deftypefnx {Method on @code{mglGraph}} @code{void} SetQuality (@code{int} val=@code{MGL_DRAW_NORM})
 @deftypefnx {C function} @code{void} mgl_set_quality (@code{HMGL} gr, @code{int} val)
 @end ifclear
-Sets quality of the plot depending on value @var{val}: @code{MGL_DRAW_WIRE=0} -- no face drawing (fastest), @code{MGL_DRAW_FAST=1} -- no color interpolation (fast), @code{MGL_DRAW_NORM=2} -- high quality (normal), @code{MGL_DRAW_HIGH=3} -- high quality with 3d primitives (arrows and marks). If @code{MGL_DRAW_LMEM=0x4} is set then direct bitmap drawing is used (low memory usage).
+Sets quality of the plot depending on value @var{val}: @code{MGL_DRAW_WIRE=0} -- no face drawing (fastest), @code{MGL_DRAW_FAST=1} -- no color interpolation (fast), @code{MGL_DRAW_NORM=2} -- high quality (normal), @code{MGL_DRAW_HIGH=3} -- high quality with 3d primitives (arrows and marks); @code{MGL_DRAW_LMEM=0x4} -- direct bitmap drawing (low memory usage); @code{MGL_DRAW_DOTS=0x8} -- for dots drawing instead of primitives (extremely fast).
 @end deftypefn
 
 @ifclear UDAV
 @deftypefn {Method on @code{mglGraph}} @code{int} GetQuality ()
 @deftypefnx {C function} @code{int} mgl_get_quality (@code{HMGL} gr)
-Gets quality of the plot: @code{MGL_DRAW_WIRE=0} -- no face drawing (fastest), @code{MGL_DRAW_FAST=1} -- no color interpolation (fast), @code{MGL_DRAW_NORM=2} -- high quality (normal), @code{MGL_DRAW_HIGH=3} -- high quality with 3d primitives (arrows and marks). If @code{MGL_DRAW_LMEM=0x4} is set then direct bitmap drawing is used (low memory usage).
+Gets quality of the plot: @code{MGL_DRAW_WIRE=0} -- no face drawing (fastest), @code{MGL_DRAW_FAST=1} -- no color interpolation (fast), @code{MGL_DRAW_NORM=2} -- high quality (normal), @code{MGL_DRAW_HIGH=3} -- high quality with 3d primitives (arrows and marks); @code{MGL_DRAW_LMEM=0x4} -- direct bitmap drawing (low memory usage); @code{MGL_DRAW_DOTS=0x8} -- for dots drawing instead of primitives (extremely fast).
 @end deftypefn
 
 @deftypefn {Method on @code{mglGraph}} @code{void} StartGroup (const char *name)
@@ -1045,9 +1105,10 @@ Ends group definition.
 @end menu
 
 @c ==================================================================
- at comment  @external{}
+ at external{}
 @node Export to file, Frames/Animation, , Export picture
 @subsection Export to file
+ at nav{}
 @cindex Write
 @ifclear UDAV
 @cindex WriteFrame
@@ -1187,9 +1248,10 @@ Imports points and primitives in file using @ref{MGLD format}. Later this file c
 
 
 @c ##################################################################
- at comment  @external{}
+ at external{}
 @node Frames/Animation, Bitmap in memory, Export to file, Export picture
 @subsection Frames/Animation
+ at nav{}
 
 @ifset UDAV
 There are no commands for making animation in MGL. However you can use features of @code{mglconv} and @code{mglview} utilities. For example, by busing special comments @samp{##a } or @samp{##c }.
@@ -1257,9 +1319,10 @@ Finish writing animated GIF and close connected pointers.
 @end ifclear
 
 @c ------------------------------------------------------------------
- at comment  @external{}
+ at external{}
 @node Bitmap in memory, Parallelization, Frames/Animation, Export picture
 @subsection Bitmap in memory
+ at nav{}
 
 @ifclear UDAV
 These functions return the created picture (bitmap), its width and height. You may display it by yourself in any graphical library (see also, @ref{Widget classes}) or save in file (see also, @ref{Export to file}).
@@ -1327,12 +1390,19 @@ Highlight the object with given @var{id}.
 Checks if point @{@var{xs}, @var{ys}@} is close to one of active point (i.e. mglBase::Act) with accuracy @var{d} and return its index or @code{-1} if not found. Active points are special points which characterize primitives (like edges and so on). This function for advanced users only.
 @end deftypefn
 
+ at deftypefn {Method on @code{mglGraph}} @code{long} SetDrawReg (@code{int} nx=@code{1}, @code{int} ny=@code{1}, @code{int} m=@code{0})
+ at deftypefnx {C function} @code{long} mgl_set_draw_reg (@code{HMGL} gr, @code{int} nx, @code{int} ny, @code{int} m)
+Limits drawing region by rectangular area of @var{m}-th cell of matrix with sizes @var{nx}*@var{ny} (like in @ref{subplot}). This function can be used to update only small region of the image for purposes of higher speed. This function for advanced users only.
+ at end deftypefn
+
+
 @end ifclear
 
 @c ------------------------------------------------------------------
- at comment  @external{}
+ at external{}
 @node Parallelization, , Bitmap in memory, Export picture
 @subsection Parallelization
+ at nav{}
 
 @ifclear UDAV
 @cindex Combine
@@ -1368,6 +1438,7 @@ Receive graphical information from node @var{id} using MPI. The width and height
 @external{}
 @node Primitives, Text printing, Export picture, MathGL core
 @section Primitives
+ at nav{}
 @cindex Ball
 @cindex Clf
 @cindex Line
@@ -1389,11 +1460,13 @@ Receive graphical information from node @var{id} using MPI. The width and height
 These functions draw some simple objects like line, point, sphere, drop, cone and so on. @sref{Using primitives}
 
 @anchor{clf}
- at deftypefn {MGL command} {} clf
+ at deftypefn {MGL command} {} clf ['col']
 @ifclear UDAV
 @deftypefnx {Method on @code{mglGraph}} @code{void} Clf ()
+ at deftypefnx {Method on @code{mglGraph}} @code{void} Clf (@code{char} col)
 @deftypefnx {Method on @code{mglGraph}} @code{void} Clf (@code{mreal} r, @code{mreal} g, @code{mreal} b)
 @deftypefnx {C function} @code{void} mgl_clf (@code{HMGL} gr)
+ at deftypefnx {C function} @code{void} mgl_clf_chr (@code{HMGL} gr, @code{char} col)
 @deftypefnx {C function} @code{void} mgl_clf_rgb (@code{HMGL} gr, @code{mreal} r, @code{mreal} g, @code{mreal} b)
 @end ifclear
 Clear the picture and fill it by color specified color.
@@ -1499,7 +1572,17 @@ Draw the drop with radius @var{r} at point @var{p} elongated in direction @var{d
 @deftypefnx {Method on @code{mglGraph}} @code{void} Cone (@code{mglPoint} p1, @code{mglPoint} p2, @code{mreal} r1, @code{mreal} r2=@code{-1}, @code{const char *}stl=@code{"B"})
 @deftypefnx {C function} @code{void} mgl_cone (@code{HMGL} gr, @code{mreal} x1, @code{mreal} y1, @code{mreal} z1, @code{mreal} x2, @code{mreal} y2, @code{mreal} z2, @code{mreal} r1, @code{mreal} r2, @code{const char *}stl)
 @end ifclear
-Draw tube (or truncated cone if @var{edge}=@code{false}) between points @var{p1}, @var{p2} with radius at the edges @var{r1}, @var{r2}. If @var{r2}<0 then it is supposed that @var{r2}=@var{r1}. The cone color is defined by string @var{stl}. If style contain @samp{@@} then edges will be drawn.
+Draw tube (or truncated cone if @var{edge}=@code{false}) between points @var{p1}, @var{p2} with radius at the edges @var{r1}, @var{r2}. If @var{r2}<0 then it is supposed that @var{r2}=@var{r1}. The cone color is defined by string @var{stl}. Parameter @var{stl} can contain:
+ at itemize @bullet
+ at item
+ at samp{@@} for drawing edges;
+ at item
+ at samp{#} for wired cones;
+ at item
+ at samp{t} for drawing tubes/cylinder instead of cones/prisms;
+ at item
+ at samp{4}, @samp{6}, @samp{8}, @samp{t} for drawing square, hex- or octo-prism instead of cones.
+ at end itemize
 @end deftypefn
 
 @anchor{circle}
@@ -1559,6 +1642,7 @@ colors for filling and boundary (second one if style @samp{@@} is used, black co
 @external{}
 @node Text printing, Axis and Colorbar, Primitives, MathGL core
 @section Text printing
+ at nav{}
 @ifclear UDAV
 @cindex Puts
 @cindex Putsw
@@ -1623,13 +1707,14 @@ Draws unrotated @var{n}-th line of file @var{fname} at position @{@var{x}, at var{y
 @deftypefnx {C function} @code{void} mgl_text_xyz (@code{HCDT} x, @code{HCDT} y, @code{HCDT} z, @code{const char *}text, @code{const char *}fnt, @code{const char *}opt)
 @deftypefnx {C function} @code{void} mgl_textw_xyz (@code{HCDT} x, @code{HCDT} y, @code{HCDT} z, @code{const wchar_t *}text, @code{const char *}fnt, @code{const char *}opt)
 @end ifclear
-The function draws @var{text} along the curve between points @{@var{x}[i], @var{y}[i], @var{z}[i]@} by font style @var{fnt}. The string @var{fnt} may contain symbols @samp{t} for printing the text under the curve (default), or @samp{T} for printing the text above the curve. The sizes of 1st dimension must be equal for all arrays @code{x.nx=y.nx=z.nx}. If array @var{x} is not specified then its an automatic array is used with values equidistantly distributed in interval [@var{Min}.x, @var [...]
+The function draws @var{text} along the curve between points @{@var{x}[i], @var{y}[i], @var{z}[i]@} by font style @var{fnt}. The string @var{fnt} may contain symbols @samp{t} for printing the text under the curve (default), or @samp{T} for printing the text above the curve. The sizes of 1st dimension must be equal for all arrays @code{x.nx=y.nx=z.nx}. If array @var{x} is not specified then its an automatic array is used with values equidistantly distributed in interval [@var{Min}.x, @var [...]
 @end deftypefn
 
 @c ##################################################################
 @external{}
 @node Axis and Colorbar, Legend, Text printing, MathGL core
 @section Axis and Colorbar
+ at nav{}
 @cindex Axis
 @cindex Box
 @cindex Grid
@@ -1655,6 +1740,8 @@ Draws axes with ticks (see @ref{Axis settings}). Parameter @var{dir} may contain
 @item
 @samp{U} for disabling rotation of tick labels;
 @item
+ at samp{^} for inverting default axis origin;
+ at item
 @samp{AKDTVISO} for drawing arrow at the end of axis;
 @item
 @samp{a} for forced adjusting of axis ticks.
@@ -1739,13 +1826,14 @@ Draws bounding box outside the plotting volume with color @var{col}. If @var{col
 @deftypefnx {C function} @code{void} mgl_label (@code{HMGL} gr, @code{char} dir, @code{const char *}text, @code{mreal} pos, @code{const char *}opt)
 @deftypefnx {C function} @code{void} mgl_labelw (@code{HMGL} gr, @code{char} dir, @code{const wchar_t *}text, @code{mreal} pos, @code{const char *}opt)
 @end ifclear
-Prints the label @var{text} for axis @var{dir}=@samp{x}, at samp{y}, at samp{z}, at samp{t} (here @samp{t} is ``ternary'' axis @math{t=1-x-y}). The position of label is determined by @var{pos} parameter. If @var{pos}=0 then label is printed at the center of axis. If @var{pos}>0 then label is printed at the maximum of axis. If @var{pos}<0 then label is printed at the minimum of axis. Value option set additional shifting of the label. @xref{Text printing}.
+Prints the label @var{text} for axis @var{dir}=@samp{x}, at samp{y}, at samp{z}, at samp{t} (here @samp{t} is ``ternary'' axis @math{t=1-x-y}). The position of label is determined by @var{pos} parameter. If @var{pos}=0 then label is printed at the center of axis. If @var{pos}>0 then label is printed at the maximum of axis. If @var{pos}<0 then label is printed at the minimum of axis. Option @code{value} set additional shifting of the label. @xref{Text printing}.
 @end deftypefn
 
 @c ##################################################################
 @external{}
 @node Legend, 1D plotting, Axis and Colorbar, MathGL core
 @section Legend
+ at nav{}
 @cindex Legend
 @cindex AddLegend
 @cindex ClearLegend
@@ -1759,6 +1847,8 @@ font style for legend text;
 @item
 @samp{A} for positioning in absolute coordinates;
 @item
+ at samp{^} for positioning outside of specified point;
+ at item
 @samp{#} for drawing box around legend;
 @item
 colors for background (first one) and border (second one) of legend. Note, that last color is always used as color for legend text.
@@ -1771,7 +1861,7 @@ colors for background (first one) and border (second one) of legend. Note, that
 @deftypefnx {Method on @code{mglGraph}} @code{void} Legend (@code{int} pos=@code{0x3}, @code{const char *}fnt=@code{"#"}, @code{const char *}opt=@code{""})
 @deftypefnx {C function} @code{void} mgl_legend (@code{HMGL} gr, @code{int} pos, @code{const char *}fnt, @code{const char *}opt)
 @end ifclear
-Draws legend of accumulated legend entries by font @var{fnt} with @var{size}. Parameter @var{pos} sets the position of the legend: @samp{0} is bottom left corner, @samp{1} is bottom right corner, @samp{2} is top left corner, @samp{3} is top right corner (is default). Parameter @var{fnt} can contain colors for face (1st one), for border (2nd one) and for text (last one). If less than 3 colors are specified then the color for border is black (for 2 and less colors), and the color for face  [...]
+Draws legend of accumulated legend entries by font @var{fnt} with @var{size}. Parameter @var{pos} sets the position of the legend: @samp{0} is bottom left corner, @samp{1} is bottom right corner, @samp{2} is top left corner, @samp{3} is top right corner (is default). Parameter @var{fnt} can contain colors for face (1st one), for border (2nd one) and for text (last one). If less than 3 colors are specified then the color for border is black (for 2 and less colors), and the color for face  [...]
 @end deftypefn
 
 @deftypefn {MGL command} {} legend @code{x y} ['fnt'='#']
@@ -1779,7 +1869,7 @@ Draws legend of accumulated legend entries by font @var{fnt} with @var{size}. Pa
 @deftypefnx {Method on @code{mglGraph}} @code{void} Legend (@code{mreal} x, @code{mreal} y, @code{const char *}fnt=@code{"#"}, @code{const char *}opt=@code{""})
 @deftypefnx {C function} @code{void} mgl_legend_pos (@code{HMGL} gr, @code{mreal} x, @code{mreal} y, @code{const char *}fnt, @code{const char *}opt)
 @end ifclear
-Draws legend of accumulated legend entries by font @var{fnt} with @var{size}. Position of legend is determined by parameter @var{x}, @var{y} which supposed to be normalized to interval [0,1].
+Draws legend of accumulated legend entries by font @var{fnt} with @var{size}. Position of legend is determined by parameter @var{x}, @var{y} which supposed to be normalized to interval [0,1]. Option @code{value} set the space between line samples and text (default is 0.1).
 @end deftypefn
 
 @anchor{addlegend}
@@ -1815,6 +1905,7 @@ Set the number of marks in the legend. By default 1 mark is used.
 @external{}
 @node 1D plotting, 2D plotting, Legend, MathGL core
 @section 1D plotting
+ at nav{}
 @cindex Plot
 @cindex Radar
 @cindex Tens
@@ -1861,7 +1952,7 @@ These functions draw continuous lines between points @{@var{x}[i], @var{y}[i], @
 @deftypefnx {Method on @code{mglGraph}} @code{void} Radar (@code{const mglDataA &}a, @code{const char *}pen=@code{""}, @code{const char *}opt=@code{""})
 @deftypefnx {C function} @code{void} mgl_radar (@code{HMGL} gr, @code{HCDT} a, @code{const char *}pen, @code{const char *}opt)
 @end ifclear
-This functions draws radar chart which is continuous lines between points located on an radial lines (like plot in Polar coordinates). Parameter @var{value} in options @var{opt} set the additional shift of data (i.e. the data @var{a}+ at var{value} is used instead of @var{a}). If @code{value<0} then @code{r=max(0, -min(value)}. If @var{pen} containt @samp{#} symbol then "grid" (radial lines and circle for @var{r}) is drawn. See also @ref{plot}. @sref{Radar sample}
+This functions draws radar chart which is continuous lines between points located on an radial lines (like plot in Polar coordinates). Option @code{value} set the additional shift of data (i.e. the data @var{a}+ at code{value} is used instead of @var{a}). If @code{value<0} then @code{r=max(0, -min(value)}. If @var{pen} containt @samp{#} symbol then "grid" (radial lines and circle for @var{r}) is drawn. See also @ref{plot}. @sref{Radar sample}
 @end deftypefn
 
 @anchor{step}
@@ -1906,7 +1997,7 @@ These functions draw continuous lines between points @{@var{x}[i], @var{y}[i], @
 @deftypefnx {C function} @code{void} mgl_tape_xy (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} y, @code{const char *}pen, @code{const char *}opt)
 @deftypefnx {C function} @code{void} mgl_tape_xyz (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} y, @code{HCDT} z, @code{const char *}pen, @code{const char *}opt)
 @end ifclear
-These functions draw tapes of normals for curve between points @{@var{x}[i], @var{y}[i], @var{z}[i]@}. Initial tape(s) was selected in x-y plane (for @samp{x} in @var{pen}) and/or y-z plane (for @samp{x} in @var{pen}). The width of tape is proportional to @ref{barwidth}. See also @ref{plot}, @ref{flow}, @ref{barwidth}. @sref{Tape sample}
+These functions draw tapes of normals for curve between points @{@var{x}[i], @var{y}[i], @var{z}[i]@}. Initial tape(s) was selected in x-y plane (for @samp{x} in @var{pen}) and/or y-z plane (for @samp{x} in @var{pen}). The width of tape is proportional to @ref{barwidth} and can be changed by option @code{value}. See also @ref{plot}, @ref{flow}, @ref{barwidth}. @sref{Tape sample}
 @end deftypefn
 
 @anchor{area}
@@ -1963,7 +2054,7 @@ These functions draw vertical lines from points to axis plane. See also @ref{are
 @deftypefnx {C function} @code{void} mgl_bars_xy (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} y, @code{const char *}pen, @code{const char *}opt)
 @deftypefnx {C function} @code{void} mgl_bars_xyz (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} y, @code{HCDT} z, @code{const char *}pen, @code{const char *}opt)
 @end ifclear
-These functions draw vertical bars from points to axis plane. If string @var{pen} contain symbol @samp{a} then lines are drawn one above another (like summation). If string contain symbol @samp{f} then waterfall chart is drawn for determining the cumulative effect of sequentially introduced positive or negative values. You can give different colors for positive and negative values if number of specified colors is equal to 2*number of curves. See also @ref{barh}, @ref{cones}, @ref{area},  [...]
+These functions draw vertical bars from points to axis plane. If string @var{pen} contain symbol @samp{a} then lines are drawn one above another (like summation). If string contain symbol @samp{f} then waterfall chart is drawn for determining the cumulative effect of sequentially introduced positive or negative values. You can give different colors for positive and negative values if number of specified colors is equal to 2*number of curves. If @var{pen} contain @samp{<}, @samp{^} or @sa [...]
 @end deftypefn
 
 @anchor{barh}
@@ -1975,7 +2066,7 @@ These functions draw vertical bars from points to axis plane. If string @var{pen
 @deftypefnx {C function} @code{void} mgl_barh (@code{HMGL} gr, @code{HCDT} v, @code{const char *}pen, @code{const char *}opt)
 @deftypefnx {C function} @code{void} mgl_barh_xy (@code{HMGL} gr, @code{HCDT} y, @code{HCDT} v, @code{const char *}pen, @code{const char *}opt)
 @end ifclear
-These functions draw horizontal bars from points to axis plane. If string contain symbol @samp{a} then lines are drawn one above another (like summation). If string contain symbol @samp{f} then waterfall chart is drawn for determining the cumulative effect of sequentially introduced positive or negative values. You can give different colors for positive and negative values if number of specified colors is equal to 2*number of curves. See also @ref{bars}, @ref{barwidth}. @sref{Barh sample}
+These functions draw horizontal bars from points to axis plane. If string contain symbol @samp{a} then lines are drawn one above another (like summation). If string contain symbol @samp{f} then waterfall chart is drawn for determining the cumulative effect of sequentially introduced positive or negative values. You can give different colors for positive and negative values if number of specified colors is equal to 2*number of curves. If @var{pen} contain @samp{<}, @samp{^} or @samp{>} th [...]
 @end deftypefn
 
 @anchor{cones}
@@ -1990,7 +2081,20 @@ These functions draw horizontal bars from points to axis plane. If string contai
 @deftypefnx {C function} @code{void} mgl_cones_xy (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} y, @code{const char *}pen, @code{const char *}opt)
 @deftypefnx {C function} @code{void} mgl_cones_xyz (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} y, @code{HCDT} z, @code{const char *}pen, @code{const char *}opt)
 @end ifclear
-These functions draw cones from points to axis plane. If string contain symbol @samp{a} then cones are drawn one above another (like summation). You can give different colors for positive and negative values if number of specified colors is equal to 2*number of curves. See also @ref{bars}, @ref{barwidth}. @sref{Cones sample}
+These functions draw cones from points to axis plane. If string contain symbol @samp{a} then cones are drawn one above another (like summation). You can give different colors for positive and negative values if number of specified colors is equal to 2*number of curves. Parameter @var{pen} can contain:
+ at itemize @bullet
+ at item
+ at samp{@@} for drawing edges;
+ at item
+ at samp{#} for wired cones;
+ at item
+ at samp{t} for drawing tubes/cylinders instead of cones/prisms;
+ at item
+ at samp{4}, @samp{6}, @samp{8}, @samp{t} for drawing square, hex- or octo-prism instead of cones;
+ at item
+ at samp{<}, @samp{^} or @samp{>} for aligning boxes left, right or centering them at its x-coordinates.
+ at end itemize
+See also @ref{bars}, @ref{cone}, @ref{barwidth}. @sref{Cones sample}
 @end deftypefn
 
 
@@ -2013,7 +2117,7 @@ The function draws colored stripes (boxes) for data in array @var{a}. The number
 @deftypefnx {C function} @code{void} mgl_boxplot (@code{HMGL} gr, @code{HCDT} a, @code{const char *}pen, @code{const char *}opt)
 @deftypefnx {C function} @code{void} mgl_boxplot_xy (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} a, @code{const char *}pen, @code{const char *}opt)
 @end ifclear
-These functions draw boxplot (also known as a box-and-whisker diagram) at points @var{x}[i]. This is five-number summaries of data @var{a}[i,j] (minimum, lower quartile (Q1), median (Q2), upper quartile (Q3) and maximum) along second (j-th) direction. See also @ref{plot}, @ref{error}, @ref{bars}, @ref{barwidth}. @sref{BoxPlot sample}
+These functions draw boxplot (also known as a box-and-whisker diagram) at points @var{x}[i]. This is five-number summaries of data @var{a}[i,j] (minimum, lower quartile (Q1), median (Q2), upper quartile (Q3) and maximum) along second (j-th) direction. If @var{pen} contain @samp{<}, @samp{^} or @samp{>} then boxes will be aligned left, right or centered at its x-coordinates. See also @ref{plot}, @ref{error}, @ref{bars}, @ref{barwidth}. @sref{BoxPlot sample}
 @end deftypefn
 
 @anchor{candle}
@@ -2032,7 +2136,19 @@ These functions draw boxplot (also known as a box-and-whisker diagram) at points
 @deftypefnx {C function} @code{void} mgl_candle_yv (@code{HMGL} gr, @code{HCDT} v1, @code{HCDT} v2, @code{HCDT} y1, @code{HCDT} y2, @code{const char *}pen, @code{const char *}opt)
 @deftypefnx {C function} @code{void} mgl_candle_xyv (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} v1, @code{HCDT} v2, @code{HCDT} y1, @code{HCDT} y2, @code{const char *}pen, @code{const char *}opt)
 @end ifclear
-These functions draw candlestick chart at points @var{x}[i]. This is a combination of a line-chart and a bar-chart, in that each bar represents the range of price movement over a given time interval. Wire (or white) candle correspond to price growth @var{v1}[i]<@var{v2}[i], opposite case -- solid (or dark) candle. "Shadows" show the minimal @var{y1} and maximal @var{y2} prices. If @var{v2} is absent then it is determined as @var{v2}[i]=@var{v1}[i+1]. See also @ref{plot}, @ref{bars}, @ref [...]
+These functions draw candlestick chart at points @var{x}[i]. This is a combination of a line-chart and a bar-chart, in that each bar represents the range of price movement over a given time interval. Wire (or white) candle correspond to price growth @var{v1}[i]<@var{v2}[i], opposite case -- solid (or dark) candle. "Shadows" show the minimal @var{y1} and maximal @var{y2} prices. If @var{v2} is absent then it is determined as @var{v2}[i]=@var{v1}[i+1]. See also @ref{plot}, @ref{bars}, @ref [...]
+ at end deftypefn
+
+ at anchor{ohlc}
+ at deftypefn {MGL command} {} ohlc odat hdat ldat cdat ['stl'='']
+ at deftypefnx {MGL command} {} ohlc xdat odat hdat ldat cdat ['stl'='']
+ at ifclear UDAV
+ at deftypefnx {Method on @code{mglGraph}} @code{void} OHLC (@code{const mglDataA &}o, @code{const mglDataA &}h, @code{const mglDataA &}l, @code{const mglDataA &}c, @code{const char *}pen=@code{""}, @code{const char *}opt=@code{""})
+ at deftypefnx {Method on @code{mglGraph}} @code{void} OHLC (@code{const mglDataA &}x, @code{const mglDataA &}o, @code{const mglDataA &}h, @code{const mglDataA &}l, @code{const mglDataA &}c, @code{const char *}pen=@code{""}, @code{const char *}opt=@code{""})
+ at deftypefnx {C function} @code{void} mgl_ohlc (@code{HMGL} gr, @code{HCDT} o, @code{HCDT} h, @code{HCDT} l, @code{HCDT} c, @code{const char *}pen, @code{const char *}opt)
+ at deftypefnx {C function} @code{void} mgl_ohlc_x (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} o, @code{HCDT} h, @code{HCDT} l, @code{HCDT} c, @code{const char *}pen, @code{const char *}opt)
+ at end ifclear
+These functions draw Open-High-Low-Close diagram. This diagram show vertical line for between maximal(high @var{h}) and minimal(low @var{l}) values, as well as horizontal lines before/after vertical line for initial(open @var{o})/final(close @var{c}) values of some process (usually price). See also @ref{candle}, @ref{plot}, @ref{barwidth}. @sref{OHLC sample}
 @end deftypefn
 
 
@@ -2164,6 +2280,7 @@ These functions draw surface which is result of curve @{@var{r}, @var{z}@} rotat
 @external{}
 @node 2D plotting, 3D plotting, 1D plotting, MathGL core
 @section 2D plotting
+ at nav{}
 @cindex Mesh
 @cindex Fall
 @cindex Belt
@@ -2284,7 +2401,7 @@ The function draws contour lines for surface specified parametrically @{@var{x}[
 @deftypefnx {C function} @code{void} mgl_cont (@code{HMGL} gr, @code{HCDT} z, @code{const char *}sch, @code{const char *}opt)
 @deftypefnx {C function} @code{void} mgl_cont_xy (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} y, @code{HCDT} z, @code{const char *}sch, @code{const char *}opt)
 @end ifclear
-The same as previous with vector @var{v} of @var{num}-th elements equidistantly distributed in color range. Here @var{num} is equal to parameter @var{value} in options @var{opt} (default is 7).
+The same as previous with vector @var{v} of @var{num}-th elements equidistantly distributed in color range. Here @var{num} is equal to parameter @code{value} in options @var{opt} (default is 7).
 @end deftypefn
 
 @anchor{contf}
@@ -2307,7 +2424,7 @@ The function draws solid (or filled) contour lines for surface specified paramet
 @deftypefnx {C function} @code{void} mgl_contf (@code{HMGL} gr, @code{HCDT} z, @code{const char *}sch, @code{const char *}opt)
 @deftypefnx {C function} @code{void} mgl_contf_xy (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} y, @code{HCDT} z, @code{const char *}sch, @code{const char *}opt)
 @end ifclear
-The same as previous with vector @var{v} of @var{num}-th elements equidistantly distributed in color range. Here @var{num} is equal to parameter @var{value} in options @var{opt} (default is 7).
+The same as previous with vector @var{v} of @var{num}-th elements equidistantly distributed in color range. Here @var{num} is equal to parameter @code{value} in options @var{opt} (default is 7).
 @end deftypefn
 
 @anchor{contd}
@@ -2330,7 +2447,7 @@ The function draws solid (or filled) contour lines for surface specified paramet
 @deftypefnx {C function} @code{void} mgl_contd (@code{HMGL} gr, @code{HCDT} z, @code{const char *}sch, @code{const char *}opt)
 @deftypefnx {C function} @code{void} mgl_contd_xy (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} y, @code{HCDT} z, @code{const char *}sch, @code{const char *}opt)
 @end ifclear
-The same as previous with vector @var{v} of @var{num}-th elements equidistantly distributed in color range. Here @var{num} is equal to parameter @var{value} in options @var{opt} (default is 7).
+The same as previous with vector @var{v} of @var{num}-th elements equidistantly distributed in color range. Here @var{num} is equal to parameter @code{value} in options @var{opt} (default is 7).
 @end deftypefn
 
 @anchor{contv}
@@ -2353,7 +2470,7 @@ The function draws vertical cylinder (tube) at contour lines for surface specifi
 @deftypefnx {C function} @code{void} mgl_contv (@code{HMGL} gr, @code{HCDT} z, @code{const char *}sch, @code{const char *}opt)
 @deftypefnx {C function} @code{void} mgl_contv_xy (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} y, @code{HCDT} z, @code{const char *}sch, @code{const char *}opt)
 @end ifclear
-The same as previous with vector @var{v} of @var{num}-th elements equidistantly distributed in color range. Here @var{num} is equal to parameter @var{value} in options @var{opt} (default is 7).
+The same as previous with vector @var{v} of @var{num}-th elements equidistantly distributed in color range. Here @var{num} is equal to parameter @code{value} in options @var{opt} (default is 7).
 @end deftypefn
 
 @anchor{axial}
@@ -2376,7 +2493,7 @@ The function draws surface which is result of contour plot rotation for surface
 @deftypefnx {C function} @code{void} mgl_axial (@code{HMGL} gr, @code{HCDT} z, @code{const char *}sch, @code{const char *}opt)
 @deftypefnx {C function} @code{void} mgl_axial_xy (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} y, @code{HCDT} z, @code{const char *}sch, @code{const char *}opt)
 @end ifclear
-The same as previous with vector @var{v} of @var{num}-th elements equidistantly distributed in color range. Here @var{num} is equal to parameter @var{value} in options @var{opt} (default is 3).
+The same as previous with vector @var{v} of @var{num}-th elements equidistantly distributed in color range. Here @var{num} is equal to parameter @code{value} in options @var{opt} (default is 3).
 @end deftypefn
 
 @anchor{grid2}
@@ -2396,6 +2513,7 @@ The function draws grid lines for density plot of surface specified parametrical
 @external{}
 @node 3D plotting, Dual plotting, 2D plotting, MathGL core
 @section 3D plotting
+ at nav{}
 @cindex Surf3
 @cindex Dens3
 @cindex Cont3
@@ -2426,7 +2544,7 @@ The function draws isosurface plot for 3d array specified parametrically @var{a}
 @deftypefnx {C function} @code{void} mgl_surf3 (@code{HMGL} gr, @code{HCDT} a, @code{const char *}sch, @code{const char *}opt)
 @deftypefnx {C function} @code{void} mgl_surf3_xyz (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} y, @code{HCDT} z, @code{HCDT} a, @code{const char *}sch, @code{const char *}opt)
 @end ifclear
-Draws @var{num}-th uniformly distributed in color range isosurfaces for 3d data. Here @var{num} is equal to parameter @var{value} in options @var{opt} (default is 3).
+Draws @var{num}-th uniformly distributed in color range isosurfaces for 3d data. Here @var{num} is equal to parameter @code{value} in options @var{opt} (default is 3).
 @end deftypefn
 
 @anchor{cloud}
@@ -2473,7 +2591,7 @@ The function draws contour plot for 3d data specified parametrically @var{a}[i,j
 @deftypefnx {C function} @code{void} mgl_cont3 (@code{HMGL} gr, @code{HCDT} a, @code{const char *}sch, @code{mreal} sVal, @code{const char *}opt)
 @deftypefnx {C function} @code{void} mgl_cont3_xyz (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} y, @code{HCDT} z, @code{HCDT} a, @code{const char *}sch, @code{mreal} sVal, @code{const char *}opt)
 @end ifclear
-The same as previous with vector @var{v} of @var{num}-th elements equidistantly distributed in color range. Here @var{num} is equal to parameter @var{value} in options @var{opt} (default is 7).
+The same as previous with vector @var{v} of @var{num}-th elements equidistantly distributed in color range. Here @var{num} is equal to parameter @code{value} in options @var{opt} (default is 7).
 @end deftypefn
 
 @anchor{contf3}
@@ -2496,7 +2614,7 @@ The function draws solid (or filled) contour plot for 3d data specified parametr
 @deftypefnx {C function} @code{void} mgl_contf3 (@code{HMGL} gr, @code{HCDT} a, @code{const char *}sch, @code{mreal} sVal, @code{const char *}opt)
 @deftypefnx {C function} @code{void} mgl_contf3_xyz (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} y, @code{HCDT} z, @code{HCDT} a, @code{const char *}sch, @code{mreal} sVal, @code{const char *}opt)
 @end ifclear
-The same as previous with vector @var{v} of @var{num}-th elements equidistantly distributed in color range. Here @var{num} is equal to parameter @var{value} in options @var{opt} (default is 7).
+The same as previous with vector @var{v} of @var{num}-th elements equidistantly distributed in color range. Here @var{num} is equal to parameter @code{value} in options @var{opt} (default is 7).
 @end deftypefn
 
 @anchor{grid3}
@@ -2527,6 +2645,7 @@ Draws the isosurface for 3d array @var{a} at constant values of @var{a}=@var{val
 @external{}
 @node Dual plotting, Vector fields, 3D plotting, MathGL core
 @section Dual plotting
+ at nav{}
 @cindex SurfC
 @cindex SurfA
 @cindex Surf3C
@@ -2569,7 +2688,7 @@ The function draws isosurface plot for 3d array specified parametrically @var{a}
 @deftypefnx {C function} @code{void} mgl_surf3c (@code{HMGL} gr, @code{HCDT} a, @code{HCDT} c, @code{const char *}sch, @code{const char *}opt)
 @deftypefnx {C function} @code{void} mgl_surf3c_xyz (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} y, @code{HCDT} z, @code{HCDT} a, @code{HCDT} c, @code{const char *}sch, @code{const char *}opt)
 @end ifclear
-Draws @var{num}-th uniformly distributed in color range isosurfaces for 3d data. Here @var{num} is equal to parameter @var{value} in options @var{opt} (default is 3).
+Draws @var{num}-th uniformly distributed in color range isosurfaces for 3d data. Here @var{num} is equal to parameter @code{value} in options @var{opt} (default is 3).
 @end deftypefn
 
 
@@ -2605,7 +2724,7 @@ The function draws isosurface plot for 3d array specified parametrically @var{a}
 @deftypefnx {C function} @code{void} mgl_surf3a (@code{HMGL} gr, @code{HCDT} a, @code{HCDT} c, @code{const char *}sch, @code{const char *}opt)
 @deftypefnx {C function} @code{void} mgl_surf3a_xyz (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} y, @code{HCDT} z, @code{HCDT} a, @code{HCDT} c, @code{const char *}sch, @code{const char *}opt)
 @end ifclear
-Draws @var{num}-th uniformly distributed in color range isosurfaces for 3d data. At this array @var{c} can be vector with values of transparency and @var{num}=@var{c}.nx. In opposite case @var{num} is equal to parameter @var{value} in options @var{opt} (default is 3).
+Draws @var{num}-th uniformly distributed in color range isosurfaces for 3d data. At this array @var{c} can be vector with values of transparency and @var{num}=@var{c}.nx. In opposite case @var{num} is equal to parameter @code{value} in options @var{opt} (default is 3).
 @end deftypefn
 
 @anchor{tiles}
@@ -2649,6 +2768,7 @@ Draws spectrogram of complex array @var{re}+i*@var{im} for Fourier size of @var{
 @external{}
 @node Vector fields, Other plotting, Dual plotting, MathGL core
 @section Vector fields
+ at nav{}
 @cindex Traj
 @cindex Vect
 @cindex Dew
@@ -2667,7 +2787,7 @@ These functions perform plotting of 2D and 3D vector fields. There are 5 general
 @deftypefnx {C function} @code{void} mgl_traj_xyz (@code{HMGL} gr, @code{HCDT}x, @code{HCDT}y, @code{HCDT}z, @code{HCDT}ax, @code{HCDT}ay, @code{HCDT}az, @code{const char *}sch, @code{const char *}opt)
 @deftypefnx {C function} @code{void} mgl_traj_xy (@code{HMGL} gr, @code{HCDT}x, @code{HCDT}y, @code{HCDT}ax, @code{HCDT}ay, @code{const char *}sch, @code{const char *}opt)
 @end ifclear
-The function draws vectors @{@var{ax}, @var{ay}, @var{az}@} along a curve @{@var{x}, @var{y}, @var{z}@}. The length of arrows are proportional to @math{\sqrt@{ax^2+ay^2+az^2@}}. String @var{pen} specifies the color (see @ref{Line styles}). By default (@code{pen=""}) color from palette is used (see @ref{Palette and colors}). Option @var{value} set the vector length factor (if non-zero) or vector length to be proportional the distance between curve points (if @var{value}=0). The minor size [...]
+The function draws vectors @{@var{ax}, @var{ay}, @var{az}@} along a curve @{@var{x}, @var{y}, @var{z}@}. The length of arrows are proportional to @math{\sqrt@{ax^2+ay^2+az^2@}}. String @var{pen} specifies the color (see @ref{Line styles}). By default (@code{pen=""}) color from palette is used (see @ref{Palette and colors}). Option @code{value} set the vector length factor (if non-zero) or vector length to be proportional the distance between curve points (if @code{value=0}). The minor si [...]
 @end deftypefn
 
 @anchor{vect}
@@ -2748,7 +2868,7 @@ The function draws dew-drops for plane vector field @{@var{ax}, @var{ay}@} depen
 @deftypefnx {C function} @code{void} mgl_flow_2d (@code{HMGL} gr, @code{HCDT} ax, @code{HCDT} ay, @code{const char *}sch, @code{const char *}opt)
 @deftypefnx {C function} @code{void} mgl_flow_xy (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} y, @code{HCDT} ax, @code{HCDT} ay, @code{const char *}sch, @code{const char *}opt)
 @end ifclear
-The function draws flow threads for the plane vector field @{@var{ax}, @var{ay}@} parametrically depending on coordinates @var{x}, @var{y} at level @var{z} = @var{Min}.z. Number of threads is proportional to @var{value} option (default is 5). String @var{sch} may contain:
+The function draws flow threads for the plane vector field @{@var{ax}, @var{ay}@} parametrically depending on coordinates @var{x}, @var{y} at level @var{z} = @var{Min}.z. Number of threads is proportional to @code{value} option (default is 5). String @var{sch} may contain:
 @itemize @bullet
 @item
 color scheme -- up-half (warm) corresponds to normal flow (like attractor), bottom-half (cold) corresponds to inverse flow (like source);
@@ -2807,7 +2927,7 @@ This is 3D version of the previous functions.
 @deftypefnx {C function} @code{void} mgl_grad_xy (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} y, @code{HCDT} phi, @code{const char *}sch, @code{const char *}opt)
 @deftypefnx {C function} @code{void} mgl_grad_xyz (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} y, @code{HCDT} z, @code{HCDT} phi, @code{const char *}sch, @code{const char *}opt)
 @end ifclear
-The function draws gradient lines for scalar field @var{phi}[i,j] (or @var{phi}[i,j,k] in 3d case) specified parametrically @{@var{x}[i,j,k], @var{y}[i,j,k], @var{z}[i,j,k]@}. Number of lines is proportional to @var{value} option (default is 5). See also @ref{dens}, @ref{cont}, @ref{flow}.
+The function draws gradient lines for scalar field @var{phi}[i,j] (or @var{phi}[i,j,k] in 3d case) specified parametrically @{@var{x}[i,j,k], @var{y}[i,j,k], @var{z}[i,j,k]@}. Number of lines is proportional to @code{value} option (default is 5). See also @ref{dens}, @ref{cont}, @ref{flow}.
 @end deftypefn
 
 @anchor{pipe}
@@ -2819,7 +2939,7 @@ The function draws gradient lines for scalar field @var{phi}[i,j] (or @var{phi}[
 @deftypefnx {C function} @code{void} mgl_pipe_2d (@code{HMGL} gr, @code{HCDT} ax, @code{HCDT} ay, @code{const char *}sch, @code{mreal} r0, @code{const char *}opt)
 @deftypefnx {C function} @code{void} mgl_pipe_xy (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} y, @code{HCDT} ax, @code{HCDT} ay, @code{const char *}sch, @code{mreal} r0, @code{const char *}opt)
 @end ifclear
-The function draws flow pipes for the plane vector field @{@var{ax}, @var{ay}@} parametrically depending on coordinates @var{x}, @var{y} at level @var{z} = @var{Min}.z. Number of pipes is proportional to @var{value} option (default is 5). If @samp{#} symbol is specified then pipes start only from edges of axis range. The color of lines is proportional to @math{\sqrt@{ax^2+ay^2@}}. Warm color corresponds to normal flow (like attractor). Cold one corresponds to inverse flow (like source).  [...]
+The function draws flow pipes for the plane vector field @{@var{ax}, @var{ay}@} parametrically depending on coordinates @var{x}, @var{y} at level @var{z} = @var{Min}.z. Number of pipes is proportional to @code{value} option (default is 5). If @samp{#} symbol is specified then pipes start only from edges of axis range. The color of lines is proportional to @math{\sqrt@{ax^2+ay^2@}}. Warm color corresponds to normal flow (like attractor). Cold one corresponds to inverse flow (like source). [...]
 @end deftypefn
 
 @deftypefn {MGL command} {} pipe udat vdat wdat ['sch'='' @code{r0=0.05}]
@@ -2838,6 +2958,7 @@ This is 3D version of the first functions. Here arrays @var{ax}, @var{ay}, @var{
 @external{}
 @node Other plotting, Nonlinear fitting, Vector fields, MathGL core
 @section Other plotting
+ at nav{}
 @cindex DensXYZ
 @cindex ContXYZ
 @cindex ContFXYZ
@@ -2878,7 +2999,7 @@ These plotting functions draw density plot in x, y, or z plain. If @var{a} is a
 @deftypefnx {C function} @code{void} mgl_cont_y (@code{HMGL} gr, @code{HCDT} a, @code{const char *}stl, @code{mreal} sVal, @code{const char *}opt)
 @deftypefnx {C function} @code{void} mgl_cont_z (@code{HMGL} gr, @code{HCDT} a, @code{const char *}stl, @code{mreal} sVal, @code{const char *}opt)
 @end ifclear
-These plotting functions draw contour lines in x, y, or z plain. If @var{a} is a tensor (3-dimensional data) then interpolation to a given @var{sVal} is performed. These functions are useful for creating projections of the 3D data array to the bounding box. See also @ref{ContFXYZ}, @ref{DensXYZ}, @ref{cont}, @ref{Data manipulation}. @sref{Cont projection sample}
+These plotting functions draw contour lines in x, y, or z plain. If @var{a} is a tensor (3-dimensional data) then interpolation to a given @var{sVal} is performed. These functions are useful for creating projections of the 3D data array to the bounding box. Option @code{value} set the number of contours. See also @ref{ContFXYZ}, @ref{DensXYZ}, @ref{cont}, @ref{Data manipulation}. @sref{Cont projection sample}
 @end deftypefn
 
 @ifclear UDAV
@@ -2904,7 +3025,7 @@ The same as previous with manual contour levels.
 @deftypefnx {C function} @code{void} mgl_contf_y (@code{HMGL} gr, @code{HCDT} a, @code{const char *}stl, @code{mreal} sVal, @code{const char *}opt)
 @deftypefnx {C function} @code{void} mgl_contf_z (@code{HMGL} gr, @code{HCDT} a, @code{const char *}stl, @code{mreal} sVal, @code{const char *}opt)
 @end ifclear
-These plotting functions draw solid contours in x, y, or z plain. If @var{a} is a tensor (3-dimensional data) then interpolation to a given @var{sVal} is performed. These functions are useful for creating projections of the 3D data array to the bounding box. See also @ref{ContFXYZ}, @ref{DensXYZ}, @ref{cont}, @ref{Data manipulation}. @sref{ContF projection sample}
+These plotting functions draw solid contours in x, y, or z plain. If @var{a} is a tensor (3-dimensional data) then interpolation to a given @var{sVal} is performed. These functions are useful for creating projections of the 3D data array to the bounding box. Option @code{value} set the number of contours. See also @ref{ContFXYZ}, @ref{DensXYZ}, @ref{cont}, @ref{Data manipulation}. @sref{ContF projection sample}
 @end deftypefn
 
 @ifclear UDAV
@@ -2924,7 +3045,7 @@ The same as previous with manual contour levels.
 @deftypefnx {Method on @code{mglGraph}} @code{void} FPlot (@code{const char *}eqY, @code{const char *}pen=@code{""}, @code{const char *}opt=@code{""})
 @deftypefnx {C function} @code{void} mgl_fplot (@code{HMGL} gr, @code{const char *}eqY, @code{const char *}pen, @code{const char *}opt)
 @end ifclear
-Draws command function @samp{y(x)} at plane @var{z}=@var{Min}.z where @samp{x} variable is changed in @code{xrange}. You do not need to create the data arrays to plot it.  See also @ref{plot}.
+Draws command function @samp{y(x)} at plane @var{z}=@var{Min}.z where @samp{x} variable is changed in @code{xrange}. You do not need to create the data arrays to plot it. Option @code{value} set initial number of points.  See also @ref{plot}.
 @end deftypefn
 
 @deftypefn {MGL command} {} fplot 'x(t)' 'y(t)' 'z(t)' ['pen'='']
@@ -2932,7 +3053,7 @@ Draws command function @samp{y(x)} at plane @var{z}=@var{Min}.z where @samp{x} v
 @deftypefnx {Method on @code{mglGraph}} @code{void} FPlot (@code{const char *}eqX, @code{const char *}eqY, @code{const char *}eqZ, @code{const char *}pen, @code{const char *}opt=@code{""})
 @deftypefnx {C function} @code{void} mgl_fplot_xyz (@code{HMGL} gr, @code{const char *}eqX, @code{const char *}eqY, @code{const char *}eqZ, @code{const char *}pen, @code{const char *}opt)
 @end ifclear
-Draws command parametrical curve @{@samp{x(t)}, @samp{y(t)}, @samp{z(t)}@} where @samp{t} variable is changed in range [0, 1]. You do not need to create the data arrays to plot it. See also @ref{plot}.
+Draws command parametrical curve @{@samp{x(t)}, @samp{y(t)}, @samp{z(t)}@} where @samp{t} variable is changed in range [0, 1]. You do not need to create the data arrays to plot it. Option @code{value} set number of points. See also @ref{plot}.
 @end deftypefn
 
 @anchor{fsurf}
@@ -2941,7 +3062,7 @@ Draws command parametrical curve @{@samp{x(t)}, @samp{y(t)}, @samp{z(t)}@} where
 @deftypefnx {Method on @code{mglGraph}} @code{void} FSurf (@code{const char *}eqZ, @code{const char *}sch=@code{""}, @code{const char *}opt=@code{""});
 @deftypefnx {C function} @code{void} mgl_fsurf (@code{HMGL} gr, @code{const char *}eqZ, @code{const char *}sch, @code{const char *}opt);
 @end ifclear
-Draws command surface for function @samp{z(x,y)} where @samp{x}, @samp{y} variable are changed in @code{xrange, yrange}. You do not need to create the data arrays to plot it. See also @ref{surf}.
+Draws command surface for function @samp{z(x,y)} where @samp{x}, @samp{y} variable are changed in @code{xrange, yrange}. You do not need to create the data arrays to plot it. Option @code{value} set number of points. See also @ref{surf}.
 @end deftypefn
 
 @deftypefn {MGL command} {} fsurf 'x(u,v)' 'y(u,v)' 'z(u,v)' ['sch'='']
@@ -2949,7 +3070,7 @@ Draws command surface for function @samp{z(x,y)} where @samp{x}, @samp{y} variab
 @deftypefnx {Method on @code{mglGraph}} @code{void} FSurf (@code{const char *}eqX, @code{const char *}eqY, @code{const char *}eqZ, @code{const char *}sch=@code{""}, @code{const char *}opt=@code{""})
 @deftypefnx {C function} @code{void} mgl_fsurf_xyz (@code{HMGL} gr, @code{const char *}eqX, @code{const char *}eqY, @code{const char *}eqZ, @code{const char *}sch, @code{const char *}opt)
 @end ifclear
-Draws command parametrical surface @{@samp{x(u,v)}, @samp{y(u,v)}, @samp{z(u,v)}@} where @samp{u}, @samp{v} variable are changed in range [0, 1]. You do not need to create the data arrays to plot it. See also @ref{surf}.
+Draws command parametrical surface @{@samp{x(u,v)}, @samp{y(u,v)}, @samp{z(u,v)}@} where @samp{u}, @samp{v} variable are changed in range [0, 1]. You do not need to create the data arrays to plot it. Option @code{value} set number of points. See also @ref{surf}.
 @end deftypefn
 
 @anchor{triplot}
@@ -2981,7 +3102,7 @@ The function draws the surface of triangles. Triangle vertexes are set by indexe
 @deftypefnx {C function} @code{void} mgl_tricont_xyzcv (@code{HMGL} gr, @code{HCDT} v, @code{HCDT} id, @code{HCDT} x, @code{HCDT} y, @code{HCDT} z, @code{HCDT} c, @code{const char *}sch, @code{const char *}opt)
 @deftypefnx {C function} @code{void} mgl_tricont_xyzv (@code{HMGL} gr, @code{HCDT} v, @code{HCDT} id, @code{HCDT} x, @code{HCDT} y, @code{HCDT} z, @code{const char *}sch, @code{const char *}opt)
 @end ifclear
-The function draws contour lines for surface of triangles at @var{z}=@var{v}[k] (or at  @var{z} = @var{Min}.z if @var{sch} contain symbol @samp{_}). Triangle vertexes are set by indexes @var{id} of data points @{@var{x}[i], @var{y}[i], @var{z}[i]@}. Contours are plotted for @var{z}[i,j]=@var{v}[k] where @var{v}[k] are values of data array @var{v}. String @var{sch} sets the color scheme. Array @var{c} (if specified) is used for contour coloring. First dimensions of @var{id} must be 3 or g [...]
+The function draws contour lines for surface of triangles at @var{z}=@var{v}[k] (or at  @var{z} = @var{Min}.z if @var{sch} contain symbol @samp{_}). Triangle vertexes are set by indexes @var{id} of data points @{@var{x}[i], @var{y}[i], @var{z}[i]@}. Contours are plotted for @var{z}[i,j]=@var{v}[k] where @var{v}[k] are values of data array @var{v}. If @var{v} is absent then arrays of option @code{value} elements  equidistantly distributed in color range is used. String @var{sch} sets the  [...]
 @end deftypefn
 
 @anchor{quadplot}
@@ -3005,10 +3126,12 @@ The function draws the surface of quadrangles. Quadrangles vertexes are set by i
 @ifclear UDAV
 @deftypefnx {Method on @code{mglGraph}} @code{void} Dots (@code{const mglDataA &}x, @code{const mglDataA &}y, @code{const mglDataA &}z, @code{const char *}sch=@code{""}, @code{const char *}opt=@code{""})
 @deftypefnx {Method on @code{mglGraph}} @code{void} Dots (@code{const mglDataA &}x, @code{const mglDataA &}y, @code{const mglDataA &}z, @code{const mglDataA &}a, @code{const char *}sch=@code{""}, @code{const char *}opt=@code{""})
+ at deftypefnx {Method on @code{mglGraph}} @code{void} Dots (@code{const mglDataA &}x, @code{const mglDataA &}y, @code{const mglDataA &}z, @code{const mglDataA &}c, @code{const mglDataA &}a, @code{const char *}sch=@code{""}, @code{const char *}opt=@code{""})
 @deftypefnx {C function} @code{void} mgl_dots (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} y, @code{HCDT} z, @code{const char *}sch, @code{const char *}opt)
 @deftypefnx {C function} @code{void} mgl_dots_a (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} y, @code{HCDT} z, @code{HCDT} a, @code{const char *}sch, @code{const char *}opt)
+ at deftypefnx {C function} @code{void} mgl_dots_ca (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} y, @code{HCDT} z, @code{HCDT} c, @code{HCDT} a, @code{const char *}sch, @code{const char *}opt)
 @end ifclear
-The function draws the arbitrary placed points @{@var{x}[i], @var{y}[i], @var{z}[i]@}. String @var{sch} sets the color scheme. If array @var{a} is specified then it define colors of dots. Arrays @var{x}, @var{y}, @var{z}, @var{a} must have equal sizes. See also @ref{crust}, @ref{mark}, @ref{plot}. @sref{Dots sample}
+The function draws the arbitrary placed points @{@var{x}[i], @var{y}[i], @var{z}[i]@}. String @var{sch} sets the color scheme and kind of marks. If arrays @var{c}, @var{a} are specified then they define colors and transparencies of dots. You can use @ref{tens} plot with style @samp{ .} to draw non-transparent dots with specified colors. Arrays @var{x}, @var{y}, @var{z}, @var{a} must have equal sizes. See also @ref{crust}, @ref{tens}, @ref{mark}, @ref{plot}. @sref{Dots sample}
 @end deftypefn
 
 @anchor{crust}
@@ -3024,6 +3147,7 @@ The function reconstruct and draws the surface for arbitrary placed points @{@va
 @external{}
 @node Nonlinear fitting, Data manipulation, Other plotting, MathGL core
 @section Nonlinear fitting
+ at nav{}
 @cindex Fit
 @cindex FitS
 @cindex PutsFit
@@ -3033,7 +3157,7 @@ The function reconstruct and draws the surface for arbitrary placed points @{@va
 
 These functions fit data to formula. Fitting goal is to find formula parameters for the best fit the data points, i.e. to minimize the sum @math{\sum_i (f(x_i, y_i, z_i) - a_i)^2/s_i^2}. At this, approximation function @samp{f} can depend only on one argument @samp{x} (1D case), on two arguments @samp{x,y} (2D case) and on three arguments @samp{x,y,z} (3D case). The function @samp{f} also may depend on parameters. Normally the list of fitted parameters is specified by @var{var} string (l [...]
 
-Functions Fit() and FitS() do not draw the obtained data themselves. They fill the data @var{fit} by formula @samp{f} with found coefficients and return it. At this, the @samp{x,y,z} coordinates are equidistantly distributed in the axis range. Number of points in @var{fit} is selected as maximal value of @var{fit} size and the value of @var{mglFitPnts}. Note, that this functions use GSL library and do something only if MathGL was compiled with GSL support. @sref{Nonlinear fitting sample}
+Functions Fit() and FitS() do not draw the obtained data themselves. They fill the data @var{fit} by formula @samp{f} with found coefficients and return it. At this, the @samp{x,y,z} coordinates are equidistantly distributed in the axis range. Number of points in @var{fit} is defined by option @code{value} (default is @var{mglFitPnts}=100). Note, that this functions use GSL library and do something only if MathGL was compiled with GSL support. @sref{Nonlinear fitting hints}
 
 @anchor{fits}
 @deftypefn {MGL command} {} fits res adat sdat 'func' 'var' [ini=0]
@@ -3112,6 +3236,7 @@ Get last fitted formula with found coefficients (as numbers).
 @external{}
 @node Data manipulation, , Nonlinear fitting, MathGL core
 @section Data manipulation
+ at nav{}
 @cindex Hist
 @cindex Fill
 @cindex DataGrid
@@ -3127,7 +3252,7 @@ Get last fitted formula with found coefficients (as numbers).
 @deftypefnx {C function} @code{HMDT} mgl_hist_xy (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} y, @code{HCDT} a, @code{const char *}opt)
 @deftypefnx {C function} @code{HMDT} mgl_hist_xyz (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} y, @code{HCDT} z, @code{HCDT} a, @code{const char *}opt)
 @end ifclear
-These functions make distribution (histogram) of data. They do not draw the obtained data themselves. These functions can be useful if user have data defined for random points (for example, after PIC simulation) and he want to produce a plot which require regular data (defined on grid(s)). The range for grids is always selected as axis range. Arrays @var{x}, @var{y}, @var{z} define the positions (coordinates) of random points. Array @var{a} define the data value. Number of points in outp [...]
+These functions make distribution (histogram) of data. They do not draw the obtained data themselves. These functions can be useful if user have data defined for random points (for example, after PIC simulation) and he want to produce a plot which require regular data (defined on grid(s)). The range for grids is always selected as axis range. Arrays @var{x}, @var{y}, @var{z} define the positions (coordinates) of random points. Array @var{a} define the data value. Number of points in outp [...]
 @end deftypefn
 
 
@@ -3148,9 +3273,20 @@ Fills the value of array @samp{u} according to the formula in string @var{eq}. F
 @deftypefnx {Method on @code{mglGraph}} @code{void} DataGrid (@code{mglData &}u, @code{const mglDataA &}x, @code{const mglDataA &}y, @code{const mglDataA &}z, @code{const char *}opt=@code{""})
 @deftypefnx {C function} @code{void} mgl_data_grid (@code{HMGL} gr, @code{HMDT} u, @code{HCDT} x, @code{HCDT} y, @code{HCDT} z, @code{const char *}opt)
 @end ifclear
-Fills the value of array @samp{u} according to the linear interpolation of triangulated surface, found for arbitrary placed points @samp{x}, @samp{y}, @samp{z}. Interpolation is done at points equidistantly distributed in axis range. NAN value is used for grid points placed outside of triangulated surface.
+Fills the value of array @samp{u} according to the linear interpolation of triangulated surface, found for arbitrary placed points @samp{x}, @samp{y}, @samp{z}. Interpolation is done at points equidistantly distributed in axis range. NAN value is used for grid points placed outside of triangulated surface. @sref{Making regular data}
 @end deftypefn
 
+ at deftypefn {MGL command} {} refill dat xdat vdat [sl=-1]
+ at deftypefnx {MGL command} {} refill dat xdat ydat vdat [sl=-1]
+ at deftypefnx {MGL command} {} refill dat xdat ydat zdat vdat
+ at ifclear UDAV
+ at deftypefnx {Method on @code{mglData}} @code{void} Refill (@code{mglDataA &}dat, @code{const mglDataA &}x, @code{const mglDataA &}v, @code{long} sl=@code{-1}, @code{const char *}opt=@code{""})
+ at deftypefnx {Method on @code{mglData}} @code{void} Refill (@code{mglDataA &}dat, @code{const mglDataA &}x, @code{const mglDataA &}y, @code{const mglDataA &}v, @code{long} sl=@code{-1}, @code{const char *}opt=@code{""})
+ at deftypefnx {Method on @code{mglData}} @code{void} Refill (@code{mglDataA &}dat, @code{const mglDataA &}x, @code{const mglDataA &}y, @code{const mglDataA &}z, @code{const mglDataA &}v, @code{const char *}opt=@code{""})
+ at deftypefnx {C function} @code{void} mgl_data_refill_gr (@code{HMGL} gr, @code{HMDT} a, @code{HCDT} x, @code{HCDT} y, @code{HCDT} z, @code{HCDT} v, @code{long} sl, @code{const char *}opt)
+ at end ifclear
+Fills by interpolated values of array @var{v} at the point @{@var{x}, @var{y}, @var{z}@}=@{@code{X[i], Y[j], Z[k]}@} (or @{@var{x}, @var{y}, @var{z}@}=@{@code{X[i,j,k], Y[i,j,k], Z[i,j,k]}@} if @var{x}, @var{y}, @var{z} are not 1d arrays), where @code{X,Y,Z} are equidistantly distributed in axis range and have the same sizes as array @var{dat}. If parameter @var{sl} is 0 or positive then changes will be applied only for slice @var{sl}.
+ at end deftypefn
 
 
 @deftypefn {MGL command} {} pde @sc{res} 'ham' ini_re ini_im [@code{dz=0.1 k0=100}]
@@ -3165,6 +3301,7 @@ Solves equation du/dz = i*k0*@var{ham}(p,q,x,y,z,|u|)[u], where p=-i/k0*d/dx, q=
 @c @external{}
 @c @node IDTF functions, , Data manipulation, MathGL core
 @c @section IDTF functions
+ at c @nav{}
 
 @c These functions provide IDTF specific features. In all other cases they do nothing.
 
@@ -3184,4 +3321,3 @@ Solves equation du/dz = i*k0*@var{ham}(p,q,x,y,z,|u|)[u], where p=-i/k0*d/dx, q=
 @c @end ifclear
 
 @external{}
-
diff --git a/texinfo/core_ru.texi b/texinfo/core_ru.texi
index ce35e23..76150a5 100644
--- a/texinfo/core_ru.texi
+++ b/texinfo/core_ru.texi
@@ -1,5 +1,6 @@
 @c ------------------------------------------------------------------
 @chapter Ядро MathGL
+ at nav{}
 @cindex mglGraph
 
 @ifset UDAV
@@ -35,6 +36,7 @@
 @external{}
 @node Constructor, Graphics setup, , MathGL core
 @section Создание и удаление графического объекта
+ at nav{}
 
 @ifclear UDAV
 @deftypefn {Конструктор класса @code{mglGraph}} {} mglGraph (@code{int} kind=@code{0}, @code{int} width=@code{600}, @code{int} height=@code{400})
@@ -63,6 +65,7 @@ MGL не требует создания данного типа объекто
 @external{}
 @node Graphics setup, Axis settings, Constructor, MathGL core
 @section Настройка графика
+ at nav{}
 @cindex Настройка MathGL
 
 Функции и переменные в этой группе влияют на вид всего рисунка. Соответственно они должны располагаться @emph{перед} вызовом функций непосредственно рисующих графики.
@@ -82,13 +85,15 @@ MGL не требует создания данного типа объекто
 * Cutting::
 * Font settings::
 * Palette and colors::
+* Masks::
 * Error handling::
 @end menu
 
 @c ==================================================================
- at comment  @external{}
+ at external{}
 @node Transparency, Lighting, , Graphics setup
 @subsection Прозрачность
+ at nav{}
 @cindex Alpha
 @ifclear UDAV
 @cindex SetAlphaDef
@@ -127,9 +132,10 @@ MGL не требует создания данного типа объекто
 @end deftypefn
 
 @c ==================================================================
- at comment  @external{}
+ at external{}
 @node Lighting, Fog, Transparency, Graphics setup
 @subsection Освещение
+ at nav{}
 @ifclear UDAV
 @cindex SetAmbient
 @cindex AddLight
@@ -169,12 +175,13 @@ MGL не требует создания данного типа объекто
 @end deftypefn
 
 @anchor{diffuse}
+ at deftypefn {Команда MGL} {} diffuse @code{val}
 @ifclear UDAV
- at deftypefn {Метод класса @code{mglGraph}} @code{void} SetDifLight (@code{bool} enable)
- at deftypefnx {Функция С} @code{void} mgl_set_light_dif (@code{HMGL} gr, @code{int} enable)
-Задает использование диффузного освещения (только для локальных источников света).
- at end deftypefn
+ at deftypefnx {Метод класса @code{mglGraph}} @code{void} SetDifLight (@code{mreal} bright)
+ at deftypefnx {Функция С} @code{void} mgl_set_difbr (@code{HMGL} gr, @code{mreal} bright)
 @end ifclear
+Задает яркость диффузного освещения (только для локальных источников света).
+ at end deftypefn
 
 @anchor{ambient}
 @deftypefn {Команда MGL} {} ambient @code{val}
@@ -186,9 +193,10 @@ MGL не требует создания данного типа объекто
 @end deftypefn
 
 @c ==================================================================
- at comment  @external{}
+ at external{}
 @node Fog, Default sizes, Lighting, Graphics setup
 @subsection Туман
+ at nav{}
 @cindex Fog
 
 @anchor{fog}
@@ -201,9 +209,10 @@ MGL не требует создания данного типа объекто
 @end deftypefn
 
 @c ==================================================================
- at comment  @external{}
+ at external{}
 @node Default sizes, Cutting, Fog, Graphics setup
 @subsection Базовые размеры
+ at nav{}
 @ifclear UDAV
 @cindex SetBarWidth
 @cindex SetMarkSize
@@ -281,9 +290,10 @@ MGL не требует создания данного типа объекто
 @end ifclear
 
 @c ==================================================================
- at comment  @external{}
+ at external{}
 @node Cutting, Font settings, Default sizes, Graphics setup
 @subsection Обрезание
+ at nav{}
 @ifclear UDAV
 @cindex SetCut
 @cindex SetCutBox
@@ -319,9 +329,10 @@ MGL не требует создания данного типа объекто
 @end deftypefn
 
 @c ==================================================================
- at comment  @external{}
+ at external{}
 @node Font settings, Palette and colors, Cutting, Graphics setup
 @subsection Шрифты
+ at nav{}
 @ifclear UDAV
 @cindex SetFontSize
 @cindex SetFontDef
@@ -351,7 +362,7 @@ MGL не требует создания данного типа объекто
 @end deftypefn
 
 @anchor{loadfont}
- at deftypefn {MGL command} {} loadfont ['name'='']
+ at deftypefn {Команда MGL} {} loadfont ['name'='']
 @ifclear UDAV
 @deftypefnx {Метод класса @code{mglGraph}} @code{void} LoadFont (@code{const char *}name, @code{const char *}path=@code{""})
 @deftypefnx {Функция С} @code{void} mgl_load_font (@code{HMGL} gr, @code{const char *}name, @code{const char *}path)
@@ -397,9 +408,10 @@ MGL не требует создания данного типа объекто
 @end ifclear
 
 @c ==================================================================
- at comment  @external{}
- at node Palette and colors, Error handling, Font settings, Graphics setup
+ at external{}
+ at node Palette and colors, Masks, Font settings, Graphics setup
 @subsection Палитра и цвета
+ at nav{}
 @ifclear UDAV
 @cindex SetPalette
 @end ifclear
@@ -420,15 +432,44 @@ MGL не требует создания данного типа объекто
 Устанавливает @var{sch} в качестве цветовой схемы по умолчанию. Начальное значение @code{"BbcyrR"}.
 @end deftypefn
 
- at deftypefn {Функция С} @code{void} mgl_set_color (@code{char} id, @code{mreal} r, @code{mreal} g, @code{mreal} b)
-Задает RGB значения для цвета с заданным @var{id}.
+ at deftypefn {Метод класса @code{mglGraph}} @code{void} SetColor (@code{char} id, @code{mreal} r, @code{mreal} g, @code{mreal} b) static
+ at deftypefnx {Функция С} @code{void} mgl_set_color (@code{char} id, @code{mreal} r, @code{mreal} g, @code{mreal} b)
+Задает RGB значения для цвета с заданным @var{id}. Изменения действуют глобально для всех последующих использований данного @var{id}.
 @end deftypefn
 @end ifclear
 
 @c ==================================================================
- at comment  @external{}
- at node Error handling, , Palette and colors, Graphics setup
+ at external{}
+ at node Masks, Error handling, Palette and colors, Graphics setup
+ at subsection Маски
+ at nav{}
+ at cindex SetMask
+ at cindex SetMaskAngle
+
+ at anchor{mask}
+ at deftypefn {Команда MGL} {} mask 'id' 'hex'
+ at ifclear UDAV
+ at deftypefnx {Метод класса @code{mglGraph}} @code{void} SetMask (@code{char} id, @code{const char *}hex)
+ at deftypefnx {Метод класса @code{mglGraph}} @code{void} SetMask (@code{char} id, @code{uint64_t} hex)
+ at deftypefnx {Функция С} @code{void} mgl_set_mask (@code{HMGL} gr, @code{const char *}hex)
+ at deftypefnx {Функция С} @code{void} mgl_set_mask_val (@code{HMGL} gr, @code{uint64_t} hex)
+ at end ifclear
+Задает новую матрицу @var{hex} размером 8*8 для маски с заданным @var{id}. Изменения действуют глобально для всех последующих использований данного @var{id}. Значения по умолчанию (см. @ref{Color scheme}): @samp{-} -- 000000FF00000000, @samp{+} -- 080808FF08080808,	@samp{=} -- 0000FF00FF000000,	@samp{;} -- 0000007700000000, @samp{o} -- 0000182424180000,	@samp{O} -- 0000183C3C180000,	@samp{s} -- 00003C24243C0000,	@samp{S} -- 00003C3C3C3C0000, @samp{~} -- 0000060990600000,	@samp{<} -- 0060 [...]
+ at end deftypefn
+
+ at deftypefn {Команда MGL} {} mask angle
+ at ifclear UDAV
+ at deftypefnx {Метод класса @code{mglGraph}} @code{void} SetMaskAngle (@code{int} angle)
+ at deftypefnx {Функция С} @code{void} mgl_set_mask_angle (@code{HMGL} gr, @code{int} angle)
+ at end ifclear
+Задает угол поворота маски в градусах. Отмечу, что символы @samp{\}, @samp{/}, @samp{I} в цветовой схеме задают угол поворота в 45, -45 и 90 градусов соответственно.
+ at end deftypefn
+
+ at c ==================================================================
+ at external{}
+ at node Error handling, , Masks, Graphics setup
 @subsection Обработка ошибок
+ at nav{}
 @ifclear UDAV
 @cindex Message
 @cindex SetWarn
@@ -446,8 +487,8 @@ MGL не требует создания данного типа объекто
 Возвращает текст предупреждений о причине отсутствия графика. Если возвращаемая строка пустая, то сообщений нет.
 @end deftypefn
 
- at deftypefn {Метод класса @code{mglGraph}} @code{int} GetWarnCode ()
- at deftypefnx {Функция С} @code{int} mgl_get_warn_code (@code{HMGL} gr)
+ at deftypefn {Метод класса @code{mglGraph}} @code{int} GetWarn ()
+ at deftypefnx {Функция С} @code{int} mgl_get_warn (@code{HMGL} gr)
 Возвращает код сообщения о причине отсутствия графика. Возможные значения:
 @table @code
 @item mglWarnNone=0
@@ -464,8 +505,6 @@ MGL не требует создания данного типа объекто
 Не достаточно памяти
 @item mglWarnZero
 Значение данных равно нулю
- at item mglWarnLegA
-Слишком много записей в легенде
 @item mglWarnLeg
 Нет записей в легенде
 @item mglWarnSlc
@@ -480,6 +519,20 @@ Light: ID вне допустимых значений
 Setsize: размер(ы) равны нулю или отрицательны
 @item mglWarnFmt
 Формат не поддерживается
+ at item mglWarnTern
+Диапазоны осей несовместимые
+ at item mglWarnNull
+Указатель равен NULL
+ at item mglWarnSpc
+Не хватает места для графика
+ at item mglScrArg
+Неправильные аргументы команды скрипта MGL
+ at item mglScrCmd
+Неправильная команда в скрипте MGL
+ at item mglScrLong
+Слишком длинная строка в скрипте MGL
+ at item mglScrStr
+Одиночная ' в скрипте MGL
 @end table
 @end deftypefn
 @end ifclear
@@ -489,8 +542,9 @@ Setsize: размер(ы) равны нулю или отрицательны
 @external{}
 @node Axis settings, Subplots and rotation, Graphics setup, MathGL core
 @section Настройки осей координат
+ at nav{}
 
-Эти функции управляет видом и масштабом осей координат. Перед построением для каждой точки выполняются 3 преобразования: сначала определяется возможность рисования точки (см. @ref{Cutting}), далее применяются формулы перехода к криволинейным координатам и наконец точка отображается.
+Эти функции управляет видом и масштабом осей координат. Перед построением для каждой точки выполняются 3 преобразования: сначала определяется возможность рисования точки (см. @ref{Cutting}), далее применяются формулы перехода к криволинейным координатам и наконец точка отображается. Отмечу, что MathGL выдает предупреждение если масштабы осей координат лежат вне области определения формул преобразования координат.
 
 @menu
 * Ranges (bounding box)::
@@ -499,9 +553,10 @@ Setsize: размер(ы) равны нулю или отрицательны
 @end menu
 
 @c ------------------------------------------------------------------
- at comment  @external{}
+ at external{}
 @node Ranges (bounding box), Curved coordinates, , Axis settings
 @subsection Масштаб осей координат
+ at nav{}
 @cindex CRange
 @cindex XRange
 @cindex YRange
@@ -588,9 +643,10 @@ Setsize: размер(ы) равны нулю или отрицательны
 
 
 @c ------------------------------------------------------------------
- at comment  @external{}
+ at external{}
 @node Curved coordinates, Ticks, Ranges (bounding box), Axis settings
 @subsection Криволинейные координаты
+ at nav{}
 @cindex Axis
 @ifclear UDAV
 @cindex SetFunc
@@ -598,7 +654,7 @@ Setsize: размер(ы) равны нулю или отрицательны
 @cindex Ternary
 @end ifclear
 
- at deftypefn {Команда MGL} {} axis 'fx' 'fy' ['fz'='' 'fa'='']
+ at deftypefn {Команда MGL} {} axis 'fx' 'fy' 'fz'='' ['fa'='']
 @ifclear UDAV
 @deftypefnx {Метод класса @code{mglGraph}} @code{void} SetFunc (@code{const char *}EqX, @code{const char *}EqY, @code{const char *}EqZ=@code{""}, @code{const char *}EqA=@code{""})
 @deftypefnx {Функция С} @code{void} mgl_set_func (@code{HMGL} gr, @code{const char *}EqX, @code{const char *}EqY, @code{const char *}EqZ, @code{const char *}EqA)
@@ -620,9 +676,9 @@ Setsize: размер(ы) равны нулю или отрицательны
 @deftypefnx {Метод класса @code{mglGraph}} @code{void} Ternary (@code{int} tern)
 @deftypefnx {Функция С} @code{void} mgl_set_ternary (@code{HMGL} gr, @code{int} tern)
 @end ifclear
-Задает рисование треугольных (Ternary, @var{tern}=@code{1}), пирамидальных (Quaternary, @var{tern}=@code{2}) осей координат и проекций осей координат (@var{tern}=@code{4,5,6}). 
+Задает рисование треугольных (Ternary, @var{tern}=@code{1}), пирамидальных (Quaternary, @var{tern}=@code{2}) осей координат и проекций осей координат (@var{tern}=@code{4,5,6}).
 
-Ternary -- специальный тип графика для 3 зависимых координат (компонент) @var{a}, @var{b}, @var{c} таких, что @var{a}+ at var{b}+ at var{c}=1. MathGL использует только 2 независимые координаты @var{a}=x и @var{b}=y поскольку их достаточно для построения всех графиков. При этом третья координата z является независимым параметром для построения линий уровня, поверхностей и т.д. 
+Ternary -- специальный тип графика для 3 зависимых координат (компонент) @var{a}, @var{b}, @var{c} таких, что @var{a}+ at var{b}+ at var{c}=1. MathGL использует только 2 независимые координаты @var{a}=x и @var{b}=y поскольку их достаточно для построения всех графиков. При этом третья координата z является независимым параметром для построения линий уровня, поверхностей и т.д.
 
 Соответственно Quaternary координаты -- 4 зависимые координаты @var{a}, @var{b}, @var{c} и @var{d}, такие что @var{a}+ at var{b}+ at var{c}+ at var{d}=1. MathGL использует только 2 независимые координаты @var{a}=x, @var{b}=y и @var{d}=z поскольку их достаточно для построения всех графиков.
 
@@ -632,9 +688,10 @@ Ternary -- специальный тип графика для 3 зависим
 @end deftypefn
 
 @c ------------------------------------------------------------------
- at comment  @external{}
+ at external{}
 @node Ticks, , Curved coordinates, Axis settings
 @subsection Метки осей
+ at nav{}
 @cindex AxisStl
 @cindex TickLen
 @cindex Adjust
@@ -729,7 +786,7 @@ Ternary -- специальный тип графика для 3 зависим
 @deftypefnx {Метод класса @code{mglGraph}} @code{void} SetTuneTicks (@code{int} tune, @code{mreal} pos=@code{1.15})
 @deftypefnx {Функция С} @code{void} mgl_tune_ticks (@code{HMGL} gr, @code{int} tune, @code{mreal} pos)
 @end ifclear
-Включает/выключает улучшение вида меток осей путем вынесения общего множителя (для маленьких, типа 0.001...0.002, или больших, типа 1000...2000, значений координат) или общей компоненты (для узкого диапазона, типа 0.999...1.000). Также задает положение @var{pos} общего множителя на оси: =0 около минимального значения, =1 около максимального значения.
+Включает/выключает улучшение вида меток осей путем вынесения общего множителя (для маленьких, типа 0.001...0.002, или больших, типа 1000...2000, значений координат) или общей компоненты (для узкого диапазона, типа 0.999...1.000). Также задает положение @var{pos} общего множителя на оси: =0 около минимального значения, =1 около максимального значения. Если @var{tune}&4 не ноль, то нули будут добавлены для фиксированной ширины всех меток оси.
 @end deftypefn
 
 @anchor{tickshift}
@@ -788,6 +845,7 @@ Ternary -- специальный тип графика для 3 зависим
 @external{}
 @node Subplots and rotation, Export picture, Axis settings, MathGL core
 @section Матрица преобразования
+ at nav{}
 @cindex Aspect
 @cindex Rotate
 @cindex RotateN
@@ -874,7 +932,7 @@ Ternary -- специальный тип графика для 3 зависим
 @end deftypefn
 
 @anchor{rotate}
- at deftypefn {Команда MGL} {} rotate @code{tetz tetx [tety=0]}
+ at deftypefn {Команда MGL} {} rotate @code{tetx tetz [tety=0]}
 @ifclear UDAV
 @deftypefnx {Метод класса @code{mglGraph}} @code{void} Rotate (@code{mreal} TetX, @code{mreal} TetZ, @code{mreal} TetY=@code{0})
 @deftypefnx {Функция С} @code{void} mgl_rotate (@code{HMGL} gr, @code{mreal} TetX, @code{mreal} TetZ, @code{mreal} TetY)
@@ -952,6 +1010,7 @@ Ternary -- специальный тип графика для 3 зависим
 @external{}
 @node Export picture, Primitives, Subplots and rotation, MathGL core
 @section Экспорт рисунка
+ at nav{}
 @cindex SetSize
 
 Функции в этой группе сохраняют или дают доступ к полученному рисунку. Поэтом обычно они должны вызываться в конце рисования.
@@ -971,13 +1030,13 @@ Ternary -- специальный тип графика для 3 зависим
 @deftypefnx {Метод класса @code{mglGraph}} @code{void} SetQuality (@code{int} val=@code{MGL_DRAW_NORM})
 @deftypefnx {Функция С} @code{void} mgl_set_quality (@code{HMGL} gr, @code{int} val)
 @end ifclear
-Задает качество графика в зависимости от значения @var{val}: @code{MGL_DRAW_WIRE=0} -- нет рисования граней (наиболее быстрый), @code{MGL_DRAW_FAST=1} -- нет интерполяции цвета (быстрый), @code{MGL_DRAW_NORM=2} -- высокое качество (нормальный), @code{MGL_DRAW_HIGH=3} -- высокое качество с рисованием 3d примитивов (стрелок и маркеров). Если установлен бит @code{MGL_DRAW_LMEM=0x4}, то происходит прямое рисование в растровое изображение (меньше затраты памяти).
+Задает качество графика в зависимости от значения @var{val}: @code{MGL_DRAW_WIRE=0} -- нет рисования граней (наиболее быстрый), @code{MGL_DRAW_FAST=1} -- нет интерполяции цвета (быстрый), @code{MGL_DRAW_NORM=2} -- высокое качество (нормальный), @code{MGL_DRAW_HIGH=3} -- высокое качество с рисованием 3d примитивов (стрелок и маркеров). Если установлен бит @code{MGL_DRAW_LMEM=0x4}, то происходит прямое рисование в растровое изображение (меньше затраты памяти). Если установлен бит @code{MGL [...]
 @end deftypefn
 
 @ifclear UDAV
 @deftypefn {Метод класса @code{mglGraph}} @code{int} GetQuality ()
 @deftypefnx {Функция С} @code{void} mgl_get_quality (@code{HMGL} gr)
-Возвращает качество графика: @code{MGL_DRAW_WIRE=0} -- нет рисования граней (наиболее быстрый), @code{MGL_DRAW_FAST=1} -- нет интерполяции цвета (быстрый), @code{MGL_DRAW_NORM=2} -- высокое качество (нормальный), @code{MGL_DRAW_HIGH=3} -- высокое качество с рисованием 3d примитивов (стрелок и маркеров). Если установлен бит @code{MGL_DRAW_LMEM=0x4}, то происходит прямое рисование в растровое изображение (меньше затраты памяти).
+Возвращает качество графика: @code{MGL_DRAW_WIRE=0} -- нет рисования граней (наиболее быстрый), @code{MGL_DRAW_FAST=1} -- нет интерполяции цвета (быстрый), @code{MGL_DRAW_NORM=2} -- высокое качество (нормальный), @code{MGL_DRAW_HIGH=3} -- высокое качество с рисованием 3d примитивов (стрелок и маркеров). Если установлен бит @code{MGL_DRAW_LMEM=0x4}, то происходит прямое рисование в растровое изображение (меньше затраты памяти). Если установлен бит @code{MGL_DRAW_DOTS=0x8}, то рисуются точ [...]
 @end deftypefn
 
 @deftypefn {Метод класса @code{mglGraph}} @code{void} StartGroup (const char *name)
@@ -999,9 +1058,10 @@ Ternary -- специальный тип графика для 3 зависим
 @end menu
 
 @c ==================================================================
- at comment  @external{}
+ at external{}
 @node Export to file, Frames/Animation, , Export picture
 @subsection Экспорт в файл
+ at nav{}
 @cindex Write
 @ifclear UDAV
 @cindex WriteFrame
@@ -1143,9 +1203,10 @@ Ternary -- специальный тип графика для 3 зависим
 
 
 @c ##################################################################
- at comment  @external{}
+ at external{}
 @node Frames/Animation, Bitmap in memory, Export to file, Export picture
 @subsection Кадры/Анимация
+ at nav{}
 
 @ifset UDAV
 В MGL нет специальных команд для создания анимации. Однако можно воспользоваться возможностями утилит @code{mglconv} и @code{mglview}. Например, используя комментарии спеиального вида @samp{##a } или @samp{##c }.
@@ -1213,9 +1274,10 @@ Ternary -- специальный тип графика для 3 зависим
 @end ifclear
 
 @c ------------------------------------------------------------------
- at comment  @external{}
+ at external{}
 @node Bitmap in memory, Parallelization, Frames/Animation, Export picture
 @subsection Рисование в памяти
+ at nav{}
 
 @ifclear UDAV
 Эти функции возвращают созданный растровый рисунок, его ширину и высоту. В дальнейшем его можно использовать в любой графической библиотеке (см. также, @ref{Widget classes}) или сохранить в файл (см. также, @ref{Export to file}).
@@ -1283,12 +1345,18 @@ gr.GetBGRN(bits, len(bits));
 Проверяет близка ли точка @{@var{xs}, @var{ys}@} к активной точке (т.е. mglBase::Act) с точностью @var{d} и возвращает индекс активной точки или @code{-1} если не найдено. Активные точки -- специальные точки, которые характеризуют примитивы (например, вершины). Это функция только для опытных пользователей.
 @end deftypefn
 
+ at deftypefn {Метод класса @code{mglGraph}} @code{long} SetDrawReg (@code{int} nx=@code{1}, @code{int} ny=@code{1}, @code{int} m=@code{0})
+ at deftypefnx {Функция С} @code{long} mgl_set_draw_reg (@code{HMGL} gr, @code{int} nx, @code{int} ny, @code{int} m)
+Ограничивает рисование прямоугольной областью @var{m}-ой клетки матрицы размером @var{nx}*@var{ny} (аналогично @ref{subplot}). Функция может бытб использована для ускорения вывода путем уменьшения выводимых примитивов. Это функция только для опытных пользователей.
+ at end deftypefn
+
 @end ifclear
 
 @c ------------------------------------------------------------------
- at comment  @external{}
+ at external{}
 @node Parallelization, , Bitmap in memory, Export picture
 @subsection Распараллеливание
+ at nav{}
 
 @ifclear UDAV
 @cindex Combine
@@ -1324,6 +1392,7 @@ gr.GetBGRN(bits, len(bits));
 @external{}
 @node Primitives, Text printing, Export picture, MathGL core
 @section Рисование примитивов
+ at nav{}
 @cindex Ball
 @cindex Clf
 @cindex Line
@@ -1345,11 +1414,13 @@ gr.GetBGRN(bits, len(bits));
 Эти функции рисуют рисуют простые объекты типа линий, точек, сфер, капель, конусов, и т.д.
 
 @anchor{clf}
- at deftypefn {Команда MGL} {} clf
+ at deftypefn {Команда MGL} {} clf ['col']
 @ifclear UDAV
 @deftypefnx {Метод класса @code{mglGraph}} @code{void} Clf ()
+ at deftypefnx {Метод класса @code{mglGraph}} @code{void} Clf (@code{char} col)
 @deftypefnx {Метод класса @code{mglGraph}} @code{void} Clf (@code{mreal} r, @code{mreal} g, @code{mreal} b)
 @deftypefnx {Функция С} @code{void} mgl_clf (@code{HMGL} gr)
+ at deftypefnx {Функция С} @code{void} mgl_clf_chr (@code{HMGL} gr, @code{char} col)
 @deftypefnx {Функция С} @code{void} mgl_clf_rgb (@code{HMGL} gr, @code{mreal} r, @code{mreal} g, @code{mreal} b)
 @end ifclear
 Очищает рисунок и заполняет его заданным цветом.
@@ -1407,8 +1478,8 @@ gr.GetBGRN(bits, len(bits));
 @end deftypefn
 
 @anchor{rect}
- at deftypefn {MGL command} {} rect @code{x1 y1 x2 y2} ['stl'='']
- at deftypefnx {MGL command} {} rect @code{x1 y1 z1 x2 y2 z2} ['stl'='']
+ at deftypefn {Команда MGL} {} rect @code{x1 y1 x2 y2} ['stl'='']
+ at deftypefnx {Команда MGL} {} rect @code{x1 y1 z1 x2 y2 z2} ['stl'='']
 Рисует закрашенный прямоугольник (грань) с вершинами @{@var{x1}, @var{y1}, @var{z1}@} и @{@var{x2}, @var{y2}, @var{z2}@} цветом @var{stl}. При этом цвет может быть один для всей грани, или различным для разных вершин если указаны все 4 цвета. Грань будет нарисована даже если часть ее лежит вне диапазона осей координат.
 @end deftypefn
 
@@ -1455,7 +1526,18 @@ gr.GetBGRN(bits, len(bits));
 @deftypefnx {Метод класса @code{mglGraph}} @code{void} Cone (@code{mglPoint} p1, @code{mglPoint} p2, @code{mreal} r1, @code{mreal} r2=@code{-1}, @code{const char *}stl=@code{"B"}, @code{bool} edge=@code{false})
 @deftypefnx {Функция С} @code{void} mgl_cone (@code{HMGL} gr, @code{mreal} x1, @code{mreal} y1, @code{mreal} z1, @code{mreal} x2, @code{mreal} y2, @code{mreal} z2, @code{mreal} r1, @code{mreal} r2, @code{const char *}stl, @code{int} draw_edge)
 @end ifclear
-Рисует трубу (или усеченный конус если @var{edge}=@code{false}) между точками @var{p1}, @var{p2} с радиусами на концах @var{r1}, @var{r2}. Если @var{r2}<0, то полагается @var{r2}=@var{r1}. Цвет конуса задается строкой @var{stl}.
+Рисует трубу (или усеченный конус если @var{edge}=@code{false}) между точками @var{p1}, @var{p2} с радиусами на концах @var{r1}, @var{r2}. Если @var{r2}<0, то полагается @var{r2}=@var{r1}. Цвет конуса задается строкой @var{stl}. Параметр @var{stl} может содержать:
+ at itemize @bullet
+ at item
+ at samp{@@} для рисования торцов;
+ at item
+ at samp{#} для сетчатой фигуры;
+ at item
+ at samp{t} для рисования цилиндра вместо конуса/призмы;
+ at item
+ at samp{4}, @samp{6}, @samp{8}, @samp{t} для рисования квадратной, шестиугольной или восьмиугольной призмы вместо конуса.
+ at end itemize
+
 @end deftypefn
 
 @anchor{circle}
@@ -1472,7 +1554,7 @@ gr.GetBGRN(bits, len(bits));
 @deftypefnx {Команда MGL} {} ellipse @code{x1 y1 z1 x2 y2 z2 r} ['col'='r']
 @ifclear UDAV
 @deftypefnx {Метод класса @code{mglGraph}} @code{void} Ellipse (@code{mglPoint} p1, @code{mglPoint} p2, @code{mreal} r, @code{const char *}col=@code{"r"})
- at deftypefnx {Функция С} @code{void} mgl_ellipse(@code{HMGL} gr, @code{mreal} x1, @code{mreal} y1, @code{mreal} z1, @code{mreal} x2, @code{mreal} y2, @code{mreal} z2, @code{mreal} r, @code{const char *}col)
+ at deftypefnx {Функция С} @code{void} mgl_ellipse (@code{HMGL} gr, @code{mreal} x1, @code{mreal} y1, @code{mreal} z1, @code{mreal} x2, @code{mreal} y2, @code{mreal} z2, @code{mreal} r, @code{const char *}col)
 @end ifclear
 Рисует круг радиуса @var{r} с фокусами в точках @var{p1}, @var{p2} цветом @var{stl}. Если @var{col} содержит: @samp{#} то рисуется только граница, @samp{@@} то рисуется граница (вторым цветом из @var{col} или черными).
 @end deftypefn
@@ -1482,7 +1564,7 @@ gr.GetBGRN(bits, len(bits));
 @deftypefnx {Команда MGL} {} rhomb @code{x1 y1 z1 x2 y2 z2 r} ['col'='r']
 @ifclear UDAV
 @deftypefnx {Метод класса @code{mglGraph}} @code{void} Rhomb (@code{mglPoint} p1, @code{mglPoint} p2, @code{mreal} r, @code{const char *}col=@code{"r"})
- at deftypefnx {Функция С} @code{void} mgl_rhomb(@code{HMGL} gr, @code{mreal} x1, @code{mreal} y1, @code{mreal} z1, @code{mreal} x2, @code{mreal} y2, @code{mreal} z2, @code{mreal} r, @code{const char *}col)
+ at deftypefnx {Функция С} @code{void} mgl_rhomb (@code{HMGL} gr, @code{mreal} x1, @code{mreal} y1, @code{mreal} z1, @code{mreal} x2, @code{mreal} y2, @code{mreal} z2, @code{mreal} r, @code{const char *}col)
 @end ifclear
 Рисует ромб ширины @var{r} с вершинами в точках @var{p1}, @var{p2} цветом @var{stl}. Если @var{col} содержит: @samp{#} то рисуется только граница, @samp{@@} то рисуется граница (вторым цветом из @var{col} или черными). Если @var{col} содержит 3 цвета, то используется градиентная заливка.
 @end deftypefn
@@ -1491,6 +1573,7 @@ gr.GetBGRN(bits, len(bits));
 @external{}
 @node Text printing, Axis and Colorbar, Primitives, MathGL core
 @section Вывод текста
+ at nav{}
 @ifclear UDAV
 @cindex Puts
 @cindex Putsw
@@ -1561,6 +1644,7 @@ gr.GetBGRN(bits, len(bits));
 @external{}
 @node Axis and Colorbar, Legend, Text printing, MathGL core
 @section Оси и Colorbar
+ at nav{}
 @cindex Axis
 @cindex Box
 @cindex Grid
@@ -1575,7 +1659,7 @@ gr.GetBGRN(bits, len(bits));
 @deftypefnx {Метод класса @code{mglGraph}} @code{void} Axis (@code{const char *}dir=@code{"xyz"}, @code{const char *}stl=@code{""}, @code{const char *}opt=@code{""})
 @deftypefnx {Функция С} @code{void} mgl_axis (@code{HMGL} gr, @code{const char *}dir, @code{const char *}stl, @code{const char *}opt)
 @end ifclear
-Рисует оси координат и метки на них (см. @ref{Axis settings}) в направлениях @samp{xyz}, указанных строкой @var{dir}. Заглавные буквы @samp{XYZ} приведут к расположению меток с другой стороны от оси. Если строка содержит символ @samp{_}, то подписи меток отображаться не будут. Если строка содержит символ @samp{AKDTVISO}, то будет нарисована соответствующая стрелка на конце оси. Стиль меток и оси(ей) задается строкой @var{stl}. @sref{Axis and ticks}
+Рисует оси координат и метки на них (см. @ref{Axis settings}) в направлениях @samp{xyz}, указанных строкой @var{dir}. Заглавные буквы @samp{XYZ} приведут к расположению меток с другой стороны от оси. Если строка содержит символ @samp{_}, то подписи меток отображаться не будут. Если строка содержит символ @samp{^}, то инвертируется положение осей по умолчанию. Если строка содержит символ @samp{AKDTVISO}, то будет нарисована соответствующая стрелка на конце оси. Стиль меток и оси(ей) задае [...]
 @end deftypefn
 
 @anchor{colorbar}
@@ -1651,13 +1735,14 @@ gr.GetBGRN(bits, len(bits));
 @external{}
 @node Legend, 1D plotting, Axis and Colorbar, MathGL core
 @section Легенда
+ at nav{}
 @cindex Legend
 @cindex AddLegend
 @cindex ClearLegend
 @cindex SetLegendBox
 @cindex SetLegendMarks
 
-Эти функции обеспечивают рисование легенды графика (полезно для @ref{1D plotting}). Запись в легенде состоит из двух строк: одна для стиля линии и маркеров, другая с текстом описания (с включенным разбором TeX-их команд). Можно использовать непосредственно массивы строк, или накопление во внутренние массивы с помощью функции AddLegend() с последующим отображением. Положение легенды можно задать автоматически или вручную. Параметры @var{fnt} и @var{size} задают стиль и размер шрифта (см.  [...]
+Эти функции обеспечивают рисование легенды графика (полезно для @ref{1D plotting}). Запись в легенде состоит из двух строк: одна для стиля линии и маркеров, другая с текстом описания (с включенным разбором TeX-их команд). Можно использовать непосредственно массивы строк, или накопление во внутренние массивы с помощью функции AddLegend() с последующим отображением. Положение легенды можно задать автоматически или вручную. Параметры @var{fnt} и @var{size} задают стиль и размер шрифта (см.  [...]
 
 @anchor{legend}
 @deftypefn {Команда MGL} {} legend [@code{pos=3} 'fnt'='#']
@@ -1665,7 +1750,7 @@ gr.GetBGRN(bits, len(bits));
 @deftypefnx {Метод класса @code{mglGraph}} @code{void} Legend (@code{int} pos=@code{0x3}, @code{const char *}fnt=@code{"#"}, @code{const char *}opt=@code{""})
 @deftypefnx {Функция С} @code{void} mgl_legend (@code{HMGL} gr, @code{int} pos, @code{const char *}fnt, @code{const char *}opt)
 @end ifclear
-Рисует легенду из накопленных записей шрифтом @var{fnt} размером @var{size}. Параметр @var{pos} задает положение легенды: @samp{0} -- в нижнем левом углу, @samp{1} -- нижнем правом углу, @samp{2} -- верхнем левом углу, @samp{3} -- верхнем правом углу (по умолчанию). Строка @var{fnt} может содержать вет для прямоугольника (1-ый цвет), для его границы (2-ой цвет) и для текста (последний). Если указано менее 3 цветов, то цвет рёбер будет чёрным (2 и менее цвета), а цвет прямоугольника белым [...]
+Рисует легенду из накопленных записей шрифтом @var{fnt} размером @var{size}. Параметр @var{pos} задает положение легенды: @samp{0} -- в нижнем левом углу, @samp{1} -- нижнем правом углу, @samp{2} -- верхнем левом углу, @samp{3} -- верхнем правом углу (по умолчанию). Строка @var{fnt} может содержать вет для прямоугольника (1-ый цвет), для его границы (2-ой цвет) и для текста (последний). Если указано менее 3 цветов, то цвет рёбер будет чёрным (2 и менее цвета), а цвет прямоугольника белым [...]
 @end deftypefn
 
 @deftypefn {Команда MGL} {} legend @code{x y} ['fnt'='#']
@@ -1673,7 +1758,7 @@ gr.GetBGRN(bits, len(bits));
 @deftypefnx {Метод класса @code{mglGraph}} @code{void} Legend (@code{mreal} x, @code{mreal} y, @code{const char *}fnt=@code{"#"}, @code{const char *}opt=@code{""})
 @deftypefnx {Функция С} @code{void} mgl_legend_pos (@code{HMGL} gr, @code{mreal} x, @code{mreal} y, @code{const char *}fnt, @code{const char *}opt)
 @end ifclear
-Рисует легенду из накопленных записей шрифтом @var{fnt} размером @var{size}. Положение легенды задается параметрами @var{x}, @var{y}, которые полагаются нормированными в диапазоне [0,1].
+Рисует легенду из накопленных записей шрифтом @var{fnt} размером @var{size}. Положение легенды задается параметрами @var{x}, @var{y}, которые полагаются нормированными в диапазоне [0,1]. Опция @code{value} задает зазор между примером линии и текстом (по умолчанию 0.1).
 @end deftypefn
 
 @anchor{addlegend}
@@ -1709,6 +1794,7 @@ gr.GetBGRN(bits, len(bits));
 @external{}
 @node 1D plotting, 2D plotting, Legend, MathGL core
 @section 1D графики
+ at nav{}
 @cindex Plot
 @cindex Radar
 @cindex Tens
@@ -1755,7 +1841,7 @@ gr.GetBGRN(bits, len(bits));
 @deftypefnx {Метод класса @code{mglGraph}} @code{void} Radar (@code{const mglDataA &}a, @code{const char *}pen=@code{""}, @code{const char *}opt=@code{""})
 @deftypefnx {Функция С} @code{void} mgl_radar (@code{HMGL} gr, @code{HCDT} a, @code{const char *}pen, @code{const char *}opt)
 @end ifclear
-Функции рисуют radar chart, представляющий собой ломанную с вершинами на радиальных линиях (типа ломанной в полярных координатах). Параметр @var{value} в опциях @var{opt} задает дополнительный сдвиг данных (т.е. использование @var{a}+ at var{value} вместо @var{a}). Если @var{pen} содержит @samp{#}, то рисуется "сетка" (радиальные линии). См. также @ref{plot}. @sref{Radar sample}
+Функции рисуют radar chart, представляющий собой ломанную с вершинами на радиальных линиях (типа ломанной в полярных координатах). Параметр @code{value} в опциях @var{opt} задает дополнительный сдвиг данных (т.е. использование @var{a}+ at code{value} вместо @var{a}). Если @var{pen} содержит @samp{#}, то рисуется "сетка" (радиальные линии). См. также @ref{plot}. @sref{Radar sample}
 @end deftypefn
 
 @anchor{step}
@@ -1800,7 +1886,7 @@ gr.GetBGRN(bits, len(bits));
 @deftypefnx {Функция С} @code{void} mgl_tape_xy (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} y, @code{const char *}pen, @code{const char *}opt)
 @deftypefnx {Функция С} @code{void} mgl_tape_xyz (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} y, @code{HCDT} z, @code{const char *}pen, @code{const char *}opt)
 @end ifclear
-Функции рисуют ленты, которые вращаются вокруг кривой @{@var{x}[i], @var{y}[i], @var{z}[i]@} как её нормали. Начальная лента(ы) выбираются в плоскости x-y (для @samp{x} в @var{pen}) и/или y-z (для @samp{x} в @var{pen}). Ширина лент пропорциональна @ref{barwidth}. См. также @ref{plot}, @ref{flow}, @ref{barwidth}. @sref{Tape sample}
+Функции рисуют ленты, которые вращаются вокруг кривой @{@var{x}[i], @var{y}[i], @var{z}[i]@} как её нормали. Начальная лента(ы) выбираются в плоскости x-y (для @samp{x} в @var{pen}) и/или y-z (для @samp{x} в @var{pen}). Ширина лент пропорциональна @ref{barwidth}, а также может быть изменена опцией @code{value}. См. также @ref{plot}, @ref{flow}, @ref{barwidth}. @sref{Tape sample}
 @end deftypefn
 
 @anchor{area}
@@ -1857,7 +1943,7 @@ gr.GetBGRN(bits, len(bits));
 @deftypefnx {Функция С} @code{void} mgl_bars_xy (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} y, @code{const char *}pen, @code{const char *}opt)
 @deftypefnx {Функция С} @code{void} mgl_bars_xyz (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} y, @code{HCDT} z, @code{const char *}pen, @code{const char *}opt)
 @end ifclear
-Функции рисуют вертикальные полосы (прямоугольники) из точек до плоскости осей координат. Если строка @var{pen} содержит символ @samp{a}, то линии рисуются одна поверх другой. Если строка содержит символ @samp{f}, то рисуется график типа waterfall для определения кумулятивного эффекта последовательности положительных и отрицательных значений. Можно использовать разные цвета для положительных и отрицательных значений если число указанных цветов равно удвоенному числу кривых для построения [...]
+Функции рисуют вертикальные полосы (прямоугольники) из точек до плоскости осей координат. Если строка @var{pen} содержит символ @samp{a}, то линии рисуются одна поверх другой. Если строка содержит символ @samp{f}, то рисуется график типа waterfall для определения кумулятивного эффекта последовательности положительных и отрицательных значений. Можно использовать разные цвета для положительных и отрицательных значений если число указанных цветов равно удвоенному числу кривых для построения [...]
 @end deftypefn
 
 @anchor{barh}
@@ -1869,7 +1955,7 @@ gr.GetBGRN(bits, len(bits));
 @deftypefnx {Функция С} @code{void} mgl_barh (@code{HMGL} gr, @code{HCDT} v, @code{const char *}pen, @code{const char *}opt)
 @deftypefnx {Функция С} @code{void} mgl_barh_xy (@code{HMGL} gr, @code{HCDT} y, @code{HCDT} v, @code{const char *}pen, @code{const char *}opt)
 @end ifclear
-Функции рисуют горизонтальные полосы (прямоугольники) из точек до плоскости осей координат. Если строка @var{pen} содержит символ @samp{a}, то линии рисуются одна поверх другой. Если строка содержит символ @samp{f}, то рисуется график типа waterfall для определения кумулятивного эффекта последовательности положительных и отрицательных значений. Можно использовать разные цвета для положительных и отрицательных значений если число указанных цветов равно удвоенному числу кривых для построен [...]
+Функции рисуют горизонтальные полосы (прямоугольники) из точек до плоскости осей координат. Если строка @var{pen} содержит символ @samp{a}, то линии рисуются одна поверх другой. Если строка содержит символ @samp{f}, то рисуется график типа waterfall для определения кумулятивного эффекта последовательности положительных и отрицательных значений. Можно использовать разные цвета для положительных и отрицательных значений если число указанных цветов равно удвоенному числу кривых для построен [...]
 @end deftypefn
 
 @anchor{cones}
@@ -1884,7 +1970,20 @@ gr.GetBGRN(bits, len(bits));
 @deftypefnx {Функция С} @code{void} mgl_cones_xy (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} y, @code{const char *}pen, @code{const char *}opt)
 @deftypefnx {Функция С} @code{void} mgl_cones_xyz (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} y, @code{HCDT} z, @code{const char *}pen, @code{const char *}opt)
 @end ifclear
-Функции рисуют конусы из точек до плоскости осей координат. Если строка @var{pen} содержит символ @samp{a}, то линии рисуются одна поверх другой. Можно использовать разные цвета для положительных и отрицательных значений если число указанных цветов равно удвоенному числу кривых для построения. См. также @ref{bars}, @ref{barwidth}. @sref{Cones sample}
+Функции рисуют конусы из точек до плоскости осей координат. Если строка @var{pen} содержит символ @samp{a}, то линии рисуются одна поверх другой. Можно использовать разные цвета для положительных и отрицательных значений если число указанных цветов равно удвоенному числу кривых для построения. Параметр @var{pen} может содержать:
+ at itemize @bullet
+ at item
+ at samp{@@} для рисования торцов;
+ at item
+ at samp{#} для сетчатой фигуры;
+ at item
+ at samp{t} для рисования цилиндра вместо конуса/призмы;
+ at item
+ at samp{4}, @samp{6}, @samp{8}, @samp{t} для рисования квадратной, шестиугольной или восьмиугольной призмы вместо конуса;
+ at item
+ at samp{<}, @samp{^} или @samp{>} для выравнивания конусов влево, вправо или по центру относительно их координат.
+ at end itemize
+См. также @ref{bars}, @ref{cone}, @ref{barwidth}. @sref{Cones sample}
 @end deftypefn
 
 
@@ -1907,7 +2006,7 @@ gr.GetBGRN(bits, len(bits));
 @deftypefnx {Функция С} @code{void} mgl_boxplot (@code{HMGL} gr, @code{HCDT} a, @code{const char *}pen, @code{const char *}opt)
 @deftypefnx {Функция С} @code{void} mgl_boxplot_xy (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} a, @code{const char *}pen, @code{const char *}opt)
 @end ifclear
-Функции рисуют boxplot (называемый также как box-and-whisker diagram или как "ящик с усами") в точках @var{x}[i] на плоскости @var{z} = @var{zVal} (по умолчанию @var{z}=@var{Min.z}). Это график, компактно изображающий распределение вероятностей @var{a}[i,j] (минимум, нижний квартиль (Q1), медиана (Q2), верхний квартиль (Q3) и максимум) вдоль второго (j-го) направления. См. также @ref{plot}, @ref{error}, @ref{bars}, @ref{barwidth}. @sref{BoxPlot sample}
+Функции рисуют boxplot (называемый также как box-and-whisker diagram или как "ящик с усами") в точках @var{x}[i] на плоскости @var{z} = @var{zVal} (по умолчанию @var{z}=@var{Min.z}). Это график, компактно изображающий распределение вероятностей @var{a}[i,j] (минимум, нижний квартиль (Q1), медиана (Q2), верхний квартиль (Q3) и максимум) вдоль второго (j-го) направления. Если @var{pen} содержит @samp{<}, @samp{^} или @samp{>}, то полоски будут выровнены влево, вправо или центрированы относ [...]
 @end deftypefn
 
 @anchor{candle}
@@ -1926,7 +2025,19 @@ gr.GetBGRN(bits, len(bits));
 @deftypefnx {Функция С} @code{void} mgl_candle_yv (@code{HMGL} gr, @code{HCDT} v1, @code{HCDT} v2, @code{HCDT} y1, @code{HCDT} y2, @code{const char *}pen, @code{const char *}opt)
 @deftypefnx {Функция С} @code{void} mgl_candle_xyv (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} v1, @code{HCDT} v2, @code{HCDT} y1, @code{HCDT} y2, @code{const char *}pen, @code{const char *}opt)
 @end ifclear
-Функции рисуют candlestick chart в точках @var{x}[i]. Этот график показывает прямоугольником ("свечой") диапазон изменения величины. Прозрачная (белая) свеча соответствует росту величины @var{v1}[i]<@var{v2}[i], чёрная -- уменьшению. "Тени" показывают минимальное @var{y1} и максимальное @var{y2} значения. Если @var{v2} отсутствует, то он определяется как @var{v2}[i]=@var{v1}[i+1]. См. также @ref{plot}, @ref{bars}, @ref{barwidth}. @sref{Candle sample}
+Функции рисуют candlestick chart в точках @var{x}[i]. Этот график показывает прямоугольником ("свечой") диапазон изменения величины. Прозрачная (белая) свеча соответствует росту величины @var{v1}[i]<@var{v2}[i], чёрная -- уменьшению. "Тени" показывают минимальное @var{y1} и максимальное @var{y2} значения. Если @var{v2} отсутствует, то он определяется как @var{v2}[i]=@var{v1}[i+1]. См. также @ref{plot}, @ref{bars}, @ref{ohlc}, @ref{barwidth}. @sref{Candle sample}
+ at end deftypefn
+
+ at anchor{ohlc}
+ at deftypefn {Команда MGL} {} ohlc odat hdat ldat cdat ['stl'='']
+ at deftypefnx {Команда MGL} {} ohlc xdat odat hdat ldat cdat ['stl'='']
+ at ifclear UDAV
+ at deftypefnx {MМетод класса @code{mglGraph}} @code{void} OHLC (@code{const mglDataA &}o, @code{const mglDataA &}h, @code{const mglDataA &}l, @code{const mglDataA &}c, @code{const char *}pen=@code{""}, @code{const char *}opt=@code{""})
+ at deftypefnx {Метод класса @code{mglGraph}} @code{void} OHLC (@code{const mglDataA &}x, @code{const mglDataA &}o, @code{const mglDataA &}h, @code{const mglDataA &}l, @code{const mglDataA &}c, @code{const char *}pen=@code{""}, @code{const char *}opt=@code{""})
+ at deftypefnx {Функция С} @code{void} mgl_ohlc (@code{HMGL} gr, @code{HCDT} o, @code{HCDT} h, @code{HCDT} l, @code{HCDT} c, @code{const char *}pen, @code{const char *}opt)
+ at deftypefnx {Функция С} @code{void} mgl_ohlc_x (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} o, @code{HCDT} h, @code{HCDT} l, @code{HCDT} c, @code{const char *}pen, @code{const char *}opt)
+ at end ifclear
+Функции рисуют Open-High-Low-Close диаграмму. Этот график содержит вертикальные линии между максимальным @var{h} и минимальным @var{l} значениями, и горизонтальные линии перед/после вертикальной линии для начального @var{o} и конечного @var{c} значений процесса (обычно цены). См. также @ref{candle}, @ref{plot}, @ref{barwidth}. @sref{OHLC sample}
 @end deftypefn
 
 
@@ -2008,15 +2119,15 @@ gr.GetBGRN(bits, len(bits));
 @end deftypefn
 
 @anchor{table}
- at deftypefn {MGL command} {} table vdat 'txt' ['stl'='#']
- at deftypefnx {MGL command} {} table x y vdat 'txt' ['stl'='#']
+ at deftypefn {Команда MGL} {} table vdat 'txt' ['stl'='#']
+ at deftypefnx {Команда MGL} {} table x y vdat 'txt' ['stl'='#']
 @ifclear UDAV
- at deftypefnx {Method on @code{mglGraph}} @code{void} Table (@code{const mglDataA &}val, @code{const char *}txt, @code{const char *}fnt=@code{""}, @code{const char *}opt=@code{""})
- at deftypefnx {Method on @code{mglGraph}} @code{void} Table (@code{const mglDataA &}val, @code{const wchar_t *}txt, @code{const char *}fnt=@code{""}, @code{const char *}opt=@code{""})
- at deftypefnx {Method on @code{mglGraph}} @code{void} Table (@code{mreal} x, @code{mreal} y, @code{const mglDataA &}val, @code{const char *}txt, @code{const char *}fnt=@code{""}, @code{const char *}opt=@code{""})
- at deftypefnx {Method on @code{mglGraph}} @code{void} Table (@code{mreal} x, @code{mreal} y, @code{const mglDataA &}val, @code{const wchar_t *}txt, @code{const char *}fnt=@code{""}, @code{const char *}opt=@code{""})
- at deftypefnx {C function} @code{void} mgl_table (@code{HMGL} gr, @code{mreal} x, @code{mreal} y, @code{HCDT} val, @code{const char *}txt, @code{const char *}fnt, @code{const char *}opt)
- at deftypefnx {C function} @code{void} mgl_tablew (@code{HMGL} gr, @code{mreal} x, @code{mreal} y, @code{HCDT} val, @code{const wchar_t *}txt, @code{const char *}fnt, @code{const char *}opt)
+ at deftypefnx {Метод класса @code{mglGraph}} @code{void} Table (@code{const mglDataA &}val, @code{const char *}txt, @code{const char *}fnt=@code{""}, @code{const char *}opt=@code{""})
+ at deftypefnx {Метод класса @code{mglGraph}} @code{void} Table (@code{const mglDataA &}val, @code{const wchar_t *}txt, @code{const char *}fnt=@code{""}, @code{const char *}opt=@code{""})
+ at deftypefnx {Метод класса @code{mglGraph}} @code{void} Table (@code{mreal} x, @code{mreal} y, @code{const mglDataA &}val, @code{const char *}txt, @code{const char *}fnt=@code{""}, @code{const char *}opt=@code{""})
+ at deftypefnx {Метод класса @code{mglGraph}} @code{void} Table (@code{mreal} x, @code{mreal} y, @code{const mglDataA &}val, @code{const wchar_t *}txt, @code{const char *}fnt=@code{""}, @code{const char *}opt=@code{""})
+ at deftypefnx {Функция С} @code{void} mgl_table (@code{HMGL} gr, @code{mreal} x, @code{mreal} y, @code{HCDT} val, @code{const char *}txt, @code{const char *}fnt, @code{const char *}opt)
+ at deftypefnx {Функция С} @code{void} mgl_tablew (@code{HMGL} gr, @code{mreal} x, @code{mreal} y, @code{HCDT} val, @code{const wchar_t *}txt, @code{const char *}fnt, @code{const char *}opt)
 @end ifclear
 Рисует таблицу значений массива @var{val} с заголовками @var{txt} (разделенными символом новой строки @samp{\n}) в точке @{@var{x}, @var{y}@} (по умолчанию @{0,0@}) относительно текущего subplot. Если строка @var{fnt} содержит @samp{#}, то рисуются границы ячеек. Если строка @var{fnt} содержит @samp{=}, то ширина всех ячеек одинакова. Если строка @var{fnt} содержит @samp{|}, то ширина таблицы ограничена шириной subplot (эквивалентно опции @samp{value 1}). Опция @code{value} задает ширину [...]
 @end deftypefn
@@ -2061,6 +2172,7 @@ gr.GetBGRN(bits, len(bits));
 @external{}
 @node 2D plotting, 3D plotting, 1D plotting, MathGL core
 @section 2D графики
+ at nav{}
 @cindex Mesh
 @cindex Fall
 @cindex Belt
@@ -2181,7 +2293,7 @@ gr.GetBGRN(bits, len(bits));
 @deftypefnx {Функция С} @code{void} mgl_cont (@code{HMGL} gr, @code{HCDT} z, @code{const char *}sch, @code{const char *}opt)
 @deftypefnx {Функция С} @code{void} mgl_cont_xy (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} y, @code{HCDT} z, @code{const char *}sch, @code{const char *}opt)
 @end ifclear
-Как предыдущий с вектором @var{v} из @var{num} элементов равно распределенных в диапазоне изменения цвета. Здесь @var{num} равен значению параметра @var{value} в опциях @var{opt} (по умолчанию 7).
+Как предыдущий с вектором @var{v} из @var{num} элементов равно распределенных в диапазоне изменения цвета. Здесь @var{num} равен значению параметра @code{value} в опциях @var{opt} (по умолчанию 7).
 @end deftypefn
 
 @anchor{contf}
@@ -2204,7 +2316,7 @@ gr.GetBGRN(bits, len(bits));
 @deftypefnx {Функция С} @code{void} mgl_contf (@code{HMGL} gr, @code{HCDT} z, @code{const char *}sch, @code{const char *}opt)
 @deftypefnx {Функция С} @code{void} mgl_contf_xy (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} y, @code{HCDT} z, @code{const char *}sch, @code{const char *}opt)
 @end ifclear
-Как предыдущий с вектором @var{v} из @var{num} элементов равно распределенных в диапазоне изменения цвета. Здесь @var{num} равен значению параметра @var{value} в опциях @var{opt} (по умолчанию 7).
+Как предыдущий с вектором @var{v} из @var{num} элементов равно распределенных в диапазоне изменения цвета. Здесь @var{num} равен значению параметра @code{value} в опциях @var{opt} (по умолчанию 7).
 @end deftypefn
 
 @anchor{contd}
@@ -2227,7 +2339,7 @@ gr.GetBGRN(bits, len(bits));
 @deftypefnx {Функция С} @code{void} mgl_contd (@code{HMGL} gr, @code{HCDT} z, @code{const char *}sch, @code{const char *}opt)
 @deftypefnx {Функция С} @code{void} mgl_contd_xy (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} y, @code{HCDT} z, @code{const char *}sch, @code{const char *}opt)
 @end ifclear
-Как предыдущий с вектором @var{v} из @var{num} элементов равно распределенных в диапазоне изменения цвета. Здесь @var{num} равен значению параметра @var{value} в опциях @var{opt} (по умолчанию 7).
+Как предыдущий с вектором @var{v} из @var{num} элементов равно распределенных в диапазоне изменения цвета. Здесь @var{num} равен значению параметра @code{value} в опциях @var{opt} (по умолчанию 7).
 @end deftypefn
 
 @anchor{contv}
@@ -2250,7 +2362,7 @@ gr.GetBGRN(bits, len(bits));
 @deftypefnx {Функция С} @code{void} mgl_contv (@code{HMGL} gr, @code{HCDT} z, @code{const char *}sch, @code{const char *}opt)
 @deftypefnx {Функция С} @code{void} mgl_contv_xy (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} y, @code{HCDT} z, @code{const char *}sch, @code{const char *}opt)
 @end ifclear
-Как предыдущий с вектором @var{v} из @var{num} элементов равно распределенных в диапазоне изменения цвета. Здесь @var{num} равен значению параметра @var{value} в опциях @var{opt} (по умолчанию 7).
+Как предыдущий с вектором @var{v} из @var{num} элементов равно распределенных в диапазоне изменения цвета. Здесь @var{num} равен значению параметра @code{value} в опциях @var{opt} (по умолчанию 7).
 @end deftypefn
 
 @anchor{axial}
@@ -2273,7 +2385,7 @@ gr.GetBGRN(bits, len(bits));
 @deftypefnx {Функция С} @code{void} mgl_axial (@code{HMGL} gr, @code{HCDT} z, @code{const char *}sch, @code{const char *}opt)
 @deftypefnx {Функция С} @code{void} mgl_axial_xy (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} y, @code{HCDT} z, @code{const char *}sch, @code{const char *}opt)
 @end ifclear
-Как предыдущий с вектором @var{v} из @var{num} элементов равно распределенных в диапазоне изменения цвета. Здесь @var{num} равен значению параметра @var{value} в опциях @var{opt} (по умолчанию 3).
+Как предыдущий с вектором @var{v} из @var{num} элементов равно распределенных в диапазоне изменения цвета. Здесь @var{num} равен значению параметра @code{value} в опциях @var{opt} (по умолчанию 3).
 @end deftypefn
 
 @anchor{grid2}
@@ -2293,6 +2405,7 @@ gr.GetBGRN(bits, len(bits));
 @external{}
 @node 3D plotting, Dual plotting, 2D plotting, MathGL core
 @section 3D графики
+ at nav{}
 @cindex Surf3
 @cindex Dens3
 @cindex Cont3
@@ -2324,7 +2437,7 @@ gr.GetBGRN(bits, len(bits));
 @deftypefnx {Функция С} @code{void} mgl_surf3 (@code{HMGL} gr, @code{HCDT} a, @code{const char *}sch, @code{const char *}opt)
 @deftypefnx {Функция С} @code{void} mgl_surf3_xyz (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} y, @code{HCDT} z, @code{HCDT} a, @code{const char *}sch, @code{const char *}opt)
 @end ifclear
-Аналогично предыдущему для @var{num} поверхностей уровня равномерно распределённых в диапазоне изменения цвета. Величина @var{num} равна значению параметра @var{value} в опциях @var{opt} (по умолчанию 3).
+Аналогично предыдущему для @var{num} поверхностей уровня равномерно распределённых в диапазоне изменения цвета. Величина @var{num} равна значению параметра @code{value} в опциях @var{opt} (по умолчанию 3).
 @end deftypefn
 
 @anchor{cloud}
@@ -2371,7 +2484,7 @@ gr.GetBGRN(bits, len(bits));
 @deftypefnx {Функция С} @code{void} mgl_cont3 (@code{HMGL} gr, @code{HCDT} a, @code{const char *}sch, @code{mreal} sVal, @code{const char *}opt)
 @deftypefnx {Функция С} @code{void} mgl_cont3_xyz (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} y, @code{HCDT} z, @code{HCDT} a, @code{const char *}sch, @code{mreal} sVal, @code{const char *}opt)
 @end ifclear
-Аналогично предыдущему для @var{num} линий уровня равномерно распределённых в диапазоне изменения цвета. Величина @var{num} равна значению параметра @var{value} в опциях @var{opt} (по умолчанию 7).
+Аналогично предыдущему для @var{num} линий уровня равномерно распределённых в диапазоне изменения цвета. Величина @var{num} равна значению параметра @code{value} в опциях @var{opt} (по умолчанию 7).
 @end deftypefn
 
 @anchor{contf3}
@@ -2394,7 +2507,7 @@ gr.GetBGRN(bits, len(bits));
 @deftypefnx {Функция С} @code{void} mgl_contf3 (@code{HMGL} gr, @code{HCDT} a, @code{const char *}sch, @code{mreal} sVal, @code{const char *}opt)
 @deftypefnx {Функция С} @code{void} mgl_contf3_xyz (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} y, @code{HCDT} z, @code{HCDT} a, @code{const char *}sch, @code{mreal} sVal, @code{const char *}opt)
 @end ifclear
-Аналогично предыдущему для @var{num} закрашенных линий (контуров) уровня равномерно распределённых в диапазоне изменения цвета. Величина @var{num} равна значению параметра @var{value} в опциях @var{opt} (по умолчанию 7).
+Аналогично предыдущему для @var{num} закрашенных линий (контуров) уровня равномерно распределённых в диапазоне изменения цвета. Величина @var{num} равна значению параметра @code{value} в опциях @var{opt} (по умолчанию 7).
 @end deftypefn
 
 @anchor{grid3}
@@ -2425,6 +2538,7 @@ gr.GetBGRN(bits, len(bits));
 @external{}
 @node Dual plotting, Vector fields, 3D plotting, MathGL core
 @section Парные графики
+ at nav{}
 @cindex SurfC
 @cindex SurfA
 @cindex Surf3C
@@ -2468,7 +2582,7 @@ gr.GetBGRN(bits, len(bits));
 @deftypefnx {Функция С} @code{void} mgl_surf3c (@code{HMGL} gr, @code{HCDT} a, @code{HCDT} c, @code{const char *}sch, @code{const char *}opt)
 @deftypefnx {Функция С} @code{void} mgl_surf3c_xyz (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} y, @code{HCDT} z, @code{HCDT} a, @code{HCDT} c, @code{const char *}sch, @code{const char *}opt)
 @end ifclear
-Аналогично предыдущему для @var{num} поверхностей уровня равномерно распределённых в диапазоне изменения цвета. Величина @var{num} равна значению параметра @var{value} в опциях @var{opt} (по умолчанию 3).
+Аналогично предыдущему для @var{num} поверхностей уровня равномерно распределённых в диапазоне изменения цвета. Величина @var{num} равна значению параметра @code{value} в опциях @var{opt} (по умолчанию 3).
 @end deftypefn
 
 
@@ -2504,7 +2618,7 @@ gr.GetBGRN(bits, len(bits));
 @deftypefnx {Функция С} @code{void} mgl_surf3a (@code{HMGL} gr, @code{HCDT} a, @code{HCDT} c, @code{const char *}sch, @code{const char *}opt)
 @deftypefnx {Функция С} @code{void} mgl_surf3a_xyz (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} y, @code{HCDT} z, @code{HCDT} a, @code{HCDT} c, @code{const char *}sch, @code{const char *}opt)
 @end ifclear
-Аналогично предыдущему для @var{num} поверхностей уровня равномерно распределённых в диапазоне изменения цвета. При этом массив @var{c} может быть вектором со значениями прозрачности и @var{num}=@var{c}.nx. В противном случае величина @var{num} равна значению параметра @var{value} в опциях @var{opt} (по умолчанию 3).
+Аналогично предыдущему для @var{num} поверхностей уровня равномерно распределённых в диапазоне изменения цвета. При этом массив @var{c} может быть вектором со значениями прозрачности и @var{num}=@var{c}.nx. В противном случае величина @var{num} равна значению параметра @code{value} в опциях @var{opt} (по умолчанию 3).
 @end deftypefn
 
 @anchor{tiles}
@@ -2548,6 +2662,7 @@ gr.GetBGRN(bits, len(bits));
 @external{}
 @node Vector fields, Other plotting, Dual plotting, MathGL core
 @section Векторные поля
+ at nav{}
 @cindex Traj
 @cindex Vect
 @cindex Dew
@@ -2566,7 +2681,7 @@ gr.GetBGRN(bits, len(bits));
 @deftypefnx {Функция С} @code{void} mgl_traj_xyz (@code{HMGL} gr, @code{HCDT}x, @code{HCDT}y, @code{HCDT}z, @code{HCDT}ax, @code{HCDT}ay, @code{HCDT}az, @code{const char *}sch, @code{const char *}opt)
 @deftypefnx {Функция С} @code{void} mgl_traj_xy (@code{HMGL} gr, @code{HCDT}x, @code{HCDT}y, @code{HCDT}ax, @code{HCDT}ay, @code{const char *}sch, @code{const char *}opt)
 @end ifclear
-Рисует вектора @{@var{ax}, @var{ay}, @var{az}@} вдоль кривой @{@var{x}, @var{y}, @var{z}@}. Длина векторов пропорциональна @math{\sqrt@{ax^2+ay^2+az^2@}}. Строка @var{pen} задает цвет (см. @ref{Line styles}). По умолчанию (@code{pen=""}) используется текущий цвет из палитры (см. @ref{Palette and colors}). Опция @var{value} задает фактор длины векторов (если не нуль) или выбирать длину пропорционально расстоянию между точками кривой (если @var{value}=0). Размер по 1-му индексу должен быть [...]
+Рисует вектора @{@var{ax}, @var{ay}, @var{az}@} вдоль кривой @{@var{x}, @var{y}, @var{z}@}. Длина векторов пропорциональна @math{\sqrt@{ax^2+ay^2+az^2@}}. Строка @var{pen} задает цвет (см. @ref{Line styles}). По умолчанию (@code{pen=""}) используется текущий цвет из палитры (см. @ref{Palette and colors}). Опция @code{value} задает фактор длины векторов (если не нуль) или выбирать длину пропорционально расстоянию между точками кривой (если @code{value=0}). Размер по 1-му индексу должен бы [...]
 @end deftypefn
 
 @anchor{vect}
@@ -2604,13 +2719,13 @@ gr.GetBGRN(bits, len(bits));
 @end deftypefn
 
 @anchor{vect3}
- at deftypefn {MGL command} {} vect3 udat vdat wdat ['sch'='' sval]
- at deftypefnx {MGL command} {} vect3 xdat ydat zdat udat vdat wdat ['sch'='' sval]
+ at deftypefn {Команда MGL} {} vect3 udat vdat wdat ['sch'='' sval]
+ at deftypefnx {Команда MGL} {} vect3 xdat ydat zdat udat vdat wdat ['sch'='' sval]
 @ifclear UDAV
- at deftypefnx {Method on @code{mglGraph}} @code{void} Vect3 (@code{const mglDataA &}ax, @code{const mglDataA &}ay, @code{const mglDataA &}az, @code{const char *}sch=@code{""}, @code{mreal} sVal=@code{-1}, @code{const char *}opt=@code{""})
- at deftypefnx {Method on @code{mglGraph}} @code{void} Vect3 (@code{const mglDataA &}x, @code{const mglDataA &}y, @code{const mglDataA &}z, @code{const mglDataA &}ax, @code{const mglDataA &}ay, @code{const mglDataA &}az, @code{const char *}sch=@code{""}, @code{mreal} sVal=@code{-1}, @code{const char *}opt=@code{""})
- at deftypefnx {C function} @code{void} mgl_vect3 (@code{HMGL} gr, @code{HCDT} ax, @code{HCDT} ay, @code{HCDT} az, @code{const char *}sch, @code{mreal} sVal, @code{const char *}opt)
- at deftypefnx {C function} @code{void} mgl_vect3_xyz (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} y, @code{HCDT} z, @code{HCDT} ax, @code{HCDT} ay, @code{HCDT} az, @code{const char *}sch, @code{mreal} sVal, @code{const char *}opt)
+ at deftypefnx {Метод класса @code{mglGraph}} @code{void} Vect3 (@code{const mglDataA &}ax, @code{const mglDataA &}ay, @code{const mglDataA &}az, @code{const char *}sch=@code{""}, @code{mreal} sVal=@code{-1}, @code{const char *}opt=@code{""})
+ at deftypefnx {Метод класса @code{mglGraph}} @code{void} Vect3 (@code{const mglDataA &}x, @code{const mglDataA &}y, @code{const mglDataA &}z, @code{const mglDataA &}ax, @code{const mglDataA &}ay, @code{const mglDataA &}az, @code{const char *}sch=@code{""}, @code{mreal} sVal=@code{-1}, @code{const char *}opt=@code{""})
+ at deftypefnx {Функция С} @code{void} mgl_vect3 (@code{HMGL} gr, @code{HCDT} ax, @code{HCDT} ay, @code{HCDT} az, @code{const char *}sch, @code{mreal} sVal, @code{const char *}opt)
+ at deftypefnx {Функция С} @code{void} mgl_vect3_xyz (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} y, @code{HCDT} z, @code{HCDT} ax, @code{HCDT} ay, @code{HCDT} az, @code{const char *}sch, @code{mreal} sVal, @code{const char *}opt)
 @end ifclear
 Рисует 3D векторное поле @{@var{ax}, @var{ay}, @var{az}@} параметрически зависящее от координат @var{x}, @var{y}, @var{z}. График рисуется на срезе @var{sVal} в направлении @{@samp{x}, @samp{y}, @samp{z}@}, указанном в строке @var{sch} (по умолчанию, в напралении @samp{y}). Длина и цвет векторов пропорциональна @math{\sqrt@{ax^2+ay^2+az^2@}}. Число рисуемых векторов зависит от @ref{meshnum}. Вид стрелок/штрихов может быть изменён символами:
 @itemize @bullet
@@ -2647,7 +2762,7 @@ gr.GetBGRN(bits, len(bits));
 @deftypefnx {Функция С} @code{void} mgl_flow_2d (@code{HMGL} gr, @code{HCDT} ax, @code{HCDT} ay, @code{const char *}sch, @code{const char *}opt)
 @deftypefnx {Функция С} @code{void} mgl_flow_xy (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} y, @code{HCDT} ax, @code{HCDT} ay, @code{const char *}sch, @code{const char *}opt)
 @end ifclear
-Рисует нити тока для векторного поля @{@var{ax}, @var{ay}@}, параметрически зависящего от координат @var{x}, @var{y} на плоскости при @var{z} = @var{Min}.z. Число нитей пропорционально значению опции @var{value} (по умолчанию 5). Цвет нитей пропорционален @math{\sqrt@{ax^2+ay^2@}}. Строка @var{sch} может содержать
+Рисует нити тока для векторного поля @{@var{ax}, @var{ay}@}, параметрически зависящего от координат @var{x}, @var{y} на плоскости при @var{z} = @var{Min}.z. Число нитей пропорционально значению опции @code{value} (по умолчанию 5). Цвет нитей пропорционален @math{\sqrt@{ax^2+ay^2@}}. Строка @var{sch} может содержать
 @itemize @bullet
 @item
 цветовую схему -- тёплые цвета соответствуют нормальному току (типа стока), холодные цвета соответствуют обратному току (типа источника);
@@ -2706,7 +2821,7 @@ gr.GetBGRN(bits, len(bits));
 @deftypefnx {Функция С} @code{void} mgl_grad_xy (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} y, @code{HCDT} phi, @code{const char *}sch, @code{const char *}opt)
 @deftypefnx {Функция С} @code{void} mgl_grad_xyz (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} y, @code{HCDT} z, @code{HCDT} phi, @code{const char *}sch, @code{const char *}opt)
 @end ifclear
-Рисует линии градиента скалярного поля @var{phi}[i,j] (или @var{phi}[i,j,k] в 3d случае) заданного параметрически @{@var{x}[i,j,k], @var{y}[i,j,k], @var{z}[i,j,k]@}. Число линий пропорционально значению опции @var{value} (по умолчанию 5). См. также @ref{dens}, @ref{cont}, @ref{flow}.
+Рисует линии градиента скалярного поля @var{phi}[i,j] (или @var{phi}[i,j,k] в 3d случае) заданного параметрически @{@var{x}[i,j,k], @var{y}[i,j,k], @var{z}[i,j,k]@}. Число линий пропорционально значению опции @code{value} (по умолчанию 5). См. также @ref{dens}, @ref{cont}, @ref{flow}.
 @end deftypefn
 
 @anchor{pipe}
@@ -2718,7 +2833,7 @@ gr.GetBGRN(bits, len(bits));
 @deftypefnx {Функция С} @code{void} mgl_pipe_2d (@code{HMGL} gr, @code{HCDT} ax, @code{HCDT} ay, @code{const char *}sch, @code{mreal} r0, @code{const char *}opt)
 @deftypefnx {Функция С} @code{void} mgl_pipe_xy (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} y, @code{HCDT} ax, @code{HCDT} ay, @code{const char *}sch, @code{mreal} r0, @code{const char *}opt)
 @end ifclear
-Рисует трубки тока для векторного поля @{@var{ax}, @var{ay}@}, параметрически зависящего от координат @var{x}, @var{y} на плоскости при @var{z} = @var{Min}.z. Число трубок пропорционально значению опции @var{value}. Цвет и радиус трубок пропорционален @math{\sqrt@{ax^2+ay^2@}}. Тёплые цвета соответствуют нормальному току (типа стока). Холодные цвета соответствуют обратному току (типа источника). Параметр @var{r0} задает радиус трубок. При @var{r0}<0 радиус трубок обратно пропорционален и [...]
+Рисует трубки тока для векторного поля @{@var{ax}, @var{ay}@}, параметрически зависящего от координат @var{x}, @var{y} на плоскости при @var{z} = @var{Min}.z. Число трубок пропорционально значению опции @code{value}. Цвет и радиус трубок пропорционален @math{\sqrt@{ax^2+ay^2@}}. Тёплые цвета соответствуют нормальному току (типа стока). Холодные цвета соответствуют обратному току (типа источника). Параметр @var{r0} задает радиус трубок. При @var{r0}<0 радиус трубок обратно пропорционален  [...]
 @end deftypefn
 
 @deftypefn {Команда MGL} {} pipe udat vdat wdat ['sch'='' @code{r0=0.05}]
@@ -2737,6 +2852,7 @@ gr.GetBGRN(bits, len(bits));
 @external{}
 @node Other plotting, Nonlinear fitting, Vector fields, MathGL core
 @section Прочие графики
+ at nav{}
 @cindex DensXYZ
 @cindex ContXYZ
 @cindex ContFXYZ
@@ -2777,7 +2893,7 @@ gr.GetBGRN(bits, len(bits));
 @deftypefnx {Функция С} @code{void} mgl_cont_y (@code{HMGL} gr, @code{HCDT} a, @code{const char *}stl, @code{mreal} sVal, @code{const char *}opt)
 @deftypefnx {Функция С} @code{void} mgl_cont_z (@code{HMGL} gr, @code{HCDT} a, @code{const char *}stl, @code{mreal} sVal, @code{const char *}opt)
 @end ifclear
-Эти функции рисуют линии уровня на x, y или z плоскостях. Если @var{a} -- 3d массив, то выполняется интерполяция к заданному срезу @var{sVal}. Функции полезны для создания проекций 3D массивов на оси координат. См. также @ref{ContFXYZ}, @ref{DensXYZ}, @ref{cont}, @ref{Data manipulation}. @sref{Cont projection sample}
+Эти функции рисуют линии уровня на x, y или z плоскостях. Если @var{a} -- 3d массив, то выполняется интерполяция к заданному срезу @var{sVal}. Опция @code{value} задает число контуров. Функции полезны для создания проекций 3D массивов на оси координат. См. также @ref{ContFXYZ}, @ref{DensXYZ}, @ref{cont}, @ref{Data manipulation}. @sref{Cont projection sample}
 @end deftypefn
 
 @ifclear UDAV
@@ -2803,7 +2919,7 @@ gr.GetBGRN(bits, len(bits));
 @deftypefnx {Функция С} @code{void} mgl_contf_y (@code{HMGL} gr, @code{HCDT} a, @code{const char *}stl, @code{mreal} sVal, @code{const char *}opt)
 @deftypefnx {Функция С} @code{void} mgl_contf_z (@code{HMGL} gr, @code{HCDT} a, @code{const char *}stl, @code{mreal} sVal, @code{const char *}opt)
 @end ifclear
-Эти функции рисуют закрашенные контуры уровня на x, y или z плоскостях. Если @var{a} -- 3d массив, то выполняется интерполяция к заданному срезу @var{sVal}. Функции полезны для создания проекций 3D массивов на оси координат. См. также @ref{ContFXYZ}, @ref{DensXYZ}, @ref{cont}, @ref{Data manipulation}. @sref{ContF projection sample}
+Эти функции рисуют закрашенные контуры уровня на x, y или z плоскостях. Если @var{a} -- 3d массив, то выполняется интерполяция к заданному срезу @var{sVal}. Опция @code{value} задает число контуров. Функции полезны для создания проекций 3D массивов на оси координат. См. также @ref{ContFXYZ}, @ref{DensXYZ}, @ref{cont}, @ref{Data manipulation}. @sref{ContF projection sample}
 @end deftypefn
 
 @ifclear UDAV
@@ -2823,7 +2939,7 @@ gr.GetBGRN(bits, len(bits));
 @deftypefnx {Метод класса @code{mglGraph}} @code{void} FPlot (@code{const char *}eqY, @code{const char *}pen=@code{""}, @code{const char *}opt=@code{""})
 @deftypefnx {Функция С} @code{void} mgl_fplot (@code{HMGL} gr, @code{const char *}eqY, @code{const char *}pen, @code{const char *}opt)
 @end ifclear
-Рисует функцию @samp{eqY(x)} в плоскости @var{z}=@var{Min}.z с координатой @samp{x} в диапазоне [@var{Min}.x, @var{Max}.x]. См. также @ref{plot}.
+Рисует функцию @samp{eqY(x)} в плоскости @var{z}=@var{Min}.z с координатой @samp{x} в диапазоне [@var{Min}.x, @var{Max}.x]. Опция @code{value} задает начальное число точек. См. также @ref{plot}.
 @end deftypefn
 
 @deftypefn {Команда MGL} {} fplot 'x(t)' 'y(t)' 'z(t)' ['pen'='']
@@ -2831,7 +2947,7 @@ gr.GetBGRN(bits, len(bits));
 @deftypefnx {Метод класса @code{mglGraph}} @code{void} FPlot (@code{const char *}eqX, @code{const char *}eqY, @code{const char *}eqZ, @code{const char *}pen, @code{const char *}opt=@code{""})
 @deftypefnx {Функция С} @code{void} mgl_fplot_xyz (@code{HMGL} gr, @code{const char *}eqX, @code{const char *}eqY, @code{const char *}eqZ, @code{const char *}pen, @code{const char *}opt)
 @end ifclear
-Рисует параметрическую кривую @{@samp{eqX(t)}, @samp{eqY(t)}, @samp{eqZ(t)}@}, где координата @samp{t} меняется в диапазоне [0, 1]. См. также @ref{plot}.
+Рисует параметрическую кривую @{@samp{eqX(t)}, @samp{eqY(t)}, @samp{eqZ(t)}@}, где координата @samp{t} меняется в диапазоне [0, 1]. Опция @code{value} задает начальное число точек. См. также @ref{plot}.
 @end deftypefn
 
 @anchor{fsurf}
@@ -2840,7 +2956,7 @@ gr.GetBGRN(bits, len(bits));
 @deftypefnx {Метод класса @code{mglGraph}} @code{void} FSurf (@code{const char *}eqZ, @code{const char *}sch=@code{""}, @code{const char *}opt=@code{""});
 @deftypefnx {Функция С} @code{void} mgl_fsurf (@code{HMGL} gr, @code{const char *}eqZ, @code{const char *}sch, @code{const char *}opt);
 @end ifclear
-Рисует поверхность @samp{eqY(x,y)} с координатами @samp{x}, @samp{y} в диапазоне @code{xrange, yrange}. См. также @ref{surf}.
+Рисует поверхность @samp{eqY(x,y)} с координатами @samp{x}, @samp{y} в диапазоне @code{xrange, yrange}. Опция @code{value} задает число точек. См. также @ref{surf}.
 @end deftypefn
 
 @deftypefn {Команда MGL} {} fsurf 'x(u,v)' 'y(u,v)' 'z(u,v)' ['sch'='']
@@ -2848,7 +2964,7 @@ gr.GetBGRN(bits, len(bits));
 @deftypefnx {Метод класса @code{mglGraph}} @code{void} FSurf (@code{const char *}eqX, @code{const char *}eqY, @code{const char *}eqZ, @code{const char *}sch=@code{""}, @code{const char *}opt=@code{""})
 @deftypefnx {Функция С} @code{void} mgl_fsurf_xyz (@code{HMGL} gr, @code{const char *}eqX, @code{const char *}eqY, @code{const char *}eqZ, @code{const char *}sch, @code{const char *}opt)
 @end ifclear
-Рисует параметрическую поверхность @{@samp{eqX(u,v)}, @samp{eqY(u,v)}, @samp{eqZ(u,v)}@}, где координаты @samp{u}, @samp{v} меняются в диапазоне [0, 1]. См. также @ref{surf}.
+Рисует параметрическую поверхность @{@samp{eqX(u,v)}, @samp{eqY(u,v)}, @samp{eqZ(u,v)}@}, где координаты @samp{u}, @samp{v} меняются в диапазоне [0, 1]. Опция @code{value} задает число точек. См. также @ref{surf}.
 @end deftypefn
 
 @anchor{triplot}
@@ -2880,7 +2996,7 @@ gr.GetBGRN(bits, len(bits));
 @deftypefnx {Функция С} @code{void} mgl_tricont_xyzcv (@code{HMGL} gr, @code{HCDT} v, @code{HCDT} id, @code{HCDT} x, @code{HCDT} y, @code{HCDT} z, @code{HCDT} c, @code{const char *}sch, @code{const char *}opt)
 @deftypefnx {Функция С} @code{void} mgl_tricont_xyzv (@code{HMGL} gr, @code{HCDT} v, @code{HCDT} id, @code{HCDT} x, @code{HCDT} y, @code{HCDT} z, @code{const char *}sch, @code{const char *}opt)
 @end ifclear
-Рисует линии уровня поверхности из треугольников при @var{z}=@var{v}[k] (или при @var{z} = @var{Min}.z если @var{sch} содержит @samp{_}). Вершины треугольников задаются индексами @var{id} в массиве точек @{@var{x}[i], @var{y}[i], @var{z}[i]@}. Строка @var{sch} задает цветовую схему. Размер по 1-му индексу массива @var{id} должен быть 3 или больше. Массивы @var{x}, @var{y}, @var{z} должны иметь одинаковые размеры. Массив @var{c} задает цвет треугольников (если @var{id}.ny=@var{c}.nx) или  [...]
+Рисует линии уровня поверхности из треугольников при @var{z}=@var{v}[k] (или при @var{z} = @var{Min}.z если @var{sch} содержит @samp{_}). Вершины треугольников задаются индексами @var{id} в массиве точек @{@var{x}[i], @var{y}[i], @var{z}[i]@}. Если аргуент @var{v} не задан, то используется массив из @var{num} элементов равно распределенных в диапазоне изменения цвета. Здесь @var{num} равен значению параметра @code{value} в опциях @var{opt} (по умолчанию 7). Строка @var{sch} задает цветов [...]
 @end deftypefn
 
 @anchor{quadplot}
@@ -2904,10 +3020,12 @@ gr.GetBGRN(bits, len(bits));
 @ifclear UDAV
 @deftypefnx {Метод класса @code{mglGraph}} @code{void} Dots (@code{const mglDataA &}x, @code{const mglDataA &}y, @code{const mglDataA &}z, @code{const char *}sch=@code{""}, @code{const char *}opt=@code{""})
 @deftypefnx {Метод класса @code{mglGraph}} @code{void} Dots (@code{const mglDataA &}x, @code{const mglDataA &}y, @code{const mglDataA &}z, @code{const mglDataA &}a, @code{const char *}sch=@code{""}, @code{const char *}opt=@code{""})
+ at deftypefnx {Метод класса @code{mglGraph}} @code{void} Dots (@code{const mglDataA &}x, @code{const mglDataA &}y, @code{const mglDataA &}z, @code{const mglDataA &}c, @code{const mglDataA &}a, @code{const char *}sch=@code{""}, @code{const char *}opt=@code{""})
 @deftypefnx {Функция С} @code{void} mgl_dots (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} y, @code{HCDT} z, @code{const char *}sch, @code{const char *}opt)
 @deftypefnx {Функция С} @code{void} mgl_dots_a (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} y, @code{HCDT} z, @code{HCDT} a, @code{const char *}sch, @code{const char *}opt)
+ at deftypefnx {Функция С} @code{void} mgl_dots_ca (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} y, @code{HCDT} z, @code{HCDT} c, @code{HCDT} a, @code{const char *}sch, @code{const char *}opt)
 @end ifclear
-Рисует произвольно расположенные точки @{@var{x}[i], @var{y}[i], @var{z}[i]@}. Строка @var{sch} задает цветовую схему. Если определён массив @var{a}, то он задает прозрачность точек. Массивы @var{x}, @var{y}, @var{z}, @var{a} должны иметь одинаковые размеры. См. также @ref{crust}, @ref{mark}, @ref{plot}. @sref{Dots sample}
+Рисует произвольно расположенные точки @{@var{x}[i], @var{y}[i], @var{z}[i]@}. Строка @var{sch} задает цветовую схему и тип маркеров. Если определёны массивы @var{c}, @var{a} то они задают цвет и прозрачность точек соответственно. Непрозрачные точки с заданным цветом можно нарисовать с помощью @ref{tens}, используя стиль @samp{ .}. Массивы @var{x}, @var{y}, @var{z}, @var{a} должны иметь одинаковые размеры. См. также @ref{crust}, @ref{tens}, @ref{mark}, @ref{plot}. @sref{Dots sample}
 @end deftypefn
 
 @anchor{crust}
@@ -2923,6 +3041,7 @@ gr.GetBGRN(bits, len(bits));
 @external{}
 @node Nonlinear fitting, Data manipulation, Other plotting, MathGL core
 @section Nonlinear fitting
+ at nav{}
 @cindex Fit
 @cindex FitS
 @cindex PutsFit
@@ -2932,7 +3051,7 @@ gr.GetBGRN(bits, len(bits));
 
 Эти функции подбирают параметры функции для наилучшей аппроксимации данных, т.е. минимизируют сумму @math{\sum_i (f(x_i, y_i, z_i) - a_i)^2/s_i^2}. При этом аппроксимирующая функция @samp{f} может зависеть от одного аргумента @samp{x} (1D случай), от двух аргументов @samp{x,y} (2D случай) или от трех аргументов @samp{x,y,z} (3D случай). Функция @samp{f} также может зависеть от параметров. Список параметров задается строкой @var{var} (например, @samp{abcd}). Обычно пользователь должен пре [...]
 
-Функции Fit() и FitS() не рисуют полученные массивы. Они заполняют массив @var{fit} по формуле @samp{f} с найденными коэффициентами и возвращают @math{\chi^2} ошибку аппроксимации. При этом, координаты @samp{x,y,z} равно распределены в интервале @var{Min}-- at var{Max}. Число точек в @var{fit} выбирается максимальным из размера массива @var{fit} и значения переменной @var{mglFitPnts}. Функции используют библиотеку GSL. @sref{Nonlinear fitting sample}
+Функции Fit() и FitS() не рисуют полученные массивы. Они заполняют массив @var{fit} по формуле @samp{f} с найденными коэффициентами и возвращают @math{\chi^2} ошибку аппроксимации. При этом, координаты @samp{x,y,z} равно распределены в интервале @var{Min}-- at var{Max}. Число точек в @var{fit} определяется опцией @code{value} (по умолчанию @var{mglFitPnts}=100). Функции используют библиотеку GSL. @sref{Nonlinear fitting hints}
 
 @anchor{fits}
 @deftypefn {Команда MGL} {} fits res adat sdat 'func' 'var' [ini=0]
@@ -3011,6 +3130,7 @@ gr.GetBGRN(bits, len(bits));
 @external{}
 @node Data manipulation, , Nonlinear fitting, MathGL core
 @section Распределение данных
+ at nav{}
 @cindex Hist
 @cindex Fill
 @cindex DataGrid
@@ -3026,7 +3146,7 @@ gr.GetBGRN(bits, len(bits));
 @deftypefnx {Функция С} @code{HMDT} mgl_hist_xy (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} y, @code{HCDT} a, @code{const char *}opt)
 @deftypefnx {Функция С} @code{HMDT} mgl_hist_xyz (@code{HMGL} gr, @code{HCDT} x, @code{HCDT} y, @code{HCDT} z, @code{HCDT} a, @code{const char *}opt)
 @end ifclear
-Создают распределения данных. Они не рисуют данные. Функции могут быть полезны в случае когда данные пользователя определены на случайно расположенных точка (например, после PIC расчетов) и он хочет построить график, требующий регулярных данных (данных на сетках). Диапазон сеток равен диапазону осей координат. Массивы @var{x}, @var{y}, @var{z} определяют положение (координаты) точек. Массив @var{a} задает значения данных. Число точек в результате @var{res} -- максимум из размера @var{res [...]
+Создают распределения данных. Они не рисуют данные. Функции могут быть полезны в случае когда данные пользователя определены на случайно расположенных точка (например, после PIC расчетов) и он хочет построить график, требующий регулярных данных (данных на сетках). Диапазон сеток равен диапазону осей координат. Массивы @var{x}, @var{y}, @var{z} определяют положение (координаты) точек. Массив @var{a} задает значения данных. Число точек в результате @var{res} определяется опцией @code{value [...]
 @end deftypefn
 
 
@@ -3042,12 +3162,24 @@ gr.GetBGRN(bits, len(bits));
 Заполняют значения массива @samp{u} в соответствии с формулой в строке @var{eq}. Формула -- произвольное выражение, зависящее от переменных @samp{x}, @samp{y}, @samp{z}, @samp{u}, @samp{v}, @samp{w}. Координаты @samp{x}, @samp{y}, @samp{z} полагаются в диапазоне изменения осей координат. Переменная @samp{u} -- значение исходного массива. Переменные @samp{v} и @samp{w} -- значения массивов @var{v}, @var{w}, которые могут быть @code{NULL} (т.е. могут быть опущены).
 @end deftypefn
 
- at deftypefn {MGL command} {} datagrid dat xdat ydat zdat
+ at deftypefn {Команда MGL} {} datagrid dat xdat ydat zdat
 @ifclear UDAV
 @deftypefnx {Метод класса @code{mglGraph}} @code{void} DataGrid (@code{mglData &}u, @code{const mglDataA &}x, @code{const mglDataA &}y, @code{const mglDataA &}z, @code{const char *}opt=@code{""})
 @deftypefnx {Функция С} @code{void} mgl_data_grid (@code{HMGL} gr, @code{HMDT} u, @code{HCDT} x, @code{HCDT} y, @code{HCDT} z, @code{const char *}opt)
 @end ifclear
-Заполняет значения массива @samp{u} результатом линейной интерполяции по триангулированной поверхности, найденной по произвольно расположенным точкам @samp{x}, @samp{y}, @samp{z}. NAN значение используется для точек сетки вне триангулированной поверхности.
+Заполняет значения массива @samp{u} результатом линейной интерполяции по триангулированной поверхности, найденной по произвольно расположенным точкам @samp{x}, @samp{y}, @samp{z}. NAN значение используется для точек сетки вне триангулированной поверхности. @sref{Making regular data}
+ at end deftypefn
+
+ at deftypefn {Команда MGL} {} refill dat xdat vdat [sl=-1]
+ at deftypefnx {Команда MGL} {} refill dat xdat ydat vdat [sl=-1]
+ at deftypefnx {Команда MGL} {} refill dat xdat ydat zdat vdat
+ at ifclear UDAV
+ at deftypefnx {Метод класса @code{mglData}} @code{void} Refill (@code{mglDataA &}dat, @code{const mglDataA &}x, @code{const mglDataA &}v, @code{long} sl=@code{-1}, @code{const char *}opt=@code{""})
+ at deftypefnx {Метод класса @code{mglData}} @code{void} Refill (@code{mglDataA &}dat, @code{const mglDataA &}x, @code{const mglDataA &}y, @code{const mglDataA &}v, @code{long} sl=@code{-1}, @code{const char *}opt=@code{""})
+ at deftypefnx {Метод класса @code{mglData}} @code{void} Refill (@code{mglDataA &}dat, @code{const mglDataA &}x, @code{const mglDataA &}y, @code{const mglDataA &}z, @code{const mglDataA &}v, @code{const char *}opt=@code{""})
+ at deftypefnx {Функция С} @code{void} mgl_data_refill_gr (@code{HMGL} gr, @code{HMDT} a, @code{HCDT} x, @code{HCDT} y, @code{HCDT} z, @code{HCDT} v, @code{long} sl, @code{const char *}opt)
+ at end ifclear
+Заполняет значениями интерполяции массива @var{v} в точках @{@var{x}, @var{y}, @var{z}@}=@{@code{X[i], Y[j], Z[k]}@} (или @{@var{x}, @var{y}, @var{z}@}=@{@code{X[i,j,k], Y[i,j,k], Z[i,j,k]}@} если @var{x}, @var{y}, @var{z} не 1d массивы), где @code{X,Y,Z} равномерно распределены в диапазоне осей координат и имеют такой же размер как и массив @var{dat}. Если параметр @var{sl} равен 0 или положительный, то изменятся будет только @var{sl}-ый срез.
 @end deftypefn
 
 
@@ -3064,6 +3196,7 @@ gr.GetBGRN(bits, len(bits));
 @c @external{}
 @c @node IDTF functions, , Data distributions, MathGL core
 @c @section IDTF функции
+ at c @nav{}
 
 @c Эти функции обеспечивают поддержку особых возможностей при создании IDTF. Во всех прочих случаях они не делают ничего.
 
@@ -3081,4 +3214,3 @@ gr.GetBGRN(bits, len(bits));
 @c @end ifclear
 
 @external{}
-
diff --git a/texinfo/data_en.texi b/texinfo/data_en.texi
index 00ac5a3..6bf5f68 100644
--- a/texinfo/data_en.texi
+++ b/texinfo/data_en.texi
@@ -1,5 +1,6 @@
 @c ------------------------------------------------------------------
 @chapter Data processing
+ at nav{}
 
 @ifset UDAV
 This chapter describe commands for allocation, resizing, loading and saving, modifying of data arrays. Also it can numerically differentiate and integrate data, interpolate, fill data by formula and so on. Class supports data with dimensions up to 3 (like function of 3 variables -- x,y,z). Data arrays are denoted by Small Caps (like @sc{dat}) if it can be (re-)created by MGL commands.
@@ -29,6 +30,7 @@ This chapter describe classes @code{mglData} and @code{mglDataC} for working wit
 @external{}
 @node Public variables, Data constructor, , Data processing
 @section Public variables
+ at nav{}
 
 @ifset UDAV
 MGL don't support direct access to data arrays. See section @ref{Data filling}
@@ -97,6 +99,7 @@ Returns pointer to internal data array.
 @external{}
 @node Data constructor, Data resizing, Public variables, Data processing
 @section Data constructor
+ at nav{}
 @cindex mglData
 
 @ifset UDAV
@@ -167,6 +170,7 @@ Deletes the instance of class mglData.
 @external{}
 @node Data resizing, Data filling, Data constructor, Data processing
 @section Data resizing
+ at nav{}
 @cindex Create
 @cindex Rearrange
 @cindex Extend
@@ -312,11 +316,13 @@ Join data cells from @var{vdat} to @var{dat}. At this, function increase @var{da
 @external{}
 @node Data filling, File I/O, Data resizing, Data processing
 @section Data filling
+ at nav{}
 @cindex Fill
 @cindex Modify
 @cindex Set
 @cindex List
 @cindex Var
+ at cindex Refill
 
 @anchor{list}
 @deftypefn {MGL command} {} list @sc{dat} @code{v1 ...}
@@ -466,7 +472,7 @@ The same as previous ones but coordinates @samp{x}, @samp{y}, @samp{z} are suppo
 @deftypefn {MGL command} {} fillsample dat 'how'
 @ifclear UDAV
 @deftypefnx {Method on @code{mglData}} @code{void} FillSample (@code{const char *}how)
- at deftypefnx mglData @code{void} mgl_data_fill_sample (@code{HMDT} a, @code{const char *}how)
+ at deftypefnx {C function} @code{void} mgl_data_fill_sample (@code{HMDT} a, @code{const char *}how)
 @end ifclear
 Fills data by 'x' or 'k' samples for Hankel ('h') or Fourier ('f') transform.
 @end deftypefn
@@ -476,9 +482,11 @@ Fills data by 'x' or 'k' samples for Hankel ('h') or Fourier ('f') transform.
 @deftypefn {MGL command} {} datagrid dat xdat ydat zdat
 @ifclear UDAV
 @deftypefnx {Method on @code{mglData}} @code{mglData} Grid (@code{HMGL} gr, @code{const mglDataA &}x, @code{const mglDataA &}y, @code{const mglDataA &}z, @code{const char *}opt=@code{""})
+ at deftypefnx {Method on @code{mglData}} @code{mglData} Grid (@code{const mglDataA &}x, @code{const mglDataA &}y, @code{const mglDataA &}z, @code{mglPoint} p1, @code{mglPoint} p2)
 @deftypefnx {C function} @code{void} mgl_data_grid (@code{HMGL} gr, @code{HMDT} u, @code{HCDT} x, @code{HCDT} y, @code{HCDT} z, @code{const char *}opt)
+ at deftypefnx {C function} @code{void} mgl_data_grid_xy (@code{HMDT} u, @code{HCDT} x, @code{HCDT} y, @code{HCDT} z, @code{mreal} x1, @code{mreal} x2, @code{mreal} y1, @code{mreal} y2)
 @end ifclear
-Fills the value of array according to the linear interpolation of triangulated surface, found for arbitrary placed points @samp{x}, @samp{y}, @samp{z}. NAN value is used for grid points placed outside of triangulated surface.
+Fills the value of array according to the linear interpolation of triangulated surface assuming x-,y-coordinates equidistantly distributed in axis range (or in range [x1,x2]*[y1,y2]). Triangulated surface is found for arbitrary placed points @samp{x}, @samp{y}, @samp{z}. NAN value is used for grid points placed outside of triangulated surface. @sref{Making regular data}
 @end deftypefn
 
 
@@ -486,7 +494,9 @@ Fills the value of array according to the linear interpolation of triangulated s
 @deftypefn {MGL command} {} put dat @code{val [i=: j=: k=:]}
 @ifclear UDAV
 @deftypefnx {Method on @code{mglData}} @code{void} Put (@code{mreal} val, @code{int} i=@code{-1}, @code{int} j=@code{-1}, @code{int} k=@code{-1})
- at deftypefnx mglData @code{void} mgl_data_put_val (@code{HMDT} a, @code{mreal} val, @code{int} i, @code{int} j, @code{int} k)
+ at deftypefnx {Method on @code{mglDataC}} @code{void} Put (@code{dual} val, @code{int} i=@code{-1}, @code{int} j=@code{-1}, @code{int} k=@code{-1})
+ at deftypefnx {C function} @code{void} mgl_data_put_val (@code{HMDT} a, @code{mreal} val, @code{int} i, @code{int} j, @code{int} k)
+ at deftypefnx {C function} @code{void} mgl_datac_put_val (@code{HADT} a, @code{dual} val, @code{int} i, @code{int} j, @code{int} k)
 @end ifclear
 Sets value(s) of array a[@var{i}, @var{j}, @var{k}] = @var{val}. Negative indexes @var{i}, @var{j}, @var{k}=-1 set the value @var{val} to whole range in corresponding direction(s). For example, @code{Put(val,-1,0,-1);} sets a[i,0,j]=@var{val} for i=0...(nx-1), j=0...(nz-1).
 @end deftypefn
@@ -494,18 +504,40 @@ Sets value(s) of array a[@var{i}, @var{j}, @var{k}] = @var{val}. Negative indexe
 @deftypefn {MGL command} {} put dat vdat [@code{i=: j=: k=:}]
 @ifclear UDAV
 @deftypefnx {Method on @code{mglData}} @code{void} Put (@code{const mglDataA &}v, @code{int} i=@code{-1}, @code{int} j=@code{-1}, @code{int} k=@code{-1})
- at deftypefnx mglData @code{void} mgl_data_put_dat (@code{HMDT} a, @code{HCDT} v, @code{int} i, @code{int} j, @code{int} k)
+ at deftypefnx {Method on @code{mglDataC}} @code{void} Put (@code{const mglDataA &}v, @code{int} i=@code{-1}, @code{int} j=@code{-1}, @code{int} k=@code{-1})
+ at deftypefnx {C function} @code{void} mgl_data_put_dat (@code{HMDT} a, @code{HCDT} v, @code{int} i, @code{int} j, @code{int} k)
+ at deftypefnx {C function} @code{void} mgl_datac_put_dat (@code{HADT} a, @code{HCDT} v, @code{int} i, @code{int} j, @code{int} k)
 @end ifclear
 Copies value(s) from array @var{v} to the range of original array. Negative indexes @var{i}, @var{j}, @var{k}=-1 set the range in corresponding direction(s). At this minor dimensions of array @var{v} should be large than corresponding dimensions of this array. For example, @code{Put(v,-1,0,-1);} sets a[i,0,j]=v.ny>nz ? v[i,j] : v[i], where i=0...(nx-1), j=0...(nz-1) and condition v.nx>=nx is true.
 @end deftypefn
 
+ at anchor{refill}
+ at deftypefn {MGL command} {} refill dat xdat vdat [sl=-1]
+ at deftypefnx {MGL command} {} refill dat xdat ydat vdat [sl=-1]
+ at deftypefnx {MGL command} {} refill dat xdat ydat zdat vdat
+ at ifclear UDAV
+ at deftypefnx {Method on @code{mglData}} @code{void} Refill (@code{const mglDataA &}x, @code{const mglDataA &}v, @code{mreal} x1, @code{mreal} x2, @code{long} sl=@code{-1})
+ at deftypefnx {Method on @code{mglData}} @code{void} Refill (@code{const mglDataA &}x, @code{const mglDataA &}v, @code{mglPoint} p1, @code{mglPoint} p2, @code{long} sl=@code{-1})
+ at deftypefnx {Method on @code{mglData}} @code{void} Refill (@code{const mglDataA &}x, @code{const mglDataA &}y, @code{const mglDataA &}v, @code{mglPoint} p1, @code{mglPoint} p2, @code{long} sl=@code{-1})
+ at deftypefnx {Method on @code{mglData}} @code{void} Refill (@code{const mglDataA &}x, @code{const mglDataA &}y, @code{const mglDataA &}z, @code{const mglDataA &}v, @code{mglPoint} p1, @code{mglPoint} p2)
+ at deftypefnx {Method on @code{mglData}} @code{void} Refill (@code{HMGL} gr, @code{const mglDataA &}x, @code{const mglDataA &}v, @code{long} sl=@code{-1}, @code{const char *}opt=@code{""})
+ at deftypefnx {Method on @code{mglData}} @code{void} Refill (@code{HMGL} gr, @code{const mglDataA &}x, @code{const mglDataA &}y, @code{const mglDataA &}v, @code{long} sl=@code{-1}, @code{const char *}opt=@code{""})
+ at deftypefnx {Method on @code{mglData}} @code{void} Refill (@code{HMGL} gr, @code{const mglDataA &}x, @code{const mglDataA &}y, @code{const mglDataA &}z, @code{const mglDataA &}v, @code{const char *}opt=@code{""})
+ at deftypefnx {C function} @code{void} mgl_data_refill_x (@code{HMDT} a, @code{HCDT} x, @code{HCDT} v, @code{mreal} x1, @code{mreal} x2, @code{long} sl)
+ at deftypefnx {C function} @code{void} mgl_data_refill_xy (@code{HMDT} a, @code{HCDT} x, @code{HCDT} y, @code{HCDT} v, @code{mreal} x1, @code{mreal} x2, @code{mreal} y1, @code{mreal} y2, @code{long} sl)
+ at deftypefnx {C function} @code{void} mgl_data_refill_xyz (@code{HMDT} a, @code{HCDT} x, @code{HCDT} y, @code{HCDT} z, @code{HCDT} v, @code{mreal} x1, @code{mreal} x2, @code{mreal} y1, @code{mreal} y2, @code{mreal} z1, @code{mreal} z2)
+ at deftypefnx {C function} @code{void} mgl_data_refill_gr (@code{HMGL} gr, @code{HMDT} a, @code{HCDT} x, @code{HCDT} y, @code{HCDT} z, @code{HCDT} v, @code{long} sl, @code{const char *}opt)
+ at end ifclear
+Fills by interpolated values of array @var{v} at the point @{@var{x}, @var{y}, @var{z}@}=@{@code{X[i], Y[j], Z[k]}@} (or @{@var{x}, @var{y}, @var{z}@}=@{@code{X[i,j,k], Y[i,j,k], Z[i,j,k]}@} if @var{x}, @var{y}, @var{z} are not 1d arrays), where @code{X,Y,Z} are equidistantly distributed in range [@var{x1}, at var{x2}]*[@var{y1}, at var{y2}]*[@var{z1}, at var{z2}] and have the same sizes as this array. If parameter @var{sl} is 0 or positive then changes will be applied only for slice @var{sl}.
+ at end deftypefn
+
 @anchor{idset}
 @deftypefn {MGL command} {} idset dat 'ids'
 @ifclear UDAV
 @deftypefnx {Method on @code{mglData}} @code{void} SetColumnId (@code{const char *}ids)
- at deftypefnx mglData @code{void} mgl_data_set_id (@code{HMDT} a, @code{const char *}ids)
 @deftypefnx {Method on @code{mglDataC}} @code{void} SetColumnId (@code{const char *}ids)
- at deftypefnx mglData @code{void} mgl_datac_set_id (@code{HADT} a, @code{const char *}ids)
+ at deftypefnx {C function} @code{void} mgl_data_set_id (@code{HMDT} a, @code{const char *}ids)
+ at deftypefnx {C function} @code{void} mgl_datac_set_id (@code{HADT} a, @code{const char *}ids)
 @end ifclear
 Sets the symbol @var{ids} for data columns. The string should contain one symbol 'a'...'z' per column. These ids are used in @ref{column}.
 @end deftypefn
@@ -515,6 +547,7 @@ Sets the symbol @var{ids} for data columns. The string should contain one symbol
 @external{}
 @node File I/O, Make another data, Data filling, Data processing
 @section File I/O
+ at nav{}
 @cindex Read
 @cindex ReadMat
 @cindex ReadRange
@@ -643,6 +676,7 @@ Saves data matrix (or @code{ns}-th slice for 3d data) to bitmap file (now suppor
 @external{}
 @node Make another data, Data changing, File I/O, Data processing
 @section Make another data
+ at nav{}
 @cindex SubData
 @cindex Column
 @cindex Trace
@@ -655,6 +689,9 @@ Saves data matrix (or @code{ns}-th slice for 3d data) to bitmap file (now suppor
 @cindex Min
 @cindex Max
 @cindex Roots
+ at cindex Correl
+ at cindex AutoCorrel
+
 
 @anchor{subdata}
 @deftypefn {MGL command} {} subdata @sc{res} dat @code{xx [yy=: zz=:]}
@@ -663,7 +700,7 @@ Saves data matrix (or @code{ns}-th slice for 3d data) to bitmap file (now suppor
 @deftypefnx {Method on @code{mglDataC}} @code{mglData} SubData (@code{mreal} xx, @code{mreal} yy=@code{-1}, @code{mreal} zz=@code{-1}) @code{const}
 @deftypefnx {C function} @code{HMDT} mgl_data_subdata (@code{HCDT} dat, @code{mreal} xx, @code{mreal} yy, @code{mreal} zz)
 @end ifclear
-Extracts sub-array data from the original data array keeping fixed positive index. For example @code{SubData(-1,2)} extracts 3d row (indexes are zero based), @code{SubData(4,-1)} extracts 5th column, @code{SubData(-1,-1,3)} extracts 4th slice and so on. If argument(s) are non-integer then linear interpolation between slices is used. In MGL version this command usually is used as inline one @code{dat(xx,yy,zz)}.
+Extracts sub-array data from the original data array keeping fixed positive index. For example @code{SubData(-1,2)} extracts 3d row (indexes are zero based), @code{SubData(4,-1)} extracts 5th column, @code{SubData(-1,-1,3)} extracts 4th slice and so on. If argument(s) are non-integer then linear interpolation between slices is used. In MGL version this command usually is used as inline one @code{dat(xx,yy,zz)}. Function return NULL or create empty data if data cannot be created for given [...]
 @end deftypefn
 
 @deftypefn {MGL command} {} subdata @sc{res} dat xdat [ydat=: zdat=:]
@@ -672,7 +709,7 @@ Extracts sub-array data from the original data array keeping fixed positive inde
 @deftypefnx {Method on @code{mglDataC}} @code{mglData} SubData (@code{const mglDataA &}xx, @code{const mglDataA &}yy, @code{const mglDataA &}zz) @code{const}
 @deftypefnx {C function} @code{HMDT} mgl_data_subdata_ext (@code{HCDT} dat, @code{HCDT} xx, @code{HCDT} yy, @code{HCDT} zz)
 @end ifclear
-Extracts sub-array data from the original data array for indexes specified by arrays @var{xx}, @var{yy}, @var{zz} (indirect access). This function work like previous one for 1D arguments or numbers, and resulting array dimensions are equal dimensions of 1D arrays for corresponding direction. For 2D and 3D arrays in arguments, the resulting array have the same dimensions as input arrays. The dimensions of all argument must be the same (or to be scalar 1*1*1) if they are 2D or 3D arrays. I [...]
+Extracts sub-array data from the original data array for indexes specified by arrays @var{xx}, @var{yy}, @var{zz} (indirect access). This function work like previous one for 1D arguments or numbers, and resulting array dimensions are equal dimensions of 1D arrays for corresponding direction. For 2D and 3D arrays in arguments, the resulting array have the same dimensions as input arrays. The dimensions of all argument must be the same (or to be scalar 1*1*1) if they are 2D or 3D arrays. I [...]
 @end deftypefn
 
 @anchor{column}
@@ -682,18 +719,18 @@ Extracts sub-array data from the original data array for indexes specified by ar
 @deftypefnx {Method on @code{mglDataC}} @code{mglData} Column (@code{const char *}eq) @code{const}
 @deftypefnx {C function} @code{HMDT} mgl_data_column (@code{HCDT} dat, @code{const char *}eq)
 @end ifclear
-Get column (or slice) of the data filled by formula @var{eq} on column ids. For example, @code{Column("n*w^2/exp(t)");}. The column ids must be defined first by @ref{idset} function or read from files. In MGL version this command usually is used as inline one @code{dat('eq')}.
+Get column (or slice) of the data filled by formula @var{eq} on column ids. For example, @code{Column("n*w^2/exp(t)");}. The column ids must be defined first by @ref{idset} function or read from files. In MGL version this command usually is used as inline one @code{dat('eq')}. Function return NULL or create empty data if data cannot be created for given arguments.
 @end deftypefn
 
 @anchor{resize}
 @deftypefn {MGL command} {} resize @sc{res} dat @code{mx [my=1 mz=1]}
 @ifclear UDAV
- at deftypefnx {Method on @code{mglData}} @code{mglData} Resize (@code{int} mx, @code{int} my=@code{1}, @code{int} mz=@code{1}, @code{mreal} x1=@code{0}, @code{mreal} x2=@code{1}, @code{mreal} y1=@code{0}, @code{mreal} y2=@code{1}, @code{mreal} z1=@code{0}, @code{mreal} z2=@code{1}) @code{const}
- at deftypefnx {Method on @code{mglDataC}} @code{mglData} Resize (@code{int} mx, @code{int} my=@code{1}, @code{int} mz=@code{1}, @code{mreal} x1=@code{0}, @code{mreal} x2=@code{1}, @code{mreal} y1=@code{0}, @code{mreal} y2=@code{1}, @code{mreal} z1=@code{0}, @code{mreal} z2=@code{1}) @code{const}
+ at deftypefnx {Method on @code{mglData}} @code{mglData} Resize (@code{int} mx, @code{int} my=@code{0}, @code{int} mz=@code{0}, @code{mreal} x1=@code{0}, @code{mreal} x2=@code{1}, @code{mreal} y1=@code{0}, @code{mreal} y2=@code{1}, @code{mreal} z1=@code{0}, @code{mreal} z2=@code{1}) @code{const}
+ at deftypefnx {Method on @code{mglDataC}} @code{mglData} Resize (@code{int} mx, @code{int} my=@code{0}, @code{int} mz=@code{0}, @code{mreal} x1=@code{0}, @code{mreal} x2=@code{1}, @code{mreal} y1=@code{0}, @code{mreal} y2=@code{1}, @code{mreal} z1=@code{0}, @code{mreal} z2=@code{1}) @code{const}
 @deftypefnx {C function} @code{HMDT} mgl_data_resize (@code{HCDT} dat, @code{int} mx, @code{int} my, @code{int} mz)
 @deftypefnx {C function} @code{HMDT} mgl_data_resize_box (@code{HCDT} dat, @code{int} mx, @code{int} my, @code{int} mz, @code{mreal} x1, @code{mreal} x2, @code{mreal} y1, @code{mreal} y2, @code{mreal} z1, @code{mreal} z2)
 @end ifclear
-Resizes the data to new size @var{mx}, @var{my}, @var{mz} from box (part) [@var{x1}, at var{x2}] x [@var{y1}, at var{y2}] x [@var{z1}, at var{z2}] of original array. Initially x,y,z coordinates are supposed to be in [0,1].
+Resizes the data to new size @var{mx}, @var{my}, @var{mz} from box (part) [@var{x1}, at var{x2}] x [@var{y1}, at var{y2}] x [@var{z1}, at var{z2}] of original array. Initially x,y,z coordinates are supposed to be in [0,1]. If one of sizes @var{mx}, @var{my} or @var{mz} is 0 then initial size is used. Function return NULL or create empty data if data cannot be created for given arguments.
 @end deftypefn
 
 @anchor{evaluate}
@@ -709,7 +746,7 @@ Resizes the data to new size @var{mx}, @var{my}, @var{mz} from box (part) [@var{
 @deftypefnx {Method on @code{mglDataC}} @code{mglData} Evaluate (@code{const mglDataA &}idat, @code{const mglDataA &}jdat, @code{const mglDataA &}kdat, @code{bool} norm=@code{true}) @code{const}
 @deftypefnx {C function} @code{HMDT} mgl_data_evaluate (@code{HCDT} dat, @code{HCDT} idat, @code{HCDT} jdat, @code{HCDT} kdat, @code{int} norm)
 @end ifclear
-Gets array which values is result of interpolation of original array for coordinates from other arrays. All dimensions must be the same for data @var{idat}, @var{jdat}, @var{kdat}. Coordinates from @var{idat}, @var{jdat}, @var{kdat} are supposed to be normalized in range [0,1] (if @var{norm}=@code{true}) or in ranges [0,nx], [0,ny], [0,nz] correspondingly.
+Gets array which values is result of interpolation of original array for coordinates from other arrays. All dimensions must be the same for data @var{idat}, @var{jdat}, @var{kdat}. Coordinates from @var{idat}, @var{jdat}, @var{kdat} are supposed to be normalized in range [0,1] (if @var{norm}=@code{true}) or in ranges [0,nx], [0,ny], [0,nz] correspondingly. Function return NULL or create empty data if data cannot be created for given arguments.
 @end deftypefn
 
 @anchor{solve}
@@ -720,7 +757,18 @@ Gets array which values is result of interpolation of original array for coordin
 @deftypefnx {Method on @code{mglData}} @code{mglData} Solve (@code{mreal} val, @code{char} dir, @code{const mglDataA &}idat, @code{bool} norm=@code{true}) @code{const}
 @deftypefnx {C function} @code{HMDT} mgl_data_solve (@code{HCDT} dat, @code{mreal} val, @code{char} dir, @code{HCDT} idat, @code{int} norm)
 @end ifclear
-Gets array which values is indexes (roots) along given direction @var{dir}, where interpolated values of data @var{dat} are equal to @var{val}. Output data will have the sizes of @var{dat} in directions transverse to @var{dir}. If data @var{idat} is provided then its values are used as starting points. This allows to find several branches by consequentive calls. Indexes are supposed to be normalized in range [0,1] (if @var{norm}=@code{true}) or in ranges [0,nx], [0,ny], [0,nz] correspond [...]
+Gets array which values is indexes (roots) along given direction @var{dir}, where interpolated values of data @var{dat} are equal to @var{val}. Output data will have the sizes of @var{dat} in directions transverse to @var{dir}. If data @var{idat} is provided then its values are used as starting points. This allows to find several branches by consequentive calls. Indexes are supposed to be normalized in range [0,1] (if @var{norm}=@code{true}) or in ranges [0,nx], [0,ny], [0,nz] correspond [...]
+ at end deftypefn
+
+ at anchor{roots}
+ at deftypefn {MGL command} {} roots @sc{res} 'func' ini ['var'='x']
+ at deftypefnx {MGL command} {} roots @sc{res} 'func' @code{ini} ['var'='x']
+ at ifclear UDAV
+ at deftypefnx {Method on @code{mglData}} @code{mglData} Roots (@code{const char *}func, @code{char} var) @code{const}
+ at deftypefnx {C function} @code{HMDT} mgl_data_roots (@code{const char *}func, @code{HCDT} ini, @code{char} var)
+ at deftypefnx {C function} @code{mreal} mgl_find_root_txt (@code{const char *}func, @code{mreal} ini, @code{char} var)
+ at end ifclear
+Find roots of equation 'func'=0 for variable @var{var} with initial guess @var{ini}. Secant method is used for root finding. Function return NULL or create empty data if data cannot be created for given arguments.
 @end deftypefn
 
 @anchor{hist}
@@ -734,7 +782,7 @@ Gets array which values is indexes (roots) along given direction @var{dir}, wher
 @deftypefnx {C function} @code{HMDT} mgl_data_hist (@code{HCDT} dat, @code{int} n, @code{mreal} v1, @code{mreal} v2, @code{int} nsub)
 @deftypefnx {C function} @code{HMDT} mgl_data_hist_w (@code{HCDT} dat, @code{HCDT} w, @code{int} n, @code{mreal} v1, @code{mreal} v2, @code{int} nsub)
 @end ifclear
-Creates @var{n}-th points distribution of the data values in range [@var{v1}, @var{v2}]. Array @var{w} specifies weights of the data elements (by default is 1). Parameter @var{nsub} define the number of additional interpolated points (for smoothness of histogram). See also @ref{Data manipulation}
+Creates @var{n}-th points distribution of the data values in range [@var{v1}, @var{v2}]. Array @var{w} specifies weights of the data elements (by default is 1). Parameter @var{nsub} define the number of additional interpolated points (for smoothness of histogram). Function return NULL or create empty data if data cannot be created for given arguments. See also @ref{Data manipulation}
 @end deftypefn
 
 @anchor{momentum}
@@ -751,7 +799,7 @@ Gets momentum (1d-array) of the data along direction @var{dir}. String @var{how}
 @ifnottex
 res_k = \sum_ij how(x_i,y_j,z_k) a_ij/ \sum_ij a_ij
 @end ifnottex
-if @var{dir}=@samp{z} and so on. Coordinates @samp{x}, @samp{y}, @samp{z} are data indexes normalized in range [0,1].
+if @var{dir}=@samp{z} and so on. Coordinates @samp{x}, @samp{y}, @samp{z} are data indexes normalized in range [0,1]. Function return NULL or create empty data if data cannot be created for given arguments.
 @end deftypefn
 
 @anchor{sum}
@@ -761,7 +809,7 @@ if @var{dir}=@samp{z} and so on. Coordinates @samp{x}, @samp{y}, @samp{z} are da
 @deftypefnx {Method on @code{mglDataC}} @code{mglData} Sum (@code{const char *}dir) @code{const}
 @deftypefnx {C function} @code{HMDT} mgl_data_sum (@code{HCDT} dat, @code{const char *}dir)
 @end ifclear
-Gets array which is the result of summation in given direction or direction(s).
+Gets array which is the result of summation in given direction or direction(s). Function return NULL or create empty data if data cannot be created for given arguments.
 @end deftypefn
 
 @anchor{max}
@@ -771,7 +819,7 @@ Gets array which is the result of summation in given direction or direction(s).
 @deftypefnx {Method on @code{mglDataC}} @code{mglData} Max (@code{const char *}dir) @code{const}
 @deftypefnx {C function} @code{HMDT} mgl_data_max_dir (@code{HCDT} dat, @code{const char *}dir)
 @end ifclear
-Gets array which is the maximal data values in given direction or direction(s).
+Gets array which is the maximal data values in given direction or direction(s). Function return NULL or create empty data if data cannot be created for given arguments.
 @end deftypefn
 
 @anchor{min}
@@ -781,7 +829,7 @@ Gets array which is the maximal data values in given direction or direction(s).
 @deftypefnx {Method on @code{mglDataC}} @code{mglData} Min (@code{const char *}dir) @code{const}
 @deftypefnx {C function} @code{HMDT} mgl_data_min_dir (@code{HCDT} dat, @code{const char *}dir)
 @end ifclear
-Gets array which is the maximal data values in given direction or direction(s).
+Gets array which is the maximal data values in given direction or direction(s). Function return NULL or create empty data if data cannot be created for given arguments.
 @end deftypefn
 
 @anchor{combine}
@@ -791,7 +839,7 @@ Gets array which is the maximal data values in given direction or direction(s).
 @deftypefnx {Method on @code{mglDataC}} @code{mglData} Combine (@code{const mglDataA &}a) @code{const}
 @deftypefnx {C function} @code{HMDT} mgl_data_combine (@code{HCDT} dat, @code{HCDT} a)
 @end ifclear
-Returns direct multiplication of arrays (like, res[i,j] = this[i]*a[j] and so on).
+Returns direct multiplication of arrays (like, res[i,j] = this[i]*a[j] and so on). Function return NULL or create empty data if data cannot be created for given arguments.
 @end deftypefn
 
 @anchor{trace}
@@ -801,7 +849,20 @@ Returns direct multiplication of arrays (like, res[i,j] = this[i]*a[j] and so on
 @deftypefnx {Method on @code{mglDataC}} @code{mglData} Trace () @code{const}
 @deftypefnx {C function} @code{HMDT} mgl_data_trace (@code{HCDT} dat)
 @end ifclear
-Gets array of diagonal elements a[i,i] (for 2D case) or a[i,i,i] (for 3D case) where i=0...nx-1. Function return copy of itself for 1D case. Data array must have dimensions ny,nz >= nx or ny,nz = 1.
+Gets array of diagonal elements a[i,i] (for 2D case) or a[i,i,i] (for 3D case) where i=0...nx-1. Function return copy of itself for 1D case. Data array must have dimensions ny,nz >= nx or ny,nz = 1. Function return NULL or create empty data if data cannot be created for given arguments.
+ at end deftypefn
+
+ at anchor{correl}
+ at deftypefn {MGL command} {} correl @sc{res} adat bdat 'dir'
+ at ifclear UDAV
+ at deftypefnx {Method on @code{mglData}} @code{mglData} Correl (@code{const mglDataA &}b, @code{const char *}dir) @code{const}
+ at deftypefnx {Method on @code{mglData}} @code{mglData} AutoCorrel (@code{const char *}dir) @code{const}
+ at deftypefnx {Method on @code{mglDataC}} @code{mglDataC} Correl (@code{const mglDataA &}b, @code{const char *}dir) @code{const}
+ at deftypefnx {Method on @code{mglDataC}} @code{mglDataC} AutoCorrel (@code{const char *}dir) @code{const}
+ at deftypefnx {C function} @code{HMDT} mgl_data_correl (@code{HCDT} a, @code{HCDT} b, @code{const char *}dir)
+ at deftypefnx {C function} @code{HADT} mgl_datac_correl (@code{HCDT} a, @code{HCDT} b, @code{const char *}dir)
+ at end ifclear
+Find correlation between data @var{a} (or this in C++) and @var{b} along directions @var{dir}. Fourier transform is used to find the correlation. So, you may want to use functions @ref{swap} or @ref{norm} before plotting it. Function return NULL or create empty data if data cannot be created for given arguments.
 @end deftypefn
 
 @ifclear UDAV
@@ -823,21 +884,11 @@ Gets array of arguments of the data.
 @end deftypefn
 @end ifclear
 
- at anchor{roots}
- at deftypefn {MGL command} {} roots @sc{res} 'func' ini ['var'='x']
- at deftypefnx {MGL command} {} roots @sc{res} 'func' @code{ini} ['var'='x']
- at ifclear UDAV
- at deftypefnx {Method on @code{mglData}} @code{mglData} Roots (@code{const char *}func, @code{char} var) @code{const}
- at deftypefnx {C function} @code{HMDT} mgl_data_roots (@code{const char *}func, @code{HCDT} ini, @code{char} var)
- at deftypefnx {C function} @code{mreal} mgl_find_root_txt (@code{const char *}func, @code{mreal} ini, @code{char} var)
- at end ifclear
-Find roots of equation 'func'=0 for variable @var{var} with initial guess @var{ini}. Secant method is used for root finding.
- at end deftypefn
-
 @c ------------------------------------------------------------------
 @external{}
 @node Data changing, Interpolation, Make another data, Data processing
 @section Data changing
+ at nav{}
 @cindex CumSum
 @cindex Integral
 @cindex Diff
@@ -1034,6 +1085,7 @@ Normalizes data slice-by-slice along direction @var{dir} the data in slices to r
 @external{}
 @node Interpolation, Data information, Data changing, Data processing
 @section Interpolation
+ at nav{}
 
 MGL scripts can use linear interpolation by @ref{subdata} command, or spline interpolation by @ref{evaluate} command. Also you can use @ref{resize} for obtaining a data array with new sizes.
 
@@ -1043,16 +1095,20 @@ However, there are much special faster functions in other modes (C/C++/Fortran/P
 
 @cindex Spline
 @deftypefn {Method on @code{mglData}} @code{mreal} Spline (@code{mreal} x, @code{mreal} y=@code{0}, @code{mreal} z=@code{0}) @code{const}
+ at deftypefnx {Method on @code{mglDataC}} @code{dual} Spline (@code{mreal} x, @code{mreal} y=@code{0}, @code{mreal} z=@code{0}) @code{const}
 @deftypefnx {C function} @code{mreal} mgl_data_spline (@code{HCDT} dat, @code{mreal} x, @code{mreal} y, @code{mreal} z)
+ at deftypefnx {C function} @code{dual} mgl_datac_spline (@code{HCDT} dat, @code{mreal} x, @code{mreal} y, @code{mreal} z)
 Interpolates data by cubic spline to the given point @var{x} in [0...nx-1], @var{y} in [0...ny-1], @var{z} in [0...nz-1].
 @end deftypefn
 @cindex Spline1
 @deftypefn {Method on @code{mglData}} @code{mreal} Spline1 (@code{mreal} x, @code{mreal} y=@code{0}, @code{mreal} z=@code{0}) @code{const}
+ at deftypefnx {Method on @code{mglDataC}} @code{dual} Spline1 (@code{mreal} x, @code{mreal} y=@code{0}, @code{mreal} z=@code{0}) @code{const}
 Interpolates data by cubic spline to the given point @var{x}, @var{y}, @var{z} which assumed to be normalized in range [0, 1].
 @end deftypefn
 
 @deftypefn {Method on @code{mglData}} @code{mreal} Spline (@code{mglPoint} &dif, @code{mreal} x, @code{mreal} y=@code{0}, @code{mreal} z=@code{0}) @code{const}
 @deftypefnx {C function} @code{mreal} mgl_data_spline_ext (@code{HCDT} dat, @code{mreal} x, @code{mreal} y, @code{mreal} z, @code{mreal *}dx, @code{mreal *}dy, @code{mreal *}dz)
+ at deftypefnx {C function} @code{dual} mgl_datac_spline_ext (@code{HCDT} dat, @code{mreal} x, @code{mreal} y, @code{mreal} z, @code{dual *}dx, @code{dual *}dy, @code{dual *}dz)
 Interpolates data by cubic spline to the given point @var{x} in [0...nx-1], @var{y} in [0...ny-1], @var{z} in [0...nz-1]. The values of derivatives at the point are saved in @var{dif}.
 @end deftypefn
 @cindex Spline1
@@ -1091,6 +1147,7 @@ Interpolates data by linear function to the given point @var{x}, @var{y}, @var{z
 @external{}
 @node Data information, Operators, Interpolation, Data processing
 @section Data information
+ at nav{}
 
 There are a set of functions for obtaining data properties in MGL language. However most of them can be found using "suffixes". Suffix can get some numerical value of the data array (like its size, maximal or minimal value, the sum of elements and so on) as number. Later it can be used as usual number in command arguments. The suffixes start from point @samp{.} right after (without spaces) variable name or its sub-array. For example, @code{a.nx} give the x-size of data @var{a}, @code{b(1 [...]
 
@@ -1264,6 +1321,7 @@ Give first (for @code{.a}, i.e. @code{dat->a[0]}).
 @external{}
 @node Operators, Global functions, Data information, Data processing
 @section Operators
+ at nav{}
 
 @deftypefn {MGL command} {} copy @sc{dat} dat2 ['eq'='']
 @ifclear UDAV
@@ -1356,6 +1414,7 @@ Divides by the other data or the number.
 @external{}
 @node Global functions, Evaluate expression, Operators, Data processing
 @section Global functions
+ at nav{}
 
 @ifclear UDAV
 These functions are not methods of @code{mglData} class. However it provide additional functionality to handle data. So I put it in this chapter.
@@ -1445,7 +1504,7 @@ Computes the Jacobian for transformation @{i,j,k@} to @{@var{x}, at var{y}, at var{z}@
 @deftypefnx {C function} @code{HMDT} mgl_triangulation_2d (@code{HCDT} x, @code{HCDT} y)
 @c @deftypefnx {C function} @code{HMDT} mgl_triangulation_3d (@code{HCDT} x, @code{HCDT} y, @code{HCDT} z)
 @end ifclear
-Computes triangulation for arbitrary placed points with coordinates @{@var{x}, at var{y}@} (i.e. finds triangles which connect points). MathGL use @uref{http://www.s-hull.org/,s-hull} code for triangulation. The sizes of 1st dimension @strong{must be equal} for all arrays @code{x.nx=y.nx}. Resulting array can be used in @ref{triplot} or @ref{tricont} functions for visualization of reconstructed surface.
+Computes triangulation for arbitrary placed points with coordinates @{@var{x}, at var{y}@} (i.e. finds triangles which connect points). MathGL use @uref{http://www.s-hull.org/,s-hull} code for triangulation. The sizes of 1st dimension @strong{must be equal} for all arrays @code{x.nx=y.nx}. Resulting array can be used in @ref{triplot} or @ref{tricont} functions for visualization of reconstructed surface. @sref{Making regular data}
 @end deftypefn
 
 
@@ -1453,6 +1512,7 @@ Computes triangulation for arbitrary placed points with coordinates @{@var{x}, at v
 @external{}
 @node Evaluate expression, MGL variables, Global functions, Data processing
 @section Evaluate expression
+ at nav{}
 
 @ifset UDAV
 You can use arbitrary formulas of existed data arrays or constants as any argument of data processing or data plotting commands. There are only 2 limitations: formula shouldn't contain spaces (to be recognized as single argument), and formula cannot be used as argument which will be (re)created by MGL command.
@@ -1509,6 +1569,7 @@ Evaluates the formula derivation respect to @var{dir} for variables in array @va
 @external{}
 @node MGL variables, , Evaluate expression, Data processing
 @section MGL variables
+ at nav{}
 
 @ifset UDAV
 For information about MGL variables see @ref{MGL definition}.
@@ -1548,10 +1609,9 @@ Deletes the instance of class mglVar.
 @end deftypefn
 
 @deftypefn {Method on @code{mglVar}} @code{void} MoveAfter (@code{mglVar *}var)
-Evaluates the formula for @code{'x','r'}=@var{x}, @code{'y','n'}=@var{y}, @code{'z','t'}=@var{z}, @code{'a','u'}=@var{u}.
+Move variable after @var{var} in the list.
 @end deftypefn
 
 @end ifclear
 
 @external{}
-
diff --git a/texinfo/data_ru.texi b/texinfo/data_ru.texi
index 852c87b..db4a40a 100644
--- a/texinfo/data_ru.texi
+++ b/texinfo/data_ru.texi
@@ -1,5 +1,6 @@
 @c ------------------------------------------------------------------
 @chapter Обработка данных
+ at nav{}
 
 @ifset UDAV
 В данной главе описываются команды для работы с массивами данных. Они включают команды для выделения памяти и изменения размера данных, чтения данных из файла, численного дифференцирования, интегрирования, интерполяции и пр., заполнения по текстовой формуле и т.д. Класс позволяет работать с данными размерности не более 3 (как функции от трёх переменных -- x,y,z). Массивы которые могут быть созданы командами MGL отображаются Small Caps шрифтом (например, @sc{dat}).
@@ -29,6 +30,7 @@
 @external{}
 @node Public variables, Data constructor, , Data processing
 @section Переменные
+ at nav{}
 
 @ifset UDAV
 MGL не поддерживает прямой доступ к элементам массива. См. раздел @ref{Data filling}
@@ -96,6 +98,7 @@ MGL не поддерживает прямой доступ к элемента
 @external{}
 @node Data constructor, Data resizing, Public variables, Data processing
 @section Создание и удаление данных
+ at nav{}
 @cindex mglData
 
 @ifset UDAV
@@ -164,6 +167,7 @@ There are many functions, which can create data for output (see @ref{Data fillin
 @external{}
 @node Data resizing, Data filling, Data constructor, Data processing
 @section Изменение размеров данных
+ at nav{}
 @cindex Create
 @cindex Rearrange
 @cindex Extend
@@ -310,11 +314,13 @@ a_ij^new = a_i^old where j=0... at var{n1}. Соответственно, для @v
 @external{}
 @node Data filling, File I/O, Data resizing, Data processing
 @section Заполнение данных
+ at nav{}
 @cindex Fill
 @cindex Modify
 @cindex Set
 @cindex List
 @cindex Var
+ at cindex Refill
 
 @anchor{list}
 @deftypefn {Команда MGL} {} list @sc{dat} @code{v1 ...}
@@ -364,7 +370,7 @@ a_ij^new = a_i^old where j=0... at var{n1}. Соответственно, для @v
 @deftypefnx {Функция С} @code{void} mgl_datac_set_matrix (@code{HADT} dat, @code{gsl_matrix *}m)
 Выделяет память и копирует данные из структуры типа @code{gsl_matrix *}.
 @end deftypefn
- at deftypefn {Метод класса @code{mglData}} @code{void} Set (@code{const mglData &}from)
+ at deftypefn {Метод класса @code{mglData}} @code{void} Set (@code{const mglDataA &}from)
 @deftypefnx {Метод класса @code{mglData}} @code{void} Set (@code{HCDT} from)
 @deftypefnx {Функция С} @code{void} mgl_data_set (@code{HMDT} dat, @code{HCDT} from)
 @deftypefnx {Метод класса @code{mglDataC}} @code{void} Set (@code{const mglDataA &}from)
@@ -429,8 +435,8 @@ a_ij^new = a_i^old where j=0... at var{n1}. Соответственно, для @v
 @deftypefnx {Команда MGL} {} fill dat 'eq' vdat wdat
 @ifclear UDAV
 @deftypefnx {Метод класса @code{mglData}} @code{void} Fill (@code{HMGL} gr, @code{const char *}eq, @code{const char *}opt=@code{""})
- at deftypefnx {Метод класса @code{mglData}} @code{void} Fill (@code{HMGL} gr, @code{const char *}eq, @code{const mglData &}vdat, @code{const char *}opt=@code{""})
- at deftypefnx {Метод класса @code{mglData}} @code{void} Fill (@code{HMGL} gr, @code{const char *}eq, @code{const mglData &}vdat, @code{const mglData &}wdat, @code{const char *}opt=@code{""})
+ at deftypefnx {Метод класса @code{mglData}} @code{void} Fill (@code{HMGL} gr, @code{const char *}eq, @code{const mglDataA &}vdat, @code{const char *}opt=@code{""})
+ at deftypefnx {Метод класса @code{mglData}} @code{void} Fill (@code{HMGL} gr, @code{const char *}eq, @code{const mglDataA &}vdat, @code{const mglDataA &}wdat, @code{const char *}opt=@code{""})
 @deftypefnx {Метод класса @code{mglDataC}} @code{void} Fill (@code{HMGL} gr, @code{const char *}eq, @code{const char *}opt=@code{""})
 @deftypefnx {Метод класса @code{mglDataC}} @code{void} Fill (@code{HMGL} gr, @code{const char *}eq, @code{const mglDataA &}vdat, @code{const char *}opt=@code{""})
 @deftypefnx {Метод класса @code{mglDataC}} @code{void} Fill (@code{HMGL} gr, @code{const char *}eq, @code{const mglDataA &}vdat, @code{const mglDataA &}wdat, @code{const char *}opt=@code{""})
@@ -446,8 +452,8 @@ a_ij^new = a_i^old where j=0... at var{n1}. Соответственно, для @v
 @deftypefnx {Команда MGL} {} modify dat 'eq' vdat wdat
 @ifclear UDAV
 @deftypefnx {Метод класса @code{mglData}} @code{void} Modify (@code{const char *}eq, @code{int} dim=@code{0})
- at deftypefnx {Метод класса @code{mglData}} @code{void} Modify (@code{const char *}eq, @code{const mglData &}v)
- at deftypefnx {Метод класса @code{mglData}} @code{void} Modify (@code{const char *}eq, @code{const mglData &}v, @code{const mglData &}w)
+ at deftypefnx {Метод класса @code{mglData}} @code{void} Modify (@code{const char *}eq, @code{const mglDataA &}v)
+ at deftypefnx {Метод класса @code{mglData}} @code{void} Modify (@code{const char *}eq, @code{const mglDataA &}v, @code{const mglDataA &}w)
 @deftypefnx {Метод класса @code{mglDataC}} @code{void} Modify (@code{const char *}eq, @code{int} dim=@code{0})
 @deftypefnx {Метод класса @code{mglDataC}} @code{void} Modify (@code{const char *}eq, @code{const mglDataA &}v)
 @deftypefnx {Метод класса @code{mglDataC}} @code{void} Modify (@code{const char *}eq, @code{const mglDataA &}v, @code{const mglDataA &}w)
@@ -463,7 +469,7 @@ a_ij^new = a_i^old where j=0... at var{n1}. Соответственно, для @v
 @deftypefn {Команда MGL} {} fillsample dat 'how'
 @ifclear UDAV
 @deftypefnx {Метод класса @code{mglData}} @code{void} FillSample (@code{const char *}how)
- at deftypefnx mglData @code{void} mgl_data_fill_sample (@code{HMDT} a, @code{const char *}how)
+ at deftypefnx {Функция С} @code{void} mgl_data_fill_sample (@code{HMDT} a, @code{const char *}how)
 @end ifclear
 Заполняет массив данных 'x' или 'k' значениями для преобразований Ханкеля ('h') или Фурье ('f').
 @end deftypefn
@@ -472,10 +478,12 @@ a_ij^new = a_i^old where j=0... at var{n1}. Соответственно, для @v
 @anchor{datagrid}
 @deftypefn {Команда MGL} {} datagrid dat xdat ydat zdat
 @ifclear UDAV
- at deftypefnx {Метод класса @code{mglData}} @code{mglData} Grid (@code{HMGL} gr, @code{const mglData &}x, @code{const mglData &}y, @code{const mglData &}z, @code{const char *}opt=@code{""})
+ at deftypefnx {Метод класса @code{mglData}} @code{mglData} Grid (@code{HMGL} gr, @code{const mglDataA &}x, @code{const mglDataA &}y, @code{const mglDataA &}z, @code{const char *}opt=@code{""})
+ at deftypefnx {Метод класса @code{mglData}} @code{mglData} Grid (@code{const mglDataA &}x, @code{const mglDataA &}y, @code{const mglDataA &}z, @code{mglPoint} p1, @code{mglPoint} p2)
 @deftypefnx {Функция С} @code{void} mgl_data_grid (@code{HMGL} gr, @code{HMDT} u, @code{HCDT} x, @code{HCDT} y, @code{HCDT} z, @code{const char *}opt)
+ at deftypefnx {Функция С} @code{void} mgl_data_grid_xy (@code{HMDT} u, @code{HCDT} x, @code{HCDT} y, @code{HCDT} z, @code{mreal} x1, @code{mreal} x2, @code{mreal} y1, @code{mreal} y2)
 @end ifclear
-Заполняет значения массива результатом линейной интерполяции по триангулированной поверхности, найденной по произвольно расположенным точкам @samp{x}, @samp{y}, @samp{z}. NAN значение используется для точек сетки вне триангулированной поверхности.
+Заполняет значения массива результатом линейной интерполяции (считая координаты равнораспределенными в диапазоне осей координат или в диапазоне [x1,x2]*[y1,y2]) по триангулированной поверхности, найденной по произвольно расположенным точкам @samp{x}, @samp{y}, @samp{z}. NAN значение используется для точек сетки вне триангулированной поверхности. @sref{Making regular data}
 @end deftypefn
 
 
@@ -483,26 +491,50 @@ a_ij^new = a_i^old where j=0... at var{n1}. Соответственно, для @v
 @deftypefn {Команда MGL} {} put dat @code{val [i=: j=: k=:]}
 @ifclear UDAV
 @deftypefnx {Метод класса @code{mglData}} @code{void} Put (@code{mreal} val, @code{int} i=@code{-1}, @code{int} j=@code{-1}, @code{int} k=@code{-1})
- at deftypefnx mglData @code{void} mgl_data_put_val (@code{HMDT} a, @code{mreal} val, @code{int} i, @code{int} j, @code{int} k)
+ at deftypefnx {Метод класса @code{mglDataC}} @code{void} Put (@code{dual} val, @code{int} i=@code{-1}, @code{int} j=@code{-1}, @code{int} k=@code{-1})
+ at deftypefnx {Функция С} @code{void} mgl_data_put_val (@code{HMDT} a, @code{mreal} val, @code{int} i, @code{int} j, @code{int} k)
+ at deftypefnx {Функция С} @code{void} mgl_datac_put_val (@code{HADT} a, @code{dual} val, @code{int} i, @code{int} j, @code{int} k)
 @end ifclear
 Присваивает значения (под-)массива @var{dat}[@var{i}, @var{j}, @var{k}] = @var{val}. Индексы @var{i}, @var{j}, @var{k} равные @samp{-1} задают значения @var{val} для всего диапазона соответствующего направления(ий). Например, @code{Put(val,-1,0,-1);} задает a[i,0,j]=@var{val} для i=0...(nx-1), j=0...(nz-1).
 @end deftypefn
 
 @deftypefn {Команда MGL} {} put dat vdat [@code{i=: j=: k=:}]
 @ifclear UDAV
- at deftypefnx {Метод класса @code{mglData}} @code{void} Put (@code{const mglData &}v, @code{int} i=@code{-1}, @code{int} j=@code{-1}, @code{int} k=@code{-1})
- at deftypefnx mglData @code{void} mgl_data_put_dat (@code{HMDT} a, @code{HCDT} v, @code{int} i, @code{int} j, @code{int} k)
+ at deftypefnx {Метод класса @code{mglData}} @code{void} Put (@code{const mglDataA &}v, @code{int} i=@code{-1}, @code{int} j=@code{-1}, @code{int} k=@code{-1})
+ at deftypefnx {Метод класса @code{mglDataC}} @code{void} Put (@code{const mglDataA &}v, @code{int} i=@code{-1}, @code{int} j=@code{-1}, @code{int} k=@code{-1})
+ at deftypefnx {Функция С} @code{void} mgl_data_put_dat (@code{HMDT} a, @code{HCDT} v, @code{int} i, @code{int} j, @code{int} k)
+ at deftypefnx {Функция С} @code{void} mgl_datac_put_dat (@code{HADT} a, @code{HCDT} v, @code{int} i, @code{int} j, @code{int} k)
 @end ifclear
 Копирует значения из массива @var{v} в диапазон значений данного массива. Индексы @var{i}, @var{j}, @var{k} равные @samp{-1} задают диапазон изменения значений в соответствующих направление(ях). Младшие размерности массива @var{v} должны быть больше выбранного диапазона массива. Например, @code{Put(v,-1,0,-1);} присвоит a[i,0,j]=@var{v}.ny>nz ? @var{v}.a[i,j] : @var{v}.a[i], где i=0...(nx-1), j=0...(nz-1) и условие v.nx>=nx выполнено.
 @end deftypefn
 
+ at anchor{refill}
+ at deftypefn {Команда MGL} {} refill dat xdat vdat [sl=-1]
+ at deftypefnx {Команда MGL} {} refill dat xdat ydat vdat [sl=-1]
+ at deftypefnx {Команда MGL} {} refill dat xdat ydat zdat vdat
+ at ifclear UDAV
+ at deftypefnx {Метод класса @code{mglData}} @code{void} Refill (@code{const mglDataA &}x, @code{const mglDataA &}v, @code{mreal} x1, @code{mreal} x2, @code{long} sl=@code{-1})
+ at deftypefnx {Метод класса @code{mglData}} @code{void} Refill (@code{const mglDataA &}x, @code{const mglDataA &}v, @code{mglPoint} p1, @code{mglPoint} p2, @code{long} sl=@code{-1})
+ at deftypefnx {Метод класса @code{mglData}} @code{void} Refill (@code{const mglDataA &}x, @code{const mglDataA &}y, @code{const mglDataA &}v, @code{mglPoint} p1, @code{mglPoint} p2, @code{long} sl=@code{-1})
+ at deftypefnx {Метод класса @code{mglData}} @code{void} Refill (@code{const mglDataA &}x, @code{const mglDataA &}y, @code{const mglDataA &}z, @code{const mglDataA &}v, @code{mglPoint} p1, @code{mglPoint} p2)
+ at deftypefnx {Метод класса @code{mglData}} @code{void} Refill (@code{HMGL} gr, @code{const mglDataA &}x, @code{const mglDataA &}v, @code{long} sl=@code{-1}, @code{const char *}opt=@code{""})
+ at deftypefnx {Метод класса @code{mglData}} @code{void} Refill (@code{HMGL} gr, @code{const mglDataA &}x, @code{const mglDataA &}y, @code{const mglDataA &}v, @code{long} sl=@code{-1}, @code{const char *}opt=@code{""})
+ at deftypefnx {Метод класса @code{mglData}} @code{void} Refill (@code{HMGL} gr, @code{const mglDataA &}x, @code{const mglDataA &}y, @code{const mglDataA &}z, @code{const mglDataA &}v, @code{const char *}opt=@code{""})
+ at deftypefnx {Функция С} @code{void} mgl_data_refill_x (@code{HMDT} a, @code{HCDT} x, @code{HCDT} v, @code{mreal} x1, @code{mreal} x2, @code{long} sl)
+ at deftypefnx {Функция С} @code{void} mgl_data_refill_xy (@code{HMDT} a, @code{HCDT} x, @code{HCDT} y, @code{HCDT} v, @code{mreal} x1, @code{mreal} x2, @code{mreal} y1, @code{mreal} y2, @code{long} sl)
+ at deftypefnx {Функция С} @code{void} mgl_data_refill_xyz (@code{HMDT} a, @code{HCDT} x, @code{HCDT} y, @code{HCDT} z, @code{HCDT} v, @code{mreal} x1, @code{mreal} x2, @code{mreal} y1, @code{mreal} y2, @code{mreal} z1, @code{mreal} z2)
+ at deftypefnx {Функция С} @code{void} mgl_data_refill_gr (@code{HMGL} gr, @code{HMDT} a, @code{HCDT} x, @code{HCDT} y, @code{HCDT} z, @code{HCDT} v, @code{long} sl, @code{const char *}opt)
+ at end ifclear
+Заполняет значениями интерполяции массива @var{v} в точках @{@var{x}, @var{y}, @var{z}@}=@{@code{X[i], Y[j], Z[k]}@} (или @{@var{x}, @var{y}, @var{z}@}=@{@code{X[i,j,k], Y[i,j,k], Z[i,j,k]}@} если @var{x}, @var{y}, @var{z} не 1d массивы), где @code{X,Y,Z} равномерно распределены в диапазоне [@var{x1}, at var{x2}]*[@var{y1}, at var{y2}]*[@var{z1}, at var{z2}] и имеют такой же размер как и заполняемый массив. Если параметр @var{sl} равен 0 или положительный, то изменятся будет только @var{sl}-ый срез.
+ at end deftypefn
+
 @anchor{idset}
 @deftypefn {Команда MGL} {} idset dat 'ids'
 @ifclear UDAV
 @deftypefnx {Метод класса @code{mglData}} @code{void} SetColumnId (@code{const char *}ids)
- at deftypefnx mglData @code{void} mgl_data_set_id (@code{const char *}ids)
+ at deftypefnx {Функция С} @code{void} mgl_data_set_id (@code{const char *}ids)
 @deftypefnx {Метод класса @code{mglDataC}} @code{void} SetColumnId (@code{const char *}ids)
- at deftypefnx mglData @code{void} mgl_datac_set_id (@code{HADT} a, @code{const char *}ids)
+ at deftypefnx {Функция С} @code{void} mgl_datac_set_id (@code{HADT} a, @code{const char *}ids)
 @end ifclear
 Задает названия @var{ids} для колонок массива данных. Строка должна содержать один символ 'a'...'z' на колонку. Эти названия используются в функции @ref{column}.
 @end deftypefn
@@ -512,6 +544,7 @@ a_ij^new = a_i^old where j=0... at var{n1}. Соответственно, для @v
 @external{}
 @node File I/O, Make another data, Data filling, Data processing
 @section Чтение/сохранение данных
+ at nav{}
 @cindex Read
 @cindex ReadMat
 @cindex ReadRange
@@ -640,6 +673,7 @@ a_ij^new = a_i^old where j=0... at var{n1}. Соответственно, для @v
 @external{}
 @node Make another data, Data changing, File I/O, Data processing
 @section Make another data
+ at nav{}
 @cindex SubData
 @cindex Column
 @cindex Trace
@@ -652,6 +686,8 @@ a_ij^new = a_i^old where j=0... at var{n1}. Соответственно, для @v
 @cindex Min
 @cindex Max
 @cindex Roots
+ at cindex Correl
+ at cindex AutoCorrel
 
 @anchor{subdata}
 @deftypefn {Команда MGL} {} subdata @sc{res} dat @code{xx [yy=: zz=:]}
@@ -660,16 +696,16 @@ a_ij^new = a_i^old where j=0... at var{n1}. Соответственно, для @v
 @deftypefnx {Метод класса @code{mglDataC}} @code{mglData} SubData (@code{mreal} xx, @code{mreal} yy=@code{-1}, @code{mreal} zz=@code{-1}) @code{const}
 @deftypefnx {Функция С} @code{HMDT} mgl_data_subdata (@code{HCDT} dat, @code{mreal} xx, @code{mreal} yy, @code{mreal} zz)
 @end ifclear
-Возвращает в @var{res} подмассив массива данных @var{dat} с фиксированными значениями индексов с положительными значениями. Например, @code{SubData(-1,2)} выделяет третью строку (индексы начинаются с нуля), @code{SubData(4,-1)} выделяет 5-ую колонку, @code{SubData(-1,-1,3)} выделяет 4-ый срез и т.д. В MGL скриптах обычно используется упрощенная версия @code{dat(xx,yy,zz)}.
+Возвращает в @var{res} подмассив массива данных @var{dat} с фиксированными значениями индексов с положительными значениями. Например, @code{SubData(-1,2)} выделяет третью строку (индексы начинаются с нуля), @code{SubData(4,-1)} выделяет 5-ую колонку, @code{SubData(-1,-1,3)} выделяет 4-ый срез и т.д. В MGL скриптах обычно используется упрощенная версия @code{dat(xx,yy,zz)}. Функция возвращает NULL или пустой массив если данные не могут быть созданы при данных значениях аргументов.
 @end deftypefn
 
 @deftypefn {Команда MGL} {} subdata @sc{res} dat xdat [ydat=: zdat=:]
 @ifclear UDAV
- at deftypefnx {Метод класса @code{mglData}} @code{mglData} SubData (@code{const mglData &}xx, @code{const mglData &}yy, @code{const mglData &}zz) @code{const}
+ at deftypefnx {Метод класса @code{mglData}} @code{mglData} SubData (@code{const mglDataA &}xx, @code{const mglDataA &}yy, @code{const mglDataA &}zz) @code{const}
 @deftypefnx {Метод класса @code{mglDataC}} @code{mglData} SubData (@code{const mglDataA &}xx, @code{const mglDataA &}yy, @code{const mglDataA &}zz) @code{const}
 @deftypefnx {Функция С} @code{HMDT} mgl_data_subdata_ext (@code{HCDT} dat, @code{HCDT} xx, @code{HCDT} yy, @code{HCDT} zz)
 @end ifclear
-Возвращает в @var{res} подмассив массива данных @var{dat} с индексами, заданными в массивах @var{xx}, @var{yy}, @var{zz} (косвенная адресация). Результат будет иметь размерность массивов с индексами. Размеры массивов @var{xx}, @var{yy}, @var{zz} с индексами должна быть одинакова, либо должны быть "скаляром" (т.е. 1*1*1). В MGL скриптах обычно используется упрощенная версия @code{dat(xx,yy,zz)}.
+Возвращает в @var{res} подмассив массива данных @var{dat} с индексами, заданными в массивах @var{xx}, @var{yy}, @var{zz} (косвенная адресация). Результат будет иметь размерность массивов с индексами. Размеры массивов @var{xx}, @var{yy}, @var{zz} с индексами должна быть одинакова, либо должны быть "скаляром" (т.е. 1*1*1). В MGL скриптах обычно используется упрощенная версия @code{dat(xx,yy,zz)}. Функция возвращает NULL или пустой массив если данные не могут быть созданы при данных значени [...]
 @end deftypefn
 
 @anchor{column}
@@ -679,18 +715,18 @@ a_ij^new = a_i^old where j=0... at var{n1}. Соответственно, для @v
 @deftypefnx {Метод класса @code{mglDataC}} @code{mglData} Column (@code{const char *}eq) @code{const}
 @deftypefnx {Функция С} @code{HMDT} mgl_data_column (@code{HCDT} dat, @code{const char *}eq)
 @end ifclear
-Возвращает массив данных заполненный по формуле @var{eq}, вычисленной для именованных колонок (или срезов). Например, @code{Column("n*w^2/exp(t)");}. Имена колонок должны быть предварительно заданы функцией @ref{idset} или при чтении файлов данных. В MGL скриптах обычно используется упрощенная версия @code{dat('eq')}.
+Возвращает массив данных заполненный по формуле @var{eq}, вычисленной для именованных колонок (или срезов). Например, @code{Column("n*w^2/exp(t)");}. Имена колонок должны быть предварительно заданы функцией @ref{idset} или при чтении файлов данных. В MGL скриптах обычно используется упрощенная версия @code{dat('eq')}. Функция возвращает NULL или пустой массив если данные не могут быть созданы при данных значениях аргументов.
 @end deftypefn
 
 @anchor{resize}
 @deftypefn {Команда MGL} {} resize @sc{res} dat @code{mx [my=1 mz=1]}
 @ifclear UDAV
- at deftypefnx {Метод класса @code{mglData}} @code{mglData} Resize (@code{int} mx, @code{int} my=@code{1}, @code{int} mz=@code{1}, @code{mreal} x1=@code{0}, @code{mreal} x2=@code{1}, @code{mreal} y1=@code{0}, @code{mreal} y2=@code{1}, @code{mreal} z1=@code{0}, @code{mreal} z2=@code{1}) @code{const}
- at deftypefnx {Метод класса @code{mglDataC}} @code{mglData} Resize (@code{int} mx, @code{int} my=@code{1}, @code{int} mz=@code{1}, @code{mreal} x1=@code{0}, @code{mreal} x2=@code{1}, @code{mreal} y1=@code{0}, @code{mreal} y2=@code{1}, @code{mreal} z1=@code{0}, @code{mreal} z2=@code{1}) @code{const}
+ at deftypefnx {Метод класса @code{mglData}} @code{mglData} Resize (@code{int} mx, @code{int} my=@code{0}, @code{int} mz=@code{0}, @code{mreal} x1=@code{0}, @code{mreal} x2=@code{1}, @code{mreal} y1=@code{0}, @code{mreal} y2=@code{1}, @code{mreal} z1=@code{0}, @code{mreal} z2=@code{1}) @code{const}
+ at deftypefnx {Метод класса @code{mglDataC}} @code{mglData} Resize (@code{int} mx, @code{int} my=@code{0}, @code{int} mz=@code{0}, @code{mreal} x1=@code{0}, @code{mreal} x2=@code{1}, @code{mreal} y1=@code{0}, @code{mreal} y2=@code{1}, @code{mreal} z1=@code{0}, @code{mreal} z2=@code{1}) @code{const}
 @deftypefnx {Функция С} @code{HMDT} mgl_data_resize (@code{HCDT} dat, @code{int} mx, @code{int} my, @code{int} mz)
 @deftypefnx {Функция С} @code{HMDT} mgl_data_resize_box (@code{HCDT} dat, @code{int} mx, @code{int} my, @code{int} mz, @code{mreal} x1, @code{mreal} x2, @code{mreal} y1, @code{mreal} y2, @code{mreal} z1, @code{mreal} z2)
 @end ifclear
-Возвращает массив данных размером @var{mx}, @var{my}, @var{mz} со значениями полученными интерполяцией значений из части [@var{x1}, at var{x2}] x [@var{y1}, at var{y2}] x [@var{z1}, at var{z2}] исходного массива. Величины x,y,z полагаются нормированными в диапазоне [0,1].
+Возвращает массив данных размером @var{mx}, @var{my}, @var{mz} со значениями полученными интерполяцией значений из части [@var{x1}, at var{x2}] x [@var{y1}, at var{y2}] x [@var{z1}, at var{z2}] исходного массива. Величины x,y,z полагаются нормированными в диапазоне [0,1]. Если значение @var{mx}, @var{my} или @var{mz} равно 0, то исходный размер используется.  Функция возвращает NULL или пустой массив если данные не могут быть созданы при данных значениях аргументов.
 @end deftypefn
 
 @anchor{evaluate}
@@ -698,15 +734,15 @@ a_ij^new = a_i^old where j=0... at var{n1}. Соответственно, для @v
 @deftypefnx {Команда MGL} {} evaluate @sc{res} dat idat jdat [@code{norm=on}]
 @deftypefnx {Команда MGL} {} evaluate @sc{res} dat idat jdat kdat [@code{norm=on}]
 @ifclear UDAV
- at deftypefnx {Метод класса @code{mglData}} @code{mglData} Evaluate (@code{const mglData &}idat, @code{bool} norm=@code{true}) @code{const}
- at deftypefnx {Метод класса @code{mglData}} @code{mglData} Evaluate (@code{const mglData &}idat, @code{const mglData &}jdat, @code{bool} norm=@code{true}) @code{const}
- at deftypefnx {Метод класса @code{mglData}} @code{mglData} Evaluate (@code{const mglData &}idat, @code{const mglData &}jdat, @code{const mglData &}kdat, @code{bool} norm=@code{true}) @code{const}
+ at deftypefnx {Метод класса @code{mglData}} @code{mglData} Evaluate (@code{const mglDataA &}idat, @code{bool} norm=@code{true}) @code{const}
+ at deftypefnx {Метод класса @code{mglData}} @code{mglData} Evaluate (@code{const mglDataA &}idat, @code{const mglDataA &}jdat, @code{bool} norm=@code{true}) @code{const}
+ at deftypefnx {Метод класса @code{mglData}} @code{mglData} Evaluate (@code{const mglDataA &}idat, @code{const mglDataA &}jdat, @code{const mglDataA &}kdat, @code{bool} norm=@code{true}) @code{const}
 @deftypefnx {Метод класса @code{mglDataC}} @code{mglData} Evaluate (@code{const mglDataA &}idat, @code{bool} norm=@code{true}) @code{const}
 @deftypefnx {Метод класса @code{mglDataC}} @code{mglData} Evaluate (@code{const mglDataA &}idat, @code{const mglDataA &}jdat, @code{bool} norm=@code{true}) @code{const}
 @deftypefnx {Метод класса @code{mglDataC}} @code{mglData} Evaluate (@code{const mglDataA &}idat, @code{const mglDataA &}jdat, @code{const mglDataA &}kdat, @code{bool} norm=@code{true}) @code{const}
 @deftypefnx {Функция С} @code{HMDT} mgl_data_evaluate (@code{HCDT} dat, @code{HCDT} idat, @code{HCDT} jdat, @code{HCDT} kdat, @code{int} norm)
 @end ifclear
-Возвращает массив данных, полученный в результате интерполяции исходного массива в точках других массивов (например, res[i,j]=dat[idat[i,j],jdat[i,j]]). Размеры массивов @var{idat}, @var{jdat}, @var{kdat} должны совпадать. Координаты в @var{idat}, @var{jdat}, @var{kdat} полагаются нормированными в диапазон [0,1] (при @var{norm}=@code{true}) или в диапазоны [0,nx], [0,ny], [0,nz] соответственно.
+Возвращает массив данных, полученный в результате интерполяции исходного массива в точках других массивов (например, res[i,j]=dat[idat[i,j],jdat[i,j]]). Размеры массивов @var{idat}, @var{jdat}, @var{kdat} должны совпадать. Координаты в @var{idat}, @var{jdat}, @var{kdat} полагаются нормированными в диапазон [0,1] (при @var{norm}=@code{true}) или в диапазоны [0,nx], [0,ny], [0,nz] соответственно. Функция возвращает NULL или пустой массив если данные не могут быть созданы при данных значени [...]
 @end deftypefn
 
 @anchor{solve}
@@ -717,7 +753,18 @@ a_ij^new = a_i^old where j=0... at var{n1}. Соответственно, для @v
 @deftypefnx {Метод класса @code{mglData}} @code{mglData} Solve (@code{mreal} val, @code{char} dir, @code{const mglDataA &}idat, @code{bool} norm=@code{true}) @code{const}
 @deftypefnx {Функция С} @code{HMDT} mgl_data_solve (@code{HCDT} dat, @code{mreal} val, @code{char} dir, @code{HCDT} idat, @code{int} norm)
 @end ifclear
-Возвращает массив индексов (корней) вдоль выбранного направления @var{dir} в которых значения массива @var{dat} равны @var{val}. Выходной массив будет иметь размеры массива @var{dat} в направлениях поперечных @var{dir}. Если предоставлен массив @var{idat}, то его значения используются как стартовые при поиске. Это позволяет найти несколько веток с помощью последовательного вызова функции. Индексы полагаются нормированными в диапазон [0,1] (при @var{norm}=@code{true}) или в диапазоны [0,n [...]
+Возвращает массив индексов (корней) вдоль выбранного направления @var{dir} в которых значения массива @var{dat} равны @var{val}. Выходной массив будет иметь размеры массива @var{dat} в направлениях поперечных @var{dir}. Если предоставлен массив @var{idat}, то его значения используются как стартовые при поиске. Это позволяет найти несколько веток с помощью последовательного вызова функции. Индексы полагаются нормированными в диапазон [0,1] (при @var{norm}=@code{true}) или в диапазоны [0,n [...]
+ at end deftypefn
+
+ at anchor{roots}
+ at deftypefn {Команда MGL} {} roots @sc{res} 'func' ini ['var'='x']
+ at deftypefnx {Команда MGL} {} roots @sc{res} 'func' @code{ini} ['var'='x']
+ at ifclear UDAV
+ at deftypefnx {Метод класса @code{mglData}} @code{mglData} Roots (@code{const char *}func, @code{char} var) @code{const}
+ at deftypefnx {Функция С} @code{HMDT} mgl_data_roots (@code{const char *}func, @code{HCDT} ini, @code{char} var)
+ at deftypefnx {Функция С} @code{mreal} mgl_find_root_txt (@code{const char *}func, @code{mreal} ini, @code{char} var)
+ at end ifclear
+Возвращает массив корней уравнения 'func'=0 для переменной @var{var} с начальными положениями @var{ini}. Функция возвращает NULL или пустой массив если данные не могут быть созданы при данных значениях аргументов.
 @end deftypefn
 
 @anchor{hist}
@@ -725,13 +772,13 @@ a_ij^new = a_i^old where j=0... at var{n1}. Соответственно, для @v
 @deftypefnx {Команда MGL} {} hist @sc{res} dat wdat @code{num v1 v2 [nsub=0]}
 @ifclear UDAV
 @deftypefnx {Метод класса @code{mglData}} @code{mglData} Hist (@code{int} n, @code{mreal} v1=@code{0}, @code{mreal} v2=@code{1}, @code{int} nsub=@code{0}) @code{const}
- at deftypefnx {Метод класса @code{mglData}} @code{mglData} Hist (@code{const mglData &}w, @code{int} n, @code{mreal} v1=@code{0}, @code{mreal} v2=@code{1}, @code{int} nsub=@code{0}) @code{const}
+ at deftypefnx {Метод класса @code{mglData}} @code{mglData} Hist (@code{const mglDataA &}w, @code{int} n, @code{mreal} v1=@code{0}, @code{mreal} v2=@code{1}, @code{int} nsub=@code{0}) @code{const}
 @deftypefnx {Метод класса @code{mglDataC}} @code{mglData} Hist (@code{int} n, @code{mreal} v1=@code{0}, @code{mreal} v2=@code{1}, @code{int} nsub=@code{0}) @code{const}
 @deftypefnx {Метод класса @code{mglDataC}} @code{mglData} Hist (@code{const mglDataA &}w, @code{int} n, @code{mreal} v1=@code{0}, @code{mreal} v2=@code{1}, @code{int} nsub=@code{0}) @code{const}
 @deftypefnx {Функция С} @code{HMDT} mgl_data_hist (@code{HCDT} dat, @code{int} n, @code{mreal} v1, @code{mreal} v2, @code{int} nsub)
 @deftypefnx {Функция С} @code{HMDT} mgl_data_hist_w (@code{HCDT} dat, @code{HCDT} w, @code{int} n, @code{mreal} v1, @code{mreal} v2, @code{int} nsub)
 @end ifclear
-Возвращает распределение (гистограмму) из @var{n} точек от значений массива в диапазоне [@var{v1}, @var{v2}]. Массив @var{w} задает веса элементов (по умолчанию все веса равны 1). Параметр @var{nsub} задает число дополнительных точек интерполяции (для сглаживания получившейся гистограммы). См. также @ref{Data manipulation}
+Возвращает распределение (гистограмму) из @var{n} точек от значений массива в диапазоне [@var{v1}, @var{v2}]. Массив @var{w} задает веса элементов (по умолчанию все веса равны 1). Параметр @var{nsub} задает число дополнительных точек интерполяции (для сглаживания получившейся гистограммы). Функция возвращает NULL или пустой массив если данные не могут быть созданы при данных значениях аргументов. См. также @ref{Data manipulation}
 @end deftypefn
 
 @anchor{momentum}
@@ -748,7 +795,7 @@ a_ij^new = a_i^old where j=0... at var{n1}. Соответственно, для @v
 @ifnottex
 res_k = \sum_ij how(x_i,y_j,z_k) a_ij/ \sum_ij a_ij
 @end ifnottex
-если @var{dir}=@samp{z} и т.д. Координаты @samp{x}, @samp{y}, @samp{z} -- индексы массива в диапазоне [0,1].
+если @var{dir}=@samp{z} и т.д. Координаты @samp{x}, @samp{y}, @samp{z} -- индексы массива в диапазоне [0,1]. Функция возвращает NULL или пустой массив если данные не могут быть созданы при данных значениях аргументов.
 @end deftypefn
 
 @anchor{sum}
@@ -758,7 +805,7 @@ res_k = \sum_ij how(x_i,y_j,z_k) a_ij/ \sum_ij a_ij
 @deftypefnx {Метод класса @code{mglDataC}} @code{mglData} Sum (@code{const char *}dir) @code{const}
 @deftypefnx {Функция С} @code{HMDT} mgl_data_sum (@code{HCDT} dat, @code{const char *}dir)
 @end ifclear
-Возвращает результат суммирования данных вдоль направления(ий) @var{dir}.
+Возвращает результат суммирования данных вдоль направления(ий) @var{dir}. Функция возвращает NULL или пустой массив если данные не могут быть созданы при данных значениях аргументов.
 @end deftypefn
 
 @anchor{max}
@@ -768,7 +815,7 @@ res_k = \sum_ij how(x_i,y_j,z_k) a_ij/ \sum_ij a_ij
 @deftypefnx {Метод класса @code{mglDataC}} @code{mglData} Max (@code{const char *}dir) @code{const}
 @deftypefnx {Функция С} @code{HMDT} mgl_data_max_dir (@code{HCDT} dat, @code{const char *}dir)
 @end ifclear
-Возвращает максимальное значение данных вдоль направления(ий) @var{dir}.
+Возвращает максимальное значение данных вдоль направления(ий) @var{dir}. Функция возвращает NULL или пустой массив если данные не могут быть созданы при данных значениях аргументов.
 @end deftypefn
 
 @anchor{min}
@@ -778,17 +825,17 @@ res_k = \sum_ij how(x_i,y_j,z_k) a_ij/ \sum_ij a_ij
 @deftypefnx {Метод класса @code{mglDataC}} @code{mglData} Min (@code{const char *}dir) @code{const}
 @deftypefnx {Функция С} @code{HMDT} mgl_data_min_dir (@code{HCDT} dat, @code{const char *}dir)
 @end ifclear
-Возвращает минимальное значение данных вдоль направления(ий) @var{dir}.
+Возвращает минимальное значение данных вдоль направления(ий) @var{dir}. Функция возвращает NULL или пустой массив если данные не могут быть созданы при данных значениях аргументов.
 @end deftypefn
 
 @anchor{combine}
 @deftypefn {Команда MGL} {} combine @sc{res} adat bdat
 @ifclear UDAV
- at deftypefnx {Метод класса @code{mglData}} @code{mglData} Combine (@code{const mglData &}a) @code{const}
+ at deftypefnx {Метод класса @code{mglData}} @code{mglData} Combine (@code{const mglDataA &}a) @code{const}
 @deftypefnx {Метод класса @code{mglDataC}} @code{mglData} Combine (@code{const mglDataA &}a) @code{const}
 @deftypefnx {Функция С} @code{HMDT} mgl_data_combine (@code{HCDT} dat, @code{HCDT} a)
 @end ifclear
-Возвращает прямое произведение массивов (наподобие, res[i,j] = adat[i]*bdat[j] и т.д.).
+Возвращает прямое произведение массивов (наподобие, res[i,j] = adat[i]*bdat[j] и т.д.). Функция возвращает NULL или пустой массив если данные не могут быть созданы при данных значениях аргументов.
 @end deftypefn
 
 @anchor{trace}
@@ -798,7 +845,20 @@ res_k = \sum_ij how(x_i,y_j,z_k) a_ij/ \sum_ij a_ij
 @deftypefnx {Метод класса @code{mglDataC}} @code{mglData} Trace () @code{const}
 @deftypefnx {Функция С} @code{HMDT} mgl_data_trace (@code{HCDT} dat)
 @end ifclear
-Возвращает массив диагональных элементов a[i,i] (для 2D данных) или a[i,i,i] (для 3D данных) где i=0...nx-1. В 1D случае возвращается сам массив данных. Размеры массива данных должен быть ny,nz >= nx или ny,nz = 1.
+Возвращает массив диагональных элементов a[i,i] (для 2D данных) или a[i,i,i] (для 3D данных) где i=0...nx-1. В 1D случае возвращается сам массив данных. Размеры массива данных должен быть ny,nz >= nx или ny,nz = 1. Функция возвращает NULL или пустой массив если данные не могут быть созданы при данных значениях аргументов.
+ at end deftypefn
+
+ at anchor{correl}
+ at deftypefn {Команда MGL} {} correl @sc{res} adat bdat 'dir'
+ at ifclear UDAV
+ at deftypefnx {Метод класса @code{mglData}} @code{mglData} Correl (@code{const mglDataA &}b, @code{const char *}dir) @code{const}
+ at deftypefnx {Метод класса @code{mglData}} @code{mglData} AutoCorrel (@code{const char *}dir) @code{const}
+ at deftypefnx {Метод класса @code{mglDataC}} @code{mglDataC} Correl (@code{const mglDataA &}b, @code{const char *}dir) @code{const}
+ at deftypefnx {Метод класса @code{mglDataC}} @code{mglDataC} AutoCorrel (@code{const char *}dir) @code{const}
+ at deftypefnx {Функция С} @code{HMDT} mgl_data_correl (@code{HCDT} a, @code{HCDT} b, @code{const char *}dir)
+ at deftypefnx {Функция С} @code{HADT} mgl_datac_correl (@code{HCDT} a, @code{HCDT} b, @code{const char *}dir)
+ at end ifclear
+Возвращает корреляцию массивов @var{a} (или this в C++) и @var{b} вдоль направлений @var{dir}. При вычислении используется преобразование Фурье. Поэтому может потребоваться вызов функций @ref{swap} и/или @ref{norm} перед построением. Функция возвращает NULL или пустой массив если данные не могут быть созданы при данных значениях аргументов.
 @end deftypefn
 
 @ifclear UDAV
@@ -820,21 +880,11 @@ res_k = \sum_ij how(x_i,y_j,z_k) a_ij/ \sum_ij a_ij
 @end deftypefn
 @end ifclear
 
- at anchor{roots}
- at deftypefn {Команда MGL} {} roots @sc{res} 'func' ini ['var'='x']
- at deftypefnx {Команда MGL} {} roots @sc{res} 'func' @code{ini} ['var'='x']
- at ifclear UDAV
- at deftypefnx {Метод класса @code{mglData}} @code{mglData} Roots (@code{const char *}func, @code{char} var) @code{const}
- at deftypefnx {Функция С} @code{HMDT} mgl_data_roots (@code{const char *}func, @code{HCDT} ini, @code{char} var)
- at deftypefnx {Функция С} @code{mreal} mgl_find_root_txt (@code{const char *}func, @code{mreal} ini, @code{char} var)
- at end ifclear
-Возвращает массив корней уравнения 'func'=0 для переменной @var{var} с начальными положениями @var{ini}.
- at end deftypefn
-
 @c ------------------------------------------------------------------
 @external{}
 @node Data changing, Interpolation, Make another data, Data processing
 @section Изменение данных
+ at nav{}
 @cindex CumSum
 @cindex Integral
 @cindex Diff
@@ -888,8 +938,8 @@ These functions change the data in some direction like differentiations, integra
 
 @deftypefn {Команда MGL} {} diff dat xdat ydat [zdat=0]
 @ifclear UDAV
- at deftypefnx {Метод класса @code{mglData}} @code{void} Diff (@code{const mglData &}x, @code{const mglData &}y)
- at deftypefnx {Метод класса @code{mglData}} @code{void} Diff (@code{const mglData &}x, @code{const mglData &}y, @code{const mglData &}z)
+ at deftypefnx {Метод класса @code{mglData}} @code{void} Diff (@code{const mglDataA &}x, @code{const mglDataA &}y)
+ at deftypefnx {Метод класса @code{mglData}} @code{void} Diff (@code{const mglDataA &}x, @code{const mglDataA &}y, @code{const mglDataA &}z)
 @deftypefnx {Функция С} @code{void} mgl_data_diff_par (@code{HMDT} dat, @code{HCDT} x, @code{HCDT}y, @code{HCDT}z)
 @end ifclear
 Выполняет дифференцирование данных, параметрически зависящих от координат, в направлении @var{x} с @var{y}, @var{z}=constant. Параметр @var{z} может быть опущен, что соответствует 2D случаю. Используются следующие формулы (2D случай): @math{da/dx = (a_j*y_i-a_i*y_j)/(x_j*y_i-x_i*y_j)}, где @math{a_i=da/di, a_j=da/dj} обозначает дифференцирование вдоль 1-ой и 2-ой размерности. Похожие формулы используются и в 3D случае. Порядок аргументов можно менять -- например, если данные a(i,j) завис [...]
@@ -1031,6 +1081,7 @@ These functions change the data in some direction like differentiations, integra
 @external{}
 @node Interpolation, Data information, Data changing, Data processing
 @section Интерполяция
+ at nav{}
 
 Скрипты MGL могут использовать линейную интерполяцию с помощью команды @ref{subdata}, или кубические сплайны при использовании команды @ref{evaluate}. Также можно использовать @ref{resize} для массива с новыми размерами.
 
@@ -1040,16 +1091,20 @@ These functions change the data in some direction like differentiations, integra
 
 @cindex Spline
 @deftypefn {Метод класса @code{mglData}} @code{mreal} Spline (@code{mreal} x, @code{mreal} y=@code{0}, @code{mreal} z=@code{0}) @code{const}
+ at deftypefnx {Метод класса @code{mglDataC}} @code{dual} Spline (@code{mreal} x, @code{mreal} y=@code{0}, @code{mreal} z=@code{0}) @code{const}
 @deftypefnx {Функция С} @code{mreal} mgl_data_spline (@code{HCDT} dat, @code{mreal} x, @code{mreal} y, @code{mreal} z)
+ at deftypefnx {Функция С} @code{dual} mgl_datac_spline (@code{HCDT} dat, @code{mreal} x, @code{mreal} y, @code{mreal} z)
 Интерполирует данные кубическим сплайном в точке @var{x} в [0...nx-1], @var{y} в [0...ny-1], @var{z} в [0...nz-1].
 @end deftypefn
 @cindex Spline1
 @deftypefn {Метод класса @code{mglData}} @code{mreal} Spline1 (@code{mreal} x, @code{mreal} y=@code{0}, @code{mreal} z=@code{0}) @code{const}
+ at deftypefnx {Метод класса @code{mglDataC}} @code{dual} Spline1 (@code{mreal} x, @code{mreal} y=@code{0}, @code{mreal} z=@code{0}) @code{const}
 Интерполирует данные кубическим сплайном в точке @var{x}, @var{y}, @var{z}, где координаты полагаются в интервале [0, 1].
 @end deftypefn
 
 @deftypefn {Метод класса @code{mglData}} @code{mreal} Spline (@code{mglPoint} &dif, @code{mreal} x, @code{mreal} y=@code{0}, @code{mreal} z=@code{0}) @code{const}
 @deftypefnx {Функция С} @code{mreal} mgl_data_spline_ext (@code{HCDT} dat, @code{mreal} x, @code{mreal} y, @code{mreal} z, @code{mreal *}dx, @code{mreal *}dy, @code{mreal *}dz)
+ at deftypefnx {Функция С} @code{dual} mgl_datac_spline_ext (@code{HCDT} dat, @code{mreal} x, @code{mreal} y, @code{mreal} z, @code{dual *}dx, @code{dual *}dy, @code{dual *}dz)
 Интерполирует данные кубическим сплайном в точке @var{x} в [0...nx-1], @var{y} в [0...ny-1], @var{z} в [0...nz-1]. Значения производных в точке записываются в @var{dif}.
 @end deftypefn
 @cindex Spline1
@@ -1089,6 +1144,7 @@ These functions change the data in some direction like differentiations, integra
 @external{}
 @node Data information, Operators, Interpolation, Data processing
 @section Информационные функции
+ at nav{}
 
 В MathGL есть ряд функций для получения свойств массива данных. В MGL скриптах большинство из них реализовано в виде "суффиксов". Суффиксы дают числовое значение некоторой характеристики массива данных. Например, его размер, минимальное и максимальное значение, сумму элементов и т.д. Суффиксы начинаются с точки @samp{.} сразу после массива (без пробелов). Например, @code{a.nx} даст размер массива @var{a} вдоль x, @code{b(1).max} даст максимальное значение второй колонки массива @var{b},  [...]
 
@@ -1262,10 +1318,11 @@ These functions change the data in some direction like differentiations, integra
 @external{}
 @node Operators, Global functions, Data information, Data processing
 @section Операторы
+ at nav{}
 
 @deftypefn {Команда MGL} {} copy @sc{dat} dat2 ['eq'='']
 @ifclear UDAV
- at deftypefnx {Метод класса @code{mglData}} @code{void} operator= (@code{const mglData &}d)
+ at deftypefnx {Метод класса @code{mglData}} @code{void} operator= (@code{const mglDataA &}d)
 @end ifclear
 Копирует данные из другого экземпляра.
 @end deftypefn
@@ -1281,7 +1338,7 @@ These functions change the data in some direction like differentiations, integra
 @deftypefn {Команда MGL} {} multo dat dat2
 @deftypefnx {Команда MGL} {} multo dat @code{val}
 @ifclear UDAV
- at deftypefnx {Метод класса @code{mglData}} @code{void} operator*= (@code{const mglData &}d)
+ at deftypefnx {Метод класса @code{mglData}} @code{void} operator*= (@code{const mglDataA &}d)
 @deftypefnx {Метод класса @code{mglData}} @code{void} operator*= (@code{mreal} d)
 @deftypefnx {Функция С} @code{void} mgl_data_mul_dat (@code{HMDT} dat, @code{HCDT} d)
 @deftypefnx {Функция С} @code{void} mgl_data_mul_num (@code{HMDT} dat, @code{mreal} d)
@@ -1293,7 +1350,7 @@ These functions change the data in some direction like differentiations, integra
 @deftypefn {Команда MGL} {} divto dat dat2
 @deftypefnx {Команда MGL} {} divto dat @code{val}
 @ifclear UDAV
- at deftypefnx {Метод класса @code{mglData}} @code{void} operator/= (@code{const mglData &}d)
+ at deftypefnx {Метод класса @code{mglData}} @code{void} operator/= (@code{const mglDataA &}d)
 @deftypefnx {Метод класса @code{mglData}} @code{void} operator/= (@code{mreal} d)
 @deftypefnx {Функция С} @code{void} mgl_data_div_dat (@code{HMDT} dat, @code{HCDT} d)
 @deftypefnx {Функция С} @code{void} mgl_data_div_num (@code{HMDT} dat, @code{mreal} d)
@@ -1305,7 +1362,7 @@ These functions change the data in some direction like differentiations, integra
 @deftypefn {Команда MGL} {} addto dat dat2
 @deftypefnx {Команда MGL} {} addto dat @code{val}
 @ifclear UDAV
- at deftypefnx {Метод класса @code{mglData}} @code{void} operator+= (@code{const mglData &}d)
+ at deftypefnx {Метод класса @code{mglData}} @code{void} operator+= (@code{const mglDataA &}d)
 @deftypefnx {Метод класса @code{mglData}} @code{void} operator+= (@code{mreal} d)
 @deftypefnx {Функция С} @code{void} mgl_data_add_dat (@code{HMDT} dat, @code{HCDT} d)
 @deftypefnx {Функция С} @code{void} mgl_data_add_num (@code{HMDT} dat, @code{mreal} d)
@@ -1317,7 +1374,7 @@ These functions change the data in some direction like differentiations, integra
 @deftypefn {Команда MGL} {} subto dat dat2
 @deftypefnx {Команда MGL} {} subto dat @code{val}
 @ifclear UDAV
- at deftypefnx {Метод класса @code{mglData}} @code{void} operator-= (@code{const mglData &}d)
+ at deftypefnx {Метод класса @code{mglData}} @code{void} operator-= (@code{const mglDataA &}d)
 @deftypefnx {Метод класса @code{mglData}} @code{void} operator-= (@code{mreal} d)
 @deftypefnx {Функция С} @code{void} mgl_data_sub_dat (@code{HMDT} dat, @code{HCDT} d)
 @deftypefnx {Функция С} @code{void} mgl_data_sub_num (@code{HMDT} dat, @code{mreal} d)
@@ -1326,26 +1383,26 @@ These functions change the data in some direction like differentiations, integra
 @end deftypefn
 
 @ifclear UDAV
- at deftypefn {Library Function} mglData operator+ (@code{const mglData &}a, @code{const mglData &}b)
- at deftypefnx {Library Function} mglData operator+ (@code{mreal} a, @code{const mglData &}b)
- at deftypefnx {Library Function} mglData operator+ (@code{const mglData &}a, @code{mreal} b)
+ at deftypefn {Library Function} mglData operator+ (@code{const mglDataA &}a, @code{const mglDataA &}b)
+ at deftypefnx {Library Function} mglData operator+ (@code{mreal} a, @code{const mglDataA &}b)
+ at deftypefnx {Library Function} mglData operator+ (@code{const mglDataA &}a, @code{mreal} b)
 Возвращает поэлементную сумму данных.
 @end deftypefn
 
- at deftypefn {Library Function} mglData operator- (@code{const mglData &}a, @code{const mglData &}b)
- at deftypefnx {Library Function} mglData operator- (@code{mreal} a, @code{const mglData &}b)
- at deftypefnx {Library Function} mglData operator- (@code{const mglData &}a, @code{mreal} b)
+ at deftypefn {Library Function} mglData operator- (@code{const mglDataA &}a, @code{const mglDataA &}b)
+ at deftypefnx {Library Function} mglData operator- (@code{mreal} a, @code{const mglDataA &}b)
+ at deftypefnx {Library Function} mglData operator- (@code{const mglDataA &}a, @code{mreal} b)
 Возвращает поэлементную разность данных.
 @end deftypefn
 
- at deftypefn {Library Function} mglData operator* (@code{const mglData &}a, @code{const mglData &}b)
- at deftypefnx {Library Function} mglData operator* (@code{mreal} a, @code{const mglData &}b)
- at deftypefnx {Library Function} mglData operator* (@code{const mglData &}a, @code{mreal} b)
+ at deftypefn {Library Function} mglData operator* (@code{const mglDataA &}a, @code{const mglDataA &}b)
+ at deftypefnx {Library Function} mglData operator* (@code{mreal} a, @code{const mglDataA &}b)
+ at deftypefnx {Library Function} mglData operator* (@code{const mglDataA &}a, @code{mreal} b)
 Возвращает поэлементное произведение данных.
 @end deftypefn
 
- at deftypefn {Library Function} mglData operator/ (@code{const mglData &}a, @code{const mglData &}b)
- at deftypefnx {Library Function} mglData operator/ (@code{const mglData &}a, @code{mreal} b)
+ at deftypefn {Library Function} mglData operator/ (@code{const mglDataA &}a, @code{const mglDataA &}b)
+ at deftypefnx {Library Function} mglData operator/ (@code{const mglDataA &}a, @code{mreal} b)
 Возвращает поэлементное деление данных.
 @end deftypefn
 @end ifclear
@@ -1354,6 +1411,7 @@ These functions change the data in some direction like differentiations, integra
 @external{}
 @node Global functions, Evaluate expression, Operators, Data processing
 @section Глобальные функции
+ at nav{}
 
 @ifclear UDAV
 Эти функции не методы класса @code{mglData}, но они дают дополнительные возможности по обработке данных. Поэтому я поместил их в эту главу.
@@ -1362,7 +1420,7 @@ These functions change the data in some direction like differentiations, integra
 @anchor{transform}
 @deftypefn {Команда MGL} {} transform @sc{dat} 'type' real imag
 @ifclear UDAV
- at deftypefnx {Global function} @code{mglData} mglTransform (@code{const mglData &}real, @code{const mglData &}imag, @code{const char *}type)
+ at deftypefnx {Global function} @code{mglData} mglTransform (@code{const mglDataA &}real, @code{const mglDataA &}imag, @code{const char *}type)
 @deftypefnx {Функция С} @code{HMDT} mgl_transform (@code{HCDT} real, @code{HCDT} imag, @code{const char *}type)
 @end ifclear
 Выполняет интегральное преобразование комплексных данных @var{real}, @var{imag} в выбранном направлении и возвращает модуль результата. Порядок и тип преобразований задается строкой @var{type}: первый символ для x-направления, второй для y-направления, третий для z-направления. Возможные символы: @samp{f} -- прямое преобразование Фурье, @samp{i} -- обратное преобразование Фурье, @samp{s} -- синус преобразование, @samp{c} -- косинус преобразование, @samp{h} -- преобразование Ханкеля, @sam [...]
@@ -1371,7 +1429,7 @@ These functions change the data in some direction like differentiations, integra
 @anchor{transforma}
 @deftypefn {Команда MGL} {} transforma @sc{dat} 'type' ampl phase
 @ifclear UDAV
- at deftypefnx {Global function} @code{mglData} mglTransformA @code{const mglData &}ampl, @code{const mglData &}phase, @code{const char *}type)
+ at deftypefnx {Global function} @code{mglData} mglTransformA @code{const mglDataA &}ampl, @code{const mglDataA &}phase, @code{const char *}type)
 @deftypefnx {Функция С} @code{HMDT} mgl_transform_a @code{HCDT} ampl, @code{HCDT} phase, @code{const char *}type)
 @end ifclear
 Аналогично предыдущему с заданными амплитудой @var{ampl} и фазой @var{phase} комплексных чисел.
@@ -1380,7 +1438,7 @@ These functions change the data in some direction like differentiations, integra
 @anchor{fourier}
 @deftypefn {Команда MGL} {} fourier reDat imDat 'dir'
 @ifclear UDAV
- at deftypefnx {Global function} @code{void} mglFourier @code{const mglData &}re, @code{const mglData &}im, @code{const char *}dir)
+ at deftypefnx {Global function} @code{void} mglFourier @code{const mglDataA &}re, @code{const mglDataA &}im, @code{const char *}dir)
 @deftypefnx {Функция С} @code{void} mgl_data_fourier @code{HCDT} re, @code{HCDT} im, @code{const char *}dir)
 @end ifclear
 Выполняет Фурье преобразование для комплексных данных @var{re}+i*@var{im} в направлениях @var{dir}. Результат помещается обратно в массивы @var{re} и @var{im}.
@@ -1389,7 +1447,7 @@ These functions change the data in some direction like differentiations, integra
 @anchor{stfad}
 @deftypefn {Команда MGL} {} stfad @sc{res} real imag @code{dn} ['dir'='x']
 @ifclear UDAV
- at deftypefnx {Global function} @code{mglData} mglSTFA (@code{const mglData &}real, @code{const mglData &}imag, @code{int} dn, @code{char} dir=@code{'x'})
+ at deftypefnx {Global function} @code{mglData} mglSTFA (@code{const mglDataA &}real, @code{const mglDataA &}imag, @code{int} dn, @code{char} dir=@code{'x'})
 @deftypefnx {Функция С} @code{HMDT} mgl_data_stfa (@code{HCDT} real, @code{HCDT} imag, @code{int} dn, at code{char} dir)
 @end ifclear
 Выполняет оконное преобразование Фурье длиной @var{dn} для комплексных данных @var{real}, @var{imag} и возвращает модуль результата. Например, для @var{dir}=@samp{x} результат будет иметь размер @{int(nx/dn), dn, ny@} и будет равен @math{res[i,j,k]=|\sum_d^dn exp(I*j*d)*(real[i*dn+d,k]+I*imag[i*dn+d,k])|/dn}.
@@ -1398,7 +1456,7 @@ These functions change the data in some direction like differentiations, integra
 @anchor{pde}
 @deftypefn {Команда MGL} {} pde @sc{res} 'ham' ini_re ini_im [@code{dz=0.1 k0=100}]
 @ifclear UDAV
- at deftypefnx {Global function} @code{mglData} mglPDE (@code{HMGL} gr, @code{const char *}ham, @code{const mglData &}ini_re, @code{const mglData &}ini_im, @code{mreal} dz=@code{0.1}, @code{mreal} k0=@code{100}, @code{const char *}opt=@code{""})
+ at deftypefnx {Global function} @code{mglData} mglPDE (@code{HMGL} gr, @code{const char *}ham, @code{const mglDataA &}ini_re, @code{const mglDataA &}ini_im, @code{mreal} dz=@code{0.1}, @code{mreal} k0=@code{100}, @code{const char *}opt=@code{""})
 @deftypefnx {Функция С} @code{HMDT} mgl_pde_solve (@code{HMGL} gr, @code{const char *}ham, @code{HCDT} ini_re, @code{HCDT} ini_im, @code{mreal} dz, @code{mreal} k0, @code{const char *}opt)
 @end ifclear
 Решает уравнение в частных производных du/dz = i*k0*@var{ham}(p,q,x,y,z,|u|)[u], где p=-i/k0*d/dx, q=-i/k0*d/dy -- псевдо-дифференциальные операторы. Параметры @var{ini_re}, @var{ini_im} задают начальное распределение поля. Координаты в уравнении и в решении полагаются в диапазоне осей координат. Замечу, что внутри этот диапазон увеличивается в 3/2 раза для уменьшения отражения от границ расчетного интервала. Параметр @var{dz} задает шаг по эволюционной координате z. В данный момент испо [...]
@@ -1416,8 +1474,8 @@ These functions change the data in some direction like differentiations, integra
 @anchor{qo2d}
 @deftypefn {Команда MGL} {} qo2d @sc{res} 'ham' ini_re ini_im ray [@code{r=1 k0=100} xx yy]
 @ifclear UDAV
- at deftypefnx {Global function} @code{mglData} mglQO2d (@code{const char *}ham, @code{const mglData &}ini_re, @code{const mglData &}ini_im, @code{const mglData &}ray, @code{mreal} r=@code{1}, @code{mreal} k0=@code{100}, @code{mglData *}xx=@code{0}, @code{mglData *}yy=@code{0})
- at deftypefnx {Global function} @code{mglData} mglQO2d (@code{const char *}ham, @code{const mglData &}ini_re, @code{const mglData &}ini_im, @code{const mglData &}ray, @code{mglData &}xx, @code{mglData &}yy, @code{mreal} r=@code{1}, @code{mreal} k0=@code{100})
+ at deftypefnx {Global function} @code{mglData} mglQO2d (@code{const char *}ham, @code{const mglDataA &}ini_re, @code{const mglDataA &}ini_im, @code{const mglDataA &}ray, @code{mreal} r=@code{1}, @code{mreal} k0=@code{100}, @code{mglData *}xx=@code{0}, @code{mglData *}yy=@code{0})
+ at deftypefnx {Global function} @code{mglData} mglQO2d (@code{const char *}ham, @code{const mglDataA &}ini_re, @code{const mglDataA &}ini_im, @code{const mglDataA &}ray, @code{mglData &}xx, @code{mglData &}yy, @code{mreal} r=@code{1}, @code{mreal} k0=@code{100})
 @deftypefnx {Функция С} @code{HMDT} mgl_qo2d_solve (@code{const char *}ham, @code{HCDT} ini_re, @code{HCDT} ini_im, @code{HCDT} ray, @code{mreal} r, @code{mreal} k0, @code{HMDT} xx, @code{HMDT} yy)
 @end ifclear
 Решает уравнение в частных производных du/dt = i*k0*@var{ham}(p,q,x,y,|u|)[u] в сопровождающей системе координат, где p=-i/k0*d/dx, q=-i/k0*d/dy -- псевдо-дифференциальные операторы. Параметры @var{ini_re}, @var{ini_im} задают начальное распределение поля. Параметр @var{ray} задает опорный луч для сопровождающей системы координат. Можно использовать луч найденный с помощью @code{mglRay()}. Опорный луч должен быть достаточно гладкий, чтобы система координат была однозначной и для исключен [...]
@@ -1426,8 +1484,8 @@ These functions change the data in some direction like differentiations, integra
 @anchor{jacobian}
 @deftypefn {Команда MGL} {} jacobian @sc{res} xdat ydat [zdat]
 @ifclear UDAV
- at deftypefnx {Global function} @code{mglData} mglJacobian (@code{const mglData &}x, @code{const mglData &}y)
- at deftypefnx {Global function} @code{mglData} mglJacobian (@code{const mglData &}x, @code{const mglData &}y, @code{const mglData &}z)
+ at deftypefnx {Global function} @code{mglData} mglJacobian (@code{const mglDataA &}x, @code{const mglDataA &}y)
+ at deftypefnx {Global function} @code{mglData} mglJacobian (@code{const mglDataA &}x, @code{const mglDataA &}y, @code{const mglDataA &}z)
 @deftypefnx {Функция С} @code{HMDT} mgl_jacobian_2d (@code{HCDT} x, @code{HCDT} y)
 @deftypefnx {Функция С} @code{HMDT} mgl_jacobian_3d (@code{HCDT} x, @code{HCDT} y, @code{HCDT} z)
 @end ifclear
@@ -1438,12 +1496,12 @@ These functions change the data in some direction like differentiations, integra
 @deftypefn {Команда MGL} {} triangulation @sc{res} xdat ydat [zdat]
 @c @deftypefn {Команда MGL} {} triangulation @sc{res} xdat ydat [zdat]
 @ifclear UDAV
- at deftypefnx {Global function} @code{mglData} mglTriangulation (@code{const mglData &}x, @code{const mglData &}y)
- at deftypefnx {Global function} @code{mglData} mglTriangulation (@code{const mglData &}x, @code{const mglData &}y, @code{const mglData &}z)
+ at deftypefnx {Global function} @code{mglData} mglTriangulation (@code{const mglDataA &}x, @code{const mglDataA &}y)
+ at deftypefnx {Global function} @code{mglData} mglTriangulation (@code{const mglDataA &}x, @code{const mglDataA &}y, @code{const mglDataA &}z)
 @deftypefnx {Функция С} @code{HMDT} mgl_triangulation_2d (@code{HCDT} x, @code{HCDT} y)
 @deftypefnx {Функция С} @code{HMDT} mgl_triangulation_3d (@code{HCDT} x, @code{HCDT} y, @code{HCDT} z)
 @end ifclear
-Выполняет триангуляцию для произвольно расположенных точек с координатами @{@var{x}, at var{y}, at var{z}@} (т.е. находит треугольники, соединяющие точки). Первая размерность всех массивов должна быть одинакова @code{x.nx=y.nx=z.nx}. Получившийся массив можно использовать в @ref{triplot} или @ref{tricont} для визуализации реконструированной поверхности.
+Выполняет триангуляцию для произвольно расположенных точек с координатами @{@var{x}, at var{y}, at var{z}@} (т.е. находит треугольники, соединяющие точки). Первая размерность всех массивов должна быть одинакова @code{x.nx=y.nx=z.nx}. Получившийся массив можно использовать в @ref{triplot} или @ref{tricont} для визуализации реконструированной поверхности. @sref{Making regular data}
 @end deftypefn
 
 
@@ -1451,6 +1509,7 @@ These functions change the data in some direction like differentiations, integra
 @external{}
 @node Evaluate expression, MGL variables, Global functions, Data processing
 @section Вычисление выражений
+ at nav{}
 
 @ifset UDAV
 В MGL скриптах в качестве аргументов команд можно использовать произвольные формулы от существующих массивов данных и констант. Есть только 2 ограничения: формула не должна содержать пробелов (чтобы распознаваться как один аргумент), формула не может быть аргументом, который может быть пересоздан при выполнении скрипта.
@@ -1503,50 +1562,50 @@ These functions change the data in some direction like differentiations, integra
 @c ------------------------------------------------------------------
 @external{}
 @node MGL variables, , Evaluate expression, Data processing
- at section MGL variables
+ at section Переменные MGL
+ at nav{}
 
 @ifset UDAV
-For information about MGL variables see @ref{MGL definition}.
+Для информации о переменных MGL см. @ref{MGL definition}.
 @end ifset
 
 @ifclear UDAV
 
-Class mglVar represent MGL variables. It is needed for parsing MGL scripts (see @ref{mglParse class}). This class is derived from @code{mglData} and is defined in @code{#include <mgl2/mgl.h>}.
+Класс mglVar содержит переменную/массив скрипта MGL и используется при разборе MGL скриптов (см. @ref{mglParse class}). Это класс наследник @code{mglData} и определен в @code{#include <mgl2/mgl.h>}.
 
 @deftypecv {Variable} mglVar @code{std::wstring} s
-Name of variable.
+Имя переменной в скрипте.
 @end deftypecv
 
 @deftypecv {Variable} mglVar @code{mglVar *} next
 @deftypecvx {Variable} mglVar @code{mglVar *} prev
-Next and previous variable in the list.
+Следующая и предыдущая переменная в списке.
 @end deftypecv
 
 @deftypecv {Variable} mglVar @code{bool} temp
-Flag of the temporary variable. If @code{true} the this variable will be removed after script execution.
+Флаг временной переменной. Если @code{true}, то переменная будет удалена после выполнения скрипта.
 @end deftypecv
 
 @deftypecv {Variable} mglVar @code{void (*}func at code{)(void *)}
-Callback function, which will be called at variable destroying.
+Callback функция, вызываемая при удалении переменной.
 @end deftypecv
 
 @deftypecv {Variable} mglVar @code{void *} o
-Pointer to external object for callback function.
+Указатель на внешний объект, передаваемый callback функции.
 @end deftypecv
 
 @deftypefn {Constructor on @code{mglVar}} @code{} mglVar ()
-Create variable with size 1*1*1.
+Создает переменную с размерами 1*1*1.
 @end deftypefn
 
 @deftypefn {Destructor on @code{mglVar}} @code{} ~mglVar ()
-Deletes the instance of class mglVar.
+Удаляет переменную mglVar.
 @end deftypefn
 
- at deftypefn {Method on @code{mglVar}} @code{void} MoveAfter (@code{mglVar *}var)
-Evaluates the formula for @code{'x','r'}=@var{x}, @code{'y','n'}=@var{y}, @code{'z','t'}=@var{z}, @code{'a','u'}=@var{u}.
+ at deftypefn {Метод класса @code{mglVar}} @code{void} MoveAfter (@code{mglVar *}var)
+Перемещает переменную после @var{var} в списке переменных.
 @end deftypefn
 
 @end ifclear
 
 @external{}
-
diff --git a/texinfo/doc_en.texi b/texinfo/doc_en.texi
index 4875277..50e5415 100644
--- a/texinfo/doc_en.texi
+++ b/texinfo/doc_en.texi
@@ -1,6 +1,9 @@
 \input texinfo
+ at documentencoding UTF-8
+ at documentlanguage en
+
 @setfilename mathgl_en.info
- at set VERSION 2.1.3
+ at include version.texi
 @settitle MathGL @value{VERSION}
 @syncodeindex pg cp
 @comment %**end of header
@@ -27,7 +30,6 @@ This manual is for MathGL (version @value{VERSION}), a collection of classes and
 
 @contents
 
- at ifnottex
 @node Top
 @top MathGL
 
@@ -35,8 +37,6 @@ This file documents the Mathematical Graphic Library (MathGL), a collection of c
 
 @include copyright.texi
 
- at end ifnottex
-
 @menu
 * Website::
 * Overview::
@@ -51,26 +51,56 @@ This file documents the Mathematical Graphic Library (MathGL), a collection of c
 * Symbols and hot-keys::
 * File formats::
 * TeX-like symbols::
+* Plotting time::
 * Copying This Manual::
 * Index::
 @end menu
 
- at ifhtml
+ at macro nav {}
+ at html
+<nav style="float:right;border:1px solid black;padding:3px;margin-left:7px">
+ at end html
+@ @ @ref{Main, Main page}@*
+@ @ @ref{News}@*
+@ @ @ref{Pictures}@*
+@ @ @ref{Download}@*
+ at comment @ @ @ref{Download}
+
+ at html
+<table style="background-color: #fff; padding: 5px;" cellspacing=0>
+<tr><td><img src="http://groups.google.com/intl/en/images/logos/groups_logo_sm.gif" height=25 width=117 alt="Google Groups"></td></tr>
+<tr><td style="padding-left: 5px;font-size: 110%"> <a target=_blank href="http://groups.google.com/group/mathgl"><b>MathGL</b></a> </td></tr>
+</table>
+
+<hr style="width: 100%; height: 1px;">
+<script type="text/javascript"><!--
+google_ad_client = "ca-pub-1128070552722622";
+/* Vertical small */
+google_ad_slot = "5501954624";
+google_ad_width = 120;
+google_ad_height = 240;
+//-->
+</script>
+<script type="text/javascript"
+src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
+</script></nav>
+ at end html
+ at end macro
+
 @macro external {}
- at comment  @html
- at comment  <script type="text/javascript"><!--
- at comment  google_ad_client = "ca-pub-1128070552722622";
- at comment  /* 728x90, создано 23.12.09 */
- at comment  google_ad_slot = "9958083480";
- at comment  google_ad_width = 728;
- at comment  google_ad_height = 90;
- at comment  //-->
- at comment  </script>
- at comment  <script type="text/javascript"
- at comment  src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
- at comment  </script>
- at comment  <br/>
 @html
+<script type="text/javascript"><!--
+google_ad_client = "ca-pub-1128070552722622";
+/* 728x90, создано 23.12.09 */
+google_ad_slot = "9958083480";
+google_ad_width = 728;
+google_ad_height = 90;
+//-->
+</script>
+<script type="text/javascript"
+src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
+</script><br/>
+<footer>
 <!--LiveInternet counter--><script type="text/javascript"><!--
 document.write("<a href='http://www.liveinternet.ru/click' "+
 "target=_blank><img src='http://counter.yadro.ru/hit?t12.2;r"+
@@ -87,55 +117,23 @@ screen.colorDepth:screen.pixelDepth))+";u"+escape(document.URL)+
 <a target=_blank href="http://www.thefreecountry.com/"> <img src="http://www.thefreecountry.com/images/tfc88x31green.gif" alt="thefreecountry.com: Free Programmers' Resources, Free Webmasters' Resources, Free Security Resources, Free Software" border="0" height="31" width="88"></a>
 
 <a target=_blank href="http://sourceforge.net/donate/index.php?group_id=152187"><img src="http://images.sourceforge.net/images/project-support.jpg" width="88" height="32" border="0" alt="Support This Project" /> </a>
+</footer>
 @end html
 @end macro
 
 @macro fig {fname,text}
- at center @image{../\fname\, 11cm, , \text\, .png}
+ at center @image{../\fname\, 11cm, , \text\, png}
 @end macro
 @macro pfig {fname,text}
- at center @uref{../pdf/\fname\.pdf, @image{../png/\fname\, 11cm, , \text\, .png}}
+ at center @uref{../pdf/\fname\.pdf, @image{../png/\fname\, 11cm, , \text\, png}}
 @c @center @image{../png/\fname\, 11cm, , \text\. See also @uref{../pdf/\fname\.pdf, 3D PDF} sample, .png}
 @end macro
 @macro ufig {fname,width,text}
- at center @image{../udav/\fname\, \width\cm, , \text\, .png}
+ at center @image{../udav/\fname\, \width\cm, , \text\, png}
 @end macro
 @macro sfig {plot,text}
- at ref{\text\, @image{../small/\plot\-sm,3cm, , , .png}}
+ at ref{\text\, @image{../small/\plot\-sm,3cm, , , png}}
 @end macro
- at end ifhtml
-
- at ifnothtml
- at macro external {}
- at end macro
- at macro sfig {plot,text}
- at ref{\text\, @image{small/\plot\-sm,3cm, , , .png}}
- at end macro
-
- at iftex
- at macro fig {fname,text}
- at center @image{\fname\, 11cm, , \text\, .png}
- at end macro
- at macro pfig {fname,text}
- at center @image{png/\fname\, 11cm, , \text\, .png}
- at end macro
- at macro ufig {fname,width,text}
- at center @image{udav/\fname\, \width\cm, , \text\, .png}
- at end macro
- at end iftex
-
- at ifnottex
- at macro fig {fname,text}
- at c @center @image{\fname\, 11cm, , \text\, .png}
- at end macro
- at macro pfig {fname,text}
- at c @center @image{png/\fname\, 11cm, , \text\, .png}
- at end macro
- at macro ufig {fname,width,text}
- at c @center @image{../udav/\fname\, 11cm, , \text\, .png}
- at end macro
- at end ifnottex
- at end ifnothtml
 
 
 @macro sref {arg}
@@ -180,11 +178,25 @@ screen.colorDepth:screen.pixelDepth))+";u"+escape(document.URL)+
 @appendix File formats
 @include formats_en.texi
 
- at node TeX-like symbols, Copying This Manual, File formats, Top
+ at node TeX-like symbols, Plotting time, File formats, Top
 @appendix TeX-like symbols
 @include appendix_en.texi
 
- at node Copying This Manual, Index, TeX-like symbols, Top
+ at node Plotting time, Copying This Manual, TeX-like symbols, Top
+ at appendix Plotting time
+ at nav{}
+
+Table below show plotting time in seconds for all samples in file @uref{http://sourceforge.net/p/mathgl/code/HEAD/tree/mathgl-2x/examples/samples.cpp, examples/samples.cpp}. The test was done in my laptop (i5-2430M) with 64-bit Debian.
+
+Few words about the speed. Firstly, direct bitmap drawing (Quality=4,5,6) is faster than buffered one (Quality=0,1,2), but sometimes it give incorrect result (see @ref{cloud}) and don't allow to export in vector or 3d formats (like EPS, SVG, PDF ...). Secondly, lower quality is faster than high one generally, i.e. Quality=1 is faster than Quality=2, and Quality=0 is faster than Quality=1. However, if plot contain a lot of faces (like @ref{cloud}, @ref{surf3}, @ref{pipe}, @ref{dew}) then  [...]
+
+Results for image size 800*600 (default one).
+ at include time.texi
+
+Results for image size 1920*1440 (print quality)
+ at include time_big.texi
+
+ at node Copying This Manual, Index, Plotting time, Top
 @appendix GNU Free Documentation License
 @include fdl.texi
 
diff --git a/texinfo/doc_ru.texi b/texinfo/doc_ru.texi
index b72936b..cf7f52a 100644
--- a/texinfo/doc_ru.texi
+++ b/texinfo/doc_ru.texi
@@ -1,6 +1,9 @@
 \input texinfo
+ at documentencoding UTF-8
+ at documentlanguage ru
+
 @setfilename mathgl_en.info
- at set VERSION 2.1.3
+ at include version.texi
 @settitle MathGL @value{VERSION}
 @syncodeindex pg cp
 @comment %**end of header
@@ -51,26 +54,55 @@ This file documents the Mathematical Graphic Library (MathGL), a collection of c
 * Symbols and hot-keys::
 * File formats::
 * TeX-like symbols::
+* Plotting time::
 * Copying This Manual::
 * Index::
 @end menu
 
- at ifhtml
+ at macro nav {}
+ at html
+<nav style="float:right;border:1px solid black;padding:3px;margin-left:7px">
+ at end html
+@ @ @ref{Main, Main page}@*
+@ @ @ref{News}@*
+@ @ @ref{Pictures}@*
+@ @ @ref{Download}@*
+ at comment @ @ @ref{Download}
+
+ at html
+<table style="background-color: #fff; padding: 5px;" cellspacing=0>
+<tr><td><img src="http://groups.google.com/intl/en/images/logos/groups_logo_sm.gif" height=25 width=117 alt="Google Groups"></td></tr>
+<tr><td style="padding-left: 5px;font-size: 110%"> <a target=_blank href="http://groups.google.com/group/mathgl"><b>MathGL</b></a> </td></tr>
+</table>
+
+<hr style="width: 100%; height: 1px;">
+<script type="text/javascript"><!--
+google_ad_client = "ca-pub-1128070552722622";
+/* Vertical small */
+google_ad_slot = "5501954624";
+google_ad_width = 120;
+google_ad_height = 240;
+//-->
+</script>
+<script type="text/javascript"
+src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
+</script></nav>
+ at end html
+ at end macro
+
 @macro external {}
- at comment  @html
- at comment  <script type="text/javascript"><!--
- at comment  google_ad_client = "ca-pub-1128070552722622";
- at comment  /* 728x90, создано 23.12.09 */
- at comment  google_ad_slot = "9958083480";
- at comment  google_ad_width = 728;
- at comment  google_ad_height = 90;
- at comment  //-->
- at comment  </script>
- at comment  <script type="text/javascript"
- at comment  src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
- at comment  </script>
- at comment  <br/>
 @html
+<script type="text/javascript"><!--
+google_ad_client = "ca-pub-1128070552722622";
+/* 728x90, создано 23.12.09 */
+google_ad_slot = "9958083480";
+google_ad_width = 728;
+google_ad_height = 90;
+//-->
+</script>
+<script type="text/javascript"
+src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
+</script><br/>
 <!--LiveInternet counter--><script type="text/javascript"><!--
 document.write("<a href='http://www.liveinternet.ru/click' "+
 "target=_blank><img src='http://counter.yadro.ru/hit?t12.2;r"+
@@ -91,53 +123,19 @@ screen.colorDepth:screen.pixelDepth))+";u"+escape(document.URL)+
 @end macro
 
 @macro fig {fname,text}
- at center @image{../\fname\, 11cm, , \text\, .png}
+ at center @image{../\fname\, 11cm, , \text\, png}
 @end macro
 @macro pfig {fname,text}
- at uref{../pdf/\fname\.pdf, @image{../png/\fname\, 11cm, , \text\, .png}}
+ at uref{../pdf/\fname\.pdf, @image{../png/\fname\, 11cm, , \text\, png}}
 @c @center @image{../png/\fname\, 11cm, , \text\ См. также пример @uref{../pdf/\fname\.pdf, 3D PDF}, .png}
 @end macro
 @macro ufig {fname,width,text}
- at center @image{../udav/\fname\, \width\cm, , \text\, .png}
- at end macro
- at macro sfig {plot,text}
- at ref{\text\, @image{../small/\plot\-sm,3cm, , , .png}}
- at end macro
- at end ifhtml
-
- at ifnothtml
- at macro external {}
+ at center @image{../udav/\fname\, \width\cm, , \text\, png}
 @end macro
 @macro sfig {plot,text}
- at ref{\text\, @image{../small/\plot\-sm,3cm, , , .png}}
+ at ref{\text\, @image{../small/\plot\-sm,3cm, , , png}}
 @end macro
 
- at iftex
- at macro fig {fname,text}
- at center @image{\fname\, 11cm, , \text\, .png}
- at end macro
- at macro pfig {fname,text}
- at center @image{png/\fname\, 11cm, , \text\, .png}
- at end macro
- at macro ufig {fname,width,text}
- at center @image{udav/\fname\, \width\cm, , \text\, .png}
- at end macro
- at end iftex
-
- at ifnottex
- at macro fig {fname,text}
- at c @center @image{\fname\, 11cm, , \text\, .png}
- at end macro
- at macro pfig {fname,text}
- at c @center @image{png/\fname\, 11cm, , \text\, .png}
- at end macro
- at macro ufig {fname,width,text}
- at c @center @image{../udav/\fname\, 11cm, , \text\, .png}
- at end macro
- at end ifnottex
- at end ifnothtml
-
-
 @macro sref {arg}
 См. раздел @ref{\arg\}, для примеров кода и графика.
 @end macro
@@ -180,11 +178,25 @@ screen.colorDepth:screen.pixelDepth))+";u"+escape(document.URL)+
 @appendix File formats
 @include formats_ru.texi
 
- at node TeX-like symbols, Copying This Manual, File formats, Top
- at appendix TeX-like symbols
+ at node TeX-like symbols, Plotting time, File formats, Top
+ at appendix Символы TeX
 @include appendix_ru.texi
 
- at node Copying This Manual, Index, TeX-like symbols, Top
+ at node Plotting time, Copying This Manual, TeX-like symbols, Top
+ at appendix Время отрисовки
+ at nav{}
+
+В таблице показаны времена создания графика для всех примеров из файла @uref{http://sourceforge.net/p/mathgl/code/HEAD/tree/mathgl-2x/examples/samples.cpp, examples/samples.cpp}. Тест выполнен на моем ноутбуке (i5-2430M) с 64-bit Debian.
+
+Несколько слов о скорости. Во-первых, прямое рисование в память (Quality=4,5,6) быстрее буферизованного (Quality=0,1,2), но иногда результат некоректен (см. @ref{cloud}) и пропадает возможность экспорта в векторные и 3d форматы (например, EPS, SVG, PDF, ...). Во-вторых, обычно картинка худшего качества рисуется быстрее, т.е. Quality=1 быстрее Quality=2, и Quality=0 быстрее Quality=1. Однако, если график содержит множество граней (например @ref{cloud}, @ref{surf3}, @ref{pipe}, @ref{dew}), [...]
+
+Результаты для изображения размером 800*600 (по умолчанию).
+ at include time.texi
+
+Результаты для изображения размером 1920*1440 (для печати)
+ at include time_big.texi
+
+ at node Copying This Manual, Index, Plotting time, Top
 @appendix GNU Free Documentation License
 @include fdl.texi
 
diff --git a/texinfo/ex_mgl_en.texi b/texinfo/ex_mgl_en.texi
index 5c696d4..c97475d 100644
--- a/texinfo/ex_mgl_en.texi
+++ b/texinfo/ex_mgl_en.texi
@@ -1,5 +1,6 @@
 @c ------------------------------------------------------------------
 @chapter MathGL examples
+ at nav{}
 
 This chapter contain information about basic and advanced MathGL, hints and samples for all types of graphics. I recommend you read first 2 sections one after another and at least look on @ref{Hints} section. Also I recommend you to look at @ref{General concepts} and @ref{FAQ}.
 
@@ -58,6 +59,7 @@ Basically, you can put this text after the script. Note, that you need to termin
 @external{}
 @node Basic usage, Advanced usage, , Examples
 @section Basic usage
+ at nav{}
 
 MGL script can be used by several manners. Each has positive and negative sides:
 @itemize @bullet
@@ -95,9 +97,10 @@ fplot 'x^3' # draw some function
 Just type it in UDAV and press F5. Also you can save it in text file @samp{test.mgl} and type in the console @code{mglconv test.mgl} what produce file @samp{test.mgl.png} with resulting picture.
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Advanced usage, Data handling, Basic usage, Examples
 @section Advanced usage
+ at nav{}
 
 Now I show several non-obvious features of MGL: several subplots in a single picture, curvilinear coordinates, text printing and so on. Generally you may miss this section at first reading, but I don't recommend it.
 
@@ -114,9 +117,10 @@ Now I show several non-obvious features of MGL: several subplots in a single pic
 @end menu
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Subplots, Axis and ticks, , Advanced usage
 @subsection Subplots
+ at nav{}
 
 Let me demonstrate possibilities of plot positioning and rotation. MathGL has a set of functions: @ref{subplot}, @ref{inplot}, @ref{title}, @ref{aspect} and @ref{rotate} and so on (see @ref{Subplots and rotation}). The order of their calling is strictly determined. First, one changes the position of plot in image area (functions @ref{subplot}, @ref{inplot} and @ref{multiplot}). Secondly, you can add the title of plot by @ref{title} function. After that one may rotate the plot (command @r [...]
 @verbatim
@@ -167,9 +171,10 @@ multiplot 3 2 1 2 1 '':title 'MultiPlot':box
 @pfig{inplot, Example for most of positioning functions.}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Axis and ticks, Curvilinear coordinates, Subplots, Advanced usage
 @subsection Axis and ticks
+ at nav{}
 
 MathGL library can draw not only the bounding box but also the axes, grids, labels and so on. The ranges of axes and their origin (the point of intersection) are determined by functions @code{SetRange()}, @code{SetRanges()}, @code{SetOrigin()} (see @ref{Ranges (bounding box)}). Ticks on axis are specified by function @code{SetTicks}, @code{SetTicksVal}, @code{SetTicksTime} (see @ref{Ticks}). But usually
 
@@ -272,9 +277,10 @@ xlabel 'x' 1:ylabel 'y = x' 0
 You can see that MathGL automatically switch to log-ticks as we define log-axis formula (in difference from v.1.*). Moreover, it switch to log-ticks for any formula if axis range will be large enough (see right bottom plot). Another interesting feature is that you not necessary define usual log-axis (i.e. when coordinates are positive), but you can define ``minus-log'' axis when coordinate is negative (see left bottom plot).
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Curvilinear coordinates, Colorbars, Axis and ticks, Advanced usage
 @subsection Curvilinear coordinates
+ at nav{}
 
 As I noted in previous subsection, MathGL support curvilinear coordinates. In difference from other plotting programs and libraries, MathGL uses textual formulas for connection of the old (data) and new (output) coordinates. This allows one to plot in arbitrary coordinates. The following code plots the line @var{y}=0, @var{z}=0 in Cartesian, polar, parabolic and spiral coordinates:
 @verbatim
@@ -299,9 +305,10 @@ fplot '2*t-1' '0.5' '0' '2r':axis:grid
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Colorbars, Bounding box, Curvilinear coordinates, Advanced usage
 @subsection Colorbars
+ at nav{}
 
 MathGL handle @ref{colorbar} as special kind of axis. So, most of functions for axis and ticks setup will work for colorbar too. Colorbars can be in log-scale, and generally as arbitrary function scale; common factor of colorbar labels can be separated; and so on.
 
@@ -333,9 +340,10 @@ colorbar '>':text 1.35 1.2 'Log scale'
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Bounding box, Ternary axis, Colorbars, Advanced usage
 @subsection Bounding box
+ at nav{}
 
 Box around the plot is rather useful thing because it allows one to: see the plot boundaries, and better estimate points position since box contain another set of ticks. MathGL provide special function for drawing such box -- @ref{box} function. By default, it draw black or white box with ticks (color depend on transparency type, see @ref{Types of transparency}). However, you can change the color of box, or add drawing of rectangles at rear faces of box. Also you can disable ticks drawin [...]
 @verbatim
@@ -352,9 +360,10 @@ subplot 2 2 3:title 'both':rotate 50 60:box '@cm'
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Ternary axis, Text features, Bounding box, Advanced usage
 @subsection Ternary axis
+ at nav{}
 
 There are another unusual axis types which are supported by MathGL. These are ternary and quaternary axis. Ternary axis is special axis of 3 coordinates @var{a}, @var{b}, @var{c} which satisfy relation @var{a}+ at var{b}+ at var{c}=1. Correspondingly, quaternary axis is special axis of 4 coordinates @var{a}, @var{b}, @var{c}, @var{d} which satisfy relation @var{a}+ at var{b}+ at var{c}+ at var{d}=1.
 
@@ -392,9 +401,10 @@ xlabel 'B':ylabel 'C':tlabel 'A':zlabel 'Z'
 @pfig{ternary, Ternary and Quaternary axis}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Text features, Legend sample, Ternary axis, Advanced usage
 @subsection Text features
+ at nav{}
 
 MathGL prints text by vector font. There are functions for manual specifying of text position (like @code{Puts}) and for its automatic selection (like @code{Label}, @code{Legend} and so on). MathGL prints text always in specified position even if it lies outside the bounding box. The default size of font is specified by functions @var{SetFontSize*} (see @ref{Font settings}). However, the actual size of output string depends on subplot size (depends on functions @code{SubPlot}, @code{InPl [...]
 
@@ -446,9 +456,10 @@ loadfont 'termes':text 0 1.1-9*d 'termes font'
 @pfig{fonts, Example of font faces}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Legend sample, Cutting sample, Text features, Advanced usage
 @subsection Legend sample
+ at nav{}
 
 Legend is one of standard ways to show plot annotations. Basically you need to connect the plot style (line style, marker and color) with some text. In MathGL, you can do it by 2 methods: manually using @ref{addlegend} function; or use @samp{legend} option (see @ref{Command options}), which will use last plot style. In both cases, legend entries will be added into internal accumulator, which later used for legend drawing itself. @ref{clearlegend} function allow you to remove all saved le [...]
 
@@ -479,9 +490,10 @@ legend 1 '#-':text 0.75 0.25 'Horizontal legend' 'a'
 @pfig{legend, Example of legend}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Cutting sample, , Legend sample, Advanced usage
 @subsection Cutting sample
+ at nav{}
 
 The last common thing which I want to show in this section is how one can cut off points from plot. There are 4 mechanism for that.
 @itemize @bullet
@@ -525,6 +537,7 @@ cut '(z>(x+0.5*y-1)^2-1) & (z>(x-0.5*y-1)^2-1)':surf3 c
 @external{}
 @node Data handling, Data plotting, Advanced usage, Examples
 @section Data handling
+ at nav{}
 
 Class @code{mglData} contains all functions for the data handling in MathGL (@pxref{Data processing}). There are several matters why I use class @code{mglData} but not a single array: it does not depend on type of data (mreal or double), sizes of data arrays are kept with data, memory working is simpler and safer.
 
@@ -534,9 +547,10 @@ Class @code{mglData} contains all functions for the data handling in MathGL (@px
 @end menu
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Array creation, Change data, , Data handling
 @subsection Array creation
+ at nav{}
 
 One can put numbers into the data instance by several ways. Let us do it for square function:
 @itemize @bullet
@@ -610,9 +624,10 @@ new z 30 40 'sin(pi*x)*cos(pi*y)'
 or loaded from a file.
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Change data, , Array creation, Data handling
 @subsection Change data
+ at nav{}
 
 MathGL has functions for data processing: differentiating, integrating, smoothing and so on (for more detail, see @ref{Data processing}). Let us consider some examples. The simplest ones are integration and differentiation. The direction in which operation will be performed is specified by textual string, which may contain symbols @samp{x}, @samp{y} or @samp{z}. For example, the call of @code{diff 'x'} will differentiate data along @samp{x} direction; the call of @code{integrate 'xy'} pe [...]
 @verbatim
@@ -719,6 +734,7 @@ plot v1 u2 'r2v':line 0.5 0.7 0.5 0.85 'rA'
 @external{}
 @node Data plotting, 1D samples, Data handling, Examples
 @section Data plotting
+ at nav{}
 
 Let me now show how to plot the data. Next section will give much more examples for all plotting functions. Here I just show some basics. MathGL generally has 2 types of plotting functions. Simple variant requires a single data array for plotting, other data (coordinates) are considered uniformly distributed in axis range. Second variant requires data arrays for all coordinates. It allows one to plot rather complex multivalent curves and surfaces (in case of parametric dependencies). Usu [...]
 
@@ -810,6 +826,7 @@ Drawing of other 2D plots is analogous. The only peculiarity is the usage of fla
 @external{}
 @node 1D samples, 2D samples, Data plotting, Examples
 @section 1D samples
+ at nav{}
 
 This section is devoted to visualization of 1D data arrays. 1D means the data which depend on single index (parameter) like curve in parametric form @{x(i),y(i),z(i)@}, i=1...n. Most of samples will use the same data for plotting. So, I put its initialization in separate function
 @verbatim
@@ -840,6 +857,7 @@ Basically, you can put this text after the script. Note, that you need to termin
 * Chart sample::
 * BoxPlot sample::
 * Candle sample::
+* OHLC sample::
 * Error sample::
 * Mark sample::
 * TextMark sample::
@@ -852,9 +870,10 @@ Basically, you can put this text after the script. Note, that you need to termin
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Plot sample, Radar sample, , 1D samples
 @subsection Plot sample
+ at nav{}
 
 Command @ref{plot} is most standard way to visualize 1D data array. By default, @code{Plot} use colors from palette. However, you can specify manual color/palette, and even set to use new color for each points by using @samp{!} style. Another feature is @samp{ } style which draw only markers without line between points. The sample code is:
 @verbatim
@@ -877,9 +896,10 @@ plot xc yc z 'rs'
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Radar sample, Step sample, Plot sample, 1D samples
 @subsection Radar sample
+ at nav{}
 
 Command @ref{radar} plot is variant of @code{Plot} one, which make plot in polar coordinates and draw radial rays in point directions. If you just need a plot in polar coordinates then I recommend to use @ref{Curvilinear coordinates} or @code{Plot} in parabolic form with @code{x=r*cos(fi); y=r*sin(fi);}. The sample code is:
 @verbatim
@@ -891,9 +911,10 @@ radar yr '#'
 @pfig{radar, Example of Radar()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Step sample, Tens sample, Radar sample, 1D samples
 @subsection Step sample
+ at nav{}
 
 Command @ref{step} plot data as stairs. It have the same options as @code{Plot}. The sample code is:
 @verbatim
@@ -912,9 +933,10 @@ step y 's!rgb'
 @pfig{step, Example of Step()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Tens sample, Area sample, Step sample, 1D samples
 @subsection Tens sample
+ at nav{}
 
 Command @ref{tens} is variant of @ref{plot} with smooth coloring along the curves. At this, color is determined as for surfaces (see @ref{Color scheme}). The sample code is:
 @verbatim
@@ -933,9 +955,10 @@ tens xc yc z z 's'
 @pfig{tens, Example of Tens()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Area sample, Region sample, Tens sample, 1D samples
 @subsection Area sample
+ at nav{}
 
 Command @ref{area} fill the area between curve and axis plane. It support gradient filling if 2 colors per curve is specified. The sample code is:
 @verbatim
@@ -958,9 +981,10 @@ area xc yc z 'r':area xc -yc z 'b#'
 @pfig{area, Example of Area()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Region sample, Stem sample, Area sample, 1D samples
 @subsection Region sample
+ at nav{}
 
 Command @ref{region} fill the area between 2 curves. It support gradient filling if 2 colors per curve is specified. Also it can fill only the region y1<y<y2 if style @samp{i} is used. The sample code is:
 @verbatim
@@ -982,9 +1006,10 @@ region y1 y2 'ir':plot y1 'k2':plot y2 'k2'
 @pfig{region, Example of Region()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Stem sample, Bars sample, Region sample, 1D samples
 @subsection Stem sample
+ at nav{}
 
 Command @ref{stem} draw vertical bars. It is most attractive if markers are drawn too. The sample code is:
 @verbatim
@@ -1003,9 +1028,10 @@ stem y 'o!rgb'
 @pfig{stem, Example of Stem()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Bars sample, Barh sample, Stem sample, 1D samples
 @subsection Bars sample
+ at nav{}
 
 Command @ref{bars} draw vertical bars. It have a lot of options: bar-above-bar (@samp{a} style), fall like (@samp{f} style), 2 colors for positive and negative values, wired bars (@samp{#} style), 3D variant. The sample code is:
 @verbatim
@@ -1033,9 +1059,10 @@ bars ys 'f'
 @pfig{bars, Example of Bars()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Barh sample, Cones sample, Bars sample, 1D samples
 @subsection Barh sample
+ at nav{}
 
 Command @ref{barh} is the similar to @code{Bars} but draw horizontal bars. The sample code is:
 @verbatim
@@ -1054,33 +1081,41 @@ barh ys 'f'
 @pfig{barh, Example of Barh()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Cones sample, Chart sample, Bars sample, 1D samples
 @subsection Cones sample
+ at nav{}
 
 Command @ref{cones} is similar to @code{Bars} but draw cones. The sample code is:
 @verbatim
 new ys 10 3 '0.8*sin(pi*(x+y/4+1.25))+0.2*rnd'
 origin 0 0 0:light on
-subplot 2 2 0:title 'Cones plot':rotate 50 60:box
+subplot 3 2 0:title 'Cones plot':rotate 50 60:box
 cones ys
 
-subplot 2 2 1:title '2 colors':rotate 50 60:box
+subplot 3 2 1:title '2 colors':rotate 50 60:box
 cones ys 'cbgGyr'
 
-subplot 2 2 2:title '"\#" style':rotate 50 60:box
+subplot 3 2 2:title '"\#" style':rotate 50 60:box
 cones ys '#'
 
-subplot 2 2 3:title '"a" style':rotate 50 60:zrange -2 2:box
+subplot 3 2 3:title '"a" style':rotate 50 60:zrange -2 2:box
 cones ys 'a'
+
+subplot 3 2 4:title '"t" style':rotate 50 60:box
+cones ys 't'
+
+subplot 3 2 5:title '"4" style':rotate 50 60:box
+cones ys '4'
 @end verbatim
 
 @pfig{cones, Example of Cones()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Chart sample, BoxPlot sample, Cones sample, 1D samples
 @subsection Chart sample
+ at nav{}
 
 Command @ref{chart} draw colored boxes with width proportional to data values. Use @samp{ } for empty box. Plot looks most attractive in polar coordinates -- well known pie chart. The sample code is:
 @verbatim
@@ -1103,9 +1138,10 @@ chart ch 'bgr cmy#'
 @pfig{chart, Example of Chart()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node BoxPlot sample, Candle sample, Chart sample, 1D samples
 @subsection BoxPlot sample
+ at nav{}
 
 Command @ref{boxplot} draw box-and-whisker diagram. The sample code is:
 @verbatim
@@ -1117,9 +1153,10 @@ boxplot a
 @pfig{boxplot, Example of BoxPlot()}
 
 @c ------------------------------------------------------------------
- at c @external{}
- at node Candle sample, Error sample, BoxPlot sample, 1D samples
+ at external{}
+ at node Candle sample, OHLC sample, BoxPlot sample, 1D samples
 @subsection Candle sample
+ at nav{}
 
 Command @ref{candle} draw candlestick chart. This is a combination of a line-chart and a bar-chart, in that each bar represents the range of price movement over a given time interval. The sample code is:
 @verbatim
@@ -1131,9 +1168,28 @@ candle y y1 y2
 @pfig{candle, Example of Candle()}
 
 @c ------------------------------------------------------------------
- at c @external{}
- at node Error sample, Mark sample, Candle sample, 1D samples
+ at external{}
+ at node OHLC sample, Error sample, Candle sample, 1D samples
+ at subsection OHLC sample
+ at nav{}
+
+Command @ref{ohlc} draw Open-High-Low-Close diagram. This diagram show vertical line for between maximal(high) and minimal(low) values, as well as horizontal lines before/after vertical line for initial(open)/final(close) values of some process. The sample code is:
+ at verbatim
+new o 10 '0.5*sin(pi*x)'
+new c 10 '0.5*sin(pi*(x+2/9))'
+new l 10 '0.3*rnd-0.8'
+new h 10 '0.3*rnd+0.5'
+subplot 1 1 0 '':title 'OHLC plot':box
+ohlc o h l c
+ at end verbatim
+
+ at pfig{candle, Example of OHLC()}
+
+ at c ------------------------------------------------------------------
+ at external{}
+ at node Error sample, Mark sample, OHLC sample, 1D samples
 @subsection Error sample
+ at nav{}
 
 Command @ref{error} draw error boxes around the points. You can draw default boxes or semi-transparent symbol (like marker, see @ref{Line styles}). Also you can set individual color for each box. The sample code is:
 @verbatim
@@ -1159,10 +1215,32 @@ next
 
 @pfig{error, Example of Error()}
 
+Additionally, you can use solid large "marks" instead of error boxes by selecting proper style.
+ at verbatim
+new x0 10 'rnd':new ex 10 '0.1'
+new y0 10 'rnd':new ey 10 '0.1'
+ranges 0 1 0 1
+subplot 4 3 0 '':box:error x0 y0 ex ey '#+@'
+subplot 4 3 1 '':box:error x0 y0 ex ey '#x@'
+subplot 4 3 2 '':box:error x0 y0 ex ey '#s@'; alpha 0.5
+subplot 4 3 3 '':box:error x0 y0 ex ey 's@'
+subplot 4 3 4 '':box:error x0 y0 ex ey 'd@'
+subplot 4 3 5 '':box:error x0 y0 ex ey '#d@'; alpha 0.5
+subplot 4 3 6 '':box:error x0 y0 ex ey '+@'
+subplot 4 3 7 '':box:error x0 y0 ex ey 'x@'
+subplot 4 3 8 '':box:error x0 y0 ex ey 'o@'
+subplot 4 3 9 '':box:error x0 y0 ex ey '#o@'; alpha 0.5
+subplot 4 3 10 '':box:error x0 y0 ex ey '#.@'
+subplot 4 3 11 '':box:error x0 y0 ex ey; alpha 0.5
+ at end verbatim
+
+ at pfig{error2, Example of Error() with marks}
+
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Mark sample, TextMark sample, Error sample, 1D samples
 @subsection Mark sample
+ at nav{}
 
 Command @ref{mark} draw markers at points. It is mostly the same as @code{Plot} but marker size can be variable. The sample code is:
 @verbatim
@@ -1174,9 +1252,10 @@ mark y y1 's'
 @pfig{mark, Example of Mark()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node TextMark sample, Label sample, Mark sample, 1D samples
 @subsection TextMark sample
+ at nav{}
 
 Command @ref{textmark} like @code{Mark} but draw text instead of markers. The sample code is:
 @verbatim
@@ -1188,9 +1267,10 @@ textmark y y1 '\gamma' 'r'
 @pfig{textmark, Example of TextMark()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Label sample, Table sample, TextMark sample, 1D samples
 @subsection Label sample
+ at nav{}
 
 Command @ref{label} print text at data points. The string may contain @samp{%x}, @samp{%y}, @samp{%z} for x-, y-, z-coordinates of points, @samp{%n} for point index. The sample code is:
 @verbatim
@@ -1203,9 +1283,10 @@ plot ys ' *':label ys 'y=%y'
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Table sample, Tube sample, Label sample, 1D samples
 @subsection Table sample
+ at nav{}
 
 Command @ref{table} draw table with data values. The sample code is:
 @verbatim
@@ -1227,9 +1308,10 @@ table 0.5 0.95 ys 'y_1\n{}y_2\n{}y_3' '#';value 0.7
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Tube sample, Tape sample, Table sample, 1D samples
 @subsection Tube sample
+ at nav{}
 
 Command @ref{tube} draw tube with variable radius. The sample code is:
 @verbatim
@@ -1253,9 +1335,10 @@ tube xc yc z y2 'r'
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Tape sample, Torus sample, Tube sample, 1D samples
 @subsection Tape sample
+ at nav{}
 
 Command @ref{tape} draw tapes which rotate around the curve as normal and binormal. The sample code is:
 @verbatim
@@ -1279,9 +1362,10 @@ plot xc yc z 'k':tape xc yc z 'zg':tape xc yc z 'zg#'
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Torus sample, , Tape sample, 1D samples
 @subsection Torus sample
+ at nav{}
 
 Command @ref{torus} draw surface of the curve rotation. The sample code is:
 @verbatim
@@ -1306,6 +1390,7 @@ torus y1 y2 '#'
 @external{}
 @node 2D samples, 3D samples, 1D samples, Examples
 @section 2D samples
+ at nav{}
 
 This section is devoted to visualization of 2D data arrays. 2D means the data which depend on 2 indexes (parameters) like matrix z(i,j)=z(x(i),y(j)), i=1...n, j=1...m or in parametric form @{x(i,j),y(i,j),z(i,j)@}. Most of samples will use the same data for plotting. So, I put its initialization in separate function
 @verbatim
@@ -1336,9 +1421,10 @@ Basically, you can put this text after the script. Note, that you need to termin
 @end menu
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Surf sample, SurfC sample, , 2D samples
 @subsection Surf sample
+ at nav{}
 
 Command @ref{surf} is most standard way to visualize 2D data array. @code{Surf} use color scheme for coloring (see @ref{Color scheme}). You can use @samp{#} style for drawing black meshes on the surface. The sample code is:
 @verbatim
@@ -1361,9 +1447,10 @@ surf x y z 'BbwrR'
 @pfig{surf, Example of Surf()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node SurfC sample, SurfA sample, Surf sample, 2D samples
 @subsection SurfC sample
+ at nav{}
 
 Command @ref{surfc} is similar to @ref{surf} but its coloring is determined by another data. The sample code is:
 @verbatim
@@ -1375,9 +1462,10 @@ surfc a b
 @pfig{surfc, Example of SurfC()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node SurfA sample, Mesh sample, SurfC sample, 2D samples
 @subsection SurfA sample
+ at nav{}
 
 Command @ref{surfa} is similar to @ref{surf} but its transparency is determined by another data. The sample code is:
 @verbatim
@@ -1390,9 +1478,10 @@ surfa a b
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Mesh sample, Fall sample, SurfA sample, 2D samples
 @subsection Mesh sample
+ at nav{}
 
 Command @ref{mesh} draw wired surface. You can use @ref{meshnum} for changing number of lines to be drawn. The sample code is:
 @verbatim
@@ -1404,9 +1493,10 @@ mesh a
 @pfig{mesh, Example of Mesh()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Fall sample, Belt sample, Mesh sample, 2D samples
 @subsection Fall sample
+ at nav{}
 
 Command @ref{fall} draw waterfall surface. You can use @ref{meshnum} for changing number of lines to be drawn. Also you can use @samp{x} style for drawing lines in other direction. The sample code is:
 @verbatim
@@ -1418,9 +1508,10 @@ fall a
 @pfig{fall, Example of Fall()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Belt sample, Boxs sample, Fall sample, 2D samples
 @subsection Belt sample
+ at nav{}
 
 Command @ref{belt} draw surface by belts. You can use @samp{x} style for drawing lines in other direction. The sample code is:
 @verbatim
@@ -1432,9 +1523,10 @@ belt a
 @pfig{belt, Example of Belt()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Boxs sample, Tile sample, Fall sample, 2D samples
 @subsection Boxs sample
+ at nav{}
 
 Command @ref{boxs} draw surface by boxes. You can use @samp{#} for drawing wire plot. The sample code is:
 @verbatim
@@ -1456,9 +1548,10 @@ tile a
 @pfig{boxs, Example of Boxs()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Tile sample, TileS sample, Boxs sample, 2D samples
 @subsection Tile sample
+ at nav{}
 
 Command @ref{tile} draw surface by tiles. The sample code is:
 @verbatim
@@ -1470,9 +1563,10 @@ tile a
 @pfig{tile, Example of Tile()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node TileS sample, Dens sample, Tile sample, 2D samples
 @subsection TileS sample
+ at nav{}
 
 Command @ref{tiles} is similar to @ref{tile} but tile sizes is determined by another data. This allows one to simulate transparency of the plot. The sample code is:
 @verbatim
@@ -1485,9 +1579,10 @@ tiles a b
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Dens sample, Cont sample, TileS sample, 2D samples
 @subsection Dens sample
+ at nav{}
 
 Command @ref{dens} draw density plot for surface. The sample code is:
 @verbatim
@@ -1510,9 +1605,10 @@ dens a1
 @pfig{dens, Example of Dens()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Cont sample, ContF sample, Dens sample, 2D samples
 @subsection Cont sample
+ at nav{}
 
 Command @ref{cont} draw contour lines for surface. You can select automatic (default) or manual levels for contours, print contour labels, draw it on the surface (default) or at plane (as @code{Dens}). The sample code is:
 @verbatim
@@ -1534,9 +1630,10 @@ cont a 't'
 @pfig{cont, Example of Cont()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node ContF sample, ContD sample, Cont sample, 2D samples
 @subsection ContF sample
+ at nav{}
 
 Command @ref{contf} draw filled contours.  You can select automatic (default) or manual levels for contours. The sample code is:
 @verbatim
@@ -1560,9 +1657,10 @@ contf a1
 @pfig{contf, Example of ContF()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node ContD sample, ContV sample, ContF sample, 2D samples
 @subsection ContD sample
+ at nav{}
 
 Command @ref{contd} is similar to @code{ContF} but with manual contour colors. The sample code is:
 @verbatim
@@ -1586,9 +1684,10 @@ contd a1
 @pfig{contd, Example of ContD()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node ContV sample, Axial sample, ContD sample, 2D samples
 @subsection ContV sample
+ at nav{}
 
 Command @ref{contv} draw vertical cylinders (belts) at contour lines. The sample code is:
 @verbatim
@@ -1610,9 +1709,10 @@ contv a:contf a:cont a 'k'
 @pfig{contv, Example of ContV()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Axial sample, Grad sample, ContV sample, 2D samples
 @subsection Axial sample
+ at nav{}
 
 Command @ref{axial} draw surfaces of rotation for contour lines. You can draw wire surfaces (@samp{#} style) or ones rotated in other directions (@samp{x}, @samp{z} styles). The sample code is:
 @verbatim
@@ -1633,9 +1733,10 @@ axial a '#'
 @pfig{axial, Example of Axial()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Grad sample, , Axial sample, 2D samples
 @subsection Grad sample
+ at nav{}
 
 Command @ref{grad} draw gradient lines for matrix. The sample code is:
 @verbatim
@@ -1651,6 +1752,7 @@ grad a:dens a '{u8}w{q8}'
 @external{}
 @node 3D samples, Vector field samples, 2D samples, Examples
 @section 3D samples
+ at nav{}
 
 This section is devoted to visualization of 3D data arrays. 3D means the data which depend on 3 indexes (parameters) like tensor a(i,j,k)=a(x(i),y(j),x(k)), i=1...n, j=1...m, k=1...l or in parametric form @{x(i,j,k),y(i,j,k),z(i,j,k),a(i,j,k)@}. Most of samples will use the same data for plotting. So, I put its initialization in separate function
 @verbatim
@@ -1677,9 +1779,10 @@ Basically, you can put this text after the script. Note, that you need to termin
 @end menu
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Surf3 sample, Surf3C sample, , 3D samples
 @subsection Surf3 sample
+ at nav{}
 
 Command @ref{surf3} is one of most suitable (for my opinion) functions to visualize 3D data. It draw the isosurface(s) -- surface(s) of constant amplitude (3D analogue of contour lines). You can draw wired isosurfaces if specify @samp{#} style. The sample code is:
 @verbatim
@@ -1698,9 +1801,10 @@ surf3 c '.'
 @pfig{surf3, Example of Surf3()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Surf3C sample, Surf3A sample, Surf3 sample, 3D samples
 @subsection Surf3C sample
+ at nav{}
 
 Command @ref{surf3c} is similar to @ref{surf3} but its coloring is determined by another data. The sample code is:
 @verbatim
@@ -1712,9 +1816,10 @@ surf3c c d
 @pfig{surf3c, Example of Surf3C()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Surf3A sample, Cloud sample, Surf3C sample, 3D samples
 @subsection Surf3A sample
+ at nav{}
 
 Command @ref{surf3a} is similar to @ref{surf3} but its transparency is determined by another data. The sample code is:
 @verbatim
@@ -1726,9 +1831,10 @@ surf3a c d
 @pfig{surf3a, Example of Surf3A()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Cloud sample, Dens3 sample, Surf3A sample, 3D samples
 @subsection Cloud sample
+ at nav{}
 
 Command @ref{cloud} draw cloud-like object which is less transparent for higher data values. Similar plot can be created using many (about 10-20) @code{Surf3A(a,a)} isosurfaces. The sample code is:
 @verbatim
@@ -1736,8 +1842,8 @@ call 'prepare3d'
 subplot 2 2 0:title 'Cloud plot':rotate 50 60:alpha on:box
 cloud c 'wyrRk'
 
-subplot 2 2 1:title '"!" style':rotate 50 60:box
-cloud c '!wyrRk'
+subplot 2 2 1:title '"i" style':rotate 50 60:box
+cloud c 'iwyrRk'
 
 subplot 2 2 2:title '"." style':rotate 50 60:box
 cloud c '.wyrRk'
@@ -1749,9 +1855,10 @@ cloud c 'wyrRk'; meshnum 10
 @pfig{cloud, Example of Cloud()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Dens3 sample, Cont3 sample, Cloud sample, 3D samples
 @subsection Dens3 sample
+ at nav{}
 
 Command @ref{dens3} draw just usual density plot but at slices of 3D data. The sample code is:
 @verbatim
@@ -1764,9 +1871,10 @@ dens3 c 'x':dens3 c ':y':dens3 c 'z'
 @pfig{densa, Example of Dens3()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Cont3 sample, ContF3 sample, Dens3 sample, 3D samples
 @subsection Cont3 sample
+ at nav{}
 
 Command @ref{cont3} draw just usual contour lines but at slices of 3D data. The sample code is:
 @verbatim
@@ -1778,9 +1886,10 @@ cont3 c 'x':cont3 c:cont3 c 'z'
 @pfig{conta, Example of Cont3()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node ContF3 sample, Dens projection sample, Cont3 sample, 3D samples
 @subsection ContF3 sample
+ at nav{}
 
 Command @ref{contf3} draw just usual filled contours but at slices of 3D data. The sample code is:
 @verbatim
@@ -1793,11 +1902,12 @@ cont3 c 'xk':cont3 c 'k':cont3 c 'zk'
 @pfig{contfa, Example of ContF3()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Dens projection sample, Cont projection sample, ContF3 sample, 3D samples
 @subsection Dens projection sample
+ at nav{}
 
-Functions @ref{DensXYZ} draw density plot on plane perpendicular to corresponding axis. One of possible application is drawing projections of 3D field. The sample code is:
+Functions @ref{densz}, @ref{densy}, @ref{densx} draw density plot on plane perpendicular to corresponding axis. One of possible application is drawing projections of 3D field. The sample code is:
 @verbatim
 call 'prepare3d'
 title 'Dens[XYZ] sample':rotate 50 60:box
@@ -1806,14 +1916,15 @@ densy {sum c 'y'} '' 1
 densz {sum c 'z'} '' -1
 @end verbatim
 
- at pfig{dens_xyz, {Example of DensX(), DensY(), DensZ()}}
+ at pfig{dens_xyz, Example of DensX() DensY() DensZ()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Cont projection sample, ContF projection sample, Dens projection sample, 3D samples
 @subsection Cont projection sample
+ at nav{}
 
-Functions @ref{ContXYZ} draw contour lines on plane perpendicular to corresponding axis. One of possible application is drawing projections of 3D field. The sample code is:
+Functions @ref{contz}, @ref{conty}, @ref{contx} draw contour lines on plane perpendicular to corresponding axis. One of possible application is drawing projections of 3D field. The sample code is:
 @verbatim
 call 'prepare3d'
 title 'Cont[XYZ] sample':rotate 50 60:box
@@ -1822,14 +1933,15 @@ conty {sum c 'y'} '' 1
 contz {sum c 'z'} '' -1
 @end verbatim
 
- at pfig{cont_xyz, {Example of ContX(), ContY(), ContZ()}}
+ at pfig{cont_xyz, Example of ContX() ContY() ContZ()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node ContF projection sample, TriPlot and QuadPlot, Cont projection sample, 3D samples
 @subsection ContF projection sample
+ at nav{}
 
-Functions @code{ContFXYZ} draw filled contours on plane perpendicular to corresponding axis. One of possible application is drawing projections of 3D field. The sample code is:
+Functions @ref{contfz}, @ref{contfy}, @ref{contfx} draw filled contours on plane perpendicular to corresponding axis. One of possible application is drawing projections of 3D field. The sample code is:
 @verbatim
 call 'prepare3d'
 title 'ContF[XYZ] sample':rotate 50 60:box
@@ -1838,12 +1950,13 @@ contfy {sum c 'y'} '' 1
 contfz {sum c 'z'} '' -1
 @end verbatim
 
- at pfig{contf_xyz, {Example of ContFX(), ContFY(), ContFZ()}}
+ at pfig{contf_xyz, Example of ContFX() ContFY() ContFZ()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node TriPlot and QuadPlot, Axial sample, ContF projection sample, 3D samples
 @subsection TriPlot and QuadPlot
+ at nav{}
 
 Command @ref{triplot} and @ref{quadplot} draw set of triangles (or quadrangles for @code{QuadPlot}) for irregular data arrays. Note, that you have to provide not only vertexes, but also the indexes of triangles or quadrangles. I.e. perform triangulation by some other library. The sample code is:
 @verbatim
@@ -1877,9 +1990,10 @@ tricont t xt yt zt 'B'
 @pfig{triplot, Example of TriPlot() and QuadPlot()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Dots sample, , TriPlot and QuadPlot, 3D samples
 @subsection Dots sample
+ at nav{}
 
 Command @ref{dots} is another way to draw irregular points. @code{Dots} use color scheme for coloring (see @ref{Color scheme}). The sample code is:
 @verbatim
@@ -1897,6 +2011,7 @@ dots x y z
 @external{}
 @node Vector field samples, Hints, 3D samples, Examples
 @section Vector field samples
+ at nav{}
 
 Vector field visualization (especially in 3d case) is more or less complex task. MathGL provides 3 general types of plots: vector field itself (@code{Vect}), flow threads (@code{Flow}), and flow pipes with radius proportional to field amplitude (@code{Pipe}).
 
@@ -1930,9 +2045,10 @@ Basically, you can put this text after the script. Note, that you need to termin
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Vect sample, Vect3 sample, , Vector field samples
 @subsection Vect sample
+ at nav{}
 
 Command @ref{vect} is most standard way to visualize vector fields -- it draw a lot of arrows or hachures for each data cell. It have a lot of options which can be seen on the figure (and in the sample code). @code{Vect} use color scheme for coloring (see @ref{Color scheme}). The sample code is:
 @verbatim
@@ -1960,9 +2076,10 @@ vect ex ey ez
 @pfig{vect, Example of Vect()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Vect3 sample, Traj sample, Vect sample, Vector field samples
 @subsection Vect3 sample
+ at nav{}
 
 Command @ref{vect3} draw just usual vector field plot but at slices of 3D data. The sample code is:
 @verbatim
@@ -1980,9 +2097,10 @@ grid3 ex 'Wx':grid3 ex 'W':grid3 ex 'Wz'
 @pfig{vecta, Example of Vect3()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Traj sample, Flow sample, Vect3 sample, Vector field samples
 @subsection Traj sample
+ at nav{}
 
 Command @ref{traj} is 1D analogue of @code{Vect}. It draw vectors from specified points. The sample code is:
 @verbatim
@@ -1995,9 +2113,10 @@ plot x1 y:traj x1 y y1 y2
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Flow sample, Pipe sample, Traj sample, Vector field samples
 @subsection Flow sample
+ at nav{}
 
 Command @ref{flow} is another standard way to visualize vector fields -- it draw lines (threads) which is tangent to local vector field direction. MathGL draw threads from edges of bounding box and from central slices. Sometimes it is not most appropriate variant -- you may want to use @code{FlowP} to specify manual position of threads. @code{Flow} use color scheme for coloring (see @ref{Color scheme}). At this warm color corresponds to normal flow (like attractor), cold one corresponds  [...]
 @verbatim
@@ -2019,9 +2138,10 @@ flow ex ey ez
 @pfig{flow, Example of Flow()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Pipe sample, Dew sample, Flow sample, Vector field samples
 @subsection Pipe sample
+ at nav{}
 
 Command @ref{pipe} is similar to @ref{flow} but draw pipes (tubes) which radius is proportional to the amplitude of vector field. @code{Pipe} use color scheme for coloring (see @ref{Color scheme}). At this warm color corresponds to normal flow (like attractor), cold one corresponds to inverse flow (like source). The sample code is:
 @verbatim
@@ -2043,9 +2163,10 @@ pipe ex ey ez '' 0.1
 @pfig{pipe, Example of Pipe()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Dew sample, , Pipe sample, Vector field samples
 @subsection Dew sample
+ at nav{}
 
 Command @ref{dew} is similar to @code{Vect} but use drops instead of arrows. The sample code is:
 @verbatim
@@ -2061,6 +2182,7 @@ dew a b
 @external{}
 @node Hints, FAQ, Vector field samples, Examples
 @section Hints
+ at nav{}
 
 In this section I've included some small hints and advices for the improving of the quality of plots and for the demonstration of some non-trivial features of MathGL library. In contrast to previous examples I showed mostly the idea but not the whole drawing function.
 
@@ -2070,12 +2192,13 @@ In this section I've included some small hints and advices for the improving of
 * Types of transparency::
 * Axis projection::
 * Adding fog::
-* Several light sources::
+* Lighting sample::
 * Using primitives::
 * STFA sample::
 * Mapping visualization::
+* Making regular data::
 * Making histogram::
-* Nonlinear fitting sample::
+* Nonlinear fitting hints::
 * PDE solving hints::
 * MGL parser using::
 * Using options::
@@ -2085,9 +2208,10 @@ In this section I've included some small hints and advices for the improving of
 @end menu
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node ``Compound'' graphics, Transparency and lighting, , Hints
 @subsection ``Compound'' graphics
+ at nav{}
 
 As I noted above, MathGL functions (except the special one, like Clf()) do  not erase the previous plotting but just add the new one. It allows one to draw ``compound'' plots easily. For example, popular Matlab command @code{surfc} can be emulated in MathGL by 2 calls:
 @verbatim
@@ -2139,9 +2263,10 @@ contf3 v c 'z' c.nz-1:surf3 c -0.5
 @pfig{combined, Example of ``combined'' plots}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Transparency and lighting, Types of transparency, ``Compound'' graphics, Hints
 @subsection Transparency and lighting
+ at nav{}
 
 Here I want to show how transparency and lighting both and separately change the look of a surface. So, there is code and picture for that:
 @verbatim
@@ -2162,9 +2287,10 @@ light off:surf a
 @pfig{alpha, Example of transparency and lightings}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Types of transparency, Axis projection, Transparency and lighting, Hints
 @subsection Types of transparency
+ at nav{}
 
 MathGL library has advanced features for setting and handling the surface transparency. The simplest way to add transparency is the using of command @ref{alpha}. As a result, all further surfaces (and isosurfaces, density plots and so on) become transparent. However, their  look can be additionally improved.
 
@@ -2191,9 +2317,10 @@ subplot 2 2 3:rotate 50 60:axial a:box
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Axis projection, Adding fog, Ternary axis, Hints
 @subsection Axis projection
+ at nav{}
 
 You can easily make 3D plot and draw its x-,y-,z-projections (like in CAD) by using @ref{ternary} function with arguments: 4 for Cartesian, 5 for Ternary and 6 for Quaternary coordinates. The sample code is:
 @verbatim
@@ -2214,9 +2341,10 @@ xlabel 'X':ylabel 'Y':zlabel 'Z'
 @pfig{projection, Example of axis projections}
 
 @c ------------------------------------------------------------------
- at c @external{}
- at node Adding fog, Several light sources, Axis projection, Hints
+ at external{}
+ at node Adding fog, Lighting sample, Axis projection, Hints
 @subsection Adding fog
+ at nav{}
 
 MathGL can add a fog to the image. Its switching on is rather simple -- just use @ref{fog} function. There is the only feature -- fog is applied for whole image. Not to particular subplot. The sample code is:
 @verbatim
@@ -2229,9 +2357,10 @@ box:surf a
 @pfig{fog, Example of @code{Fog()}.}
 
 @c ------------------------------------------------------------------
- at c @external{}
- at node Several light sources, Using primitives, Adding fog, Hints
- at subsection Several light sources
+ at external{}
+ at node Lighting sample, Using primitives, Adding fog, Hints
+ at subsection Lighting sample
+ at nav{}
 
 In contrast to the most of other programs, MathGL supports several (up to 10) light sources. Moreover, the color each of them can be different: white (this is usual), yellow, red, cyan, green and so on. The use of several light sources may be interesting for the highlighting of some peculiarities of the plot or just to make an amusing picture. Note, each light source can be switched on/off individually. The sample code is:
 @verbatim
@@ -2243,10 +2372,34 @@ box:surf a 'h'
 
 @pfig{several_light, Example of several light sources.}
 
+Additionally, you can use local light sources and set to use diffise reflection instead of specular one (by default) or both kinds.
+ at verbatim
+# use Quality=6 because need lighting in placed
+light on:quality 6
+call 'prepare2d'
+subplot 2 2 0:title 'Default':rotate 50 60:box:surf a
+line -1 -0.7 1.7 -1 -0.7 0.7 'BA'
+
+light 0 1 0 1 -2 -1 -1
+subplot 2 2 1:title 'Local':rotate 50 60:box:surf a
+line 1 0 1 -1 -1 0 'BAO'
+
+diffuse 0
+subplot 2 2 2:title 'no diffuse':rotate 50 60:box:surf a
+line 1 0 1 -1 -1 0 'BAO'
+
+diffuse 0.5:light 0 1 0 1 -2 -1 -1 'w' 0
+subplot 2 2 3:title 'diffusive only':rotate 50 60:box:surf a
+line 1 0 1 -1 -1 0 'BAO'
+ at end verbatim
+
+ at pfig{light, Example of different types of lighting.}
+
 @c ------------------------------------------------------------------
- at c @external{}
- at node Using primitives, STFA sample, Several light sources, Hints
+ at external{}
+ at node Using primitives, STFA sample, Lighting sample, Hints
 @subsection Using primitives
+ at nav{}
 
 MathGL provide a set of functions for drawing primitives (see @ref{Primitives}). Primitives are low level object, which used by most of plotting functions. Picture below demonstrate some of commonly used primitives.
 @verbatim
@@ -2323,9 +2476,10 @@ Of course, the first variant is more suitable if you need to plot a lot of circl
 @pfig{venn, Example of Venn diagram.}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node STFA sample, Mapping visualization, Using primitives, Hints
 @subsection STFA sample
+ at nav{}
 
 Short-time Fourier Analysis (@ref{stfa}) is one of informative method for analyzing long rapidly oscillating 1D data arrays. It is used to determine the sinusoidal frequency and phase content of local sections of a signal as it changes over time.
 
@@ -2345,9 +2499,10 @@ stfa a b 64:axis:ylabel '\omega' 0:xlabel '\i t'
 @pfig{stfa, Example of STFA().}
 
 @c ------------------------------------------------------------------
- at c @external{}
- at node Mapping visualization, Making histogram, STFA sample, Hints
+ at external{}
+ at node Mapping visualization, Making regular data, STFA sample, Hints
 @subsection Mapping visualization
+ at nav{}
 
 Sometime ago I worked with mapping and have a question about its visualization. Let me remember you that mapping is some transformation rule for one set of number to another one. The 1d mapping is just an ordinary function -- it takes a number and transforms it to another one. The 2d mapping (which I used) is a pair of functions which take 2 numbers and transform them to another 2 ones. Except general plots (like @ref{surfc}, @ref{surfa}) there is a special plot -- Arnold diagram. It sho [...]
 
@@ -2367,9 +2522,32 @@ fill a '(x^3+y^3)/2':fill b '(x-y)/2':map a b 'brgk'
 @pfig{map, Example of Map().}
 
 @c ------------------------------------------------------------------
- at c @external{}
- at node Making histogram, Nonlinear fitting sample, Mapping visualization, Hints
+ at external{}
+ at node Making regular data, Making histogram, Mapping visualization, Hints
+ at subsection Making regular data
+ at nav{}
+
+Sometimes, one have only unregular data, like as data on triangular grids, or experimental results and so on. Such kind of data cannot be used as simple as regular data (like matrices). Only few functions, like @ref{dots}, can handle unregular data as is.
+
+However, one can use built in triangulation functions for interpolating unregular data points to a regular data grids. There are 2 ways. First way, one can use @ref{triangulation} function to obtain list of vertexes for triangles. Later this list can be used in functions like @ref{triplot} or @ref{tricont}. Second way consist in usage of @ref{datagrid} function, which fill regular data grid by interpolated values, assuming that coordinates of the data grid is equidistantly distributed in [...]
+ at verbatim
+new x 100 '2*rnd-1':new y 100 '2*rnd-1':copy z x^2-y^2
+# first way - plot triangular surface for points
+triangulate d x y
+title 'Triangulation'
+rotate 50 60:box:light on
+triplot d x y z:triplot d x y z '#k'
+# second way - make regular data and plot it
+new g 30 30:datagrid g x y z:mesh g 'm'
+ at end verbatim
+
+ at pfig{triangulation, Example of triangulation.}
+
+ at c ------------------------------------------------------------------
+ at external{}
+ at node Making histogram, Nonlinear fitting hints, Making regular data, Hints
 @subsection Making histogram
+ at nav{}
 
 Using the @ref{hist} function(s) for making regular distributions is one of useful fast methods to process and plot irregular data. @code{Hist} can be used to find some momentum of set of points by specifying weight function. It is possible to create not only 1D distributions but also 2D and 3D ones. Below I place the simplest sample code which demonstrate @ref{hist} usage:
 @verbatim
@@ -2385,9 +2563,10 @@ subplot 3 3 2:text 0.5 0.5 'Hist and\n{}MultiPlot\n{}sample' 'a' -3
 
 
 @c ------------------------------------------------------------------
- at c @external{}
- at node Nonlinear fitting sample, PDE solving hints, Making histogram, Hints
+ at external{}
+ at node Nonlinear fitting hints, PDE solving hints, Making histogram, Hints
 @subsection Nonlinear fitting hints
+ at nav{}
 
 Nonlinear fitting is rather simple. All that you need is the data to fit, the approximation formula and the list of coefficients to fit (better with its initial guess values). Let me demonstrate it on the following simple example. First, let us use sin function with some random noise:
 @verbatim
@@ -2428,9 +2607,10 @@ text 0 2.2 'initial: y = 0.3+sin(2\pi x)' 'b'
 @pfig{fit, Example of nonlinear fitting.}
 
 @c ------------------------------------------------------------------
- at c @external{}
- at node PDE solving hints, MGL parser using, Nonlinear fitting sample, Hints
+ at external{}
+ at node PDE solving hints, MGL parser using, Nonlinear fitting hints, Hints
 @subsection PDE solving hints
+ at nav{}
 
 Solving of Partial Differential Equations (PDE, including beam tracing) and ray tracing (or finding particle trajectory) are more or less common task. So, MathGL have several functions for that. There are @code{mglRay()} for ray tracing, @code{mglPDE()} for PDE solving, @code{mglQO2d()} for beam tracing in 2D case (see @ref{Global functions}). Note, that these functions take ``Hamiltonian'' or equations as string values. And I don't plan now to allow one to use user-defined functions. Th [...]
 
@@ -2482,9 +2662,10 @@ text 0.7 -0.05 'central ray'
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node MGL parser using, Using options, PDE solving hints, Hints
 @subsection MGL parser using
+ at nav{}
 
 MGL scripts can contain loops, conditions and user-defined functions. Below I show very simple example of its usage:
 @verbatim
@@ -2508,9 +2689,10 @@ next
 @pfig{parser, Example of MGL script parsing.}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Using options, ``Templates'', MGL parser using, Hints
 @subsection Using options
+ at nav{}
 
 @ref{Command options} allow the easy setup of the selected plot by changing global settings only for this plot. Often, options are used for specifying the range of automatic variables (coordinates). However, options allows easily change plot transparency, numbers of line or faces to be drawn, or add legend entries. The sample function for options usage is:
 @verbatim
@@ -2537,9 +2719,10 @@ box:axis:legend 2
 @pfig{mirror, Example of options usage.}
 
 @c ------------------------------------------------------------------
- at c @external{}
- at node ``Templates'', Nonlinear fitting sample, Using options, Hints
+ at external{}
+ at node ``Templates'', Nonlinear fitting hints, Using options, Hints
 @subsection ``Templates''
+ at nav{}
 
 As I have noted before, the change of settings will influence only for the further plotting commands. This allows one to create ``template'' function which will contain settings and primitive drawing for often used plots. Correspondingly one may call this template-function for drawing simplification.
 
@@ -2569,9 +2752,10 @@ A template-function can also contain settings for font, transparency, lightning,
 I understand that this is obvious thing for any professional programmer, but I several times receive suggestion about ``templates'' ... So, I decide to point out it here.
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Stereo image, Reduce memory usage, ``Templates'', Hints
 @subsection Stereo image
+ at nav{}
 
 One can easily create stereo image in MathGL. Stereo image can be produced by making two subplots with slightly different rotation angles. The corresponding code looks like this:
 @verbatim
@@ -2584,9 +2768,10 @@ subplot 2 1 1:rotate 50 60-1:box:surf a
 @pfig{stereo, Example of stereo image.}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Reduce memory usage, , Stereo image, Hints
 @subsection Reduce memory usage
+ at nav{}
 
 By default MathGL save all primitives in memory, rearrange it and only later draw them on bitmaps. Usually, this speed up drawing, but may require a lot of memory for plots which contain a lot of faces (like @ref{cloud}, @ref{dew}). You can use @ref{quality} function for setting to use direct drawing on bitmap and bypassing keeping any primitives in memory. This function also allow you to decrease the quality of the resulting image but increase the speed of the drawing.
 
@@ -2603,6 +2788,7 @@ next
 @external{}
 @node FAQ, , Hints, Examples
 @section FAQ
+ at nav{}
 
 @table @strong
 @item The plot does not appear
@@ -2646,4 +2832,3 @@ Just use @code{aspect nan nan} for each subplot, or at the beginning of the draw
 @end table
 
 @external{}
-
diff --git a/texinfo/ex_mgl_ru.texi b/texinfo/ex_mgl_ru.texi
index 3c9f65f..c97475d 100644
--- a/texinfo/ex_mgl_ru.texi
+++ b/texinfo/ex_mgl_ru.texi
@@ -1,5 +1,6 @@
 @c ------------------------------------------------------------------
 @chapter MathGL examples
+ at nav{}
 
 This chapter contain information about basic and advanced MathGL, hints and samples for all types of graphics. I recommend you read first 2 sections one after another and at least look on @ref{Hints} section. Also I recommend you to look at @ref{General concepts} and @ref{FAQ}.
 
@@ -58,6 +59,7 @@ Basically, you can put this text after the script. Note, that you need to termin
 @external{}
 @node Basic usage, Advanced usage, , Examples
 @section Basic usage
+ at nav{}
 
 MGL script can be used by several manners. Each has positive and negative sides:
 @itemize @bullet
@@ -98,6 +100,7 @@ Just type it in UDAV and press F5. Also you can save it in text file @samp{test.
 @external{}
 @node Advanced usage, Data handling, Basic usage, Examples
 @section Advanced usage
+ at nav{}
 
 Now I show several non-obvious features of MGL: several subplots in a single picture, curvilinear coordinates, text printing and so on. Generally you may miss this section at first reading, but I don't recommend it.
 
@@ -114,9 +117,10 @@ Now I show several non-obvious features of MGL: several subplots in a single pic
 @end menu
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Subplots, Axis and ticks, , Advanced usage
 @subsection Subplots
+ at nav{}
 
 Let me demonstrate possibilities of plot positioning and rotation. MathGL has a set of functions: @ref{subplot}, @ref{inplot}, @ref{title}, @ref{aspect} and @ref{rotate} and so on (see @ref{Subplots and rotation}). The order of their calling is strictly determined. First, one changes the position of plot in image area (functions @ref{subplot}, @ref{inplot} and @ref{multiplot}). Secondly, you can add the title of plot by @ref{title} function. After that one may rotate the plot (command @r [...]
 @verbatim
@@ -167,9 +171,10 @@ multiplot 3 2 1 2 1 '':title 'MultiPlot':box
 @pfig{inplot, Example for most of positioning functions.}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Axis and ticks, Curvilinear coordinates, Subplots, Advanced usage
 @subsection Axis and ticks
+ at nav{}
 
 MathGL library can draw not only the bounding box but also the axes, grids, labels and so on. The ranges of axes and their origin (the point of intersection) are determined by functions @code{SetRange()}, @code{SetRanges()}, @code{SetOrigin()} (see @ref{Ranges (bounding box)}). Ticks on axis are specified by function @code{SetTicks}, @code{SetTicksVal}, @code{SetTicksTime} (see @ref{Ticks}). But usually
 
@@ -272,9 +277,10 @@ xlabel 'x' 1:ylabel 'y = x' 0
 You can see that MathGL automatically switch to log-ticks as we define log-axis formula (in difference from v.1.*). Moreover, it switch to log-ticks for any formula if axis range will be large enough (see right bottom plot). Another interesting feature is that you not necessary define usual log-axis (i.e. when coordinates are positive), but you can define ``minus-log'' axis when coordinate is negative (see left bottom plot).
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Curvilinear coordinates, Colorbars, Axis and ticks, Advanced usage
 @subsection Curvilinear coordinates
+ at nav{}
 
 As I noted in previous subsection, MathGL support curvilinear coordinates. In difference from other plotting programs and libraries, MathGL uses textual formulas for connection of the old (data) and new (output) coordinates. This allows one to plot in arbitrary coordinates. The following code plots the line @var{y}=0, @var{z}=0 in Cartesian, polar, parabolic and spiral coordinates:
 @verbatim
@@ -299,9 +305,10 @@ fplot '2*t-1' '0.5' '0' '2r':axis:grid
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Colorbars, Bounding box, Curvilinear coordinates, Advanced usage
 @subsection Colorbars
+ at nav{}
 
 MathGL handle @ref{colorbar} as special kind of axis. So, most of functions for axis and ticks setup will work for colorbar too. Colorbars can be in log-scale, and generally as arbitrary function scale; common factor of colorbar labels can be separated; and so on.
 
@@ -333,9 +340,10 @@ colorbar '>':text 1.35 1.2 'Log scale'
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Bounding box, Ternary axis, Colorbars, Advanced usage
 @subsection Bounding box
+ at nav{}
 
 Box around the plot is rather useful thing because it allows one to: see the plot boundaries, and better estimate points position since box contain another set of ticks. MathGL provide special function for drawing such box -- @ref{box} function. By default, it draw black or white box with ticks (color depend on transparency type, see @ref{Types of transparency}). However, you can change the color of box, or add drawing of rectangles at rear faces of box. Also you can disable ticks drawin [...]
 @verbatim
@@ -352,9 +360,10 @@ subplot 2 2 3:title 'both':rotate 50 60:box '@cm'
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Ternary axis, Text features, Bounding box, Advanced usage
 @subsection Ternary axis
+ at nav{}
 
 There are another unusual axis types which are supported by MathGL. These are ternary and quaternary axis. Ternary axis is special axis of 3 coordinates @var{a}, @var{b}, @var{c} which satisfy relation @var{a}+ at var{b}+ at var{c}=1. Correspondingly, quaternary axis is special axis of 4 coordinates @var{a}, @var{b}, @var{c}, @var{d} which satisfy relation @var{a}+ at var{b}+ at var{c}+ at var{d}=1.
 
@@ -392,9 +401,10 @@ xlabel 'B':ylabel 'C':tlabel 'A':zlabel 'Z'
 @pfig{ternary, Ternary and Quaternary axis}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Text features, Legend sample, Ternary axis, Advanced usage
 @subsection Text features
+ at nav{}
 
 MathGL prints text by vector font. There are functions for manual specifying of text position (like @code{Puts}) and for its automatic selection (like @code{Label}, @code{Legend} and so on). MathGL prints text always in specified position even if it lies outside the bounding box. The default size of font is specified by functions @var{SetFontSize*} (see @ref{Font settings}). However, the actual size of output string depends on subplot size (depends on functions @code{SubPlot}, @code{InPl [...]
 
@@ -446,9 +456,10 @@ loadfont 'termes':text 0 1.1-9*d 'termes font'
 @pfig{fonts, Example of font faces}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Legend sample, Cutting sample, Text features, Advanced usage
 @subsection Legend sample
+ at nav{}
 
 Legend is one of standard ways to show plot annotations. Basically you need to connect the plot style (line style, marker and color) with some text. In MathGL, you can do it by 2 methods: manually using @ref{addlegend} function; or use @samp{legend} option (see @ref{Command options}), which will use last plot style. In both cases, legend entries will be added into internal accumulator, which later used for legend drawing itself. @ref{clearlegend} function allow you to remove all saved le [...]
 
@@ -479,9 +490,10 @@ legend 1 '#-':text 0.75 0.25 'Horizontal legend' 'a'
 @pfig{legend, Example of legend}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Cutting sample, , Legend sample, Advanced usage
 @subsection Cutting sample
+ at nav{}
 
 The last common thing which I want to show in this section is how one can cut off points from plot. There are 4 mechanism for that.
 @itemize @bullet
@@ -525,6 +537,7 @@ cut '(z>(x+0.5*y-1)^2-1) & (z>(x-0.5*y-1)^2-1)':surf3 c
 @external{}
 @node Data handling, Data plotting, Advanced usage, Examples
 @section Data handling
+ at nav{}
 
 Class @code{mglData} contains all functions for the data handling in MathGL (@pxref{Data processing}). There are several matters why I use class @code{mglData} but not a single array: it does not depend on type of data (mreal or double), sizes of data arrays are kept with data, memory working is simpler and safer.
 
@@ -534,9 +547,10 @@ Class @code{mglData} contains all functions for the data handling in MathGL (@px
 @end menu
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Array creation, Change data, , Data handling
 @subsection Array creation
+ at nav{}
 
 One can put numbers into the data instance by several ways. Let us do it for square function:
 @itemize @bullet
@@ -610,9 +624,10 @@ new z 30 40 'sin(pi*x)*cos(pi*y)'
 or loaded from a file.
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Change data, , Array creation, Data handling
 @subsection Change data
+ at nav{}
 
 MathGL has functions for data processing: differentiating, integrating, smoothing and so on (for more detail, see @ref{Data processing}). Let us consider some examples. The simplest ones are integration and differentiation. The direction in which operation will be performed is specified by textual string, which may contain symbols @samp{x}, @samp{y} or @samp{z}. For example, the call of @code{diff 'x'} will differentiate data along @samp{x} direction; the call of @code{integrate 'xy'} pe [...]
 @verbatim
@@ -719,6 +734,7 @@ plot v1 u2 'r2v':line 0.5 0.7 0.5 0.85 'rA'
 @external{}
 @node Data plotting, 1D samples, Data handling, Examples
 @section Data plotting
+ at nav{}
 
 Let me now show how to plot the data. Next section will give much more examples for all plotting functions. Here I just show some basics. MathGL generally has 2 types of plotting functions. Simple variant requires a single data array for plotting, other data (coordinates) are considered uniformly distributed in axis range. Second variant requires data arrays for all coordinates. It allows one to plot rather complex multivalent curves and surfaces (in case of parametric dependencies). Usu [...]
 
@@ -810,6 +826,7 @@ Drawing of other 2D plots is analogous. The only peculiarity is the usage of fla
 @external{}
 @node 1D samples, 2D samples, Data plotting, Examples
 @section 1D samples
+ at nav{}
 
 This section is devoted to visualization of 1D data arrays. 1D means the data which depend on single index (parameter) like curve in parametric form @{x(i),y(i),z(i)@}, i=1...n. Most of samples will use the same data for plotting. So, I put its initialization in separate function
 @verbatim
@@ -840,6 +857,7 @@ Basically, you can put this text after the script. Note, that you need to termin
 * Chart sample::
 * BoxPlot sample::
 * Candle sample::
+* OHLC sample::
 * Error sample::
 * Mark sample::
 * TextMark sample::
@@ -852,9 +870,10 @@ Basically, you can put this text after the script. Note, that you need to termin
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Plot sample, Radar sample, , 1D samples
 @subsection Plot sample
+ at nav{}
 
 Command @ref{plot} is most standard way to visualize 1D data array. By default, @code{Plot} use colors from palette. However, you can specify manual color/palette, and even set to use new color for each points by using @samp{!} style. Another feature is @samp{ } style which draw only markers without line between points. The sample code is:
 @verbatim
@@ -877,9 +896,10 @@ plot xc yc z 'rs'
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Radar sample, Step sample, Plot sample, 1D samples
 @subsection Radar sample
+ at nav{}
 
 Command @ref{radar} plot is variant of @code{Plot} one, which make plot in polar coordinates and draw radial rays in point directions. If you just need a plot in polar coordinates then I recommend to use @ref{Curvilinear coordinates} or @code{Plot} in parabolic form with @code{x=r*cos(fi); y=r*sin(fi);}. The sample code is:
 @verbatim
@@ -891,9 +911,10 @@ radar yr '#'
 @pfig{radar, Example of Radar()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Step sample, Tens sample, Radar sample, 1D samples
 @subsection Step sample
+ at nav{}
 
 Command @ref{step} plot data as stairs. It have the same options as @code{Plot}. The sample code is:
 @verbatim
@@ -912,9 +933,10 @@ step y 's!rgb'
 @pfig{step, Example of Step()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Tens sample, Area sample, Step sample, 1D samples
 @subsection Tens sample
+ at nav{}
 
 Command @ref{tens} is variant of @ref{plot} with smooth coloring along the curves. At this, color is determined as for surfaces (see @ref{Color scheme}). The sample code is:
 @verbatim
@@ -933,9 +955,10 @@ tens xc yc z z 's'
 @pfig{tens, Example of Tens()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Area sample, Region sample, Tens sample, 1D samples
 @subsection Area sample
+ at nav{}
 
 Command @ref{area} fill the area between curve and axis plane. It support gradient filling if 2 colors per curve is specified. The sample code is:
 @verbatim
@@ -958,9 +981,10 @@ area xc yc z 'r':area xc -yc z 'b#'
 @pfig{area, Example of Area()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Region sample, Stem sample, Area sample, 1D samples
 @subsection Region sample
+ at nav{}
 
 Command @ref{region} fill the area between 2 curves. It support gradient filling if 2 colors per curve is specified. Also it can fill only the region y1<y<y2 if style @samp{i} is used. The sample code is:
 @verbatim
@@ -982,9 +1006,10 @@ region y1 y2 'ir':plot y1 'k2':plot y2 'k2'
 @pfig{region, Example of Region()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Stem sample, Bars sample, Region sample, 1D samples
 @subsection Stem sample
+ at nav{}
 
 Command @ref{stem} draw vertical bars. It is most attractive if markers are drawn too. The sample code is:
 @verbatim
@@ -1003,9 +1028,10 @@ stem y 'o!rgb'
 @pfig{stem, Example of Stem()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Bars sample, Barh sample, Stem sample, 1D samples
 @subsection Bars sample
+ at nav{}
 
 Command @ref{bars} draw vertical bars. It have a lot of options: bar-above-bar (@samp{a} style), fall like (@samp{f} style), 2 colors for positive and negative values, wired bars (@samp{#} style), 3D variant. The sample code is:
 @verbatim
@@ -1033,9 +1059,10 @@ bars ys 'f'
 @pfig{bars, Example of Bars()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Barh sample, Cones sample, Bars sample, 1D samples
 @subsection Barh sample
+ at nav{}
 
 Command @ref{barh} is the similar to @code{Bars} but draw horizontal bars. The sample code is:
 @verbatim
@@ -1054,33 +1081,41 @@ barh ys 'f'
 @pfig{barh, Example of Barh()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Cones sample, Chart sample, Bars sample, 1D samples
 @subsection Cones sample
+ at nav{}
 
 Command @ref{cones} is similar to @code{Bars} but draw cones. The sample code is:
 @verbatim
 new ys 10 3 '0.8*sin(pi*(x+y/4+1.25))+0.2*rnd'
 origin 0 0 0:light on
-subplot 2 2 0:title 'Cones plot':rotate 50 60:box
+subplot 3 2 0:title 'Cones plot':rotate 50 60:box
 cones ys
 
-subplot 2 2 1:title '2 colors':rotate 50 60:box
+subplot 3 2 1:title '2 colors':rotate 50 60:box
 cones ys 'cbgGyr'
 
-subplot 2 2 2:title '"\#" style':rotate 50 60:box
+subplot 3 2 2:title '"\#" style':rotate 50 60:box
 cones ys '#'
 
-subplot 2 2 3:title '"a" style':rotate 50 60:zrange -2 2:box
+subplot 3 2 3:title '"a" style':rotate 50 60:zrange -2 2:box
 cones ys 'a'
+
+subplot 3 2 4:title '"t" style':rotate 50 60:box
+cones ys 't'
+
+subplot 3 2 5:title '"4" style':rotate 50 60:box
+cones ys '4'
 @end verbatim
 
 @pfig{cones, Example of Cones()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Chart sample, BoxPlot sample, Cones sample, 1D samples
 @subsection Chart sample
+ at nav{}
 
 Command @ref{chart} draw colored boxes with width proportional to data values. Use @samp{ } for empty box. Plot looks most attractive in polar coordinates -- well known pie chart. The sample code is:
 @verbatim
@@ -1103,9 +1138,10 @@ chart ch 'bgr cmy#'
 @pfig{chart, Example of Chart()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node BoxPlot sample, Candle sample, Chart sample, 1D samples
 @subsection BoxPlot sample
+ at nav{}
 
 Command @ref{boxplot} draw box-and-whisker diagram. The sample code is:
 @verbatim
@@ -1117,9 +1153,10 @@ boxplot a
 @pfig{boxplot, Example of BoxPlot()}
 
 @c ------------------------------------------------------------------
- at c @external{}
- at node Candle sample, Error sample, BoxPlot sample, 1D samples
+ at external{}
+ at node Candle sample, OHLC sample, BoxPlot sample, 1D samples
 @subsection Candle sample
+ at nav{}
 
 Command @ref{candle} draw candlestick chart. This is a combination of a line-chart and a bar-chart, in that each bar represents the range of price movement over a given time interval. The sample code is:
 @verbatim
@@ -1131,9 +1168,28 @@ candle y y1 y2
 @pfig{candle, Example of Candle()}
 
 @c ------------------------------------------------------------------
- at c @external{}
- at node Error sample, Mark sample, Candle sample, 1D samples
+ at external{}
+ at node OHLC sample, Error sample, Candle sample, 1D samples
+ at subsection OHLC sample
+ at nav{}
+
+Command @ref{ohlc} draw Open-High-Low-Close diagram. This diagram show vertical line for between maximal(high) and minimal(low) values, as well as horizontal lines before/after vertical line for initial(open)/final(close) values of some process. The sample code is:
+ at verbatim
+new o 10 '0.5*sin(pi*x)'
+new c 10 '0.5*sin(pi*(x+2/9))'
+new l 10 '0.3*rnd-0.8'
+new h 10 '0.3*rnd+0.5'
+subplot 1 1 0 '':title 'OHLC plot':box
+ohlc o h l c
+ at end verbatim
+
+ at pfig{candle, Example of OHLC()}
+
+ at c ------------------------------------------------------------------
+ at external{}
+ at node Error sample, Mark sample, OHLC sample, 1D samples
 @subsection Error sample
+ at nav{}
 
 Command @ref{error} draw error boxes around the points. You can draw default boxes or semi-transparent symbol (like marker, see @ref{Line styles}). Also you can set individual color for each box. The sample code is:
 @verbatim
@@ -1159,10 +1215,32 @@ next
 
 @pfig{error, Example of Error()}
 
+Additionally, you can use solid large "marks" instead of error boxes by selecting proper style.
+ at verbatim
+new x0 10 'rnd':new ex 10 '0.1'
+new y0 10 'rnd':new ey 10 '0.1'
+ranges 0 1 0 1
+subplot 4 3 0 '':box:error x0 y0 ex ey '#+@'
+subplot 4 3 1 '':box:error x0 y0 ex ey '#x@'
+subplot 4 3 2 '':box:error x0 y0 ex ey '#s@'; alpha 0.5
+subplot 4 3 3 '':box:error x0 y0 ex ey 's@'
+subplot 4 3 4 '':box:error x0 y0 ex ey 'd@'
+subplot 4 3 5 '':box:error x0 y0 ex ey '#d@'; alpha 0.5
+subplot 4 3 6 '':box:error x0 y0 ex ey '+@'
+subplot 4 3 7 '':box:error x0 y0 ex ey 'x@'
+subplot 4 3 8 '':box:error x0 y0 ex ey 'o@'
+subplot 4 3 9 '':box:error x0 y0 ex ey '#o@'; alpha 0.5
+subplot 4 3 10 '':box:error x0 y0 ex ey '#.@'
+subplot 4 3 11 '':box:error x0 y0 ex ey; alpha 0.5
+ at end verbatim
+
+ at pfig{error2, Example of Error() with marks}
+
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Mark sample, TextMark sample, Error sample, 1D samples
 @subsection Mark sample
+ at nav{}
 
 Command @ref{mark} draw markers at points. It is mostly the same as @code{Plot} but marker size can be variable. The sample code is:
 @verbatim
@@ -1174,9 +1252,10 @@ mark y y1 's'
 @pfig{mark, Example of Mark()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node TextMark sample, Label sample, Mark sample, 1D samples
 @subsection TextMark sample
+ at nav{}
 
 Command @ref{textmark} like @code{Mark} but draw text instead of markers. The sample code is:
 @verbatim
@@ -1188,9 +1267,10 @@ textmark y y1 '\gamma' 'r'
 @pfig{textmark, Example of TextMark()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Label sample, Table sample, TextMark sample, 1D samples
 @subsection Label sample
+ at nav{}
 
 Command @ref{label} print text at data points. The string may contain @samp{%x}, @samp{%y}, @samp{%z} for x-, y-, z-coordinates of points, @samp{%n} for point index. The sample code is:
 @verbatim
@@ -1203,9 +1283,10 @@ plot ys ' *':label ys 'y=%y'
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Table sample, Tube sample, Label sample, 1D samples
 @subsection Table sample
+ at nav{}
 
 Command @ref{table} draw table with data values. The sample code is:
 @verbatim
@@ -1227,9 +1308,10 @@ table 0.5 0.95 ys 'y_1\n{}y_2\n{}y_3' '#';value 0.7
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Tube sample, Tape sample, Table sample, 1D samples
 @subsection Tube sample
+ at nav{}
 
 Command @ref{tube} draw tube with variable radius. The sample code is:
 @verbatim
@@ -1253,9 +1335,10 @@ tube xc yc z y2 'r'
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Tape sample, Torus sample, Tube sample, 1D samples
 @subsection Tape sample
+ at nav{}
 
 Command @ref{tape} draw tapes which rotate around the curve as normal and binormal. The sample code is:
 @verbatim
@@ -1279,9 +1362,10 @@ plot xc yc z 'k':tape xc yc z 'zg':tape xc yc z 'zg#'
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Torus sample, , Tape sample, 1D samples
 @subsection Torus sample
+ at nav{}
 
 Command @ref{torus} draw surface of the curve rotation. The sample code is:
 @verbatim
@@ -1306,6 +1390,7 @@ torus y1 y2 '#'
 @external{}
 @node 2D samples, 3D samples, 1D samples, Examples
 @section 2D samples
+ at nav{}
 
 This section is devoted to visualization of 2D data arrays. 2D means the data which depend on 2 indexes (parameters) like matrix z(i,j)=z(x(i),y(j)), i=1...n, j=1...m or in parametric form @{x(i,j),y(i,j),z(i,j)@}. Most of samples will use the same data for plotting. So, I put its initialization in separate function
 @verbatim
@@ -1336,9 +1421,10 @@ Basically, you can put this text after the script. Note, that you need to termin
 @end menu
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Surf sample, SurfC sample, , 2D samples
 @subsection Surf sample
+ at nav{}
 
 Command @ref{surf} is most standard way to visualize 2D data array. @code{Surf} use color scheme for coloring (see @ref{Color scheme}). You can use @samp{#} style for drawing black meshes on the surface. The sample code is:
 @verbatim
@@ -1361,9 +1447,10 @@ surf x y z 'BbwrR'
 @pfig{surf, Example of Surf()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node SurfC sample, SurfA sample, Surf sample, 2D samples
 @subsection SurfC sample
+ at nav{}
 
 Command @ref{surfc} is similar to @ref{surf} but its coloring is determined by another data. The sample code is:
 @verbatim
@@ -1375,9 +1462,10 @@ surfc a b
 @pfig{surfc, Example of SurfC()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node SurfA sample, Mesh sample, SurfC sample, 2D samples
 @subsection SurfA sample
+ at nav{}
 
 Command @ref{surfa} is similar to @ref{surf} but its transparency is determined by another data. The sample code is:
 @verbatim
@@ -1390,9 +1478,10 @@ surfa a b
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Mesh sample, Fall sample, SurfA sample, 2D samples
 @subsection Mesh sample
+ at nav{}
 
 Command @ref{mesh} draw wired surface. You can use @ref{meshnum} for changing number of lines to be drawn. The sample code is:
 @verbatim
@@ -1404,9 +1493,10 @@ mesh a
 @pfig{mesh, Example of Mesh()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Fall sample, Belt sample, Mesh sample, 2D samples
 @subsection Fall sample
+ at nav{}
 
 Command @ref{fall} draw waterfall surface. You can use @ref{meshnum} for changing number of lines to be drawn. Also you can use @samp{x} style for drawing lines in other direction. The sample code is:
 @verbatim
@@ -1418,9 +1508,10 @@ fall a
 @pfig{fall, Example of Fall()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Belt sample, Boxs sample, Fall sample, 2D samples
 @subsection Belt sample
+ at nav{}
 
 Command @ref{belt} draw surface by belts. You can use @samp{x} style for drawing lines in other direction. The sample code is:
 @verbatim
@@ -1432,9 +1523,10 @@ belt a
 @pfig{belt, Example of Belt()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Boxs sample, Tile sample, Fall sample, 2D samples
 @subsection Boxs sample
+ at nav{}
 
 Command @ref{boxs} draw surface by boxes. You can use @samp{#} for drawing wire plot. The sample code is:
 @verbatim
@@ -1456,9 +1548,10 @@ tile a
 @pfig{boxs, Example of Boxs()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Tile sample, TileS sample, Boxs sample, 2D samples
 @subsection Tile sample
+ at nav{}
 
 Command @ref{tile} draw surface by tiles. The sample code is:
 @verbatim
@@ -1470,9 +1563,10 @@ tile a
 @pfig{tile, Example of Tile()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node TileS sample, Dens sample, Tile sample, 2D samples
 @subsection TileS sample
+ at nav{}
 
 Command @ref{tiles} is similar to @ref{tile} but tile sizes is determined by another data. This allows one to simulate transparency of the plot. The sample code is:
 @verbatim
@@ -1485,9 +1579,10 @@ tiles a b
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Dens sample, Cont sample, TileS sample, 2D samples
 @subsection Dens sample
+ at nav{}
 
 Command @ref{dens} draw density plot for surface. The sample code is:
 @verbatim
@@ -1510,9 +1605,10 @@ dens a1
 @pfig{dens, Example of Dens()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Cont sample, ContF sample, Dens sample, 2D samples
 @subsection Cont sample
+ at nav{}
 
 Command @ref{cont} draw contour lines for surface. You can select automatic (default) or manual levels for contours, print contour labels, draw it on the surface (default) or at plane (as @code{Dens}). The sample code is:
 @verbatim
@@ -1534,9 +1630,10 @@ cont a 't'
 @pfig{cont, Example of Cont()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node ContF sample, ContD sample, Cont sample, 2D samples
 @subsection ContF sample
+ at nav{}
 
 Command @ref{contf} draw filled contours.  You can select automatic (default) or manual levels for contours. The sample code is:
 @verbatim
@@ -1560,9 +1657,10 @@ contf a1
 @pfig{contf, Example of ContF()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node ContD sample, ContV sample, ContF sample, 2D samples
 @subsection ContD sample
+ at nav{}
 
 Command @ref{contd} is similar to @code{ContF} but with manual contour colors. The sample code is:
 @verbatim
@@ -1586,9 +1684,10 @@ contd a1
 @pfig{contd, Example of ContD()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node ContV sample, Axial sample, ContD sample, 2D samples
 @subsection ContV sample
+ at nav{}
 
 Command @ref{contv} draw vertical cylinders (belts) at contour lines. The sample code is:
 @verbatim
@@ -1610,9 +1709,10 @@ contv a:contf a:cont a 'k'
 @pfig{contv, Example of ContV()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Axial sample, Grad sample, ContV sample, 2D samples
 @subsection Axial sample
+ at nav{}
 
 Command @ref{axial} draw surfaces of rotation for contour lines. You can draw wire surfaces (@samp{#} style) or ones rotated in other directions (@samp{x}, @samp{z} styles). The sample code is:
 @verbatim
@@ -1633,9 +1733,10 @@ axial a '#'
 @pfig{axial, Example of Axial()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Grad sample, , Axial sample, 2D samples
 @subsection Grad sample
+ at nav{}
 
 Command @ref{grad} draw gradient lines for matrix. The sample code is:
 @verbatim
@@ -1651,6 +1752,7 @@ grad a:dens a '{u8}w{q8}'
 @external{}
 @node 3D samples, Vector field samples, 2D samples, Examples
 @section 3D samples
+ at nav{}
 
 This section is devoted to visualization of 3D data arrays. 3D means the data which depend on 3 indexes (parameters) like tensor a(i,j,k)=a(x(i),y(j),x(k)), i=1...n, j=1...m, k=1...l or in parametric form @{x(i,j,k),y(i,j,k),z(i,j,k),a(i,j,k)@}. Most of samples will use the same data for plotting. So, I put its initialization in separate function
 @verbatim
@@ -1677,9 +1779,10 @@ Basically, you can put this text after the script. Note, that you need to termin
 @end menu
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Surf3 sample, Surf3C sample, , 3D samples
 @subsection Surf3 sample
+ at nav{}
 
 Command @ref{surf3} is one of most suitable (for my opinion) functions to visualize 3D data. It draw the isosurface(s) -- surface(s) of constant amplitude (3D analogue of contour lines). You can draw wired isosurfaces if specify @samp{#} style. The sample code is:
 @verbatim
@@ -1698,9 +1801,10 @@ surf3 c '.'
 @pfig{surf3, Example of Surf3()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Surf3C sample, Surf3A sample, Surf3 sample, 3D samples
 @subsection Surf3C sample
+ at nav{}
 
 Command @ref{surf3c} is similar to @ref{surf3} but its coloring is determined by another data. The sample code is:
 @verbatim
@@ -1712,9 +1816,10 @@ surf3c c d
 @pfig{surf3c, Example of Surf3C()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Surf3A sample, Cloud sample, Surf3C sample, 3D samples
 @subsection Surf3A sample
+ at nav{}
 
 Command @ref{surf3a} is similar to @ref{surf3} but its transparency is determined by another data. The sample code is:
 @verbatim
@@ -1726,9 +1831,10 @@ surf3a c d
 @pfig{surf3a, Example of Surf3A()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Cloud sample, Dens3 sample, Surf3A sample, 3D samples
 @subsection Cloud sample
+ at nav{}
 
 Command @ref{cloud} draw cloud-like object which is less transparent for higher data values. Similar plot can be created using many (about 10-20) @code{Surf3A(a,a)} isosurfaces. The sample code is:
 @verbatim
@@ -1736,8 +1842,8 @@ call 'prepare3d'
 subplot 2 2 0:title 'Cloud plot':rotate 50 60:alpha on:box
 cloud c 'wyrRk'
 
-subplot 2 2 1:title '"!" style':rotate 50 60:box
-cloud c '!wyrRk'
+subplot 2 2 1:title '"i" style':rotate 50 60:box
+cloud c 'iwyrRk'
 
 subplot 2 2 2:title '"." style':rotate 50 60:box
 cloud c '.wyrRk'
@@ -1749,9 +1855,10 @@ cloud c 'wyrRk'; meshnum 10
 @pfig{cloud, Example of Cloud()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Dens3 sample, Cont3 sample, Cloud sample, 3D samples
 @subsection Dens3 sample
+ at nav{}
 
 Command @ref{dens3} draw just usual density plot but at slices of 3D data. The sample code is:
 @verbatim
@@ -1764,9 +1871,10 @@ dens3 c 'x':dens3 c ':y':dens3 c 'z'
 @pfig{densa, Example of Dens3()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Cont3 sample, ContF3 sample, Dens3 sample, 3D samples
 @subsection Cont3 sample
+ at nav{}
 
 Command @ref{cont3} draw just usual contour lines but at slices of 3D data. The sample code is:
 @verbatim
@@ -1778,9 +1886,10 @@ cont3 c 'x':cont3 c:cont3 c 'z'
 @pfig{conta, Example of Cont3()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node ContF3 sample, Dens projection sample, Cont3 sample, 3D samples
 @subsection ContF3 sample
+ at nav{}
 
 Command @ref{contf3} draw just usual filled contours but at slices of 3D data. The sample code is:
 @verbatim
@@ -1793,11 +1902,12 @@ cont3 c 'xk':cont3 c 'k':cont3 c 'zk'
 @pfig{contfa, Example of ContF3()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Dens projection sample, Cont projection sample, ContF3 sample, 3D samples
 @subsection Dens projection sample
+ at nav{}
 
-Functions @ref{DensXYZ} draw density plot on plane perpendicular to corresponding axis. One of possible application is drawing projections of 3D field. The sample code is:
+Functions @ref{densz}, @ref{densy}, @ref{densx} draw density plot on plane perpendicular to corresponding axis. One of possible application is drawing projections of 3D field. The sample code is:
 @verbatim
 call 'prepare3d'
 title 'Dens[XYZ] sample':rotate 50 60:box
@@ -1806,14 +1916,15 @@ densy {sum c 'y'} '' 1
 densz {sum c 'z'} '' -1
 @end verbatim
 
- at pfig{dens_xyz, {Example of DensX(), DensY(), DensZ()}}
+ at pfig{dens_xyz, Example of DensX() DensY() DensZ()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Cont projection sample, ContF projection sample, Dens projection sample, 3D samples
 @subsection Cont projection sample
+ at nav{}
 
-Functions @ref{ContXYZ} draw contour lines on plane perpendicular to corresponding axis. One of possible application is drawing projections of 3D field. The sample code is:
+Functions @ref{contz}, @ref{conty}, @ref{contx} draw contour lines on plane perpendicular to corresponding axis. One of possible application is drawing projections of 3D field. The sample code is:
 @verbatim
 call 'prepare3d'
 title 'Cont[XYZ] sample':rotate 50 60:box
@@ -1822,14 +1933,15 @@ conty {sum c 'y'} '' 1
 contz {sum c 'z'} '' -1
 @end verbatim
 
- at pfig{cont_xyz, {Example of ContX(), ContY(), ContZ()}}
+ at pfig{cont_xyz, Example of ContX() ContY() ContZ()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node ContF projection sample, TriPlot and QuadPlot, Cont projection sample, 3D samples
 @subsection ContF projection sample
+ at nav{}
 
-Functions @code{ContFXYZ} draw filled contours on plane perpendicular to corresponding axis. One of possible application is drawing projections of 3D field. The sample code is:
+Functions @ref{contfz}, @ref{contfy}, @ref{contfx} draw filled contours on plane perpendicular to corresponding axis. One of possible application is drawing projections of 3D field. The sample code is:
 @verbatim
 call 'prepare3d'
 title 'ContF[XYZ] sample':rotate 50 60:box
@@ -1838,12 +1950,13 @@ contfy {sum c 'y'} '' 1
 contfz {sum c 'z'} '' -1
 @end verbatim
 
- at pfig{contf_xyz, {Example of ContFX(), ContFY(), ContFZ()}}
+ at pfig{contf_xyz, Example of ContFX() ContFY() ContFZ()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node TriPlot and QuadPlot, Axial sample, ContF projection sample, 3D samples
 @subsection TriPlot and QuadPlot
+ at nav{}
 
 Command @ref{triplot} and @ref{quadplot} draw set of triangles (or quadrangles for @code{QuadPlot}) for irregular data arrays. Note, that you have to provide not only vertexes, but also the indexes of triangles or quadrangles. I.e. perform triangulation by some other library. The sample code is:
 @verbatim
@@ -1877,9 +1990,10 @@ tricont t xt yt zt 'B'
 @pfig{triplot, Example of TriPlot() and QuadPlot()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Dots sample, , TriPlot and QuadPlot, 3D samples
 @subsection Dots sample
+ at nav{}
 
 Command @ref{dots} is another way to draw irregular points. @code{Dots} use color scheme for coloring (see @ref{Color scheme}). The sample code is:
 @verbatim
@@ -1897,6 +2011,7 @@ dots x y z
 @external{}
 @node Vector field samples, Hints, 3D samples, Examples
 @section Vector field samples
+ at nav{}
 
 Vector field visualization (especially in 3d case) is more or less complex task. MathGL provides 3 general types of plots: vector field itself (@code{Vect}), flow threads (@code{Flow}), and flow pipes with radius proportional to field amplitude (@code{Pipe}).
 
@@ -1930,9 +2045,10 @@ Basically, you can put this text after the script. Note, that you need to termin
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Vect sample, Vect3 sample, , Vector field samples
 @subsection Vect sample
+ at nav{}
 
 Command @ref{vect} is most standard way to visualize vector fields -- it draw a lot of arrows or hachures for each data cell. It have a lot of options which can be seen on the figure (and in the sample code). @code{Vect} use color scheme for coloring (see @ref{Color scheme}). The sample code is:
 @verbatim
@@ -1960,9 +2076,10 @@ vect ex ey ez
 @pfig{vect, Example of Vect()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Vect3 sample, Traj sample, Vect sample, Vector field samples
 @subsection Vect3 sample
+ at nav{}
 
 Command @ref{vect3} draw just usual vector field plot but at slices of 3D data. The sample code is:
 @verbatim
@@ -1980,9 +2097,10 @@ grid3 ex 'Wx':grid3 ex 'W':grid3 ex 'Wz'
 @pfig{vecta, Example of Vect3()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Traj sample, Flow sample, Vect3 sample, Vector field samples
 @subsection Traj sample
+ at nav{}
 
 Command @ref{traj} is 1D analogue of @code{Vect}. It draw vectors from specified points. The sample code is:
 @verbatim
@@ -1995,9 +2113,10 @@ plot x1 y:traj x1 y y1 y2
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Flow sample, Pipe sample, Traj sample, Vector field samples
 @subsection Flow sample
+ at nav{}
 
 Command @ref{flow} is another standard way to visualize vector fields -- it draw lines (threads) which is tangent to local vector field direction. MathGL draw threads from edges of bounding box and from central slices. Sometimes it is not most appropriate variant -- you may want to use @code{FlowP} to specify manual position of threads. @code{Flow} use color scheme for coloring (see @ref{Color scheme}). At this warm color corresponds to normal flow (like attractor), cold one corresponds  [...]
 @verbatim
@@ -2019,9 +2138,10 @@ flow ex ey ez
 @pfig{flow, Example of Flow()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Pipe sample, Dew sample, Flow sample, Vector field samples
 @subsection Pipe sample
+ at nav{}
 
 Command @ref{pipe} is similar to @ref{flow} but draw pipes (tubes) which radius is proportional to the amplitude of vector field. @code{Pipe} use color scheme for coloring (see @ref{Color scheme}). At this warm color corresponds to normal flow (like attractor), cold one corresponds to inverse flow (like source). The sample code is:
 @verbatim
@@ -2043,9 +2163,10 @@ pipe ex ey ez '' 0.1
 @pfig{pipe, Example of Pipe()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Dew sample, , Pipe sample, Vector field samples
 @subsection Dew sample
+ at nav{}
 
 Command @ref{dew} is similar to @code{Vect} but use drops instead of arrows. The sample code is:
 @verbatim
@@ -2061,6 +2182,7 @@ dew a b
 @external{}
 @node Hints, FAQ, Vector field samples, Examples
 @section Hints
+ at nav{}
 
 In this section I've included some small hints and advices for the improving of the quality of plots and for the demonstration of some non-trivial features of MathGL library. In contrast to previous examples I showed mostly the idea but not the whole drawing function.
 
@@ -2070,12 +2192,13 @@ In this section I've included some small hints and advices for the improving of
 * Types of transparency::
 * Axis projection::
 * Adding fog::
-* Several light sources::
+* Lighting sample::
 * Using primitives::
 * STFA sample::
 * Mapping visualization::
+* Making regular data::
 * Making histogram::
-* Nonlinear fitting sample::
+* Nonlinear fitting hints::
 * PDE solving hints::
 * MGL parser using::
 * Using options::
@@ -2085,9 +2208,10 @@ In this section I've included some small hints and advices for the improving of
 @end menu
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node ``Compound'' graphics, Transparency and lighting, , Hints
 @subsection ``Compound'' graphics
+ at nav{}
 
 As I noted above, MathGL functions (except the special one, like Clf()) do  not erase the previous plotting but just add the new one. It allows one to draw ``compound'' plots easily. For example, popular Matlab command @code{surfc} can be emulated in MathGL by 2 calls:
 @verbatim
@@ -2139,9 +2263,10 @@ contf3 v c 'z' c.nz-1:surf3 c -0.5
 @pfig{combined, Example of ``combined'' plots}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Transparency and lighting, Types of transparency, ``Compound'' graphics, Hints
 @subsection Transparency and lighting
+ at nav{}
 
 Here I want to show how transparency and lighting both and separately change the look of a surface. So, there is code and picture for that:
 @verbatim
@@ -2162,9 +2287,10 @@ light off:surf a
 @pfig{alpha, Example of transparency and lightings}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Types of transparency, Axis projection, Transparency and lighting, Hints
 @subsection Types of transparency
+ at nav{}
 
 MathGL library has advanced features for setting and handling the surface transparency. The simplest way to add transparency is the using of command @ref{alpha}. As a result, all further surfaces (and isosurfaces, density plots and so on) become transparent. However, their  look can be additionally improved.
 
@@ -2191,9 +2317,10 @@ subplot 2 2 3:rotate 50 60:axial a:box
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Axis projection, Adding fog, Ternary axis, Hints
 @subsection Axis projection
+ at nav{}
 
 You can easily make 3D plot and draw its x-,y-,z-projections (like in CAD) by using @ref{ternary} function with arguments: 4 for Cartesian, 5 for Ternary and 6 for Quaternary coordinates. The sample code is:
 @verbatim
@@ -2214,9 +2341,10 @@ xlabel 'X':ylabel 'Y':zlabel 'Z'
 @pfig{projection, Example of axis projections}
 
 @c ------------------------------------------------------------------
- at c @external{}
- at node Adding fog, Several light sources, Axis projection, Hints
+ at external{}
+ at node Adding fog, Lighting sample, Axis projection, Hints
 @subsection Adding fog
+ at nav{}
 
 MathGL can add a fog to the image. Its switching on is rather simple -- just use @ref{fog} function. There is the only feature -- fog is applied for whole image. Not to particular subplot. The sample code is:
 @verbatim
@@ -2229,9 +2357,10 @@ box:surf a
 @pfig{fog, Example of @code{Fog()}.}
 
 @c ------------------------------------------------------------------
- at c @external{}
- at node Several light sources, Using primitives, Adding fog, Hints
- at subsection Several light sources
+ at external{}
+ at node Lighting sample, Using primitives, Adding fog, Hints
+ at subsection Lighting sample
+ at nav{}
 
 In contrast to the most of other programs, MathGL supports several (up to 10) light sources. Moreover, the color each of them can be different: white (this is usual), yellow, red, cyan, green and so on. The use of several light sources may be interesting for the highlighting of some peculiarities of the plot or just to make an amusing picture. Note, each light source can be switched on/off individually. The sample code is:
 @verbatim
@@ -2243,10 +2372,34 @@ box:surf a 'h'
 
 @pfig{several_light, Example of several light sources.}
 
+Additionally, you can use local light sources and set to use diffise reflection instead of specular one (by default) or both kinds.
+ at verbatim
+# use Quality=6 because need lighting in placed
+light on:quality 6
+call 'prepare2d'
+subplot 2 2 0:title 'Default':rotate 50 60:box:surf a
+line -1 -0.7 1.7 -1 -0.7 0.7 'BA'
+
+light 0 1 0 1 -2 -1 -1
+subplot 2 2 1:title 'Local':rotate 50 60:box:surf a
+line 1 0 1 -1 -1 0 'BAO'
+
+diffuse 0
+subplot 2 2 2:title 'no diffuse':rotate 50 60:box:surf a
+line 1 0 1 -1 -1 0 'BAO'
+
+diffuse 0.5:light 0 1 0 1 -2 -1 -1 'w' 0
+subplot 2 2 3:title 'diffusive only':rotate 50 60:box:surf a
+line 1 0 1 -1 -1 0 'BAO'
+ at end verbatim
+
+ at pfig{light, Example of different types of lighting.}
+
 @c ------------------------------------------------------------------
- at c @external{}
- at node Using primitives, STFA sample, Several light sources, Hints
+ at external{}
+ at node Using primitives, STFA sample, Lighting sample, Hints
 @subsection Using primitives
+ at nav{}
 
 MathGL provide a set of functions for drawing primitives (see @ref{Primitives}). Primitives are low level object, which used by most of plotting functions. Picture below demonstrate some of commonly used primitives.
 @verbatim
@@ -2323,9 +2476,10 @@ Of course, the first variant is more suitable if you need to plot a lot of circl
 @pfig{venn, Example of Venn diagram.}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node STFA sample, Mapping visualization, Using primitives, Hints
 @subsection STFA sample
+ at nav{}
 
 Short-time Fourier Analysis (@ref{stfa}) is one of informative method for analyzing long rapidly oscillating 1D data arrays. It is used to determine the sinusoidal frequency and phase content of local sections of a signal as it changes over time.
 
@@ -2345,9 +2499,10 @@ stfa a b 64:axis:ylabel '\omega' 0:xlabel '\i t'
 @pfig{stfa, Example of STFA().}
 
 @c ------------------------------------------------------------------
- at c @external{}
- at node Mapping visualization, Making histogram, STFA sample, Hints
+ at external{}
+ at node Mapping visualization, Making regular data, STFA sample, Hints
 @subsection Mapping visualization
+ at nav{}
 
 Sometime ago I worked with mapping and have a question about its visualization. Let me remember you that mapping is some transformation rule for one set of number to another one. The 1d mapping is just an ordinary function -- it takes a number and transforms it to another one. The 2d mapping (which I used) is a pair of functions which take 2 numbers and transform them to another 2 ones. Except general plots (like @ref{surfc}, @ref{surfa}) there is a special plot -- Arnold diagram. It sho [...]
 
@@ -2367,9 +2522,32 @@ fill a '(x^3+y^3)/2':fill b '(x-y)/2':map a b 'brgk'
 @pfig{map, Example of Map().}
 
 @c ------------------------------------------------------------------
- at c @external{}
- at node Making histogram, Nonlinear fitting sample, Mapping visualization, Hints
+ at external{}
+ at node Making regular data, Making histogram, Mapping visualization, Hints
+ at subsection Making regular data
+ at nav{}
+
+Sometimes, one have only unregular data, like as data on triangular grids, or experimental results and so on. Such kind of data cannot be used as simple as regular data (like matrices). Only few functions, like @ref{dots}, can handle unregular data as is.
+
+However, one can use built in triangulation functions for interpolating unregular data points to a regular data grids. There are 2 ways. First way, one can use @ref{triangulation} function to obtain list of vertexes for triangles. Later this list can be used in functions like @ref{triplot} or @ref{tricont}. Second way consist in usage of @ref{datagrid} function, which fill regular data grid by interpolated values, assuming that coordinates of the data grid is equidistantly distributed in [...]
+ at verbatim
+new x 100 '2*rnd-1':new y 100 '2*rnd-1':copy z x^2-y^2
+# first way - plot triangular surface for points
+triangulate d x y
+title 'Triangulation'
+rotate 50 60:box:light on
+triplot d x y z:triplot d x y z '#k'
+# second way - make regular data and plot it
+new g 30 30:datagrid g x y z:mesh g 'm'
+ at end verbatim
+
+ at pfig{triangulation, Example of triangulation.}
+
+ at c ------------------------------------------------------------------
+ at external{}
+ at node Making histogram, Nonlinear fitting hints, Making regular data, Hints
 @subsection Making histogram
+ at nav{}
 
 Using the @ref{hist} function(s) for making regular distributions is one of useful fast methods to process and plot irregular data. @code{Hist} can be used to find some momentum of set of points by specifying weight function. It is possible to create not only 1D distributions but also 2D and 3D ones. Below I place the simplest sample code which demonstrate @ref{hist} usage:
 @verbatim
@@ -2385,9 +2563,10 @@ subplot 3 3 2:text 0.5 0.5 'Hist and\n{}MultiPlot\n{}sample' 'a' -3
 
 
 @c ------------------------------------------------------------------
- at c @external{}
- at node Nonlinear fitting sample, PDE solving hints, Making histogram, Hints
+ at external{}
+ at node Nonlinear fitting hints, PDE solving hints, Making histogram, Hints
 @subsection Nonlinear fitting hints
+ at nav{}
 
 Nonlinear fitting is rather simple. All that you need is the data to fit, the approximation formula and the list of coefficients to fit (better with its initial guess values). Let me demonstrate it on the following simple example. First, let us use sin function with some random noise:
 @verbatim
@@ -2428,9 +2607,10 @@ text 0 2.2 'initial: y = 0.3+sin(2\pi x)' 'b'
 @pfig{fit, Example of nonlinear fitting.}
 
 @c ------------------------------------------------------------------
- at c @external{}
- at node PDE solving hints, MGL parser using, Nonlinear fitting sample, Hints
+ at external{}
+ at node PDE solving hints, MGL parser using, Nonlinear fitting hints, Hints
 @subsection PDE solving hints
+ at nav{}
 
 Solving of Partial Differential Equations (PDE, including beam tracing) and ray tracing (or finding particle trajectory) are more or less common task. So, MathGL have several functions for that. There are @code{mglRay()} for ray tracing, @code{mglPDE()} for PDE solving, @code{mglQO2d()} for beam tracing in 2D case (see @ref{Global functions}). Note, that these functions take ``Hamiltonian'' or equations as string values. And I don't plan now to allow one to use user-defined functions. Th [...]
 
@@ -2482,9 +2662,10 @@ text 0.7 -0.05 'central ray'
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node MGL parser using, Using options, PDE solving hints, Hints
 @subsection MGL parser using
+ at nav{}
 
 MGL scripts can contain loops, conditions and user-defined functions. Below I show very simple example of its usage:
 @verbatim
@@ -2508,9 +2689,10 @@ next
 @pfig{parser, Example of MGL script parsing.}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Using options, ``Templates'', MGL parser using, Hints
 @subsection Using options
+ at nav{}
 
 @ref{Command options} allow the easy setup of the selected plot by changing global settings only for this plot. Often, options are used for specifying the range of automatic variables (coordinates). However, options allows easily change plot transparency, numbers of line or faces to be drawn, or add legend entries. The sample function for options usage is:
 @verbatim
@@ -2537,9 +2719,10 @@ box:axis:legend 2
 @pfig{mirror, Example of options usage.}
 
 @c ------------------------------------------------------------------
- at c @external{}
- at node ``Templates'', Nonlinear fitting sample, Using options, Hints
+ at external{}
+ at node ``Templates'', Nonlinear fitting hints, Using options, Hints
 @subsection ``Templates''
+ at nav{}
 
 As I have noted before, the change of settings will influence only for the further plotting commands. This allows one to create ``template'' function which will contain settings and primitive drawing for often used plots. Correspondingly one may call this template-function for drawing simplification.
 
@@ -2569,9 +2752,10 @@ A template-function can also contain settings for font, transparency, lightning,
 I understand that this is obvious thing for any professional programmer, but I several times receive suggestion about ``templates'' ... So, I decide to point out it here.
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Stereo image, Reduce memory usage, ``Templates'', Hints
 @subsection Stereo image
+ at nav{}
 
 One can easily create stereo image in MathGL. Stereo image can be produced by making two subplots with slightly different rotation angles. The corresponding code looks like this:
 @verbatim
@@ -2584,9 +2768,10 @@ subplot 2 1 1:rotate 50 60-1:box:surf a
 @pfig{stereo, Example of stereo image.}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Reduce memory usage, , Stereo image, Hints
 @subsection Reduce memory usage
+ at nav{}
 
 By default MathGL save all primitives in memory, rearrange it and only later draw them on bitmaps. Usually, this speed up drawing, but may require a lot of memory for plots which contain a lot of faces (like @ref{cloud}, @ref{dew}). You can use @ref{quality} function for setting to use direct drawing on bitmap and bypassing keeping any primitives in memory. This function also allow you to decrease the quality of the resulting image but increase the speed of the drawing.
 
@@ -2603,6 +2788,7 @@ next
 @external{}
 @node FAQ, , Hints, Examples
 @section FAQ
+ at nav{}
 
 @table @strong
 @item The plot does not appear
@@ -2612,7 +2798,7 @@ Check that points of the plot are located inside the bounding box and resize the
 Most ``new'' types of plots can be created by using the existing drawing functions. For example, the surface of curve rotation can be created by a special function @ref{torus}, or as a parametrically specified surface by @ref{surf}. See also, @ref{Hints}. If you can not find a specific type of plot, please e-mail me and this plot will appear in the next version of MathGL library.
 
 @item How can I print in Russian/Spanish/Arabic/Japanese, and so on?
-The standard way is to use Unicode encoding for the text output. But the MathGL library also has interface for 8-bit (char *) strings with internal conversion to Unicode. This conversion depends on the current locale OS. You may change it by @code{setlocale()} function. For example, for Russian text in CP1251 encoding you may use @code{setlocale(LC_CTYPE, "ru_RU.cp1251");} (under MS Windows the name of locale may differ -- @code{setlocale(LC_CTYPE, "russian_russia.1251")}). I strongly re [...]
+The standard way is to use Unicode encoding for the text output. But the MathGL library also has interface for 8-bit (char *) strings with internal conversion to Unicode. This conversion depends on the current locale OS.
 
 @item How can I exclude a point or a region of plot from the drawing?
 There are 3 general ways. First, the point with @code{nan} value as one of the coordinates (including color/alpha range) will never be plotted. Second, special functions define the condition when the points should be omitted (see @ref{Cutting}). Last, you may change the transparency of a part of the plot by the help of functions @ref{surfa}, @ref{surf3a} (see @ref{Dual plotting}). In last case the transparency is switched on smoothly.
@@ -2623,6 +2809,14 @@ Most of the library was written by one person. This is a result of nearly a year
 @item How can I display a bitmap on the figure?
 You can import data by command @ref{import} and display it by @ref{dens} function. For example, for black-and-white bitmap you can use the code: @code{import bmp 'fname.png' 'wk':dens  bmp 'wk'}.
 
+
+ at item How can I create 3D in PDF?
+Just use command @code{write fname.pdf}, which create PDF file if enable-pdf=ON at MathGL configure.
+
+ at item How can I create TeX figure?
+Just use command @code{write fname.tex}, which create LaTeX files with figure itself @samp{@var{fname}.tex}, with MathGL colors @samp{mglcolors.tex} and main file @samp{mglmain.tex}. Last one can be used for viewing image by command like @code{pdflatex mglmain.tex}.
+
+
 @item How I can change the font family?
 First, you should download new font files from @uref{http://mathgl.sourceforge.net/download.html, here} or from @uref{http://sourceforge.net/project/showfiles.php?group_id=152187&package_id=267177, here}. Next, you should load the font files into by the following command: @code{loadfont 'fontname'}. Here @var{fontname} is the base font name like @samp{STIX}. Use @code{loadfont ''} to start using the default font.
 
@@ -2630,12 +2824,11 @@ First, you should download new font files from @uref{http://mathgl.sourceforge.n
 Just set a negative value in @ref{ticklen}. For example, use @code{ticklen -0.1}.
 
 @item How can I prevent text rotation?
-Just use @code{rotatetext off}.
+Just use @code{rotatetext off}. Also you can use axis style @samp{U} for disable only tick labels rotation.
 
- at item Как нарисовать одинаковые оси координат для прямоугольного (не квадратного) рисунка?
-Просто используйте @code{aspect nan nan} для каждого подграфика, или в начале рисования.
+ at item How can I draw equal axis range even for rectangular image?
+Just use @code{aspect nan nan} for each subplot, or at the beginning of the drawing.
 
 @end table
 
 @external{}
-
diff --git a/texinfo/example_en.texi b/texinfo/example_en.texi
index 316d42e..119a58b 100644
--- a/texinfo/example_en.texi
+++ b/texinfo/example_en.texi
@@ -1,5 +1,6 @@
 @c ------------------------------------------------------------------
 @chapter MathGL examples
+ at nav{}
 
 This chapter contain information about basic and advanced MathGL, hints and samples for all types of graphics. I recommend you read first 2 sections one after another and at least look on @ref{Hints} section. Also I recommend you to look at @ref{General concepts} and @ref{FAQ}.
 
@@ -66,6 +67,7 @@ and so on.
 @external{}
 @node Basic usage, Advanced usage, , Examples
 @section Basic usage
+ at nav{}
 
 MathGL library can be used by several manners. Each has positive and negative sides:
 @itemize @bullet
@@ -107,15 +109,16 @@ Let me consider the aforesaid in more detail.
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Using MathGL window, Drawing to file, , Basic usage
 @subsection Using MathGL window
+ at nav{}
 @cindex window
 @cindex widgets
 
-The ``interactive'' way of drawing in MathGL consists in window creation  with help of class @code{mglWindow} or @code{mglGLUT} (see @ref{Widget classes}) and the following drawing in this window. There is a corresponding code:
+The ``interactive'' way of drawing in MathGL consists in window creation  with help of class @code{mglQT}, @code{mglFLTK} or @code{mglGLUT} (see @ref{Widget classes}) and the following drawing in this window. There is a corresponding code:
 @verbatim
-#include <mgl2/window.h>
+#include <mgl2/qt.h>
 int sample(mglGraph *gr)
 {
   gr->Rotate(60,40);
@@ -125,18 +128,18 @@ int sample(mglGraph *gr)
 //-----------------------------------------------------
 int main(int argc,char **argv)
 {
-  mglWindow gr(sample,"MathGL examples");
+  mglQT gr(sample,"MathGL examples");
   return gr.Run();
 }
 @end verbatim
 Here callback function @code{sample} is defined. This function does all drawing. Other function @code{main} is entry point function for console program. For compilation, just execute the command
 @verbatim
-gcc test.cpp -lmgl-wnd -lmgl
+gcc test.cpp -lmgl-qt -lmgl
 @end verbatim
 
 Alternatively you can create yours own class inherited from class @code{mglDraw} and re-implement the function @code{Draw()} in it:
 @verbatim
-#include <mgl2/window.h>
+#include <mgl2/qt.h>
 class Foo : public mglDraw
 {
 public:
@@ -153,7 +156,7 @@ int Foo::Draw(mglGraph *gr)
 int main(int argc,char **argv)
 {
   Foo foo;
-  mglWindow gr(&foo,"MathGL examples");
+  mglQT gr(&foo,"MathGL examples");
   return gr.Run();
 }
 @end verbatim
@@ -185,14 +188,15 @@ int main(int argc,char **argv)
 }
 @end verbatim
 
-The rotation, shift, zooming, switching on/off transparency and lighting can be done with help of tool-buttons (for @code{mglWindow}) or by hot-keys: @samp{a}, @samp{d}, @samp{w}, @samp{s} for plot rotation, @samp{r} and @samp{f} switching on/off transparency and lighting. Press @samp{x} for exit (or closing the window).
+The rotation, shift, zooming, switching on/off transparency and lighting can be done with help of tool-buttons (for @code{mglQT, mglFLTK}) or by hot-keys: @samp{a}, @samp{d}, @samp{w}, @samp{s} for plot rotation, @samp{r} and @samp{f} switching on/off transparency and lighting. Press @samp{x} for exit (or closing the window).
 
 In this example function @code{sample} rotates axes (@code{Rotate()}, @pxref{Subplots and rotation}) and draws the bounding box (@code{Box()}). Drawing is placed in separate function since it will be used on demand when window canvas needs to be redrawn.
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Drawing to file, Animation, Using MathGL window, Basic usage
 @subsection Drawing to file
+ at nav{}
 
 Another way of using MathGL library is the direct writing of the picture to the file. It is most usable for plot creation during long calculation or for using of small programs (like Matlab or Scilab scripts) for visualizing repetitive sets of data. But the speed of drawing is much higher in comparison with a script language.
 
@@ -231,9 +235,10 @@ int main(int ,char **)
 The difference from the previous one is using other function @code{WriteEPS()} for EPS format instead of function @code{WritePNG()}. Also, there is no switching on of the plot transparency @code{Alpha} since EPS format does not support it.
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Animation, Drawing in memory, Drawing to file, Basic usage
 @subsection Animation
+ at nav{}
 
 Widget classes (@code{mglWindow}, @code{mglGLUT}) support a delayed drawing, when all plotting functions are called once at the beginning of writing to memory lists. Further program displays the saved lists faster. Resulting redrawing will be faster but it requires sufficient memory. Several lists (frames) can be displayed one after another (by pressing @samp{,}, @samp{.}) or run as cinema. To switch these feature on one needs to modify function @code{sample}:
 @verbatim
@@ -364,9 +369,10 @@ Created files can be converted to movie by help of a lot of programs. For exampl
 Finally, you can use @code{mglconv} tool for doing the same with MGL scripts (@pxref{Utilities}).
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Drawing in memory, Using QMathGL, Animation, Basic usage
 @subsection Drawing in memory
+ at nav{}
 
 The last way of MathGL using is the drawing in memory. Class @code{mglGraph} allows one  to create a bitmap picture in memory. Further this picture can be displayed in window by some window libraries (like wxWidgets, FLTK, Windows GDI and so on). For example, the code for drawing in wxWidget library looks like:
 @verbatim
@@ -422,9 +428,10 @@ void MyWidget::paintEvent(QPaintEvent *)
 @end verbatim
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Using QMathGL, MathGL and PyQt, Drawing in memory, Basic usage
 @subsection Using QMathGL
+ at nav{}
 
 MathGL have several interface widgets for different widget libraries. There are QMathGL for Qt, Fl_MathGL for FLTK. These classes provide control which display MathGL graphics. Unfortunately there is no uniform interface for widget classes because all libraries have slightly different set of functions, features and so on. However the usage of MathGL widgets is rather simple. Let me show it on the example of QMathGL.
 
@@ -460,9 +467,10 @@ int main(int argc,char **argv)
 @end verbatim
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node MathGL and PyQt, MathGL and MPI, Using QMathGL, Basic usage
 @subsection MathGL and PyQt
+ at nav{}
 
 Generally SWIG based classes (including the Python one) are the same as C++ classes. However, there are few tips for using MathGL with PyQt. Below I place a very simple python code which demonstrate how MathGL can be used with PyQt. This code is mostly written by Prof. Dr. Heino Falcke. You can just copy it to a file @code{mgl-pyqt-test.py} and execute it from python shell by command @code{execfile("mgl-pyqt-test.py")}
 
@@ -533,16 +541,17 @@ qw.raise_()
 
 
 @c ------------------------------------------------------------------
- at c @external{}
- at node MathGL and MPI, , MathGL and PyQt, , Basic usage
+ at external{}
+ at node MathGL and MPI, , MathGL and PyQt, Basic usage
 @subsection MathGL and MPI
+ at nav{}
 
 For using MathGL in MPI program you just need to: (1) plot its own part of data for each running node; (2) collect resulting graphical information in a single program (for example, at node with rank=0); (3) save it. The sample code below demonstrate this for very simple sample of surface drawing.
 
 First you need to initialize MPI
 @verbatim
 #include <stdio.h>
-#include <mgl2/mgl.h>
+#include <mgl2/mpi.h>
 #include <mpi.h>
 
 int main(int argc, char *argv[])
@@ -560,7 +569,7 @@ Next step is data creation. For simplicity, I create data arrays with the same s
 @verbatim
   // initialize data similarly for all nodes
   mglData a(128,256);
-  mglGraph gr;
+  mglGraphMPI gr;
 @end verbatim
 
 Now, data should be filled by numbers. In real case, it should be some kind of calculations. But I just fill it by formula.
@@ -607,13 +616,14 @@ In my case the program is done, and I finalize MPI. In real program, you can rep
 }
 @end verbatim
 
-You can type @samp{mpic++ test.cpp -lmgl && mpirun -np 8 ./a.out} for compilation and running the sample program on 8 nodes. Note, that you have to set enable-mpi=ON at MathGL configure to use this feature.
+You can type @samp{mpic++ test.cpp -lmgl-mpi -lmgl && mpirun -np 8 ./a.out} for compilation and running the sample program on 8 nodes. Note, that you have to set enable-mpi=ON at MathGL configure to use this feature.
 
 
 @c ------------------------------------------------------------------
 @external{}
 @node Advanced usage, Data handling, Basic usage, Examples
 @section Advanced usage
+ at nav{}
 
 Now I show several non-obvious features of MathGL: several subplots in a single picture, curvilinear coordinates, text printing and so on. Generally you may miss this section at first reading.
 
@@ -630,9 +640,10 @@ Now I show several non-obvious features of MathGL: several subplots in a single
 @end menu
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Subplots, Axis and ticks, , Advanced usage
 @subsection Subplots
+ at nav{}
 
 Let me demonstrate possibilities of plot positioning and rotation. MathGL has a set of functions: @ref{subplot}, @ref{inplot}, @ref{title}, @ref{aspect} and @ref{rotate} and so on (see @ref{Subplots and rotation}). The order of their calling is strictly determined. First, one changes the position of plot in image area (functions @ref{subplot}, @ref{inplot} and @ref{multiplot}). Secondly, you can add the title of plot by @ref{title} function. After that one may rotate the plot (function @ [...]
 @verbatim
@@ -683,9 +694,10 @@ int sample(mglGraph *gr)
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Axis and ticks, Curvilinear coordinates, Subplots, Advanced usage
 @subsection Axis and ticks
+ at nav{}
 
 MathGL library can draw not only the bounding box but also the axes, grids, labels and so on. The ranges of axes and their origin (the point of intersection) are determined by functions @code{SetRange()}, @code{SetRanges()}, @code{SetOrigin()} (see @ref{Ranges (bounding box)}). Ticks on axis are specified by function @code{SetTicks}, @code{SetTicksVal}, @code{SetTicksTime} (see @ref{Ticks}). But usually
 
@@ -797,9 +809,10 @@ int sample(mglGraph *gr)
 You can see that MathGL automatically switch to log-ticks as we define log-axis formula (in difference from v.1.*). Moreover, it switch to log-ticks for any formula if axis range will be large enough (see right bottom plot). Another interesting feature is that you not necessary define usual log-axis (i.e. when coordinates are positive), but you can define ``minus-log'' axis when coordinate is negative (see left bottom plot).
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Curvilinear coordinates, Colorbars, Axis and ticks, Advanced usage
 @subsection Curvilinear coordinates
+ at nav{}
 
 As I noted in previous subsection, MathGL support curvilinear coordinates. In difference from other plotting programs and libraries, MathGL uses textual formulas for connection of the old (data) and new (output) coordinates. This allows one to plot in arbitrary coordinates. The following code plots the line @var{y}=0, @var{z}=0 in Cartesian, polar, parabolic and spiral coordinates:
 @verbatim
@@ -834,9 +847,10 @@ int sample(mglGraph *gr)
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Colorbars, Bounding box, Curvilinear coordinates, Advanced usage
 @subsection Colorbars
+ at nav{}
 
 MathGL handle @ref{colorbar} as special kind of axis. So, most of functions for axis and ticks setup will work for colorbar too. Colorbars can be in log-scale, and generally as arbitrary function scale; common factor of colorbar labels can be separated; and so on.
 
@@ -876,9 +890,10 @@ int sample(mglGraph *gr)
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Bounding box, Ternary axis, Colorbars, Advanced usage
 @subsection Bounding box
+ at nav{}
 
 Box around the plot is rather useful thing because it allows one to: see the plot boundaries, and better estimate points position since box contain another set of ticks. MathGL provide special function for drawing such box -- @ref{box} function. By default, it draw black or white box with ticks (color depend on transparency type, see @ref{Types of transparency}). However, you can change the color of box, or add drawing of rectangles at rear faces of box. Also you can disable ticks drawin [...]
 @verbatim
@@ -900,9 +915,10 @@ int sample(mglGraph *gr)
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Ternary axis, Text features, Bounding box, Advanced usage
 @subsection Ternary axis
+ at nav{}
 
 There are another unusual axis types which are supported by MathGL. These are ternary and quaternary axis. Ternary axis is special axis of 3 coordinates @var{a}, @var{b}, @var{c} which satisfy relation @var{a}+ at var{b}+ at var{c}=1. Correspondingly, quaternary axis is special axis of 4 coordinates @var{a}, @var{b}, @var{c}, @var{d} which satisfy relation @var{a}+ at var{b}+ at var{c}+ at var{d}=1.
 
@@ -953,9 +969,10 @@ int sample(mglGraph *gr)
 @pfig{ternary, Example of colorbars}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Text features, Legend sample, Ternary axis, Advanced usage
 @subsection Text features
+ at nav{}
 
 MathGL prints text by vector font. There are functions for manual specifying of text position (like @code{Puts}) and for its automatic selection (like @code{Label}, @code{Legend} and so on). MathGL prints text always in specified position even if it lies outside the bounding box. The default size of font is specified by functions @var{SetFontSize*} (see @ref{Font settings}). However, the actual size of output string depends on subplot size (depends on functions @code{SubPlot}, @code{InPl [...]
 
@@ -1022,9 +1039,10 @@ int sample(mglGraph *gr)
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Legend sample, Cutting sample, Text features, Advanced usage
 @subsection Legend sample
+ at nav{}
 
 Legend is one of standard ways to show plot annotations. Basically you need to connect the plot style (line style, marker and color) with some text. In MathGL, you can do it by 2 methods: manually using @ref{addlegend} function; or use @samp{legend} option (see @ref{Command options}), which will use last plot style. In both cases, legend entries will be added into internal accumulator, which later used for legend drawing itself. @ref{clearlegend} function allow you to remove all saved le [...]
 
@@ -1059,9 +1077,10 @@ int sample(mglGraph *gr)
 @pfig{legend, Example of legend}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Cutting sample, , Legend sample, Advanced usage
 @subsection Cutting sample
+ at nav{}
 
 The last common thing which I want to show in this section is how one can cut off points from plot. There are 4 mechanism for that.
 @itemize @bullet
@@ -1110,6 +1129,7 @@ int sample(mglGraph *gr)
 @external{}
 @node Data handling, Data plotting, Advanced usage, Examples
 @section Data handling
+ at nav{}
 
 Class @code{mglData} contains all functions for the data handling in MathGL (@pxref{Data processing}). There are several matters why I use class @code{mglData} but not a single array: it does not depend on type of data (mreal or double), sizes of data arrays are kept with data, memory working is simpler and safer.
 
@@ -1120,9 +1140,10 @@ Class @code{mglData} contains all functions for the data handling in MathGL (@px
 @end menu
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Array creation, Linking array, , Data handling
 @subsection Array creation
+ at nav{}
 
 There are many ways in MathGL how data arrays can be created and filled.
 
@@ -1198,9 +1219,10 @@ or by using @code{Modify()} function
 The only non-obvious thing here is using multidimensional arrays in C/C++, i.e. arrays defined like @code{mreal dat[40][30];}. Since, formally these elements @code{dat[i]} can address the memory in arbitrary place you should use the proper function to convert such arrays to @code{mglData} object. For C++ this is functions like @code{mglData::Set(mreal **dat, int N1, int N2);}. For C this is functions like @code{mgl_data_set_mreal2(HMDT d, const mreal **dat, int N1, int N2);}. At this, yo [...]
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Linking array, Change data, Array creation, Data handling
 @subsection Linking array
+ at nav{}
 
 Sometimes the data arrays are so large, that one couldn't' copy its values to another array (i.e. into mglData). In this case, he can define its own class derived from @code{mglDataA} (see @ref{mglDataA class}) or can use @code{Link} function.
 
@@ -1216,9 +1238,10 @@ Creating the link is rather simple -- just the same as using @code{Set} function
 @end verbatim
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Change data, , Linking array, Data handling
 @subsection Change data
+ at nav{}
 
 MathGL has functions for data processing: differentiating, integrating, smoothing and so on (for more detail, see @ref{Data processing}). Let us consider some examples. The simplest ones are integration and differentiation. The direction in which operation will be performed is specified by textual string, which may contain symbols @samp{x}, @samp{y} or @samp{z}. For example, the call of @code{Diff("x")} will differentiate data along @samp{x} direction; the call of @code{Integral("xy")} p [...]
 @verbatim
@@ -1343,6 +1366,7 @@ int sample(mglGraph *gr)
 @external{}
 @node Data plotting, 1D samples, Data handling, Examples
 @section Data plotting
+ at nav{}
 
 Let me now show how to plot the data. Next section will give much more examples for all plotting functions. Here I just show some basics. MathGL generally has 2 types of plotting functions. Simple variant requires a single data array for plotting, other data (coordinates) are considered uniformly distributed in axis range. Second variant requires data arrays for all coordinates. It allows one to plot rather complex multivalent curves and surfaces (in case of parametric dependencies). Usu [...]
 
@@ -1464,6 +1488,7 @@ int sample(mglGraph *gr)
 @external{}
 @node 1D samples, 2D samples, Data plotting, Examples
 @section 1D samples
+ at nav{}
 
 This section is devoted to visualization of 1D data arrays. 1D means the data which depend on single index (parameter) like curve in parametric form @{x(i),y(i),z(i)@}, i=1...n. Most of samples will use the same data for plotting. So, I put its initialization in separate function
 @verbatim
@@ -1532,6 +1557,7 @@ void mgls_prepare1d(HMDT y, HMDT y1=0, HMDT y2=0, HMDT x1=0, HMDT x2=0)
 * Chart sample::
 * BoxPlot sample::
 * Candle sample::
+* OHLC sample::
 * Error sample::
 * Mark sample::
 * TextMark sample::
@@ -1544,9 +1570,10 @@ void mgls_prepare1d(HMDT y, HMDT y1=0, HMDT y2=0, HMDT x1=0, HMDT x2=0)
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Plot sample, Radar sample, , 1D samples
 @subsection Plot sample
+ at nav{}
 
 Function @ref{plot} is most standard way to visualize 1D data array. By default, @code{Plot} use colors from palette. However, you can specify manual color/palette, and even set to use new color for each points by using @samp{!} style. Another feature is @samp{ } style which draw only markers without line between points. The sample code is:
 @verbatim
@@ -1575,9 +1602,10 @@ int sample(mglGraph *gr)
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Radar sample, Step sample, Plot sample, 1D samples
 @subsection Radar sample
+ at nav{}
 
 Function @ref{radar} plot is variant of @code{Plot} one, which make plot in polar coordinates and draw radial rays in point directions. If you just need a plot in polar coordinates then I recommend to use @ref{Curvilinear coordinates} or @code{Plot} in parabolic form with @code{x=r*cos(fi); y=r*sin(fi);}. The sample code is:
 @verbatim
@@ -1593,9 +1621,10 @@ int sample(mglGraph *gr)
 @pfig{radar, Example of Radar()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Step sample, Tens sample, Radar sample, 1D samples
 @subsection Step sample
+ at nav{}
 
 Function @ref{step} plot data as stairs. It have the same options as @code{Plot}. The sample code is:
 @verbatim
@@ -1620,9 +1649,10 @@ int sample(mglGraph *gr)
 @pfig{step, Example of Step()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Tens sample, Area sample, Step sample, 1D samples
 @subsection Tens sample
+ at nav{}
 
 Function @ref{tens} is variant of @ref{plot} with smooth coloring along the curves. At this, color is determined as for surfaces (see @ref{Color scheme}). The sample code is:
 @verbatim
@@ -1646,9 +1676,10 @@ int sample(mglGraph *gr)
 @pfig{tens, Example of Tens()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Area sample, Region sample, Tens sample, 1D samples
 @subsection Area sample
+ at nav{}
 
 Function @ref{area} fill the area between curve and axis plane. It support gradient filling if 2 colors per curve is specified. The sample code is:
 @verbatim
@@ -1677,9 +1708,10 @@ int sample(mglGraph *gr)
 @pfig{area, Example of Area()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Region sample, Stem sample, Area sample, 1D samples
 @subsection Region sample
+ at nav{}
 
 Function @ref{region} fill the area between 2 curves. It support gradient filling if 2 colors per curve is specified. Also it can fill only the region y1<y<y2 if style @samp{i} is used. The sample code is:
 @verbatim
@@ -1705,9 +1737,10 @@ int sample(mglGraph *gr)
 @pfig{region, Example of Region()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Stem sample, Bars sample, Region sample, 1D samples
 @subsection Stem sample
+ at nav{}
 
 Function @ref{stem} draw vertical bars. It is most attractive if markers are drawn too. The sample code is:
 @verbatim
@@ -1731,9 +1764,10 @@ int sample(mglGraph *gr)
 @pfig{stem, Example of Stem()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Bars sample, Barh sample, Stem sample, 1D samples
 @subsection Bars sample
+ at nav{}
 
 Function @ref{bars} draw vertical bars. It have a lot of options: bar-above-bar (@samp{a} style), fall like (@samp{f} style), 2 colors for positive and negative values, wired bars (@samp{#} style), 3D variant. The sample code is:
 @verbatim
@@ -1769,9 +1803,10 @@ int sample(mglGraph *gr)
 @pfig{bars, Example of Bars()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Barh sample, Cones sample, Bars sample, 1D samples
 @subsection Barh sample
+ at nav{}
 
 Function @ref{barh} is the similar to @code{Bars} but draw horizontal bars. The sample code is:
 @verbatim
@@ -1798,9 +1833,10 @@ int sample(mglGraph *gr)
 @pfig{barh, Example of Barh()}
 
 @c ------------------------------------------------------------------
- at c @external{}
- at node Cones sample, Chart sample, Bars sample, 1D samples
+ at external{}
+ at node Cones sample, Chart sample, Barh sample, 1D samples
 @subsection Cones sample
+ at nav{}
 
 Function @ref{cones} is similar to @code{Bars} but draw cones. The sample code is:
 @verbatim
@@ -1808,18 +1844,24 @@ int sample(mglGraph *gr)
 {
   mglData ys(10,3);   ys.Modify("0.8*sin(pi*(2*x+y/2))+0.2*rnd");
   gr->Light(true);    gr->SetOrigin(0,0,0);
-  gr->SubPlot(2,2,0); gr->Title("Cones plot");
+  gr->SubPlot(3,2,0); gr->Title("Cones plot");
   gr->Rotate(50,60);  gr->Box();  gr->Cones(ys);
 
-  gr->SubPlot(2,2,1); gr->Title("2 colors");
+  gr->SubPlot(3,2,1); gr->Title("2 colors");
   gr->Rotate(50,60);  gr->Box();  gr->Cones(ys,"cbgGyr");
 
-  gr->SubPlot(2,2,2); gr->Title("'#' style");
+  gr->SubPlot(3,2,2); gr->Title("'#' style");
   gr->Rotate(50,60);  gr->Box();  gr->Cones(ys,"#");
 
-  gr->SubPlot(2,2,3); gr->Title("'a' style");
+  gr->SubPlot(3,2,3); gr->Title("'a' style");
   gr->SetRange('z',-2,2); // increase range since summation can exceed [-1,1]
   gr->Rotate(50,60);  gr->Box();  gr->Cones(ys,"a");
+
+  gr->SubPlot(3,2,4); gr->Title("'t' style");
+  gr->Rotate(50,60);  gr->Box();  gr->Cones(ys,"t");
+
+  gr->SubPlot(3,2,5); gr->Title("'4' style");
+  gr->Rotate(50,60);  gr->Box();  gr->Cones(ys,"4");
   return 0;
 }
 @end verbatim
@@ -1827,9 +1869,10 @@ int sample(mglGraph *gr)
 @pfig{cones, Example of Cones()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Chart sample, BoxPlot sample, Cones sample, 1D samples
 @subsection Chart sample
+ at nav{}
 
 Function @ref{chart} draw colored boxes with width proportional to data values. Use @samp{ } for empty box. Plot looks most attractive in polar coordinates -- well known pie chart. The sample code is:
 @verbatim
@@ -1856,9 +1899,10 @@ int sample(mglGraph *gr)
 @pfig{chart, Example of Chart()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node BoxPlot sample, Candle sample, Chart sample, 1D samples
 @subsection BoxPlot sample
+ at nav{}
 
 Function @ref{boxplot} draw box-and-whisker diagram. The sample code is:
 @verbatim
@@ -1874,9 +1918,10 @@ int sample(mglGraph *gr)
 @pfig{boxplot, Example of BoxPlot()}
 
 @c ------------------------------------------------------------------
- at c @external{}
- at node Candle sample, Error sample, BoxPlot sample, 1D samples
+ at external{}
+ at node Candle sample, OHLC sample, BoxPlot sample, 1D samples
 @subsection Candle sample
+ at nav{}
 
 Function @ref{candle} draw candlestick chart. This is a combination of a line-chart and a bar-chart, in that each bar represents the range of price movement over a given time interval. The sample code is:
 @verbatim
@@ -1894,9 +1939,31 @@ int sample(mglGraph *gr)
 @pfig{candle, Example of Candle()}
 
 @c ------------------------------------------------------------------
- at c @external{}
- at node Error sample, Mark sample, Candle sample, 1D samples
+ at external{}
+ at node OHLC sample, Error sample, Candle sample, 1D samples
+ at subsection OHLC sample
+ at nav{}
+
+Function @ref{ohlc} draw Open-High-Low-Close diagram. This diagram show vertical line for between maximal(high) and minimal(low) values, as well as horizontal lines before/after vertical line for initial(open)/final(close) values of some process. The sample code is:
+ at verbatim
+int sample(mglGraph *gr)
+{
+  mglData o(10), h(10), l(10), c(10);
+  gr->Fill(o,"0.5*sin(pi*x)");  gr->Fill(c,"0.5*sin(pi*(x+2/9))");
+  gr->Fill(l,"0.3*rnd-0.8");    gr->Fill(h,"0.3*rnd+0.5");
+  gr->SubPlot(1,1,0,"");  gr->Title("OHLC plot");
+  gr->Box();  gr->OHLC(o,h,l,c);
+  return 0;
+}
+ at end verbatim
+
+ at pfig{ohlc, Example of OHLC()}
+
+ at c ------------------------------------------------------------------
+ at external{}
+ at node Error sample, Mark sample, OHLC sample, 1D samples
 @subsection Error sample
+ at nav{}
 
 Function @ref{error} draw error boxes around the points. You can draw default boxes or semi-transparent symbol (like marker, see @ref{Line styles}). Also you can set individual color for each box. The sample code is:
 @verbatim
@@ -1933,10 +2000,37 @@ int sample(mglGraph *gr)
 
 @pfig{error, Example of Error()}
 
+Additionally, you can use solid large "marks" instead of error boxes by selecting proper style.
+ at verbatim
+int sample(mglGraph *gr)
+{
+  mglData x0(10), y0(10), ex(10), ey(10);
+  for(int i=0;i<10;i++)
+  {  x0.a[i] = mgl_rnd(); y0.a[i] = mgl_rnd(); ey.a[i] = ex.a[i] = 0.1; }
+  gr->SetRanges(0,1,0,1); gr->Alpha(true);
+  gr->SubPlot(4,3,0,"");  gr->Box(); gr->Error(x0,y0,ex,ey,"#+@");
+  gr->SubPlot(4,3,1,"");  gr->Box(); gr->Error(x0,y0,ex,ey,"#x@");
+  gr->SubPlot(4,3,2,"");  gr->Box(); gr->Error(x0,y0,ex,ey,"#s@","alpha 0.5");
+  gr->SubPlot(4,3,3,"");  gr->Box(); gr->Error(x0,y0,ex,ey,"s@");
+  gr->SubPlot(4,3,4,"");  gr->Box(); gr->Error(x0,y0,ex,ey,"d@");
+  gr->SubPlot(4,3,5,"");  gr->Box(); gr->Error(x0,y0,ex,ey,"#d@","alpha 0.5");
+  gr->SubPlot(4,3,6,"");  gr->Box(); gr->Error(x0,y0,ex,ey,"+@");
+  gr->SubPlot(4,3,7,"");  gr->Box(); gr->Error(x0,y0,ex,ey,"x@");
+  gr->SubPlot(4,3,8,"");  gr->Box(); gr->Error(x0,y0,ex,ey,"o@");
+  gr->SubPlot(4,3,9,"");  gr->Box(); gr->Error(x0,y0,ex,ey,"#o@","alpha 0.5");
+  gr->SubPlot(4,3,10,""); gr->Box(); gr->Error(x0,y0,ex,ey,"#.@");
+  gr->SubPlot(4,3,11,""); gr->Box(); gr->Error(x0,y0,ex,ey);
+}
+ at end verbatim
+
+ at pfig{error2, Example of Error() with marks}
+
+
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Mark sample, TextMark sample, Error sample, 1D samples
 @subsection Mark sample
+ at nav{}
 
 Function @ref{mark} draw markers at points. It is mostly the same as @code{Plot} but marker size can be variable. The sample code is:
 @verbatim
@@ -1952,9 +2046,10 @@ int sample(mglGraph *gr)
 @pfig{mark, Example of Mark()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node TextMark sample, Label sample, Mark sample, 1D samples
 @subsection TextMark sample
+ at nav{}
 
 Function @ref{textmark} like @code{Mark} but draw text instead of markers. The sample code is:
 @verbatim
@@ -1970,9 +2065,10 @@ int sample(mglGraph *gr)
 @pfig{textmark, Example of TextMark()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Label sample, Table sample, TextMark sample, 1D samples
 @subsection Label sample
+ at nav{}
 
 Function @ref{label} print text at data points. The string may contain @samp{%x}, @samp{%y}, @samp{%z} for x-, y-, z-coordinates of points, @samp{%n} for point index. The sample code is:
 @verbatim
@@ -1988,9 +2084,10 @@ int sample(mglGraph *gr)
 @pfig{label, Example of Label()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Table sample, Tube sample, Label sample, 1D samples
 @subsection Table sample
+ at nav{}
 
 Function @ref{table} draw table with data values. The sample code is:
 @verbatim
@@ -2013,9 +2110,10 @@ int sample(mglGraph *gr)
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Tube sample, Tape sample, Table sample, 1D samples
 @subsection Tube sample
+ at nav{}
 
 Function @ref{tube} draw tube with variable radius. The sample code is:
 @verbatim
@@ -2043,9 +2141,10 @@ int sample(mglGraph *gr)
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Tape sample, Torus sample, Tube sample, 1D samples
 @subsection Tape sample
+ at nav{}
 
 Function @ref{tape} draw tapes which rotate around the curve as normal and binormal. The sample code is:
 @verbatim
@@ -2077,9 +2176,10 @@ int sample(mglGraph *gr)
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Torus sample, , Tape sample, 1D samples
 @subsection Torus sample
+ at nav{}
 
 Function @ref{torus} draw surface of the curve rotation. The sample code is:
 @verbatim
@@ -2109,6 +2209,7 @@ int sample(mglGraph *gr)
 @external{}
 @node 2D samples, 3D samples, 1D samples, Examples
 @section 2D samples
+ at nav{}
 
 This section is devoted to visualization of 2D data arrays. 2D means the data which depend on 2 indexes (parameters) like matrix z(i,j)=z(x(i),y(j)), i=1...n, j=1...m or in parametric form @{x(i,j),y(i,j),z(i,j)@}. Most of samples will use the same data for plotting. So, I put its initialization in separate function
 @verbatim
@@ -2164,9 +2265,10 @@ void mgls_prepare2d(HMDT a, HMDT b=0, HMDT v=0)
 @end menu
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Surf sample, SurfC sample, , 2D samples
 @subsection Surf sample
+ at nav{}
 
 Function @ref{surf} is most standard way to visualize 2D data array. @code{Surf} use color scheme for coloring (see @ref{Color scheme}). You can use @samp{#} style for drawing black meshes on the surface. The sample code is:
 @verbatim
@@ -2195,9 +2297,10 @@ int sample(mglGraph *gr)
 @pfig{surf, Example of Surf()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node SurfC sample, SurfA sample, Surf sample, 2D samples
 @subsection SurfC sample
+ at nav{}
 
 Function @ref{surfc} is similar to @ref{surf} but its coloring is determined by another data. The sample code is:
 @verbatim
@@ -2213,9 +2316,10 @@ int sample(mglGraph *gr)
 @pfig{surfc, Example of SurfC()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node SurfA sample, Mesh sample, SurfC sample, 2D samples
 @subsection SurfA sample
+ at nav{}
 
 Function @ref{surfa} is similar to @ref{surf} but its transparency is determined by another data. The sample code is:
 @verbatim
@@ -2233,9 +2337,10 @@ int sample(mglGraph *gr)
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Mesh sample, Fall sample, SurfA sample, 2D samples
 @subsection Mesh sample
+ at nav{}
 
 Function @ref{mesh} draw wired surface. You can use @ref{meshnum} for changing number of lines to be drawn. The sample code is:
 @verbatim
@@ -2251,9 +2356,10 @@ int sample(mglGraph *gr)
 @pfig{mesh, Example of Mesh()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Fall sample, Belt sample, Mesh sample, 2D samples
 @subsection Fall sample
+ at nav{}
 
 Function @ref{fall} draw waterfall surface. You can use @ref{meshnum} for changing number of lines to be drawn. Also you can use @samp{x} style for drawing lines in other direction. The sample code is:
 @verbatim
@@ -2269,9 +2375,10 @@ int sample(mglGraph *gr)
 @pfig{fall, Example of Fall()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Belt sample, Boxs sample, Fall sample, 2D samples
 @subsection Belt sample
+ at nav{}
 
 Function @ref{belt} draw surface by belts. You can use @samp{x} style for drawing lines in other direction. The sample code is:
 @verbatim
@@ -2287,9 +2394,10 @@ int sample(mglGraph *gr)
 @pfig{belt, Example of Belt()}
 
 @c ------------------------------------------------------------------
- at c @external{}
- at node Boxs sample, Tile sample, Fall sample, 2D samples
+ at external{}
+ at node Boxs sample, Tile sample, Belt sample, 2D samples
 @subsection Boxs sample
+ at nav{}
 
 Function @ref{boxs} draw surface by boxes. You can use @samp{#} for drawing wire plot. The sample code is:
 @verbatim
@@ -2315,9 +2423,10 @@ int sample(mglGraph *gr)
 @pfig{boxs, Example of Boxs()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Tile sample, TileS sample, Boxs sample, 2D samples
 @subsection Tile sample
+ at nav{}
 
 Function @ref{tile} draw surface by tiles. The sample code is:
 @verbatim
@@ -2333,9 +2442,10 @@ int sample(mglGraph *gr)
 @pfig{tile, Example of Tile()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node TileS sample, Dens sample, Tile sample, 2D samples
 @subsection TileS sample
+ at nav{}
 
 Function @ref{tiles} is similar to @ref{tile} but tile sizes is determined by another data. This allows one to simulate transparency of the plot. The sample code is:
 @verbatim
@@ -2352,9 +2462,10 @@ int sample(mglGraph *gr)
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Dens sample, Cont sample, TileS sample, 2D samples
 @subsection Dens sample
+ at nav{}
 
 Function @ref{dens} draw density plot for surface. The sample code is:
 @verbatim
@@ -2380,9 +2491,10 @@ int sample(mglGraph *gr)
 @pfig{dens, Example of Dens()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Cont sample, ContF sample, Dens sample, 2D samples
 @subsection Cont sample
+ at nav{}
 
 Function @ref{cont} draw contour lines for surface. You can select automatic (default) or manual levels for contours, print contour labels, draw it on the surface (default) or at plane (as @code{Dens}). The sample code is:
 @verbatim
@@ -2407,9 +2519,10 @@ int sample(mglGraph *gr)
 @pfig{cont, Example of Cont()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node ContF sample, ContD sample, Cont sample, 2D samples
 @subsection ContF sample
+ at nav{}
 
 Function @ref{contf} draw filled contours.  You can select automatic (default) or manual levels for contours. The sample code is:
 @verbatim
@@ -2426,7 +2539,8 @@ int sample(mglGraph *gr)
   gr->SubPlot(2,2,2); gr->Title("'\\_' style");
   gr->Rotate(50,60);  gr->Box();  gr->ContF(a,"_");
 
-  gr->Fill(a1,"0.6*sin(2*pi*x+pi*(z+1)/2)*sin(3*pi*y+pi*z) + 0.4*cos(3*pi*(x*y)+pi*(z+1)^2/2)");
+  gr->Fill(a1,"0.6*sin(2*pi*x+pi*(z+1)/2)*sin(3*pi*y+pi*z) +
+               0.4*cos(3*pi*(x*y)+pi*(z+1)^2/2)");
   gr->SubPlot(2,2,3); gr->Title("several slices");
   gr->Rotate(50,60);  gr->Box();  gr->ContF(a1);
   return 0;
@@ -2436,9 +2550,10 @@ int sample(mglGraph *gr)
 @pfig{contf, Example of ContF()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node ContD sample, ContV sample, ContF sample, 2D samples
 @subsection ContD sample
+ at nav{}
 
 Function @ref{contd} is similar to @code{ContF} but with manual contour colors. The sample code is:
 @verbatim
@@ -2465,9 +2580,10 @@ int sample(mglGraph *gr)
 @pfig{contd, Example of ContD()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node ContV sample, Axial sample, ContD sample, 2D samples
 @subsection ContV sample
+ at nav{}
 
 Function @ref{contv} draw vertical cylinders (belts) at contour lines. The sample code is:
 @verbatim
@@ -2494,9 +2610,10 @@ int sample(mglGraph *gr)
 @pfig{contv, Example of ContV()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Axial sample, Grad sample, ContV sample, 2D samples
 @subsection Axial sample
+ at nav{}
 
 Function @ref{axial} draw surfaces of rotation for contour lines. You can draw wire surfaces (@samp{#} style) or ones rotated in other directions (@samp{x}, @samp{z} styles). The sample code is:
 @verbatim
@@ -2522,9 +2639,10 @@ int sample(mglGraph *gr)
 @pfig{axial, Example of Axial()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Grad sample, , Axial sample, 2D samples
 @subsection Grad sample
+ at nav{}
 
 Function @ref{grad} draw gradient lines for matrix. The sample code is:
 @verbatim
@@ -2544,6 +2662,7 @@ int sample(mglGraph *gr)
 @external{}
 @node 3D samples, Vector field samples, 2D samples, Examples
 @section 3D samples
+ at nav{}
 
 This section is devoted to visualization of 3D data arrays. 3D means the data which depend on 3 indexes (parameters) like tensor a(i,j,k)=a(x(i),y(j),x(k)), i=1...n, j=1...m, k=1...l or in parametric form @{x(i,j,k),y(i,j,k),z(i,j,k),a(i,j,k)@}. Most of samples will use the same data for plotting. So, I put its initialization in separate function
 @verbatim
@@ -2593,9 +2712,10 @@ void mgls_prepare3d(HMDT a, HMDT b=0)
 @end menu
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Surf3 sample, Surf3C sample, , 3D samples
 @subsection Surf3 sample
+ at nav{}
 
 Function @ref{surf3} is one of most suitable (for my opinion) functions to visualize 3D data. It draw the isosurface(s) -- surface(s) of constant amplitude (3D analogue of contour lines). You can draw wired isosurfaces if specify @samp{#} style. The sample code is:
 @verbatim
@@ -2618,9 +2738,10 @@ int sample(mglGraph *gr)
 @pfig{surf3, Example of Surf3()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Surf3C sample, Surf3A sample, Surf3 sample, 3D samples
 @subsection Surf3C sample
+ at nav{}
 
 Function @ref{surf3c} is similar to @ref{surf3} but its coloring is determined by another data. The sample code is:
 @verbatim
@@ -2637,9 +2758,10 @@ int sample(mglGraph *gr)
 @pfig{surf3c, Example of Surf3C()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Surf3A sample, Cloud sample, Surf3C sample, 3D samples
 @subsection Surf3A sample
+ at nav{}
 
 Function @ref{surf3a} is similar to @ref{surf3} but its transparency is determined by another data. The sample code is:
 @verbatim
@@ -2656,9 +2778,10 @@ int sample(mglGraph *gr)
 @pfig{surf3a, Example of Surf3A()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Cloud sample, Dens3 sample, Surf3A sample, 3D samples
 @subsection Cloud sample
+ at nav{}
 
 Function @ref{cloud} draw cloud-like object which is less transparent for higher data values. Similar plot can be created using many (about 10-20) @code{Surf3A(a,a)} isosurfaces. The sample code is:
 @verbatim
@@ -2669,8 +2792,8 @@ int sample(mglGraph *gr)
   gr->Rotate(50,60);  gr->Alpha(true);
   gr->Box();  gr->Cloud(c,"wyrRk");
 
-  gr->SubPlot(2,2,1); gr->Title("'!' style");
-  gr->Rotate(50,60);  gr->Box();  gr->Cloud(c,"!wyrRk");
+  gr->SubPlot(2,2,1); gr->Title("'i' style");
+  gr->Rotate(50,60);  gr->Box();  gr->Cloud(c,"iwyrRk");
 
   gr->SubPlot(2,2,2); gr->Title("'.' style");
   gr->Rotate(50,60);  gr->Box();  gr->Cloud(c,".wyrRk");
@@ -2684,9 +2807,10 @@ int sample(mglGraph *gr)
 @pfig{cloud, Example of Cloud()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Dens3 sample, Cont3 sample, Cloud sample, 3D samples
 @subsection Dens3 sample
+ at nav{}
 
 Function @ref{dens3} draw just usual density plot but at slices of 3D data. The sample code is:
 @verbatim
@@ -2704,9 +2828,10 @@ int sample(mglGraph *gr)
 @pfig{densa, Example of Dens3()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Cont3 sample, ContF3 sample, Dens3 sample, 3D samples
 @subsection Cont3 sample
+ at nav{}
 
 Function @ref{cont3} draw just usual contour lines but at slices of 3D data. The sample code is:
 @verbatim
@@ -2724,9 +2849,10 @@ int sample(mglGraph *gr)
 @pfig{conta, Example of Cont3()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node ContF3 sample, Dens projection sample, Cont3 sample, 3D samples
 @subsection ContF3 sample
+ at nav{}
 
 Function @ref{contf3} draw just usual filled contours but at slices of 3D data. The sample code is:
 @verbatim
@@ -2745,11 +2871,12 @@ int sample(mglGraph *gr)
 @pfig{contfa, Example of ContF3()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Dens projection sample, Cont projection sample, ContF3 sample, 3D samples
 @subsection Dens projection sample
+ at nav{}
 
-Functions @ref{DensXYZ} draw density plot on plane perpendicular to corresponding axis. One of possible application is drawing projections of 3D field. The sample code is:
+Functions @ref{densz}, @ref{densy}, @ref{densx} draw density plot on plane perpendicular to corresponding axis. One of possible application is drawing projections of 3D field. The sample code is:
 @verbatim
 int sample(mglGraph *gr)
 {
@@ -2761,14 +2888,15 @@ int sample(mglGraph *gr)
 }
 @end verbatim
 
- at pfig{dens_xyz, Example of DensX()\, DensY()\, DensZ()}
+ at pfig{dens_xyz, Example of DensX() DensY() DensZ()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Cont projection sample, ContF projection sample, Dens projection sample, 3D samples
 @subsection Cont projection sample
+ at nav{}
 
-Functions @ref{ContXYZ} draw contour lines on plane perpendicular to corresponding axis. One of possible application is drawing projections of 3D field. The sample code is:
+Functions @ref{contz}, @ref{conty}, @ref{contx} draw contour lines on plane perpendicular to corresponding axis. One of possible application is drawing projections of 3D field. The sample code is:
 @verbatim
 int sample(mglGraph *gr)
 {
@@ -2780,14 +2908,15 @@ int sample(mglGraph *gr)
 }
 @end verbatim
 
- at pfig{cont_xyz, Example of ContX()\, ContY()\, ContZ()}
+ at pfig{cont_xyz, Example of ContX() ContY() ContZ()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node ContF projection sample, TriPlot and QuadPlot, Cont projection sample, 3D samples
 @subsection ContF projection sample
+ at nav{}
 
-Functions @code{ContFXYZ} draw filled contours on plane perpendicular to corresponding axis. One of possible application is drawing projections of 3D field. The sample code is:
+Functions @ref{contfz}, @ref{contfy}, @ref{contfx}, draw filled contours on plane perpendicular to corresponding axis. One of possible application is drawing projections of 3D field. The sample code is:
 @verbatim
 int sample(mglGraph *gr)
 {
@@ -2799,12 +2928,13 @@ int sample(mglGraph *gr)
 }
 @end verbatim
 
- at pfig{contf_xyz, Example of ContFX()\, ContFY()\, ContFZ()}
+ at pfig{contf_xyz, Example of ContFX() ContFY() ContFZ()}
 
 @c ------------------------------------------------------------------
- at c @external{}
- at node TriPlot and QuadPlot, Axial sample, ContF projection sample, 3D samples
+ at external{}
+ at node TriPlot and QuadPlot, Dots sample, ContF projection sample, 3D samples
 @subsection TriPlot and QuadPlot
+ at nav{}
 
 Function @ref{triplot} and @ref{quadplot} draw set of triangles (or quadrangles for @code{QuadPlot}) for irregular data arrays. Note, that you have to provide not only vertexes, but also the indexes of triangles or quadrangles. I.e. perform triangulation by some other library. The sample code is:
 @verbatim
@@ -2838,9 +2968,10 @@ int sample(mglGraph *gr)
 @pfig{triplot, Example of TriPlot() and QuadPlot()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Dots sample, , TriPlot and QuadPlot, 3D samples
 @subsection Dots sample
+ at nav{}
 
 Function @ref{dots} is another way to draw irregular points. @code{Dots} use color scheme for coloring (see @ref{Color scheme}). The sample code is:
 @verbatim
@@ -2867,6 +2998,7 @@ int sample(mglGraph *gr)
 @external{}
 @node Vector field samples, Hints, 3D samples, Examples
 @section Vector field samples
+ at nav{}
 
 Vector field visualization (especially in 3d case) is more or less complex task. MathGL provides 3 general types of plots: vector field itself (@code{Vect}), flow threads (@code{Flow}), and flow pipes with radius proportional to field amplitude (@code{Pipe}).
 
@@ -2949,9 +3081,10 @@ void mgls_prepare3v(HMDT ex, HMDT ey, HMDT ez)
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Vect sample, Vect3 sample, , Vector field samples
 @subsection Vect sample
+ at nav{}
 
 Function @ref{vect} is most standard way to visualize vector fields -- it draw a lot of arrows or hachures for each data cell. It have a lot of options which can be seen on the figure (and in the sample code). @code{Vect} use color scheme for coloring (see @ref{Color scheme}). The sample code is:
 @verbatim
@@ -2983,9 +3116,10 @@ int sample(mglGraph *gr)
 @pfig{vect, Example of Vect()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Vect3 sample, Traj sample, Vect sample, Vector field samples
 @subsection Vect3 sample
+ at nav{}
 
 Function @ref{vect3} draw just usual vector field plot but at slices of 3D data. The sample code is:
 @verbatim
@@ -3007,9 +3141,10 @@ int sample(mglGraph *gr)
 @pfig{vecta, Example of Vect3()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Traj sample, Flow sample, Vect3 sample, Vector field samples
 @subsection Traj sample
+ at nav{}
 
 Function @ref{traj} is 1D analogue of @code{Vect}. It draw vectors from specified points. The sample code is:
 @verbatim
@@ -3026,9 +3161,10 @@ int sample(mglGraph *gr)
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Flow sample, Pipe sample, Traj sample, Vector field samples
 @subsection Flow sample
+ at nav{}
 
 Function @ref{flow} is another standard way to visualize vector fields -- it draw lines (threads) which is tangent to local vector field direction. MathGL draw threads from edges of bounding box and from central slices. Sometimes it is not most appropriate variant -- you may want to use @code{FlowP} to specify manual position of threads. @code{Flow} use color scheme for coloring (see @ref{Color scheme}). At this warm color corresponds to normal flow (like attractor), cold one corresponds [...]
 @verbatim
@@ -3054,9 +3190,10 @@ int sample(mglGraph *gr)
 @pfig{flow, Example of Flow()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Pipe sample, Dew sample, Flow sample, Vector field samples
 @subsection Pipe sample
+ at nav{}
 
 Function @ref{pipe} is similar to @ref{flow} but draw pipes (tubes) which radius is proportional to the amplitude of vector field. @code{Pipe} use color scheme for coloring (see @ref{Color scheme}). At this warm color corresponds to normal flow (like attractor), cold one corresponds to inverse flow (like source). The sample code is:
 @verbatim
@@ -3082,9 +3219,10 @@ int sample(mglGraph *gr)
 @pfig{pipe, Example of Pipe()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Dew sample, , Pipe sample, Vector field samples
 @subsection Dew sample
+ at nav{}
 
 Function @ref{dew} is similar to @code{Vect} but use drops instead of arrows. The sample code is:
 @verbatim
@@ -3104,6 +3242,7 @@ int sample(mglGraph *gr)
 @external{}
 @node Hints, FAQ, Vector field samples, Examples
 @section Hints
+ at nav{}
 
 In this section I've included some small hints and advices for the improving of the quality of plots and for the demonstration of some non-trivial features of MathGL library. In contrast to previous examples I showed mostly the idea but not the whole drawing function.
 
@@ -3113,12 +3252,13 @@ In this section I've included some small hints and advices for the improving of
 * Types of transparency::
 * Axis projection::
 * Adding fog::
-* Several light sources::
+* Lighting sample::
 * Using primitives::
 * STFA sample::
 * Mapping visualization::
+* Making regular data::
 * Making histogram::
-* Nonlinear fitting sample::
+* Nonlinear fitting hints::
 * PDE solving hints::
 * MGL parser using::
 * Using options::
@@ -3128,9 +3268,10 @@ In this section I've included some small hints and advices for the improving of
 @end menu
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node ``Compound'' graphics, Transparency and lighting, , Hints
 @subsection ``Compound'' graphics
+ at nav{}
 
 As I noted above, MathGL functions (except the special one, like Clf()) do  not erase the previous plotting but just add the new one. It allows one to draw ``compound'' plots easily. For example, popular Matlab command @code{surfc} can be emulated in MathGL by 2 calls:
 @verbatim
@@ -3188,9 +3329,10 @@ int sample(mglGraph *gr)
 @pfig{combined, Example of ``combined'' plots}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Transparency and lighting, Types of transparency, ``Compound'' graphics, Hints
 @subsection Transparency and lighting
+ at nav{}
 
 Here I want to show how transparency and lighting both and separately change the look of a surface. So, there is code and picture for that:
 @verbatim
@@ -3215,9 +3357,10 @@ int sample(mglGraph *gr)
 @pfig{alpha, Example of transparency and lightings}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Types of transparency, Axis projection, Transparency and lighting, Hints
 @subsection Types of transparency
+ at nav{}
 
 MathGL library has advanced features for setting and handling the surface transparency. The simplest way to add transparency is the using of function @ref{alpha}. As a result, all further surfaces (and isosurfaces, density plots and so on) become transparent. However, their  look can be additionally improved.
 
@@ -3248,9 +3391,10 @@ int sample(mglGraph *gr)
 
 
 @c ------------------------------------------------------------------
- at c @external{}
- at node Axis projection, Adding fog, Ternary axis, Hints
+ at external{}
+ at node Axis projection, Adding fog, Types of transparency, Hints
 @subsection Axis projection
+ at nav{}
 
 You can easily make 3D plot and draw its x-,y-,z-projections (like in CAD) by using @ref{ternary} function with arguments: 4 for Cartesian, 5 for Ternary and 6 for Quaternary coordinates. The sample code is:
 @verbatim
@@ -3278,9 +3422,10 @@ int sample(mglGraph *gr)
 @c @pfig{projection6, Example of quaternary axis projections}
 
 @c ------------------------------------------------------------------
- at c @external{}
- at node Adding fog, Several light sources, Axis projection, Hints
+ at external{}
+ at node Adding fog, Lighting sample, Axis projection, Hints
 @subsection Adding fog
+ at nav{}
 
 MathGL can add a fog to the image. Its switching on is rather simple -- just use @ref{fog} function. There is the only feature -- fog is applied for whole image. Not to particular subplot. The sample code is:
 @verbatim
@@ -3297,9 +3442,10 @@ int sample(mglGraph *gr)
 @pfig{fog, Example of @code{Fog()}.}
 
 @c ------------------------------------------------------------------
- at c @external{}
- at node Several light sources, Using primitives, Adding fog, Hints
- at subsection Several light sources
+ at external{}
+ at node Lighting sample, Using primitives, Adding fog, Hints
+ at subsection Lighting sample
+ at nav{}
 
 In contrast to the most of other programs, MathGL supports several (up to 10) light sources. Moreover, the color each of them can be different: white (this is usual), yellow, red, cyan, green and so on. The use of several light sources may be interesting for the highlighting of some peculiarities of the plot or just to make an amusing picture. Note, each light source can be switched on/off individually. The sample code is:
 @verbatim
@@ -3318,10 +3464,42 @@ int sample(mglGraph *gr)
 
 @pfig{several_light, Example of several light sources.}
 
+Additionally, you can use local light sources and set to use diffise reflection instead of specular one (by default) or both kinds.
+ at verbatim
+int sample(mglGraph *gr)
+{
+  // use Quality=6 because need lighting in placed
+  int qual = gr->GetQuality();
+  gr->Light(true);   gr->SetQuality(6);
+
+  mglData a;	mgls_prepare2d(&a);
+  gr->SubPlot(2,2,0);  gr->Title("Default");
+  gr->Rotate(50,60); gr->Box(); gr->Surf(a);
+  gr->Line(mglPoint(-1,-0.7,1.7),mglPoint(-1,-0.7,0.7),"BA");
+  gr->AddLight(0,mglPoint(1,0,1),mglPoint(-2,-1,-1));
+  gr->SubPlot(2,2,1);  gr->Title("Local");
+  gr->Rotate(50,60); gr->Box(); gr->Surf(a);
+  gr->Line(mglPoint(1,0,1),mglPoint(-1,-1,0),"BAO");
+  gr->SetDiffuse(0);
+  gr->SubPlot(2,2,2);  gr->Title("no diffuse");
+  gr->Rotate(50,60); gr->Box(); gr->Surf(a);
+  gr->Line(mglPoint(1,0,1),mglPoint(-1,-1,0),"BAO");
+  gr->SetDiffuse(0.5);
+  gr->AddLight(0,mglPoint(1,0,1),mglPoint(-2,-1,-1),'w',0);
+  gr->SubPlot(2,2,3);  gr->Title("diffusive only");
+  gr->Rotate(50,60); gr->Box(); gr->Surf(a);
+  gr->Line(mglPoint(1,0,1),mglPoint(-1,-1,0),"BAO");
+  gr->SetQuality(qual);
+}
+ at end verbatim
+
+ at pfig{light, Example of different types of lighting.}
+
 @c ------------------------------------------------------------------
- at c @external{}
- at node Using primitives, STFA sample, Several light sources, Hints
+ at external{}
+ at node Using primitives, STFA sample, Lighting sample, Hints
 @subsection Using primitives
+ at nav{}
 
 MathGL provide a set of functions for drawing primitives (see @ref{Primitives}). Primitives are low level object, which used by most of plotting functions. Picture below demonstrate some of commonly used primitives.
 
@@ -3420,9 +3598,10 @@ Of course, the first variant is more suitable if you need to plot a lot of circl
 @pfig{venn, Example of Venn diagram.}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node STFA sample, Mapping visualization, Using primitives, Hints
 @subsection STFA sample
+ at nav{}
 
 Short-time Fourier Analysis (@ref{stfa}) is one of informative method for analyzing long rapidly oscillating 1D data arrays. It is used to determine the sinusoidal frequency and phase content of local sections of a signal as it changes over time.
 
@@ -3450,9 +3629,10 @@ int sample(mglGraph *gr)
 @pfig{stfa, Example of STFA().}
 
 @c ------------------------------------------------------------------
- at c @external{}
- at node Mapping visualization, Making histogram, STFA sample, Hints
+ at external{}
+ at node Mapping visualization, Making regular data, STFA sample, Hints
 @subsection Mapping visualization
+ at nav{}
 
 Sometime ago I worked with mapping and have a question about its visualization. Let me remember you that mapping is some transformation rule for one set of number to another one. The 1d mapping is just an ordinary function -- it takes a number and transforms it to another one. The 2d mapping (which I used) is a pair of functions which take 2 numbers and transform them to another 2 ones. Except general plots (like @ref{surfc}, @ref{surfa}) there is a special plot -- Arnold diagram. It sho [...]
 
@@ -3483,9 +3663,37 @@ int sample(mglGraph *gr)
 @pfig{map, Example of Map().}
 
 @c ------------------------------------------------------------------
- at c @external{}
- at node Making histogram, Nonlinear fitting sample, Mapping visualization, Hints
+ at external{}
+ at node Making regular data, Making histogram, Mapping visualization, Hints
+ at subsection Making regular data
+ at nav{}
+
+Sometimes, one have only unregular data, like as data on triangular grids, or experimental results and so on. Such kind of data cannot be used as simple as regular data (like matrices). Only few functions, like @ref{dots}, can handle unregular data as is.
+
+However, one can use built in triangulation functions for interpolating unregular data points to a regular data grids. There are 2 ways. First way, one can use @ref{triangulation} function to obtain list of vertexes for triangles. Later this list can be used in functions like @ref{triplot} or @ref{tricont}. Second way consist in usage of @ref{datagrid} function, which fill regular data grid by interpolated values, assuming that coordinates of the data grid is equidistantly distributed in [...]
+ at verbatim
+int sample(mglGraph *gr)
+{
+  mglData x(100), y(100), z(100);
+  gr->Fill(x,"2*rnd-1"); gr->Fill(y,"2*rnd-1"); gr->Fill(z,"v^2-w^2",x,y);
+  // first way - plot triangular surface for points
+  mglData d = mglTriangulation(x,y);
+  gr->Title("Triangulation");
+  gr->Rotate(40,60);	gr->Box();	gr->Light(true);
+  gr->TriPlot(d,x,y,z);	gr->TriPlot(d,x,y,z,"#k");
+  // second way - make regular data and plot it
+  mglData g(30,30);
+  gr->DataGrid(g,x,y,z);	gr->Mesh(g,"m");
+}
+ at end verbatim
+
+ at pfig{triangulation, Example of triangulation.}
+
+ at c ------------------------------------------------------------------
+ at external{}
+ at node Making histogram, Nonlinear fitting hints, Making regular data, Hints
 @subsection Making histogram
+ at nav{}
 
 Using the @ref{hist} function(s) for making regular distributions is one of useful fast methods to process and plot irregular data. @code{Hist} can be used to find some momentum of set of points by specifying weight function. It is possible to create not only 1D distributions but also 2D and 3D ones. Below I place the simplest sample code which demonstrate @ref{hist} usage:
 @verbatim
@@ -3511,9 +3719,10 @@ int sample(mglGraph *gr)
 
 
 @c ------------------------------------------------------------------
- at c @external{}
- at node Nonlinear fitting sample, PDE solving hints, Making histogram, Hints
+ at external{}
+ at node Nonlinear fitting hints, PDE solving hints, Making histogram, Hints
 @subsection Nonlinear fitting hints
+ at nav{}
 
 Nonlinear fitting is rather simple. All that you need is the data to fit, the approximation formula and the list of coefficients to fit (better with its initial guess values). Let me demonstrate it on the following simple example. First, let us use sin function with some random noise:
 @verbatim
@@ -3569,9 +3778,10 @@ int sample(mglGraph *gr)
 @pfig{fit, Example of nonlinear fitting.}
 
 @c ------------------------------------------------------------------
- at c @external{}
- at node PDE solving hints, MGL parser using, Nonlinear fitting sample, Hints
+ at external{}
+ at node PDE solving hints, MGL parser using, Nonlinear fitting hints, Hints
 @subsection PDE solving hints
+ at nav{}
 
 Solving of Partial Differential Equations (PDE, including beam tracing) and ray tracing (or finding particle trajectory) are more or less common task. So, MathGL have several functions for that. There are @code{mglRay()} for ray tracing, @code{mglPDE()} for PDE solving, @code{mglQO2d()} for beam tracing in 2D case (see @ref{Global functions}). Note, that these functions take ``Hamiltonian'' or equations as string values. And I don't plan now to allow one to use user-defined functions. Th [...]
 
@@ -3637,9 +3847,10 @@ int sample(mglGraph *gr)
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node MGL parser using, Using options, PDE solving hints, Hints
 @subsection MGL parser using
+ at nav{}
 
 Sometimes you may prefer to use MGL scripts in yours code. It is simpler (especially in comparison with C/Fortran interfaces) and provide faster way to plot the data with annotations, labels and so on. Class @code{mglParse} (@pxref{mglParse class} parse MGL scripts in C++. It have also the corresponding interface for C/Fortran.
 
@@ -3696,9 +3907,10 @@ int sample(HMGL gr)
 @pfig{parser, Example of MGL script parsing.}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Using options, ``Templates'', MGL parser using, Hints
 @subsection Using options
+ at nav{}
 
 @ref{Command options} allow the easy setup of the selected plot by changing global settings only for this plot. Often, options are used for specifying the range of automatic variables (coordinates). However, options allows easily change plot transparency, numbers of line or faces to be drawn, or add legend entries. The sample function for options usage is:
 @verbatim
@@ -3729,9 +3941,10 @@ void template(mglGraph *gr)
 @pfig{mirror, Example of options usage.}
 
 @c ------------------------------------------------------------------
- at c @external{}
- at node ``Templates'', Nonlinear fitting sample, Using options, Hints
+ at external{}
+ at node ``Templates'', Stereo image, Using options, Hints
 @subsection ``Templates''
+ at nav{}
 
 As I have noted before, the change of settings will influence only for the further plotting commands. This allows one to create ``template'' function which will contain settings and primitive drawing for often used plots. Correspondingly one may call this template-function for drawing simplification.
 
@@ -3761,9 +3974,10 @@ A template-function can also contain settings for font, transparency, lightning,
 I understand that this is obvious thing for any professional programmer, but I several times receive suggestion about ``templates'' ... So, I decide to point out it here.
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Stereo image, Reduce memory usage, ``Templates'', Hints
 @subsection Stereo image
+ at nav{}
 
 One can easily create stereo image in MathGL. Stereo image can be produced by making two subplots with slightly different rotation angles. The corresponding code looks like this:
 @verbatim
@@ -3784,9 +3998,10 @@ int sample(mglGraph *gr)
 @pfig{stereo, Example of stereo image.}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Reduce memory usage, , Stereo image, Hints
 @subsection Reduce memory usage
+ at nav{}
 
 By default MathGL save all primitives in memory, rearrange it and only later draw them on bitmaps. Usually, this speed up drawing, but may require a lot of memory for plots which contain a lot of faces (like @ref{cloud}, @ref{dew}). You can use @ref{quality} function for setting to use direct drawing on bitmap and bypassing keeping any primitives in memory. This function also allow you to decrease the quality of the resulting image but increase the speed of the drawing.
 
@@ -3805,6 +4020,7 @@ int sample(mglGraph *gr)
 @external{}
 @node FAQ, , Hints, Examples
 @section FAQ
+ at nav{}
 
 @table @strong
 @item The plot does not appear
@@ -3882,4 +4098,3 @@ Just use @code{Aspect(NAN,NAN)} for each subplot, or at the beginning of the dra
 @end table
 
 @external{}
-
diff --git a/texinfo/example_ru.texi b/texinfo/example_ru.texi
index f655354..6b765c7 100644
--- a/texinfo/example_ru.texi
+++ b/texinfo/example_ru.texi
@@ -1,9 +1,10 @@
 @c ------------------------------------------------------------------
- at chapter MathGL examples
+ at chapter Примеры MathGL
+ at nav{}
 
-This chapter contain information about basic and advanced MathGL, hints and samples for all types of graphics. I recommend you read first 2 sections one after another and at least look on @ref{Hints} section. Also I recommend you to look at @ref{General concepts} and @ref{FAQ}.
+В данной главе рассмотрены базовые и продвинутые возможности MathGL, даны советы по использованию и примеры для всех типов графиков. Я рекомендую прочитать вначале первые 2 раздела и посмотреть на раздел @ref{Hints}. Также рекомендую прочитать @ref{General concepts} и @ref{FAQ}.
 
-Note, that MathGL v.2.* have only 2 end-user interfaces: one for C/Fortran and similar languages which don't support classes, another one for C++/Python/Octave and similar languages which support classes. So, most of samples placed in this chapter can be run as is (after minor changes due to different syntaxes for different languages). For example, the C++ code
+Отмечу, что MathGL v.2.* имеет только пользовательских 2 интерфейса: один для языков подобных C или Fortran (не поддерживающих классы), другой для языков подобных C++/Python/Octave, которые поддерживают классы. При этом все классы являются "оберткой" С-ого интерфейсы, а функции-члены классов -- inline вызовами функций С. Поэтому, в большинстве примеров в этой главе я буду приводить только один вариант кода, который после минимальных изменений синтаксиса может быть применен для других язы [...]
 @verbatim
 #include <mgl2/mgl.h>
 int main()
@@ -13,20 +14,20 @@ int main()
   gr.WriteFrame("test.png");
 }
 @end verbatim
-in Python will be as
+на Python будет выглядеть как
 @verbatim
 from mathgl import *
 gr = mglGraph();
 gr.FPlot("sin(pi*x)");
 gr.WriteFrame("test.png");
 @end verbatim
-in Octave will be as (you need first install MathGL package by command @code{octave:1> pkg install /usr/share/mathgl/octave/mathgl.tar.gz} from @code{sudo octave})
+в Octave он будет почти тем же
 @verbatim
 gr = mglGraph();
 gr.FPlot("sin(pi*x)");
 gr.WriteFrame("test.png");
 @end verbatim
-in C will be as
+в C необходимо будет найти С-ые аналоги функций (из документации) и указать все их аргументы явно
 @verbatim
 #include <mgl2/mgl_cf.h>
 int main()
@@ -37,7 +38,7 @@ int main()
   mgl_delete_graph(gr);
 }
 @end verbatim
-in Fortran will be as
+в Fortran помимо этого придется определить функции возвращающие указатели на объекты как функции возвращающие целое
 @verbatim
 integer gr, mgl_create_graph
 gr = mgl_create_graph(600,400);
@@ -45,7 +46,7 @@ call mgl_fplot(gr,'sin(pi*x)','','');
 call mgl_write_frame(gr,'test.png','');
 call mgl_delete_graph(gr);
 @end verbatim
-and so on.
+и т.д.
 
 
 
@@ -65,35 +66,35 @@ and so on.
 @c ------------------------------------------------------------------
 @external{}
 @node Basic usage, Advanced usage, , Examples
- at section Basic usage
+ at section Основы использования
+ at nav{}
 
-MathGL library can be used by several manners. Each has positive and negative sides:
+Библиотеку MathGL можно использовать несколькими способами, каждый из которых имеет свои достоинства и недостатки:
 @itemize @bullet
 @item
- at emph{Using of MathGL library features for creating graphical window (requires FLTK, Qt or GLUT libraries).}
+ at emph{Использовать возможности MathGL для создания графического окна (требуется FLTK, Qt или GLUT библиотеки).}
 
-Positive side is the possibility to view the plot at once and to modify it (rotate, zoom or switch on transparency or lighting) by hand or by mouse. Negative sides are: the need  of X-terminal and limitation consisting in working with the only one set of data at a time.
+Положительная сторона состоит в возможности сразу увидеть график и быстро его мышкой поправить (повернуть, приблизить, выключить прозрачность или освещение и т.д.). Однако, в этом случае требуется наличие графической системы (нельзя запускать на удаленной машине), и работать можно только с одним набором данных одновременно.
 
 @item
- at emph{Direct writing to file in bitmap or vector format without creation of graphical window.}
+ at emph{Прямой вывод в файл в растровом или векторном формате, без создания графического окна.}
 
-Positive aspects are: batch processing of similar data set (for example, a set of resulting data files for different calculation parameters), running from the console program (including the cluster calculation), fast and automated drawing, saving pictures for further analysis (or demonstration). Negative sides are: the usage of the external program for picture viewing. Also, the data plotting is non-visual. So, you have to imagine the picture (view angles, lighting and so on) before the  [...]
+Достоинства такого подхода: пакетная обработка похожих данных (например, набора расчетных файлов при различных условиях), возможность запуска из консольной программы (включая запуск на удаленном компьютере/сервере/кластере), более быстрая и автоматизированная отрисовка, сохранение графиков для последующего анализа непосредственно во время расчета. К недостаткам подхода можно отнести: использование внешней программы просмотра для построенных графиков, необходимость заранее представить кар [...]
 
 @item
- at emph{Drawing in memory with the following displaying by other graphical program.}
+ at emph{Рисовать график в памяти с последующим выводом на экран другой графической программой.}
 
-In this case the programmer has more freedom in selecting the window libraries (not only FLTK, Qt or GLUT), in positioning and surroundings control and so on. I recommend to use such way for ``stand alone'' programs.
+В этом случае программист имеет максимум свободы в выборе графической библиотеки (не только FLTK, Qt или GLUT), в расположении и выборе элементов управления графиком и т.д. Я рекомендую этот вариант для "самодостаточного" приложения.
 
 @item
- at emph{Using FLTK or Qt widgets provided by MathGL}
+ at emph{Использовать FLTK или Qt виджеты, предоставляемые MathGL}
 
-Here one can use a set of standard widgets which support export to many file formats, copying to clipboard, handle mouse and so on. 
+Вы также можете использовать ряд элементов управления (виджетов), которые позволяют отобразить график, сохранить его в файл в различных форматах или скопировать в буфер обмена, обработать движение/клики мышкой и пр.
 @end itemize
 
-MathGL drawing can be created not only by object oriented languages (like, C++ or Python), but also by pure C or Fortran-like languages. The usage of last one is mostly identical to usage of classes (except the different function names). But there are some differences. C functions must have argument HMGL (for graphics) and/or HMDT (for data arrays) which specifies the object for drawing or manipulating (changing). Fortran users may regard these variables as integer. So, firstly the user  [...]
- at c Also, all arguments of C function have to be defined. So there are several functions with practically identical names doing practically the same. But some of them have simplified interface for the quick plotting and some of them have access to all plotting parameters for manual tunning.
+Графики MathGL могут быть созданы не только с помощью объектно-ориентированных языков (например, C++ или Python), но и на C или Fortran подобных языках. Использование последних в основном идентичны использованию классов (за исключением различных имен функций). Различие состоит в обязательном предварительном создании (и удалении после использования) объектов типа HMGL (для графики) и/или HMDT (для данных). Пользователи Fortran могут считать эти переменные целочисленными с достаточной разр [...]
 
-Let me consider the aforesaid in more detail.
+Рассмотрим вышесказанное подробно.
 
 @menu
 * Using MathGL window::
@@ -107,15 +108,16 @@ Let me consider the aforesaid in more detail.
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Using MathGL window, Drawing to file, , Basic usage
- at subsection Using MathGL window
+ at subsection Использование окон MathGL
+ at nav{}
 @cindex window
 @cindex widgets
 
-The ``interactive'' way of drawing in MathGL consists in window creation  with help of class @code{mglWindow} or @code{mglGLUT} (see @ref{Widget classes}) and the following drawing in this window. There is a corresponding code:
+``Интерактивный'' способ использования MathGL состоит в создании окна с помощью классов @code{mglQT}, @code{mglFLTK} или @code{mglGLUT} (см. @ref{Widget classes}) и последующем рисовании в этом окне. Соответствующий код выглядит так:
 @verbatim
-#include <mgl2/window.h>
+#include <mgl2/qt.h>
 int sample(mglGraph *gr)
 {
   gr->Rotate(60,40);
@@ -125,18 +127,18 @@ int sample(mglGraph *gr)
 //-----------------------------------------------------
 int main(int argc,char **argv)
 {
-  mglWindow gr(sample,"MathGL examples");
+  mglQT gr(sample,"MathGL examples");
   return gr.Run();
 }
 @end verbatim
-Here callback function @code{sample} is defined. This function does all drawing. Other function @code{main} is entry point function for console program. For compilation, just execute the command
+Здесь используется callback функция @code{sample}, выполняющая собственно рисование. Функция @code{main} -- точка входа в программу -- создает окно (объект @var{gr} типа @code{mglQT}) и запускает цикл обработки сообщений (вызов @code{gr.Run()}). Для компиляции достаточно выполнить команду
 @verbatim
-gcc test.cpp -lmgl-wnd -lmgl
+gcc test.cpp -lmgl-qt -lmgl
 @end verbatim
 
-Alternatively you can create yours own class inherited from class @code{mglDraw} and re-implement the function @code{Draw()} in it:
+Альтернативный способ состоит в использовании класса, производного от @code{mglDraw} с переопределенной функцией @code{Draw()}:
 @verbatim
-#include <mgl2/window.h>
+#include <mgl2/qt.h>
 class Foo : public mglDraw
 {
 public:
@@ -153,11 +155,11 @@ int Foo::Draw(mglGraph *gr)
 int main(int argc,char **argv)
 {
   Foo foo;
-  mglWindow gr(&foo,"MathGL examples");
+  mglQT gr(&foo,"MathGL examples");
   return gr.Run();
 }
 @end verbatim
-Or use pure C-functions:
+Или в использовании функций С:
 @verbatim
 #include <mgl2/mgl_cf.h>
 int sample(HMGL gr, void *)
@@ -175,7 +177,7 @@ int main(int argc,char **argv)
 }
 @end verbatim
 
-The similar code can be written for @code{mglGLUT} window (function @code{sample()} is the same):
+Похожий код получается и при использовании окон @code{mglFLTK}, @code{mglGLUT} (функция @code{sample()} та же):
 @verbatim
 #include <mgl2/glut.h>
 int main(int argc,char **argv)
@@ -190,9 +192,10 @@ The rotation, shift, zooming, switching on/off transparency and lighting can be
 In this example function @code{sample} rotates axes (@code{Rotate()}, @pxref{Subplots and rotation}) and draws the bounding box (@code{Box()}). Drawing is placed in separate function since it will be used on demand when window canvas needs to be redrawn.
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Drawing to file, Animation, Using MathGL window, Basic usage
 @subsection Drawing to file
+ at nav{}
 
 Another way of using MathGL library is the direct writing of the picture to the file. It is most usable for plot creation during long calculation or for using of small programs (like Matlab or Scilab scripts) for visualizing repetitive sets of data. But the speed of drawing is much higher in comparison with a script language.
 
@@ -231,9 +234,10 @@ int main(int ,char **)
 The difference from the previous one is using other function @code{WriteEPS()} for EPS format instead of function @code{WritePNG()}. Also, there is no switching on of the plot transparency @code{Alpha} since EPS format does not support it.
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Animation, Drawing in memory, Drawing to file, Basic usage
 @subsection Animation
+ at nav{}
 
 Widget classes (@code{mglWindow}, @code{mglGLUT}) support a delayed drawing, when all plotting functions are called once at the beginning of writing to memory lists. Further program displays the saved lists faster. Resulting redrawing will be faster but it requires sufficient memory. Several lists (frames) can be displayed one after another (by pressing @samp{,}, @samp{.}) or run as cinema. To switch these feature on one needs to modify function @code{sample}:
 @verbatim
@@ -364,9 +368,10 @@ Created files can be converted to movie by help of a lot of programs. For exampl
 Finally, you can use @code{mglconv} tool for doing the same with MGL scripts (@pxref{Utilities}).
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Drawing in memory, Using QMathGL, Animation, Basic usage
 @subsection Drawing in memory
+ at nav{}
 
 The last way of MathGL using is the drawing in memory. Class @code{mglGraph} allows one  to create a bitmap picture in memory. Further this picture can be displayed in window by some window libraries (like wxWidgets, FLTK, Windows GDI and so on). For example, the code for drawing in wxWidget library looks like:
 @verbatim
@@ -422,9 +427,10 @@ void MyWidget::paintEvent(QPaintEvent *)
 @end verbatim
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Using QMathGL, MathGL and PyQt, Drawing in memory, Basic usage
 @subsection Using QMathGL
+ at nav{}
 
 MathGL have several interface widgets for different widget libraries. There are QMathGL for Qt, Fl_MathGL for FLTK. These classes provide control which display MathGL graphics. Unfortunately there is no uniform interface for widget classes because all libraries have slightly different set of functions, features and so on. However the usage of MathGL widgets is rather simple. Let me show it on the example of QMathGL.
 
@@ -460,9 +466,10 @@ int main(int argc,char **argv)
 @end verbatim
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node MathGL and PyQt, MathGL and MPI, Using QMathGL, Basic usage
 @subsection MathGL and PyQt
+ at nav{}
 
 Generally SWIG based classes (including the Python one) are the same as C++ classes. However, there are few tips for using MathGL with PyQt. Below I place a very simple python code which demonstrate how MathGL can be used with PyQt. This code is mostly written by Prof. Dr. Heino Falcke. You can just copy it to a file @code{mgl-pyqt-test.py} and execute it from python shell by command @code{execfile("mgl-pyqt-test.py")}
 
@@ -534,16 +541,17 @@ qw.raise_()
 
 
 @c ------------------------------------------------------------------
- at c @external{}
- at node MathGL and MPI, , MathGL and PyQt, , Basic usage
+ at external{}
+ at node MathGL and MPI, , MathGL and PyQt, Basic usage
 @subsection MathGL and MPI
+ at nav{}
 
 For using MathGL in MPI program you just need to: (1) plot its own part of data for each running node; (2) collect resulting graphical information in a single program (for example, at node with rank=0); (3) save it. The sample code below demonstrate this for very simple sample of surface drawing.
 
 First you need to initialize MPI
 @verbatim
 #include <stdio.h>
-#include <mgl2/mgl.h>
+#include <mgl2/mpi.h>
 #include <mpi.h>
 
 int main(int argc, char *argv[])
@@ -561,7 +569,7 @@ Next step is data creation. For simplicity, I create data arrays with the same s
 @verbatim
   // initialize data similarly for all nodes
   mglData a(128,256);
-  mglGraph gr;
+  mglGraphMPI gr;
 @end verbatim
 
 Now, data should be filled by numbers. In real case, it should be some kind of calculations. But I just fill it by formula.
@@ -608,12 +616,13 @@ In my case the program is done, and I finalize MPI. In real program, you can rep
 }
 @end verbatim
 
-You can type @samp{mpic++ test.cpp -lmgl && mpirun -np 8 ./a.out} for compilation and running the sample program on 8 nodes. Note, that you have to set enable-mpi=ON at MathGL configure to use this feature.
+You can type @samp{mpic++ test.cpp -lmgl-mpi -lmgl && mpirun -np 8 ./a.out} for compilation and running the sample program on 8 nodes. Note, that you have to set enable-mpi=ON at MathGL configure to use this feature.
 
 @c ------------------------------------------------------------------
 @external{}
 @node Advanced usage, Data handling, Basic usage, Examples
 @section Advanced usage
+ at nav{}
 
 Now I show several non-obvious features of MathGL: several subplots in a single picture, curvilinear coordinates, text printing and so on. Generally you may miss this section at first reading.
 
@@ -630,9 +639,10 @@ Now I show several non-obvious features of MathGL: several subplots in a single
 @end menu
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Subplots, Axis and ticks, , Advanced usage
 @subsection Subplots
+ at nav{}
 
 Let me demonstrate possibilities of plot positioning and rotation. MathGL has a set of functions: @ref{subplot}, @ref{inplot}, @ref{title}, @ref{aspect} and @ref{rotate} and so on (see @ref{Subplots and rotation}). The order of their calling is strictly determined. First, one changes the position of plot in image area (functions @ref{subplot}, @ref{inplot} and @ref{multiplot}). Secondly, you can add the title of plot by @ref{title} function. After that one may rotate the plot (function @ [...]
 @verbatim
@@ -683,9 +693,10 @@ int sample(mglGraph *gr)
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Axis and ticks, Curvilinear coordinates, Subplots, Advanced usage
 @subsection Axis and ticks
+ at nav{}
 
 MathGL library can draw not only the bounding box but also the axes, grids, labels and so on. The ranges of axes and their origin (the point of intersection) are determined by functions @code{SetRange()}, @code{SetRanges()}, @code{SetOrigin()} (see @ref{Ranges (bounding box)}). Ticks on axis are specified by function @code{SetTicks}, @code{SetTicksVal}, @code{SetTicksTime} (see @ref{Ticks}). But usually
 
@@ -797,9 +808,10 @@ int sample(mglGraph *gr)
 You can see that MathGL automatically switch to log-ticks as we define log-axis formula (in difference from v.1.*). Moreover, it switch to log-ticks for any formula if axis range will be large enough (see right bottom plot). Another interesting feature is that you not necessary define usual log-axis (i.e. when coordinates are positive), but you can define ``minus-log'' axis when coordinate is negative (see left bottom plot).
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Curvilinear coordinates, Colorbars, Axis and ticks, Advanced usage
 @subsection Curvilinear coordinates
+ at nav{}
 
 As I noted in previous subsection, MathGL support curvilinear coordinates. In difference from other plotting programs and libraries, MathGL uses textual formulas for connection of the old (data) and new (output) coordinates. This allows one to plot in arbitrary coordinates. The following code plots the line @var{y}=0, @var{z}=0 in Cartesian, polar, parabolic and spiral coordinates:
 @verbatim
@@ -834,9 +846,10 @@ int sample(mglGraph *gr)
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Colorbars, Bounding box, Curvilinear coordinates, Advanced usage
 @subsection Colorbars
+ at nav{}
 
 MathGL handle @ref{colorbar} as special kind of axis. So, most of functions for axis and ticks setup will work for colorbar too. Colorbars can be in log-scale, and generally as arbitrary function scale; common factor of colorbar labels can be separated; and so on.
 
@@ -876,9 +889,10 @@ int sample(mglGraph *gr)
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Bounding box, Ternary axis, Colorbars, Advanced usage
 @subsection Bounding box
+ at nav{}
 
 Box around the plot is rather useful thing because it allows one to: see the plot boundaries, and better estimate points position since box contain another set of ticks. MathGL provide special function for drawing such box -- @ref{box} function. By default, it draw black or white box with ticks (color depend on transparency type, see @ref{Types of transparency}). However, you can change the color of box, or add drawing of rectangles at rear faces of box. Also you can disable ticks drawin [...]
 @verbatim
@@ -900,9 +914,10 @@ int sample(mglGraph *gr)
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Ternary axis, Text features, Bounding box, Advanced usage
 @subsection Ternary axis
+ at nav{}
 
 There are another unusual axis types which are supported by MathGL. These are ternary and quaternary axis. Ternary axis is special axis of 3 coordinates @var{a}, @var{b}, @var{c} which satisfy relation @var{a}+ at var{b}+ at var{c}=1. Correspondingly, quaternary axis is special axis of 4 coordinates @var{a}, @var{b}, @var{c}, @var{d} which satisfy relation @var{a}+ at var{b}+ at var{c}+ at var{d}=1.
 
@@ -953,9 +968,10 @@ int sample(mglGraph *gr)
 @pfig{ternary, Example of colorbars}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Text features, Legend sample, Ternary axis, Advanced usage
 @subsection Text features
+ at nav{}
 
 MathGL prints text by vector font. There are functions for manual specifying of text position (like @code{Puts}) and for its automatic selection (like @code{Label}, @code{Legend} and so on). MathGL prints text always in specified position even if it lies outside the bounding box. The default size of font is specified by functions @var{SetFontSize*} (see @ref{Font settings}). However, the actual size of output string depends on subplot size (depends on functions @code{SubPlot}, @code{InPl [...]
 
@@ -1021,9 +1037,10 @@ int sample(mglGraph *gr)
 @pfig{fonts, Example of font faces}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Legend sample, Cutting sample, Text features, Advanced usage
 @subsection Legend sample
+ at nav{}
 
 Legend is one of standard ways to show plot annotations. Basically you need to connect the plot style (line style, marker and color) with some text. In MathGL, you can do it by 2 methods: manually using @ref{addlegend} function; or use @samp{legend} option (see @ref{Command options}), which will use last plot style. In both cases, legend entries will be added into internal accumulator, which later used for legend drawing itself. @ref{clearlegend} function allow you to remove all saved le [...]
 
@@ -1058,9 +1075,10 @@ int sample(mglGraph *gr)
 @pfig{legend, Example of legend}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Cutting sample, , Legend sample, Advanced usage
 @subsection Cutting sample
+ at nav{}
 
 The last common thing which I want to show in this section is how one can cut off points from plot. There are 4 mechanism for that.
 @itemize @bullet
@@ -1109,6 +1127,7 @@ int sample(mglGraph *gr)
 @external{}
 @node Data handling, Data plotting, Advanced usage, Examples
 @section Data handling
+ at nav{}
 
 Class @code{mglData} contains all functions for the data handling in MathGL (@pxref{Data processing}). There are several matters why I use class @code{mglData} but not a single array: it does not depend on type of data (mreal or double), sizes of data arrays are kept with data, memory working is simpler and safer.
 
@@ -1119,9 +1138,10 @@ Class @code{mglData} contains all functions for the data handling in MathGL (@px
 @end menu
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Array creation, Linking array, , Data handling
 @subsection Array creation
+ at nav{}
 
 There are many ways in MathGL how data arrays can be created and filled.
 
@@ -1197,9 +1217,10 @@ or by using @code{Modify()} function
 The only non-obvious thing here is using multidimensional arrays in C/C++, i.e. arrays defined like @code{mreal dat[40][30];}. Since, formally these elements @code{dat[i]} can address the memory in arbitrary place you should use the proper function to convert such arrays to @code{mglData} object. For C++ this is functions like @code{mglData::Set(mreal **dat, int N1, int N2);}. For C this is functions like @code{mgl_data_set_mreal2(HMDT d, const mreal **dat, int N1, int N2);}. At this, yo [...]
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Linking array, Change data, Array creation, Data handling
 @subsection Linking array
+ at nav{}
 
 Sometimes the data arrays are so large, that one couldn't' copy its values to another array (i.e. into mglData). In this case, he can define its own class derived from @code{mglDataA} (see @ref{mglDataA class}) or can use @code{Link} function.
 
@@ -1215,9 +1236,10 @@ Creating the link is rather simple -- just the same as using @code{Set} function
 @end verbatim
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Change data, , Linking array, Data handling
 @subsection Change data
+ at nav{}
 
 MathGL has functions for data processing: differentiating, integrating, smoothing and so on (for more detail, see @ref{Data processing}). Let us consider some examples. The simplest ones are integration and differentiation. The direction in which operation will be performed is specified by textual string, which may contain symbols @samp{x}, @samp{y} or @samp{z}. For example, the call of @code{Diff("x")} will differentiate data along @samp{x} direction; the call of @code{Integral("xy")} p [...]
 @verbatim
@@ -1342,6 +1364,7 @@ int sample(mglGraph *gr)
 @external{}
 @node Data plotting, 1D samples, Data handling, Examples
 @section Data plotting
+ at nav{}
 
 Let me now show how to plot the data. Next section will give much more examples for all plotting functions. Here I just show some basics. MathGL generally has 2 types of plotting functions. Simple variant requires a single data array for plotting, other data (coordinates) are considered uniformly distributed in axis range. Second variant requires data arrays for all coordinates. It allows one to plot rather complex multivalent curves and surfaces (in case of parametric dependencies). Usu [...]
 
@@ -1463,6 +1486,7 @@ int sample(mglGraph *gr)
 @external{}
 @node 1D samples, 2D samples, Data plotting, Examples
 @section 1D samples
+ at nav{}
 
 This section is devoted to visualization of 1D data arrays. 1D means the data which depend on single index (parameter) like curve in parametric form @{x(i),y(i),z(i)@}, i=1...n. Most of samples will use the same data for plotting. So, I put its initialization in separate function
 @verbatim
@@ -1531,6 +1555,7 @@ void mgls_prepare1d(HMDT y, HMDT y1=0, HMDT y2=0, HMDT x1=0, HMDT x2=0)
 * Chart sample::
 * BoxPlot sample::
 * Candle sample::
+* OHLC sample::
 * Error sample::
 * Mark sample::
 * TextMark sample::
@@ -1543,9 +1568,10 @@ void mgls_prepare1d(HMDT y, HMDT y1=0, HMDT y2=0, HMDT x1=0, HMDT x2=0)
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Plot sample, Radar sample, , 1D samples
 @subsection Plot sample
+ at nav{}
 
 Function @ref{plot} is most standard way to visualize 1D data array. By default, @code{Plot} use colors from palette. However, you can specify manual color/palette, and even set to use new color for each points by using @samp{!} style. Another feature is @samp{ } style which draw only markers without line between points. The sample code is:
 @verbatim
@@ -1574,9 +1600,10 @@ int sample(mglGraph *gr)
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Radar sample, Step sample, Plot sample, 1D samples
 @subsection Radar sample
+ at nav{}
 
 Function @ref{radar} plot is variant of @code{Plot} one, which make plot in polar coordinates and draw radial rays in point directions. If you just need a plot in polar coordinates then I recommend to use @ref{Curvilinear coordinates} or @code{Plot} in parabolic form with @code{x=r*cos(fi); y=r*sin(fi);}. The sample code is:
 @verbatim
@@ -1592,9 +1619,10 @@ int sample(mglGraph *gr)
 @pfig{radar, Example of Radar()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Step sample, Tens sample, Radar sample, 1D samples
 @subsection Step sample
+ at nav{}
 
 Function @ref{step} plot data as stairs. It have the same options as @code{Plot}. The sample code is:
 @verbatim
@@ -1619,9 +1647,10 @@ int sample(mglGraph *gr)
 @pfig{step, Example of Step()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Tens sample, Area sample, Step sample, 1D samples
 @subsection Tens sample
+ at nav{}
 
 Function @ref{tens} is variant of @ref{plot} with smooth coloring along the curves. At this, color is determined as for surfaces (see @ref{Color scheme}). The sample code is:
 @verbatim
@@ -1645,9 +1674,10 @@ int sample(mglGraph *gr)
 @pfig{tens, Example of Tens()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Area sample, Region sample, Tens sample, 1D samples
 @subsection Area sample
+ at nav{}
 
 Function @ref{area} fill the area between curve and axis plane. It support gradient filling if 2 colors per curve is specified. The sample code is:
 @verbatim
@@ -1676,9 +1706,10 @@ int sample(mglGraph *gr)
 @pfig{area, Example of Area()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Region sample, Stem sample, Area sample, 1D samples
 @subsection Region sample
+ at nav{}
 
 Function @ref{region} fill the area between 2 curves. It support gradient filling if 2 colors per curve is specified. Also it can fill only the region y1<y<y2 if style @samp{i} is used. The sample code is:
 @verbatim
@@ -1704,9 +1735,10 @@ int sample(mglGraph *gr)
 @pfig{region, Example of Region()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Stem sample, Bars sample, Region sample, 1D samples
 @subsection Stem sample
+ at nav{}
 
 Function @ref{stem} draw vertical bars. It is most attractive if markers are drawn too. The sample code is:
 @verbatim
@@ -1730,9 +1762,10 @@ int sample(mglGraph *gr)
 @pfig{stem, Example of Stem()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Bars sample, Barh sample, Stem sample, 1D samples
 @subsection Bars sample
+ at nav{}
 
 Function @ref{bars} draw vertical bars. It have a lot of options: bar-above-bar (@samp{a} style), fall like (@samp{f} style), 2 colors for positive and negative values, wired bars (@samp{#} style), 3D variant. The sample code is:
 @verbatim
@@ -1768,9 +1801,10 @@ int sample(mglGraph *gr)
 @pfig{bars, Example of Bars()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Barh sample, Cones sample, Bars sample, 1D samples
 @subsection Barh sample
+ at nav{}
 
 Function @ref{barh} is the similar to @code{Bars} but draw horizontal bars. The sample code is:
 @verbatim
@@ -1797,9 +1831,10 @@ int sample(mglGraph *gr)
 @pfig{barh, Example of Barh()}
 
 @c ------------------------------------------------------------------
- at c @external{}
- at node Cones sample, Chart sample, Bars sample, 1D samples
+ at external{}
+ at node Cones sample, Chart sample, Barh sample, 1D samples
 @subsection Cones sample
+ at nav{}
 
 Function @ref{cones} is similar to @code{Bars} but draw cones. The sample code is:
 @verbatim
@@ -1807,18 +1842,24 @@ int sample(mglGraph *gr)
 {
   mglData ys(10,3);   ys.Modify("0.8*sin(pi*(2*x+y/2))+0.2*rnd");
   gr->Light(true);    gr->SetOrigin(0,0,0);
-  gr->SubPlot(2,2,0); gr->Title("Cones plot");
+  gr->SubPlot(3,2,0); gr->Title("Cones plot");
   gr->Rotate(50,60);  gr->Box();  gr->Cones(ys);
 
-  gr->SubPlot(2,2,1); gr->Title("2 colors");
+  gr->SubPlot(3,2,1); gr->Title("2 colors");
   gr->Rotate(50,60);  gr->Box();  gr->Cones(ys,"cbgGyr");
 
-  gr->SubPlot(2,2,2); gr->Title("'#' style");
+  gr->SubPlot(3,2,2); gr->Title("'#' style");
   gr->Rotate(50,60);  gr->Box();  gr->Cones(ys,"#");
 
-  gr->SubPlot(2,2,3); gr->Title("'a' style");
+  gr->SubPlot(3,2,3); gr->Title("'a' style");
   gr->SetRange('z',-2,2); // increase range since summation can exceed [-1,1]
   gr->Rotate(50,60);  gr->Box();  gr->Cones(ys,"a");
+
+  gr->SubPlot(3,2,4); gr->Title("'t' style");
+  gr->Rotate(50,60);  gr->Box();  gr->Cones(ys,"t");
+
+  gr->SubPlot(3,2,5); gr->Title("'4' style");
+  gr->Rotate(50,60);  gr->Box();  gr->Cones(ys,"4");
   return 0;
 }
 @end verbatim
@@ -1826,9 +1867,10 @@ int sample(mglGraph *gr)
 @pfig{cones, Example of Cones()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Chart sample, BoxPlot sample, Cones sample, 1D samples
 @subsection Chart sample
+ at nav{}
 
 Function @ref{chart} draw colored boxes with width proportional to data values. Use @samp{ } for empty box. Plot looks most attractive in polar coordinates -- well known pie chart. The sample code is:
 @verbatim
@@ -1855,9 +1897,10 @@ int sample(mglGraph *gr)
 @pfig{chart, Example of Chart()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node BoxPlot sample, Candle sample, Chart sample, 1D samples
 @subsection BoxPlot sample
+ at nav{}
 
 Function @ref{boxplot} draw box-and-whisker diagram. The sample code is:
 @verbatim
@@ -1873,9 +1916,10 @@ int sample(mglGraph *gr)
 @pfig{boxplot, Example of BoxPlot()}
 
 @c ------------------------------------------------------------------
- at c @external{}
- at node Candle sample, Error sample, BoxPlot sample, 1D samples
+ at external{}
+ at node Candle sample, OHLC sample, BoxPlot sample, 1D samples
 @subsection Candle sample
+ at nav{}
 
 Function @ref{candle} draw candlestick chart. This is a combination of a line-chart and a bar-chart, in that each bar represents the range of price movement over a given time interval. The sample code is:
 @verbatim
@@ -1893,9 +1937,31 @@ int sample(mglGraph *gr)
 @pfig{candle, Example of Candle()}
 
 @c ------------------------------------------------------------------
- at c @external{}
- at node Error sample, Mark sample, Candle sample, 1D samples
+ at external{}
+ at node OHLC sample, Error sample, Candle sample, 1D samples
+ at subsection OHLC sample
+ at nav{}
+
+Function @ref{ohlc} draw Open-High-Low-Close diagram. This diagram show vertical line for between maximal(high) and minimal(low) values, as well as horizontal lines before/after vertical line for initial(open)/final(close) values of some process. The sample code is:
+ at verbatim
+int sample(mglGraph *gr)
+{
+  mglData o(10), h(10), l(10), c(10);
+  gr->Fill(o,"0.5*sin(pi*x)");  gr->Fill(c,"0.5*sin(pi*(x+2/9))");
+  gr->Fill(l,"0.3*rnd-0.8");    gr->Fill(h,"0.3*rnd+0.5");
+  gr->SubPlot(1,1,0,"");  gr->Title("OHLC plot");
+  gr->Box();  gr->OHLC(o,h,l,c);
+  return 0;
+}
+ at end verbatim
+
+ at pfig{ohlc, Example of OHLC()}
+
+ at c ------------------------------------------------------------------
+ at external{}
+ at node Error sample, Mark sample, OHLC sample, 1D samples
 @subsection Error sample
+ at nav{}
 
 Function @ref{error} draw error boxes around the points. You can draw default boxes or semi-transparent symbol (like marker, see @ref{Line styles}). Also you can set individual color for each box. The sample code is:
 @verbatim
@@ -1932,10 +1998,36 @@ int sample(mglGraph *gr)
 
 @pfig{error, Example of Error()}
 
+Additionally, you can use solid large "marks" instead of error boxes by selecting proper style.
+ at verbatim
+int sample(mglGraph *gr)
+{
+  mglData x0(10), y0(10), ex(10), ey(10);
+  for(int i=0;i<10;i++)
+  {  x0.a[i] = mgl_rnd(); y0.a[i] = mgl_rnd(); ey.a[i] = ex.a[i] = 0.1; }
+  gr->SetRanges(0,1,0,1); gr->Alpha(true);
+  gr->SubPlot(4,3,0,"");  gr->Box(); gr->Error(x0,y0,ex,ey,"#+@");
+  gr->SubPlot(4,3,1,"");  gr->Box(); gr->Error(x0,y0,ex,ey,"#x@");
+  gr->SubPlot(4,3,2,"");  gr->Box(); gr->Error(x0,y0,ex,ey,"#s@","alpha 0.5");
+  gr->SubPlot(4,3,3,"");  gr->Box(); gr->Error(x0,y0,ex,ey,"s@");
+  gr->SubPlot(4,3,4,"");  gr->Box(); gr->Error(x0,y0,ex,ey,"d@");
+  gr->SubPlot(4,3,5,"");  gr->Box(); gr->Error(x0,y0,ex,ey,"#d@","alpha 0.5");
+  gr->SubPlot(4,3,6,"");  gr->Box(); gr->Error(x0,y0,ex,ey,"+@");
+  gr->SubPlot(4,3,7,"");  gr->Box(); gr->Error(x0,y0,ex,ey,"x@");
+  gr->SubPlot(4,3,8,"");  gr->Box(); gr->Error(x0,y0,ex,ey,"o@");
+  gr->SubPlot(4,3,9,"");  gr->Box(); gr->Error(x0,y0,ex,ey,"#o@","alpha 0.5");
+  gr->SubPlot(4,3,10,""); gr->Box(); gr->Error(x0,y0,ex,ey,"#.@");
+  gr->SubPlot(4,3,11,""); gr->Box(); gr->Error(x0,y0,ex,ey);
+}
+ at end verbatim
+
+ at pfig{error2, Example of Error() with marks}
+
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Mark sample, TextMark sample, Error sample, 1D samples
 @subsection Mark sample
+ at nav{}
 
 Function @ref{mark} draw markers at points. It is mostly the same as @code{Plot} but marker size can be variable. The sample code is:
 @verbatim
@@ -1951,9 +2043,10 @@ int sample(mglGraph *gr)
 @pfig{mark, Example of Mark()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node TextMark sample, Label sample, Mark sample, 1D samples
 @subsection TextMark sample
+ at nav{}
 
 Function @ref{textmark} like @code{Mark} but draw text instead of markers. The sample code is:
 @verbatim
@@ -1969,9 +2062,10 @@ int sample(mglGraph *gr)
 @pfig{textmark, Example of TextMark()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Label sample, Table sample, TextMark sample, 1D samples
 @subsection Label sample
+ at nav{}
 
 Function @ref{label} print text at data points. The string may contain @samp{%x}, @samp{%y}, @samp{%z} for x-, y-, z-coordinates of points, @samp{%n} for point index. The sample code is:
 @verbatim
@@ -1987,9 +2081,10 @@ int sample(mglGraph *gr)
 @pfig{label, Example of Label()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Table sample, Tube sample, Label sample, 1D samples
 @subsection Table sample
+ at nav{}
 
 Function @ref{table} draw table with data values. The sample code is:
 @verbatim
@@ -2012,9 +2107,10 @@ int sample(mglGraph *gr)
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Tube sample, Tape sample, Table sample, 1D samples
 @subsection Tube sample
+ at nav{}
 
 Function @ref{tube} draw tube with variable radius. The sample code is:
 @verbatim
@@ -2042,9 +2138,10 @@ int sample(mglGraph *gr)
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Tape sample, Torus sample, Tube sample, 1D samples
 @subsection Tape sample
+ at nav{}
 
 Function @ref{tape} draw tapes which rotate around the curve as normal and binormal. The sample code is:
 @verbatim
@@ -2076,9 +2173,10 @@ int sample(mglGraph *gr)
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Torus sample, , Tape sample, 1D samples
 @subsection Torus sample
+ at nav{}
 
 Function @ref{torus} draw surface of the curve rotation. The sample code is:
 @verbatim
@@ -2108,6 +2206,7 @@ int sample(mglGraph *gr)
 @external{}
 @node 2D samples, 3D samples, 1D samples, Examples
 @section 2D samples
+ at nav{}
 
 This section is devoted to visualization of 2D data arrays. 2D means the data which depend on 2 indexes (parameters) like matrix z(i,j)=z(x(i),y(j)), i=1...n, j=1...m or in parametric form @{x(i,j),y(i,j),z(i,j)@}. Most of samples will use the same data for plotting. So, I put its initialization in separate function
 @verbatim
@@ -2163,9 +2262,10 @@ void mgls_prepare2d(HMDT a, HMDT b=0, HMDT v=0)
 @end menu
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Surf sample, SurfC sample, , 2D samples
 @subsection Surf sample
+ at nav{}
 
 Function @ref{surf} is most standard way to visualize 2D data array. @code{Surf} use color scheme for coloring (see @ref{Color scheme}). You can use @samp{#} style for drawing black meshes on the surface. The sample code is:
 @verbatim
@@ -2194,9 +2294,10 @@ int sample(mglGraph *gr)
 @pfig{surf, Example of Surf()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node SurfC sample, SurfA sample, Surf sample, 2D samples
 @subsection SurfC sample
+ at nav{}
 
 Function @ref{surfc} is similar to @ref{surf} but its coloring is determined by another data. The sample code is:
 @verbatim
@@ -2212,9 +2313,10 @@ int sample(mglGraph *gr)
 @pfig{surfc, Example of SurfC()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node SurfA sample, Mesh sample, SurfC sample, 2D samples
 @subsection SurfA sample
+ at nav{}
 
 Function @ref{surfa} is similar to @ref{surf} but its transparency is determined by another data. The sample code is:
 @verbatim
@@ -2232,9 +2334,10 @@ int sample(mglGraph *gr)
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Mesh sample, Fall sample, SurfA sample, 2D samples
 @subsection Mesh sample
+ at nav{}
 
 Function @ref{mesh} draw wired surface. You can use @ref{meshnum} for changing number of lines to be drawn. The sample code is:
 @verbatim
@@ -2250,9 +2353,10 @@ int sample(mglGraph *gr)
 @pfig{mesh, Example of Mesh()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Fall sample, Belt sample, Mesh sample, 2D samples
 @subsection Fall sample
+ at nav{}
 
 Function @ref{fall} draw waterfall surface. You can use @ref{meshnum} for changing number of lines to be drawn. Also you can use @samp{x} style for drawing lines in other direction. The sample code is:
 @verbatim
@@ -2268,9 +2372,10 @@ int sample(mglGraph *gr)
 @pfig{fall, Example of Fall()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Belt sample, Boxs sample, Fall sample, 2D samples
 @subsection Belt sample
+ at nav{}
 
 Function @ref{belt} draw surface by belts. You can use @samp{x} style for drawing lines in other direction. The sample code is:
 @verbatim
@@ -2286,9 +2391,10 @@ int sample(mglGraph *gr)
 @pfig{belt, Example of Belt()}
 
 @c ------------------------------------------------------------------
- at c @external{}
- at node Boxs sample, Tile sample, Fall sample, 2D samples
+ at external{}
+ at node Boxs sample, Tile sample, Belt sample, 2D samples
 @subsection Boxs sample
+ at nav{}
 
 Function @ref{boxs} draw surface by boxes. You can use @samp{#} for drawing wire plot. The sample code is:
 @verbatim
@@ -2314,9 +2420,10 @@ int sample(mglGraph *gr)
 @pfig{boxs, Example of Boxs()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Tile sample, TileS sample, Boxs sample, 2D samples
 @subsection Tile sample
+ at nav{}
 
 Function @ref{tile} draw surface by tiles. The sample code is:
 @verbatim
@@ -2332,9 +2439,10 @@ int sample(mglGraph *gr)
 @pfig{tile, Example of Tile()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node TileS sample, Dens sample, Tile sample, 2D samples
 @subsection TileS sample
+ at nav{}
 
 Function @ref{tiles} is similar to @code{Tile} but tile sizes is determined by another data. This allows one to simulate transparency of the plot. The sample code is:
 @verbatim
@@ -2351,9 +2459,10 @@ int sample(mglGraph *gr)
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Dens sample, Cont sample, TileS sample, 2D samples
 @subsection Dens sample
+ at nav{}
 
 Function @ref{dens} draw density plot for surface. The sample code is:
 @verbatim
@@ -2379,9 +2488,10 @@ int sample(mglGraph *gr)
 @pfig{dens, Example of Dens()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Cont sample, ContF sample, Dens sample, 2D samples
 @subsection Cont sample
+ at nav{}
 
 Function @ref{cont} draw contour lines for surface. You can select automatic (default) or manual levels for contours, print contour labels, draw it on the surface (default) or at plane (as @code{Dens}). The sample code is:
 @verbatim
@@ -2406,9 +2516,10 @@ int sample(mglGraph *gr)
 @pfig{cont, Example of Cont()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node ContF sample, ContD sample, Cont sample, 2D samples
 @subsection ContF sample
+ at nav{}
 
 Function @ref{contf} draw filled contours.  You can select automatic (default) or manual levels for contours. The sample code is:
 @verbatim
@@ -2425,7 +2536,8 @@ int sample(mglGraph *gr)
   gr->SubPlot(2,2,2); gr->Title("'\\_' style");
   gr->Rotate(50,60);  gr->Box();  gr->ContF(a,"_");
 
-  gr->Fill(a1,"0.6*sin(2*pi*x+pi*(z+1)/2)*sin(3*pi*y+pi*z) + 0.4*cos(3*pi*(x*y)+pi*(z+1)^2/2)");
+  gr->Fill(a1,"0.6*sin(2*pi*x+pi*(z+1)/2)*sin(3*pi*y+pi*z) +
+               0.4*cos(3*pi*(x*y)+pi*(z+1)^2/2)");
   gr->SubPlot(2,2,3); gr->Title("several slices");
   gr->Rotate(50,60);  gr->Box();  gr->ContF(a1);
   return 0;
@@ -2435,9 +2547,10 @@ int sample(mglGraph *gr)
 @pfig{contf, Example of ContF()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node ContD sample, ContV sample, ContF sample, 2D samples
 @subsection ContD sample
+ at nav{}
 
 Function @ref{contd} is similar to @code{ContF} but with manual contour colors. The sample code is:
 @verbatim
@@ -2464,9 +2577,10 @@ int sample(mglGraph *gr)
 @pfig{contd, Example of ContD()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node ContV sample, Axial sample, ContD sample, 2D samples
 @subsection ContV sample
+ at nav{}
 
 Function @ref{contv} draw vertical cylinders (belts) at contour lines. The sample code is:
 @verbatim
@@ -2493,9 +2607,10 @@ int sample(mglGraph *gr)
 @pfig{contv, Example of ContV()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Axial sample, Grad sample, ContV sample, 2D samples
 @subsection Axial sample
+ at nav{}
 
 Function @ref{axial} draw surfaces of rotation for contour lines. You can draw wire surfaces (@samp{#} style) or ones rotated in other directions (@samp{x}, @samp{z} styles). The sample code is:
 @verbatim
@@ -2521,9 +2636,10 @@ int sample(mglGraph *gr)
 @pfig{axial, Example of Axial()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Grad sample, , Axial sample, 2D samples
 @subsection Grad sample
+ at nav{}
 
 Function @ref{grad} draw gradient lines for matrix. The sample code is:
 @verbatim
@@ -2543,6 +2659,7 @@ int sample(mglGraph *gr)
 @external{}
 @node 3D samples, Vector field samples, 2D samples, Examples
 @section 3D samples
+ at nav{}
 
 This section is devoted to visualization of 3D data arrays. 3D means the data which depend on 3 indexes (parameters) like tensor a(i,j,k)=a(x(i),y(j),x(k)), i=1...n, j=1...m, k=1...l or in parametric form @{x(i,j,k),y(i,j,k),z(i,j,k),a(i,j,k)@}. Most of samples will use the same data for plotting. So, I put its initialization in separate function
 @verbatim
@@ -2592,9 +2709,10 @@ void mgls_prepare3d(HMDT a, HMDT b=0)
 @end menu
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Surf3 sample, Surf3C sample, , 3D samples
 @subsection Surf3 sample
+ at nav{}
 
 Function @ref{surf3} is one of most suitable (for my opinion) functions to visualize 3D data. It draw the isosurface(s) -- surface(s) of constant amplitude (3D analogue of contour lines). You can draw wired isosurfaces if specify @samp{#} style. The sample code is:
 @verbatim
@@ -2617,9 +2735,10 @@ int sample(mglGraph *gr)
 @pfig{surf3, Example of Surf3()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Surf3C sample, Surf3A sample, Surf3 sample, 3D samples
 @subsection Surf3C sample
+ at nav{}
 
 Function @ref{surf3c} is similar to @ref{surf3} but its coloring is determined by another data. The sample code is:
 @verbatim
@@ -2636,9 +2755,10 @@ int sample(mglGraph *gr)
 @pfig{surf3c, Example of Surf3C()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Surf3A sample, Cloud sample, Surf3C sample, 3D samples
 @subsection Surf3A sample
+ at nav{}
 
 Function @ref{surf3a} is similar to @ref{surf3} but its transparency is determined by another data. The sample code is:
 @verbatim
@@ -2655,9 +2775,10 @@ int sample(mglGraph *gr)
 @pfig{surf3a, Example of Surf3A()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Cloud sample, Dens3 sample, Surf3A sample, 3D samples
 @subsection Cloud sample
+ at nav{}
 
 Function @ref{cloud} draw cloud-like object which is less transparent for higher data values. Similar plot can be created using many (about 10-20) @code{Surf3A(a,a)} isosurfaces. The sample code is:
 @verbatim
@@ -2668,8 +2789,8 @@ int sample(mglGraph *gr)
   gr->Rotate(50,60);  gr->Alpha(true);
   gr->Box();  gr->Cloud(c,"wyrRk");
 
-  gr->SubPlot(2,2,1); gr->Title("'!' style");
-  gr->Rotate(50,60);  gr->Box();  gr->Cloud(c,"!wyrRk");
+  gr->SubPlot(2,2,1); gr->Title("'i' style");
+  gr->Rotate(50,60);  gr->Box();  gr->Cloud(c,"iwyrRk");
 
   gr->SubPlot(2,2,2); gr->Title("'.' style");
   gr->Rotate(50,60);  gr->Box();  gr->Cloud(c,".wyrRk");
@@ -2683,9 +2804,10 @@ int sample(mglGraph *gr)
 @pfig{cloud, Example of Cloud()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Dens3 sample, Cont3 sample, Cloud sample, 3D samples
 @subsection Dens3 sample
+ at nav{}
 
 Function @ref{dens3} draw just usual density plot but at slices of 3D data. The sample code is:
 @verbatim
@@ -2703,9 +2825,10 @@ int sample(mglGraph *gr)
 @pfig{densa, Example of Dens3()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Cont3 sample, ContF3 sample, Dens3 sample, 3D samples
 @subsection Cont3 sample
+ at nav{}
 
 Function @ref{cont3} draw just usual contour lines but at slices of 3D data. The sample code is:
 @verbatim
@@ -2723,9 +2846,10 @@ int sample(mglGraph *gr)
 @pfig{conta, Example of Cont3()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node ContF3 sample, Dens projection sample, Cont3 sample, 3D samples
 @subsection ContF3 sample
+ at nav{}
 
 Function @ref{contf3} draw just usual filled contours but at slices of 3D data. The sample code is:
 @verbatim
@@ -2744,11 +2868,12 @@ int sample(mglGraph *gr)
 @pfig{contfa, Example of ContF3()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Dens projection sample, Cont projection sample, ContF3 sample, 3D samples
 @subsection Dens projection sample
+ at nav{}
 
-Functions @ref{DensXYZ} draw density plot on plane perpendicular to corresponding axis. One of possible application is drawing projections of 3D field. The sample code is:
+Functions @ref{densz}, @ref{densy}, @ref{densx} draw density plot on plane perpendicular to corresponding axis. One of possible application is drawing projections of 3D field. The sample code is:
 @verbatim
 int sample(mglGraph *gr)
 {
@@ -2760,14 +2885,15 @@ int sample(mglGraph *gr)
 }
 @end verbatim
 
- at pfig{dens_xyz, Example of DensX()\, DensY()\, DensZ()}
+ at pfig{dens_xyz, Example of DensX() DensY() DensZ()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Cont projection sample, ContF projection sample, Dens projection sample, 3D samples
 @subsection Cont projection sample
+ at nav{}
 
-Functions @ref{ContXYZ} draw contour lines on plane perpendicular to corresponding axis. One of possible application is drawing projections of 3D field. The sample code is:
+Functions @ref{contz}, @ref{conty}, @ref{contx} draw contour lines on plane perpendicular to corresponding axis. One of possible application is drawing projections of 3D field. The sample code is:
 @verbatim
 int sample(mglGraph *gr)
 {
@@ -2779,14 +2905,15 @@ int sample(mglGraph *gr)
 }
 @end verbatim
 
- at pfig{cont_xyz, Example of ContX()\, ContY()\, ContZ()}
+ at pfig{cont_xyz, Example of ContX() ContY() ContZ()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node ContF projection sample, TriPlot and QuadPlot, Cont projection sample, 3D samples
 @subsection ContF projection sample
+ at nav{}
 
-Functions @code{ContFXYZ} draw filled contours on plane perpendicular to corresponding axis. One of possible application is drawing projections of 3D field. The sample code is:
+Functions @ref{contfz}, @ref{contfy}, @ref{contfx} draw filled contours on plane perpendicular to corresponding axis. One of possible application is drawing projections of 3D field. The sample code is:
 @verbatim
 int sample(mglGraph *gr)
 {
@@ -2798,12 +2925,13 @@ int sample(mglGraph *gr)
 }
 @end verbatim
 
- at pfig{contf_xyz, Example of ContFX()\, ContFY()\, ContFZ()}
+ at pfig{contf_xyz, Example of ContFX() ContFY() ContFZ()}
 
 @c ------------------------------------------------------------------
- at c @external{}
- at node TriPlot and QuadPlot, Axial sample, ContF projection sample, 3D samples
+ at external{}
+ at node TriPlot and QuadPlot, Dots sample, ContF projection sample, 3D samples
 @subsection TriPlot and QuadPlot
+ at nav{}
 
 Function @ref{triplot} and @ref{quadplot} draw set of triangles (or quadrangles for @code{QuadPlot}) for irregular data arrays. Note, that you have to provide not only vertexes, but also the indexes of triangles or quadrangles. I.e. perform triangulation by some other library. The sample code is:
 @verbatim
@@ -2837,9 +2965,10 @@ int sample(mglGraph *gr)
 @pfig{triplot, Example of TriPlot() and QuadPlot()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Dots sample, , TriPlot and QuadPlot, 3D samples
 @subsection Dots sample
+ at nav{}
 
 Function @ref{dots} is another way to draw irregular points. @code{Dots} use color scheme for coloring (see @ref{Color scheme}). The sample code is:
 @verbatim
@@ -2866,6 +2995,7 @@ int sample(mglGraph *gr)
 @external{}
 @node Vector field samples, Hints, 3D samples, Examples
 @section Vector field samples
+ at nav{}
 
 Vector field visualization (especially in 3d case) is more or less complex task. MathGL provides 3 general types of plots: vector field itself (@code{Vect}), flow threads (@code{Flow}), and flow pipes with radius proportional to field amplitude (@code{Pipe}).
 
@@ -2948,9 +3078,10 @@ void mgls_prepare3v(HMDT ex, HMDT ey, HMDT ez)
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Vect sample, Vect3 sample, , Vector field samples
 @subsection Vect sample
+ at nav{}
 
 Function @ref{vect} is most standard way to visualize vector fields -- it draw a lot of arrows or hachures for each data cell. It have a lot of options which can be seen on the figure (and in the sample code). @code{Vect} use color scheme for coloring (see @ref{Color scheme}). The sample code is:
 @verbatim
@@ -2982,9 +3113,10 @@ int sample(mglGraph *gr)
 @pfig{vect, Example of Vect()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Vect3 sample, Traj sample, Vect sample, Vector field samples
 @subsection Vect3 sample
+ at nav{}
 
 Function @ref{vect3} draw just usual vector field plot but at slices of 3D data. The sample code is:
 @verbatim
@@ -3006,9 +3138,10 @@ int sample(mglGraph *gr)
 @pfig{vecta, Example of Vect3()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Traj sample, Flow sample, Vect3 sample, Vector field samples
 @subsection Traj sample
+ at nav{}
 
 Function @ref{traj} is 1D analogue of @code{Vect}. It draw vectors from specified points. The sample code is:
 @verbatim
@@ -3025,9 +3158,10 @@ int sample(mglGraph *gr)
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Flow sample, Pipe sample, Traj sample, Vector field samples
 @subsection Flow sample
+ at nav{}
 
 Function @ref{flow} is another standard way to visualize vector fields -- it draw lines (threads) which is tangent to local vector field direction. MathGL draw threads from edges of bounding box and from central slices. Sometimes it is not most appropriate variant -- you may want to use @code{FlowP} to specify manual position of threads. @code{Flow} use color scheme for coloring (see @ref{Color scheme}). At this warm color corresponds to normal flow (like attractor), cold one corresponds [...]
 @verbatim
@@ -3053,9 +3187,10 @@ int sample(mglGraph *gr)
 @pfig{flow, Example of Flow()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Pipe sample, Dew sample, Flow sample, Vector field samples
 @subsection Pipe sample
+ at nav{}
 
 Function @ref{pipe} is similar to @ref{flow} but draw pipes (tubes) which radius is proportional to the amplitude of vector field. @code{Pipe} use color scheme for coloring (see @ref{Color scheme}). At this warm color corresponds to normal flow (like attractor), cold one corresponds to inverse flow (like source). The sample code is:
 @verbatim
@@ -3081,9 +3216,10 @@ int sample(mglGraph *gr)
 @pfig{pipe, Example of Pipe()}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Dew sample, , Pipe sample, Vector field samples
 @subsection Dew sample
+ at nav{}
 
 Function @ref{dew} is similar to @code{Vect} but use drops instead of arrows. The sample code is:
 @verbatim
@@ -3103,6 +3239,7 @@ int sample(mglGraph *gr)
 @external{}
 @node Hints, FAQ, Vector field samples, Examples
 @section Hints
+ at nav{}
 
 In this section I've included some small hints and advices for the improving of the quality of plots and for the demonstration of some non-trivial features of MathGL library. In contrast to previous examples I showed mostly the idea but not the whole drawing function.
 
@@ -3112,12 +3249,13 @@ In this section I've included some small hints and advices for the improving of
 * Types of transparency::
 * Axis projection::
 * Adding fog::
-* Several light sources::
+* Lighting sample::
 * Using primitives::
 * STFA sample::
 * Mapping visualization::
+* Making regular data::
 * Making histogram::
-* Nonlinear fitting sample::
+* Nonlinear fitting hints::
 * PDE solving hints::
 * MGL parser using::
 * Using options::
@@ -3127,9 +3265,10 @@ In this section I've included some small hints and advices for the improving of
 @end menu
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node ``Compound'' graphics, Transparency and lighting, , Hints
 @subsection ``Compound'' graphics
+ at nav{}
 
 As I noted above, MathGL functions (except the special one, like Clf()) do  not erase the previous plotting but just add the new one. It allows one to draw ``compound'' plots easily. For example, popular Matlab command @code{surfc} can be emulated in MathGL by 2 calls:
 @verbatim
@@ -3187,9 +3326,10 @@ int sample(mglGraph *gr)
 @pfig{combined, Example of ``combined'' plots}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Transparency and lighting, Types of transparency, ``Compound'' graphics, Hints
 @subsection Transparency and lighting
+ at nav{}
 
 Here I want to show how transparency and lighting both and separately change the look of a surface. So, there is code and picture for that:
 @verbatim
@@ -3214,9 +3354,10 @@ int sample(mglGraph *gr)
 @pfig{alpha, Example of transparency and lightings}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Types of transparency, Axis projection, Transparency and lighting, Hints
 @subsection Types of transparency
+ at nav{}
 
 MathGL library has advanced features for setting and handling the surface transparency. The simplest way to add transparency is the using of function @ref{alpha}. As a result, all further surfaces (and isosurfaces, density plots and so on) become transparent. However, their  look can be additionally improved.
 
@@ -3247,9 +3388,10 @@ int sample(mglGraph *gr)
 
 
 @c ------------------------------------------------------------------
- at c @external{}
- at node Axis projection, Adding fog, Ternary axis, Hints
+ at external{}
+ at node Axis projection, Adding fog, Types of transparency, Hints
 @subsection Axis projection
+ at nav{}
 
 You can easily make 3D plot and draw its x-,y-,z-projections (like in CAD) by using @ref{ternary} function with arguments: 4 for Cartesian, 5 for Ternary and 6 for Quaternary coordinates. The sample code is:
 @verbatim
@@ -3277,9 +3419,10 @@ int sample(mglGraph *gr)
 @c @pfig{projection6, Example of quaternary axis projections}
 
 @c ------------------------------------------------------------------
- at c @external{}
- at node Adding fog, Several light sources, Axis projection, Hints
+ at external{}
+ at node Adding fog, Lighting sample, Axis projection, Hints
 @subsection Adding fog
+ at nav{}
 
 MathGL can add a fog to the image. Its switching on is rather simple -- just use @ref{fog} function. There is the only feature -- fog is applied for whole image. Not to particular subplot. The sample code is:
 @verbatim
@@ -3296,9 +3439,10 @@ int sample(mglGraph *gr)
 @pfig{fog, Example of @code{Fog()}.}
 
 @c ------------------------------------------------------------------
- at c @external{}
- at node Several light sources, Using primitives, Adding fog, Hints
- at subsection Several light sources
+ at external{}
+ at node Lighting sample, Using primitives, Adding fog, Hints
+ at subsection Lighting sample
+ at nav{}
 
 In contrast to the most of other programs, MathGL supports several (up to 10) light sources. Moreover, the color each of them can be different: white (this is usual), yellow, red, cyan, green and so on. The use of several light sources may be interesting for the highlighting of some peculiarities of the plot or just to make an amusing picture. Note, each light source can be switched on/off individually. The sample code is:
 @verbatim
@@ -3317,10 +3461,42 @@ int sample(mglGraph *gr)
 
 @pfig{several_light, Example of several light sources.}
 
+Additionally, you can use local light sources and set to use diffise reflection instead of specular one (by default) or both kinds.
+ at verbatim
+int sample(mglGraph *gr)
+{
+  // use Quality=6 because need lighting in placed
+  int qual = gr->GetQuality();
+  gr->Light(true);   gr->SetQuality(6);
+
+  mglData a;	mgls_prepare2d(&a);
+  gr->SubPlot(2,2,0);  gr->Title("Default");
+  gr->Rotate(50,60); gr->Box(); gr->Surf(a);
+  gr->Line(mglPoint(-1,-0.7,1.7),mglPoint(-1,-0.7,0.7),"BA");
+  gr->AddLight(0,mglPoint(1,0,1),mglPoint(-2,-1,-1));
+  gr->SubPlot(2,2,1);  gr->Title("Local");
+  gr->Rotate(50,60); gr->Box(); gr->Surf(a);
+  gr->Line(mglPoint(1,0,1),mglPoint(-1,-1,0),"BAO");
+  gr->SetDiffuse(0);
+  gr->SubPlot(2,2,2);  gr->Title("no diffuse");
+  gr->Rotate(50,60); gr->Box(); gr->Surf(a);
+  gr->Line(mglPoint(1,0,1),mglPoint(-1,-1,0),"BAO");
+  gr->SetDiffuse(0.5);
+  gr->AddLight(0,mglPoint(1,0,1),mglPoint(-2,-1,-1),'w',0);
+  gr->SubPlot(2,2,3);  gr->Title("diffusive only");
+  gr->Rotate(50,60); gr->Box(); gr->Surf(a);
+  gr->Line(mglPoint(1,0,1),mglPoint(-1,-1,0),"BAO");
+  gr->SetQuality(qual);
+}
+ at end verbatim
+
+ at pfig{light, Example of different types of lighting.}
+
 @c ------------------------------------------------------------------
- at c @external{}
- at node Using primitives, STFA sample, Several light sources, Hints
+ at external{}
+ at node Using primitives, STFA sample, Lighting sample, Hints
 @subsection Using primitives
+ at nav{}
 
 MathGL provide a set of functions for drawing primitives (see @ref{Primitives}). Primitives are low level object, which used by most of plotting functions. Picture below demonstrate some of commonly used primitives.
 
@@ -3419,9 +3595,10 @@ Of course, the first variant is more suitable if you need to plot a lot of circl
 @pfig{venn, Example of Venn diagram.}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node STFA sample, Mapping visualization, Using primitives, Hints
 @subsection STFA sample
+ at nav{}
 
 Short-time Fourier Analysis (@ref{stfa}) is one of informative method for analyzing long rapidly oscillating 1D data arrays. It is used to determine the sinusoidal frequency and phase content of local sections of a signal as it changes over time.
 
@@ -3449,9 +3626,10 @@ int sample(mglGraph *gr)
 @pfig{stfa, Example of STFA().}
 
 @c ------------------------------------------------------------------
- at c @external{}
- at node Mapping visualization, Making histogram, STFA sample, Hints
+ at external{}
+ at node Mapping visualization, Making regular data, STFA sample, Hints
 @subsection Mapping visualization
+ at nav{}
 
 Sometime ago I worked with mapping and have a question about its visualization. Let me remember you that mapping is some transformation rule for one set of number to another one. The 1d mapping is just an ordinary function -- it takes a number and transforms it to another one. The 2d mapping (which I used) is a pair of functions which take 2 numbers and transform them to another 2 ones. Except general plots (like @ref{surfc}, @ref{surfa}) there is a special plot -- Arnold diagram. It sho [...]
 
@@ -3482,9 +3660,37 @@ int sample(mglGraph *gr)
 @pfig{map, Example of Map().}
 
 @c ------------------------------------------------------------------
- at c @external{}
- at node Making histogram, Nonlinear fitting sample, Mapping visualization, Hints
+ at external{}
+ at node Making regular data, Making histogram, Mapping visualization, Hints
+ at subsection Making regular data
+ at nav{}
+
+Sometimes, one have only unregular data, like as data on triangular grids, or experimental results and so on. Such kind of data cannot be used as simple as regular data (like matrices). Only few functions, like @ref{dots}, can handle unregular data as is.
+
+However, one can use built in triangulation functions for interpolating unregular data points to a regular data grids. There are 2 ways. First way, one can use @ref{triangulation} function to obtain list of vertexes for triangles. Later this list can be used in functions like @ref{triplot} or @ref{tricont}. Second way consist in usage of @ref{datagrid} function, which fill regular data grid by interpolated values, assuming that coordinates of the data grid is equidistantly distributed in [...]
+ at verbatim
+int sample(mglGraph *gr)
+{
+  mglData x(100), y(100), z(100);
+  gr->Fill(x,"2*rnd-1"); gr->Fill(y,"2*rnd-1"); gr->Fill(z,"v^2-w^2",x,y);
+  // first way - plot triangular surface for points
+  mglData d = mglTriangulation(x,y);
+  gr->Title("Triangulation");
+  gr->Rotate(40,60);	gr->Box();	gr->Light(true);
+  gr->TriPlot(d,x,y,z);	gr->TriPlot(d,x,y,z,"#k");
+  // second way - make regular data and plot it
+  mglData g(30,30);
+  gr->DataGrid(g,x,y,z);	gr->Mesh(g,"m");
+}
+ at end verbatim
+
+ at pfig{triangulation, Example of triangulation.}
+
+ at c ------------------------------------------------------------------
+ at external{}
+ at node Making histogram, Nonlinear fitting hints, Making regular data, Hints
 @subsection Making histogram
+ at nav{}
 
 Using the @ref{hist} function(s) for making regular distributions is one of useful fast methods to process and plot irregular data. @code{Hist} can be used to find some momentum of set of points by specifying weight function. It is possible to create not only 1D distributions but also 2D and 3D ones. Below I place the simplest sample code which demonstrate @ref{hist} usage:
 @verbatim
@@ -3510,9 +3716,10 @@ int sample(mglGraph *gr)
 
 
 @c ------------------------------------------------------------------
- at c @external{}
- at node Nonlinear fitting sample, PDE solving hints, Making histogram, Hints
+ at external{}
+ at node Nonlinear fitting hints, PDE solving hints, Making histogram, Hints
 @subsection Nonlinear fitting hints
+ at nav{}
 
 Nonlinear fitting is rather simple. All that you need is the data to fit, the approximation formula and the list of coefficients to fit (better with its initial guess values). Let me demonstrate it on the following simple example. First, let us use sin function with some random noise:
 @verbatim
@@ -3568,9 +3775,10 @@ int sample(mglGraph *gr)
 @pfig{fit, Example of nonlinear fitting.}
 
 @c ------------------------------------------------------------------
- at c @external{}
- at node PDE solving hints, MGL parser using, Nonlinear fitting sample, Hints
+ at external{}
+ at node PDE solving hints, MGL parser using, Nonlinear fitting hints, Hints
 @subsection PDE solving hints
+ at nav{}
 
 Solving of Partial Differential Equations (PDE, including beam tracing) and ray tracing (or finding particle trajectory) are more or less common task. So, MathGL have several functions for that. There are @code{mglRay()} for ray tracing, @code{mglPDE()} for PDE solving, @code{mglQO2d()} for beam tracing in 2D case (see @ref{Global functions}). Note, that these functions take ``Hamiltonian'' or equations as string values. And I don't plan now to allow one to use user-defined functions. Th [...]
 
@@ -3636,9 +3844,10 @@ int sample(mglGraph *gr)
 
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node MGL parser using, Using options, PDE solving hints, Hints
 @subsection MGL parser using
+ at nav{}
 
 Sometimes you may prefer to use MGL scripts in yours code. It is simpler (especially in comparison with C/Fortran interfaces) and provide faster way to plot the data with annotations, labels and so on. Class @code{mglParse} (@pxref{mglParse class} parse MGL scripts in C++. It have also the corresponding interface for C/Fortran.
 
@@ -3693,9 +3902,10 @@ int sample(HMGL gr)
 @pfig{parser, Example of MGL script parsing.}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Using options, ``Templates'', MGL parser using, Hints
 @subsection Using options
+ at nav{}
 
 @ref{Command options} allow the easy setup of the selected plot by changing global settings only for this plot. Often, options are used for specifying the range of automatic variables (coordinates). However, options allows easily change plot transparency, numbers of line or faces to be drawn, or add legend entries. The sample function for options usage is:
 @verbatim
@@ -3726,9 +3936,10 @@ void template(mglGraph *gr)
 @pfig{mirror, Example of options usage.}
 
 @c ------------------------------------------------------------------
- at c @external{}
- at node ``Templates'', Nonlinear fitting sample, Using options, Hints
+ at external{}
+ at node ``Templates'', Stereo image, Using options, Hints
 @subsection ``Templates''
+ at nav{}
 
 As I have noted before, the change of settings will influence only for the further plotting commands. This allows one to create ``template'' function which will contain settings and primitive drawing for often used plots. Correspondingly one may call this template-function for drawing simplification.
 
@@ -3758,9 +3969,10 @@ A template-function can also contain settings for font, transparency, lightning,
 I understand that this is obvious thing for any professional programmer, but I several times receive suggestion about ``templates'' ... So, I decide to point out it here.
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Stereo image, Reduce memory usage, ``Templates'', Hints
 @subsection Stereo image
+ at nav{}
 
 One can easily create stereo image in MathGL. Stereo image can be produced by making two subplots with slightly different rotation angles. The corresponding code looks like this:
 @verbatim
@@ -3781,9 +3993,10 @@ int sample(mglGraph *gr)
 @pfig{stereo, Example of stereo image.}
 
 @c ------------------------------------------------------------------
- at c @external{}
+ at external{}
 @node Reduce memory usage, , Stereo image, Hints
 @subsection Reduce memory usage
+ at nav{}
 
 By default MathGL save all primitives in memory, rearrange it and only later draw them on bitmaps. Usually, this speed up drawing, but may require a lot of memory for plots which contain a lot of faces (like @ref{cloud}, @ref{dew}). You can use @ref{quality} function for setting to use direct drawing on bitmap and bypassing keeping any primitives in memory. This function also allow you to decrease the quality of the resulting image but increase the speed of the drawing.
 
@@ -3802,6 +4015,7 @@ int sample(mglGraph *gr)
 @external{}
 @node FAQ, , Hints, Examples
 @section FAQ
+ at nav{}
 
 @table @strong
 @item График не рисуется?!
@@ -3943,4 +4157,3 @@ int main (int argc, char ** argv)
 @end table
 
 @external{}
-
diff --git a/texinfo/formats_en.texi b/texinfo/formats_en.texi
index cda1232..96fee70 100644
--- a/texinfo/formats_en.texi
+++ b/texinfo/formats_en.texi
@@ -1,3 +1,5 @@
+ at nav{}
+
 This appendix contain description of file formats used by MathGL.
 
 @menu
@@ -10,6 +12,7 @@ This appendix contain description of file formats used by MathGL.
 @external{}
 @node Font files, MGLD format, , File formats
 @section Font files
+ at nav{}
 
 Starting from v.1.6 the MathGL library uses new font files. The font is defined in 4 files with suffixes @samp{*.vfm}, @samp{*_b.vfm}, @samp{*_i.vfm}, @samp{*_bi.vfm}. These files are text files containing the data for roman font, bold font, italic font and bold italic font. The files (or some symbols in the files) for bold, italic or bold italic fonts can be absent. In this case the roman glyph will be used for them. By analogy, if the bold italic font is absent but the bold font is pre [...]
 
@@ -34,6 +37,7 @@ Note: the closing contour line  is done automatically (so the last segment may b
 @external{}
 @node MGLD format, JSON format, Font files, File formats
 @section MGLD format
+ at nav{}
 
 MGLD is textual file, which contain all required information for drawing 3D image, i.e. it contain vertexes with colors and normales, primitives with all properties, textures, and glyph descriptions. MGLD file can be imported or viewed separately, without parsing data files itself.
 
@@ -73,6 +77,7 @@ Here nT is the number of triangles; nL is the number of line vertexes; xA, yA, x
 @external{}
 @node JSON format, , MGLD format, File formats
 @section JSON format
+ at nav{}
 
 MathGL can save points and primitives of 3D object. It contain a set of variables listed below.
 
@@ -104,7 +109,7 @@ array of glyph positions, each element is array in form [dx,dy]
 @item nglfs
 number of glyph descriptions
 @item glfs
-array of glyph descriptions, each element is array in form [nT, nL, [xA0, yA0, xB0, yB0, xC0, yC0, xA1, yA1, xB1, yB1, xC1, yC1 ...], [xP0, yP0, xP1, yP1 ...]]. Here nT is the number of triangles; nL is the number of line vertexes; xA, yA, xB, yB, xC, yC are coordinates of triangles; and xP, yP, xQ, yQ are coordinates of lines. Line coordinate xP=0x3fff, yP=0x3fff denote line breaking.
+array of glyph descriptions, each element is array in form @code{[nL, [xP0, yP0, xP1, yP1 ...]]}. Here @code{nL} is the number of line vertexes; and @code{xP, yP, xQ, yQ} are coordinates of lines. Line coordinate xP=0x3fff, yP=0x3fff denote line breaking.
 
 @end table
 @external{}
diff --git a/texinfo/formats_ru.texi b/texinfo/formats_ru.texi
index cda1232..96fee70 100644
--- a/texinfo/formats_ru.texi
+++ b/texinfo/formats_ru.texi
@@ -1,3 +1,5 @@
+ at nav{}
+
 This appendix contain description of file formats used by MathGL.
 
 @menu
@@ -10,6 +12,7 @@ This appendix contain description of file formats used by MathGL.
 @external{}
 @node Font files, MGLD format, , File formats
 @section Font files
+ at nav{}
 
 Starting from v.1.6 the MathGL library uses new font files. The font is defined in 4 files with suffixes @samp{*.vfm}, @samp{*_b.vfm}, @samp{*_i.vfm}, @samp{*_bi.vfm}. These files are text files containing the data for roman font, bold font, italic font and bold italic font. The files (or some symbols in the files) for bold, italic or bold italic fonts can be absent. In this case the roman glyph will be used for them. By analogy, if the bold italic font is absent but the bold font is pre [...]
 
@@ -34,6 +37,7 @@ Note: the closing contour line  is done automatically (so the last segment may b
 @external{}
 @node MGLD format, JSON format, Font files, File formats
 @section MGLD format
+ at nav{}
 
 MGLD is textual file, which contain all required information for drawing 3D image, i.e. it contain vertexes with colors and normales, primitives with all properties, textures, and glyph descriptions. MGLD file can be imported or viewed separately, without parsing data files itself.
 
@@ -73,6 +77,7 @@ Here nT is the number of triangles; nL is the number of line vertexes; xA, yA, x
 @external{}
 @node JSON format, , MGLD format, File formats
 @section JSON format
+ at nav{}
 
 MathGL can save points and primitives of 3D object. It contain a set of variables listed below.
 
@@ -104,7 +109,7 @@ array of glyph positions, each element is array in form [dx,dy]
 @item nglfs
 number of glyph descriptions
 @item glfs
-array of glyph descriptions, each element is array in form [nT, nL, [xA0, yA0, xB0, yB0, xC0, yC0, xA1, yA1, xB1, yB1, xC1, yC1 ...], [xP0, yP0, xP1, yP1 ...]]. Here nT is the number of triangles; nL is the number of line vertexes; xA, yA, xB, yB, xC, yC are coordinates of triangles; and xP, yP, xQ, yQ are coordinates of lines. Line coordinate xP=0x3fff, yP=0x3fff denote line breaking.
+array of glyph descriptions, each element is array in form @code{[nL, [xP0, yP0, xP1, yP1 ...]]}. Here @code{nL} is the number of line vertexes; and @code{xP, yP, xQ, yQ} are coordinates of lines. Line coordinate xP=0x3fff, yP=0x3fff denote line breaking.
 
 @end table
 @external{}
diff --git a/texinfo/index.html b/texinfo/index.html
index 3d48f35..ddffc89 100644
--- a/texinfo/index.html
+++ b/texinfo/index.html
@@ -1,12 +1,11 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html401/frameset.dtd">
-<html>
-<head><title>MathGL 2.0</title></head>
-
-<frameset rows="90,*" frameborder="0" noresize>
-  <frame src="title.html">
-  <frameset cols="150,*" frameborder="0" noresize>
-    <frame name="toc" src="toc_en.html">
-    <frame name="main" src="doc_en/doc_en_2.html">
-  </frameset>
-</frameset>
-</html>
+<!DOCTYPE HTML>
+<html lang="en-US">
+<head>
+	<meta charset="UTF-8">
+	<meta http-equiv="refresh" content="0;url=doc_en/Main.html">
+	<title>Page Redirection</title>
+</head>
+<body>
+	If you are not redirected automatically, follow the link to <a href='doc_en/Main.html'>English</a> or <a href='doc_ru/Main.html'>Russian</a> version.
+</body>
+</html>
\ No newline at end of file
diff --git a/texinfo/json.html b/texinfo/json.html
index 7f64219..e2ab752 100644
--- a/texinfo/json.html
+++ b/texinfo/json.html
@@ -4,7 +4,7 @@
 
 <head>
 	<script type="text/javascript" src="mathgl.js"></script>
-	<script type="text/javascript" src="inflate.min.js"></script>
+<!--	<script type="text/javascript" src="inflate.min.js"></script>-->
 </head>
 
 <body onload="main();">
diff --git a/texinfo/mathgl.js b/texinfo/mathgl.js
index 0ae9daf..c70b95f 100644
--- a/texinfo/mathgl.js
+++ b/texinfo/mathgl.js
@@ -115,14 +115,14 @@ var mgl_init = function(name)
 		}
 	};*/
 	req.send(null);
-	if(name[name.length-1]!='z')
+//	if(name[name.length-1]!='z')
 		txt = req.responseText;
-	else
-	{
-console.debug("compressed=",req.responseText);
-		var inflate = new Zlib.Inflate(req.responseText);
-		txt = inflate.decompress();
-	}
+// 	else
+// 	{
+// console.debug("compressed=",req.responseText);
+// 		var inflate = new Zlib.Inflate(req.responseText);
+// 		txt = inflate.decompress();
+// 	}
 	obj = JSON.parse(txt);
 
 	// copy original data for transformation
@@ -217,7 +217,7 @@ var mgl_draw_fast = function(obj, ctx, skip)
 			ctx.beginPath();
 			ctx.moveTo(obj.pp[n1][0],obj.pp[n1][1]);
 			ctx.lineTo(obj.pp[n2][0],obj.pp[n2][1]);
-			ctx.lineWidth = obj.prim[i][7];
+			ctx.lineWidth = obj.prim[i][7]/100;
 			ctx.stroke();
 		}
 		else
@@ -246,15 +246,14 @@ var mgl_draw_good = function(obj, ctx, skip)
 		switch(obj.prim[i][0])		// draw it depending on its type
 		{
 		case 0: // marks
-//			var d = 0.35*(obj.width>obj.height?obj.height:obj.width)*scl;
-			ctx.lineWidth = obj.prim[i][7]*obj.prim[i][6]*50;
-			mgl_draw_mark(ctx, obj.pp[n1][0], obj.pp[n1][1], n4, obj.prim[i][6], scl);
+			ctx.lineWidth = obj.prim[i][7]*obj.prim[i][6]*5e-4;
+			mgl_draw_mark(ctx, obj.pp[n1][0], obj.pp[n1][1], n4, obj.prim[i][6]/100, scl);
 			break;
 		case 1: // lines
 			ctx.beginPath();
 			ctx.moveTo(obj.pp[n1][0],obj.pp[n1][1]);
 			ctx.lineTo(obj.pp[n2][0],obj.pp[n2][1]);
-			ctx.lineWidth = obj.prim[i][7];
+			ctx.lineWidth = obj.prim[i][7]/100;
 			ctx.stroke();	break;
 		case 2: // triangles
 			ctx.beginPath();
@@ -274,11 +273,11 @@ var mgl_draw_good = function(obj, ctx, skip)
 			if(obj.prim[i][10].charAt(0)=='#')	ctx.stroke();
 			ctx.fill();	break;
 		case 4: // glyphs
-			var t=obj.prim[i][7]*deg;
-			var xx=obj.coor[n2][2],yy=-obj.coor[n2][3],zz=obj.coor[n2][4];
+			var t=obj.prim[i][7]*deg/100;
+			var xx=obj.coor[n2][2]/100,yy=-obj.coor[n2][3]/100,zz=obj.coor[n2][4]/100;
 			var xc = obj.b[0]*xx + obj.b[1]*yy + obj.b[2]*zz;
 			var yc = obj.b[3]*xx + obj.b[4]*yy + obj.b[5]*zz;
-			var zc = obj.b[6]*xx + obj.b[7]*yy + obj.b[8]*zz;
+//			var zc = obj.b[6]*xx + obj.b[7]*yy + obj.b[8]*zz;
 			var ll = xc*xc+yc*yc;
 			if(ll < 1e-10)	break;
 			if(ll<1e10 && t/deg<1e4)
@@ -287,19 +286,19 @@ var mgl_draw_good = function(obj, ctx, skip)
 				if(Math.abs(t)>Math.PI/2)	t += Math.PI;
 			}
 			else t=0;
-			var c=Math.cos(t), s=Math.sin(t), d=obj.prim[i][6]/2;
+			var c=Math.cos(t), s=Math.sin(t), d=obj.prim[i][6]/200;
 
 			var b=[d*c, d*s, d*s, -d*c, obj.pp[n1][0],obj.pp[n1][1]];
-			var x=obj.coor[n2][0]*scl, y=obj.coor[n2][1]*scl, f=obj.prim[i][8]*scl;
+			var x=obj.coor[n2][0]*scl/100, y=obj.coor[n2][1]*scl/100, f=obj.prim[i][8]*scl/1e5;
 			if(n3&8)
 			{
 				if(!(n3&4))	mgl_line_glyph(ctx, x,y, f,1,b);
-				mgl_line_glyph(ctx, x,y, f,0,b);
+				else	mgl_line_glyph(ctx, x,y, f,0,b);
 			}
 			else
 			{
 				if(!(n3&4)) mgl_fill_glyph(ctx, x,y, f,obj.glfs[n4],b);
-				mgl_wire_glyph(ctx, x,y, f,obj.glfs[n4],b);
+				else	mgl_wire_glyph(ctx, x,y, f,obj.glfs[n4],b);
 			}
 			break;
 		}
@@ -476,30 +475,39 @@ var mgl_draw_mark = function(ctx,x,y,st,size,d)
 // This function for internal use only!!!
 var mgl_fill_glyph = function(ctx, x,y, f,g,b)
 {
-	var xx,yy,j,xs,ys;
+	var xx,yy,j;
+	var np=0;	ctx.beginPath();
 	for(j=0;j<g[0];j++)
 	{
-		xx = x+f*g[2][6*j];	yy = y+f*g[2][6*j+1]; ctx.beginPath();
-		ctx.moveTo(b[4]+b[0]*xx+b[1]*yy, b[5]+b[2]*xx+b[3]*yy)
-		xx = x+f*g[2][6*j+2]; yy = y+f*g[2][6*j+3];
-		ctx.lineTo(b[4]+b[0]*xx+b[1]*yy, b[5]+b[2]*xx+b[3]*yy)
-		xx = x+f*g[2][6*j+4]; yy = y+f*g[2][6*j+5];
-		ctx.lineTo(b[4]+b[0]*xx+b[1]*yy, b[5]+b[2]*xx+b[3]*yy)
-		ctx.closePath();	ctx.fill();
+		xx = g[1][2*j]; yy = g[1][2*j+1];
+		if(xx==16383 && yy==16383)
+		{
+			ctx.closePath();	np = 1;
+		}
+		else if(np)
+		{
+			xx = x+f*xx;	yy = y+f*yy;	np = 0;
+			ctx.moveTo(b[4]+b[0]*xx+b[1]*yy, b[5]+b[2]*xx+b[3]*yy);
+		}
+		else
+		{
+			xx = x+f*xx;	yy = y+f*yy;
+			ctx.lineTo(b[4]+b[0]*xx+b[1]*yy, b[5]+b[2]*xx+b[3]*yy);
+		}
 	}
+	ctx.closePath();	ctx.fill('evenodd');
 }
 // This function for internal use only!!!
 var mgl_wire_glyph = function(ctx, x,y, f,g,b)
 {
-	var xx,yy,j,xs,ys;
-	var np=1;	ctx.beginPath();
-	for(j=0;j<g[1];j++)
+	var xx,yy,j;
+	var np=0;	ctx.beginPath();
+	for(j=0;j<g[0];j++)
 	{
-		xx = g[3][2*j]; yy = g[3][2*j+1];
+		xx = g[1][2*j]; yy = g[1][2*j+1];
 		if(xx==16383 && yy==16383)
 		{
-			ctx.closePath();	ctx.stroke();
-			ctx.beginPath();	np = 1;
+			ctx.closePath();	np = 1;
 		}
 		else if(np)
 		{
diff --git a/texinfo/mathgl_en.texi b/texinfo/mathgl_en.texi
index 54a5341..63e269a 100644
--- a/texinfo/mathgl_en.texi
+++ b/texinfo/mathgl_en.texi
@@ -1,6 +1,9 @@
 \input texinfo
+ at documentencoding UTF-8
+ at documentlanguage en
+
 @setfilename mathgl_en.info
- at set VERSION 2.1.2
+ at include version.texi
 @settitle MathGL @value{VERSION}
 @syncodeindex pg cp
 @comment %**end of header
@@ -49,59 +52,35 @@ This file documents the Mathematical Graphic Library (MathGL), a collection of c
 * Other classes::
 * Symbols and hot-keys::
 * File formats::
+ at ifhtml
 * TeX-like symbols::
+ at end ifhtml
+* Plotting time::
 * Copying This Manual::
 * Index::
 @end menu
 
 @macro external {}
 @end macro
-
- at ifhtml
- at macro fig {fname,text}
- at center @image{../\fname\, 11cm, , \text\, .png}
- at end macro
- at macro pfig {fname,text}
- at center @image{../png/\fname\, 11cm, , \text\, .png}
- at c @center @image{../png/\fname\, 11cm, , \text\. See also @uref{../pdf/\fname\.pdf, U3D PDF} sample, .png}
- at end macro
- at macro ufig {fname,width,text}
- at center @image{../udav/\fname\, \width\cm, , \text\, .png}
+ at macro nav {}
 @end macro
- at end ifhtml
 
- at ifnothtml
- at iftex
 @macro fig {fname,text}
- at center @image{\fname\, 11cm, , \text\, .png}
+ at center @image{\fname\, 11cm, , \text\, png}
 @end macro
 @macro pfig {fname,text}
- at center @image{png/\fname\, 11cm, , \text\, .png}
- at end macro
- at macro ufig {fname,width,text}
- at center @image{udav/\fname\, \width\cm, , \text\, .png}
- at end macro
- at end iftex
-
- at ifnottex
- at macro fig {fname,text}
- at c @center @image{\fname\, 11cm, , \text\, .png}
- at end macro
- at macro pfig {fname,text}
- at c @center @image{png/\fname\, 11cm, , \text\, .png}
+ at center @image{png/\fname\, 11cm, , \text\, png}
+ at c @center @image{../png/\fname\, 11cm, , \text\. See also @uref{../pdf/\fname\.pdf, U3D PDF} sample, .png}
 @end macro
 @macro ufig {fname,width,text}
- at c @center @image{../udav/\fname\, 11cm, , \text\, .png}
+ at center @image{udav/\fname\, \width\cm, , \text\, png}
 @end macro
- at end ifnottex
- at end ifnothtml
-
 
 @macro sref {arg}
 @xref{\arg\}, for sample code and picture.
 @end macro
 
- at node Overview, Examples, , Top
+ at node Overview, Examples, Top, Top
 @include overview_en.texi
 
 @node Examples, General concepts, Overview, Top
@@ -132,15 +111,37 @@ This file documents the Mathematical Graphic Library (MathGL), a collection of c
 @appendix Symbols and hot-keys
 @include symbols_en.texi
 
- at node File formats, TeX-like symbols, Symbols and hot-keys, Top
+ at node File formats, Plotting time, Symbols and hot-keys, Top
 @appendix File formats
 @include formats_en.texi
 
- at node TeX-like symbols, Copying This Manual, File formats, Top
+ at ifhtml
+ at node Plotting time, TeX-like symbols, File formats, Top
+ at end ifhtml
+ at ifnothtml
+ at node Plotting time, Copying This Manual, File formats, Top
+ at end ifnothtml
+ at appendix Plotting time
+
+Table below show plotting time in seconds for all samples in file @uref{http://sourceforge.net/p/mathgl/code/HEAD/tree/mathgl-2x/examples/samples.cpp, examples/samples.cpp}. The test was done in my laptop (i5-2430M) with 64-bit Debian.
+
+Few words about the speed. Firstly, direct bitmap drawing (Quality=4,5,6) is faster than buffered one (Quality=0,1,2), but sometimes it give incorrect result (see @ref{cloud}) and don't allow to export in vector or 3d formats (like EPS, SVG, PDF ...). Secondly, lower quality is faster than high one generally, i.e. Quality=1 is faster than Quality=2, and Quality=0 is faster than Quality=1. However, if plot contain a lot of faces (like @ref{cloud}, @ref{surf3}, @ref{pipe}, @ref{dew}) then  [...]
+
+Results for image size 800*600 (default one).
+ at include time.texi
+
+Results for image size 1920*1440 (print quality)
+ at include time_big.texi
+
+ at ifhtml
+ at node TeX-like symbols, Copying This Manual, Plotting time, Top
 @appendix TeX-like symbols
 @include appendix_en.texi
-
 @node Copying This Manual, Index, TeX-like symbols, Top
+ at end ifhtml
+ at ifnothtml
+ at node Copying This Manual, Index, Plotting time, Top
+ at end ifnothtml
 @appendix GNU Free Documentation License
 @include fdl.texi
 
diff --git a/texinfo/mathgl_ru.texi b/texinfo/mathgl_ru.texi
index 5c9f5f0..078911f 100644
--- a/texinfo/mathgl_ru.texi
+++ b/texinfo/mathgl_ru.texi
@@ -1,11 +1,12 @@
 \input texinfo
+ at c @documentencoding UTF-8
+ at documentlanguage ru
+
 @setfilename mathgl_ru.info
- at c @documentlanguage ru
 @documentencoding UTF-8
- at set VERSION 2.1.2
+ at include version.texi
 @settitle MathGL @value{VERSION}
 @syncodeindex pg cp
- at comment %**end of header
 
 @copying
 Это документация для MathGL (версии @value{VERSION}) -- библиотеки классов и функций для построения научной графики. Пожалуйста сообщайте о любых ошибках в этом руководстве на @email{mathgl.abalakin@@gmail.org}.
@@ -51,59 +52,34 @@
 * Other classes::
 * Symbols and hot-keys::
 * File formats::
+ at ifhtml
 * TeX-like symbols::
+ at end ifhtml
+* Plotting time::
 * Copying This Manual::
 * Index::
 @end menu
 
 @macro external {}
 @end macro
-
- at ifhtml
- at macro fig {fname,text}
- at center @image{../\fname\, 11cm, , \text\, .png}
- at end macro
- at macro pfig {fname,text}
- at center @image{../png/\fname\, 11cm, , \text\, .png}
- at c @center @image{../png/\fname\, 11cm, , \text\, .png}. See also @uref{../pdf/\fname\.pdf, U3D PDF} sample.
- at end macro
- at macro ufig {fname,width,text}
- at center @image{../udav/\fname\, \width\cm, , \text\, .png}
+ at macro nav {}
 @end macro
- at end ifhtml
 
- at ifnothtml
- at iftex
 @macro fig {fname,text}
- at center @image{\fname\, 11cm, , \text\, .png}
+ at center @image{\fname\, 11cm, , \text\, png}
 @end macro
 @macro pfig {fname,text}
- at center @image{png/\fname\, 11cm, , \text\, .png}
+ at center @image{png/\fname\, 11cm, , \text\, png}
 @end macro
 @macro ufig {fname,width,text}
- at center @image{udav/\fname\, \width\cm, , \text\, .png}
+ at center @image{udav/\fname\, \width\cm, , \text\, png}
 @end macro
- at end iftex
-
- at ifnottex
- at macro fig {fname,text}
- at c @center @image{\fname\, 11cm, , \text\, .png}
- at end macro
- at macro pfig {fname,text}
- at c @center @image{png/\fname\, 11cm, , \text\, .png}
- at end macro
- at macro ufig {fname,width,text}
- at c @center @image{../udav/\fname\, 11cm, , \text\, .png}
- at end macro
- at end ifnottex
- at end ifnothtml
-
 
 @macro sref {arg}
 См. раздел @ref{\arg\}, для примеров кода и графика.
 @end macro
 
- at node Overview, Examples, , Top
+ at node Overview, Examples, Top, Top
 @include overview_ru.texi
 
 @node Examples, General concepts, Overview, Top
@@ -134,15 +110,37 @@
 @appendix Symbols and hot-keys
 @include symbols_ru.texi
 
- at node File formats, TeX-like symbols, Symbols and hot-keys, Top
+ at node File formats, Plotting time, Symbols and hot-keys, Top
 @appendix File formats
 @include formats_ru.texi
 
- at node TeX-like symbols, Copying This Manual, File formats, Top
- at appendix TeX-like symbols
- at include appendix_ru.texi
+ at ifhtml
+ at node Plotting time, TeX-like symbols, File formats, Top
+ at end ifhtml
+ at ifnothtml
+ at node Plotting time, Copying This Manual, File formats, Top
+ at end ifnothtml
+ at appendix Время отрисовки
 
+В таблице показаны времена создания графика для всех примеров из файла @uref{http://sourceforge.net/p/mathgl/code/HEAD/tree/mathgl-2x/examples/samples.cpp, examples/samples.cpp}. Тест выполнен на моем ноутбуке (i5-2430M) с 64-bit Debian.
+
+Несколько слов о скорости. Во-первых, прямое рисование в память (Quality=4,5,6) быстрее буферизованного (Quality=0,1,2), но иногда результат некоректен (см. @ref{cloud}) и пропадает возможность экспорта в векторные и 3d форматы (например, EPS, SVG, PDF, ...). Во-вторых, обычно картинка худшего качества рисуется быстрее, т.е. Quality=1 быстрее Quality=2, и Quality=0 быстрее Quality=1. Однако, если график содержит множество граней (например @ref{cloud}, @ref{surf3}, @ref{pipe}, @ref{dew}), [...]
+
+Результаты для изображения размером 800*600 (по умолчанию).
+ at include time.texi
+
+Результаты для изображения размером 1920*1440 (для печати)
+ at include time_big.texi
+
+ at ifhtml
+ at node TeX-like symbols, Copying This Manual, Plotting time, Top
+ at appendix Символы TeX
+ at include appendix_en.texi
 @node Copying This Manual, Index, TeX-like symbols, Top
+ at end ifhtml
+ at ifnothtml
+ at node Copying This Manual, Index, Plotting time, Top
+ at end ifnothtml
 @appendix GNU Free Documentation License
 @include fdl.texi
 
diff --git a/texinfo/mgl_en.texi b/texinfo/mgl_en.texi
index 8f6a207..78d32bc 100644
--- a/texinfo/mgl_en.texi
+++ b/texinfo/mgl_en.texi
@@ -1,6 +1,9 @@
 \input texinfo
+ at documentencoding UTF-8
+ at documentlanguage en
+
 @setfilename mgl_en.info
- at set VERSION 2.1.3
+ at include version.texi
 @settitle MGL script language for version @value{VERSION}
 @syncodeindex pg cp
 @comment %**end of header
@@ -51,33 +54,15 @@ This file documents the MGL script language. It corresponds to release @value{VE
 
 @macro external {}
 @end macro
-
- at ifhtml
- at macro fig {fname,text}
- at center @image{\fname\, 11cm, , \text\, .png}
- at end macro
- at macro pfig {fname,text}
- at center @image{png/\fname\, 11cm, , \text\, .png}
- at end macro
- at end ifhtml
-
- at ifnothtml
- at iftex
- at macro fig {fname,text}
- at center @image{\fname\, 11cm, , \text\, .png}
- at end macro
- at macro pfig {fname,text}
- at center @image{png/\fname\, 11cm, , \text\, .png}
+ at macro nav {}
 @end macro
- at end iftex
 
- at ifnottex
 @macro fig {fname,text}
+ at center @image{\fname\, 11cm, , \text\, png}
 @end macro
 @macro pfig {fname,text}
+ at center @image{png/\fname\, 11cm, , \text\, png}
 @end macro
- at end ifnottex
- at end ifnothtml
 
 @macro sref {arg}
 @xref{\arg\}, for sample code and picture.
diff --git a/texinfo/mgl_ru.texi b/texinfo/mgl_ru.texi
index 82873e3..3246535 100644
--- a/texinfo/mgl_ru.texi
+++ b/texinfo/mgl_ru.texi
@@ -1,11 +1,12 @@
 \input texinfo
- at setfilename mgl_ru.info
+ at documentencoding UTF-8
 @c @documentlanguage ru
+
+ at setfilename mgl_ru.info
 @documentencoding UTF-8
- at set VERSION 2.1.3
+ at include version.texi
 @settitle Язык MGL для версии @value{VERSION}
 @syncodeindex pg cp
- at comment %**end of header
 
 @copying
 Это документация для MathGL (версии @value{VERSION}) -- библиотеки классов и функций для построения научной графики. Пожалуйста сообщайте о любых ошибках в этом руководстве на @email{mathgl.abalakin@@gmail.org}.
@@ -53,33 +54,15 @@
 
 @macro external {}
 @end macro
-
- at ifhtml
- at macro fig {fname,text}
- at center @image{\fname\, 11cm, , \text\, .png}
- at end macro
- at macro pfig {fname,text}
- at center @image{png/\fname\, 11cm, , \text\, .png}
+ at macro nav {}
 @end macro
- at end ifhtml
 
- at ifnothtml
- at iftex
 @macro fig {fname,text}
- at center @image{\fname\, 11cm, , \text\, .png}
+ at center @image{\fname\, 11cm, , \text\, png}
 @end macro
 @macro pfig {fname,text}
- at center @image{png/\fname\, 11cm, , \text\, .png}
+ at center @image{png/\fname\, 11cm, , \text\, png}
 @end macro
- at end iftex
-
- at ifnottex
- at macro fig {fname,text}
- at end macro
- at macro pfig {fname,text}
- at end macro
- at end ifnottex
- at end ifnothtml
 
 @macro sref {arg}
 См. @ref{\arg\}, для примеров кода и графика.
diff --git a/texinfo/other_en.texi b/texinfo/other_en.texi
index c6233aa..87d8df7 100644
--- a/texinfo/other_en.texi
+++ b/texinfo/other_en.texi
@@ -1,6 +1,6 @@
-
 @c ------------------------------------------------------------------
 @chapter Other classes
+ at nav{}
 
 There are few end-user classes: @code{mglGraph} (see @ref{MathGL core}), @code{mglWindow} and @code{mglGLUT} (see @ref{Widget classes}), @code{mglData} (see @ref{Data processing}), @code{mglParse} (see @ref{MGL scripts}). Exactly these classes I recommend to use in most of user programs. All methods in all of these classes are inline and have exact C/Fortran analogue functions. This give compiler independent binary libraries for MathGL.
 
@@ -24,6 +24,7 @@ Below I show how this internal classes can be used.
 @external{}
 @node mglBase class, mglDataA class, , Other classes
 @section Define new kind of plot (mglBase class)
+ at nav{}
 
 Basically most of new kinds of plot can be created using just MathGL primitives (see @ref{Primitives}). However the usage of @code{mglBase} methods can give you higher speed of drawing and better control of plot settings. 
 
@@ -328,6 +329,7 @@ int main()
 @external{}
 @node mglDataA class, mglColor class, mglBase class, Other classes
 @section User defined types (mglDataA class)
+ at nav{}
 
 @code{mglData} class have abstract predecessor class @code{mglDataA}. Exactly the pointers to @code{mglDataA} instances are used in all plotting functions and some of data processing functions. This was done for taking possibility to define yours own class, which will handle yours own data (for example, complex numbers, or differently organized data). And this new class will be almost the same as @code{mglData} for plotting purposes.
 
@@ -416,6 +418,7 @@ int main()
 @external{}
 @node mglColor class, mglPoint class, mglDataA class, Other classes
 @section mglColor class
+ at nav{}
 @cindex mglColor
 
 Structure for working with colors. This structure is defined in @code{#include <mgl2/type.h>}.
@@ -486,6 +489,7 @@ Return inverted color.
 @external{}
 @node mglPoint class, , mglColor class, Other classes
 @section mglPoint class
+ at nav{}
 @cindex mglPoint
 
 Structure describes point in space. This structure is defined in @code{#include <mgl2/type.h>}
diff --git a/texinfo/other_ru.texi b/texinfo/other_ru.texi
index fd8b5fe..038903f 100644
--- a/texinfo/other_ru.texi
+++ b/texinfo/other_ru.texi
@@ -1,6 +1,6 @@
-
 @c ------------------------------------------------------------------
 @chapter Other classes
+ at nav{}
 
 There are few end-user classes: @code{mglGraph} (see @ref{MathGL core}), @code{mglWindow} and @code{mglGLUT} (see @ref{Widget classes}), @code{mglData} (see @ref{Data processing}), @code{mglParse} (see @ref{MGL scripts}). Exactly these classes I recommend to use in most of user programs. All methods in all of these classes are inline and have exact C/Fortran analogue functions. This give compiler independent binary libraries for MathGL.
 
@@ -24,6 +24,7 @@ Below I show how this internal classes can be used.
 @external{}
 @node mglBase class, mglDataA class, , Other classes
 @section Define new kind of plot (mglBase class)
+ at nav{}
 
 Basically most of new kinds of plot can be created using just MathGL primitives (see @ref{Primitives}). However the usage of @code{mglBase} methods can give you higher speed of drawing and better control of plot settings. 
 
@@ -328,6 +329,7 @@ int main()
 @external{}
 @node mglDataA class, mglColor class, mglBase class, Other classes
 @section User defined types (mglDataA class)
+ at nav{}
 
 @code{mglData} class have abstract predecessor class @code{mglDataA}. Exactly the pointers to @code{mglDataA} instances are used in all plotting functions and some of data processing functions. This was done for taking possibility to define yours own class, which will handle yours own data (for example, complex numbers, or differently organized data). And this new class will be almost the same as @code{mglData} for plotting purposes.
 
@@ -416,6 +418,7 @@ int main()
 @external{}
 @node mglColor class, mglPoint class, mglDataA class, Other classes
 @section mglColor class
+ at nav{}
 @cindex mglColor
 
 Structure for working with colors. This structure is defined in @code{#include <mgl2/type.h>}.
@@ -486,6 +489,7 @@ Return inverted color.
 @external{}
 @node mglPoint class, , mglColor class, Other classes
 @section mglPoint class
+ at nav{}
 @cindex mglPoint
 
 Structure describes point in space. This structure is defined in @code{#include <mgl2/type.h>}
diff --git a/texinfo/overview_en.texi b/texinfo/overview_en.texi
index 58b67c3..ac5d43b 100644
--- a/texinfo/overview_en.texi
+++ b/texinfo/overview_en.texi
@@ -1,4 +1,5 @@
 @chapter Overview
+ at nav{}
 
 @cindex MathGL overview
 
@@ -27,6 +28,7 @@ a library with large and growing set of graphics.
 @external{}
 @node What is MathGL?, MathGL features, , Overview
 @section What is MathGL?
+ at nav{}
 
 A code for making high-quality scientific graphics under Linux and Windows. A  code for the fast handling and plotting of large data arrays. A code for working in window and console regimes and for easy including into another program. A code with large and renewal set of graphics. Exactly such a code I tried to put in MathGL library.
 
@@ -35,6 +37,7 @@ At this version (@value{VERSION}) MathGL has more than 50 general types of graph
 @external{}
 @node MathGL features, Installation, What is MathGL?, Overview
 @section MathGL features
+ at nav{}
 
 MathGL can plot a wide range of graphics. It includes:
 @itemize @bullet
@@ -67,6 +70,7 @@ There is fast evaluation of a textual mathematical expression (@pxref{Textual fo
 @external{}
 @node Installation, Quick guide, MathGL features, Overview
 @section Installation
+ at nav{}
 
 MathGL can be installed in 4 different ways.
 @enumerate
@@ -75,6 +79,8 @@ Compile from sources. The cmake build system is useded in the library. To run it
 
 There are several additional options which are switched off by default. They are: @code{enable-fltk, enable-glut, enable-qt} for ebabling FLTK, GLUT and/or Qt windows; @code{enable-jpeg, enable-gif, enable-hdf5} and so on for enabling corresponding file formats; @code{enable-all} for enabling all additional features. For using @code{double} as base internal data type use option @code{enable-double}. For enabling language interfaces use @code{enable-python, enable-octave} or @code{enable- [...]
 
+There is known bug for building in MinGW -- you need to manually add linker option @code{-fopenmp} (i.e. @code{CMAKE_EXE_LINKER_FLAGS:STRING='-fopenmp'} and @code{CMAKE_SHARED_LINKER_FLAGS:STRING='-fopenmp'}) if you enable OpenMP support (i.e. if @code{enable-openmp=ON}).
+
 @item
 Use a precompiled binary. There are binaries for MinGW (platform Win32). For a precompiled variant one needs only to unpack the archive to the location of the compiler (i.e. mathgl/lib in mingw/lib, mathgl/include in mingw/include and so on) or in arbitrary other folder and setup paths in compiler. By default, precompiled versions include the support of GSL (www.gsl.org) and PNG. So, one needs to have these libraries installed on system (it can be found, for example, at @uref{http://gnuw [...]
 
@@ -91,6 +97,7 @@ svn checkout http://svn.code.sf.net/p/mathgl/code/mathgl-2x mathgl-code
 @external{}
 @node  Quick guide, Changes from v.1, Installation, Overview
 @section Quick guide
+ at nav{}
 
 There are 3 steps to prepare the plot in MathGL: (1) prepare data to be plotted, (2) setup plot, (3) plot data. Let me show this on the example of surface plotting.
 
@@ -140,6 +147,7 @@ Fortran users also should add C++ library by the option @code{-lstdc++}. If libr
 @external{}
 @node  Changes from v.1, Utilities, Quick guide, Overview
 @section Changes from v.1.*
+ at nav{}
 
 There are a lot of changes for v.2. Here I denote only main of them.
 @itemize @bullet
@@ -171,6 +179,7 @@ Add pipes support in utilities (@code{mglconv, mglview}).
 @external{}
 @node  Utilities, Thanks, Changes from v.1, Overview
 @section Utilities for parsing MGL
+ at nav{}
 
 MathGL library provides several tools for parsing MGL scripts. There is tools saving it to bitmap or vectorial images (@code{mglconv}). Tool @code{mglview} show MGL script and allow to rotate and setup the image. Another feature of @code{mglview} is loading *.mgld files (see @code{ExportMGLD()}) for quick viewing 3d pictures.
 
@@ -203,6 +212,7 @@ MathGL also provide another simple tool @code{mgl.cgi} which parse MGL script fr
 @external{}
 @node Thanks, , Utilities, Overview
 @section Thanks
+ at nav{}
 
 @itemize @bullet
 @item
diff --git a/texinfo/overview_ru.texi b/texinfo/overview_ru.texi
index 143e561..795aa9a 100644
--- a/texinfo/overview_ru.texi
+++ b/texinfo/overview_ru.texi
@@ -1,4 +1,5 @@
 @chapter Обзор MathGL
+ at nav{}
 
 @cindex Обзор MathGL
 
@@ -27,6 +28,7 @@ MathGL это ...
 @external{}
 @node What is MathGL?, MathGL features, , Overview
 @section Что такое MathGL?
+ at nav{}
 
 Код для создания качественной научной графики на различных платформах. Код для быстрой обработки и отображения больших массивов данных. Код для работы в графическом и консольном режимах и легкого интегрирования в другие программы. Код с большим обновляемым набором графиков и инструментами обработки данных. Именно такого кода мне не хватало в последние годы при работе на персональных компьютерах и на кластерах. И именно такой код я постарался создать в библиотеке MathGL.
 
@@ -35,6 +37,7 @@ MathGL это ...
 @external{}
 @node MathGL features, Installation, What is MathGL?, Overview
 @section Возможности MathGL
+ at nav{}
 
 Библиотека MathGL позволяет строить широкий класс графиков, включая:
 @itemize @bullet
@@ -67,6 +70,7 @@ MathGL это ...
 @external{}
 @node Installation, Quick guide, MathGL features, Overview
 @section Установка MathGL
+ at nav{}
 
 Установка библиотеки возможна 4-мя способами.
 @enumerate
@@ -75,6 +79,9 @@ MathGL это ...
 
 Есть несколько дополнительных опций, которые по умолчанию отключены. К их числу относятся: @code{enable-fltk, enable-glut, enable-qt} для поддержки FLTK, GLUT и/или Qt окон; @code{enable-jpeg, enable-gif, enable-hdf5} для поддержки соответствующих форматов; @code{enable-all} для включения всех возможностей. Для использования типа @code{double} для внутреннего хранения данных используйте опцию @code{enable-double}. Для создания интерфейсов к другим языкам (кроме С/Фортран/MGL) используйте [...]
 
+При сборке с помощью MinGW необходимо дополнительно установить опцию сборки @code{-fopenmp} (т.е. @code{CMAKE_EXE_LINKER_FLAGS:STRING='-fopenmp'} и @code{CMAKE_SHARED_LINKER_FLAGS:STRING='-fopenmp'}) если включена поддержка OpenMP (@code{enable-openmp=ON}).
+
+
 @item
 Использовать предварительно скомпилированные файлы -- с библиотекой поставляются файлы для MinGW (платформа Win32). В скомпилированной версии достаточно распаковать заголовочные файлы в папку с заголовочными файлами и библиотеку libmgl.a в папку с библиотеками. По умолчанию, скомпилированная версия включают поддержку GSL (www.gsl.org), PNG, GIF и JPEG. Соответственно, при сборке программы эти библиотеки должны быть установлены (их можно найти на @uref{http://gnuwin32.sourceforge.net/pack [...]
 @item
@@ -92,6 +99,7 @@ svn checkout http://svn.code.sf.net/p/mathgl/code/mathgl-2x mathgl-code
 @external{}
 @node  Quick guide, Changes from v.1, Installation, Overview
 @section Quick guide
+ at nav{}
 
 There are 3 steps to prepare the plot in MathGL: (1) prepare data to be plotted, (2) setup plot, (3) plot data. Let me show this on the example of surface plotting.
 
@@ -141,6 +149,7 @@ This is enough for a compilation of console program or with external (non-MathGL
 @external{}
 @node  Changes from v.1, Utilities, Quick guide, Overview
 @section Changes from v.1.*
+ at nav{}
 
 There are a lot of changes for v.2. Here I denote only main of them.
 @itemize @bullet
@@ -172,6 +181,7 @@ Add pipes support in utilities (@code{mglconv, mglview}).
 @external{}
 @node  Utilities, Thanks, Changes from v.1, Overview
 @section Utilities for parsing MGL
+ at nav{}
 
 MathGL library provides several tools for parsing MGL scripts. There is tools saving it to bitmap or vectorial images (@code{mglconv}). Tool @code{mglview} show MGL script and allow to rotate and setup the image. Another feature of @code{mglview} is loading *.mgld files (see @code{ExportMGLD()}) for quick viewing 3d pictures.
 
@@ -204,6 +214,7 @@ MathGL also provide another simple tool @code{mgl.cgi} which parse MGL script fr
 @external{}
 @node Thanks, , Utilities, Overview
 @section Благодарности
+ at nav{}
 
 
 @itemize @bullet
diff --git a/texinfo/parse_en.texi b/texinfo/parse_en.texi
index 4e353f2..21b0e7b 100644
--- a/texinfo/parse_en.texi
+++ b/texinfo/parse_en.texi
@@ -1,32 +1,27 @@
 
 @c ------------------------------------------------------------------
 @chapter MGL scripts
+ at nav{}
 
 MathGL library supports the simplest scripts for data handling and plotting. These scripts can be used independently (with the help of UDAV, mglconv, mglview programs and others
 @ifclear UDAV
 , @pxref{Utilities}) or in the frame of the library using.
 @end ifclear
 
- at ifclear UDAV
 @menu
 * MGL definition::
 * Program flow commands::
+ at ifclear UDAV
 * mglParse class::
- at end menu
 @end ifclear
-
- at ifset UDAV
- at menu
-* MGL definition::
-* Program flow commands::
 @end menu
- at end ifset
 
 
 @c ------------------------------------------------------------------
 @external{}
 @node MGL definition, Program flow commands, , MGL scripts
 @section MGL definition
+ at nav{}
 
 MGL script language is rather simple. Each string is a command. First word of string is the name of command. Other words are command arguments. Command may have up to 1000 arguments (at least for now). Words are separated from each other by space or tabulation symbol. The upper or lower case of words is important, i.e. variables @var{a} and @var{A} are different variables. Symbol @samp{#} starts the comment (all characters after # will be ignored). The exception is situation when @samp{# [...]
 
@@ -67,8 +62,14 @@ Command may have several set of possible arguments (for example, @code{plot ydat
 
 @c ------------------------------------------------------------------
 @external{}
- at node Program flow commands, MGL definition, MGL scripts
+ at ifclear UDAV
+ at node Program flow commands, mglParse class, MGL definition, MGL scripts
+ at end ifclear
+ at ifset UDAV
+ at node Program flow commands, , MGL definition, MGL scripts
+ at end ifset
 @section Program flow commands
+ at nav{}
 
 Below I show commands to control program flow, like, conditions, loops, define script arguments and so on. Other commands can be found in chapters @ref{MathGL core} and @ref{Data processing}. Note, that some of program flow commands (like @ref{define}, @ref{ask}, @ref{call}, @ref{for}, @ref{func}) should be placed alone in the string.
 
@@ -90,7 +91,7 @@ Sets @var{N}-th script argument to answer which give the user on the @var{questi
 Sets @var{N}-th script argument to @var{smth}. Note, that @var{smth} is used as is (with @samp{'} symbols if present). Here @var{N} is digit (0...9) or alpha (a...z).
 @end deftypefn
 @deftypefn {MGL command} {} define name smth
-Create scalar variable @code{name} which have the numeric value of @code{smth}. Later you can use this variable as usual number. Here @var{N} is digit (0...9) or alpha (a...z).
+Create scalar variable @code{name} which have the numeric value of @code{smth}. Later you can use this variable as usual number.
 @end deftypefn
 @cindex defchr
 @anchor{defchr}
@@ -182,11 +183,12 @@ Terminate execution.
 @external{}
 @node mglParse class, , Program flow commands, MGL scripts
 @section mglParse class
+ at nav{}
 @cindex mglParse
 
 Class for parsing and executing MGL script. This class is defined in @code{#include <mgl2/mgl.h>}.
 
-Class mglParse is the interpreter for MGL scripts. The main function of mglParse class is @code{Execute()}. Exactly this function parses and executes the script string-by-string. Also there are subservient functions for the finding and creation of a variable. These functions can be useful for displaying values of variables (arrays) in some external program (in window, for example). Function @code{AllowSetSize()} allows one to prevent changing the size of the  picture inside the script (f [...]
+The main function of mglParse class is @code{Execute()}. Exactly this function parses and executes the script string-by-string. Also there are subservient functions for the finding and creation of a variable (object derived from @code{mglData} class, see @ref{MGL variables}). These functions can be useful for displaying values of variables (arrays) in some external object (like, window) or for providing access to internal data. Function @code{AllowSetSize()} allows one to prevent changin [...]
 
 @c Note an important feature -- if user defines function @var{func} in variable then it will be called before the destroying of this variable (@pxref{mglVar class}).
 
@@ -257,7 +259,7 @@ Function returns the pointer to variable with name @var{name}. If variable is ab
 @deftypefnx{Method on @code{mglParse} (C++)} @code{void} DeleteVar (@code{const wchar_t *}name)
 @deftypefnx {C function} @code{void} mgl_parser_del_var (@code{HMPR} p, @code{const char *}name)
 @deftypefnx {C function} @code{void} mgl_parser_del_varw (@code{HMPR} p, @code{const wchar_t *}name)
-Function delete the variable specified by its name or by its pointer.
+Function delete the variable with given @var{name}.
 @end deftypefn
 
 @deftypefn{Method on @code{mglParse} (C++)} @code{void} DeleteAll ()
diff --git a/texinfo/parse_ru.texi b/texinfo/parse_ru.texi
index b7d0817..52769c9 100644
--- a/texinfo/parse_ru.texi
+++ b/texinfo/parse_ru.texi
@@ -1,34 +1,27 @@
 
 @c ------------------------------------------------------------------
 @chapter Скрипты MGL
+ at nav{}
 
- at c TODO Translate it!
-
-MathGL library supports the simplest scripts for data handling and plotting. These scripts can be used independently (with the help of UDAV, mglconv, mglview programs and others
+MathGL имеет встроенный скриптовый язык MGL для обработки и отображения данных. Скрипты MGL могут быть выполнены независимо (с помощью программ UDAV, mglconv, mglview и др.
 @ifclear UDAV
-, @pxref{Utilities}) or in the frame of the library using.
+, см. @ref{Utilities}) или с использованием вызовов библиотеки.
 @end ifclear
 
- at ifclear UDAV
 @menu
 * MGL definition::
 * Program flow commands::
+ at ifclear UDAV
 * mglParse class::
- at end menu
 @end ifclear
-
- at ifset UDAV
- at menu
-* MGL definition::
-* Program flow commands::
 @end menu
- at end ifset
 
 
 @c ------------------------------------------------------------------
 @external{}
 @node MGL definition, Program flow commands, , MGL scripts
 @section Основы MGL
+ at nav{}
 
 Язык MGL достаточно простой. Каждая строка -- отдельная команда. Первое слово -- имя команды, а все остальные ее аргументы. Команда может иметь до 1000 аргументов (по крайней мере сейчас). Слова разделяются одно от другого пробелом или символом табуляции. Различий между верхним и нижним индексом нет, т.е. переменные @var{a} и @var{A} идентичны. Символ @samp{#} начинает комментарий -- все символы после него игнорируются до конца строки. Исключением является случай, когда @samp{#} входит в [...]
 
@@ -72,114 +65,121 @@ MathGL library supports the simplest scripts for data handling and plotting. The
 
 @c ------------------------------------------------------------------
 @external{}
- at node Program flow commands, MGL definition, MGL scripts
- at section Program flow commands
+ at ifclear UDAV
+ at node Program flow commands, mglParse class, MGL definition, MGL scripts
+ at end ifclear
+ at ifset UDAV
+ at node Program flow commands, , MGL definition, MGL scripts
+ at end ifset
+ at section Управление ходом выполнения
+ at nav{}
 
-Below I show commands to control program flow, like, conditions, loops, define script arguments and so on. Other commands can be found in chapters @ref{MathGL core} and @ref{Data processing}. Note, that some of program flow commands (like @ref{define}, @ref{ask}, @ref{call}, @ref{for}, @ref{func}) should be placed alone in the string.
+Ниже собраны команды, управляющие порядком выполнения других команд (условия, циклы, подпрограммы), (пере-)определяют аргументы скрипта и пр. Прочие команды могут быть найдены в главах @ref{MathGL core} и @ref{Data processing}. Отмечу, что некоторые из команд (например, @ref{define}, @ref{ask}, @ref{call}, @ref{for}, @ref{func}) должны быть расположены на отдельной строке.
 
 @cindex chdir
 @anchor{chdir}
 @deftypefn {MGL command} {} chdir 'path'
-Changes the current directory to @var{path}.
+Переходит в папку @var{path}.
 @end deftypefn
 
 @cindex ask
 @anchor{ask}
 @deftypefn {MGL command} {} ask $N 'question'
-Sets @var{N}-th script argument to answer which give the user on the @var{question}. Usually this show dialog with question where user can enter some text as answer. Here @var{N} is digit (0...9) or alpha (a...z).
+Задает @var{N}-ый аргумент скрипта равным ответу пользователя на вопрос @var{question}. Обычно команда показывает диалог с вопросом и полем ввода текста ответа. Здесь @var{N} это цифра (0...9) или буква (a...z).
 @end deftypefn
 
 @cindex define
 @anchor{define}
 @deftypefn {MGL command} {} define $N smth
-Sets @var{N}-th script argument to @var{smth}. Note, that @var{smth} is used as is (with @samp{'} symbols if present). Here @var{N} is digit (0...9) or alpha (a...z).
+Задает @var{N}-ый аргумент скрипта равным @var{smth}. Отмечу, что @var{smth} используется как есть (с символами @samp{'} если присутствуют). Выполняется только подстановка других макроопределений $0...$9, $a...$z. Здесь @var{N} это цифра (0...9) или буква (a...z).
 @end deftypefn
 @deftypefn {MGL command} {} define name smth
-Create scalar variable @code{name} which have the numeric value of @code{smth}. Later you can use this variable as usual number. Here @var{N} is digit (0...9) or alpha (a...z).
+Определяет константу (скаляр) с именем @code{name} и числовым значением @code{smth}. Позднее она может быть использована как обычное число.
 @end deftypefn
 @cindex defchr
 @anchor{defchr}
 @deftypefn {MGL command} {} defchr $N smth
-Sets @var{N}-th script argument to character with value evaluated from @var{smth}. Here @var{N} is digit (0...9) or alpha (a...z).
+Задает @var{N}-ый аргумент скрипта равным символу с UTF кодом @var{smth}. Здесь @var{N} это цифра (0...9) или буква (a...z).
 @end deftypefn
 @cindex defnum
 @anchor{defnum}
 @deftypefn {MGL command} {} defnum $N smth
-Sets @var{N}-th script argument to number with value evaluated from @var{smth}. Here @var{N} is digit (0...9) or alpha (a...z).
+Задает @var{N}-ый аргумент скрипта равным числовому значению @var{smth}. Здесь @var{N} это цифра (0...9) или буква (a...z).
 @end deftypefn
 @cindex defpal
 @anchor{defpal}
 @deftypefn {MGL command} {} defpal $N smth
-Sets @var{N}-th script argument to palette character at position evaluated from @var{smth}. Here @var{N} is digit (0...9) or alpha (a...z).
+Задает @var{N}-ый аргумент скрипта равным символу палитры с индексом, найденным из @var{smth}. Здесь @var{N} это цифра (0...9) или буква (a...z).
 @end deftypefn
 
 @cindex call
 @anchor{call}
 @deftypefn {MGL command} {} call 'fname' [ARG1 ARG2 ... ARG9]
-Executes function @var{fname} (or script if function is not found). Optional arguments will be passed to functions. See also @ref{func}.
+Переходит к выполнению (вызывает) подпрограммы @var{fname} (или внешнего скрипта, если функция не была найдена). Опциональные аргументы передаются в подпрограмму. См. также @ref{func}.
 @end deftypefn
 @cindex func
 @anchor{func}
 @deftypefn {MGL command} {} func 'fname' [narg=0]
-Define the function @var{fname} and number of required arguments. The arguments will be placed in script parameters $1, $2, ... $9. Note, you should stop script execution before function definition(s) by command @ref{stop}. See also @ref{return}.
+Определяет подпрограмму с именем @var{fname} и задает число требуемых аргументов. Аргументы будут помещены в параметры скрипта $1, $2, ... $9. Отмечу, что выполнение основной программы должно быть остановлено до начала определений подпрограмм. См. также @ref{stop},  @ref{return}.
+
 @end deftypefn
 @cindex return
 @anchor{return}
 @deftypefn {MGL command} {} return
-Return from the function. See also @ref{func}.
+Возвращается из подпрограммы. См. также @ref{func}.
 @end deftypefn
 
 
 @cindex if
 @anchor{if}
 @deftypefn {MGL command} {} if dat 'cond'
-Starts block which will be executed if @var{dat} satisfy to @var{cond}.
+Начинает блок команд, выполняемый если каждый элемент @var{dat} удовлетворяет условию @var{cond}.
 @end deftypefn
 @deftypefn {MGL command} {} if @code{val}
-Starts block which will be executed if @code{val} is nonzero.
+Начинает блок команд, выполняемый если @code{val} не ноль.
 @end deftypefn
 @cindex elseif
 @anchor{elseif}
 @deftypefn {MGL command} {} elseif dat 'cond'
-Starts block which will be executed if previous @code{if} or @code{elseif} is false and @var{dat} satisfy to @var{cond}.
+Начинает блок команд, выполняемый если предыдущий @code{if} или @code{elseif} не был выполнен и каждый элемент @var{dat} удовлетворяет условию @var{cond}.
 @end deftypefn
 @deftypefn {MGL command} {} elseif @code{val}
-Starts block which will be executed if previous @code{if} or @code{elseif} is false and @code{val} is nonzero.
+Начинает блок команд, выполняемый если предыдущий @code{if} или @code{elseif} не был выполнен и @code{val} не ноль.
 @end deftypefn
 @cindex else
 @anchor{else}
- at deftypefn {MGL command} {} else
-Starts block which will be executed if previous @code{if} or @code{elseif} is false.
+ at deftypefn {Команда MGL} {} else
+Начинает блок команд, выполняемый если предыдущий @code{if} или @code{elseif} не был выполнен.
 @end deftypefn
 @cindex endif
 @anchor{endif}
- at deftypefn {MGL command} {} endif
-Finishes @code{if/elseif/else} block.
+ at deftypefn {Команда MGL} {} endif
+Заканчивает определение блока @code{if/elseif/else}.
 @end deftypefn
 
 @cindex for
 @anchor{for}
 @deftypefn {MGL command} {} for $N @code{v1 v2 [dv=1]}
-Starts cycle with $@var{N}-th argument changing from @var{v1} to @var{v2} with the step @var{dv}. Here @var{N} is digit (0...9) or alpha (a...z).
+Начинает блок команд, выполняемый в цикле с $@var{N}-ым аргументом изменяющимся от @var{v1} до @var{v2} с шагом @var{dv}. Здесь @var{N} это цифра (0...9) или буква (a...z).
 @end deftypefn
- at deftypefn {MGL command} {} for $N dat
-Starts cycle with $@var{N}-th argument changing for @var{dat} values. Here @var{N} is digit (0...9) or alpha (a...z).
+ at deftypefn {Команда MGL} {} for $N dat
+Начинает блок команд, выполняемый в цикле с $@var{N}-ым аргументом пробегающим значения массива @var{dat}. Здесь @var{N} это цифра (0...9) или буква (a...z).
 @end deftypefn
 @cindex next
 @anchor{next}
- at deftypefn {MGL command} {} next
-Finishes @code{for} cycle.
+ at deftypefn {Команда MGL} {} next
+Заканчивает блок цикла @code{for}.
 @end deftypefn
 
 @cindex once
 @anchor{once}
 @deftypefn {MGL command} {} once @code{val}
-The code between @code{once on} and @code{once off} will be executed only once. Useful for large data manipulation in programs like UDAV.
+Определяет код (между @code{once on} и @code{once off}) который будет выполнен только один раз. Полезно для работы с большими данными в программах типа UDAV.
 @end deftypefn
 @cindex stop
 @anchor{stop}
 @deftypefn {MGL command} {} stop
-Terminate execution.
+Останавливает выполнение скрипта.
 @end deftypefn
 
 @ifclear UDAV
@@ -187,136 +187,136 @@ Terminate execution.
 @external{}
 @node mglParse class, , Program flow commands, MGL scripts
 @section mglParse class
+ at nav{}
 @cindex mglParse
 
-Class for parsing and executing MGL script. This class is defined in @code{#include <mgl2/mgl.h>}.
+Класс разбирает и выполняет скрипты MGL. Он определен в @code{#include <mgl2/mgl.h>}.
 
-Class mglParse is the interpreter for MGL scripts. The main function of mglParse class is @code{Execute()}. Exactly this function parses and executes the script string-by-string. Also there are subservient functions for the finding and creation of a variable. These functions can be useful for displaying values of variables (arrays) in some external program (in window, for example). Function @code{AllowSetSize()} allows one to prevent changing the size of the  picture inside the script (f [...]
+Основная функция класса mglParse -- @code{Execute()}, выполняющая построчный разбор скрипта. Также есть вспомогательные функции для поиска и создания переменных MGL (объектов, производных от @code{mglData}, см. @ref{MGL variables}). Эти функции полезны для отображения значений массивов во внешних объектах (например, в отдельном окне) или для предоставления доступа к внутренним массивам. Функция @code{AllowSetSize()} позволяет запретить изменение размера картинки (запрещает команду @code{ [...]
 
 @c Note an important feature -- if user defines function @var{func} in variable then it will be called before the destroying of this variable (@pxref{mglVar class}).
 
- at deftypefn {Constructor on @code{mglParse}} @code{} mglParse (@code{bool} setsize=@code{false})
- at deftypefnx {Constructor on @code{mglParse}} @code{} mglParse (@code{HMPR} pr)
- at deftypefnx {Constructor on @code{mglParse}} @code{} mglParse (@code{mglParse &}pr)
- at deftypefnx {C function} @code{HMPR} mgl_create_parser ()
-Constructor initializes all values with zero and set @var{AllowSetSize} value.
+ at deftypefn {Конструктор класса @code{mglParse}} @code{} mglParse (@code{bool} setsize=@code{false})
+ at deftypefnx {Конструктор класса @code{mglParse}} @code{} mglParse (@code{HMPR} pr)
+ at deftypefnx {Конструктор класса @code{mglParse}} @code{} mglParse (@code{mglParse &}pr)
+ at deftypefnx {Функция С} @code{HMPR} mgl_create_parser ()
+Создает экземпляр класса @code{mglParse} и устанавливает значение @var{AllowSetSize}.
 @end deftypefn
 
- at deftypefn {Destructor on @code{mglParse}} @code{} ~mglParse ()
- at deftypefnx {C function} @code{void} mgl_delete_parser (@code{HMPR} p)
-Destructor delete parser
+ at deftypefn {Деструктор класса @code{mglParse}} @code{} ~mglParse ()
+ at deftypefnx {Функция С} @code{void} mgl_delete_parser (@code{HMPR} p)
+Удаляет экземпляр класса.
 @end deftypefn
 
- at deftypefn {Method on @code{mglParse}} @code{HMPR} Self ()
-Returns the pointer to internal object of type @code{HMPR}.
+ at deftypefn {Метод класса @code{mglParse}} @code{HMPR} Self ()
+Возвращает указатель на используемый объект типа @code{HMPR}.
 @end deftypefn
 
- at deftypefn {Method on @code{mglParse}} @code{void} Execute (@code{mglGraph *}gr, @code{const char *}text)
- at deftypefnx{Method on @code{mglParse}} @code{void} Execute (@code{mglGraph *}gr, @code{const wchar_t *}text)
- at deftypefnx {C function} @code{void} mgl_parse_text (@code{HMGL} gr, @code{HMPR} p, @code{const char *}text)
- at deftypefnx {C function} @code{void} mgl_parse_textw (@code{HMGL} gr, @code{HMPR} p, @code{const wchar_t *}text)
-Main function in the class. Function parse and execute line-by-line MGL script in array @var{text}. Lines are separated by newline symbol @samp{\n} as usual.
+ at deftypefn {Метод класса @code{mglParse}} @code{void} Execute (@code{mglGraph *}gr, @code{const char *}text)
+ at deftypefnx{Метод класса @code{mglParse}} @code{void} Execute (@code{mglGraph *}gr, @code{const wchar_t *}text)
+ at deftypefnx {Функция С} @code{void} mgl_parse_text (@code{HMGL} gr, @code{HMPR} p, @code{const char *}text)
+ at deftypefnx {Функция С} @code{void} mgl_parse_textw (@code{HMGL} gr, @code{HMPR} p, @code{const wchar_t *}text)
+Выполняет построчно скрипт MGL, содержащийся в @var{text}. Строки считаются разделенными символом @samp{\n}. Это основная функция класса.
 @end deftypefn
 
- at deftypefn {Method on @code{mglParse}} @code{void} Execute (@code{mglGraph *}gr, @code{FILE *}fp, @code{bool} print=@code{false})
- at deftypefnx {C function} @code{void} mgl_parse_file (@code{HMGL} gr, @code{HMPR} p, @code{FILE *}fp, @code{int} print)
-The same as previous but read script from the file @var{fp}. If @var{print}=@code{true} then all warnings and information will be printed in stdout.
+ at deftypefn {Метод класса @code{mglParse}} @code{void} Execute (@code{mglGraph *}gr, @code{FILE *}fp, @code{bool} print=@code{false})
+ at deftypefnx {Функция С} @code{void} mgl_parse_file (@code{HMGL} gr, @code{HMPR} p, @code{FILE *}fp, @code{int} print)
+Аналогично предыдущему, но скрипт читается из файла @var{fp}. Если @var{print}=@code{true}, то предупреждения и информационные сообщения печатаются в stdout.
 @end deftypefn
 
- at deftypefn {Method on @code{mglParse}} @code{int} Parse (@code{mglGraph *}gr, @code{const char *}str, @code{long} pos=@code{0})
- at deftypefnx {Method on @code{mglParse}} @code{int} Parse (@code{mglGraph *}gr, @code{const wchar_t *}str, @code{long} pos=@code{0})
- at deftypefnx {C function} @code{int} mgl_parse_line (@code{HMGL} gr, @code{HMPR} p, @code{const char *}str, @code{int} pos)
- at deftypefnx {C function} @code{int} mgl_parse_linew (@code{HMGL} gr, @code{HMPR} p, @code{const wchar_t *}str, @code{int} pos)
-Function parses the string @var{str} and executes it by  using @var{gr} as a graphics plotter. Returns the value depending on an error presence in the string @var{str}: 0 -- no error, 1 -- wrong command argument(s), 2 -- unknown command, 3 -- string is too long. Optional argument @var{pos} allows to save the string position in the document (or file) for using @code{for|next} command.
+ at deftypefn {Метод класса @code{mglParse}} @code{int} Parse (@code{mglGraph *}gr, @code{const char *}str, @code{long} pos=@code{0})
+ at deftypefnx {Метод класса @code{mglParse}} @code{int} Parse (@code{mglGraph *}gr, @code{const wchar_t *}str, @code{long} pos=@code{0})
+ at deftypefnx {Функция С} @code{int} mgl_parse_line (@code{HMGL} gr, @code{HMPR} p, @code{const char *}str, @code{int} pos)
+ at deftypefnx {Функция С} @code{int} mgl_parse_linew (@code{HMGL} gr, @code{HMPR} p, @code{const wchar_t *}str, @code{int} pos)
+Выполняет строку @var{str} с выводом графики на @var{gr}. Возвращает код ошибки: 0 -- нет ошибок, 1 -- неправильные аргументы, 2 -- неизвестная команда, 3 -- строка слишком длинная. Аргумент @var{pos} задает позицию строки в документе/файле для использования в команде @ref{for}.
 @end deftypefn
 
- at deftypefn {Method on @code{mglParse}} @code{mglData} Calc (@code{const char *}formula)
- at deftypefnx {Method on @code{mglParse}} @code{mglData} Calc (@code{const wchar_t *}formula)
- at deftypefnx {C function} @code{HMDT} mgl_parser_calc (@code{HMPR} p, @code{const char *}formula)
- at deftypefnx {C function} @code{HMDT} mgl_parser_calcw (@code{HMPR} p, @code{const wchar_t *}formula)
-Function parses the string @var{formula} and return resulting data array. In difference to @code{AddVar()} or @code{FindVar()}, it is usual data array which should be deleted after usage.
+ at deftypefn {Метод класса @code{mglParse}} @code{mglData} Calc (@code{const char *}formula)
+ at deftypefnx {Метод класса @code{mglParse}} @code{mglData} Calc (@code{const wchar_t *}formula)
+ at deftypefnx {Функция С} @code{HMDT} mgl_parser_calc (@code{HMPR} p, @code{const char *}formula)
+ at deftypefnx {Функция С} @code{HMDT} mgl_parser_calcw (@code{HMPR} p, @code{const wchar_t *}formula)
+Разбирает строку @var{formula} и возвращает полученный массив. В отличие от @code{AddVar()} или @code{FindVar()}, это обычный массив данных, который следует удалить после использования.
 @end deftypefn
 
 
- at deftypefn {Method on @code{mglParse}} @code{void} AddParam (@code{int} n, @code{const char *}str)
- at deftypefnx {Method on @code{mglParse}} @code{void} AddParam (@code{int} n, @code{const wchar_t *}str)
- at deftypefnx {C function} @code{void} mgl_parser_add_param (@code{HMPR} p, @code{int} id, @code{const char *}val)
- at deftypefnx {C function} @code{void} mgl_parser_add_paramw (@code{HMPR} p, @code{int} id, @code{const wchar_t *}val)
-Function set the value of @var{n}-th parameter as string @var{str} (@var{n}=0, 1 ... 'z'-'a'+10). String @var{str} shouldn't contain @samp{$} symbol.
+ at deftypefn {Метод класса @code{mglParse}} @code{void} AddParam (@code{int} n, @code{const char *}str)
+ at deftypefnx {Метод класса @code{mglParse}} @code{void} AddParam (@code{int} n, @code{const wchar_t *}str)
+ at deftypefnx {Функция С} @code{void} mgl_parser_add_param (@code{HMPR} p, @code{int} id, @code{const char *}val)
+ at deftypefnx {Функция С} @code{void} mgl_parser_add_paramw (@code{HMPR} p, @code{int} id, @code{const wchar_t *}val)
+Устанавливает значение @var{n}-го параметра строкой @var{str} (@var{n}=0, 1 ... 'z'-'a'+10). Строка @var{str} не должна содержать символ @samp{$}.
 @end deftypefn
 
- at deftypefn {Method on @code{mglParse}} @code{mglVar *} FindVar (@code{const char *}name)
- at deftypefnx {Method on @code{mglParse}} @code{mglVar *} FindVar (@code{const wchar_t *}name)
- at deftypefnx {C function} @code{HMDT} mgl_parser_find_var  (@code{HMPR} p, @code{const char *}name)
- at deftypefnx {C function} @code{HMDT} mgl_parser_find_varw  (@code{HMPR} p, @code{const wchar_t *}name)
-Function returns the pointer to variable with name @var{name} or zero if variable is absent. Use this function to put external data array to the script or get the data from the script. You must @strong{not delete} obtained data arrays!
+ at deftypefn {Метод класса @code{mglParse}} @code{mglVar *} FindVar (@code{const char *}name)
+ at deftypefnx {Метод класса @code{mglParse}} @code{mglVar *} FindVar (@code{const wchar_t *}name)
+ at deftypefnx {Функция С} @code{HMDT} mgl_parser_find_var  (@code{HMPR} p, @code{const char *}name)
+ at deftypefnx {Функция С} @code{HMDT} mgl_parser_find_varw  (@code{HMPR} p, @code{const wchar_t *}name)
+Возвращает указатель на переменную с именем @var{name} или @code{NULL} если переменная отсутствует. Используйте эту функцию для добавления внешних массивов в скрипт. @strong{Не удаляйте} полученный массив!
 @end deftypefn
- at deftypefn {Method on @code{mglParse}} @code{mglVar *} AddVar (@code{const char *}name)
- at deftypefnx {Method on @code{mglParse}} @code{mglVar *} AddVar (@code{const wchar_t *}name)
- at deftypefnx {C function} @code{HMDT} mgl_parser_add_var (@code{HMPR} p, @code{const char *}name)
- at deftypefnx {C function} @code{HMDT} mgl_parser_add_varw (@code{HMPR} p, @code{const wchar_t *}name)
-Function returns the pointer to variable with name @var{name}. If variable is absent then new variable is created with name @var{name}. Use this function to put external data array to the script or get the data from the script. You must @strong{not delete} obtained data arrays!
+ at deftypefn {Метод класса @code{mglParse}} @code{mglVar *} AddVar (@code{const char *}name)
+ at deftypefnx {Метод класса @code{mglParse}} @code{mglVar *} AddVar (@code{const wchar_t *}name)
+ at deftypefnx {Функция С} @code{HMDT} mgl_parser_add_var (@code{HMPR} p, @code{const char *}name)
+ at deftypefnx {Функция С} @code{HMDT} mgl_parser_add_varw (@code{HMPR} p, @code{const wchar_t *}name)
+Возвращает указатель на переменную с именем @var{name}. Если переменная отсутствует, то она будет создана. Используйте эту функцию для добавления внешних массивов в скрипт. @strong{Не удаляйте} полученный массив!
 @end deftypefn
 
- at deftypefn{Method on @code{mglParse} (C++)} @code{void} DeleteVar (@code{const char *}name)
- at deftypefnx{Method on @code{mglParse} (C++)} @code{void} DeleteVar (@code{const wchar_t *}name)
- at deftypefnx {C function} @code{void} mgl_parser_del_var (@code{HMPR} p, @code{const char *}name)
- at deftypefnx {C function} @code{void} mgl_parser_del_varw (@code{HMPR} p, @code{const wchar_t *}name)
-Function delete the variable specified by its name or by its pointer.
+ at deftypefn{Метод класса @code{mglParse} (C++)} @code{void} DeleteVar (@code{const char *}name)
+ at deftypefnx{Метод класса @code{mglParse} (C++)} @code{void} DeleteVar (@code{const wchar_t *}name)
+ at deftypefnx {Функция С} @code{void} mgl_parser_del_var (@code{HMPR} p, @code{const char *}name)
+ at deftypefnx {Функция С} @code{void} mgl_parser_del_varw (@code{HMPR} p, @code{const wchar_t *}name)
+Удаляет переменную по имени @var{name}.
 @end deftypefn
 
- at deftypefn{Method on @code{mglParse} (C++)} @code{void} DeleteAll ()
- at deftypefnx {C function} @code{void} mgl_parser_del_all (@code{HMPR} p)
-Function delete all variables in this parser.
+ at deftypefn{Метод класса @code{mglParse} (C++)} @code{void} DeleteAll ()
+ at deftypefnx {Функция С} @code{void} mgl_parser_del_all (@code{HMPR} p)
+Удаляет все переменные в данном классе.
 @end deftypefn
 
- at deftypefn {Method on @code{mglParse}} @code{void} RestoreOnce ()
- at deftypefnx {C function} @code{void} mgl_parser_restore_once (@code{HMPR} p)
-Restore Once flag.
+ at deftypefn {Метод класса @code{mglParse}} @code{void} RestoreOnce ()
+ at deftypefnx {Функция С} @code{void} mgl_parser_restore_once (@code{HMPR} p)
+Восстанавливает состояние флага Once.
 @end deftypefn
 
- at deftypefn {Method on @code{mglParse}} @code{void} AllowSetSize (@code{bool} a)
- at deftypefnx {C function} @code{void} mgl_parser_allow_setsize (@code{HMPR} p, @code{int} a)
-Allow to parse 'setsize' command or not.
+ at deftypefn {Метод класса @code{mglParse}} @code{void} AllowSetSize (@code{bool} a)
+ at deftypefnx {Функция С} @code{void} mgl_parser_allow_setsize (@code{HMPR} p, @code{int} a)
+Разрешает/запрещает команду 'setsize'.
 @end deftypefn
 
- at deftypefn {Method on @code{mglParse}} @code{void} AllowFileIO (@code{bool} a)
- at deftypefnx {C function} @code{void} mgl_parser_allow_file_io (@code{HMPR} p, @code{int} a)
-Allow reading/saving files or not.
+ at deftypefn {Метод класса @code{mglParse}} @code{void} AllowFileIO (@code{bool} a)
+ at deftypefnx {Функция С} @code{void} mgl_parser_allow_file_io (@code{HMPR} p, @code{int} a)
+Разрешает/запрещает команды чтения файлов.
 @end deftypefn
 
- at deftypefn {Method on @code{mglParse}} @code{void} Stop ()
- at deftypefnx {C function} @code{void} mgl_parser_stop (@code{HMPR} p)
-Sends stop signal which terminate execution at next command.
+ at deftypefn {Метод класса @code{mglParse}} @code{void} Stop ()
+ at deftypefnx {Функция С} @code{void} mgl_parser_stop (@code{HMPR} p)
+Посылает сигнал завершения выполнения для следующей команды.
 @end deftypefn
 
 
- at deftypefn {Method on @code{mglParse}} @code{long} GetCmdNum ()
- at deftypefnx {C function} @code{long} mgl_parser_cmd_num (@code{HMPR} p)
-Return the number of registered MGL commands.
+ at deftypefn {Метод класса @code{mglParse}} @code{long} GetCmdNum ()
+ at deftypefnx {Функция С} @code{long} mgl_parser_cmd_num (@code{HMPR} p)
+Возвращает число зарегистрированных команд MGL.
 @end deftypefn
 
- at deftypefn {Method on @code{mglParse}} @code{const char *} GetCmdName (@code{long} id)
- at deftypefnx {C function} @code{const char *} mgl_parser_cmd_name (@code{HMPR} p, @code{long} id)
-Return the name of command with given @var{id}.
+ at deftypefn {Метод класса @code{mglParse}} @code{const char *} GetCmdName (@code{long} id)
+ at deftypefnx {Функция С} @code{const char *} mgl_parser_cmd_name (@code{HMPR} p, @code{long} id)
+Возвращает имя команды MGL с заданным номером @var{id}.
 @end deftypefn
 
- at deftypefn {Method on @code{mglParse}} @code{int} CmdType (@code{const char *}name)
- at deftypefnx {C function} @code{int} mgl_parser_cmd_type (@code{HMPR} p, @code{const char *}name)
-Return the type of MGL command @var{name}. Type of commands are: 0 -- not the command, 1 - data plot, 2 - other plot, 3 - setup, 4 - data handle, 5 - data create, 6 - subplot, 7 - program, 8 - 1d plot, 9 - 2d plot, 10 - 3d plot, 11 - dd plot, 12 - vector plot, 13 - axis, 14 - primitives, 15 - axis setup, 16 - text/legend, 17 - data transform.
+ at deftypefn {Метод класса @code{mglParse}} @code{int} CmdType (@code{const char *}name)
+ at deftypefnx {Функция С} @code{int} mgl_parser_cmd_type (@code{HMPR} p, @code{const char *}name)
+Возвращает тип команды MGL с именем @var{name}. Типы команд: 0 -- не команда, 1 - графики по данным, 2 - прочие графики, 3 - настройка, 4 - обработка данных, 5 - создание данных, 6 - трансформация, 7 - ход выполнения, 8 - 1d графики, 9 - 2d графики, 10 - 3d графики, 11 - двойные графики, 12 - векторные поля, 13 - оси координат, 14 - примитивы, 15 - настройка осей, 16 - текст/легенда, 17 - изменение данных.
 @end deftypefn
 
- at deftypefn {Method on @code{mglParse}} @code{const char *} CmdFormat (@code{const char *}name)
- at deftypefnx {C function} @code{const char *} mgl_parser_cmd_frmt (@code{HMPR} p, @code{const char *}name)
-Return the format of arguments for MGL command @var{name}.
+ at deftypefn {Метод класса @code{mglParse}} @code{const char *} CmdFormat (@code{const char *}name)
+ at deftypefnx {Функция С} @code{const char *} mgl_parser_cmd_frmt (@code{HMPR} p, @code{const char *}name)
+Возвращает формат аргументов команды MGL с именем @var{name}.
 @end deftypefn
 
- at deftypefn {Method on @code{mglParse}} @code{const char *} CmdDesc (@code{const char *}name)
- at deftypefnx {C function} @code{const char *} mgl_parser_cmd_desc (@code{HMPR} p, @code{const char *}name)
-Return the description of MGL command @var{name}.
+ at deftypefn {Метод класса @code{mglParse}} @code{const char *} CmdDesc (@code{const char *}name)
+ at deftypefnx {Функция С} @code{const char *} mgl_parser_cmd_desc (@code{HMPR} p, @code{const char *}name)
+Возвращает описание команды MGL с именем @var{name}.
 @end deftypefn
 
 @end ifclear
 
 @external{}
-
diff --git a/texinfo/surf_cont_fog_g.png b/texinfo/surf_cont_fog_g.png
deleted file mode 100644
index 8b4e906..0000000
Binary files a/texinfo/surf_cont_fog_g.png and /dev/null differ
diff --git a/texinfo/symbols_en.texi b/texinfo/symbols_en.texi
index 6d14b3e..53fca6c 100644
--- a/texinfo/symbols_en.texi
+++ b/texinfo/symbols_en.texi
@@ -1,3 +1,5 @@
+ at nav{}
+
 This appendix contain the full list of symbols (characters) used by MathGL for setting up plot. Also it contain sections for full list of hot-keys supported by mglview tool and by UDAV program.
 
 @menu
@@ -10,6 +12,7 @@ This appendix contain the full list of symbols (characters) used by MathGL for s
 @external{}
 @node Symbols for styles, Hot-keys for mglview, , Symbols and hot-keys
 @section Symbols for styles
+ at nav{}
 
 Below is full list of all characters (symbols) which MathGL use for setting up the plot.
 
@@ -53,11 +56,15 @@ denote string in @ref{MGL scripts} or in @ref{Command options}.
 @item *
 one of marks (see @ref{Line styles});
 
+one of mask for face filling (see @ref{Color scheme});
+
 operation in @ref{Textual formulas}.
 
 @item +
 one of marks (see @ref{Line styles}) or kind of @ref{error} boxes;
 
+one of mask for face filling (see @ref{Color scheme});
+
 operation in @ref{Textual formulas}.
 
 @item ,
@@ -66,12 +73,14 @@ separator for color positions (see @ref{Color styles}) or items in a list.
 @item -
 solid line style (see @ref{Line styles});
 
+one of mask for face filling (see @ref{Color scheme});
+
 place entries horizontally in @ref{legend};
 
 operation in @ref{Textual formulas}.
 
 @item .
-one of marks (see @ref{Line styles});
+one of marks (see @ref{Line styles}) or kind of @ref{error} boxes;
 
 set to draw hachures instead of arrows for @ref{vect}, @ref{vect3};
 
@@ -92,34 +101,46 @@ range operation in @ref{MGL scripts}.
 @item ;
 line dashing style (see @ref{Line styles});
 
+one of mask for face filling (see @ref{Color scheme});
+
 end of an option in @ref{MGL scripts} or in @ref{Command options}.
 
 @item <
 one of marks (see @ref{Line styles});
 
+one of mask for face filling (see @ref{Color scheme});
+
 style of @ref{subplot} and @ref{inplot};
 
 set position of @ref{colorbar};
 
 style of @ref{vect}, @ref{vect3};
 
+align left in @ref{bars}, @ref{barh}, @ref{boxplot}, @ref{cones}, @ref{candle}, @ref{ohlc};
+
 operation in @ref{Textual formulas}.
 
 
 @item >
 one of marks (see @ref{Line styles});
 
+one of mask for face filling (see @ref{Color scheme});
+
 style of @ref{subplot} and @ref{inplot};
 
 set position of @ref{colorbar};
 
 style of @ref{vect}, @ref{vect3};
 
+align right in @ref{bars}, @ref{barh}, @ref{boxplot}, @ref{cones}, @ref{candle}, @ref{ohlc};
+
 operation in @ref{Textual formulas}.
 
 @item =
 line dashing style (see @ref{Line styles});
 
+one of mask for face filling (see @ref{Color scheme});
+
 set to use equidistant columns for @ref{table};
 
 set to use color gradient for @ref{vect}, @ref{vect3};
@@ -144,12 +165,20 @@ reduce text size inside a string (see @ref{Font styles}).
 @item ^
 one of marks (see @ref{Line styles});
 
+one of mask for face filling (see @ref{Color scheme});
+
 style of @ref{subplot} and @ref{inplot};
 
 set position of @ref{colorbar};
 
+set outer position for @ref{legend};
+
+inverse default position for @ref{axis};
+
 switch to upper index inside a string (see @ref{Font styles});
 
+align center in @ref{bars}, @ref{barh}, @ref{boxplot}, @ref{cones}, @ref{candle}, @ref{ohlc};
+
 operation in @ref{Textual formulas}.
 
 @item _
@@ -189,6 +218,9 @@ operation in @ref{Textual formulas}.
 @item \
 string continuation symbol on next line for @ref{MGL scripts}.
 
+ at item ~
+one of mask for face filling (see @ref{Color scheme}).
+
 @item 0,1,2,3,4,5,6,7,8,9
 line width (see @ref{Line styles});
 
@@ -198,6 +230,9 @@ kind of smoothing (for digits 1,3,5) in @ref{smooth};
 
 digits for a value.
 
+ at item 4,6,8
+draw square, hex- or octo-pyramids instead of cones in @ref{cone}, @ref{cones}.
+
 @item A,B,C,D,E,F,a,b,c,d,e,f
 can be hex-digit for color specification if placed inside @{@} (see @ref{Color styles}).
 
@@ -209,7 +244,7 @@ set to use absolute position in whole picture for @ref{text}, @ref{colorbar}, @r
 @item a
 set to use absolute position in subplot for @ref{text};
 
-style of @ref{bars}, @ref{barh}.
+style of @ref{bars}, @ref{barh}, @ref{cones}.
 
 @item B
 dark blue color (see @ref{Color styles}).
@@ -232,10 +267,14 @@ name of color axis;
 cosine transform for @ref{transform}.
 
 @item D
-arrow style (see @ref{Line styles}).
+arrow style (see @ref{Line styles});
+
+one of mask for face filling (see @ref{Color scheme}).
 
 @item d
-one of marks (see @ref{Line styles}) or kind of @ref{error} boxes.
+one of marks (see @ref{Line styles}) or kind of @ref{error} boxes;
+
+one of mask for face filling (see @ref{Color scheme}).
 
 @item E
 dark green-yellow color (see @ref{Color styles}).
@@ -283,6 +322,8 @@ inverse Fourier transform for @ref{transform}.
 @item j
 line dashing style (see @ref{Line styles});
 
+one of mask for face filling (see @ref{Color scheme}).
+
 @item K
 arrow style (see @ref{Line styles}).
 
@@ -310,11 +351,15 @@ dark sky-blue color (see @ref{Color styles}).
 sky-blue color (see @ref{Color styles}).
 
 @item O
-arrow style (see @ref{Line styles}).
+arrow style (see @ref{Line styles});
+
+one of mask for face filling (see @ref{Color scheme}).
 
 @item o
 one of marks (see @ref{Line styles}) or kind of @ref{error} boxes;
 
+one of mask for face filling (see @ref{Color scheme});
+
 over-line text if placed after @samp{:} (see @ref{Font styles}).
 
 @item P
@@ -340,11 +385,18 @@ red color (see @ref{Color styles}).
 @item S
 arrow style (see @ref{Line styles});
 
+one of mask for face filling (see @ref{Color scheme}).
+
 @item s
 one of marks (see @ref{Line styles}) or kind of @ref{error} boxes;
 
+one of mask for face filling (see @ref{Color scheme});
+
 sine transform for @ref{transform}.
 
+ at item t
+draw tubes instead of cones in @ref{cone}, @ref{cones};
+
 @item T
 arrow style (see @ref{Line styles});
 
@@ -419,6 +471,7 @@ style of @ref{tape}.
 @external{}
 @node Hot-keys for mglview, Hot-keys for UDAV, Symbols for styles, Symbols and hot-keys
 @section Hot-keys for mglview
+ at nav{}
 
 @multitable @columnfractions .3 .7
 @headitem Key @tab Description
@@ -490,6 +543,7 @@ style of @ref{tape}.
 @external{}
 @node Hot-keys for UDAV, , Hot-keys for mglview, Symbols and hot-keys
 @section Hot-keys for UDAV
+ at nav{}
 
 @multitable @columnfractions .3 .7
 @headitem Key @tab Description
diff --git a/texinfo/symbols_ru.texi b/texinfo/symbols_ru.texi
index d2b4566..53fca6c 100644
--- a/texinfo/symbols_ru.texi
+++ b/texinfo/symbols_ru.texi
@@ -1,3 +1,5 @@
+ at nav{}
+
 This appendix contain the full list of symbols (characters) used by MathGL for setting up plot. Also it contain sections for full list of hot-keys supported by mglview tool and by UDAV program.
 
 @menu
@@ -10,6 +12,7 @@ This appendix contain the full list of symbols (characters) used by MathGL for s
 @external{}
 @node Symbols for styles, Hot-keys for mglview, , Symbols and hot-keys
 @section Symbols for styles
+ at nav{}
 
 Below is full list of all characters (symbols) which MathGL use for setting up the plot.
 
@@ -53,11 +56,15 @@ denote string in @ref{MGL scripts} or in @ref{Command options}.
 @item *
 one of marks (see @ref{Line styles});
 
+one of mask for face filling (see @ref{Color scheme});
+
 operation in @ref{Textual formulas}.
 
 @item +
 one of marks (see @ref{Line styles}) or kind of @ref{error} boxes;
 
+one of mask for face filling (see @ref{Color scheme});
+
 operation in @ref{Textual formulas}.
 
 @item ,
@@ -66,12 +73,14 @@ separator for color positions (see @ref{Color styles}) or items in a list.
 @item -
 solid line style (see @ref{Line styles});
 
+one of mask for face filling (see @ref{Color scheme});
+
 place entries horizontally in @ref{legend};
 
 operation in @ref{Textual formulas}.
 
 @item .
-one of marks (see @ref{Line styles});
+one of marks (see @ref{Line styles}) or kind of @ref{error} boxes;
 
 set to draw hachures instead of arrows for @ref{vect}, @ref{vect3};
 
@@ -92,34 +101,46 @@ range operation in @ref{MGL scripts}.
 @item ;
 line dashing style (see @ref{Line styles});
 
+one of mask for face filling (see @ref{Color scheme});
+
 end of an option in @ref{MGL scripts} or in @ref{Command options}.
 
 @item <
 one of marks (see @ref{Line styles});
 
+one of mask for face filling (see @ref{Color scheme});
+
 style of @ref{subplot} and @ref{inplot};
 
 set position of @ref{colorbar};
 
 style of @ref{vect}, @ref{vect3};
 
+align left in @ref{bars}, @ref{barh}, @ref{boxplot}, @ref{cones}, @ref{candle}, @ref{ohlc};
+
 operation in @ref{Textual formulas}.
 
 
 @item >
 one of marks (see @ref{Line styles});
 
+one of mask for face filling (see @ref{Color scheme});
+
 style of @ref{subplot} and @ref{inplot};
 
 set position of @ref{colorbar};
 
 style of @ref{vect}, @ref{vect3};
 
+align right in @ref{bars}, @ref{barh}, @ref{boxplot}, @ref{cones}, @ref{candle}, @ref{ohlc};
+
 operation in @ref{Textual formulas}.
 
 @item =
 line dashing style (see @ref{Line styles});
 
+one of mask for face filling (see @ref{Color scheme});
+
 set to use equidistant columns for @ref{table};
 
 set to use color gradient for @ref{vect}, @ref{vect3};
@@ -144,12 +165,20 @@ reduce text size inside a string (see @ref{Font styles}).
 @item ^
 one of marks (see @ref{Line styles});
 
+one of mask for face filling (see @ref{Color scheme});
+
 style of @ref{subplot} and @ref{inplot};
 
 set position of @ref{colorbar};
 
+set outer position for @ref{legend};
+
+inverse default position for @ref{axis};
+
 switch to upper index inside a string (see @ref{Font styles});
 
+align center in @ref{bars}, @ref{barh}, @ref{boxplot}, @ref{cones}, @ref{candle}, @ref{ohlc};
+
 operation in @ref{Textual formulas}.
 
 @item _
@@ -189,6 +218,9 @@ operation in @ref{Textual formulas}.
 @item \
 string continuation symbol on next line for @ref{MGL scripts}.
 
+ at item ~
+one of mask for face filling (see @ref{Color scheme}).
+
 @item 0,1,2,3,4,5,6,7,8,9
 line width (see @ref{Line styles});
 
@@ -198,6 +230,9 @@ kind of smoothing (for digits 1,3,5) in @ref{smooth};
 
 digits for a value.
 
+ at item 4,6,8
+draw square, hex- or octo-pyramids instead of cones in @ref{cone}, @ref{cones}.
+
 @item A,B,C,D,E,F,a,b,c,d,e,f
 can be hex-digit for color specification if placed inside @{@} (see @ref{Color styles}).
 
@@ -209,7 +244,7 @@ set to use absolute position in whole picture for @ref{text}, @ref{colorbar}, @r
 @item a
 set to use absolute position in subplot for @ref{text};
 
-style of @ref{bars}, @ref{barh}.
+style of @ref{bars}, @ref{barh}, @ref{cones}.
 
 @item B
 dark blue color (see @ref{Color styles}).
@@ -232,10 +267,14 @@ name of color axis;
 cosine transform for @ref{transform}.
 
 @item D
-arrow style (see @ref{Line styles}).
+arrow style (see @ref{Line styles});
+
+one of mask for face filling (see @ref{Color scheme}).
 
 @item d
-one of marks (see @ref{Line styles}) or kind of @ref{error} boxes.
+one of marks (see @ref{Line styles}) or kind of @ref{error} boxes;
+
+one of mask for face filling (see @ref{Color scheme}).
 
 @item E
 dark green-yellow color (see @ref{Color styles}).
@@ -283,6 +322,8 @@ inverse Fourier transform for @ref{transform}.
 @item j
 line dashing style (see @ref{Line styles});
 
+one of mask for face filling (see @ref{Color scheme}).
+
 @item K
 arrow style (see @ref{Line styles}).
 
@@ -310,11 +351,15 @@ dark sky-blue color (see @ref{Color styles}).
 sky-blue color (see @ref{Color styles}).
 
 @item O
-arrow style (see @ref{Line styles}).
+arrow style (see @ref{Line styles});
+
+one of mask for face filling (see @ref{Color scheme}).
 
 @item o
 one of marks (see @ref{Line styles}) or kind of @ref{error} boxes;
 
+one of mask for face filling (see @ref{Color scheme});
+
 over-line text if placed after @samp{:} (see @ref{Font styles}).
 
 @item P
@@ -340,11 +385,18 @@ red color (see @ref{Color styles}).
 @item S
 arrow style (see @ref{Line styles});
 
+one of mask for face filling (see @ref{Color scheme}).
+
 @item s
 one of marks (see @ref{Line styles}) or kind of @ref{error} boxes;
 
+one of mask for face filling (see @ref{Color scheme});
+
 sine transform for @ref{transform}.
 
+ at item t
+draw tubes instead of cones in @ref{cone}, @ref{cones};
+
 @item T
 arrow style (see @ref{Line styles});
 
@@ -419,8 +471,9 @@ style of @ref{tape}.
 @external{}
 @node Hot-keys for mglview, Hot-keys for UDAV, Symbols for styles, Symbols and hot-keys
 @section Hot-keys for mglview
+ at nav{}
 
- at multitable @columnfractions .15 .25 .6
+ at multitable @columnfractions .3 .7
 @headitem Key @tab Description
 @item @key{Ctrl-P}
 @tab Open printer dialog and print graphics.
@@ -490,8 +543,9 @@ style of @ref{tape}.
 @external{}
 @node Hot-keys for UDAV, , Hot-keys for mglview, Symbols and hot-keys
 @section Hot-keys for UDAV
+ at nav{}
 
- at multitable @columnfractions .15 .25 .6
+ at multitable @columnfractions .3 .7
 @headitem Key @tab Description
 @item @key{Ctrl-N}
 @tab Create new window with empty script. Note, all scripts share variables. So, second window can be used to see some additional information of existed variables.
diff --git a/texinfo/time.texi b/texinfo/time.texi
new file mode 100644
index 0000000..a6e0383
--- /dev/null
+++ b/texinfo/time.texi
@@ -0,0 +1,112 @@
+ at multitable @columnfractions .16 .12 .12 .12 .12 .12 .12 .12
+ at headitem Name @tab q=0 @tab q=1 @tab q=2 @tab q=4 @tab q=5 @tab q=6 @tab q=8
+ at item alpha @tab 0.09 @tab 0.1 @tab 0.12 @tab 0.03 @tab 0.08 @tab 0.11 @tab 0.02
+ at item area @tab 0.04 @tab 0.07 @tab 0.1 @tab 0.05 @tab 0.07 @tab 0.11 @tab 0.02
+ at item aspect @tab 0.05 @tab 0.04 @tab 0.07 @tab 0.03 @tab 0.02 @tab 0.08 @tab 0.02
+ at item axial @tab 0.7 @tab 0.76 @tab 1.05 @tab 0.3 @tab 0.43 @tab 0.64 @tab 0.1
+ at item axis @tab 0.09 @tab 0.1 @tab 0.14 @tab 0.06 @tab 0.05 @tab 0.15 @tab 0.02
+ at item barh @tab 0.04 @tab 0.04 @tab 0.07 @tab 0.03 @tab 0.04 @tab 0.09 @tab 0.02
+ at item bars @tab 0.05 @tab 0.06 @tab 0.09 @tab 0.04 @tab 0.06 @tab 0.12 @tab 0.02
+ at item belt @tab 0.03 @tab 0.05 @tab 0.07 @tab 0.02 @tab 0.04 @tab 0.08 @tab 0.01
+ at item box @tab 0.03 @tab 0.05 @tab 0.08 @tab 0.03 @tab 0.08 @tab 0.12 @tab 0.01
+ at item boxplot @tab 0.02 @tab 0.02 @tab 0.04 @tab 0.02 @tab 0.02 @tab 0.04 @tab 0.01
+ at item boxs @tab 0.25 @tab 0.28 @tab 0.41 @tab 0.08 @tab 0.13 @tab 0.22 @tab 0.06
+ at item candle @tab 0.02 @tab 0.03 @tab 0.05 @tab 0.02 @tab 0.03 @tab 0.05 @tab 0.01
+ at item chart @tab 0.62 @tab 0.82 @tab 0.93 @tab 0.29 @tab 0.69 @tab 0.97 @tab 0.26
+ at item cloud @tab 0.04 @tab 6.14 @tab 6.24 @tab 0.03 @tab 3.1 @tab 3.37 @tab 0.03
+ at item colorbar @tab 0.17 @tab 0.2 @tab 0.25 @tab 0.1 @tab 0.17 @tab 0.3 @tab 0.05
+ at item combined @tab 0.47 @tab 0.36 @tab 0.42 @tab 0.23 @tab 0.28 @tab 0.37 @tab 0.2
+ at item cones @tab 0.21 @tab 0.16 @tab 0.21 @tab 0.07 @tab 0.11 @tab 0.23 @tab 0.05
+ at item cont @tab 0.1 @tab 0.11 @tab 0.16 @tab 0.08 @tab 0.07 @tab 0.16 @tab 0.06
+ at item cont_xyz @tab 0.06 @tab 0.05 @tab 0.08 @tab 0.05 @tab 0.05 @tab 0.08 @tab 0.05
+ at item conta @tab 0.05 @tab 0.05 @tab 0.07 @tab 0.04 @tab 0.05 @tab 0.08 @tab 0.03
+ at item contd @tab 0.23 @tab 0.24 @tab 0.27 @tab 0.14 @tab 0.17 @tab 0.23 @tab 0.12
+ at item contf @tab 0.18 @tab 0.2 @tab 0.24 @tab 0.1 @tab 0.14 @tab 0.21 @tab 0.09
+ at item contf_xyz @tab 0.09 @tab 0.11 @tab 0.15 @tab 0.08 @tab 0.1 @tab 0.11 @tab 0.05
+ at item contfa @tab 0.17 @tab 0.16 @tab 0.18 @tab 0.08 @tab 0.14 @tab 0.18 @tab 0.07
+ at item contv @tab 0.14 @tab 0.16 @tab 0.18 @tab 0.1 @tab 0.12 @tab 0.19 @tab 0.08
+ at item correl @tab 0.04 @tab 0.05 @tab 0.07 @tab 0.03 @tab 0.03 @tab 0.09 @tab 0.02
+ at item curvcoor @tab 0.15 @tab 0.15 @tab 0.2 @tab 0.1 @tab 0.11 @tab 0.18 @tab 0.09
+ at item cut @tab 1.01 @tab 0.61 @tab 0.65 @tab 0.49 @tab 0.54 @tab 0.61 @tab 0.42
+ at item dat_diff @tab 0.06 @tab 0.08 @tab 0.12 @tab 0.03 @tab 0.06 @tab 0.12 @tab 0.03
+ at item dat_extra @tab 0.28 @tab 0.19 @tab 0.24 @tab 0.1 @tab 0.11 @tab 0.2 @tab 0.06
+ at item data1 @tab 3.66 @tab 2.43 @tab 2.49 @tab 2.22 @tab 2.15 @tab 2.23 @tab 2.07
+ at item data2 @tab 2.47 @tab 2.13 @tab 2.14 @tab 2.1 @tab 2.05 @tab 2.12 @tab 2
+ at item dens @tab 0.11 @tab 0.17 @tab 0.2 @tab 0.07 @tab 0.11 @tab 0.19 @tab 0.05
+ at item dens_xyz @tab 0.07 @tab 0.1 @tab 0.13 @tab 0.05 @tab 0.09 @tab 0.12 @tab 0.03
+ at item densa @tab 0.07 @tab 0.09 @tab 0.12 @tab 0.03 @tab 0.07 @tab 0.12 @tab 0.03
+ at item dew @tab 1.67 @tab 0.74 @tab 0.73 @tab 0.14 @tab 0.14 @tab 0.15 @tab 0.07
+ at item dots @tab 0.04 @tab 0.04 @tab 0.05 @tab 0.03 @tab 0.04 @tab 0.05 @tab 0.01
+ at item error @tab 0.05 @tab 0.05 @tab 0.08 @tab 0.04 @tab 0.04 @tab 0.1 @tab 0.02
+ at item error2 @tab 0.05 @tab 0.06 @tab 0.1 @tab 0.04 @tab 0.05 @tab 0.1 @tab 0.04
+ at item export @tab 0.17 @tab 0.25 @tab 0.27 @tab 0.13 @tab 0.18 @tab 0.21 @tab 0.12
+ at item fall @tab 0.03 @tab 0.02 @tab 0.05 @tab 0.02 @tab 0.01 @tab 0.05 @tab 0.01
+ at item fexport @tab 2.34 @tab 2.31 @tab 2.72 @tab 0.5 @tab 0.5 @tab 0.85 @tab 1.59
+ at item fit @tab 0.05 @tab 0.05 @tab 0.08 @tab 0.04 @tab 0.04 @tab 0.07 @tab 0.02
+ at item flow @tab 0.3 @tab 0.32 @tab 0.42 @tab 0.23 @tab 0.24 @tab 0.36 @tab 0.23
+ at item fog @tab 0.04 @tab 0.07 @tab 0.09 @tab 0.02 @tab 0.07 @tab 0.11 @tab 0.01
+ at item fonts @tab 2.44 @tab 2.75 @tab 2.19 @tab 2.16 @tab 2.2 @tab 2.23 @tab 2.35
+ at item grad @tab 0.06 @tab 0.11 @tab 0.16 @tab 0.05 @tab 0.1 @tab 0.15 @tab 0.05
+ at item hist @tab 0.18 @tab 0.19 @tab 0.22 @tab 0.19 @tab 0.2 @tab 0.25 @tab 0.05
+ at item inplot @tab 0.06 @tab 0.06 @tab 0.1 @tab 0.04 @tab 0.04 @tab 0.11 @tab 0.04
+ at item label @tab 0.04 @tab 0.04 @tab 0.06 @tab 0.03 @tab 0.03 @tab 0.08 @tab 0.01
+ at item legend @tab 0.17 @tab 0.18 @tab 0.26 @tab 0.1 @tab 0.12 @tab 0.26 @tab 0.03
+ at item light @tab 0.15 @tab 0.15 @tab 0.16 @tab 0.15 @tab 0.15 @tab 0.16 @tab 0.15
+ at item loglog @tab 0.13 @tab 0.13 @tab 0.18 @tab 0.1 @tab 0.09 @tab 0.15 @tab 0.08
+ at item map @tab 0.04 @tab 0.08 @tab 0.1 @tab 0.03 @tab 0.06 @tab 0.1 @tab 0.02
+ at item mark @tab 0.03 @tab 0.03 @tab 0.04 @tab 0.03 @tab 0.04 @tab 0.05 @tab 0.01
+ at item mask @tab 0.07 @tab 0.12 @tab 0.14 @tab 0.05 @tab 0.08 @tab 0.15 @tab 0.02
+ at item mesh @tab 0.03 @tab 0.03 @tab 0.08 @tab 0.02 @tab 0.02 @tab 0.07 @tab 0.01
+ at item mirror @tab 0.12 @tab 0.13 @tab 0.17 @tab 0.06 @tab 0.08 @tab 0.16 @tab 0.04
+ at item molecule @tab 0.1 @tab 0.11 @tab 0.13 @tab 0.03 @tab 0.06 @tab 0.06 @tab 0.02
+ at item param1 @tab 0.27 @tab 0.28 @tab 0.37 @tab 0.11 @tab 0.15 @tab 0.37 @tab 0.07
+ at item param2 @tab 0.64 @tab 0.61 @tab 0.62 @tab 0.24 @tab 0.35 @tab 0.42 @tab 0.22
+ at item param3 @tab 3.05 @tab 3.34 @tab 3.41 @tab 1.63 @tab 2.05 @tab 2.08 @tab 1.51
+ at item paramv @tab 4.94 @tab 4.78 @tab 4.92 @tab 1.26 @tab 1.49 @tab 1.45 @tab 1.25
+ at item parser @tab 0.04 @tab 0.05 @tab 0.06 @tab 0.05 @tab 0.04 @tab 0.09 @tab 0.03
+ at item pde @tab 2.12 @tab 2.18 @tab 2.22 @tab 2.05 @tab 2.12 @tab 2.13 @tab 2.02
+ at item pipe @tab 4.73 @tab 3.13 @tab 2.99 @tab 0.81 @tab 1.05 @tab 0.99 @tab 0.64
+ at item plot @tab 0.06 @tab 0.06 @tab 0.1 @tab 0.06 @tab 0.05 @tab 0.1 @tab 0.02
+ at item primitives @tab 0.11 @tab 0.15 @tab 0.2 @tab 0.07 @tab 0.16 @tab 0.22 @tab 0.02
+ at item projection @tab 0.16 @tab 0.2 @tab 0.28 @tab 0.08 @tab 0.1 @tab 0.26 @tab 0.05
+ at item projection5 @tab 0.14 @tab 0.18 @tab 0.25 @tab 0.08 @tab 0.1 @tab 0.24 @tab 0.04
+ at item qo2d @tab 0.61 @tab 0.66 @tab 0.7 @tab 0.58 @tab 0.62 @tab 0.67 @tab 0.54
+ at item radar @tab 0.03 @tab 0.03 @tab 0.04 @tab 0.03 @tab 0.02 @tab 0.04 @tab 0.01
+ at item refill @tab 0.02 @tab 0.02 @tab 0.03 @tab 0.02 @tab 0.02 @tab 0.05 @tab 0.01
+ at item region @tab 0.05 @tab 0.06 @tab 0.11 @tab 0.04 @tab 0.08 @tab 0.15 @tab 0.02
+ at item schemes @tab 0.1 @tab 0.15 @tab 0.19 @tab 0.07 @tab 0.11 @tab 0.2 @tab 0.02
+ at item several_light @tab 0.07 @tab 0.1 @tab 0.13 @tab 0.02 @tab 0.11 @tab 0.15 @tab 0.02
+ at item solve @tab 0.07 @tab 0.07 @tab 0.13 @tab 0.06 @tab 0.06 @tab 0.15 @tab 0.02
+ at item stem @tab 0.04 @tab 0.04 @tab 0.08 @tab 0.04 @tab 0.03 @tab 0.08 @tab 0.02
+ at item step @tab 0.04 @tab 0.05 @tab 0.07 @tab 0.04 @tab 0.04 @tab 0.08 @tab 0.02
+ at item stereo @tab 0.06 @tab 0.08 @tab 0.09 @tab 0.03 @tab 0.08 @tab 0.11 @tab 0.02
+ at item stfa @tab 0.06 @tab 0.1 @tab 0.17 @tab 0.04 @tab 0.07 @tab 0.14 @tab 0.03
+ at item style @tab 0.18 @tab 0.2 @tab 0.28 @tab 0.1 @tab 0.12 @tab 0.36 @tab 0.03
+ at item surf @tab 0.17 @tab 0.18 @tab 0.21 @tab 0.08 @tab 0.12 @tab 0.18 @tab 0.04
+ at item surf3 @tab 2.5 @tab 2.18 @tab 2.56 @tab 1.91 @tab 1.92 @tab 2.52 @tab 0.58
+ at item surf3a @tab 0.62 @tab 0.37 @tab 0.38 @tab 0.26 @tab 0.4 @tab 0.44 @tab 0.2
+ at item surf3c @tab 0.61 @tab 0.36 @tab 0.39 @tab 0.24 @tab 0.4 @tab 0.43 @tab 0.19
+ at item surfa @tab 0.04 @tab 0.07 @tab 0.09 @tab 0.02 @tab 0.07 @tab 0.11 @tab 0.02
+ at item surfc @tab 0.04 @tab 0.07 @tab 0.09 @tab 0.02 @tab 0.07 @tab 0.1 @tab 0.01
+ at item table @tab 0.24 @tab 0.22 @tab 0.31 @tab 0.07 @tab 0.07 @tab 0.13 @tab 0.04
+ at item tape @tab 0.05 @tab 0.06 @tab 0.1 @tab 0.04 @tab 0.06 @tab 0.12 @tab 0.03
+ at item tens @tab 0.04 @tab 0.03 @tab 0.06 @tab 0.04 @tab 0.03 @tab 0.07 @tab 0.02
+ at item ternary @tab 0.15 @tab 0.18 @tab 0.25 @tab 0.09 @tab 0.11 @tab 0.3 @tab 0.04
+ at item text @tab 0.15 @tab 0.15 @tab 0.21 @tab 0.05 @tab 0.04 @tab 0.1 @tab 0.02
+ at item text2 @tab 0.1 @tab 0.1 @tab 0.17 @tab 0.06 @tab 0.06 @tab 0.12 @tab 0.02
+ at item textmark @tab 0.07 @tab 0.07 @tab 0.12 @tab 0.04 @tab 0.04 @tab 0.12 @tab 0.01
+ at item ticks @tab 0.11 @tab 0.11 @tab 0.17 @tab 0.06 @tab 0.06 @tab 0.16 @tab 0.02
+ at item tile @tab 0.03 @tab 0.05 @tab 0.07 @tab 0.02 @tab 0.03 @tab 0.06 @tab 0.02
+ at item tiles @tab 0.03 @tab 0.05 @tab 0.07 @tab 0.03 @tab 0.05 @tab 0.08 @tab 0.02
+ at item torus @tab 0.13 @tab 0.17 @tab 0.24 @tab 0.07 @tab 0.11 @tab 0.17 @tab 0.05
+ at item traj @tab 0.02 @tab 0.02 @tab 0.04 @tab 0.02 @tab 0.02 @tab 0.05 @tab 0.01
+ at item triangulation @tab 0.04 @tab 0.07 @tab 0.09 @tab 0.02 @tab 0.06 @tab 0.12 @tab 0.02
+ at item triplot @tab 0.03 @tab 0.13 @tab 0.18 @tab 0.03 @tab 0.12 @tab 0.19 @tab 0.01
+ at item tube @tab 0.1 @tab 0.17 @tab 0.22 @tab 0.07 @tab 0.11 @tab 0.17 @tab 0.03
+ at item type0 @tab 0.22 @tab 0.24 @tab 0.28 @tab 0.07 @tab 0.17 @tab 0.21 @tab 0.06
+ at item type1 @tab 0.24 @tab 0.24 @tab 0.28 @tab 0.07 @tab 0.17 @tab 0.21 @tab 0.05
+ at item type2 @tab 0.24 @tab 0.24 @tab 0.28 @tab 0.07 @tab 0.17 @tab 0.21 @tab 0.06
+ at item vect @tab 0.1 @tab 0.1 @tab 0.18 @tab 0.06 @tab 0.06 @tab 0.16 @tab 0.04
+ at item vecta @tab 0.03 @tab 0.04 @tab 0.07 @tab 0.03 @tab 0.03 @tab 0.08 @tab 0.02
+ at item venn @tab 0.02 @tab 0.08 @tab 0.12 @tab 0.02 @tab 0.1 @tab 0.14 @tab 0.01
+ at end multitable
diff --git a/texinfo/time_big.texi b/texinfo/time_big.texi
new file mode 100644
index 0000000..0a8d179
--- /dev/null
+++ b/texinfo/time_big.texi
@@ -0,0 +1,112 @@
+ at multitable @columnfractions .16 .12 .12 .12 .12 .12 .12 .12
+ at headitem Name @tab q=0 @tab q=1 @tab q=2 @tab q=4 @tab q=5 @tab q=6 @tab q=8
+ at item alpha @tab 0.13 @tab 0.32 @tab 0.41 @tab 0.08 @tab 0.32 @tab 0.46 @tab 0.06
+ at item area @tab 0.09 @tab 0.26 @tab 0.38 @tab 0.1 @tab 0.2 @tab 0.34 @tab 0.05
+ at item aspect @tab 0.09 @tab 0.08 @tab 0.15 @tab 0.08 @tab 0.08 @tab 0.18 @tab 0.05
+ at item axial @tab 0.9 @tab 1.77 @tab 2.43 @tab 0.44 @tab 1.11 @tab 1.64 @tab 0.15
+ at item axis @tab 0.14 @tab 0.13 @tab 0.22 @tab 0.12 @tab 0.11 @tab 0.29 @tab 0.06
+ at item barh @tab 0.08 @tab 0.13 @tab 0.21 @tab 0.08 @tab 0.17 @tab 0.32 @tab 0.06
+ at item bars @tab 0.09 @tab 0.13 @tab 0.22 @tab 0.09 @tab 0.18 @tab 0.36 @tab 0.06
+ at item belt @tab 0.07 @tab 0.16 @tab 0.22 @tab 0.07 @tab 0.25 @tab 0.36 @tab 0.05
+ at item box @tab 0.07 @tab 0.15 @tab 0.25 @tab 0.08 @tab 0.18 @tab 0.3 @tab 0.06
+ at item boxplot @tab 0.06 @tab 0.05 @tab 0.11 @tab 0.06 @tab 0.06 @tab 0.14 @tab 0.05
+ at item boxs @tab 0.31 @tab 0.63 @tab 1.03 @tab 0.13 @tab 0.45 @tab 0.72 @tab 0.11
+ at item candle @tab 0.06 @tab 0.07 @tab 0.15 @tab 0.06 @tab 0.07 @tab 0.17 @tab 0.05
+ at item chart @tab 0.71 @tab 2.39 @tab 2.9 @tab 0.4 @tab 2.65 @tab 3.62 @tab 0.33
+ at item cloud @tab 0.08 @tab 10.6 @tab 12.1 @tab 0.08 @tab 8.62 @tab 11.2 @tab 0.07
+ at item colorbar @tab 0.24 @tab 0.32 @tab 0.45 @tab 0.22 @tab 0.38 @tab 0.56 @tab 0.09
+ at item combined @tab 0.53 @tab 0.62 @tab 0.82 @tab 0.32 @tab 0.59 @tab 0.85 @tab 0.24
+ at item cones @tab 0.26 @tab 0.37 @tab 0.53 @tab 0.14 @tab 0.38 @tab 0.74 @tab 0.09
+ at item cont @tab 0.16 @tab 0.15 @tab 0.26 @tab 0.12 @tab 0.12 @tab 0.3 @tab 0.08
+ at item cont_xyz @tab 0.1 @tab 0.1 @tab 0.18 @tab 0.1 @tab 0.09 @tab 0.19 @tab 0.08
+ at item conta @tab 0.09 @tab 0.09 @tab 0.16 @tab 0.08 @tab 0.09 @tab 0.2 @tab 0.07
+ at item contd @tab 0.28 @tab 0.39 @tab 0.5 @tab 0.19 @tab 0.34 @tab 0.49 @tab 0.15
+ at item contf @tab 0.24 @tab 0.35 @tab 0.46 @tab 0.18 @tab 0.32 @tab 0.47 @tab 0.13
+ at item contf_xyz @tab 0.14 @tab 0.23 @tab 0.35 @tab 0.13 @tab 0.2 @tab 0.31 @tab 0.09
+ at item contfa @tab 0.23 @tab 0.36 @tab 0.46 @tab 0.15 @tab 0.41 @tab 0.54 @tab 0.11
+ at item contv @tab 0.19 @tab 0.3 @tab 0.4 @tab 0.16 @tab 0.33 @tab 0.41 @tab 0.11
+ at item correl @tab 0.09 @tab 0.08 @tab 0.17 @tab 0.09 @tab 0.08 @tab 0.23 @tab 0.05
+ at item curvcoor @tab 0.2 @tab 0.2 @tab 0.31 @tab 0.16 @tab 0.16 @tab 0.32 @tab 0.13
+ at item cut @tab 1.13 @tab 0.98 @tab 1.09 @tab 0.6 @tab 1.07 @tab 1.26 @tab 0.49
+ at item dat_diff @tab 0.1 @tab 0.2 @tab 0.29 @tab 0.09 @tab 0.24 @tab 0.37 @tab 0.07
+ at item dat_extra @tab 0.33 @tab 0.32 @tab 0.43 @tab 0.17 @tab 0.3 @tab 0.45 @tab 0.1
+ at item data1 @tab 4.01 @tab 2.91 @tab 3.02 @tab 2.47 @tab 2.78 @tab 2.99 @tab 2.26
+ at item data2 @tab 2.65 @tab 2.36 @tab 2.41 @tab 2.24 @tab 2.31 @tab 2.51 @tab 2.16
+ at item dens @tab 0.17 @tab 0.39 @tab 0.55 @tab 0.14 @tab 0.39 @tab 0.61 @tab 0.09
+ at item dens_xyz @tab 0.12 @tab 0.29 @tab 0.42 @tab 0.1 @tab 0.32 @tab 0.47 @tab 0.07
+ at item densa @tab 0.12 @tab 0.24 @tab 0.37 @tab 0.09 @tab 0.32 @tab 0.52 @tab 0.07
+ at item dew @tab 1.76 @tab 1.07 @tab 1.1 @tab 0.2 @tab 0.3 @tab 0.38 @tab 0.11
+ at item dots @tab 0.09 @tab 0.09 @tab 0.12 @tab 0.08 @tab 0.09 @tab 0.15 @tab 0.06
+ at item error @tab 0.1 @tab 0.11 @tab 0.2 @tab 0.1 @tab 0.11 @tab 0.26 @tab 0.06
+ at item error2 @tab 0.08 @tab 0.13 @tab 0.24 @tab 0.08 @tab 0.14 @tab 0.34 @tab 0.07
+ at item export @tab 0.25 @tab 0.53 @tab 0.67 @tab 0.2 @tab 0.52 @tab 0.72 @tab 0.14
+ at item fall @tab 0.06 @tab 0.07 @tab 0.15 @tab 0.07 @tab 0.07 @tab 0.17 @tab 0.06
+ at item fexport @tab 3.7 @tab 3.72 @tab 4.62 @tab 1.82 @tab 1.87 @tab 2.71 @tab 2.67
+ at item fit @tab 0.1 @tab 0.1 @tab 0.15 @tab 0.09 @tab 0.09 @tab 0.18 @tab 0.06
+ at item flow @tab 0.35 @tab 0.36 @tab 0.56 @tab 0.29 @tab 0.29 @tab 0.53 @tab 0.27
+ at item fog @tab 0.08 @tab 0.28 @tab 0.35 @tab 0.07 @tab 0.4 @tab 0.51 @tab 0.05
+ at item fonts @tab 2.34 @tab 2.31 @tab 2.34 @tab 2.3 @tab 2.29 @tab 2.29 @tab 2.2
+ at item grad @tab 0.11 @tab 0.37 @tab 0.55 @tab 0.1 @tab 0.4 @tab 0.6 @tab 0.08
+ at item hist @tab 0.29 @tab 0.32 @tab 0.4 @tab 0.32 @tab 0.34 @tab 0.46 @tab 0.08
+ at item inplot @tab 0.11 @tab 0.11 @tab 0.17 @tab 0.11 @tab 0.1 @tab 0.27 @tab 0.07
+ at item label @tab 0.09 @tab 0.08 @tab 0.13 @tab 0.09 @tab 0.08 @tab 0.18 @tab 0.05
+ at item legend @tab 0.23 @tab 0.28 @tab 0.44 @tab 0.17 @tab 0.26 @tab 0.47 @tab 0.06
+ at item light @tab 0.56 @tab 0.56 @tab 0.6 @tab 0.57 @tab 0.57 @tab 0.59 @tab 0.57
+ at item loglog @tab 0.19 @tab 0.19 @tab 0.28 @tab 0.15 @tab 0.15 @tab 0.27 @tab 0.12
+ at item map @tab 0.09 @tab 0.21 @tab 0.31 @tab 0.09 @tab 0.23 @tab 0.39 @tab 0.06
+ at item mark @tab 0.09 @tab 0.08 @tab 0.14 @tab 0.08 @tab 0.07 @tab 0.15 @tab 0.05
+ at item mask @tab 0.12 @tab 0.31 @tab 0.33 @tab 0.11 @tab 0.29 @tab 0.37 @tab 0.06
+ at item mesh @tab 0.08 @tab 0.07 @tab 0.19 @tab 0.07 @tab 0.07 @tab 0.23 @tab 0.05
+ at item mirror @tab 0.19 @tab 0.26 @tab 0.38 @tab 0.12 @tab 0.24 @tab 0.43 @tab 0.07
+ at item molecule @tab 0.15 @tab 0.32 @tab 0.41 @tab 0.07 @tab 0.21 @tab 0.28 @tab 0.06
+ at item param1 @tab 0.33 @tab 0.47 @tab 0.61 @tab 0.19 @tab 0.33 @tab 0.69 @tab 0.11
+ at item param2 @tab 0.7 @tab 0.97 @tab 1.11 @tab 0.32 @tab 0.76 @tab 0.96 @tab 0.27
+ at item param3 @tab 3.08 @tab 3.95 @tab 4.16 @tab 1.7 @tab 2.87 @tab 3.22 @tab 1.53
+ at item paramv @tab 5.05 @tab 4.86 @tab 5.15 @tab 1.3 @tab 1.61 @tab 1.67 @tab 1.3
+ at item parser @tab 0.09 @tab 0.09 @tab 0.17 @tab 0.09 @tab 0.08 @tab 0.24 @tab 0.06
+ at item pde @tab 2.2 @tab 2.44 @tab 2.54 @tab 2.1 @tab 2.39 @tab 2.51 @tab 2.06
+ at item pipe @tab 4.83 @tab 3.58 @tab 3.6 @tab 0.89 @tab 1.6 @tab 1.64 @tab 0.69
+ at item plot @tab 0.12 @tab 0.12 @tab 0.2 @tab 0.11 @tab 0.11 @tab 0.22 @tab 0.06
+ at item primitives @tab 0.16 @tab 0.46 @tab 0.63 @tab 0.14 @tab 0.45 @tab 0.59 @tab 0.06
+ at item projection @tab 0.22 @tab 0.35 @tab 0.57 @tab 0.13 @tab 0.3 @tab 0.66 @tab 0.09
+ at item projection5 @tab 0.22 @tab 0.29 @tab 0.52 @tab 0.14 @tab 0.24 @tab 0.54 @tab 0.09
+ at item qo2d @tab 0.67 @tab 0.91 @tab 1.11 @tab 0.65 @tab 0.86 @tab 1.02 @tab 0.57
+ at item radar @tab 0.07 @tab 0.07 @tab 0.12 @tab 0.07 @tab 0.07 @tab 0.13 @tab 0.05
+ at item refill @tab 0.06 @tab 0.06 @tab 0.11 @tab 0.07 @tab 0.06 @tab 0.16 @tab 0.06
+ at item region @tab 0.09 @tab 0.22 @tab 0.36 @tab 0.1 @tab 0.18 @tab 0.36 @tab 0.05
+ at item schemes @tab 0.18 @tab 0.39 @tab 0.53 @tab 0.19 @tab 0.39 @tab 0.57 @tab 0.07
+ at item several_light @tab 0.11 @tab 0.44 @tab 0.52 @tab 0.08 @tab 0.6 @tab 0.71 @tab 0.05
+ at item solve @tab 0.12 @tab 0.13 @tab 0.27 @tab 0.12 @tab 0.12 @tab 0.34 @tab 0.06
+ at item stem @tab 0.08 @tab 0.08 @tab 0.18 @tab 0.09 @tab 0.09 @tab 0.23 @tab 0.05
+ at item step @tab 0.09 @tab 0.1 @tab 0.16 @tab 0.1 @tab 0.1 @tab 0.18 @tab 0.06
+ at item stereo @tab 0.11 @tab 0.27 @tab 0.36 @tab 0.07 @tab 0.4 @tab 0.52 @tab 0.06
+ at item stfa @tab 0.12 @tab 0.21 @tab 0.47 @tab 0.11 @tab 0.24 @tab 0.42 @tab 0.06
+ at item style @tab 0.24 @tab 0.29 @tab 0.43 @tab 0.18 @tab 0.39 @tab 0.8 @tab 0.07
+ at item surf @tab 0.22 @tab 0.39 @tab 0.49 @tab 0.15 @tab 0.38 @tab 0.53 @tab 0.07
+ at item surf3 @tab 2.85 @tab 2.76 @tab 3.93 @tab 2.47 @tab 2.66 @tab 4.14 @tab 0.64
+ at item surf3a @tab 0.68 @tab 0.77 @tab 0.89 @tab 0.34 @tab 1.25 @tab 1.46 @tab 0.23
+ at item surf3c @tab 0.68 @tab 0.75 @tab 0.87 @tab 0.34 @tab 1.24 @tab 1.47 @tab 0.23
+ at item surfa @tab 0.09 @tab 0.25 @tab 0.33 @tab 0.07 @tab 0.37 @tab 0.48 @tab 0.05
+ at item surfc @tab 0.08 @tab 0.25 @tab 0.34 @tab 0.08 @tab 0.36 @tab 0.47 @tab 0.06
+ at item table @tab 0.28 @tab 0.29 @tab 0.44 @tab 0.12 @tab 0.1 @tab 0.23 @tab 0.07
+ at item tape @tab 0.1 @tab 0.15 @tab 0.22 @tab 0.1 @tab 0.16 @tab 0.27 @tab 0.06
+ at item tens @tab 0.08 @tab 0.08 @tab 0.14 @tab 0.09 @tab 0.09 @tab 0.18 @tab 0.06
+ at item ternary @tab 0.21 @tab 0.28 @tab 0.46 @tab 0.17 @tab 0.3 @tab 0.63 @tab 0.08
+ at item text @tab 0.2 @tab 0.2 @tab 0.31 @tab 0.1 @tab 0.11 @tab 0.22 @tab 0.06
+ at item text2 @tab 0.16 @tab 0.15 @tab 0.26 @tab 0.12 @tab 0.11 @tab 0.24 @tab 0.06
+ at item textmark @tab 0.11 @tab 0.12 @tab 0.2 @tab 0.09 @tab 0.09 @tab 0.23 @tab 0.06
+ at item ticks @tab 0.16 @tab 0.16 @tab 0.27 @tab 0.14 @tab 0.15 @tab 0.28 @tab 0.06
+ at item tile @tab 0.07 @tab 0.14 @tab 0.23 @tab 0.07 @tab 0.15 @tab 0.29 @tab 0.05
+ at item tiles @tab 0.08 @tab 0.19 @tab 0.26 @tab 0.08 @tab 0.18 @tab 0.27 @tab 0.05
+ at item torus @tab 0.2 @tab 0.48 @tab 0.69 @tab 0.11 @tab 0.32 @tab 0.5 @tab 0.08
+ at item traj @tab 0.06 @tab 0.07 @tab 0.13 @tab 0.06 @tab 0.06 @tab 0.17 @tab 0.06
+ at item triangulation @tab 0.09 @tab 0.23 @tab 0.34 @tab 0.08 @tab 0.27 @tab 0.44 @tab 0.05
+ at item triplot @tab 0.08 @tab 0.59 @tab 0.77 @tab 0.08 @tab 0.64 @tab 0.83 @tab 0.05
+ at item tube @tab 0.16 @tab 0.47 @tab 0.65 @tab 0.12 @tab 0.34 @tab 0.49 @tab 0.08
+ at item type0 @tab 0.31 @tab 0.77 @tab 0.92 @tab 0.15 @tab 0.68 @tab 0.87 @tab 0.12
+ at item type1 @tab 0.31 @tab 0.76 @tab 0.94 @tab 0.16 @tab 0.67 @tab 0.86 @tab 0.12
+ at item type2 @tab 0.31 @tab 0.75 @tab 0.94 @tab 0.16 @tab 0.67 @tab 0.85 @tab 0.14
+ at item vect @tab 0.15 @tab 0.15 @tab 0.31 @tab 0.12 @tab 0.12 @tab 0.34 @tab 0.08
+ at item vecta @tab 0.08 @tab 0.08 @tab 0.16 @tab 0.09 @tab 0.08 @tab 0.24 @tab 0.06
+ at item venn @tab 0.07 @tab 0.39 @tab 0.54 @tab 0.06 @tab 0.47 @tab 0.65 @tab 0.04
+ at end multitable
diff --git a/texinfo/title.html b/texinfo/title.html
deleted file mode 100644
index ae5db3d..0000000
--- a/texinfo/title.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<html>
-<head>
-  <meta content="text/html; charset=utf-8" http-equiv="content-type">
-  <title>MathGL 2.0</title>
-</head><body>
-
-<h2><a target="main" href="web_en/web_en_1.html"><img border="0" align="left" hspace="30" vspace="0" src="emblem_sm.png"></a> MathGL – library for scientific data visualization</h2>
-
-</body>
diff --git a/texinfo/toc_en.html b/texinfo/toc_en.html
deleted file mode 100644
index b5237ee..0000000
--- a/texinfo/toc_en.html
+++ /dev/null
@@ -1,44 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<html>
-<head>
-  <meta content="text/html; charset=utf-8" http-equiv="content-type">
-  <title>MathGL 2.0</title>
-</head><body>
-
-<a target="main" href="doc_en/doc_en_2.html"><b>Main page</b></a></p>
-<a target="main" href="doc_en/doc_en_3.html"><b>News</b></a></p>
-<a target="main" href="doc_en/doc_en_4.html"><b>Features</b></a></p>
-<a target="main" href="doc_en/doc_en_5.html"><b>Pictures</b></a></p>
-<a target="main" href="json.html"><b>JS samples</b></a></p>
-<a target="main" href="doc_en/doc_en_6.html"><b>Download</b></a></p>
-<a target="main" href="doc_en/doc_en_toc.html"><b>Documentation</b></a></p>
-<a target="main" href="doc_en/doc_en_7.html"><b>Other projects</b></a></p>
-
-<hr style="width: 100%; height: 1px;">
-<g:plusone></g:plusone>
-<p><table style="background-color: #fff; padding: 5px;" cellspacing=0>
-  <tr><td>
-  <img src="http://groups.google.com/intl/en/images/logos/groups_logo_sm.gif"
-         height=25 width=117 alt="Google Groups">
-  </td></tr>
-  <tr><td style="padding-left: 5px;font-size: 110%">
-  <b>MathGL</b>
-  </td></tr>
-  <tr><td style="padding-left: 5px">
-  <a target=_blank href="http://groups.google.com/group/mathgl">Visit this group</a>
-  </td></tr>
-</table></p>
-
-<hr style="width: 100%; height: 1px;">
-<script type="text/javascript"><!--
-google_ad_client = "ca-pub-1128070552722622";
-/* Vertical small */
-google_ad_slot = "5501954624";
-google_ad_width = 120;
-google_ad_height = 240;
-//-->
-</script>
-<script type="text/javascript"
-src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
-</script>
-</body>
diff --git a/texinfo/toc_fr.html b/texinfo/toc_fr.html
deleted file mode 100644
index a0e2556..0000000
--- a/texinfo/toc_fr.html
+++ /dev/null
@@ -1,45 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<html>
-<head>
-  <meta content="text/html; charset=utf-8" http-equiv="content-type">
-  <title>MathGL 2.0</title>
-</head><body>
-
-<a target="main" href="doc_en/doc_en_2.html"><b>Main page</b></a></p>
-<a target="main" href="doc_en/doc_en_3.html"><b>News</b></a></p>
-<a target="main" href="doc_en/doc_en_4.html"><b>Features</b></a></p>
-<a target="main" href="doc_en/doc_en_5.html"><b>Pictures</b></a></p>
-<a target="main" href="json.html"><b>JS samples</b></a></p>
-<a target="main" href="doc_en/doc_en_6.html"><b>Download</b></a></p>
-<a target="main" href="doc_en/doc_en_toc.html"><b>Documentation</b></a></p>
-<a target="main" href="doc_en/doc_en_7.html"><b>Other projects</b></a></p>
-
-<hr style="width: 100%; height: 1px;">
-<g:plusone></g:plusone>
-<p><table style="background-color: #fff; padding: 5px;" cellspacing=0>
-  <tr><td>
-  <img src="http://groups.google.com/intl/en/images/logos/groups_logo_sm.gif"
-         height=25 width=117 alt="Google Groups">
-  </td></tr>
-  <tr><td style="padding-left: 5px;font-size: 110%">
-  <b>MathGL</b>
-  </td></tr>
-  <tr><td style="padding-left: 5px">
-  <a href="http://groups.google.com/group/mathgl">Visit this group</a>
-  </td></tr>
-</table></p>
-
-<hr style="width: 100%; height: 1px;">
-<script type="text/javascript"><!--
-google_ad_client = "ca-pub-1128070552722622";
-/* Vertical small */
-google_ad_slot = "5501954624";
-google_ad_width = 120;
-google_ad_height = 240;
-//-->
-</script>
-<script type="text/javascript"
-src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
-</script>
-
-</body>
diff --git a/texinfo/toc_ru.html b/texinfo/toc_ru.html
deleted file mode 100644
index 9722049..0000000
--- a/texinfo/toc_ru.html
+++ /dev/null
@@ -1,54 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<html>
-<head>
-  <meta content="text/html; charset=utf-8" http-equiv="content-type">
-  <title>MathGL 2.0</title>
-</head><body>
-
-<a target="main" href="doc_en/doc_en_2.html"><b>Main page</b></a></p>
-<a target="main" href="doc_en/doc_en_3.html"><b>News</b></a></p>
-<a target="main" href="doc_en/doc_en_4.html"><b>Features</b></a></p>
-<a target="main" href="doc_en/doc_en_5.html"><b>Pictures</b></a></p>
-<a target="main" href="json.html"><b>JS samples</b></a></p>
-<a target="main" href="doc_en/doc_en_6.html"><b>Download</b></a></p>
-<a target="main" href="doc_en/doc_en_toc.html"><b>Documentation</b></a></p>
-<a target="main" href="doc_en/doc_en_7.html"><b>Other projects</b></a></p>
-
-
-<a target="main" href="doc_ru/doc_ru_2.html"><b>Main page</b></a></p>
-<a target="main" href="doc_ru/doc_ru_3.html"><b>Новости</b></a></p>
-<a target="main" href="doc_ru/doc_ru_4.html"><b>Возможности</b></a></p>
-<a target="main" href="doc_ru/doc_ru_5.html"><b>Примеры</b></a></p>
-<a target="main" href="json.html"><b>JS примеры</b></a></p>
-<a target="main" href="doc_ru/doc_ru_6.html"><b>Загрузка</b></a></p>
-<a target="main" href="doc_ru/doc_ru_toc.html"><b>Документация</b></a></p>
-<a target="main" href="doc_ru/doc_ru_7.html"><b>Другие проекты</b></a></p>
-
-<hr style="width: 100%; height: 1px;">
-<g:plusone></g:plusone>
-<p><table style="background-color: #fff; padding: 5px;" cellspacing=0>
-  <tr><td>
-  <img src="http://groups.google.com/intl/en/images/logos/groups_logo_sm.gif"
-         height=25 width=117 alt="Google Groups">
-  </td></tr>
-  <tr><td style="padding-left: 5px;font-size: 110%">
-  <b>MathGL</b>
-  </td></tr>
-  <tr><td style="padding-left: 5px">
-  <a href="http://groups.google.com/group/mathgl">Visit this group</a>
-  </td></tr>
-</table></p>
-
-<hr style="width: 100%; height: 1px;">
-<script type="text/javascript"><!--
-google_ad_client = "ca-pub-1128070552722622";
-/* Vertical small */
-google_ad_slot = "5501954624";
-google_ad_width = 120;
-google_ad_height = 240;
-//-->
-</script>
-<script type="text/javascript"
-src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
-</script>
-</body>
diff --git a/texinfo/udav_en.texi b/texinfo/udav_en.texi
index 0100609..99a5d12 100644
--- a/texinfo/udav_en.texi
+++ b/texinfo/udav_en.texi
@@ -1,4 +1,5 @@
 @chapter UDAV
+ at nav{}
 
 UDAV (Universal Data Array Visualizator) is cross-platform program for data arrays visualization based on MathGL library. It support wide spectrum of graphics, simple script language and visual data handling and editing. It has window interface for data viewing, changing and plotting. Also it can execute MGL scripts, setup and rotate graphics and so on. UDAV hot-keys can be found in the appendix @ref{Hot-keys for UDAV}.
 
@@ -12,6 +13,7 @@ UDAV (Universal Data Array Visualizator) is cross-platform program for data arra
 @external{}
 @node UDAV overview, UDAV dialogs, , UDAV
 @section UDAV overview
+ at nav{}
 
 UDAV have main window divided by 2 parts in general case and optional bottom panel(s). Left side contain tabs for MGL script and data arrays. Right side contain tabs with graphics itself, with list of variables and with help on MGL. Bottom side may contain the panel with MGL messages and warnings, and the panel with calculator.
 
@@ -49,6 +51,7 @@ Finally, pressing @key{F2} or @key{F4} you can show/hide windows with messages/w
 @external{}
 @node UDAV dialogs, UDAV hints, UDAV overview, UDAV
 @section UDAV dialogs
+ at nav{}
 
 There are a set of dialogs, which allow change/add a command, setup global plot properties, or setup UDAV itself.
 
@@ -89,6 +92,7 @@ There are also a set of dialogs for data handling, but they are too simple and c
 @external{}
 @node UDAV hints, , UDAV dialogs, UDAV
 @section UDAV hints
+ at nav{}
 
 @itemize
 @item
@@ -130,3 +134,5 @@ The special dialog (Edit|Insert|New Command) help you select the command, fill i
 @item
 You can put several plotting commands in the same line or in separate function, for highlighting all of them simultaneously.
 @end itemize
+
+ at external{}
\ No newline at end of file
diff --git a/texinfo/udav_ru.texi b/texinfo/udav_ru.texi
index 0100609..99a5d12 100644
--- a/texinfo/udav_ru.texi
+++ b/texinfo/udav_ru.texi
@@ -1,4 +1,5 @@
 @chapter UDAV
+ at nav{}
 
 UDAV (Universal Data Array Visualizator) is cross-platform program for data arrays visualization based on MathGL library. It support wide spectrum of graphics, simple script language and visual data handling and editing. It has window interface for data viewing, changing and plotting. Also it can execute MGL scripts, setup and rotate graphics and so on. UDAV hot-keys can be found in the appendix @ref{Hot-keys for UDAV}.
 
@@ -12,6 +13,7 @@ UDAV (Universal Data Array Visualizator) is cross-platform program for data arra
 @external{}
 @node UDAV overview, UDAV dialogs, , UDAV
 @section UDAV overview
+ at nav{}
 
 UDAV have main window divided by 2 parts in general case and optional bottom panel(s). Left side contain tabs for MGL script and data arrays. Right side contain tabs with graphics itself, with list of variables and with help on MGL. Bottom side may contain the panel with MGL messages and warnings, and the panel with calculator.
 
@@ -49,6 +51,7 @@ Finally, pressing @key{F2} or @key{F4} you can show/hide windows with messages/w
 @external{}
 @node UDAV dialogs, UDAV hints, UDAV overview, UDAV
 @section UDAV dialogs
+ at nav{}
 
 There are a set of dialogs, which allow change/add a command, setup global plot properties, or setup UDAV itself.
 
@@ -89,6 +92,7 @@ There are also a set of dialogs for data handling, but they are too simple and c
 @external{}
 @node UDAV hints, , UDAV dialogs, UDAV
 @section UDAV hints
+ at nav{}
 
 @itemize
 @item
@@ -130,3 +134,5 @@ The special dialog (Edit|Insert|New Command) help you select the command, fill i
 @item
 You can put several plotting commands in the same line or in separate function, for highlighting all of them simultaneously.
 @end itemize
+
+ at external{}
\ No newline at end of file
diff --git a/texinfo/version.texi b/texinfo/version.texi
new file mode 100644
index 0000000..86de6a9
--- /dev/null
+++ b/texinfo/version.texi
@@ -0,0 +1,2 @@
+ at set VERSION 2.2.0
+ at set MINVER .1
diff --git a/texinfo/web_en.texi b/texinfo/web_en.texi
index bd1dd45..60aac3e 100644
--- a/texinfo/web_en.texi
+++ b/texinfo/web_en.texi
@@ -1,5 +1,6 @@
 @c ------------------------------------------------------------------
 @chapter Website
+ at nav{}
 
 @menu
 * Main::
@@ -11,12 +12,15 @@
 * Other projects::
 @end menu
 
+ at external{}
+
 @node Main, News, , Website
 @section MathGL is ...
+ at nav{}
 
 @ifhtml
 @html
-<a href="surf_cont_fog.html"><img border="0" align="right" hspace="30" vspace="20" alt="Surface in fog" src="../surf_cont_fog_g.png"></a>
+<a href="Adding-fog.html"><img border="0" align="right" hspace="30" vspace="20" alt="Surface in fog" src="../small/fog-sm.png"></a>
 @end html
 @end ifhtml
 @itemize @bullet
@@ -48,6 +52,13 @@ Generally MathGL is GPL library. However, you can use LGPL license for MathGL co
 
 @strong{Latest news}
 @itemize
+ at item @emph{16 May 2013.}
+Update documentation and add Russian @uref{../doc_ru/doc_ru_toc.html, translation} for chapters 4-8.
+ at item @emph{16 May 2013.}
+New version (v.1.4.4) of @uref{http://sourceforge.net/projects/mathgl/files/u3d-1.4.4.tar.gz, U3D} is released. Main changes are: disable use of assembler, fix warnings, update cmake,
+update jpeg, png and zlib libraries.
+ at item @emph{8 May 2013.}
+New version (v. at value{VERSION}@value{MINVER}) of @uref{http://sourceforge.net/projects/mathgl, MathGL} is released. There are minor bugfixes for cmake options enable-double=OFF, enable-zlib=OFF and enable mouse actions in @uref{../json.html, JS sample} for Firefox.
 @item @emph{2 May 2013.}
 New version (v. at value{VERSION}) of @uref{http://sourceforge.net/projects/mathgl, MathGL} is released. There are minor bugfixes and improvements, which denoted @ref{News, here}.
 @item @emph{13 December 2012.}
@@ -62,15 +73,60 @@ There is detailed @ref{News, news list}. Sourceforge project page @uref{http://s
 <a href="http://www.datadvance.net"><img border="0" align="right" hspace="10" alt="$DATADVANCE" src="../datadvance.png"></a>
 @end html
 @end ifhtml
-Javascript interface was developed with support of @url{www.datadvance.net, $DATADVANCE} company.
+Javascript interface was developed with support of @url{http://www.datadvance.net, $DATADVANCE} company.
 
 @external{}
 
 @node News, Features, Main, Website
 @section News
+ at nav{}
 
 @itemize
 @item
+ at strong{11 November 2013.}
+New version (v.2.2) of @uref{http://sourceforge.net/projects/mathgl, MathGL} is released. There are minor bugfixes and improvements:
+ at itemize @bullet
+ at item Add OpenMP calls mostly everywhere (can work as replacement of pthreads - a bit faster since more loops is parallelized).
+ at item Greatly speed up consequent FFT and Hankel transforms. Add mgl_clear_fft() function for manual clearing of saved FFT/Hankel data.
+ at item Add @ref{ohlc} plot for drawing Open-High-Low-Close diagram
+ at item Add wxMathGL widget. See @ref{wxMathGL class}.
+ at item Add interface for Lua v.5.1.
+ at item Add @ref{mask} for face drawing if one of symbols @samp{-+=;oOsS~<>jdD*^} is specified in color scheme. This work only for export in bitmap images.
+ at item Add @ref{quality}=8 for dots drawing (extremely fast).
+ at item Add styles '4','6','8' for @ref{cone} and @ref{cones} to produce square, hex-, octo-prism.
+ at item Add style 't' for @ref{cones} to produce tubes (cylinders).
+ at item Add style '^' for @ref{legend} to left/right align legend if its coordinates are right/left from the center
+ at item Add style '<', '^', '>' for aligning/centering boxes in @ref{bars}, @ref{barh}, @ref{boxplot}, @ref{cones}. Also this plots become centered by default if nx sizes are the same for all data.
+ at item Add @ref{dots} function which set independently both color and transparency of dots.
+ at item Improve automatic axis position. Add style '^' for inverse automatic axis position.
+ at item Improve tick labeling. Add style @ref{tuneticks}&4 for zero filling of tick labels.
+ at item Add @ref{refill} for filling by interpolation of parametrically dependent data
+ at item Add transparency for @ref{area} and @ref{region} plots.
+ at item Add mgl_clf_chr() function and extend @ref{clf} command.
+ at item Fourier now perform true inverse Fourier transform (instead of backward one).
+ at item Improve/change lighting from local sources. Add @ref{diffuse} function.
+ at item C functions now return NULL if HMDT data cannot be created for given input argument(s).
+ at item Enable line width for @ref{mesh} and @ref{fall} plots.
+ at item Replace +INF and -INF by NAN in textual formula output.
+ at item Add manual compression of JSON.
+ at item Define WORDS_BIGENDIAN and HAVE_MEMRCHR (thanks to Dinar Valeev).
+ at item Bugfix for cleaning unused points.
+ at item Fix 'setsize' command at UDAV starting.
+ at item Rewrite MGL parsing by using std::wstring for avoiding possible bugs of wcs*() functions.
+ at item Minor bugfixes.
+ at item Update docs.
+ at end itemize
+
+ at item
+ at strong{8 May 2013.}
+New version (v.2.1.3.1) of @uref{http://sourceforge.net/projects/mathgl, MathGL} is released. There are minor bugfixes and improvements:
+ at itemize @bullet
+ at item Compatibility changes for MS VS.
+ at item Bugfixes for cmake options @code{enable-double=OFF, enable-zlib=OFF}.
+ at item Enable mouse actions for Firefox in JS sample.
+ at end itemize
+
+ at item
 @strong{2 May 2013.}
 New version (v.2.1.3) of @uref{http://sourceforge.net/projects/mathgl, MathGL} is released. There are minor bugfixes and improvements:
 @itemize @bullet
@@ -274,6 +330,7 @@ Different bugfixes.
 
 @node Features, Pictures, News, Website
 @section Features
+ at nav{}
 
 MathGL can plot a wide range of graphics. It includes:
 @itemize @bullet
@@ -307,11 +364,12 @@ There is fast evaluation of a textual mathematical expression. It is based on st
 
 @node Pictures, Download, Features, Website
 @section Pictures
+ at nav{}
 
 There are samples for @ref{1D data plotting, 1D arrays}, @ref{2D data plotting, 2D arrays}, @ref{3D data plotting, 3D arrays}, @ref{Vector fields plotting} and some @ref{Extra samples}.
 
 @anchor{1D data plotting}
- at subsection Examples of graphics for 1d arrays
+ at subheading Examples of graphics for 1d arrays
 
 @sfig{plot, Plot sample}
 @sfig{radar, Radar sample}
@@ -339,7 +397,7 @@ There are samples for @ref{1D data plotting, 1D arrays}, @ref{2D data plotting,
 @sfig{label,Label sample}
 
 @anchor{2D data plotting}
- at subsection Examples of graphics for 2d arrays
+ at subheading Examples of graphics for 2d arrays
 
 @sfig{surf, Surf sample}
 @sfig{surfc,SurfC sample}
@@ -362,7 +420,7 @@ There are samples for @ref{1D data plotting, 1D arrays}, @ref{2D data plotting,
 @sfig{contv,ContV sample}
 
 @anchor{3D data plotting}
- at subsection Examples of graphics for 3d arrays
+ at subheading Examples of graphics for 3d arrays
 
 @sfig{surf3, Surf3 sample}
 @sfig{surf3c,Surf3C sample}
@@ -380,7 +438,7 @@ There are samples for @ref{1D data plotting, 1D arrays}, @ref{2D data plotting,
 @sfig{triplot, TriPlot and QuadPlot}
 
 @anchor{Vector fields plotting}
- at subsection Examples of graphics for vector fields
+ at subheading Examples of graphics for vector fields
 
 @sfig{vect, Vect sample}
 @sfig{vecta,Vect3 sample}
@@ -391,7 +449,7 @@ There are samples for @ref{1D data plotting, 1D arrays}, @ref{2D data plotting,
 @sfig{dew, Dew sample}
 
 @anchor{Extra samples}
- at subsection Examples of additional features
+ at subheading Examples of additional features
 
 @sfig{inplot, Subplots}
 @sfig{axis, Axis and ticks}
@@ -414,7 +472,7 @@ There are samples for @ref{1D data plotting, 1D arrays}, @ref{2D data plotting,
 @sfig{fog, Adding fog}
 
 @sfig{combined, ``Compound'' graphics}
- at sfig{several_light, Several light sources}
+ at sfig{several_light, Lighting sample}
 @sfig{stereo, Stereo image}
 @sfig{primitives, Using primitives}
 
@@ -424,7 +482,7 @@ There are samples for @ref{1D data plotting, 1D arrays}, @ref{2D data plotting,
 @sfig{map, Mapping visualization}
 
 @sfig{hist, Making histogram}
- at sfig{fit, Nonlinear fitting sample}
+ at sfig{fit, Nonlinear fitting hints}
 @sfig{pde, PDE solving hints}
 @sfig{parser, MGL parser using}
 
@@ -432,13 +490,14 @@ There are samples for @ref{1D data plotting, 1D arrays}, @ref{2D data plotting,
 
 @node Download, Other projects, Pictures, Website
 @section Download
+ at nav{}
 
 @strong{Stable version (v. at value{VERSION})}
 
 You may download current version of MathGL for following configurations:
 @itemize @bullet
 @item
- at uref{http://downloads.sourceforge.net/mathgl/mathgl-@value{VERSION}.tar.gz,source} file with cmake build system.
+ at uref{http://downloads.sourceforge.net/mathgl/mathgl-@value{VERSION}@value{MINVER}.tar.gz,source} file with cmake build system.
 @item
 @uref{http://downloads.sourceforge.net/mathgl/mathgl-@value{VERSION}-mingw.i686.7z,Win32 GPL} binaries for MinGW (build for i686)
 @item
@@ -485,6 +544,7 @@ There are a set of @uref{http://sourceforge.net/project/showfiles.php?group_id=1
 
 @node Other projects, , Download, Website
 @section Other projects
+ at nav{}
 
 Except scientific (non public) projects I also have some general interest projects:
 @itemize @bullet
diff --git a/texinfo/web_fr.texi b/texinfo/web_fr.texi
index 8120720..bcf7f7e 100644
--- a/texinfo/web_fr.texi
+++ b/texinfo/web_fr.texi
@@ -1,6 +1,6 @@
 \input texinfo
 @setfilename mgl_web_en.info
- at set VERSION 2.1.2
+ at include version.texi
 @settitle MathGL @value{VERSION}
 @syncodeindex pg cp
 @comment %**end of header
@@ -139,7 +139,7 @@ There is detailed @ref{News, news list}. Sourceforge project page @uref{http://s
 <a href="http://www.datadvance.net"><img border="0" align="right" hspace="10" alt="$DATADVANCE" src="../datadvance.png"></a>
 @end html
 @end ifhtml
-Javascript interface was developed with support of @url{www.datadvance.net, $DATADVANCE} company.
+Javascript interface was developed with support of @url{http://www.datadvance.net, $DATADVANCE} company.
 
 @external{}
 
diff --git a/texinfo/web_ru.texi b/texinfo/web_ru.texi
index bd1dd45..f30c873 100644
--- a/texinfo/web_ru.texi
+++ b/texinfo/web_ru.texi
@@ -1,5 +1,6 @@
 @c ------------------------------------------------------------------
 @chapter Website
+ at nav{}
 
 @menu
 * Main::
@@ -11,12 +12,15 @@
 * Other projects::
 @end menu
 
+ at external{}
+
 @node Main, News, , Website
 @section MathGL is ...
+ at nav{}
 
 @ifhtml
 @html
-<a href="surf_cont_fog.html"><img border="0" align="right" hspace="30" vspace="20" alt="Surface in fog" src="../surf_cont_fog_g.png"></a>
+<a href="Adding-fog.html"><img border="0" align="right" hspace="30" vspace="20" alt="Surface in fog" src="../small/fog-sm.png"></a>
 @end html
 @end ifhtml
 @itemize @bullet
@@ -48,6 +52,13 @@ Generally MathGL is GPL library. However, you can use LGPL license for MathGL co
 
 @strong{Latest news}
 @itemize
+ at item @emph{16 May 2013.}
+Update documentation and add Russian @uref{../doc_ru/doc_ru_toc.html, translation} for chapters 4-8.
+ at item @emph{16 May 2013.}
+New version (v.1.4.4) of @uref{http://sourceforge.net/projects/mathgl/files/u3d-1.4.4.tar.gz, U3D} is released. Main changes are: disable use of assembler, fix warnings, update cmake,
+update jpeg, png and zlib libraries.
+ at item @emph{8 May 2013.}
+New version (v. at value{VERSION}@value{MINVER}) of @uref{http://sourceforge.net/projects/mathgl, MathGL} is released. There are minor bugfixes for cmake options enable-double=OFF, enable-zlib=OFF and enable mouse actions in @uref{../json.html, JS sample} for Firefox.
 @item @emph{2 May 2013.}
 New version (v. at value{VERSION}) of @uref{http://sourceforge.net/projects/mathgl, MathGL} is released. There are minor bugfixes and improvements, which denoted @ref{News, here}.
 @item @emph{13 December 2012.}
@@ -62,15 +73,60 @@ There is detailed @ref{News, news list}. Sourceforge project page @uref{http://s
 <a href="http://www.datadvance.net"><img border="0" align="right" hspace="10" alt="$DATADVANCE" src="../datadvance.png"></a>
 @end html
 @end ifhtml
-Javascript interface was developed with support of @url{www.datadvance.net, $DATADVANCE} company.
+Javascript interface was developed with support of @url{http://www.datadvance.net, $DATADVANCE} company.
 
 @external{}
 
 @node News, Features, Main, Website
 @section News
+ at nav{}
 
 @itemize
 @item
+ at strong{11 November 2013.}
+New version (v.2.2) of @uref{http://sourceforge.net/projects/mathgl, MathGL} is released. There are minor bugfixes and improvements:
+ at itemize @bullet
+ at item Add OpenMP calls mostly everywhere (can work as replacement of pthreads - a bit faster since more loops is parallelized).
+ at item Greatly speed up consequent FFT and Hankel transforms. Add mgl_clear_fft() function for manual clearing of saved FFT/Hankel data.
+ at item Add @ref{ohlc} plot for drawing Open-High-Low-Close diagram
+ at item Add wxMathGL widget. See @ref{wxMathGL class}.
+ at item Add interface for Lua v.5.1.
+ at item Add @ref{mask} for face drawing if one of symbols @samp{-+=;oOsS~<>jdD*^} is specified in color scheme. This work only for export in bitmap images.
+ at item Add @ref{quality}=8 for dots drawing (extremely fast).
+ at item Add styles '4','6','8' for @ref{cone} and @ref{cones} to produce square, hex-, octo-prism.
+ at item Add style 't' for @ref{cones} to produce tubes (cylinders).
+ at item Add style '^' for @ref{legend} to left/right align legend if its coordinates are right/left from the center
+ at item Add style '<', '^', '>' for aligning/centering boxes in @ref{bars}, @ref{barh}, @ref{boxplot}, @ref{cones}. Also this plots become centered by default if nx sizes are the same for all data.
+ at item Add @ref{dots} function which set independently both color and alpha of dots.
+ at item Improve automatic axis position. Add style '^' for inverse automatic axis position.
+ at item Improve tick labeling. Add style @ref{tuneticks}&4 for zero filling of tick labels.
+ at item Add @ref{refill} for filling by interpolation of parametrically dependent data
+ at item Add transparency for @ref{area} and @ref{region} plots.
+ at item Add mgl_clf_chr() function and extend @ref{clf} command.
+ at item Fourier now perform true inverse Fourier transform (instead of backward one).
+ at item Improve/change lighting from local sources. Add @ref{diffuse} function.
+ at item C functions now return NULL if HMDT data cannot be created for given input argument(s).
+ at item Enable line width for @ref{mesh} and @ref{fall} plots.
+ at item Replace +INF and -INF by NAN in textual formula output.
+ at item Add manual compression of JSON.
+ at item Define WORDS_BIGENDIAN and HAVE_MEMRCHR (thanks to Dinar Valeev).
+ at item Bugfix for cleaning unused points.
+ at item Fix 'setsize' command at UDAV starting.
+ at item Rewrite MGL parsing by using std::wstring for avoiding possible bugs of wcs*() functions.
+ at item Minor bugfixes.
+ at item Update docs.
+ at end itemize
+
+ at item
+ at strong{8 May 2013.}
+New version (v.2.1.3.1) of @uref{http://sourceforge.net/projects/mathgl, MathGL} is released. There are minor bugfixes and improvements:
+ at itemize @bullet
+ at item Compatibility changes for MS VS.
+ at item Bugfixes for cmake options @code{enable-double=OFF, enable-zlib=OFF}.
+ at item Enable mouse actions for Firefox in JS sample.
+ at end itemize
+
+ at item
 @strong{2 May 2013.}
 New version (v.2.1.3) of @uref{http://sourceforge.net/projects/mathgl, MathGL} is released. There are minor bugfixes and improvements:
 @itemize @bullet
@@ -274,6 +330,7 @@ Different bugfixes.
 
 @node Features, Pictures, News, Website
 @section Features
+ at nav{}
 
 MathGL can plot a wide range of graphics. It includes:
 @itemize @bullet
@@ -307,11 +364,12 @@ There is fast evaluation of a textual mathematical expression. It is based on st
 
 @node Pictures, Download, Features, Website
 @section Pictures
+ at nav{}
 
 There are samples for @ref{1D data plotting, 1D arrays}, @ref{2D data plotting, 2D arrays}, @ref{3D data plotting, 3D arrays}, @ref{Vector fields plotting} and some @ref{Extra samples}.
 
 @anchor{1D data plotting}
- at subsection Examples of graphics for 1d arrays
+ at subheading Examples of graphics for 1d arrays
 
 @sfig{plot, Plot sample}
 @sfig{radar, Radar sample}
@@ -339,7 +397,7 @@ There are samples for @ref{1D data plotting, 1D arrays}, @ref{2D data plotting,
 @sfig{label,Label sample}
 
 @anchor{2D data plotting}
- at subsection Examples of graphics for 2d arrays
+ at subheading Examples of graphics for 2d arrays
 
 @sfig{surf, Surf sample}
 @sfig{surfc,SurfC sample}
@@ -362,7 +420,7 @@ There are samples for @ref{1D data plotting, 1D arrays}, @ref{2D data plotting,
 @sfig{contv,ContV sample}
 
 @anchor{3D data plotting}
- at subsection Examples of graphics for 3d arrays
+ at subheading Examples of graphics for 3d arrays
 
 @sfig{surf3, Surf3 sample}
 @sfig{surf3c,Surf3C sample}
@@ -380,7 +438,7 @@ There are samples for @ref{1D data plotting, 1D arrays}, @ref{2D data plotting,
 @sfig{triplot, TriPlot and QuadPlot}
 
 @anchor{Vector fields plotting}
- at subsection Examples of graphics for vector fields
+ at subheading Examples of graphics for vector fields
 
 @sfig{vect, Vect sample}
 @sfig{vecta,Vect3 sample}
@@ -391,7 +449,7 @@ There are samples for @ref{1D data plotting, 1D arrays}, @ref{2D data plotting,
 @sfig{dew, Dew sample}
 
 @anchor{Extra samples}
- at subsection Examples of additional features
+ at subheading Examples of additional features
 
 @sfig{inplot, Subplots}
 @sfig{axis, Axis and ticks}
@@ -414,7 +472,7 @@ There are samples for @ref{1D data plotting, 1D arrays}, @ref{2D data plotting,
 @sfig{fog, Adding fog}
 
 @sfig{combined, ``Compound'' graphics}
- at sfig{several_light, Several light sources}
+ at sfig{several_light, Lighting sample}
 @sfig{stereo, Stereo image}
 @sfig{primitives, Using primitives}
 
@@ -424,7 +482,7 @@ There are samples for @ref{1D data plotting, 1D arrays}, @ref{2D data plotting,
 @sfig{map, Mapping visualization}
 
 @sfig{hist, Making histogram}
- at sfig{fit, Nonlinear fitting sample}
+ at sfig{fit, Nonlinear fitting hints}
 @sfig{pde, PDE solving hints}
 @sfig{parser, MGL parser using}
 
@@ -432,13 +490,14 @@ There are samples for @ref{1D data plotting, 1D arrays}, @ref{2D data plotting,
 
 @node Download, Other projects, Pictures, Website
 @section Download
+ at nav{}
 
 @strong{Stable version (v. at value{VERSION})}
 
 You may download current version of MathGL for following configurations:
 @itemize @bullet
 @item
- at uref{http://downloads.sourceforge.net/mathgl/mathgl-@value{VERSION}.tar.gz,source} file with cmake build system.
+ at uref{http://downloads.sourceforge.net/mathgl/mathgl-@value{VERSION}@value{MINVER}.tar.gz,source} file with cmake build system.
 @item
 @uref{http://downloads.sourceforge.net/mathgl/mathgl-@value{VERSION}-mingw.i686.7z,Win32 GPL} binaries for MinGW (build for i686)
 @item
@@ -485,6 +544,7 @@ There are a set of @uref{http://sourceforge.net/project/showfiles.php?group_id=1
 
 @node Other projects, , Download, Website
 @section Other projects
+ at nav{}
 
 Except scientific (non public) projects I also have some general interest projects:
 @itemize @bullet
diff --git a/texinfo/widget_en.texi b/texinfo/widget_en.texi
index 9880938..faa187b 100644
--- a/texinfo/widget_en.texi
+++ b/texinfo/widget_en.texi
@@ -1,6 +1,7 @@
 
 @c ------------------------------------------------------------------
 @chapter Widget classes
+ at nav{}
 @cindex mglWindow
 @cindex mglGLUT
 @cindex Fl_MathGL
@@ -25,6 +26,7 @@ You should inherit yours class from @code{mglDraw} and re-implement one or both
 * mglWindow class::
 * Fl_MathGL class::
 * QMathGL class::
+* wxMathGL class::
 @end menu
 
 
@@ -32,11 +34,12 @@ You should inherit yours class from @code{mglDraw} and re-implement one or both
 @external{}
 @node mglWindow class, Fl_MathGL class, , Widget classes
 @section mglWindow class
+ at nav{}
 @cindex mglWindow
 @cindex window
 @c @cindex mglDraw
 
-This class is derived from mglGraph class (see @ref{MathGL core}). It is defined in @code{#include <mgl2/window.h>}. It provide methods for handling window with MathGL graphics. Similar classes are exist for each widget library: @code{mglQT} in @code{#include <mgl2/qt.h>}, @code{mglFLTK} in @code{#include <mgl2/fltk.h>}, @code{mglWX} in @code{#include <mgl2/wx.h>}.
+This class is derived from mglGraph class (see @ref{MathGL core}). It is defined in @code{#include <mgl2/window.h>} and provide methods for handling window with MathGL graphics. Similar classes are exist for QT and FLTK widget libraries: @code{mglQT} in @code{#include <mgl2/qt.h>}, @code{mglFLTK} in @code{#include <mgl2/fltk.h>}.
 
 @deftypefn {Constructor on @code{mglWindow}} {} mglWindow (@code{const char *}title=@code{"MathGL"})
 @deftypefnx {Constructor on @code{mglWindow}} {} mglWindow (@code{int} (*draw)(@code{HMGL} gr, @code{void *}p), @code{const char *}title=@code{"MathGL"}, @code{void *}par=@code{NULL}, @code{int} kind=@code{0}, @code{void} (*reload)(@code{HMGL} gr, @code{void *}p)=0)
@@ -142,6 +145,7 @@ Gets last position of mouse click.
 @external{}
 @node Fl_MathGL class, QMathGL class, mglWindow class, Widget classes
 @section Fl_MathGL class
+ at nav{}
 @cindex Fl_MathGL
 @cindex widgets
 
@@ -180,13 +184,16 @@ Get zoom in/out region
 Set popup menu pointer
 @end deftypemethod
 
- at deftypemethod Fl_MathGL @code{void} set_graph (@code{mglCanvas *}gr)
+ at deftypemethod Fl_MathGL @code{void} set_graph (@code{HMGL} gr)
 @deftypemethodx Fl_MathGL @code{void} set_graph (@code{mglGraph *}gr)
 Set new grapher instead of built-in one. Note that Fl_MathGL will automatically delete this object at destruction or at new @code{set_graph()} call.
 @end deftypemethod
 @deftypemethod Fl_MathGL @code{HMGL} get_graph ()
 Get pointer to grapher.
 @end deftypemethod
+ at deftypemethod Fl_MathGL @code{void} adjust ()
+Adjust image size to fit whole widget.
+ at end deftypemethod
 
 @deftypecv {Fl_MathGL option} Fl_MathGL @code{Fl_Valuator *} tet_val
 Pointer to external tet-angle validator.
@@ -197,8 +204,9 @@ Pointer to external phi-angle validator.
 
 @c ------------------------------------------------------------------
 @external{}
- at node QMathGL class, , Fl_MathGL class, Widget classes
+ at node QMathGL class, wxMathGL class, Fl_MathGL class, Widget classes
 @section QMathGL class
+ at nav{}
 @cindex QMathGL
 @cindex widgets
 
@@ -214,7 +222,7 @@ Sets drawing functions from a class inherited from @code{mglDraw}.
 Sets the drawing function @var{draw}. There is support of a list of plots (frames). So as one can prepare a set of frames at first and redraw it fast later (but it requires more memory). Function should return positive number of frames for the list or zero if it will plot directly. Parameter @var{par} contains pointer to data for the plotting function @var{draw}.
 @end deftypemethod
 
- at deftypemethod QMathGL @code{void} setGraph (@code{mglCanvas *}gr)
+ at deftypemethod QMathGL @code{void} setGraph (@code{HMGL} gr)
 @deftypemethodx QMathGL @code{void} setGraph (@code{mglGraph *}gr)
 Set pointer to external grapher (instead of built-in one). Note that QMathGL will automatically delete this object at destruction or at new @code{setGraph()} call.
 @end deftypemethod
@@ -323,7 +331,7 @@ Shift graphics to left direction.
 @deftypefn {Slot on @code{QMathGL}} @code{void} shiftRight ()
 Shift graphics to right direction.
 @end deftypefn
- at deftypefn {Slot on @code{QMathGL}} @code{void}shiftUp  ()
+ at deftypefn {Slot on @code{QMathGL}} @code{void} shiftUp ()
 Shift graphics to up direction.
 @end deftypefn
 @deftypefn {Slot on @code{QMathGL}} @code{void} shiftDown ()
@@ -447,5 +455,165 @@ Application name for message boxes.
 Allow auto resizing (default is false).
 @end deftypecv
 
+ at c ------------------------------------------------------------------
+ at external{}
+ at node wxMathGL class, , QMathGL class, Widget classes
+ at section wxMathGL class
+ at nav{}
+ at cindex wxMathGL
+ at cindex widgets
+
+Class is WX widget which display MathGL graphics. It is defined in @code{#include <mgl2/wx.h>}.
+
+ at deftypemethod wxMathGL @code{void} SetDraw (@code{mglDraw *}dr)
+Sets drawing functions from a class inherited from @code{mglDraw}.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{void} SetDraw (@code{int (*}draw at code{)(mglBase *}gr, @code{void *}p at code{)}, @code{void *}par=@code{NULL})
+ at deftypemethodx wxMathGL @code{void} SetDraw (@code{int (*}draw at code{)(mglGraph *}gr at code{)})
+Sets the drawing function @var{draw}. There is support of a list of plots (frames). So as one can prepare a set of frames at first and redraw it fast later (but it requires more memory). Function should return positive number of frames for the list or zero if it will plot directly. Parameter @var{par} contains pointer to data for the plotting function @var{draw}.
+ at end deftypemethod
+
+ at deftypemethod wxMathGL @code{void} SetGraph (@code{HMGL} gr)
+ at deftypemethodx wxMathGL @code{void} SetGraph (@code{mglGraph *}gr)
+Set pointer to external grapher (instead of built-in one). Note that wxMathGL will automatically delete this object at destruction or at new @code{setGraph()} call.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{HMGL} GetGraph ()
+Get pointer to grapher.
+ at end deftypemethod
+
+ at deftypemethod wxMathGL @code{void} SetPopup (@code{wxMenu *}p)
+Set popup menu pointer.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{void} SetSize (@code{int} w, @code{int} h)
+Set widget/picture sizes
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{double} GetRatio ()
+Return aspect ratio of the picture.
+ at end deftypemethod
+
+ at deftypemethod wxMathGL @code{int} GetPer ()
+Get perspective value in percents.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{int} GetPhi ()
+Get Phi-angle value in degrees.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{int} GetTet ()
+Get Theta-angle value in degrees.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{bool} GetAlpha ()
+Get transparency state.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{bool} GetLight ()
+Get lightning state.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{bool} GetZoom ()
+Get mouse zooming state.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{bool} GetRotate ()
+Get mouse rotation state.
+ at end deftypemethod
+
+
+ at deftypemethod wxMathGL @code{void} Repaint ()
+Redraw saved bitmap without executing drawing function.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{void} Update ()
+Update picture by executing drawing function.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{void} Copy ()
+Copy graphics to clipboard.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{void} Print ()
+Print current picture.
+ at end deftypemethod
+
+ at comment  @deftypemethod wxMathGL @code{void} Stop ()
+ at comment  Send signal to stop drawing.
+ at comment  @end deftypemethod
+ at deftypemethod wxMathGL @code{void} Adjust ()
+Adjust image size to fit whole widget.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{void} NextSlide ()
+Show next slide.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{void} PrevSlide ()
+Show previous slide.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{void} Animation (@code{bool} st=@code{true})
+Start/stop animation.
+ at end deftypemethod
+
+ at deftypemethod wxMathGL @code{void} SetPer (@code{int} val)
+Set perspective value.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{void} SetPhi (@code{int} val)
+Set Phi-angle value.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{void} SetTet (@code{int} val)
+Set Theta-angle value.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{void} SetAlpha (@code{bool} val)
+Switch on/off transparency.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{void} SetLight (@code{bool} val)
+Switch on/off lightning.
+ at end deftypemethod
+ at comment  @deftypemethod wxMathGL @code{void} SetGrid (@code{bool} val)
+ at comment  Switch on/off drawing of grid for absolute coordinates.
+ at comment  @end deftypemethod
+ at deftypemethod wxMathGL @code{void} SetZoom (@code{bool} val)
+Switch on/off mouse zooming.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{void} SetRotate (@code{bool} val)
+Switch on/off mouse rotation.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{void} ZoomIn ()
+Zoom in graphics.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{void} ZoomOut ()
+Zoom out graphics.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{void} ShiftLeft ()
+Shift graphics to left direction.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{void} ShiftRight ()
+Shift graphics to right direction.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{void} ShiftUp  ()
+Shift graphics to up direction.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{void} ShiftDown ()
+Shift graphics to down direction.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{void} Restore ()
+Restore zoom and rotation to default values.
+ at end deftypemethod
+ at c @deftypemethod wxMathGL @code{void} reload ()
+ at c Reload data and redraw graphics.
+ at c @end deftypemethod
+
+ at deftypemethod wxMathGL @code{void} About ()
+Show about information.
+ at end deftypemethod
+
+ at deftypemethod wxMathGL @code{void} ExportPNG (@code{QString} fname=@code{""})
+Export current picture to PNG file.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{void} ExportPNGs (@code{QString} fname=@code{""})
+Export current picture to PNG file (no transparency).
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{void} ExportJPG (@code{QString} fname=@code{""})
+Export current picture to JPEG file.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{void} ExportBPS (@code{QString} fname=@code{""})
+Export current picture to bitmap EPS file.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{void} ExportEPS (@code{QString} fname=@code{""})
+Export current picture to vector EPS file.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{void} ExportSVG (@code{QString} fname=@code{""})
+Export current picture to SVG file.
+ at end deftypemethod
+
 @external{}
 
diff --git a/texinfo/widget_ru.texi b/texinfo/widget_ru.texi
index 1ef5140..e00998c 100644
--- a/texinfo/widget_ru.texi
+++ b/texinfo/widget_ru.texi
@@ -1,6 +1,7 @@
 
 @c ------------------------------------------------------------------
 @chapter ``Оконные'' классы
+ at nav{}
 @cindex mglWindow
 @cindex mglGLUT
 @cindex Fl_MathGL
@@ -25,6 +26,7 @@ public:
 * mglWindow class::
 * Fl_MathGL class::
 * QMathGL class::
+* wxMathGL class::
 @end menu
 
 
@@ -32,11 +34,12 @@ public:
 @external{}
 @node mglWindow class, Fl_MathGL class, , Widget classes
 @section Класс mglWindow
+ at nav{}
 @cindex mglWindow
 @cindex window
 @c @cindex mglDraw
 
-Этот класс производный от класса mglGraph (см. @ref{MathGL core}). Он определен в @code{#include <mgl2/window.h>}. Класс содержит методы для создания и управления окном, содержащим графику MathGL. Похожий набор классов существует отдельно для каждой библиотеки виджетов: @code{mglQT} в @code{#include <mgl2/qt.h>}, @code{mglFLTK} в @code{#include <mgl2/fltk.h>}, @code{mglWX} в @code{#include <mgl2/wx.h>}.
+Этот класс производный от класса mglGraph (см. @ref{MathGL core}). Он определен в @code{#include <mgl2/window.h>}. Класс содержит методы для создания и управления окном, содержащим графику MathGL. Похожий набор классов существует отдельно для каждой библиотеки виджетов: @code{mglQT} в @code{#include <mgl2/qt.h>}, @code{mglFLTK} в @code{#include <mgl2/fltk.h>}.
 
 @deftypefn {Конструктор класса @code{mglWindow}} {} mglWindow (@code{const char *}title=@code{"MathGL"})
 @deftypefnx {Конструктор класса @code{mglWindow}} {} mglWindow (@code{int} (*draw)(@code{HMGL} gr, @code{void *}p), @code{const char *}title=@code{"MathGL"}, @code{void *}par=@code{NULL}, @code{int} kind=@code{0}, @code{void} (*reload)(@code{HMGL} gr, @code{void *}p)=0)
@@ -140,8 +143,9 @@ public:
 
 @c ------------------------------------------------------------------
 @external{}
- at node Fl_MathGL class, QMathGL class, , Widget classes
+ at node Fl_MathGL class, QMathGL class, mglWindow class, Widget classes
 @section Класс Fl_MathGL
+ at nav{}
 @cindex Fl_MathGL
 @cindex widgets
 
@@ -185,6 +189,9 @@ public:
 @deftypemethod Fl_MathGL @code{mglGraph *} get_graph ()
 Возвращает указатель на объект, строящий графики.
 @end deftypemethod
+ at deftypemethod Fl_MathGL @code{void} adjust ()
+Подгоняет размер картинки под размер окна.
+ at end deftypemethod
 
 @deftypecv {Widget option} Fl_MathGL @code{Fl_Valuator *} tet_val
 Указатель на внешний элемент управления для изменения угла tet.
@@ -195,8 +202,9 @@ public:
 
 @c ------------------------------------------------------------------
 @external{}
- at node QMathGL class, , Fl_MathGL class, Widget classes
+ at node QMathGL class, wxMathGL class, Fl_MathGL class, Widget classes
 @section Класс QMathGL
+ at nav{}
 @cindex QMathGL
 @cindex widgets
 
@@ -321,7 +329,7 @@ public:
 @deftypefn {Slot on @code{QMathGL}} @code{void} shiftRight ()
 Сдвигает график вправо.
 @end deftypefn
- at deftypefn {Slot on @code{QMathGL}} @code{void}shiftUp  ()
+ at deftypefn {Slot on @code{QMathGL}} @code{void} shiftUp  ()
 Сдвигает график вверх.
 @end deftypefn
 @deftypefn {Slot on @code{QMathGL}} @code{void} shiftDown ()
@@ -379,7 +387,7 @@ public:
 @c Сохраняет текущий рисунок в векторный X3D файл.
 @c @end deftypefn
 
- at deftypefn {Slot on @code{QMathGL}} @code{void}setUsePrimitives (@code{bool} use)
+ at deftypefn {Slot on @code{QMathGL}} @code{void} setUsePrimitives (@code{bool} use)
 Разрешает использовать список примитивов для кадров. Это позволяет вращать/масштабировать кадры, но требует значительно больше памяти. По умолчанию разрешено (=@code{true}).
 @end deftypefn
 @deftypefn {Slot on @code{QMathGL}} @code{void} setMGLFont (@code{QString} path)
@@ -447,3 +455,169 @@ public:
 
 @external{}
 
+
+ at c ------------------------------------------------------------------
+ at external{}
+ at node wxMathGL class, , QMathGL class, Widget classes
+ at section Класс wxMathGL
+ at nav{}
+ at cindex wxMathGL
+ at cindex widgets
+
+Класс реализует элемент интерфейса WX для отображения графики MathGL. Он определен в @code{#include <mgl2/wx.h>}.
+
+ at deftypemethod wxMathGL @code{void} SetDraw (@code{mglDraw *}dr)
+Задает функцию рисования из класса производного от @code{mglDraw}.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{void} SetDraw (@code{int (*}draw at code{)(mglBase *}gr, @code{void *}p at code{)}, @code{void *}par=@code{NULL})
+ at deftypemethodx wxMathGL @code{void} SetDraw (@code{int (*}draw at code{)(mglGraph *}gr at code{)})
+Задает функцию рисования @var{draw}. Поддерживается список графиков (кадров), так что можно вначале их нарисовать (требует довольно много памяти), а потом достаточно быстро отображать. Функция должна возвращать положительное число создаваемых кадров или ноль для непосредственного рисования. Параметр @var{par} содержит указатель на данные пользователя, передаваемый функции рисования @var{draw}.
+ at end deftypemethod
+
+ at deftypemethod wxMathGL @code{void} SetGraph (@code{mglCanvas *}gr)
+ at deftypemethodx wxMathGL @code{void} SetGraph (@code{mglGraph *}gr)
+Устанавливает указатель на внешний экземпляр класса для рисования (вместо встроенного). Отмечу, что wxMathGL автоматически удалит этот объект при удалении элемента интерфейса или при новом вызове @code{setGraph()}.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{HMGL} GetGraph ()
+Возвращает указатель на объект, строящий графики.
+ at end deftypemethod
+
+ at deftypemethod wxMathGL @code{void} SetPopup (@code{QMenu *}p)
+Задает указатель на всплывающее меню.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{void} SetSize (@code{int} w, @code{int} h)
+Задает размеры элемента управления и картинки.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{double} GetRatio ()
+Возвращает соотношение сторон рисунка.
+ at end deftypemethod
+
+ at deftypemethod wxMathGL @code{int} GetPer ()
+Возвращает величину перспективы в процентах.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{int} GetPhi ()
+Возвращает величину угла Phi в градусах.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{int} GetTet ()
+Возвращает величину угла Theta в градусах.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{bool} GetAlpha ()
+Возвращает состояние переключателя прозрачности.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{bool} GetLight ()
+Возвращает состояние переключателя освещения.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{bool} GetZoom ()
+Возвращает состояние переключателя приближения мышью.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{bool} GetRotate ()
+Возвращает состояние переключателя вращения мышью.
+ at end deftypemethod
+
+
+ at deftypemethod wxMathGL @code{void} Repaint ()
+Перерисовывает (обновляет) элемент управления без вызова функции рисования.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{void} Update ()
+Обновляет рисунок путем вызова функции рисования.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{void} Copy ()
+Копирует график в буфер обмена.
+ at end deftypemethod
+ at comment  @deftypemethod wxMathGL @code{void} copyClickCoor ()
+ at comment  Копирует координаты щелчка мышью (как текст).
+ at comment  @end deftypemethod
+ at deftypemethod wxMathGL @code{void} Print ()
+Печатает текущий рисунок.
+ at end deftypemethod
+
+ at comment  @deftypemethod wxMathGL @code{void} Stop ()
+ at comment  Посылает сигнал остановки рисования.
+ at comment  @end deftypemethod
+ at deftypemethod wxMathGL @code{void} Adjust ()
+Подгоняет размер картинки под размер окна.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{void} NextSlide ()
+Показывает следующий кадр.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{void} PrevSlide ()
+Показывает предыдущий кадр.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{void} Animation (@code{bool} st=@code{true})
+Запускает анимацию.
+ at end deftypemethod
+
+ at deftypemethod wxMathGL @code{void} SetPer (@code{int} val)
+Задает величину перспективы.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{void} SetPhi (@code{int} val)
+Задает величину угла Phi.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{void} SetTet (@code{int} val)
+Задает величину угла Theta.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{void} SetAlpha (@code{bool} val)
+Включает/выключает прозрачность.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{void} SetLight (@code{bool} val)
+Включает/выключает освещение.
+ at end deftypemethod
+ at comment  @deftypemethod wxMathGL @code{void} SetGrid (@code{bool} val)
+ at comment  Включает/выключает рисование сетки абсолютных координат на графике.
+ at comment  @end deftypemethod
+ at deftypemethod wxMathGL @code{void} SetZoom (@code{bool} val)
+Включает/выключает приближение мышью.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{void} SetRotate (@code{bool} val)
+Включает/выключает вращение мышью.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{void} ZoomIn ()
+Приблиажет график.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{void} ZoomOut ()
+Отдаляет график.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{void} ShiftLeft ()
+Сдвигает график влево.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{void} ShiftRight ()
+Сдвигает график вправо.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{void} ShiftUp  ()
+Сдвигает график вверх.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{void} ShiftDown ()
+Сдвигает график вниз.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{void} Restore ()
+Восстанавливает приближение и поворот графика в значения по умолчанию.
+ at end deftypemethod
+ at c @deftypemethod wxMathGL @code{void} reload ()
+ at c Обновляет данные и перерисовывает график.
+ at c @end deftypemethod
+
+ at deftypemethod wxMathGL @code{void} About ()
+Показывает информацию о программе.
+ at end deftypemethod
+
+ at deftypemethod wxMathGL @code{void} ExportPNG (@code{QString} fname=@code{""})
+Сохраняет текущий рисунок в PNG файл.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{void} ExportPNGs (@code{QString} fname=@code{""})
+Сохраняет текущий рисунок в PNG файл без прозрачности.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{void} ExportJPG (@code{QString} fname=@code{""})
+Сохраняет текущий рисунок в JPEG файл.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{void} ExportBPS (@code{QString} fname=@code{""})
+Сохраняет текущий рисунок в растровый EPS файл.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{void} ExportEPS (@code{QString} fname=@code{""})
+Сохраняет текущий рисунок в векторный EPS файл.
+ at end deftypemethod
+ at deftypemethod wxMathGL @code{void} ExportSVG (@code{QString} fname=@code{""})
+Сохраняет текущий рисунок в векторный SVG файл.
+ at end deftypemethod
+
+ at external{}
+
diff --git a/todo.txt b/todo.txt
index c5e8bc1..ebab10a 100644
--- a/todo.txt
+++ b/todo.txt
@@ -1,43 +1,34 @@
-http://ubuntuforums.org/showthread.php?t=1862084
-Device 0 (VID=0502 and PID=337d) is UNKNOWN. (VID=18d1 and PID=4e41)
 
 ============= NEW FOR LATER =============
 
-A. Paper about MathGL!!!
-
-1. Export to X3D, COLLADA !!!
-2. GTK window/widgets
+1. Export to COLLADA !!!
+2. GTK window/widgets ???
 3. Labels at TriCont()
-4. Drawing of saddle quadrangles
+4. Rewrite glyph drawing for bitmaps (speeding up by excluding boundary checks) ?!?
+
 5. 2D textures as one of standard way for coloring -- if '%' present in color scheme
 6. Graph(mreal x, mreal y, names, styles, font, size); -- names = "node1[node2,node3,node4[node5,node6]]", styles -- the same + apply for subnodes if absent. Styles are colors (fill,border,line), dash (to subnodes), marks "dos^v><", arrows.
-7. Use libtcc for mglFormula only! -- note that MGL formulas (i.e. for mglData) are fast enough. The only possible speeding up for Fill() and Modify() functions
-8. 3D text (with depth, for Quality=3)
-9. Text along 3D curve (for Quality=3)
-10. introduce new primitive type=5 -- arrow for Quality&3!=3. for better drawing in projections + json/view ?!?
-11. enable line width for mesh and fall???
-12. WX window/widgets
-13. Textured brushes for drawing: (a) as 8*8 array, i.e. long (save only index in mglPrim::type); (b) BrushWidth; (c) BrushAngle; (d) some pixels become transparent; (e) count from edge of image; (f) symbols {+-;=\*<>^osdiODSI}. Question: how this can be exported???
-
-14. New tests:
-	b. Add test for curved text align "L","C","R"
+7. 3D text (with depth, for Quality=3)
+8. Text along 3D curve (for Quality=3)
+9. introduce new primitive type=5 -- arrow for Quality&3!=3. for better drawing in projections + json/view ?!?
+
+10. New tests:
 	c. Tests for mglDataC arrays (as separate flag)
-	e. Test for Crop, Momentum, NormSl, Sew, DiffParam, Envelope, FFT, STFA, Transform for all directions "xyz"; Clean, Last, First, Find, Spline3, FindAny, Insert, Delete, Put, Read/Save+HDF, SetId/Column, PrintInfo, Squeeze, Extend, Trace, Combine, new Max/Min/Momentum, FillSample, Hist, operators, Sort, Export/Import, Jacobian
-	h. Test for CalcXYZ -- in data samples
-	i. Tests for Quality!=2
-	l. Test Error for all marks
-	o. Add Fortran tests?
-	p. Test FaceNum for Surf
-	q. Test FSurf
+	e. Test for Crop, Momentum, NormSl, Sew, DiffParam, Envelope, STFA for all directions "xyz"; Clean, Last, First, Find, Spline3, FindAny, Insert, Delete, Put, SetId/Column, Squeeze, Extend, Trace, Combine, new Max/Min/Momentum, FillSample, Hist, operators, Sort, Roots, Jacobian
 	u. Test FlowP + 3d
-	w. Test diffuse, specular local sources
 
-15. Check samples: colorbar
-16. Add samples about data handling (data1, data2, data2)
-17. Add "Triangulation sample"
+11. Check centered curved text (see text2)
+14. Export to X3D
+
 
-20. JS rotation in Firefox
-23. check if all "value" options are described
+============= DOCUMENTATION =============
+
+A. Paper about MathGL!!!
+B. Add chapter with real samples
+C. Translate to Russian everything
+
+1. Extend Dots sample (add A, CA, Tens)
+2. Extend Refill sample (add 2d)
 
 ============= UDAV =============
 
@@ -49,7 +40,7 @@ A. Paper about MathGL!!!
 {SubPlot,MultiPlot}	-- enable rotate,aspect,title
 {ColumnPlot}		-- enable rotate,several
 {StickPlot}		-- enable several
-{InPlot}		-- enable rotate,aspect,title
+{InPlot}			-- enable rotate,aspect,title
 Image with gray alternatives and black choice
 
 04. QTreeWidgetItem -- ICON (func/call,if,for,once,subplot,...); annotation/name; (keep LINE - POS in script). After editing/changing --> put text to editor.
@@ -70,6 +61,8 @@ Buttons: new,load,save // newcmd,hide,annotation,collapse on/off,setup // calc.
 
 14. Close button on data tabs ?!?
 
+15. Add dialog for mask creation.
+
 ============= UNSURE ===========
 
 1. Problem with \calB and so on (\calH, ...) -- they are present only in italic font :(.
diff --git a/udav/dat_pnl.cpp b/udav/dat_pnl.cpp
index 0259b52..e323501 100644
--- a/udav/dat_pnl.cpp
+++ b/udav/dat_pnl.cpp
@@ -437,12 +437,12 @@ bool DatPanel::sizesDialog(const QString &cap, const QString &lab, const QString
 //-----------------------------------------------------------------------------
 #include "xpm/plot.xpm"
 #include "xpm/size.xpm"
-#include "xpm/smth.xpm"
+//#include "xpm/smth.xpm"
 #include "xpm/crop.xpm"
 #include "xpm/squize.xpm"
-#include "xpm/sum.xpm"
-#include "xpm/func.xpm"
-#include "xpm/swap.xpm"
+//#include "xpm/sum.xpm"
+//#include "xpm/func.xpm"
+//#include "xpm/swap.xpm"
 #include "xpm/hist.xpm"
 #include "xpm/oper_dir.xpm"
 #include "xpm/oper_of.xpm"
@@ -522,7 +522,6 @@ void DatPanel::newdat()
 //-----------------------------------------------------------------------------
 void DatPanel::oper()
 {
-	QLabel *l;
 	QLineEdit *f1;
 	QPushButton *b;
 	QDialog *d = new QDialog(this);
@@ -679,7 +678,7 @@ void DatPanel::toolTop(QBoxLayout *l)
 void DatPanel::toolLeft(QBoxLayout *l)
 {
 	QAction *a;
-	QMenu *o, *oo;
+	QMenu *o;
 	QToolButton *bb;
 
 	// size menu
@@ -725,13 +724,13 @@ void DatPanel::toolLeft(QBoxLayout *l)
 	a->setToolTip(tr("Find histogram of data."));
 	a->setShortcut(Qt::CTRL+Qt::SHIFT+Qt::Key_H);	o->addAction(a);
 	bb = new QToolButton(this);	l->addWidget(bb);	bb->setDefaultAction(a);
-	
+
 /*	a = new QAction(QPixmap(":/xpm/view-refresh.png"), tr("Refresh"), this);
 	connect(a, SIGNAL(triggered()), this, SLOT(refresh()));
 	a->setToolTip(tr("Refresh data values."));
 	o->addAction(a);
 	bb = new QToolButton(this);	l->addWidget(bb);	bb->setDefaultAction(a);*/
-	
+
 /*	a = new QAction(tr("Rearrange"), this);	// TODO: move in generalized dialog
 	connect(a, SIGNAL(triggered()), this, SLOT(rearrange()));
 	a->setToolTip(tr("Rearrange data sizes without changing data values."));
diff --git a/udav/info_dlg.cpp b/udav/info_dlg.cpp
index 1cc72c8..9531bb4 100644
--- a/udav/info_dlg.cpp
+++ b/udav/info_dlg.cpp
@@ -56,7 +56,7 @@ InfoDialog::InfoDialog(QWidget *parent) : QDialog(parent)
 	connect(mgl,SIGNAL(showWarn(QString)),info,SLOT(setText(QString)));
 }
 //-----------------------------------------------------------------------------
-InfoDialog::~InfoDialog()	{	delete draw;	}
+InfoDialog::~InfoDialog()	{}
 //-----------------------------------------------------------------------------
 #include <QMessageBox>
 void InfoDialog::refresh(bool force)
diff --git a/udav/plot_pnl.cpp b/udav/plot_pnl.cpp
index 3f1344b..0429554 100644
--- a/udav/plot_pnl.cpp
+++ b/udav/plot_pnl.cpp
@@ -57,7 +57,7 @@ PlotPanel::PlotPanel(QWidget *parent) : QWidget(parent)
 	popup = new QMenu(this);
 	mgl = new QMathGL(this);
 	draw = new mglDrawScript(parser.Self());
-	mgl->getGraph()->set(MGL_SHOW_POS);	mgl->setDraw(draw);
+	mgl_set_flag(mgl->getGraph(),1,MGL_SHOW_POS);	mgl->setDraw(draw);
 	connect(mgl,SIGNAL(askStyle(int)),this,SLOT(setStyle(int)));
 
 	QBoxLayout *v,*h,*m;
@@ -92,7 +92,7 @@ void PlotPanel::execute()
 	raisePanel(this);
 	emit clearWarn();
 	QTime t;	t.start();
-	mgl->getGraph()->FaceNum=0;
+	mgl_set_facenum(mgl->getGraph(),0);
 	draw->text=textMGL->toPlainText();
 	draw->line=curPos;
 	mgl->update();
@@ -365,37 +365,37 @@ void PlotPanel::toolTop(QBoxLayout *l)
 	connect(mgl, SIGNAL(usePrimChanged(bool)), a, SLOT(setVisible(bool)));
 	a->setToolTip(tr("Add curve which properties can be changed later by mouse."));
 	bb = new QToolButton(this);	l->addWidget(bb);	bb->setDefaultAction(a);	oo->addAction(a);
-	
+
 	a = new QAction(QPixmap(mark_s_xpm), tr("Add rect"), this);
 	connect(a, SIGNAL(triggered()), mgl, SLOT(addRect()));
 	connect(mgl, SIGNAL(usePrimChanged(bool)), a, SLOT(setVisible(bool)));
 	a->setToolTip(tr("Add rectangle which properties can be changed later by mouse."));
 	bb = new QToolButton(this);	l->addWidget(bb);	bb->setDefaultAction(a);	oo->addAction(a);
-	
+
 	a = new QAction(QPixmap(mark_d_xpm), tr("Add rhombus"), this);
 	connect(a, SIGNAL(triggered()), mgl, SLOT(addRhomb()));
 	connect(mgl, SIGNAL(usePrimChanged(bool)), a, SLOT(setVisible(bool)));
 	a->setToolTip(tr("Add rhombus which properties can be changed later by mouse."));
 	bb = new QToolButton(this);	l->addWidget(bb);	bb->setDefaultAction(a);	oo->addAction(a);
-	
+
 	a = new QAction(QPixmap(mark_o_xpm), tr("Add ellipse"), this);
 	connect(a, SIGNAL(triggered()), mgl, SLOT(addEllipse()));
 	connect(mgl, SIGNAL(usePrimChanged(bool)), a, SLOT(setVisible(bool)));
 	a->setToolTip(tr("Add ellipse which properties can be changed later by mouse."));
 	bb = new QToolButton(this);	l->addWidget(bb);	bb->setDefaultAction(a);	oo->addAction(a);
-	
+
 	a = new QAction(QPixmap(mark_a_xpm), tr("Add mark"), this);
 	connect(a, SIGNAL(triggered()), mgl, SLOT(addMark()));
 	connect(mgl, SIGNAL(usePrimChanged(bool)), a, SLOT(setVisible(bool)));
 	a->setToolTip(tr("Add marker which properties can be changed later by mouse."));
 	bb = new QToolButton(this);	l->addWidget(bb);	bb->setDefaultAction(a);	oo->addAction(a);
-	
+
 	a = new QAction(QPixmap(text_xpm), tr("Add text"), this);
 	connect(a, SIGNAL(triggered()), mgl, SLOT(addText()));
 	connect(mgl, SIGNAL(usePrimChanged(bool)), a, SLOT(setVisible(bool)));
 	a->setToolTip(tr("Add text which properties can be changed later by mouse."));
 	bb = new QToolButton(this);	l->addWidget(bb);	bb->setDefaultAction(a);	oo->addAction(a);
-	
+
 	o->addMenu(oo);	l->addStretch(1);
 
 	tet = new QSpinBox(this);	tet->setWrapping(true);
diff --git a/udav/udav_wnd.cpp b/udav/udav_wnd.cpp
index fcdfc20..2dd40f8 100644
--- a/udav/udav_wnd.cpp
+++ b/udav/udav_wnd.cpp
@@ -128,13 +128,14 @@ int main(int argc, char **argv)
 	}
 
 	udavLoadDefCommands();
+	parser.AllowSetSize(true);
 	MainWindow *mw = new MainWindow();
 	if(argc>1)
 	{
 		QTextCodec *codec = QTextCodec::codecForLocale();
 		mw->load(codec->toUnicode(argv[1]), true);
 	}
-	mw->show();	parser.AllowSetSize(true);
+	mw->show();
 	a.connect(&a, SIGNAL(lastWindowClosed()), &a, SLOT(quit()));
 	if(showHint)	udavShowHint(mw);
 	return a.exec();
@@ -567,7 +568,7 @@ void MainWindow::setStatus(const QString &txt)
 void MainWindow::setCurrentFile(const QString &fileName)
 {
 	filename = fileName;
-	graph->mgl->getGraph()->PlotId = fileName.toAscii().constData();
+	mgl_set_plotid(graph->mgl->getGraph(), fileName.toAscii().constData());
 	edit->setModified(false);
 	if(filename.isEmpty())
 		setWindowTitle(tr("untitled - UDAV"));
diff --git a/widgets/CMakeLists.txt b/widgets/CMakeLists.txt
index 90ea00c..b4be58b 100644
--- a/widgets/CMakeLists.txt
+++ b/widgets/CMakeLists.txt
@@ -5,7 +5,7 @@ if(MGL_HAVE_FLTK)
 	include_directories(${FLTK_INCLUDE_DIR})
 	add_library(mgl-fltk SHARED fltk.cpp ../include/mgl2/fltk.h)
 	add_library(mgl-fltk-static STATIC fltk.cpp ../include/mgl2/fltk.h)
-	set_target_properties(mgl-fltk PROPERTIES SOVERSION 7.0.0)
+	set_target_properties(mgl-fltk PROPERTIES SOVERSION ${MathGL_SOVERSION})
 	set_target_properties(mgl-fltk PROPERTIES CLEAN_DIRECT_OUTPUT 1)
 	set_target_properties(mgl-fltk PROPERTIES DEFINE_SYMBOL "mgl_EXPORTS")
 	set_target_properties(mgl-fltk-static PROPERTIES CLEAN_DIRECT_OUTPUT 1)
@@ -32,7 +32,7 @@ if(MGL_HAVE_GLUT)
 	include_directories(${GLUT_INCLUDE_DIR})
 	add_library(mgl-glut SHARED glut.cpp ../include/mgl2/glut.h)
 	add_library(mgl-glut-static STATIC glut.cpp ../include/mgl2/glut.h)
-	set_target_properties(mgl-glut PROPERTIES SOVERSION 7.0.0)
+	set_target_properties(mgl-glut PROPERTIES SOVERSION ${MathGL_SOVERSION})
 	set_target_properties(mgl-glut PROPERTIES CLEAN_DIRECT_OUTPUT 1)
 	set_target_properties(mgl-glut PROPERTIES DEFINE_SYMBOL "mgl_EXPORTS")
 	set_target_properties(mgl-glut-static PROPERTIES CLEAN_DIRECT_OUTPUT 1)
@@ -59,7 +59,7 @@ if(MGL_HAVE_WX)
 	include(${wxWidgets_USE_FILE})
 	add_library(mgl-wx SHARED wx.cpp ../include/mgl2/wx.h)
 	add_library(mgl-wx-static STATIC wx.cpp ../include/mgl2/wx.h)
-	set_target_properties(mgl-wx PROPERTIES SOVERSION 7.0.0)
+	set_target_properties(mgl-wx PROPERTIES SOVERSION ${MathGL_SOVERSION})
 	set_target_properties(mgl-wx PROPERTIES CLEAN_DIRECT_OUTPUT 1)
 	set_target_properties(mgl-wx PROPERTIES DEFINE_SYMBOL "mgl_EXPORTS")
 	set_target_properties(mgl-wx-static PROPERTIES CLEAN_DIRECT_OUTPUT 1)
@@ -87,7 +87,7 @@ if(MGL_HAVE_QT)
 	qt4_wrap_cpp(MGL_MOC_FILES ../include/mgl2/qmathgl.h)
 	add_library(mgl-qt SHARED qt.cpp ${MGL_MOC_FILES} ../include/mgl2/qt.h ../include/mgl2/qmathgl.h)
 	add_library(mgl-qt-static STATIC qt.cpp ${MGL_MOC_FILES} ../include/mgl2/qt.h ../include/mgl2/qmathgl.h)
-	set_target_properties(mgl-qt PROPERTIES SOVERSION 7.0.0)
+	set_target_properties(mgl-qt PROPERTIES SOVERSION ${MathGL_SOVERSION})
 	set_target_properties(mgl-qt PROPERTIES CLEAN_DIRECT_OUTPUT 1)
 	set_target_properties(mgl-qt PROPERTIES DEFINE_SYMBOL "mgl_EXPORTS")
 	set_target_properties(mgl-qt-static PROPERTIES CLEAN_DIRECT_OUTPUT 1)
@@ -111,19 +111,16 @@ if(MGL_HAVE_QT)
 endif(MGL_HAVE_QT)
 
 
-#if(MGL_HAVE_QT AND MGL_HAVE_WX AND MGL_HAVE_FLTK)
 if(MGL_HAVE_QT AND MGL_HAVE_FLTK)
 	include_directories(${FLTK_INCLUDE_DIR})
-#	include(${wxWidgets_USE_FILE})
 	include(${QT_USE_FILE})
 
-#	set(MGL_WND_SRC wx.cpp ../include/mgl2/wx.h qt.cpp ../include/mgl2/qt.h ../include/mgl2/qmathgl.h fltk.cpp ../include/mgl2/fltk.h)
 	set(MGL_WND_SRC qt.cpp ../include/mgl2/qt.h ../include/mgl2/qmathgl.h fltk.cpp ../include/mgl2/fltk.h)
 
 	add_library(mgl-wnd SHARED ${MGL_WND_SRC} ${MGL_MOC_FILES})
 	add_library(mgl-wnd-static STATIC ${MGL_WND_SRC} ${MGL_MOC_FILES})
 
-	set_target_properties(mgl-wnd PROPERTIES SOVERSION 7.0.0)
+	set_target_properties(mgl-wnd PROPERTIES SOVERSION ${MathGL_SOVERSION})
 	set_target_properties(mgl-wnd PROPERTIES CLEAN_DIRECT_OUTPUT 1)
 	set_target_properties(mgl-wnd PROPERTIES DEFINE_SYMBOL "mgl_EXPORTS")
 	set_target_properties(mgl-wnd-static PROPERTIES CLEAN_DIRECT_OUTPUT 1)
@@ -138,7 +135,6 @@ if(MGL_HAVE_QT AND MGL_HAVE_FLTK)
 
 	target_link_libraries(mgl-wnd mgl)
 	target_link_libraries(mgl-wnd ${QT_LIBRARIES})
-#	target_link_libraries(mgl-wnd ${wxWidgets_LIBRARIES})
 	target_link_libraries(mgl-wnd ${FLTK_LIBRARIES})
 
 	install(
@@ -147,5 +143,4 @@ if(MGL_HAVE_QT AND MGL_HAVE_FLTK)
 		ARCHIVE DESTINATION ${MGL_LIB_INSTALL_DIR}
 		LIBRARY DESTINATION ${MGL_LIB_INSTALL_DIR}
 	)
-#endif(MGL_HAVE_QT AND MGL_HAVE_WX AND MGL_HAVE_FLTK)
 endif(MGL_HAVE_QT AND MGL_HAVE_FLTK)
diff --git a/widgets/fltk.cpp b/widgets/fltk.cpp
index 60649c4..1c7e5b0 100644
--- a/widgets/fltk.cpp
+++ b/widgets/fltk.cpp
@@ -95,17 +95,15 @@ using mglCanvasWnd::Window;
 //-----------------------------------------------------------------------------
 void MGL_EXPORT mgl_ask_fltk(const wchar_t *quest, wchar_t *res)
 {
-	static char buf[1024];
+	static char buf[1024];	*res=0;
 #if FL_MINOR_VERSION>=3
-	fl_utf8fromwc(buf, 1024, quest, wcslen(quest)+1);
+	fl_utf8fromwc(buf, 1024, quest, mgl_wcslen(quest)+1);
 	const char *str = fl_input("%s",buf,"");
 	if(str)	fl_utf8towc(str, strlen(str)+1, res, 1024);
-	else		*res=0;
 #else
-	wcstombs(buf,quest,wcslen(quest)+1);
+	wcstombs(buf,quest,mgl_wcslen(quest)+1);
 	const char *str = fl_input("%s",buf,"");
-	if(str)	mbstowcs(res,str, strlen(str)+1);
-	else		*res=0;
+	MGL_TO_WCS(str,wcscpy(res,str));
 #endif
 }
 //-----------------------------------------------------------------------------
@@ -513,11 +511,7 @@ void MGL_NO_EXPORT mgl_so_cb(Fl_Widget*, void* v)
 }
 //-----------------------------------------------------------------------------
 void MGL_NO_EXPORT mgl_adjust_cb(Fl_Widget*, void*v)
-{
-	Fl_MGLView *e = (Fl_MGLView*)v;	if(!e)	return;
-	mgl_set_size(e->FMGL->get_graph(), e->scroll->w(), e->scroll->h());
-	e->FMGL->size(e->scroll->w(), e->scroll->h());	e->update();
-}
+{	Fl_MGLView *e = (Fl_MGLView*)v;	if(e)	e->adjust();	}
 void mglCanvasFL::Adjust()	{	Fl::lock();	mgl_adjust_cb(0,mgl);	Fl::unlock();	}
 //-----------------------------------------------------------------------------
 void MGL_NO_EXPORT mgl_oncemore_cb(Fl_Widget*, void*v)
@@ -591,7 +585,7 @@ Fl_MGLView::Fl_MGLView(int xx, int yy, int ww, int hh, const char *lbl) : Fl_Win
 	grid_bt->image(xpm_wire);	grid_bt->callback(mgl_grid_cb,this);
 	grid_bt->tooltip(gettext("Switch on/off grid drawing"));
 	//	grid_bt->box(FL_PLASTIC_UP_BOX);		grid_bt->down_box(FL_PLASTIC_DOWN_BOX);
-	
+
 	rotate_bt = new Fl_Button(80, 1, 25, 25);rotate_bt->type(FL_TOGGLE_BUTTON);
 	rotate_bt->image(xpm_r1);	rotate_bt->callback(mgl_rotate_cb,this);
 	rotate_bt->tooltip(gettext("Rotate picture by holding left mouse button"));
@@ -694,7 +688,7 @@ void MGL_EXPORT mgl_makemenu_fltk(Fl_Menu_ *m, Fl_MGLView *w)
 	m->add("Graphics/Reload data", "f9", mgl_oncemore_cb, w);
 	//TODO	m->add("Graphics/Stop", "f7", mgl_stop_cb, w);
 	//TODO	m->add("Graphics/Copy graphics","+^c", mgl_copyimg_cb, w);
-	
+
 	m->add("Graphics/Export/as PNG", "#p", mgl_export_png_cb, w);
 	m->add("Graphics/Export/as solid PNG", "#f", mgl_export_pngn_cb, w);
 	m->add("Graphics/Export/as JPEG", "#j", mgl_export_jpeg_cb, w);
diff --git a/widgets/glut.cpp b/widgets/glut.cpp
index 3a52d3d..f80a110 100644
--- a/widgets/glut.cpp
+++ b/widgets/glut.cpp
@@ -46,12 +46,7 @@ friend void _mgl_display();
 friend void _mgl_key_up(unsigned char ch,int ,int );
 friend void _mgl_timer(int);
 public:
-	mreal Delay;	///< Delay for animation in seconds
-	bool AutoClf;		///< Clear canvas between drawing
-
 	mglCanvasGLUT();
-	mglCanvasGLUT(int (*draw)(mglGraph *gr, void *p), const char *title, void *par=NULL,
-				void (*reload)(int next, void *p)=NULL, bool maximize=false);
 	virtual ~mglCanvasGLUT();
 	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ��������� ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 	/// Create a window for plotting. Now implemeted only for GLUT.
@@ -128,9 +123,9 @@ void _mgl_key_up(unsigned char ch,int ,int )
 	if(ch=='e')	_mgl_glwnd->View(0,10,0);
 	if(ch=='n')	_mgl_glwnd->Restore();
 	if(ch==',')
-		_mgl_glwnd->curr_fig = _mgl_glwnd->curr_fig == 1 ? _mgl_glwnd->NumFig : _mgl_glwnd->curr_fig-1;
+		_mgl_glwnd->curr_fig = _mgl_glwnd->curr_fig == 0 ? _mgl_glwnd->NumFig-1 : _mgl_glwnd->curr_fig-1;
 	if(ch=='.')
-		_mgl_glwnd->curr_fig = _mgl_glwnd->curr_fig == _mgl_glwnd->NumFig ? 1 : _mgl_glwnd->curr_fig+1;
+		_mgl_glwnd->curr_fig = _mgl_glwnd->curr_fig == _mgl_glwnd->NumFig-1 ? 0 : _mgl_glwnd->curr_fig+1;
 	if(ch=='r')	Alpha = !Alpha;
 	if(ch=='f')	Light = !Light;
 	if(ch=='u')	rL += 0.1;
@@ -143,7 +138,8 @@ void _mgl_key_up(unsigned char ch,int ,int )
 	{
 		glDeleteLists(1,_mgl_glwnd->NumFig);
 		_mgl_glwnd->LoadFunc(_mgl_glwnd->FuncPar);
-		(_mgl_glwnd->DrawFunc)(_mgl_glwnd,_mgl_glwnd->FuncPar);
+		if(_mgl_glwnd->DrawFunc)
+			(_mgl_glwnd->DrawFunc)(_mgl_glwnd,_mgl_glwnd->FuncPar);
 		_mgl_glwnd->Finish();
 	}
 	if(ch=='P')
@@ -182,17 +178,24 @@ void _mgl_display()
 {
 	if(!_mgl_glwnd)	return;
 //	glEnable(GL_LINE_SMOOTH);
-	_mgl_glwnd->CurFrameId = 1;
-	if(_mgl_glwnd->AutoClf)	_mgl_glwnd->Clf();
+//	_mgl_glwnd->CurFrameId = 1;
+//	if(_mgl_glwnd->get(MGL_CLF_ON_UPD))
+	_mgl_glwnd->Clf();
+//	_mgl_glwnd->gl_clf();
 	_mgl_glwnd->InPlot(0,1,0,1,false);
-	if(_mgl_glwnd->NumFig>0)	glCallList(_mgl_glwnd->curr_fig);
+	if(_mgl_glwnd->NumFig>0)
+	{
+		_mgl_glwnd->GetFrame(_mgl_glwnd->curr_fig);
+		_mgl_glwnd->Finish();
+//		glCallList(_mgl_glwnd->curr_fig);
+	}
 	else
 	{
-		(_mgl_glwnd->DrawFunc)(_mgl_glwnd,_mgl_glwnd->FuncPar);
+		if(_mgl_glwnd->DrawFunc)
+			(_mgl_glwnd->DrawFunc)(_mgl_glwnd,_mgl_glwnd->FuncPar);
 		_mgl_glwnd->Finish();
 	}
-	if(_mgl_glwnd->AutoClf)	glFinish();
-	if(_mgl_glwnd->AutoClf)	glutSwapBuffers();
+	glFinish();
 }
 //-----------------------------------------------------------------------------
 mglCanvasGLUT::~mglCanvasGLUT()	{	_mgl_glwnd = 0;	}
@@ -206,13 +209,18 @@ void mglCanvasGLUT::Window(int argc, char **argv,int (*draw)(mglBase *gr, void *
 	char *tmp[1];	tmp[0]=new char[1];	tmp[0][0]=0;
 	glutInit(&argc, argv ? argv:tmp);
 	delete []tmp[0];
-	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
+	glutInitDisplayMode(GLUT_RGB);
 	glutInitWindowSize(600, 600);
 	glutCreateWindow("MathPlotLibrary");
 
 	AddLight(0,mglPoint(0,0,3),false);
-	NumFig = draw(this,par)-1;	Finish();
-	DrawFunc = draw;	FuncPar = par;
+	if(draw)
+	{
+		NumFig = draw(this,par)-1;	Finish();
+		DrawFunc = draw;	FuncPar = par;
+	}
+	else
+	{	NumFig = 0;	DrawFunc=0;	FuncPar=0;	}
 	LoadFunc = reload;
 	glutSetWindowTitle(title);
 
diff --git a/widgets/qt.cpp b/widgets/qt.cpp
index f13dcbc..36fe767 100644
--- a/widgets/qt.cpp
+++ b/widgets/qt.cpp
@@ -94,7 +94,7 @@ QMathGL::QMathGL(QWidget *parent, Qt::WindowFlags f) : QWidget(parent, f)
 	popup = 0;	grBuf = 0;	draw = 0;
 	phi = tet = per = 0;
 	x1 = y1 = ax1 = ay1 = 0;	x2 = y2 = ax2 = ay2 = 1;
-	alpha = light = zoom = rotate = grid = viewYZ = false;
+	alpha = light = zoom = rotate = grid = viewYZ = custZoom = false;
 	resize(600, 400);	mgl_set_flag(gr, true, MGL_CLF_ON_UPD);
 	timer = new QTimer(this);
 	enableWheel = enableMouse = true;
@@ -107,6 +107,21 @@ QMathGL::~QMathGL()
 {
 	if(mgl_use_graph(gr,-1)<1)	mgl_delete_graph(gr);
 	if(grBuf)	delete []grBuf;
+	if(draw)	delete draw;
+}
+//-----------------------------------------------------------------------------
+void QMathGL::setDraw(int (*func)(mglBase *gr, void *par), void *par)
+{
+	if(draw)	delete draw;	draw = 0;
+	draw_func = func;	draw_par = par;
+	emit usePrimChanged(draw_func || draw);
+}
+//-----------------------------------------------------------------------------
+void QMathGL::setDraw(mglDraw *dr)
+{
+	if(draw)	delete draw;
+	draw = dr;	draw_func = 0;
+	emit usePrimChanged(draw_func || draw);
 }
 //-----------------------------------------------------------------------------
 double QMathGL::getRatio()	{	return double(mgl_get_width(gr))/mgl_get_height(gr);	}
@@ -196,6 +211,8 @@ void QMathGL::setZoom(bool z)
 	emit zoomChanged(z);	emit rotateChanged(false);	}
 }
 //-----------------------------------------------------------------------------
+void QMathGL::setCustZoom(bool z)	{	custZoom = z;	}
+//-----------------------------------------------------------------------------
 void QMathGL::shiftDown()
 {	mreal d=(y2-y1)/4;	y1+=d;	y2+=d;	refresh();	}
 //-----------------------------------------------------------------------------
@@ -274,7 +291,9 @@ void QMathGL::update()
 void QMathGL::draw_thr()
 {
 	mgl_clf(gr);
-	mgl_get_frame(gr, mgl_get_num_frame(gr)-1);
+	mglCanvasWnd *g = dynamic_cast<mglCanvasWnd *>(gr);
+	int c = g?g->GetCurFig():mgl_get_num_frame(gr)-1;
+	mgl_get_frame(gr, c);
 	mglParse pr;
 	long i, n=primitives.count('\n');
 	mglGraph gg(gr);
@@ -306,9 +325,13 @@ void QMathGL::refresh()
 			draw_thr();
 /*#endif*/
 		}
-		mgl_zoom(gr,x1,y1,x2,y2);	mgl_perspective(gr,per);
-		if(viewYZ)	mgl_view(gr,0,phi,tet);
-		else 		mgl_view(gr,phi,0,tet);
+		if(custZoom)	emit customZoom(x1,y1,x2,y2,tet,phi,per);
+		else
+		{	mgl_zoom(gr,x1,y1,x2,y2);
+			mgl_perspective(gr,per);
+			if(viewYZ)	mgl_view(gr,0,phi,tet);
+			else 		mgl_view(gr,phi,0,tet);
+		}
 	}
 	mglConvertFromGraph(pic, gr, &grBuf);
 	if(pic.size()!=size())	setSize(pic.width(), pic.height());
@@ -326,7 +349,7 @@ void QMathGL::mousePressEvent(QMouseEvent *ev)
 		emit mouseClick(p.x,p.y,p.z);
 		int id = mgl_get_obj_id(gr,ev->x(),ev->y());
 		if(id<MGL_MAX_LINES)	emit objChanged(id-1);
-		
+
 		p = gr->CalcXYZ(ev->x(), ev->y(), true);
 		if(mgl_isnan(p.x))	mousePos = "";
 		else	mousePos.sprintf("x=%g, y=%g, z=%g",p.x,p.y,p.z);
@@ -1129,7 +1152,7 @@ QMenu *mglMakeMenu(QMainWindow *Wnd, QMathGL *QMGL, QSpinBox *&tet, QSpinBox *&p
 		Wnd->addToolBar(Qt::LeftToolBarArea, bb);
 		a = new QAction(QPixmap(next_sl_xpm), TR("&Next slide"), Wnd);
 		Wnd->connect(a, SIGNAL(triggered()), QMGL, SLOT(nextSlide()));
-		a->setToolTip(TR("Show next slide (Alt+Right)."));
+		a->setToolTip(TR("Show next slide (Ctrl+.)."));
 		a->setShortcut(Qt::CTRL+Qt::Key_Period);	o->addAction(a);		bb->addAction(a);
 		a = new QAction(QPixmap(show_sl_xpm), TR("&Slideshow"), Wnd);
 		a->setCheckable(true);
@@ -1138,7 +1161,7 @@ QMenu *mglMakeMenu(QMainWindow *Wnd, QMathGL *QMGL, QSpinBox *&tet, QSpinBox *&p
 		a->setShortcut(Qt::CTRL+Qt::Key_F5);	o->addAction(a);		bb->addAction(a);
 		a = new QAction(QPixmap(prev_sl_xpm), TR("&Prev slide"), Wnd);
 		Wnd->connect(a, SIGNAL(triggered()), QMGL, SLOT(prevSlide()));
-		a->setToolTip(TR("Show previous slide (Alt+Left)."));
+		a->setToolTip(TR("Show previous slide (Ctrl+,)."));
 		a->setShortcut(Qt::CTRL+Qt::Key_Comma);	o->addAction(a);		bb->addAction(a);
 	}
 
diff --git a/widgets/wx.cpp b/widgets/wx.cpp
index 6256732..c4448d6 100644
--- a/widgets/wx.cpp
+++ b/widgets/wx.cpp
@@ -28,7 +28,7 @@
 #include "mgl2/canvas_wnd.h"
 #include "mgl2/wx.h"
 //-----------------------------------------------------------------------------
-class mglCanvasWX : public mglCanvasWnd
+class MGL_EXPORT mglCanvasWX : public mglCanvasWnd
 {
 friend class wxMathGL;
 public:
@@ -87,12 +87,11 @@ END_EVENT_TABLE()
 wxMathGL::wxMathGL(wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxString& name) : wxWindow(parent,id,pos,size,style,name)
 {
 	AutoResize = false;	draw_par = 0;	draw_func = 0;
-	gr = new mglCanvas;
-	popup = 0;		//!grBuf = 0;
+	gr = new mglCanvas;	popup = 0;
 	phi = tet = per = 0;
 	x1 = y1 = 0;	x2 = y2 = 1;
 	alpha = light = zoom = rotate = false;
-	SetSize(600, 400);
+//	SetSize(600, 400);
 	timer = new wxTimer(this,TIMER_ID);
 }
 //-----------------------------------------------------------------------------
@@ -206,27 +205,20 @@ void wxMathGL::Update()
 	MousePos.Empty();	Repaint();
 }
 //-----------------------------------------------------------------------------
-void convertFromGraph(wxBitmap &pic, mglCanvas *gr, unsigned char **buf)
+wxBitmap MGL_EXPORT ConvertFromGraph(HMGL gr)
 {
 	const unsigned char *bb = mgl_get_rgb(gr);
-	register long i,w=mgl_get_width(gr), h=mgl_get_height(gr);
-	if(*buf) 	delete [](*buf);
-	*buf = new unsigned char[4*w*h];
-	for(i=0;i<w*h;i++)
-	{
-		(*buf)[4*i]   = bb[3*i+2];
-		(*buf)[4*i+1] = bb[3*i+1];
-		(*buf)[4*i+2] = bb[3*i];
-		(*buf)[4*i+3] = 255;
-	}
-	wxImage img(w, h, *buf);
-	wxBitmap bmp(img,32);	pic = bmp;
+	int w=mgl_get_width(gr), h=mgl_get_height(gr);
+	unsigned char *tmp = (unsigned char *)malloc(3*w*h);
+	memcpy(tmp,bb,3*w*h);
+	wxImage img(w, h);	img.SetData(tmp);
+	return wxBitmap(img);
 }
 //-----------------------------------------------------------------------------
 void wxMathGL::Repaint()
 {
 	mgl_zoom(gr,x1,y1,x2,y2);	mgl_view(gr,phi,0,tet);	mgl_perspective(gr, per);
-	convertFromGraph(pic, gr, &grBuf);
+	pic = ConvertFromGraph(gr);
 	wxSize sz=GetSize();
 	if(pic.GetWidth()!=sz.GetWidth() || pic.GetHeight()!=sz.GetHeight())
 		SetSize(pic.GetWidth(), pic.GetHeight());
@@ -428,278 +420,3 @@ void wxMathGL::About()
 	wxMessageBox(s, wxT("MathGL - about"), wxOK|wxICON_INFORMATION, this);
 }
 //-----------------------------------------------------------------------------
-//
-//		class mglCanvasWX
-//
-//-----------------------------------------------------------------------------
-#include <wx/app.h>
-#include "xpm/fileprint.xpm"
-#include "xpm/copy.xpm"
-#include "xpm/left_1.xpm"
-#include "xpm/right_1.xpm"
-#include "xpm/down_1.xpm"
-#include "xpm/norm_1.xpm"
-#include "xpm/zoom_1.xpm"
-#include "xpm/up_1.xpm"
-#include "xpm/alpha.xpm"
-#include "xpm/light.xpm"
-#include "xpm/zoom_in.xpm"
-#include "xpm/zoom_out.xpm"
-#include "xpm/rotate.xpm"
-#include "xpm/ok.xpm"
-#include "xpm/show_sl.xpm"
-#include "xpm/next_sl.xpm"
-#include "xpm/prev_sl.xpm"
-//-----------------------------------------------------------------------------
-mglCanvasWX::mglCanvasWX() : mglCanvasWnd()	{	Wnd = 0;	}
-//-----------------------------------------------------------------------------
-mglCanvasWX::~mglCanvasWX()	{	if(Wnd)	delete Wnd;	}
-//-----------------------------------------------------------------------------
-void mglCanvasWX::ToggleAlpha()	{	WMGL->SetAlpha(!WMGL->GetAlpha());	}
-//-----------------------------------------------------------------------------
-void mglCanvasWX::ToggleLight()	{	WMGL->SetLight(!WMGL->GetLight());	}
-//-----------------------------------------------------------------------------
-void mglCanvasWX::ToggleNo()		{	WMGL->Restore();	}
-//-----------------------------------------------------------------------------
-void mglCanvasWX::ToggleZoom()	{	WMGL->SetZoom(!WMGL->GetZoom());	}
-//-----------------------------------------------------------------------------
-void mglCanvasWX::ToggleRotate()	{	WMGL->SetRotate(!WMGL->GetRotate());}
-//-----------------------------------------------------------------------------
-void mglCanvasWX::Update()		{	WMGL->Update();	}
-//-----------------------------------------------------------------------------
-void mglCanvasWX::Adjust()
-{
-	wxSize sz = scroll->GetSize();
-	SetSize(sz.GetWidth(), sz.GetHeight());
-	WMGL->SetSize(sz.GetWidth(), sz.GetHeight());
-	Update();
-}
-//-----------------------------------------------------------------------------
-void mglCanvasWX::GotoFrame(int d)
-{
-	int f = GetCurFig()+d;
-	if(f>=GetNumFig())	f = 0;
-	if(f<0)	f = GetNumFig()-1;
-	if(GetNumFig()>0 && d)	{	SetCurFig(f);	WMGL->Repaint();	}
-}
-//-----------------------------------------------------------------------------
-void mglCanvasWX::Animation()
-{
-/*	if(anim)
-	{
-		bool s = anim->isChecked();
-		anim->setChecked(!s);
-		WMGL->Animation(!s);
-	}*/
-}
-//-----------------------------------------------------------------------------
-void mglCanvasWX::Window(int argc, char **argv, int (*draw)(mglBase *gr, void *p), const char *title, void *par, void (*reload)(void *p), bool maximize)
-{
-	SetDrawFunc(draw, par, reload);
-	popup = 0;
-	if(Wnd)
-	{
-		Wnd->SetLabel(wxString(title,wxConvLibc));
-		if(maximize)
-		{	Wnd->SetSize(Wnd->GetMaxSize());	}
-		else	Wnd->Show();
-		return;
-	}
-
-	if(!wxTheApp)	{	new wxApp;	wxTheApp->SetExitOnFrameDelete(true);	}
-
-	Wnd = new wxWindow;	Wnd->SetSize(650,480);
-	Wnd->SetLabel(wxString(title,wxConvLibc));
-
-	scroll = new wxScrolledWindow(Wnd);
-	WMGL = new wxMathGL(scroll);	MakeMenu();
-	WMGL->SetPopup(popup);	WMGL->SetGraph(this);
-	WMGL->SetDraw(draw, par);
-
-	WMGL->Update();
-	if(maximize)	Wnd->SetSize(Wnd->GetMaxSize());
-	Wnd->Show();
-}
-//-----------------------------------------------------------------------------
-void mglCanvasWX::MakeMenu()
-{
-/*	wxMenuBar *m = new wxMenuBar;
-	wxMenu *o, *oo;
-	
-	o = new wxMenu;	m->Append(o, wxT("&File"));
-	oo= new wxMenu;	o->AppendSubMenu(oo,wxT("&Export as ..."));
-	o->Append(wxID_EXIT, wxT("&Close"));
-	Wnd->Connect(wxID_EXIT, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(wxWindow::Close));
-*/
-}
-/*void mglGraphQT::makeMenu()
-{
-	QAction *a;
-	QMenu *o, *oo;
-	QToolBar *bb;
-
-	popup = new QMenu(Wnd);
-	// file menu
-	{
-		o = Wnd->menuBar()->addMenu(TR("&File"));
-		oo = new QMenu(TR("&Export as ..."),Wnd);
-		oo->addAction(TR("PNG"), QMGL, SLOT(exportPNG()),Qt::ALT+Qt::Key_P);
-		oo->addAction(TR("solid PNG"), QMGL, SLOT(exportPNGs()),Qt::ALT+Qt::Key_F);
-		oo->addAction(TR("JPEG"), QMGL, SLOT(exportJPG()),Qt::ALT+Qt::Key_J);
-		oo->addAction(TR("bitmap EPS"), QMGL, SLOT(exportBPS()));
-		oo->addAction(TR("vector EPS"), QMGL, SLOT(exportEPS()),Qt::ALT+Qt::Key_E);
-		oo->addAction(TR("SVG"), QMGL, SLOT(exportSVG()),Qt::ALT+Qt::Key_S);
-		oo->addAction(TR("IDTF"), QMGL, SLOT(exportIDTF()));
-		o->addMenu(oo);
-		popup->addMenu(oo);
-
-		o->addSeparator();
-		a = new QAction(QPixmap(fileprint), TR("Print &graphics"), Wnd);
-		Wnd->connect(a, SIGNAL(activated()), QMGL, SLOT(print()));
-		a->setToolTip(TR("Open printer dialog and print graphics\t(CTRl+P)"));
-		a->setShortcut(Qt::CTRL+Qt::Key_P);	o->addAction(a);
-		o->addSeparator();
-		o->addAction(TR("&Close"), Wnd, SLOT(close()), Qt::CTRL+Qt::Key_W);
-	}
-	// graphics menu
-	{
-		bb = new QToolBar(TR("Graphics"),Wnd);
-		Wnd->addToolBar(Qt::TopToolBarArea, bb);
-		o = Wnd->menuBar()->addMenu(TR("&Graphics"));
-		a = new QAction(QPixmap(alpha_xpm), TR("&Alpha"), Wnd);
-		a->setShortcut(Qt::ALT+Qt::Key_T);	a->setCheckable(true);
-		Wnd->connect(a, SIGNAL(toggled(bool)), QMGL, SLOT(setAlpha(bool)));
-		Wnd->connect(QMGL, SIGNAL(alphaChanged(bool)), a, SLOT(setOn(bool)));
-		a->setToolTip(TR("Switch on/off TRansparency for the graphics (Alt+T)."));
-		o->addAction(a);		bb->addAction(a);
-		a = new QAction(QPixmap(light_xpm), TR("&Light"), Wnd);
-		a->setShortcut(Qt::ALT+Qt::Key_L);	a->setCheckable(true);
-		Wnd->connect(a, SIGNAL(toggled(bool)), QMGL, SLOT(setLight(bool)));
-		Wnd->connect(QMGL, SIGNAL(lightChanged(bool)), a, SLOT(setOn(bool)));
-		a->setToolTip(TR("Switch on/off lightning for the graphics (Alt+L)."));
-		o->addAction(a);		bb->addAction(a);
-		a = new QAction(QPixmap(rotate_xpm), TR("&Rotate by mouse"), Wnd);
-		a->setCheckable(true);
-		Wnd->connect(a, SIGNAL(toggled(bool)), QMGL, SLOT(setRotate(bool)));
-		Wnd->connect(QMGL, SIGNAL(rotateChanged(bool)), a, SLOT(setOn(bool)));
-		a->setToolTip(TR("Switch on/off mouse handling of the graphics\n(rotation, shifting, zooming and perspective)."));
-		bb->addAction(a);
-		a = new QAction(QPixmap(zoom_in_xpm), TR("&Zoom by mouse"), Wnd);
-		a->setCheckable(true);
-		Wnd->connect(a, SIGNAL(toggled(bool)), QMGL, SLOT(setZoom(bool)));
-		Wnd->connect(QMGL, SIGNAL(zoomChanged(bool)), a, SLOT(setOn(bool)));
-		a->setToolTip(TR("Switch on/off mouse zoom of selected region."));
-		bb->addAction(a);
-		o->addSeparator();
-		a = new QAction(QPixmap(zoom_out_xpm), TR("Res&tore"), Wnd);
-		Wnd->connect(a, SIGNAL(activated()), QMGL, SLOT(restore()));
-		a->setToolTip(TR("Restore default graphics rotation, zoom and perspective (Alt+Space)."));
-		a->setShortcut(Qt::ALT+Qt::Key_Space);
-		o->addAction(a);	bb->addAction(a);	popup->addAction(a);
-		bb->addSeparator();
-		a = new QAction(QPixmap(ok_xpm), TR("Re&draw"), Wnd);
-		Wnd->connect(a, SIGNAL(activated()), QMGL, SLOT(update()));
-		a->setToolTip(TR("Execute script and redraw graphics (F5)."));
-		a->setShortcut(Qt::Key_F5);
-		o->addAction(a);	bb->addAction(a);	popup->addAction(a);
-		a = new QAction(TR("&Adjust size"), Wnd);
-		Wnd->connect(a, SIGNAL(activated()), QMGL, SLOT(adjust()));
-		a->setToolTip(TR("Change canvas size to fill whole region (F6)."));
-		a->setShortcut(Qt::Key_F6);		o->addAction(a);
-		a = new QAction(QPixmap(copy_xpm), TR("&Copy plot"), Wnd);
-		Wnd->connect(a, SIGNAL(activated()), QMGL, SLOT(copy()));
-		a->setToolTip(TR("Copy graphics to clipboard (CTRl+C)."));
-		a->setShortcut(Qt::CTRL+Qt::Key_C);
-		o->addAction(a);		bb->addAction(a);	popup->addAction(a);
-		bb->addSeparator();
-		tet = new QSpinBox(Wnd);	tet->setWrapping(true);
-		bb->addWidget(tet);	tet->setRange(-180, 180);	tet->setSingleStep(10);
-		Wnd->connect(tet, SIGNAL(valueChanged(int)), QMGL, SLOT(setTet(int)));
-		Wnd->connect(QMGL, SIGNAL(tetChanged(int)), tet, SLOT(setValue(int)));
-		tet->setToolTip(TR("Set value of \\theta angle."));
-		bb->addSeparator();
-		phi = new QSpinBox(Wnd);	phi->setWrapping(true);
-		bb->addWidget(phi);	phi->setRange(-180, 180);	phi->setSingleStep(10);
-		Wnd->connect(phi, SIGNAL(valueChanged(int)), QMGL, SLOT(setPhi(int)));
-		Wnd->connect(QMGL, SIGNAL(phiChanged(int)), phi, SLOT(setValue(int)));
-		phi->setToolTip(TR("Set value of \\phi angle."));
-//	bb->addSeparator();
-	}
-	// zooming menu
-	{
-		oo = o->addMenu(TR("Zoom/move"));
-		bb = new QToolBar(TR("Zoom graphics"),Wnd);
-		Wnd->addToolBar(Qt::LeftToolBarArea, bb);
-		a = new QAction(QPixmap(left_1_xpm), TR("Move &left"), Wnd);
-		Wnd->connect(a, SIGNAL(activated()), QMGL, SLOT(shiftLeft()));
-		a->setToolTip(TR("Move graphics left by 1/3 of its width."));
-		bb->addAction(a);		oo->addAction(a);
-		a = new QAction(QPixmap(up_1_xpm), TR("Move &up"), Wnd);
-		Wnd->connect(a, SIGNAL(activated()), QMGL, SLOT(shiftUp()));
-		a->setToolTip(TR("Move graphics up by 1/3 of its height."));
-		bb->addAction(a);		oo->addAction(a);
-		a = new QAction(QPixmap(zoom_1_xpm), TR("Zoom &in"), Wnd);
-		Wnd->connect(a, SIGNAL(activated()), QMGL, SLOT(zoomIn()));
-		a->setToolTip(TR("Zoom in graphics."));
-		bb->addAction(a);		oo->addAction(a);
-		a = new QAction(QPixmap(norm_1_xpm), TR("Zoom &out"), Wnd);
-		Wnd->connect(a, SIGNAL(activated()), QMGL, SLOT(zoomOut()));
-		a->setToolTip(TR("Zoom out graphics."));
-		bb->addAction(a);		oo->addAction(a);
-		a = new QAction(QPixmap(down_1_xpm), TR("Move &down"), Wnd);
-		Wnd->connect(a, SIGNAL(activated()), QMGL, SLOT(shiftDown()));
-		a->setToolTip(TR("Move graphics up down 1/3 of its height."));
-		bb->addAction(a);		oo->addAction(a);
-		a = new QAction(QPixmap(right_1_xpm), TR("Move &right"), Wnd);
-		Wnd->connect(a, SIGNAL(activated()), QMGL, SLOT(shiftRight()));
-		a->setToolTip(TR("Move graphics right by 1/3 of its width."));
-		bb->addAction(a);		oo->addAction(a);
-	}
-	// animation menu
-	{
-		o = Wnd->menuBar()->addMenu(TR("&Animation"));
-		bb = new QToolBar(TR("Animation"),Wnd);
-		Wnd->addToolBar(Qt::LeftToolBarArea, bb);
-		a = new QAction(QPixmap(next_sl_xpm), TR("&Next slide"), Wnd);
-		Wnd->connect(a, SIGNAL(activated()), QMGL, SLOT(nextSlide()));
-		a->setToolTip(TR("Show next slide (Alt+Right)."));
-		a->setShortcut(Qt::ALT+Qt::Key_Right);	o->addAction(a);		bb->addAction(a);
-		a = new QAction(QPixmap(show_sl_xpm), TR("&Slideshow"), Wnd);
-		a->setCheckable(true);	anim = a;
-		Wnd->connect(a, SIGNAL(toggled(bool)), QMGL, SLOT(animation(bool)));
-		a->setToolTip(TR("Run slideshow (CTRl+F5)."));
-		a->setShortcut(Qt::CTRL+Qt::Key_F5);	o->addAction(a);		bb->addAction(a);
-		a = new QAction(QPixmap(prev_sl_xpm), TR("&Prev slide"), Wnd);
-		Wnd->connect(a, SIGNAL(activated()), QMGL, SLOT(prevSlide()));
-		a->setToolTip(TR("Show previous slide (Alt+Left)."));
-		a->setShortcut(Qt::ALT+Qt::Key_Left);	o->addAction(a);		bb->addAction(a);
-	}
-
-	Wnd->menuBar()->addSeparator();
-	o = Wnd->menuBar()->addMenu(TR("&Help"));
-	o->addAction(TR("About"), QMGL, SLOT(about()));
-	o->addAction(TR("About &Qt"), QMGL, SLOT(aboutQt()));
-}*/
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-HMGL MGL_EXPORT mgl_create_graph_wx(int (*draw)(HMGL gr, void *p), const char *title, void *par, void (*load)(void *p))
-{
-	mglCanvasWX *g = new mglCanvasWX;
-	g->Window(0,0,draw,title,par,load);
-	return g;
-}
-int MGL_EXPORT mgl_wx_run(){	return wxTheApp ? wxTheApp->MainLoop():0;	}
-//-----------------------------------------------------------------------------
-uintptr_t MGL_EXPORT mgl_create_graph_wx_(const char *title, int l)
-{
-	char *s = new char[l+1];	memcpy(s,title,l);	s[l]=0;
-	uintptr_t t = uintptr_t(mgl_create_graph_wx(0,s,0,0));
-	delete []s;	return t;
-}
-int MGL_EXPORT mgl_wx_run_()	{	return mgl_wx_run();	}
-//-----------------------------------------------------------------------------

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/mathgl.git



More information about the debian-science-commits mailing list