From 5b0535a9d30ced6cd7487a14f3fcbed11ebe10b1 Mon Sep 17 00:00:00 2001
From: Christophe Geuzaine <cgeuzaine@ulg.ac.be>
Date: Sat, 26 Jun 2004 17:58:16 +0000
Subject: [PATCH] Merged Netgen 4.3.1: a Delaunay/Frontal 2D/3D mesh generator.

Thanks a lot to Nicolas Tardieu for this!
---
 Common/CommandLine.cpp                     |   13 +-
 Geo/GeoUtils.cpp                           |    4 +-
 Makefile                                   |    4 +-
 Mesh/3D_Mesh.cpp                           |   11 +-
 Mesh/3D_Mesh_Netgen.cpp                    |  179 +
 Mesh/Makefile                              |   18 +-
 Mesh/Mesh.h                                |    9 +-
 Netgen/COPYING.LIB                         |  504 +++
 Netgen/Makefile                            | 2926 ++++++++++++++
 Netgen/NEWS                                |    9 +
 Netgen/README.GMSH                         |   69 +
 Netgen/VERSION                             |    1 +
 Netgen/libsrc/Makefile                     |   38 +
 Netgen/libsrc/csg/Makefile                 |   26 +
 Netgen/libsrc/csg/algprim.cpp              | 1371 +++++++
 Netgen/libsrc/csg/algprim.hpp              |  331 ++
 Netgen/libsrc/csg/brick.cpp                |  409 ++
 Netgen/libsrc/csg/brick.hpp                |   97 +
 Netgen/libsrc/csg/bspline2d.cpp            |  243 ++
 Netgen/libsrc/csg/csg.hpp                  |   43 +
 Netgen/libsrc/csg/csgeom.cpp               | 1067 +++++
 Netgen/libsrc/csg/csgeom.hpp               |  241 ++
 Netgen/libsrc/csg/csgparser.cpp            | 1186 ++++++
 Netgen/libsrc/csg/csgparser_dalibor.cpp    | 1111 ++++++
 Netgen/libsrc/csg/csgscanner.cpp           |  205 +
 Netgen/libsrc/csg/curve2d.cpp              |   78 +
 Netgen/libsrc/csg/curve2d.hpp              |   59 +
 Netgen/libsrc/csg/edgeflw.cpp              | 1399 +++++++
 Netgen/libsrc/csg/edgeflw.hpp              |   90 +
 Netgen/libsrc/csg/explicitcurve2d.cpp      |  160 +
 Netgen/libsrc/csg/explicitcurve2d.hpp      |  109 +
 Netgen/libsrc/csg/extrusion.cpp            |  175 +
 Netgen/libsrc/csg/extrusion.hpp            |   89 +
 Netgen/libsrc/csg/gencyl.cpp               |  209 +
 Netgen/libsrc/csg/gencyl.hpp               |   64 +
 Netgen/libsrc/csg/genmesh.cpp              |  709 ++++
 Netgen/libsrc/csg/geometry.cpp             | 1792 +++++++++
 Netgen/libsrc/csg/geoml.hpp                |   16 +
 Netgen/libsrc/csg/identify.cpp             | 1483 +++++++
 Netgen/libsrc/csg/identify.hpp             |  173 +
 Netgen/libsrc/csg/lex.yy.cpp               | 1834 +++++++++
 Netgen/libsrc/csg/manifold.cpp             |   14 +
 Netgen/libsrc/csg/manifold.hpp             |   22 +
 Netgen/libsrc/csg/meshsurf.cpp             |  178 +
 Netgen/libsrc/csg/meshsurf.hpp             |   85 +
 Netgen/libsrc/csg/polyhedra.cpp            |  288 ++
 Netgen/libsrc/csg/polyhedra.hpp            |   72 +
 Netgen/libsrc/csg/revolution.cpp           |  151 +
 Netgen/libsrc/csg/revolution.hpp           |   65 +
 Netgen/libsrc/csg/singularref.cpp          |  134 +
 Netgen/libsrc/csg/singularref.hpp          |   45 +
 Netgen/libsrc/csg/solid.cpp                | 1285 ++++++
 Netgen/libsrc/csg/solid.hpp                |  163 +
 Netgen/libsrc/csg/specpoin.cpp             | 1369 +++++++
 Netgen/libsrc/csg/specpoin.hpp             |  143 +
 Netgen/libsrc/csg/spline3d.cpp             |  355 ++
 Netgen/libsrc/csg/spline3d.hpp             |   92 +
 Netgen/libsrc/csg/surface.cpp              |  380 ++
 Netgen/libsrc/csg/surface.hpp              |  300 ++
 Netgen/libsrc/csg/triapprox.cpp            |   62 +
 Netgen/libsrc/csg/triapprox.hpp            |   60 +
 Netgen/libsrc/general/Makefile             |   12 +
 Netgen/libsrc/general/array.cpp            |   75 +
 Netgen/libsrc/general/array.hpp            |  471 +++
 Netgen/libsrc/general/autoptr.hpp          |   31 +
 Netgen/libsrc/general/bitarray.cpp         |  132 +
 Netgen/libsrc/general/bitarray.hpp         |  207 +
 Netgen/libsrc/general/dynamicmem.cpp       |  117 +
 Netgen/libsrc/general/dynamicmem.hpp       |   94 +
 Netgen/libsrc/general/flags.cpp            |  330 ++
 Netgen/libsrc/general/flags.hpp            |   83 +
 Netgen/libsrc/general/hashtabl.cpp         |  293 ++
 Netgen/libsrc/general/hashtabl.hpp         |  931 +++++
 Netgen/libsrc/general/moveablemem.cpp      |  241 ++
 Netgen/libsrc/general/moveablemem.hpp      |   97 +
 Netgen/libsrc/general/myadt.hpp            |   43 +
 Netgen/libsrc/general/mystring.cpp         |  383 ++
 Netgen/libsrc/general/mystring.hpp         |  193 +
 Netgen/libsrc/general/ngexception.cpp      |   33 +
 Netgen/libsrc/general/ngexception.hpp      |   30 +
 Netgen/libsrc/general/optmem.cpp           |   59 +
 Netgen/libsrc/general/optmem.hpp           |   36 +
 Netgen/libsrc/general/parthreads.cpp       |   40 +
 Netgen/libsrc/general/parthreads.hpp       |  126 +
 Netgen/libsrc/general/seti.cpp             |   70 +
 Netgen/libsrc/general/seti.hpp             |   45 +
 Netgen/libsrc/general/sort.cpp             |   74 +
 Netgen/libsrc/general/sort.hpp             |   18 +
 Netgen/libsrc/general/spbita2d.cpp         |  172 +
 Netgen/libsrc/general/spbita2d.hpp         |   56 +
 Netgen/libsrc/general/stack.hpp            |  112 +
 Netgen/libsrc/general/symbolta.cpp         |   52 +
 Netgen/libsrc/general/symbolta.hpp         |  158 +
 Netgen/libsrc/general/table.cpp            |  192 +
 Netgen/libsrc/general/table.hpp            |  202 +
 Netgen/libsrc/general/template.hpp         |  422 ++
 Netgen/libsrc/geom2d/Makefile              |   12 +
 Netgen/libsrc/geom2d/genmesh2d.cpp         |  121 +
 Netgen/libsrc/geom2d/geom2dmesh.cpp        |   96 +
 Netgen/libsrc/geom2d/geom2dmesh.hpp        |   38 +
 Netgen/libsrc/geom2d/geometry2d.hpp        |   20 +
 Netgen/libsrc/geom2d/spline2d.cpp          |  350 ++
 Netgen/libsrc/geom2d/spline2d.hpp          |  167 +
 Netgen/libsrc/geom2d/splinegeometry2.cpp   |  224 ++
 Netgen/libsrc/geom2d/splinegeometry2.hpp   |   43 +
 Netgen/libsrc/gprim/Makefile               |   14 +
 Netgen/libsrc/gprim/adtree.cpp             | 2292 +++++++++++
 Netgen/libsrc/gprim/adtree.hpp             |  477 +++
 Netgen/libsrc/gprim/geom2d.cpp             |  485 +++
 Netgen/libsrc/gprim/geom2d.hpp             |  870 ++++
 Netgen/libsrc/gprim/geom3d.cpp             |  640 +++
 Netgen/libsrc/gprim/geom3d.hpp             |  728 ++++
 Netgen/libsrc/gprim/geomfuncs.cpp          |  111 +
 Netgen/libsrc/gprim/geomfuncs.hpp          |  129 +
 Netgen/libsrc/gprim/geomobjects.hpp        |  333 ++
 Netgen/libsrc/gprim/geomobjects2.hpp       |  366 ++
 Netgen/libsrc/gprim/geomops.hpp            |  374 ++
 Netgen/libsrc/gprim/geomops2.hpp           |  428 ++
 Netgen/libsrc/gprim/geomtest3d.cpp         | 1223 ++++++
 Netgen/libsrc/gprim/geomtest3d.hpp         |   80 +
 Netgen/libsrc/gprim/gprim.hpp              |   26 +
 Netgen/libsrc/gprim/testgeom.cpp           |   20 +
 Netgen/libsrc/gprim/transform3d.cpp        |  172 +
 Netgen/libsrc/gprim/transform3d.hpp        |  131 +
 Netgen/libsrc/include/csg.hpp              |    1 +
 Netgen/libsrc/include/geometry2d.hpp       |    1 +
 Netgen/libsrc/include/gprim.hpp            |    1 +
 Netgen/libsrc/include/incvis.hpp           |   33 +
 Netgen/libsrc/include/linalg.hpp           |    1 +
 Netgen/libsrc/include/meshing.hpp          |    1 +
 Netgen/libsrc/include/myadt.hpp            |    1 +
 Netgen/libsrc/include/mydefs.hpp           |   29 +
 Netgen/libsrc/include/occgeom.hpp          |    1 +
 Netgen/libsrc/include/opti.hpp             |    1 +
 Netgen/libsrc/include/stepgeom.hpp         |   10 +
 Netgen/libsrc/include/stepreader.hpp       |    1 +
 Netgen/libsrc/include/stlgeom.hpp          |    1 +
 Netgen/libsrc/include/visual.hpp           |    1 +
 Netgen/libsrc/interface/Makefile           |    7 +
 Netgen/libsrc/interface/importsolution.cpp |  121 +
 Netgen/libsrc/interface/nginterface.cpp    | 1301 ++++++
 Netgen/libsrc/interface/nglib.cpp          |  538 +++
 Netgen/libsrc/interface/printdest.cpp      |   11 +
 Netgen/libsrc/interface/readuser.cpp       |  372 ++
 Netgen/libsrc/interface/writeabaqus.cpp    |  237 ++
 Netgen/libsrc/interface/writediffpack.cpp  |  296 ++
 Netgen/libsrc/interface/writefeap.cpp      |  220 ++
 Netgen/libsrc/interface/writefluent.cpp    |  200 +
 Netgen/libsrc/interface/writepermas.cpp    |  169 +
 Netgen/libsrc/interface/writetecplot.cpp   |  127 +
 Netgen/libsrc/interface/writetochnog.cpp   |  108 +
 Netgen/libsrc/interface/writeuser.cpp      |  729 ++++
 Netgen/libsrc/interface/writeuser.hpp      |  101 +
 Netgen/libsrc/interface/wuchemnitz.cpp     |  309 ++
 Netgen/libsrc/linalg/Makefile              |   13 +
 Netgen/libsrc/linalg/basemat.cpp           |  465 +++
 Netgen/libsrc/linalg/basemat.hpp           |  105 +
 Netgen/libsrc/linalg/densemat.cpp          | 1443 +++++++
 Netgen/libsrc/linalg/densemat.hpp          |  260 ++
 Netgen/libsrc/linalg/linalg.hpp            |   33 +
 Netgen/libsrc/linalg/polynomial.cpp        |  216 +
 Netgen/libsrc/linalg/polynomial.hpp        |   45 +
 Netgen/libsrc/linalg/sparsmat.cpp          | 1703 ++++++++
 Netgen/libsrc/linalg/sparsmat.hpp          |  261 ++
 Netgen/libsrc/linalg/vector.cpp            |  786 ++++
 Netgen/libsrc/linalg/vector.hpp            |  485 +++
 Netgen/libsrc/makefile.inc                 |   46 +
 Netgen/libsrc/makefile.mach.INTEL          |   18 +
 Netgen/libsrc/makefile.mach.LINUX          |   20 +
 Netgen/libsrc/makefile.mach.SGI            |   19 +
 Netgen/libsrc/makefile.mach.SGIGCC         |   53 +
 Netgen/libsrc/makefile.mach.SUN            |   16 +
 Netgen/libsrc/meshing/Makefile             |   16 +
 Netgen/libsrc/meshing/adfront2.cpp         |  535 +++
 Netgen/libsrc/meshing/adfront2.hpp         |  336 ++
 Netgen/libsrc/meshing/adfront3.cpp         |  895 +++++
 Netgen/libsrc/meshing/adfront3.hpp         |  274 ++
 Netgen/libsrc/meshing/bisect.cpp           | 2298 +++++++++++
 Netgen/libsrc/meshing/bisect.hpp           |   71 +
 Netgen/libsrc/meshing/boundarylayer.cpp    |   91 +
 Netgen/libsrc/meshing/boundarylayer.hpp    |    9 +
 Netgen/libsrc/meshing/clusters.cpp         |  253 ++
 Netgen/libsrc/meshing/clusters.hpp         |   42 +
 Netgen/libsrc/meshing/curvedelems.cpp      | 1910 +++++++++
 Netgen/libsrc/meshing/curvedelems.hpp      |  835 ++++
 Netgen/libsrc/meshing/curvedelems2.cpp     |  719 ++++
 Netgen/libsrc/meshing/delaunay.cpp         | 1652 ++++++++
 Netgen/libsrc/meshing/findip.cpp           |  115 +
 Netgen/libsrc/meshing/findip.hpp           |  116 +
 Netgen/libsrc/meshing/geomsearch.cpp       |  265 ++
 Netgen/libsrc/meshing/geomsearch.hpp       |  116 +
 Netgen/libsrc/meshing/global.cpp           |   53 +
 Netgen/libsrc/meshing/global.hpp           |   54 +
 Netgen/libsrc/meshing/hprefinement.cpp     | 3703 +++++++++++++++++
 Netgen/libsrc/meshing/hprefinement.hpp     |   22 +
 Netgen/libsrc/meshing/improve2.cpp         |  766 ++++
 Netgen/libsrc/meshing/improve2.hpp         |   91 +
 Netgen/libsrc/meshing/improve2gen.cpp      |  465 +++
 Netgen/libsrc/meshing/improve3.cpp         | 1950 +++++++++
 Netgen/libsrc/meshing/improve3.hpp         |   50 +
 Netgen/libsrc/meshing/localh.cpp           |  682 ++++
 Netgen/libsrc/meshing/localh.hpp           |  143 +
 Netgen/libsrc/meshing/meshclass.cpp        | 4165 ++++++++++++++++++++
 Netgen/libsrc/meshing/meshclass.hpp        |  591 +++
 Netgen/libsrc/meshing/meshfunc.cpp         |  745 ++++
 Netgen/libsrc/meshing/meshfunc.hpp         |   42 +
 Netgen/libsrc/meshing/meshfunc2d.cpp       |   61 +
 Netgen/libsrc/meshing/meshing.hpp          |   48 +
 Netgen/libsrc/meshing/meshing2.cpp         | 1650 ++++++++
 Netgen/libsrc/meshing/meshing2.hpp         |  149 +
 Netgen/libsrc/meshing/meshing3.cpp         | 1303 ++++++
 Netgen/libsrc/meshing/meshing3.hpp         |  192 +
 Netgen/libsrc/meshing/meshtool.cpp         |  865 ++++
 Netgen/libsrc/meshing/meshtool.hpp         |   82 +
 Netgen/libsrc/meshing/meshtype.cpp         | 1880 +++++++++
 Netgen/libsrc/meshing/meshtype.hpp         |  919 +++++
 Netgen/libsrc/meshing/msghandler.cpp       |  186 +
 Netgen/libsrc/meshing/msghandler.hpp       |   47 +
 Netgen/libsrc/meshing/netrule2.cpp         |  212 +
 Netgen/libsrc/meshing/netrule3.cpp         | 1143 ++++++
 Netgen/libsrc/meshing/parser2.cpp          |  550 +++
 Netgen/libsrc/meshing/parser3.cpp          |  987 +++++
 Netgen/libsrc/meshing/prism2rls.cpp        |  446 +++
 Netgen/libsrc/meshing/pyramid2rls.cpp      |  309 ++
 Netgen/libsrc/meshing/pyramidrls.cpp       |  263 ++
 Netgen/libsrc/meshing/quadrls.cpp          |  743 ++++
 Netgen/libsrc/meshing/refine.cpp           |  549 +++
 Netgen/libsrc/meshing/ruler2.cpp           |  642 +++
 Netgen/libsrc/meshing/ruler2.hpp           |  149 +
 Netgen/libsrc/meshing/ruler3.cpp           | 1177 ++++++
 Netgen/libsrc/meshing/ruler3.hpp           |  210 +
 Netgen/libsrc/meshing/secondorder.cpp      |  454 +++
 Netgen/libsrc/meshing/smoothing2.cpp       |  790 ++++
 Netgen/libsrc/meshing/smoothing3.cpp       | 1557 ++++++++
 Netgen/libsrc/meshing/specials.cpp         |  193 +
 Netgen/libsrc/meshing/specials.hpp         |   16 +
 Netgen/libsrc/meshing/tetrarls.cpp         | 1466 +++++++
 Netgen/libsrc/meshing/topology.cpp         | 1523 +++++++
 Netgen/libsrc/meshing/topology.hpp         |  109 +
 Netgen/libsrc/meshing/triarls.cpp          |  468 +++
 Netgen/libsrc/meshing/zrefine.cpp          |  735 ++++
 Netgen/libsrc/occ/Makefile                 |   11 +
 Netgen/libsrc/occ/occgenmesh.cpp           |  666 ++++
 Netgen/libsrc/occ/occgeom.cpp              |  106 +
 Netgen/libsrc/occ/occgeom.hpp              |  181 +
 Netgen/libsrc/occ/occmeshsurf.cpp          |  387 ++
 Netgen/libsrc/occ/occmeshsurf.hpp          |  175 +
 Netgen/libsrc/opti/Makefile                |   10 +
 Netgen/libsrc/opti/bfgs.cpp                |  367 ++
 Netgen/libsrc/opti/linopt.cpp              |   73 +
 Netgen/libsrc/opti/linsearch.cpp           |  346 ++
 Netgen/libsrc/opti/opti.hpp                |  142 +
 Netgen/libsrc/stlgeom/Makefile             |   11 +
 Netgen/libsrc/stlgeom/meshstlsurface.cpp   | 1118 ++++++
 Netgen/libsrc/stlgeom/meshstlsurface.hpp   |  120 +
 Netgen/libsrc/stlgeom/stlgeom.cpp          | 3477 ++++++++++++++++
 Netgen/libsrc/stlgeom/stlgeom.hpp          |  450 +++
 Netgen/libsrc/stlgeom/stlgeomchart.cpp     |  801 ++++
 Netgen/libsrc/stlgeom/stlgeommesh.cpp      | 1591 ++++++++
 Netgen/libsrc/stlgeom/stlline.cpp          |  780 ++++
 Netgen/libsrc/stlgeom/stlline.hpp          |  188 +
 Netgen/libsrc/stlgeom/stltool.cpp          | 1288 ++++++
 Netgen/libsrc/stlgeom/stltool.hpp          |  271 ++
 Netgen/libsrc/stlgeom/stltopology.cpp      | 1067 +++++
 Netgen/libsrc/stlgeom/stltopology.hpp      |  362 ++
 Netgen/libsrc/visualization/Makefile       |   13 +
 Netgen/libsrc/visualization/meshdoc.cpp    |  615 +++
 Netgen/libsrc/visualization/meshdoc.hpp    |   37 +
 Netgen/libsrc/visualization/mvdraw.cpp     | 1540 ++++++++
 Netgen/libsrc/visualization/mvdraw.hpp     |  352 ++
 Netgen/libsrc/visualization/soldata.hpp    |   41 +
 Netgen/libsrc/visualization/stlmeshing.cpp | 1080 +++++
 Netgen/libsrc/visualization/visual.hpp     |   26 +
 Netgen/libsrc/visualization/vscsg.cpp      |  199 +
 Netgen/libsrc/visualization/vsmesh.cpp     | 2741 +++++++++++++
 Netgen/libsrc/visualization/vssolution.cpp | 2738 +++++++++++++
 Netgen/libsrc/visualization/vssolution.hpp |  212 +
 configure                                  |   59 +
 configure.in                               |   37 +-
 tutorial/t2.geo                            |    4 +-
 tutorial/t5.geo                            |   12 +-
 281 files changed, 120140 insertions(+), 30 deletions(-)
 create mode 100644 Mesh/3D_Mesh_Netgen.cpp
 create mode 100644 Netgen/COPYING.LIB
 create mode 100644 Netgen/Makefile
 create mode 100644 Netgen/NEWS
 create mode 100644 Netgen/README.GMSH
 create mode 100644 Netgen/VERSION
 create mode 100644 Netgen/libsrc/Makefile
 create mode 100644 Netgen/libsrc/csg/Makefile
 create mode 100644 Netgen/libsrc/csg/algprim.cpp
 create mode 100644 Netgen/libsrc/csg/algprim.hpp
 create mode 100644 Netgen/libsrc/csg/brick.cpp
 create mode 100644 Netgen/libsrc/csg/brick.hpp
 create mode 100644 Netgen/libsrc/csg/bspline2d.cpp
 create mode 100644 Netgen/libsrc/csg/csg.hpp
 create mode 100644 Netgen/libsrc/csg/csgeom.cpp
 create mode 100644 Netgen/libsrc/csg/csgeom.hpp
 create mode 100644 Netgen/libsrc/csg/csgparser.cpp
 create mode 100644 Netgen/libsrc/csg/csgparser_dalibor.cpp
 create mode 100644 Netgen/libsrc/csg/csgscanner.cpp
 create mode 100644 Netgen/libsrc/csg/curve2d.cpp
 create mode 100644 Netgen/libsrc/csg/curve2d.hpp
 create mode 100644 Netgen/libsrc/csg/edgeflw.cpp
 create mode 100644 Netgen/libsrc/csg/edgeflw.hpp
 create mode 100644 Netgen/libsrc/csg/explicitcurve2d.cpp
 create mode 100644 Netgen/libsrc/csg/explicitcurve2d.hpp
 create mode 100644 Netgen/libsrc/csg/extrusion.cpp
 create mode 100644 Netgen/libsrc/csg/extrusion.hpp
 create mode 100644 Netgen/libsrc/csg/gencyl.cpp
 create mode 100644 Netgen/libsrc/csg/gencyl.hpp
 create mode 100644 Netgen/libsrc/csg/genmesh.cpp
 create mode 100644 Netgen/libsrc/csg/geometry.cpp
 create mode 100644 Netgen/libsrc/csg/geoml.hpp
 create mode 100644 Netgen/libsrc/csg/identify.cpp
 create mode 100644 Netgen/libsrc/csg/identify.hpp
 create mode 100644 Netgen/libsrc/csg/lex.yy.cpp
 create mode 100644 Netgen/libsrc/csg/manifold.cpp
 create mode 100644 Netgen/libsrc/csg/manifold.hpp
 create mode 100644 Netgen/libsrc/csg/meshsurf.cpp
 create mode 100644 Netgen/libsrc/csg/meshsurf.hpp
 create mode 100644 Netgen/libsrc/csg/polyhedra.cpp
 create mode 100644 Netgen/libsrc/csg/polyhedra.hpp
 create mode 100644 Netgen/libsrc/csg/revolution.cpp
 create mode 100644 Netgen/libsrc/csg/revolution.hpp
 create mode 100644 Netgen/libsrc/csg/singularref.cpp
 create mode 100644 Netgen/libsrc/csg/singularref.hpp
 create mode 100644 Netgen/libsrc/csg/solid.cpp
 create mode 100644 Netgen/libsrc/csg/solid.hpp
 create mode 100644 Netgen/libsrc/csg/specpoin.cpp
 create mode 100644 Netgen/libsrc/csg/specpoin.hpp
 create mode 100644 Netgen/libsrc/csg/spline3d.cpp
 create mode 100644 Netgen/libsrc/csg/spline3d.hpp
 create mode 100644 Netgen/libsrc/csg/surface.cpp
 create mode 100644 Netgen/libsrc/csg/surface.hpp
 create mode 100644 Netgen/libsrc/csg/triapprox.cpp
 create mode 100644 Netgen/libsrc/csg/triapprox.hpp
 create mode 100644 Netgen/libsrc/general/Makefile
 create mode 100644 Netgen/libsrc/general/array.cpp
 create mode 100644 Netgen/libsrc/general/array.hpp
 create mode 100644 Netgen/libsrc/general/autoptr.hpp
 create mode 100644 Netgen/libsrc/general/bitarray.cpp
 create mode 100644 Netgen/libsrc/general/bitarray.hpp
 create mode 100644 Netgen/libsrc/general/dynamicmem.cpp
 create mode 100644 Netgen/libsrc/general/dynamicmem.hpp
 create mode 100644 Netgen/libsrc/general/flags.cpp
 create mode 100644 Netgen/libsrc/general/flags.hpp
 create mode 100644 Netgen/libsrc/general/hashtabl.cpp
 create mode 100644 Netgen/libsrc/general/hashtabl.hpp
 create mode 100644 Netgen/libsrc/general/moveablemem.cpp
 create mode 100644 Netgen/libsrc/general/moveablemem.hpp
 create mode 100644 Netgen/libsrc/general/myadt.hpp
 create mode 100644 Netgen/libsrc/general/mystring.cpp
 create mode 100644 Netgen/libsrc/general/mystring.hpp
 create mode 100644 Netgen/libsrc/general/ngexception.cpp
 create mode 100644 Netgen/libsrc/general/ngexception.hpp
 create mode 100644 Netgen/libsrc/general/optmem.cpp
 create mode 100644 Netgen/libsrc/general/optmem.hpp
 create mode 100644 Netgen/libsrc/general/parthreads.cpp
 create mode 100644 Netgen/libsrc/general/parthreads.hpp
 create mode 100644 Netgen/libsrc/general/seti.cpp
 create mode 100644 Netgen/libsrc/general/seti.hpp
 create mode 100644 Netgen/libsrc/general/sort.cpp
 create mode 100644 Netgen/libsrc/general/sort.hpp
 create mode 100644 Netgen/libsrc/general/spbita2d.cpp
 create mode 100644 Netgen/libsrc/general/spbita2d.hpp
 create mode 100644 Netgen/libsrc/general/stack.hpp
 create mode 100644 Netgen/libsrc/general/symbolta.cpp
 create mode 100644 Netgen/libsrc/general/symbolta.hpp
 create mode 100644 Netgen/libsrc/general/table.cpp
 create mode 100644 Netgen/libsrc/general/table.hpp
 create mode 100644 Netgen/libsrc/general/template.hpp
 create mode 100644 Netgen/libsrc/geom2d/Makefile
 create mode 100644 Netgen/libsrc/geom2d/genmesh2d.cpp
 create mode 100644 Netgen/libsrc/geom2d/geom2dmesh.cpp
 create mode 100644 Netgen/libsrc/geom2d/geom2dmesh.hpp
 create mode 100644 Netgen/libsrc/geom2d/geometry2d.hpp
 create mode 100644 Netgen/libsrc/geom2d/spline2d.cpp
 create mode 100644 Netgen/libsrc/geom2d/spline2d.hpp
 create mode 100644 Netgen/libsrc/geom2d/splinegeometry2.cpp
 create mode 100644 Netgen/libsrc/geom2d/splinegeometry2.hpp
 create mode 100644 Netgen/libsrc/gprim/Makefile
 create mode 100644 Netgen/libsrc/gprim/adtree.cpp
 create mode 100644 Netgen/libsrc/gprim/adtree.hpp
 create mode 100644 Netgen/libsrc/gprim/geom2d.cpp
 create mode 100644 Netgen/libsrc/gprim/geom2d.hpp
 create mode 100644 Netgen/libsrc/gprim/geom3d.cpp
 create mode 100644 Netgen/libsrc/gprim/geom3d.hpp
 create mode 100644 Netgen/libsrc/gprim/geomfuncs.cpp
 create mode 100644 Netgen/libsrc/gprim/geomfuncs.hpp
 create mode 100644 Netgen/libsrc/gprim/geomobjects.hpp
 create mode 100644 Netgen/libsrc/gprim/geomobjects2.hpp
 create mode 100644 Netgen/libsrc/gprim/geomops.hpp
 create mode 100644 Netgen/libsrc/gprim/geomops2.hpp
 create mode 100644 Netgen/libsrc/gprim/geomtest3d.cpp
 create mode 100644 Netgen/libsrc/gprim/geomtest3d.hpp
 create mode 100644 Netgen/libsrc/gprim/gprim.hpp
 create mode 100644 Netgen/libsrc/gprim/testgeom.cpp
 create mode 100644 Netgen/libsrc/gprim/transform3d.cpp
 create mode 100644 Netgen/libsrc/gprim/transform3d.hpp
 create mode 100644 Netgen/libsrc/include/csg.hpp
 create mode 100644 Netgen/libsrc/include/geometry2d.hpp
 create mode 100644 Netgen/libsrc/include/gprim.hpp
 create mode 100644 Netgen/libsrc/include/incvis.hpp
 create mode 100644 Netgen/libsrc/include/linalg.hpp
 create mode 100644 Netgen/libsrc/include/meshing.hpp
 create mode 100644 Netgen/libsrc/include/myadt.hpp
 create mode 100644 Netgen/libsrc/include/mydefs.hpp
 create mode 100644 Netgen/libsrc/include/occgeom.hpp
 create mode 100644 Netgen/libsrc/include/opti.hpp
 create mode 100644 Netgen/libsrc/include/stepgeom.hpp
 create mode 100644 Netgen/libsrc/include/stepreader.hpp
 create mode 100644 Netgen/libsrc/include/stlgeom.hpp
 create mode 100644 Netgen/libsrc/include/visual.hpp
 create mode 100644 Netgen/libsrc/interface/Makefile
 create mode 100644 Netgen/libsrc/interface/importsolution.cpp
 create mode 100644 Netgen/libsrc/interface/nginterface.cpp
 create mode 100644 Netgen/libsrc/interface/nglib.cpp
 create mode 100644 Netgen/libsrc/interface/printdest.cpp
 create mode 100644 Netgen/libsrc/interface/readuser.cpp
 create mode 100644 Netgen/libsrc/interface/writeabaqus.cpp
 create mode 100644 Netgen/libsrc/interface/writediffpack.cpp
 create mode 100644 Netgen/libsrc/interface/writefeap.cpp
 create mode 100644 Netgen/libsrc/interface/writefluent.cpp
 create mode 100644 Netgen/libsrc/interface/writepermas.cpp
 create mode 100644 Netgen/libsrc/interface/writetecplot.cpp
 create mode 100644 Netgen/libsrc/interface/writetochnog.cpp
 create mode 100644 Netgen/libsrc/interface/writeuser.cpp
 create mode 100644 Netgen/libsrc/interface/writeuser.hpp
 create mode 100644 Netgen/libsrc/interface/wuchemnitz.cpp
 create mode 100644 Netgen/libsrc/linalg/Makefile
 create mode 100644 Netgen/libsrc/linalg/basemat.cpp
 create mode 100644 Netgen/libsrc/linalg/basemat.hpp
 create mode 100644 Netgen/libsrc/linalg/densemat.cpp
 create mode 100644 Netgen/libsrc/linalg/densemat.hpp
 create mode 100644 Netgen/libsrc/linalg/linalg.hpp
 create mode 100644 Netgen/libsrc/linalg/polynomial.cpp
 create mode 100644 Netgen/libsrc/linalg/polynomial.hpp
 create mode 100644 Netgen/libsrc/linalg/sparsmat.cpp
 create mode 100644 Netgen/libsrc/linalg/sparsmat.hpp
 create mode 100644 Netgen/libsrc/linalg/vector.cpp
 create mode 100644 Netgen/libsrc/linalg/vector.hpp
 create mode 100644 Netgen/libsrc/makefile.inc
 create mode 100644 Netgen/libsrc/makefile.mach.INTEL
 create mode 100644 Netgen/libsrc/makefile.mach.LINUX
 create mode 100644 Netgen/libsrc/makefile.mach.SGI
 create mode 100644 Netgen/libsrc/makefile.mach.SGIGCC
 create mode 100644 Netgen/libsrc/makefile.mach.SUN
 create mode 100644 Netgen/libsrc/meshing/Makefile
 create mode 100644 Netgen/libsrc/meshing/adfront2.cpp
 create mode 100644 Netgen/libsrc/meshing/adfront2.hpp
 create mode 100644 Netgen/libsrc/meshing/adfront3.cpp
 create mode 100644 Netgen/libsrc/meshing/adfront3.hpp
 create mode 100644 Netgen/libsrc/meshing/bisect.cpp
 create mode 100644 Netgen/libsrc/meshing/bisect.hpp
 create mode 100644 Netgen/libsrc/meshing/boundarylayer.cpp
 create mode 100644 Netgen/libsrc/meshing/boundarylayer.hpp
 create mode 100644 Netgen/libsrc/meshing/clusters.cpp
 create mode 100644 Netgen/libsrc/meshing/clusters.hpp
 create mode 100644 Netgen/libsrc/meshing/curvedelems.cpp
 create mode 100644 Netgen/libsrc/meshing/curvedelems.hpp
 create mode 100644 Netgen/libsrc/meshing/curvedelems2.cpp
 create mode 100644 Netgen/libsrc/meshing/delaunay.cpp
 create mode 100644 Netgen/libsrc/meshing/findip.cpp
 create mode 100644 Netgen/libsrc/meshing/findip.hpp
 create mode 100644 Netgen/libsrc/meshing/geomsearch.cpp
 create mode 100644 Netgen/libsrc/meshing/geomsearch.hpp
 create mode 100644 Netgen/libsrc/meshing/global.cpp
 create mode 100644 Netgen/libsrc/meshing/global.hpp
 create mode 100644 Netgen/libsrc/meshing/hprefinement.cpp
 create mode 100644 Netgen/libsrc/meshing/hprefinement.hpp
 create mode 100644 Netgen/libsrc/meshing/improve2.cpp
 create mode 100644 Netgen/libsrc/meshing/improve2.hpp
 create mode 100644 Netgen/libsrc/meshing/improve2gen.cpp
 create mode 100644 Netgen/libsrc/meshing/improve3.cpp
 create mode 100644 Netgen/libsrc/meshing/improve3.hpp
 create mode 100644 Netgen/libsrc/meshing/localh.cpp
 create mode 100644 Netgen/libsrc/meshing/localh.hpp
 create mode 100644 Netgen/libsrc/meshing/meshclass.cpp
 create mode 100644 Netgen/libsrc/meshing/meshclass.hpp
 create mode 100644 Netgen/libsrc/meshing/meshfunc.cpp
 create mode 100644 Netgen/libsrc/meshing/meshfunc.hpp
 create mode 100644 Netgen/libsrc/meshing/meshfunc2d.cpp
 create mode 100644 Netgen/libsrc/meshing/meshing.hpp
 create mode 100644 Netgen/libsrc/meshing/meshing2.cpp
 create mode 100644 Netgen/libsrc/meshing/meshing2.hpp
 create mode 100644 Netgen/libsrc/meshing/meshing3.cpp
 create mode 100644 Netgen/libsrc/meshing/meshing3.hpp
 create mode 100644 Netgen/libsrc/meshing/meshtool.cpp
 create mode 100644 Netgen/libsrc/meshing/meshtool.hpp
 create mode 100644 Netgen/libsrc/meshing/meshtype.cpp
 create mode 100644 Netgen/libsrc/meshing/meshtype.hpp
 create mode 100644 Netgen/libsrc/meshing/msghandler.cpp
 create mode 100644 Netgen/libsrc/meshing/msghandler.hpp
 create mode 100644 Netgen/libsrc/meshing/netrule2.cpp
 create mode 100644 Netgen/libsrc/meshing/netrule3.cpp
 create mode 100644 Netgen/libsrc/meshing/parser2.cpp
 create mode 100644 Netgen/libsrc/meshing/parser3.cpp
 create mode 100644 Netgen/libsrc/meshing/prism2rls.cpp
 create mode 100644 Netgen/libsrc/meshing/pyramid2rls.cpp
 create mode 100644 Netgen/libsrc/meshing/pyramidrls.cpp
 create mode 100644 Netgen/libsrc/meshing/quadrls.cpp
 create mode 100644 Netgen/libsrc/meshing/refine.cpp
 create mode 100644 Netgen/libsrc/meshing/ruler2.cpp
 create mode 100644 Netgen/libsrc/meshing/ruler2.hpp
 create mode 100644 Netgen/libsrc/meshing/ruler3.cpp
 create mode 100644 Netgen/libsrc/meshing/ruler3.hpp
 create mode 100644 Netgen/libsrc/meshing/secondorder.cpp
 create mode 100644 Netgen/libsrc/meshing/smoothing2.cpp
 create mode 100644 Netgen/libsrc/meshing/smoothing3.cpp
 create mode 100644 Netgen/libsrc/meshing/specials.cpp
 create mode 100644 Netgen/libsrc/meshing/specials.hpp
 create mode 100644 Netgen/libsrc/meshing/tetrarls.cpp
 create mode 100644 Netgen/libsrc/meshing/topology.cpp
 create mode 100644 Netgen/libsrc/meshing/topology.hpp
 create mode 100644 Netgen/libsrc/meshing/triarls.cpp
 create mode 100644 Netgen/libsrc/meshing/zrefine.cpp
 create mode 100644 Netgen/libsrc/occ/Makefile
 create mode 100644 Netgen/libsrc/occ/occgenmesh.cpp
 create mode 100644 Netgen/libsrc/occ/occgeom.cpp
 create mode 100644 Netgen/libsrc/occ/occgeom.hpp
 create mode 100644 Netgen/libsrc/occ/occmeshsurf.cpp
 create mode 100644 Netgen/libsrc/occ/occmeshsurf.hpp
 create mode 100644 Netgen/libsrc/opti/Makefile
 create mode 100644 Netgen/libsrc/opti/bfgs.cpp
 create mode 100644 Netgen/libsrc/opti/linopt.cpp
 create mode 100644 Netgen/libsrc/opti/linsearch.cpp
 create mode 100644 Netgen/libsrc/opti/opti.hpp
 create mode 100644 Netgen/libsrc/stlgeom/Makefile
 create mode 100644 Netgen/libsrc/stlgeom/meshstlsurface.cpp
 create mode 100644 Netgen/libsrc/stlgeom/meshstlsurface.hpp
 create mode 100644 Netgen/libsrc/stlgeom/stlgeom.cpp
 create mode 100644 Netgen/libsrc/stlgeom/stlgeom.hpp
 create mode 100644 Netgen/libsrc/stlgeom/stlgeomchart.cpp
 create mode 100644 Netgen/libsrc/stlgeom/stlgeommesh.cpp
 create mode 100644 Netgen/libsrc/stlgeom/stlline.cpp
 create mode 100644 Netgen/libsrc/stlgeom/stlline.hpp
 create mode 100644 Netgen/libsrc/stlgeom/stltool.cpp
 create mode 100644 Netgen/libsrc/stlgeom/stltool.hpp
 create mode 100644 Netgen/libsrc/stlgeom/stltopology.cpp
 create mode 100644 Netgen/libsrc/stlgeom/stltopology.hpp
 create mode 100644 Netgen/libsrc/visualization/Makefile
 create mode 100644 Netgen/libsrc/visualization/meshdoc.cpp
 create mode 100644 Netgen/libsrc/visualization/meshdoc.hpp
 create mode 100644 Netgen/libsrc/visualization/mvdraw.cpp
 create mode 100644 Netgen/libsrc/visualization/mvdraw.hpp
 create mode 100644 Netgen/libsrc/visualization/soldata.hpp
 create mode 100644 Netgen/libsrc/visualization/stlmeshing.cpp
 create mode 100644 Netgen/libsrc/visualization/visual.hpp
 create mode 100644 Netgen/libsrc/visualization/vscsg.cpp
 create mode 100644 Netgen/libsrc/visualization/vsmesh.cpp
 create mode 100644 Netgen/libsrc/visualization/vssolution.cpp
 create mode 100644 Netgen/libsrc/visualization/vssolution.hpp

diff --git a/Common/CommandLine.cpp b/Common/CommandLine.cpp
index 45504626a2..68d229c245 100644
--- a/Common/CommandLine.cpp
+++ b/Common/CommandLine.cpp
@@ -1,4 +1,4 @@
-// $Id: CommandLine.cpp,v 1.43 2004-06-20 23:25:31 geuzaine Exp $
+// $Id: CommandLine.cpp,v 1.44 2004-06-26 17:58:14 geuzaine Exp $
 //
 // Copyright (C) 1997-2004 C. Geuzaine, J.-F. Remacle
 //
@@ -46,8 +46,6 @@ extern Mesh *THEM;
 char *TheFileNameTab[MAX_OPEN_FILES];
 char *TheBgmFileName = NULL, *TheOptString = NULL;
 
-// *INDENT-OFF*
-
 char gmsh_progname[]  = "Gmsh, a 3D mesh generator with pre- and post-processing facilities" ;
 char gmsh_copyright[] = "Copyright (C) 1997-2004 Christophe Geuzaine and Jean-Francois Remacle";
 char gmsh_version[]   = "Version        : " ;
@@ -74,7 +72,7 @@ void Print_Usage(char *name){
   Msg(DIRECT, "  -saveall              save all elements (discard physical group definitions)");
   Msg(DIRECT, "  -o file               specify mesh output file name");
   Msg(DIRECT, "  -format msh|unv|gref  set output mesh format (default: msh)");
-  Msg(DIRECT, "  -algo iso|tri|aniso   select 2D mesh algorithm (default: iso)");
+  Msg(DIRECT, "  -algo iso|tri|aniso   select mesh algorithm (default: iso)");
   Msg(DIRECT, "  -smooth int           set mesh smoothing (default: 0)");
   Msg(DIRECT, "  -order int            set mesh order (default: 1)");
   Msg(DIRECT, "  -scale float          set global scaling factor (default: 1.0)");
@@ -125,6 +123,9 @@ char *Get_BuildOptions(void)
 #if defined(HAVE_TRIANGLE)
     strcat(opt, "TRIANGLE ");
 #endif
+#if defined(HAVE_NETGEN)
+    strcat(opt, "NETGEN ");
+#endif
 #if defined(HAVE_LIBJPEG)
     strcat(opt, "JPEG ");
 #endif
@@ -142,8 +143,6 @@ char *Get_BuildOptions(void)
   return opt;
 }
 
-// *INDENT-ON*
-
 void Get_Options(int argc, char *argv[], int *nbfiles)
 {
   int i = 1;
@@ -402,6 +401,8 @@ void Get_Options(int argc, char *argv[], int *nbfiles)
             CTX.mesh.algo2d = DELAUNAY_TRIANGLE;
           else if(!strncmp(argv[i], "aniso", 5))
             CTX.mesh.algo2d = DELAUNAY_ANISO;
+          else if(!strncmp(argv[i], "netgen", 6))
+            CTX.mesh.algo3d = FRONTAL_NETGEN;
           else {
             fprintf(stderr, ERROR_STR "Unknown mesh algorithm\n");
             exit(1);
diff --git a/Geo/GeoUtils.cpp b/Geo/GeoUtils.cpp
index 81ce31524f..a7fc3e7095 100644
--- a/Geo/GeoUtils.cpp
+++ b/Geo/GeoUtils.cpp
@@ -1,4 +1,4 @@
-// $Id: GeoUtils.cpp,v 1.2 2004-06-26 05:07:47 geuzaine Exp $
+// $Id: GeoUtils.cpp,v 1.3 2004-06-26 17:58:14 geuzaine Exp $
 //
 // Copyright (C) 1997-2004 C. Geuzaine, J.-F. Remacle
 //
@@ -140,7 +140,7 @@ void setVolumeSurfaces(Volume *v, List_T * loops)
         }
         else{
           List_Add(v->Surfaces, &s);
-	  int tmp = (s->Num > 0) ? 1 : -1;
+	  int tmp = (is > 0) ? 1 : -1;
 	  List_Add(v->SurfacesOrientations, &tmp);
 	}
       }
diff --git a/Makefile b/Makefile
index 7de1722010..373fa57e83 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.353 2004-06-20 23:30:36 geuzaine Exp $
+# $Id: Makefile,v 1.354 2004-06-26 17:58:14 geuzaine Exp $
 #
 # Copyright (C) 1997-2004 C. Geuzaine, J.-F. Remacle
 #
@@ -146,7 +146,7 @@ source: source-common
 
 source-commercial: source-common
 	cd gmsh-${GMSH_VERSION} && rm -rf CVS */CVS */*/CVS */*/*/CVS */.globalrc\
-          MathEval Triangle/triangle.* TODO *.spec doc/gmsh.html doc/FAQ\
+          MathEval Triangle/triangle.* Netgen/NGsrc TODO *.spec doc/gmsh.html doc/FAQ\
           doc/README.cvs utils/commercial ${GMSH_VERSION_FILE}
 	cp -f utils/commercial/README gmsh-${GMSH_VERSION}/README
 	cp -f utils/commercial/LICENSE gmsh-${GMSH_VERSION}/doc/LICENSE
diff --git a/Mesh/3D_Mesh.cpp b/Mesh/3D_Mesh.cpp
index 75d0243c12..f9a6285b14 100644
--- a/Mesh/3D_Mesh.cpp
+++ b/Mesh/3D_Mesh.cpp
@@ -1,4 +1,4 @@
-// $Id: 3D_Mesh.cpp,v 1.60 2004-05-26 00:33:37 geuzaine Exp $
+// $Id: 3D_Mesh.cpp,v 1.61 2004-06-26 17:58:14 geuzaine Exp $
 //
 // Copyright (C) 1997-2004 C. Geuzaine, J.-F. Remacle
 //
@@ -897,8 +897,12 @@ void Maillage_Volume(void *data, void *dum)
   }
   else if(MeshTransfiniteVolume(v)) {
   }
-  else if(v->Typ == 99999) {
-
+  else if(v->Typ != 99999){
+    if (Mesh_Netgen(v)) {
+    }
+  }
+  else if((v->Typ == 99999) && (CTX.mesh.algo3d !=FRONTAL_NETGEN)) {
+    
     Simplexes_New = List_Create(10, 10, sizeof(Simplex *));
     Simplexes_Destroyed = List_Create(10, 10, sizeof(Simplex *));
 
@@ -910,6 +914,7 @@ void Maillage_Volume(void *data, void *dum)
     POINTS_LIST = List_Create(100, 100, sizeof(Vertex *));
     LOCAL->Simplexes = v->Simplexes;
     LOCAL->Vertices = v->Vertices;
+    
 
     for(i = 0; i < List_Nbr(v->Surfaces); i++) {
       List_Read(v->Surfaces, i, &s);
diff --git a/Mesh/3D_Mesh_Netgen.cpp b/Mesh/3D_Mesh_Netgen.cpp
new file mode 100644
index 0000000000..1f8e851751
--- /dev/null
+++ b/Mesh/3D_Mesh_Netgen.cpp
@@ -0,0 +1,179 @@
+// $Id: 3D_Mesh_Netgen.cpp,v 1.1 2004-06-26 17:58:14 geuzaine Exp $
+//
+// Copyright (C) 1997-2004 C. Geuzaine, J.-F. Remacle
+//
+// 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.
+// 
+// Please report all bugs and problems to <gmsh@geuz.org>.
+//
+// Contributor(s):
+//   Nicolas Tardieu
+//
+
+#include "Gmsh.h"
+#include "Mesh.h"
+#include "Numeric.h"
+#include "Context.h"
+
+#if !defined(HAVE_NETGEN)
+
+int Mesh_Netgen(Surface * s)
+{
+  Msg(GERROR, "Netgen is not compiled in this version of Gmsh");
+  return 0;
+}
+
+#else
+
+extern "C"
+{
+#include "nglib.h"
+}
+
+extern Context_T CTX;
+extern Mesh *THEM;
+
+int Mesh_Netgen(Volume * v)
+{
+  if(CTX.mesh.algo3d != FRONTAL_NETGEN)
+    return 0;
+
+  if(THEM->BGM.Typ == ONFILE){
+    Msg(GERROR, "Netgen is not ready to be used with a background mesh");
+    return 0;
+  }
+
+  List_T *lSurfaceVertexList = List_Create(100, 100, sizeof(Vertex*));
+  
+  // ===================================
+  //         GMSH => NETGEN 
+  // ===================================
+  
+  // creates Netgen mesh structure
+  Ng_Init();
+  Ng_Mesh *lNetgenMesh = Ng_NewMesh();
+
+  // Transfert all surface vertices to Netgen
+  for(int i = 0; i < List_Nbr(v->Surfaces); i++) {
+    Surface *s;
+    List_Read(v->Surfaces, i, &s);
+    List_T *lVertexList = Tree2List(s->Vertices);
+    for(int j = 0; j < List_Nbr(lVertexList); j++) {
+      Vertex *lVertex;
+      List_Read(lVertexList, j, &lVertex);
+      // We must *not* add 2 times the same vertex (the same vertex
+      // can belong to several surfaces)
+      if(List_ISearchSeq(lSurfaceVertexList, &lVertex, compareVertex) < 0) {
+	List_Add(lSurfaceVertexList, &lVertex);
+	double tmp[3];
+	tmp[0] = lVertex->Pos.X;
+	tmp[1] = lVertex->Pos.Y;
+	tmp[2] = lVertex->Pos.Z;
+      	Ng_AddPoint(lNetgenMesh, tmp);
+      }
+    }
+    List_Delete(lVertexList) ;
+  }
+      
+  // Transfert all surface simplices to Netgen
+  for(int i = 0; i < List_Nbr(v->Surfaces); i++) {
+    Surface *s;
+    int sign;
+    List_Read(v->Surfaces, i, &s);
+    List_Read(v->SurfacesOrientations, i, &sign);
+    List_T *lSimplexeList = Tree2List(s->Simplexes);
+    for(int j = 0; j < List_Nbr(lSimplexeList); j++) {
+      Simplex *lSimplex;
+      List_Read(lSimplexeList, j, &lSimplex);
+      int tmp[3], index[3];
+      if(sign > 0){
+	index[0] = 0;
+	index[1] = 1;
+	index[2] = 2;
+      }
+      else{
+	index[0] = 0;
+	index[1] = 2;
+	index[2] = 1;
+      }
+      tmp[0] = 1 + List_ISearchSeq(lSurfaceVertexList, &lSimplex->V[index[0]],
+				   compareVertex);
+      tmp[1] = 1 + List_ISearchSeq(lSurfaceVertexList, &lSimplex->V[index[1]],
+				   compareVertex);
+      tmp[2] = 1 + List_ISearchSeq(lSurfaceVertexList, &lSimplex->V[index[2]],
+				   compareVertex);
+      Ng_AddSurfaceElement(lNetgenMesh, NG_TRIG, tmp);
+    }
+    List_Delete(lSimplexeList);
+  }
+
+  // ===================================
+  //            MESHING
+  // ===================================
+  
+  // define Netgen meshing option
+  Ng_Meshing_Parameters mp;
+  mp.maxh = 1;
+  mp.fineness = 1;
+  mp.secondorder = 0;
+
+  // generate Netgen volume mesh
+  Msg(STATUS3, "Meshing volume %d", v->Num);
+  Ng_GenerateVolumeMesh(lNetgenMesh, &mp);
+  
+  // ===================================
+  //            NETGEN => GMSH
+  // ===================================
+  
+  // Gets total number of vertices of Netgen's mesh
+  int lNbOfNGPoints = Ng_GetNP(lNetgenMesh);
+  Vertex **vtable = (Vertex **)Malloc(lNbOfNGPoints * sizeof(Vertex*));
+  
+  // Writes existing surface vertices
+  for(int i = 0; i < List_Nbr(lSurfaceVertexList); i++)
+    List_Read(lSurfaceVertexList, i, &vtable[i]);
+
+  // Writes and transfers new volume vertices
+  for(int i = List_Nbr(lSurfaceVertexList); i < lNbOfNGPoints; i++) {
+    double tmp[3];
+    Ng_GetPoint(lNetgenMesh, i+1, tmp);
+    vtable[i] = Create_Vertex(++(THEM->MaxPointNum), tmp[0], tmp[1], tmp[2], 1., 0);
+    Tree_Add(v->Vertices, &vtable[i]);
+    Tree_Add(THEM->Vertices, &vtable[i]);
+  }
+
+  // Get total number of simplices of Netgen's mesh
+  int lNbOfNGElements = Ng_GetNE(lNetgenMesh);
+  // Transfers new volume simplices
+  for(int i = 1; i <= lNbOfNGElements; i++) {
+    int tmp[4];
+    Ng_GetVolumeElement(lNetgenMesh, i, tmp);
+    Simplex *lSimplex = Create_Simplex(vtable[tmp[0]-1], vtable[tmp[1]-1],
+				       vtable[tmp[2]-1], vtable[tmp[3]-1]);
+    lSimplex->iEnt = v->Num;
+    Tree_Add(v->Simplexes, &lSimplex);
+  }
+
+  List_Delete(lSurfaceVertexList);
+  Free(vtable);
+
+  Ng_DeleteMesh(lNetgenMesh);
+  Ng_Exit();
+
+  return 1;
+}
+
+#endif // !HAVE_NETGEN
diff --git a/Mesh/Makefile b/Mesh/Makefile
index c4a799bb1d..a6e305c2c8 100644
--- a/Mesh/Makefile
+++ b/Mesh/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.65 2004-05-29 10:11:12 geuzaine Exp $
+# $Id: Makefile,v 1.66 2004-06-26 17:58:14 geuzaine Exp $
 #
 # Copyright (C) 1997-2004 C. Geuzaine, J.-F. Remacle
 #
@@ -23,7 +23,8 @@ include ../variables
 
 LIB     = ../lib/libGmshMesh.a
 INCLUDE = -I../Numeric -I../NR -I../Common -I../DataStr -I../Geo -I../Mesh\
-          -I../Graphics -I../Parser -I../Fltk -I../Triangle
+          -I../Graphics -I../Parser -I../Fltk -I../Triangle\
+          -I../Netgen/libsrc/include  -I../Netgen/libsrc/interface
 CFLAGS  = ${OPTIM} ${FLAGS} ${INCLUDE}
 
 SRC = 1D_Mesh.cpp \
@@ -51,6 +52,7 @@ SRC = 1D_Mesh.cpp \
         3D_Coherence.cpp \
         3D_Divide.cpp \
         3D_Bricks.cpp \
+        3D_Mesh_Netgen.cpp \
       MeshQuality.cpp \
       Create.cpp \
       Generator.cpp \
@@ -84,7 +86,10 @@ ${LIB}: ${OBJ}
 
 # Don't optimize 3D_Mesh: it sometimes mysteriously crashes on Linux
 3D_Mesh.o:
-	${CXX} ${FLAGS} ${INCLUDE} -c $<
+	${CXX} ${OPTIM} ${FLAGS} ${INCLUDE} -c $<
+
+3D_Mesh_Netgen.o:
+	${CXX} ${OPTIM} ${FLAGS} ${INCLUDE} -c $<
 
 clean:
 	rm -f *.o
@@ -110,7 +115,7 @@ depend:
   ../Geo/CAD.h ../Mesh/Mesh.h ../Mesh/Vertex.h ../Mesh/Element.h \
   ../Mesh/Simplex.h ../Mesh/Face.h ../Mesh/Edge.h ../Geo/ExtrudeParams.h \
   ../Mesh/STL.h ../Common/VertexArray.h ../Mesh/Metric.h ../Mesh/Matrix.h \
-  Utils.h Create.h 2D_Mesh.h ../Common/Context.h
+  Utils.h Create.h 2D_Mesh.h ../Common/Context.h Interpolation.h
 2D_Transfinite.o: 2D_Transfinite.cpp ../Common/Gmsh.h ../Common/Message.h \
   ../DataStr/Malloc.h ../DataStr/List.h ../DataStr/Tree.h \
   ../DataStr/avl.h ../DataStr/Tools.h ../Geo/Geo.h Mesh.h Vertex.h \
@@ -241,6 +246,11 @@ depend:
   ../DataStr/avl.h ../DataStr/Tools.h ../Numeric/Numeric.h Mesh.h \
   Vertex.h Element.h Simplex.h Face.h Edge.h ../Geo/ExtrudeParams.h STL.h \
   ../Common/VertexArray.h Metric.h Matrix.h
+3D_Mesh_Netgen.o: 3D_Mesh_Netgen.cpp ../Common/Gmsh.h ../Common/Message.h \
+  ../DataStr/Malloc.h ../DataStr/List.h ../DataStr/Tree.h \
+  ../DataStr/avl.h ../DataStr/Tools.h Mesh.h Vertex.h Element.h Simplex.h \
+  Face.h Edge.h ../Geo/ExtrudeParams.h STL.h ../Common/VertexArray.h \
+  Metric.h Matrix.h ../Numeric/Numeric.h ../Common/Context.h
 MeshQuality.o: MeshQuality.cpp ../Common/Gmsh.h ../Common/Message.h \
   ../DataStr/Malloc.h ../DataStr/List.h ../DataStr/Tree.h \
   ../DataStr/avl.h ../DataStr/Tools.h ../Numeric/Numeric.h Mesh.h \
diff --git a/Mesh/Mesh.h b/Mesh/Mesh.h
index 8ef09c18f0..c373ec234c 100644
--- a/Mesh/Mesh.h
+++ b/Mesh/Mesh.h
@@ -465,11 +465,12 @@ int MeshCylindricalSurface(Surface * s);
 int MeshParametricSurface(Surface * s);
 int MeshEllipticSurface(Surface * sur);
 
-int  AlgorithmeMaillage2DAnisotropeModeJF(Surface * s);
+int AlgorithmeMaillage2DAnisotropeModeJF(Surface * s);
 void Maillage_Automatique_VieuxCode(Surface * pS, Mesh * m, int ori);
-int  Mesh_Shewchuk(Surface *s);
+int Mesh_Shewchuk(Surface *s);
+int Mesh_Netgen(Volume * v);
 
-int  Calcule_Contours(Surface * s);
+int Calcule_Contours(Surface * s);
 void Link_Simplexes(List_T * Sim, Tree_T * Tim);
 void Calcule_Z(void *data, void *dum);
 void Calcule_Z_Plan(void *data, void *dum);
@@ -482,7 +483,7 @@ void ReOrientSurfaceMesh(Surface *s);
 double Lc_XYZ(double X, double Y, double Z, Mesh * m);
 void ActionLiss(void *data, void *dummy);
 void ActionLissSurf(void *data, void *dummy);
-int  Recombine(Tree_T *TreeAllVert, Tree_T *TreeAllSimp, Tree_T *TreeAllQuad,
+int Recombine(Tree_T *TreeAllVert, Tree_T *TreeAllSimp, Tree_T *TreeAllQuad,
 		double a);
 void ApplyLcFactor(Mesh *M);
 void ExportLcFieldOnVolume(Mesh * M, char *filename);
diff --git a/Netgen/COPYING.LIB b/Netgen/COPYING.LIB
new file mode 100644
index 0000000000..b1e3f5a263
--- /dev/null
+++ b/Netgen/COPYING.LIB
@@ -0,0 +1,504 @@
+		  GNU LESSER GENERAL PUBLIC LICENSE
+		       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+		  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+			    NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library 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
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/Netgen/Makefile b/Netgen/Makefile
new file mode 100644
index 0000000000..d178bc3492
--- /dev/null
+++ b/Netgen/Makefile
@@ -0,0 +1,2926 @@
+# $Id: Makefile,v 1.1 2004-06-26 17:58:14 geuzaine Exp $
+#
+# Copyright (C) 1997-2004 C. Geuzaine, J.-F. Remacle
+#
+# 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.
+# 
+# Please report all bugs and problems to <gmsh@geuz.org>.
+
+include ../variables
+
+LIB     = ../lib/libGmshNetgen.a
+INCLUDE = -Ilibsrc/include 
+CFLAGS  = ${OPTIM} ${INCLUDE} -DNO_PARALLEL_THREADS
+
+SRC = libsrc/opti/linopt.cpp \
+	libsrc/opti/bfgs.cpp \
+	libsrc/opti/linsearch.cpp \
+	libsrc/meshing/global.cpp \
+	libsrc/meshing/bisect.cpp \
+	libsrc/meshing/meshtool.cpp \
+	libsrc/meshing/refine.cpp \
+	libsrc/meshing/ruler3.cpp \
+	libsrc/meshing/improve3.cpp \
+	libsrc/meshing/smoothing3.cpp \
+	libsrc/meshing/adfront3.cpp \
+	libsrc/meshing/tetrarls.cpp \
+	libsrc/meshing/prism2rls.cpp \
+	libsrc/meshing/pyramidrls.cpp \
+	libsrc/meshing/pyramid2rls.cpp \
+	libsrc/meshing/netrule3.cpp \
+	libsrc/meshing/ruler2.cpp \
+	libsrc/meshing/meshclass.cpp \
+	libsrc/meshing/improve2.cpp \
+	libsrc/meshing/smoothing2.cpp \
+	libsrc/meshing/adfront2.cpp \
+	libsrc/meshing/netrule2.cpp \
+	libsrc/meshing/triarls.cpp \
+	libsrc/meshing/geomsearch.cpp \
+	libsrc/meshing/secondorder.cpp \
+	libsrc/meshing/meshtype.cpp \
+	libsrc/meshing/parser3.cpp \
+	libsrc/meshing/meshing2.cpp \
+	libsrc/meshing/quadrls.cpp \
+	libsrc/meshing/specials.cpp \
+	libsrc/meshing/parser2.cpp \
+	libsrc/meshing/meshing3.cpp \
+	libsrc/meshing/meshfunc.cpp \
+	libsrc/meshing/localh.cpp \
+	libsrc/meshing/improve2gen.cpp \
+	libsrc/meshing/delaunay.cpp \
+	libsrc/meshing/boundarylayer.cpp \
+	libsrc/meshing/msghandler.cpp \
+	libsrc/meshing/meshfunc2d.cpp \
+	libsrc/meshing/topology.cpp \
+	libsrc/meshing/clusters.cpp \
+	libsrc/meshing/curvedelems.cpp \
+	libsrc/meshing/curvedelems2.cpp \
+	libsrc/interface/nglib.cpp \
+	libsrc/gprim/geomtest3d.cpp \
+	libsrc/gprim/geom2d.cpp \
+	libsrc/gprim/geom3d.cpp \
+	libsrc/gprim/adtree.cpp \
+	libsrc/gprim/transform3d.cpp \
+	libsrc/gprim/geomfuncs.cpp \
+	libsrc/linalg/polynomial.cpp \
+	libsrc/linalg/densemat.cpp \
+	libsrc/linalg/vector.cpp \
+	libsrc/csg/algprim.cpp \
+	libsrc/csg/brick.cpp \
+	libsrc/csg/manifold.cpp \
+	libsrc/csg/bspline2d.cpp \
+	libsrc/csg/meshsurf.cpp \
+	libsrc/csg/csgeom.cpp \
+	libsrc/csg/polyhedra.cpp \
+	libsrc/csg/curve2d.cpp \
+	libsrc/csg/singularref.cpp \
+	libsrc/csg/edgeflw.cpp \
+	libsrc/csg/solid.cpp \
+	libsrc/csg/explicitcurve2d.cpp \
+	libsrc/csg/specpoin.cpp \
+	libsrc/csg/gencyl.cpp \
+	libsrc/csg/revolution.cpp \
+	libsrc/csg/genmesh.cpp \
+	libsrc/csg/spline3d.cpp \
+	libsrc/csg/surface.cpp \
+	libsrc/csg/identify.cpp \
+	libsrc/csg/triapprox.cpp \
+	libsrc/geom2d/geom2dmesh.cpp \
+	libsrc/geom2d/spline2d.cpp \
+	libsrc/geom2d/splinegeometry2.cpp \
+	libsrc/geom2d/genmesh2d.cpp \
+	libsrc/stlgeom/meshstlsurface.cpp \
+	libsrc/stlgeom/stlline.cpp \
+	libsrc/stlgeom/stltopology.cpp \
+	libsrc/stlgeom/stltool.cpp \
+	libsrc/stlgeom/stlgeom.cpp \
+	libsrc/stlgeom/stlgeomchart.cpp \
+	libsrc/stlgeom/stlgeommesh.cpp \
+	libsrc/general/moveablemem.cpp \
+	libsrc/general/ngexception.cpp \
+	libsrc/general/table.cpp \
+	libsrc/general/optmem.cpp \
+	libsrc/general/spbita2d.cpp \
+	libsrc/general/hashtabl.cpp \
+	libsrc/general/sort.cpp \
+	libsrc/general/flags.cpp \
+	libsrc/general/seti.cpp \
+	libsrc/general/bitarray.cpp \
+	libsrc/general/array.cpp \
+	libsrc/general/symbolta.cpp \
+	libsrc/general/mystring.cpp 
+
+OBJ = ${SRC:.cpp=.o}
+
+.SUFFIXES: .o .cpp
+
+${LIB}: ${OBJ} 
+	${AR} ${LIB} ${OBJ} 
+	${RANLIB} ${LIB}
+
+.cpp.o:
+	${CXX} ${CFLAGS} -c $< -o ${<:.cpp=.o}
+
+clean:
+	rm -f libsrc/*/*.o
+
+depend:
+	(sed '/^# DO NOT DELETE THIS LINE/q' Makefile && \
+	${CXX} -MM ${CFLAGS} ${SRC} \
+	) >Makefile.new
+	cp Makefile Makefile.bak
+	cp Makefile.new Makefile
+	rm -f Makefile.new
+
+# DO NOT DELETE THIS LINE
+linopt.o: libsrc/opti/linopt.cpp libsrc/include/mystdlib.h \
+  libsrc/include/myadt.hpp libsrc/general/myadt.hpp \
+  libsrc/include/mydefs.hpp libsrc/general/ngexception.hpp \
+  libsrc/general/parthreads.hpp libsrc/general/moveablemem.hpp \
+  libsrc/general/dynamicmem.hpp libsrc/general/template.hpp \
+  libsrc/general/array.hpp libsrc/general/table.hpp \
+  libsrc/general/hashtabl.hpp libsrc/general/symbolta.hpp \
+  libsrc/general/bitarray.hpp libsrc/general/flags.hpp \
+  libsrc/general/spbita2d.hpp libsrc/general/seti.hpp \
+  libsrc/general/optmem.hpp libsrc/general/autoptr.hpp \
+  libsrc/general/sort.hpp libsrc/general/stack.hpp \
+  libsrc/general/mystring.hpp libsrc/include/linalg.hpp \
+  libsrc/linalg/linalg.hpp libsrc/linalg/vector.hpp \
+  libsrc/linalg/densemat.hpp libsrc/linalg/polynomial.hpp \
+  libsrc/opti/opti.hpp
+bfgs.o: libsrc/opti/bfgs.cpp libsrc/include/mystdlib.h \
+  libsrc/include/myadt.hpp libsrc/general/myadt.hpp \
+  libsrc/include/mydefs.hpp libsrc/general/ngexception.hpp \
+  libsrc/general/parthreads.hpp libsrc/general/moveablemem.hpp \
+  libsrc/general/dynamicmem.hpp libsrc/general/template.hpp \
+  libsrc/general/array.hpp libsrc/general/table.hpp \
+  libsrc/general/hashtabl.hpp libsrc/general/symbolta.hpp \
+  libsrc/general/bitarray.hpp libsrc/general/flags.hpp \
+  libsrc/general/spbita2d.hpp libsrc/general/seti.hpp \
+  libsrc/general/optmem.hpp libsrc/general/autoptr.hpp \
+  libsrc/general/sort.hpp libsrc/general/stack.hpp \
+  libsrc/general/mystring.hpp libsrc/include/linalg.hpp \
+  libsrc/linalg/linalg.hpp libsrc/linalg/vector.hpp \
+  libsrc/linalg/densemat.hpp libsrc/linalg/polynomial.hpp \
+  libsrc/opti/opti.hpp
+linsearch.o: libsrc/opti/linsearch.cpp libsrc/include/mystdlib.h \
+  libsrc/include/myadt.hpp libsrc/general/myadt.hpp \
+  libsrc/include/mydefs.hpp libsrc/general/ngexception.hpp \
+  libsrc/general/parthreads.hpp libsrc/general/moveablemem.hpp \
+  libsrc/general/dynamicmem.hpp libsrc/general/template.hpp \
+  libsrc/general/array.hpp libsrc/general/table.hpp \
+  libsrc/general/hashtabl.hpp libsrc/general/symbolta.hpp \
+  libsrc/general/bitarray.hpp libsrc/general/flags.hpp \
+  libsrc/general/spbita2d.hpp libsrc/general/seti.hpp \
+  libsrc/general/optmem.hpp libsrc/general/autoptr.hpp \
+  libsrc/general/sort.hpp libsrc/general/stack.hpp \
+  libsrc/general/mystring.hpp libsrc/include/linalg.hpp \
+  libsrc/linalg/linalg.hpp libsrc/linalg/vector.hpp \
+  libsrc/linalg/densemat.hpp libsrc/linalg/polynomial.hpp \
+  libsrc/opti/opti.hpp
+global.o: libsrc/meshing/global.cpp libsrc/include/mystdlib.h \
+  libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \
+  libsrc/general/myadt.hpp libsrc/include/mydefs.hpp \
+  libsrc/general/ngexception.hpp libsrc/general/parthreads.hpp \
+  libsrc/general/moveablemem.hpp libsrc/general/dynamicmem.hpp \
+  libsrc/general/template.hpp libsrc/general/array.hpp \
+  libsrc/general/table.hpp libsrc/general/hashtabl.hpp \
+  libsrc/general/symbolta.hpp libsrc/general/bitarray.hpp \
+  libsrc/general/flags.hpp libsrc/general/spbita2d.hpp \
+  libsrc/general/seti.hpp libsrc/general/optmem.hpp \
+  libsrc/general/autoptr.hpp libsrc/general/sort.hpp \
+  libsrc/general/stack.hpp libsrc/general/mystring.hpp \
+  libsrc/include/gprim.hpp libsrc/gprim/gprim.hpp \
+  libsrc/gprim/geomobjects.hpp libsrc/gprim/geomops.hpp \
+  libsrc/gprim/geomfuncs.hpp libsrc/gprim/geom2d.hpp \
+  libsrc/gprim/geom3d.hpp libsrc/gprim/geomtest3d.hpp \
+  libsrc/gprim/transform3d.hpp libsrc/gprim/adtree.hpp \
+  libsrc/include/linalg.hpp libsrc/linalg/linalg.hpp \
+  libsrc/linalg/vector.hpp libsrc/linalg/densemat.hpp \
+  libsrc/linalg/polynomial.hpp libsrc/include/opti.hpp \
+  libsrc/opti/opti.hpp libsrc/meshing/msghandler.hpp \
+  libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \
+  libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \
+  libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \
+  libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \
+  libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \
+  libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \
+  libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \
+  libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \
+  libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \
+  libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \
+  libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \
+  libsrc/meshing/specials.hpp
+bisect.o: libsrc/meshing/bisect.cpp libsrc/include/mystdlib.h \
+  libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \
+  libsrc/general/myadt.hpp libsrc/include/mydefs.hpp \
+  libsrc/general/ngexception.hpp libsrc/general/parthreads.hpp \
+  libsrc/general/moveablemem.hpp libsrc/general/dynamicmem.hpp \
+  libsrc/general/template.hpp libsrc/general/array.hpp \
+  libsrc/general/table.hpp libsrc/general/hashtabl.hpp \
+  libsrc/general/symbolta.hpp libsrc/general/bitarray.hpp \
+  libsrc/general/flags.hpp libsrc/general/spbita2d.hpp \
+  libsrc/general/seti.hpp libsrc/general/optmem.hpp \
+  libsrc/general/autoptr.hpp libsrc/general/sort.hpp \
+  libsrc/general/stack.hpp libsrc/general/mystring.hpp \
+  libsrc/include/gprim.hpp libsrc/gprim/gprim.hpp \
+  libsrc/gprim/geomobjects.hpp libsrc/gprim/geomops.hpp \
+  libsrc/gprim/geomfuncs.hpp libsrc/gprim/geom2d.hpp \
+  libsrc/gprim/geom3d.hpp libsrc/gprim/geomtest3d.hpp \
+  libsrc/gprim/transform3d.hpp libsrc/gprim/adtree.hpp \
+  libsrc/include/linalg.hpp libsrc/linalg/linalg.hpp \
+  libsrc/linalg/vector.hpp libsrc/linalg/densemat.hpp \
+  libsrc/linalg/polynomial.hpp libsrc/include/opti.hpp \
+  libsrc/opti/opti.hpp libsrc/meshing/msghandler.hpp \
+  libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \
+  libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \
+  libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \
+  libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \
+  libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \
+  libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \
+  libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \
+  libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \
+  libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \
+  libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \
+  libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \
+  libsrc/meshing/specials.hpp libsrc/interface/writeuser.hpp
+meshtool.o: libsrc/meshing/meshtool.cpp libsrc/include/mystdlib.h \
+  libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \
+  libsrc/general/myadt.hpp libsrc/include/mydefs.hpp \
+  libsrc/general/ngexception.hpp libsrc/general/parthreads.hpp \
+  libsrc/general/moveablemem.hpp libsrc/general/dynamicmem.hpp \
+  libsrc/general/template.hpp libsrc/general/array.hpp \
+  libsrc/general/table.hpp libsrc/general/hashtabl.hpp \
+  libsrc/general/symbolta.hpp libsrc/general/bitarray.hpp \
+  libsrc/general/flags.hpp libsrc/general/spbita2d.hpp \
+  libsrc/general/seti.hpp libsrc/general/optmem.hpp \
+  libsrc/general/autoptr.hpp libsrc/general/sort.hpp \
+  libsrc/general/stack.hpp libsrc/general/mystring.hpp \
+  libsrc/include/gprim.hpp libsrc/gprim/gprim.hpp \
+  libsrc/gprim/geomobjects.hpp libsrc/gprim/geomops.hpp \
+  libsrc/gprim/geomfuncs.hpp libsrc/gprim/geom2d.hpp \
+  libsrc/gprim/geom3d.hpp libsrc/gprim/geomtest3d.hpp \
+  libsrc/gprim/transform3d.hpp libsrc/gprim/adtree.hpp \
+  libsrc/include/linalg.hpp libsrc/linalg/linalg.hpp \
+  libsrc/linalg/vector.hpp libsrc/linalg/densemat.hpp \
+  libsrc/linalg/polynomial.hpp libsrc/include/opti.hpp \
+  libsrc/opti/opti.hpp libsrc/meshing/msghandler.hpp \
+  libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \
+  libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \
+  libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \
+  libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \
+  libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \
+  libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \
+  libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \
+  libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \
+  libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \
+  libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \
+  libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \
+  libsrc/meshing/specials.hpp libsrc/include/csg.hpp libsrc/csg/csg.hpp \
+  libsrc/include/meshing.hpp libsrc/csg/surface.hpp libsrc/csg/solid.hpp \
+  libsrc/csg/identify.hpp libsrc/csg/singularref.hpp \
+  libsrc/csg/csgeom.hpp libsrc/csg/triapprox.hpp libsrc/csg/algprim.hpp \
+  libsrc/csg/brick.hpp libsrc/csg/spline3d.hpp libsrc/csg/manifold.hpp \
+  libsrc/csg/curve2d.hpp libsrc/csg/explicitcurve2d.hpp \
+  libsrc/csg/gencyl.hpp libsrc/csg/polyhedra.hpp libsrc/csg/extrusion.hpp \
+  libsrc/csg/revolution.hpp libsrc/csg/specpoin.hpp \
+  libsrc/csg/edgeflw.hpp libsrc/csg/meshsurf.hpp \
+  libsrc/include/geometry2d.hpp libsrc/geom2d/geometry2d.hpp \
+  libsrc/geom2d/spline2d.hpp libsrc/geom2d/splinegeometry2.hpp \
+  libsrc/geom2d/geom2dmesh.hpp
+refine.o: libsrc/meshing/refine.cpp libsrc/include/mystdlib.h \
+  libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \
+  libsrc/general/myadt.hpp libsrc/include/mydefs.hpp \
+  libsrc/general/ngexception.hpp libsrc/general/parthreads.hpp \
+  libsrc/general/moveablemem.hpp libsrc/general/dynamicmem.hpp \
+  libsrc/general/template.hpp libsrc/general/array.hpp \
+  libsrc/general/table.hpp libsrc/general/hashtabl.hpp \
+  libsrc/general/symbolta.hpp libsrc/general/bitarray.hpp \
+  libsrc/general/flags.hpp libsrc/general/spbita2d.hpp \
+  libsrc/general/seti.hpp libsrc/general/optmem.hpp \
+  libsrc/general/autoptr.hpp libsrc/general/sort.hpp \
+  libsrc/general/stack.hpp libsrc/general/mystring.hpp \
+  libsrc/include/gprim.hpp libsrc/gprim/gprim.hpp \
+  libsrc/gprim/geomobjects.hpp libsrc/gprim/geomops.hpp \
+  libsrc/gprim/geomfuncs.hpp libsrc/gprim/geom2d.hpp \
+  libsrc/gprim/geom3d.hpp libsrc/gprim/geomtest3d.hpp \
+  libsrc/gprim/transform3d.hpp libsrc/gprim/adtree.hpp \
+  libsrc/include/linalg.hpp libsrc/linalg/linalg.hpp \
+  libsrc/linalg/vector.hpp libsrc/linalg/densemat.hpp \
+  libsrc/linalg/polynomial.hpp libsrc/include/opti.hpp \
+  libsrc/opti/opti.hpp libsrc/meshing/msghandler.hpp \
+  libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \
+  libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \
+  libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \
+  libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \
+  libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \
+  libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \
+  libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \
+  libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \
+  libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \
+  libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \
+  libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \
+  libsrc/meshing/specials.hpp
+ruler3.o: libsrc/meshing/ruler3.cpp libsrc/include/mystdlib.h \
+  libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \
+  libsrc/general/myadt.hpp libsrc/include/mydefs.hpp \
+  libsrc/general/ngexception.hpp libsrc/general/parthreads.hpp \
+  libsrc/general/moveablemem.hpp libsrc/general/dynamicmem.hpp \
+  libsrc/general/template.hpp libsrc/general/array.hpp \
+  libsrc/general/table.hpp libsrc/general/hashtabl.hpp \
+  libsrc/general/symbolta.hpp libsrc/general/bitarray.hpp \
+  libsrc/general/flags.hpp libsrc/general/spbita2d.hpp \
+  libsrc/general/seti.hpp libsrc/general/optmem.hpp \
+  libsrc/general/autoptr.hpp libsrc/general/sort.hpp \
+  libsrc/general/stack.hpp libsrc/general/mystring.hpp \
+  libsrc/include/gprim.hpp libsrc/gprim/gprim.hpp \
+  libsrc/gprim/geomobjects.hpp libsrc/gprim/geomops.hpp \
+  libsrc/gprim/geomfuncs.hpp libsrc/gprim/geom2d.hpp \
+  libsrc/gprim/geom3d.hpp libsrc/gprim/geomtest3d.hpp \
+  libsrc/gprim/transform3d.hpp libsrc/gprim/adtree.hpp \
+  libsrc/include/linalg.hpp libsrc/linalg/linalg.hpp \
+  libsrc/linalg/vector.hpp libsrc/linalg/densemat.hpp \
+  libsrc/linalg/polynomial.hpp libsrc/include/opti.hpp \
+  libsrc/opti/opti.hpp libsrc/meshing/msghandler.hpp \
+  libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \
+  libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \
+  libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \
+  libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \
+  libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \
+  libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \
+  libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \
+  libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \
+  libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \
+  libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \
+  libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \
+  libsrc/meshing/specials.hpp
+improve3.o: libsrc/meshing/improve3.cpp libsrc/include/mystdlib.h \
+  libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \
+  libsrc/general/myadt.hpp libsrc/include/mydefs.hpp \
+  libsrc/general/ngexception.hpp libsrc/general/parthreads.hpp \
+  libsrc/general/moveablemem.hpp libsrc/general/dynamicmem.hpp \
+  libsrc/general/template.hpp libsrc/general/array.hpp \
+  libsrc/general/table.hpp libsrc/general/hashtabl.hpp \
+  libsrc/general/symbolta.hpp libsrc/general/bitarray.hpp \
+  libsrc/general/flags.hpp libsrc/general/spbita2d.hpp \
+  libsrc/general/seti.hpp libsrc/general/optmem.hpp \
+  libsrc/general/autoptr.hpp libsrc/general/sort.hpp \
+  libsrc/general/stack.hpp libsrc/general/mystring.hpp \
+  libsrc/include/gprim.hpp libsrc/gprim/gprim.hpp \
+  libsrc/gprim/geomobjects.hpp libsrc/gprim/geomops.hpp \
+  libsrc/gprim/geomfuncs.hpp libsrc/gprim/geom2d.hpp \
+  libsrc/gprim/geom3d.hpp libsrc/gprim/geomtest3d.hpp \
+  libsrc/gprim/transform3d.hpp libsrc/gprim/adtree.hpp \
+  libsrc/include/linalg.hpp libsrc/linalg/linalg.hpp \
+  libsrc/linalg/vector.hpp libsrc/linalg/densemat.hpp \
+  libsrc/linalg/polynomial.hpp libsrc/include/opti.hpp \
+  libsrc/opti/opti.hpp libsrc/meshing/msghandler.hpp \
+  libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \
+  libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \
+  libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \
+  libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \
+  libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \
+  libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \
+  libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \
+  libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \
+  libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \
+  libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \
+  libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \
+  libsrc/meshing/specials.hpp
+smoothing3.o: libsrc/meshing/smoothing3.cpp libsrc/include/mystdlib.h \
+  libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \
+  libsrc/general/myadt.hpp libsrc/include/mydefs.hpp \
+  libsrc/general/ngexception.hpp libsrc/general/parthreads.hpp \
+  libsrc/general/moveablemem.hpp libsrc/general/dynamicmem.hpp \
+  libsrc/general/template.hpp libsrc/general/array.hpp \
+  libsrc/general/table.hpp libsrc/general/hashtabl.hpp \
+  libsrc/general/symbolta.hpp libsrc/general/bitarray.hpp \
+  libsrc/general/flags.hpp libsrc/general/spbita2d.hpp \
+  libsrc/general/seti.hpp libsrc/general/optmem.hpp \
+  libsrc/general/autoptr.hpp libsrc/general/sort.hpp \
+  libsrc/general/stack.hpp libsrc/general/mystring.hpp \
+  libsrc/include/gprim.hpp libsrc/gprim/gprim.hpp \
+  libsrc/gprim/geomobjects.hpp libsrc/gprim/geomops.hpp \
+  libsrc/gprim/geomfuncs.hpp libsrc/gprim/geom2d.hpp \
+  libsrc/gprim/geom3d.hpp libsrc/gprim/geomtest3d.hpp \
+  libsrc/gprim/transform3d.hpp libsrc/gprim/adtree.hpp \
+  libsrc/include/linalg.hpp libsrc/linalg/linalg.hpp \
+  libsrc/linalg/vector.hpp libsrc/linalg/densemat.hpp \
+  libsrc/linalg/polynomial.hpp libsrc/include/opti.hpp \
+  libsrc/opti/opti.hpp libsrc/meshing/msghandler.hpp \
+  libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \
+  libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \
+  libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \
+  libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \
+  libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \
+  libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \
+  libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \
+  libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \
+  libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \
+  libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \
+  libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \
+  libsrc/meshing/specials.hpp
+adfront3.o: libsrc/meshing/adfront3.cpp libsrc/include/mystdlib.h \
+  libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \
+  libsrc/general/myadt.hpp libsrc/include/mydefs.hpp \
+  libsrc/general/ngexception.hpp libsrc/general/parthreads.hpp \
+  libsrc/general/moveablemem.hpp libsrc/general/dynamicmem.hpp \
+  libsrc/general/template.hpp libsrc/general/array.hpp \
+  libsrc/general/table.hpp libsrc/general/hashtabl.hpp \
+  libsrc/general/symbolta.hpp libsrc/general/bitarray.hpp \
+  libsrc/general/flags.hpp libsrc/general/spbita2d.hpp \
+  libsrc/general/seti.hpp libsrc/general/optmem.hpp \
+  libsrc/general/autoptr.hpp libsrc/general/sort.hpp \
+  libsrc/general/stack.hpp libsrc/general/mystring.hpp \
+  libsrc/include/gprim.hpp libsrc/gprim/gprim.hpp \
+  libsrc/gprim/geomobjects.hpp libsrc/gprim/geomops.hpp \
+  libsrc/gprim/geomfuncs.hpp libsrc/gprim/geom2d.hpp \
+  libsrc/gprim/geom3d.hpp libsrc/gprim/geomtest3d.hpp \
+  libsrc/gprim/transform3d.hpp libsrc/gprim/adtree.hpp \
+  libsrc/include/linalg.hpp libsrc/linalg/linalg.hpp \
+  libsrc/linalg/vector.hpp libsrc/linalg/densemat.hpp \
+  libsrc/linalg/polynomial.hpp libsrc/include/opti.hpp \
+  libsrc/opti/opti.hpp libsrc/meshing/msghandler.hpp \
+  libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \
+  libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \
+  libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \
+  libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \
+  libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \
+  libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \
+  libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \
+  libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \
+  libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \
+  libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \
+  libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \
+  libsrc/meshing/specials.hpp
+tetrarls.o: libsrc/meshing/tetrarls.cpp
+prism2rls.o: libsrc/meshing/prism2rls.cpp
+pyramidrls.o: libsrc/meshing/pyramidrls.cpp
+pyramid2rls.o: libsrc/meshing/pyramid2rls.cpp
+netrule3.o: libsrc/meshing/netrule3.cpp libsrc/include/mystdlib.h \
+  libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \
+  libsrc/general/myadt.hpp libsrc/include/mydefs.hpp \
+  libsrc/general/ngexception.hpp libsrc/general/parthreads.hpp \
+  libsrc/general/moveablemem.hpp libsrc/general/dynamicmem.hpp \
+  libsrc/general/template.hpp libsrc/general/array.hpp \
+  libsrc/general/table.hpp libsrc/general/hashtabl.hpp \
+  libsrc/general/symbolta.hpp libsrc/general/bitarray.hpp \
+  libsrc/general/flags.hpp libsrc/general/spbita2d.hpp \
+  libsrc/general/seti.hpp libsrc/general/optmem.hpp \
+  libsrc/general/autoptr.hpp libsrc/general/sort.hpp \
+  libsrc/general/stack.hpp libsrc/general/mystring.hpp \
+  libsrc/include/gprim.hpp libsrc/gprim/gprim.hpp \
+  libsrc/gprim/geomobjects.hpp libsrc/gprim/geomops.hpp \
+  libsrc/gprim/geomfuncs.hpp libsrc/gprim/geom2d.hpp \
+  libsrc/gprim/geom3d.hpp libsrc/gprim/geomtest3d.hpp \
+  libsrc/gprim/transform3d.hpp libsrc/gprim/adtree.hpp \
+  libsrc/include/linalg.hpp libsrc/linalg/linalg.hpp \
+  libsrc/linalg/vector.hpp libsrc/linalg/densemat.hpp \
+  libsrc/linalg/polynomial.hpp libsrc/include/opti.hpp \
+  libsrc/opti/opti.hpp libsrc/meshing/msghandler.hpp \
+  libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \
+  libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \
+  libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \
+  libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \
+  libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \
+  libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \
+  libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \
+  libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \
+  libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \
+  libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \
+  libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \
+  libsrc/meshing/specials.hpp
+ruler2.o: libsrc/meshing/ruler2.cpp libsrc/include/mystdlib.h \
+  libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \
+  libsrc/general/myadt.hpp libsrc/include/mydefs.hpp \
+  libsrc/general/ngexception.hpp libsrc/general/parthreads.hpp \
+  libsrc/general/moveablemem.hpp libsrc/general/dynamicmem.hpp \
+  libsrc/general/template.hpp libsrc/general/array.hpp \
+  libsrc/general/table.hpp libsrc/general/hashtabl.hpp \
+  libsrc/general/symbolta.hpp libsrc/general/bitarray.hpp \
+  libsrc/general/flags.hpp libsrc/general/spbita2d.hpp \
+  libsrc/general/seti.hpp libsrc/general/optmem.hpp \
+  libsrc/general/autoptr.hpp libsrc/general/sort.hpp \
+  libsrc/general/stack.hpp libsrc/general/mystring.hpp \
+  libsrc/include/gprim.hpp libsrc/gprim/gprim.hpp \
+  libsrc/gprim/geomobjects.hpp libsrc/gprim/geomops.hpp \
+  libsrc/gprim/geomfuncs.hpp libsrc/gprim/geom2d.hpp \
+  libsrc/gprim/geom3d.hpp libsrc/gprim/geomtest3d.hpp \
+  libsrc/gprim/transform3d.hpp libsrc/gprim/adtree.hpp \
+  libsrc/include/linalg.hpp libsrc/linalg/linalg.hpp \
+  libsrc/linalg/vector.hpp libsrc/linalg/densemat.hpp \
+  libsrc/linalg/polynomial.hpp libsrc/include/opti.hpp \
+  libsrc/opti/opti.hpp libsrc/meshing/msghandler.hpp \
+  libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \
+  libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \
+  libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \
+  libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \
+  libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \
+  libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \
+  libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \
+  libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \
+  libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \
+  libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \
+  libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \
+  libsrc/meshing/specials.hpp
+meshclass.o: libsrc/meshing/meshclass.cpp libsrc/include/mystdlib.h \
+  libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \
+  libsrc/general/myadt.hpp libsrc/include/mydefs.hpp \
+  libsrc/general/ngexception.hpp libsrc/general/parthreads.hpp \
+  libsrc/general/moveablemem.hpp libsrc/general/dynamicmem.hpp \
+  libsrc/general/template.hpp libsrc/general/array.hpp \
+  libsrc/general/table.hpp libsrc/general/hashtabl.hpp \
+  libsrc/general/symbolta.hpp libsrc/general/bitarray.hpp \
+  libsrc/general/flags.hpp libsrc/general/spbita2d.hpp \
+  libsrc/general/seti.hpp libsrc/general/optmem.hpp \
+  libsrc/general/autoptr.hpp libsrc/general/sort.hpp \
+  libsrc/general/stack.hpp libsrc/general/mystring.hpp \
+  libsrc/include/gprim.hpp libsrc/gprim/gprim.hpp \
+  libsrc/gprim/geomobjects.hpp libsrc/gprim/geomops.hpp \
+  libsrc/gprim/geomfuncs.hpp libsrc/gprim/geom2d.hpp \
+  libsrc/gprim/geom3d.hpp libsrc/gprim/geomtest3d.hpp \
+  libsrc/gprim/transform3d.hpp libsrc/gprim/adtree.hpp \
+  libsrc/include/linalg.hpp libsrc/linalg/linalg.hpp \
+  libsrc/linalg/vector.hpp libsrc/linalg/densemat.hpp \
+  libsrc/linalg/polynomial.hpp libsrc/include/opti.hpp \
+  libsrc/opti/opti.hpp libsrc/meshing/msghandler.hpp \
+  libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \
+  libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \
+  libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \
+  libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \
+  libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \
+  libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \
+  libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \
+  libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \
+  libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \
+  libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \
+  libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \
+  libsrc/meshing/specials.hpp
+improve2.o: libsrc/meshing/improve2.cpp libsrc/include/mystdlib.h \
+  libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \
+  libsrc/general/myadt.hpp libsrc/include/mydefs.hpp \
+  libsrc/general/ngexception.hpp libsrc/general/parthreads.hpp \
+  libsrc/general/moveablemem.hpp libsrc/general/dynamicmem.hpp \
+  libsrc/general/template.hpp libsrc/general/array.hpp \
+  libsrc/general/table.hpp libsrc/general/hashtabl.hpp \
+  libsrc/general/symbolta.hpp libsrc/general/bitarray.hpp \
+  libsrc/general/flags.hpp libsrc/general/spbita2d.hpp \
+  libsrc/general/seti.hpp libsrc/general/optmem.hpp \
+  libsrc/general/autoptr.hpp libsrc/general/sort.hpp \
+  libsrc/general/stack.hpp libsrc/general/mystring.hpp \
+  libsrc/include/gprim.hpp libsrc/gprim/gprim.hpp \
+  libsrc/gprim/geomobjects.hpp libsrc/gprim/geomops.hpp \
+  libsrc/gprim/geomfuncs.hpp libsrc/gprim/geom2d.hpp \
+  libsrc/gprim/geom3d.hpp libsrc/gprim/geomtest3d.hpp \
+  libsrc/gprim/transform3d.hpp libsrc/gprim/adtree.hpp \
+  libsrc/include/linalg.hpp libsrc/linalg/linalg.hpp \
+  libsrc/linalg/vector.hpp libsrc/linalg/densemat.hpp \
+  libsrc/linalg/polynomial.hpp libsrc/include/opti.hpp \
+  libsrc/opti/opti.hpp libsrc/meshing/msghandler.hpp \
+  libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \
+  libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \
+  libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \
+  libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \
+  libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \
+  libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \
+  libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \
+  libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \
+  libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \
+  libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \
+  libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \
+  libsrc/meshing/specials.hpp
+smoothing2.o: libsrc/meshing/smoothing2.cpp libsrc/include/mystdlib.h \
+  libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \
+  libsrc/general/myadt.hpp libsrc/include/mydefs.hpp \
+  libsrc/general/ngexception.hpp libsrc/general/parthreads.hpp \
+  libsrc/general/moveablemem.hpp libsrc/general/dynamicmem.hpp \
+  libsrc/general/template.hpp libsrc/general/array.hpp \
+  libsrc/general/table.hpp libsrc/general/hashtabl.hpp \
+  libsrc/general/symbolta.hpp libsrc/general/bitarray.hpp \
+  libsrc/general/flags.hpp libsrc/general/spbita2d.hpp \
+  libsrc/general/seti.hpp libsrc/general/optmem.hpp \
+  libsrc/general/autoptr.hpp libsrc/general/sort.hpp \
+  libsrc/general/stack.hpp libsrc/general/mystring.hpp \
+  libsrc/include/gprim.hpp libsrc/gprim/gprim.hpp \
+  libsrc/gprim/geomobjects.hpp libsrc/gprim/geomops.hpp \
+  libsrc/gprim/geomfuncs.hpp libsrc/gprim/geom2d.hpp \
+  libsrc/gprim/geom3d.hpp libsrc/gprim/geomtest3d.hpp \
+  libsrc/gprim/transform3d.hpp libsrc/gprim/adtree.hpp \
+  libsrc/include/linalg.hpp libsrc/linalg/linalg.hpp \
+  libsrc/linalg/vector.hpp libsrc/linalg/densemat.hpp \
+  libsrc/linalg/polynomial.hpp libsrc/include/opti.hpp \
+  libsrc/opti/opti.hpp libsrc/meshing/msghandler.hpp \
+  libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \
+  libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \
+  libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \
+  libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \
+  libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \
+  libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \
+  libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \
+  libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \
+  libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \
+  libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \
+  libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \
+  libsrc/meshing/specials.hpp
+adfront2.o: libsrc/meshing/adfront2.cpp libsrc/include/mystdlib.h \
+  libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \
+  libsrc/general/myadt.hpp libsrc/include/mydefs.hpp \
+  libsrc/general/ngexception.hpp libsrc/general/parthreads.hpp \
+  libsrc/general/moveablemem.hpp libsrc/general/dynamicmem.hpp \
+  libsrc/general/template.hpp libsrc/general/array.hpp \
+  libsrc/general/table.hpp libsrc/general/hashtabl.hpp \
+  libsrc/general/symbolta.hpp libsrc/general/bitarray.hpp \
+  libsrc/general/flags.hpp libsrc/general/spbita2d.hpp \
+  libsrc/general/seti.hpp libsrc/general/optmem.hpp \
+  libsrc/general/autoptr.hpp libsrc/general/sort.hpp \
+  libsrc/general/stack.hpp libsrc/general/mystring.hpp \
+  libsrc/include/gprim.hpp libsrc/gprim/gprim.hpp \
+  libsrc/gprim/geomobjects.hpp libsrc/gprim/geomops.hpp \
+  libsrc/gprim/geomfuncs.hpp libsrc/gprim/geom2d.hpp \
+  libsrc/gprim/geom3d.hpp libsrc/gprim/geomtest3d.hpp \
+  libsrc/gprim/transform3d.hpp libsrc/gprim/adtree.hpp \
+  libsrc/include/linalg.hpp libsrc/linalg/linalg.hpp \
+  libsrc/linalg/vector.hpp libsrc/linalg/densemat.hpp \
+  libsrc/linalg/polynomial.hpp libsrc/include/opti.hpp \
+  libsrc/opti/opti.hpp libsrc/meshing/msghandler.hpp \
+  libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \
+  libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \
+  libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \
+  libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \
+  libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \
+  libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \
+  libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \
+  libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \
+  libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \
+  libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \
+  libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \
+  libsrc/meshing/specials.hpp
+netrule2.o: libsrc/meshing/netrule2.cpp libsrc/include/mystdlib.h \
+  libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \
+  libsrc/general/myadt.hpp libsrc/include/mydefs.hpp \
+  libsrc/general/ngexception.hpp libsrc/general/parthreads.hpp \
+  libsrc/general/moveablemem.hpp libsrc/general/dynamicmem.hpp \
+  libsrc/general/template.hpp libsrc/general/array.hpp \
+  libsrc/general/table.hpp libsrc/general/hashtabl.hpp \
+  libsrc/general/symbolta.hpp libsrc/general/bitarray.hpp \
+  libsrc/general/flags.hpp libsrc/general/spbita2d.hpp \
+  libsrc/general/seti.hpp libsrc/general/optmem.hpp \
+  libsrc/general/autoptr.hpp libsrc/general/sort.hpp \
+  libsrc/general/stack.hpp libsrc/general/mystring.hpp \
+  libsrc/include/gprim.hpp libsrc/gprim/gprim.hpp \
+  libsrc/gprim/geomobjects.hpp libsrc/gprim/geomops.hpp \
+  libsrc/gprim/geomfuncs.hpp libsrc/gprim/geom2d.hpp \
+  libsrc/gprim/geom3d.hpp libsrc/gprim/geomtest3d.hpp \
+  libsrc/gprim/transform3d.hpp libsrc/gprim/adtree.hpp \
+  libsrc/include/linalg.hpp libsrc/linalg/linalg.hpp \
+  libsrc/linalg/vector.hpp libsrc/linalg/densemat.hpp \
+  libsrc/linalg/polynomial.hpp libsrc/include/opti.hpp \
+  libsrc/opti/opti.hpp libsrc/meshing/msghandler.hpp \
+  libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \
+  libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \
+  libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \
+  libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \
+  libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \
+  libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \
+  libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \
+  libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \
+  libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \
+  libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \
+  libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \
+  libsrc/meshing/specials.hpp
+triarls.o: libsrc/meshing/triarls.cpp
+geomsearch.o: libsrc/meshing/geomsearch.cpp libsrc/include/mystdlib.h \
+  libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \
+  libsrc/general/myadt.hpp libsrc/include/mydefs.hpp \
+  libsrc/general/ngexception.hpp libsrc/general/parthreads.hpp \
+  libsrc/general/moveablemem.hpp libsrc/general/dynamicmem.hpp \
+  libsrc/general/template.hpp libsrc/general/array.hpp \
+  libsrc/general/table.hpp libsrc/general/hashtabl.hpp \
+  libsrc/general/symbolta.hpp libsrc/general/bitarray.hpp \
+  libsrc/general/flags.hpp libsrc/general/spbita2d.hpp \
+  libsrc/general/seti.hpp libsrc/general/optmem.hpp \
+  libsrc/general/autoptr.hpp libsrc/general/sort.hpp \
+  libsrc/general/stack.hpp libsrc/general/mystring.hpp \
+  libsrc/include/gprim.hpp libsrc/gprim/gprim.hpp \
+  libsrc/gprim/geomobjects.hpp libsrc/gprim/geomops.hpp \
+  libsrc/gprim/geomfuncs.hpp libsrc/gprim/geom2d.hpp \
+  libsrc/gprim/geom3d.hpp libsrc/gprim/geomtest3d.hpp \
+  libsrc/gprim/transform3d.hpp libsrc/gprim/adtree.hpp \
+  libsrc/include/linalg.hpp libsrc/linalg/linalg.hpp \
+  libsrc/linalg/vector.hpp libsrc/linalg/densemat.hpp \
+  libsrc/linalg/polynomial.hpp libsrc/include/opti.hpp \
+  libsrc/opti/opti.hpp libsrc/meshing/msghandler.hpp \
+  libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \
+  libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \
+  libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \
+  libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \
+  libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \
+  libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \
+  libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \
+  libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \
+  libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \
+  libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \
+  libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \
+  libsrc/meshing/specials.hpp
+secondorder.o: libsrc/meshing/secondorder.cpp libsrc/include/mystdlib.h \
+  libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \
+  libsrc/general/myadt.hpp libsrc/include/mydefs.hpp \
+  libsrc/general/ngexception.hpp libsrc/general/parthreads.hpp \
+  libsrc/general/moveablemem.hpp libsrc/general/dynamicmem.hpp \
+  libsrc/general/template.hpp libsrc/general/array.hpp \
+  libsrc/general/table.hpp libsrc/general/hashtabl.hpp \
+  libsrc/general/symbolta.hpp libsrc/general/bitarray.hpp \
+  libsrc/general/flags.hpp libsrc/general/spbita2d.hpp \
+  libsrc/general/seti.hpp libsrc/general/optmem.hpp \
+  libsrc/general/autoptr.hpp libsrc/general/sort.hpp \
+  libsrc/general/stack.hpp libsrc/general/mystring.hpp \
+  libsrc/include/gprim.hpp libsrc/gprim/gprim.hpp \
+  libsrc/gprim/geomobjects.hpp libsrc/gprim/geomops.hpp \
+  libsrc/gprim/geomfuncs.hpp libsrc/gprim/geom2d.hpp \
+  libsrc/gprim/geom3d.hpp libsrc/gprim/geomtest3d.hpp \
+  libsrc/gprim/transform3d.hpp libsrc/gprim/adtree.hpp \
+  libsrc/include/linalg.hpp libsrc/linalg/linalg.hpp \
+  libsrc/linalg/vector.hpp libsrc/linalg/densemat.hpp \
+  libsrc/linalg/polynomial.hpp libsrc/include/opti.hpp \
+  libsrc/opti/opti.hpp libsrc/meshing/msghandler.hpp \
+  libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \
+  libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \
+  libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \
+  libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \
+  libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \
+  libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \
+  libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \
+  libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \
+  libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \
+  libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \
+  libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \
+  libsrc/meshing/specials.hpp
+meshtype.o: libsrc/meshing/meshtype.cpp libsrc/include/mystdlib.h \
+  libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \
+  libsrc/general/myadt.hpp libsrc/include/mydefs.hpp \
+  libsrc/general/ngexception.hpp libsrc/general/parthreads.hpp \
+  libsrc/general/moveablemem.hpp libsrc/general/dynamicmem.hpp \
+  libsrc/general/template.hpp libsrc/general/array.hpp \
+  libsrc/general/table.hpp libsrc/general/hashtabl.hpp \
+  libsrc/general/symbolta.hpp libsrc/general/bitarray.hpp \
+  libsrc/general/flags.hpp libsrc/general/spbita2d.hpp \
+  libsrc/general/seti.hpp libsrc/general/optmem.hpp \
+  libsrc/general/autoptr.hpp libsrc/general/sort.hpp \
+  libsrc/general/stack.hpp libsrc/general/mystring.hpp \
+  libsrc/include/gprim.hpp libsrc/gprim/gprim.hpp \
+  libsrc/gprim/geomobjects.hpp libsrc/gprim/geomops.hpp \
+  libsrc/gprim/geomfuncs.hpp libsrc/gprim/geom2d.hpp \
+  libsrc/gprim/geom3d.hpp libsrc/gprim/geomtest3d.hpp \
+  libsrc/gprim/transform3d.hpp libsrc/gprim/adtree.hpp \
+  libsrc/include/linalg.hpp libsrc/linalg/linalg.hpp \
+  libsrc/linalg/vector.hpp libsrc/linalg/densemat.hpp \
+  libsrc/linalg/polynomial.hpp libsrc/include/opti.hpp \
+  libsrc/opti/opti.hpp libsrc/meshing/msghandler.hpp \
+  libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \
+  libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \
+  libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \
+  libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \
+  libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \
+  libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \
+  libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \
+  libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \
+  libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \
+  libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \
+  libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \
+  libsrc/meshing/specials.hpp
+parser3.o: libsrc/meshing/parser3.cpp libsrc/include/mystdlib.h \
+  libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \
+  libsrc/general/myadt.hpp libsrc/include/mydefs.hpp \
+  libsrc/general/ngexception.hpp libsrc/general/parthreads.hpp \
+  libsrc/general/moveablemem.hpp libsrc/general/dynamicmem.hpp \
+  libsrc/general/template.hpp libsrc/general/array.hpp \
+  libsrc/general/table.hpp libsrc/general/hashtabl.hpp \
+  libsrc/general/symbolta.hpp libsrc/general/bitarray.hpp \
+  libsrc/general/flags.hpp libsrc/general/spbita2d.hpp \
+  libsrc/general/seti.hpp libsrc/general/optmem.hpp \
+  libsrc/general/autoptr.hpp libsrc/general/sort.hpp \
+  libsrc/general/stack.hpp libsrc/general/mystring.hpp \
+  libsrc/include/gprim.hpp libsrc/gprim/gprim.hpp \
+  libsrc/gprim/geomobjects.hpp libsrc/gprim/geomops.hpp \
+  libsrc/gprim/geomfuncs.hpp libsrc/gprim/geom2d.hpp \
+  libsrc/gprim/geom3d.hpp libsrc/gprim/geomtest3d.hpp \
+  libsrc/gprim/transform3d.hpp libsrc/gprim/adtree.hpp \
+  libsrc/include/linalg.hpp libsrc/linalg/linalg.hpp \
+  libsrc/linalg/vector.hpp libsrc/linalg/densemat.hpp \
+  libsrc/linalg/polynomial.hpp libsrc/include/opti.hpp \
+  libsrc/opti/opti.hpp libsrc/meshing/msghandler.hpp \
+  libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \
+  libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \
+  libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \
+  libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \
+  libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \
+  libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \
+  libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \
+  libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \
+  libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \
+  libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \
+  libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \
+  libsrc/meshing/specials.hpp
+meshing2.o: libsrc/meshing/meshing2.cpp libsrc/include/mystdlib.h \
+  libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \
+  libsrc/general/myadt.hpp libsrc/include/mydefs.hpp \
+  libsrc/general/ngexception.hpp libsrc/general/parthreads.hpp \
+  libsrc/general/moveablemem.hpp libsrc/general/dynamicmem.hpp \
+  libsrc/general/template.hpp libsrc/general/array.hpp \
+  libsrc/general/table.hpp libsrc/general/hashtabl.hpp \
+  libsrc/general/symbolta.hpp libsrc/general/bitarray.hpp \
+  libsrc/general/flags.hpp libsrc/general/spbita2d.hpp \
+  libsrc/general/seti.hpp libsrc/general/optmem.hpp \
+  libsrc/general/autoptr.hpp libsrc/general/sort.hpp \
+  libsrc/general/stack.hpp libsrc/general/mystring.hpp \
+  libsrc/include/gprim.hpp libsrc/gprim/gprim.hpp \
+  libsrc/gprim/geomobjects.hpp libsrc/gprim/geomops.hpp \
+  libsrc/gprim/geomfuncs.hpp libsrc/gprim/geom2d.hpp \
+  libsrc/gprim/geom3d.hpp libsrc/gprim/geomtest3d.hpp \
+  libsrc/gprim/transform3d.hpp libsrc/gprim/adtree.hpp \
+  libsrc/include/linalg.hpp libsrc/linalg/linalg.hpp \
+  libsrc/linalg/vector.hpp libsrc/linalg/densemat.hpp \
+  libsrc/linalg/polynomial.hpp libsrc/include/opti.hpp \
+  libsrc/opti/opti.hpp libsrc/meshing/msghandler.hpp \
+  libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \
+  libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \
+  libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \
+  libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \
+  libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \
+  libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \
+  libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \
+  libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \
+  libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \
+  libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \
+  libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \
+  libsrc/meshing/specials.hpp
+quadrls.o: libsrc/meshing/quadrls.cpp
+specials.o: libsrc/meshing/specials.cpp libsrc/include/mystdlib.h \
+  libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \
+  libsrc/general/myadt.hpp libsrc/include/mydefs.hpp \
+  libsrc/general/ngexception.hpp libsrc/general/parthreads.hpp \
+  libsrc/general/moveablemem.hpp libsrc/general/dynamicmem.hpp \
+  libsrc/general/template.hpp libsrc/general/array.hpp \
+  libsrc/general/table.hpp libsrc/general/hashtabl.hpp \
+  libsrc/general/symbolta.hpp libsrc/general/bitarray.hpp \
+  libsrc/general/flags.hpp libsrc/general/spbita2d.hpp \
+  libsrc/general/seti.hpp libsrc/general/optmem.hpp \
+  libsrc/general/autoptr.hpp libsrc/general/sort.hpp \
+  libsrc/general/stack.hpp libsrc/general/mystring.hpp \
+  libsrc/include/gprim.hpp libsrc/gprim/gprim.hpp \
+  libsrc/gprim/geomobjects.hpp libsrc/gprim/geomops.hpp \
+  libsrc/gprim/geomfuncs.hpp libsrc/gprim/geom2d.hpp \
+  libsrc/gprim/geom3d.hpp libsrc/gprim/geomtest3d.hpp \
+  libsrc/gprim/transform3d.hpp libsrc/gprim/adtree.hpp \
+  libsrc/include/linalg.hpp libsrc/linalg/linalg.hpp \
+  libsrc/linalg/vector.hpp libsrc/linalg/densemat.hpp \
+  libsrc/linalg/polynomial.hpp libsrc/include/opti.hpp \
+  libsrc/opti/opti.hpp libsrc/meshing/msghandler.hpp \
+  libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \
+  libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \
+  libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \
+  libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \
+  libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \
+  libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \
+  libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \
+  libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \
+  libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \
+  libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \
+  libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \
+  libsrc/meshing/specials.hpp
+parser2.o: libsrc/meshing/parser2.cpp libsrc/include/mystdlib.h \
+  libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \
+  libsrc/general/myadt.hpp libsrc/include/mydefs.hpp \
+  libsrc/general/ngexception.hpp libsrc/general/parthreads.hpp \
+  libsrc/general/moveablemem.hpp libsrc/general/dynamicmem.hpp \
+  libsrc/general/template.hpp libsrc/general/array.hpp \
+  libsrc/general/table.hpp libsrc/general/hashtabl.hpp \
+  libsrc/general/symbolta.hpp libsrc/general/bitarray.hpp \
+  libsrc/general/flags.hpp libsrc/general/spbita2d.hpp \
+  libsrc/general/seti.hpp libsrc/general/optmem.hpp \
+  libsrc/general/autoptr.hpp libsrc/general/sort.hpp \
+  libsrc/general/stack.hpp libsrc/general/mystring.hpp \
+  libsrc/include/gprim.hpp libsrc/gprim/gprim.hpp \
+  libsrc/gprim/geomobjects.hpp libsrc/gprim/geomops.hpp \
+  libsrc/gprim/geomfuncs.hpp libsrc/gprim/geom2d.hpp \
+  libsrc/gprim/geom3d.hpp libsrc/gprim/geomtest3d.hpp \
+  libsrc/gprim/transform3d.hpp libsrc/gprim/adtree.hpp \
+  libsrc/include/linalg.hpp libsrc/linalg/linalg.hpp \
+  libsrc/linalg/vector.hpp libsrc/linalg/densemat.hpp \
+  libsrc/linalg/polynomial.hpp libsrc/include/opti.hpp \
+  libsrc/opti/opti.hpp libsrc/meshing/msghandler.hpp \
+  libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \
+  libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \
+  libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \
+  libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \
+  libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \
+  libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \
+  libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \
+  libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \
+  libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \
+  libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \
+  libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \
+  libsrc/meshing/specials.hpp
+meshing3.o: libsrc/meshing/meshing3.cpp libsrc/include/mystdlib.h \
+  libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \
+  libsrc/general/myadt.hpp libsrc/include/mydefs.hpp \
+  libsrc/general/ngexception.hpp libsrc/general/parthreads.hpp \
+  libsrc/general/moveablemem.hpp libsrc/general/dynamicmem.hpp \
+  libsrc/general/template.hpp libsrc/general/array.hpp \
+  libsrc/general/table.hpp libsrc/general/hashtabl.hpp \
+  libsrc/general/symbolta.hpp libsrc/general/bitarray.hpp \
+  libsrc/general/flags.hpp libsrc/general/spbita2d.hpp \
+  libsrc/general/seti.hpp libsrc/general/optmem.hpp \
+  libsrc/general/autoptr.hpp libsrc/general/sort.hpp \
+  libsrc/general/stack.hpp libsrc/general/mystring.hpp \
+  libsrc/include/gprim.hpp libsrc/gprim/gprim.hpp \
+  libsrc/gprim/geomobjects.hpp libsrc/gprim/geomops.hpp \
+  libsrc/gprim/geomfuncs.hpp libsrc/gprim/geom2d.hpp \
+  libsrc/gprim/geom3d.hpp libsrc/gprim/geomtest3d.hpp \
+  libsrc/gprim/transform3d.hpp libsrc/gprim/adtree.hpp \
+  libsrc/include/linalg.hpp libsrc/linalg/linalg.hpp \
+  libsrc/linalg/vector.hpp libsrc/linalg/densemat.hpp \
+  libsrc/linalg/polynomial.hpp libsrc/include/opti.hpp \
+  libsrc/opti/opti.hpp libsrc/meshing/msghandler.hpp \
+  libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \
+  libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \
+  libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \
+  libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \
+  libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \
+  libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \
+  libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \
+  libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \
+  libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \
+  libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \
+  libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \
+  libsrc/meshing/specials.hpp
+meshfunc.o: libsrc/meshing/meshfunc.cpp libsrc/include/mystdlib.h \
+  libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \
+  libsrc/general/myadt.hpp libsrc/include/mydefs.hpp \
+  libsrc/general/ngexception.hpp libsrc/general/parthreads.hpp \
+  libsrc/general/moveablemem.hpp libsrc/general/dynamicmem.hpp \
+  libsrc/general/template.hpp libsrc/general/array.hpp \
+  libsrc/general/table.hpp libsrc/general/hashtabl.hpp \
+  libsrc/general/symbolta.hpp libsrc/general/bitarray.hpp \
+  libsrc/general/flags.hpp libsrc/general/spbita2d.hpp \
+  libsrc/general/seti.hpp libsrc/general/optmem.hpp \
+  libsrc/general/autoptr.hpp libsrc/general/sort.hpp \
+  libsrc/general/stack.hpp libsrc/general/mystring.hpp \
+  libsrc/include/gprim.hpp libsrc/gprim/gprim.hpp \
+  libsrc/gprim/geomobjects.hpp libsrc/gprim/geomops.hpp \
+  libsrc/gprim/geomfuncs.hpp libsrc/gprim/geom2d.hpp \
+  libsrc/gprim/geom3d.hpp libsrc/gprim/geomtest3d.hpp \
+  libsrc/gprim/transform3d.hpp libsrc/gprim/adtree.hpp \
+  libsrc/include/linalg.hpp libsrc/linalg/linalg.hpp \
+  libsrc/linalg/vector.hpp libsrc/linalg/densemat.hpp \
+  libsrc/linalg/polynomial.hpp libsrc/include/opti.hpp \
+  libsrc/opti/opti.hpp libsrc/meshing/msghandler.hpp \
+  libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \
+  libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \
+  libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \
+  libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \
+  libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \
+  libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \
+  libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \
+  libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \
+  libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \
+  libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \
+  libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \
+  libsrc/meshing/specials.hpp
+localh.o: libsrc/meshing/localh.cpp libsrc/include/mystdlib.h \
+  libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \
+  libsrc/general/myadt.hpp libsrc/include/mydefs.hpp \
+  libsrc/general/ngexception.hpp libsrc/general/parthreads.hpp \
+  libsrc/general/moveablemem.hpp libsrc/general/dynamicmem.hpp \
+  libsrc/general/template.hpp libsrc/general/array.hpp \
+  libsrc/general/table.hpp libsrc/general/hashtabl.hpp \
+  libsrc/general/symbolta.hpp libsrc/general/bitarray.hpp \
+  libsrc/general/flags.hpp libsrc/general/spbita2d.hpp \
+  libsrc/general/seti.hpp libsrc/general/optmem.hpp \
+  libsrc/general/autoptr.hpp libsrc/general/sort.hpp \
+  libsrc/general/stack.hpp libsrc/general/mystring.hpp \
+  libsrc/include/gprim.hpp libsrc/gprim/gprim.hpp \
+  libsrc/gprim/geomobjects.hpp libsrc/gprim/geomops.hpp \
+  libsrc/gprim/geomfuncs.hpp libsrc/gprim/geom2d.hpp \
+  libsrc/gprim/geom3d.hpp libsrc/gprim/geomtest3d.hpp \
+  libsrc/gprim/transform3d.hpp libsrc/gprim/adtree.hpp \
+  libsrc/include/linalg.hpp libsrc/linalg/linalg.hpp \
+  libsrc/linalg/vector.hpp libsrc/linalg/densemat.hpp \
+  libsrc/linalg/polynomial.hpp libsrc/include/opti.hpp \
+  libsrc/opti/opti.hpp libsrc/meshing/msghandler.hpp \
+  libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \
+  libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \
+  libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \
+  libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \
+  libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \
+  libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \
+  libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \
+  libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \
+  libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \
+  libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \
+  libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \
+  libsrc/meshing/specials.hpp
+improve2gen.o: libsrc/meshing/improve2gen.cpp libsrc/include/mystdlib.h \
+  libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \
+  libsrc/general/myadt.hpp libsrc/include/mydefs.hpp \
+  libsrc/general/ngexception.hpp libsrc/general/parthreads.hpp \
+  libsrc/general/moveablemem.hpp libsrc/general/dynamicmem.hpp \
+  libsrc/general/template.hpp libsrc/general/array.hpp \
+  libsrc/general/table.hpp libsrc/general/hashtabl.hpp \
+  libsrc/general/symbolta.hpp libsrc/general/bitarray.hpp \
+  libsrc/general/flags.hpp libsrc/general/spbita2d.hpp \
+  libsrc/general/seti.hpp libsrc/general/optmem.hpp \
+  libsrc/general/autoptr.hpp libsrc/general/sort.hpp \
+  libsrc/general/stack.hpp libsrc/general/mystring.hpp \
+  libsrc/include/gprim.hpp libsrc/gprim/gprim.hpp \
+  libsrc/gprim/geomobjects.hpp libsrc/gprim/geomops.hpp \
+  libsrc/gprim/geomfuncs.hpp libsrc/gprim/geom2d.hpp \
+  libsrc/gprim/geom3d.hpp libsrc/gprim/geomtest3d.hpp \
+  libsrc/gprim/transform3d.hpp libsrc/gprim/adtree.hpp \
+  libsrc/include/linalg.hpp libsrc/linalg/linalg.hpp \
+  libsrc/linalg/vector.hpp libsrc/linalg/densemat.hpp \
+  libsrc/linalg/polynomial.hpp libsrc/include/opti.hpp \
+  libsrc/opti/opti.hpp libsrc/meshing/msghandler.hpp \
+  libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \
+  libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \
+  libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \
+  libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \
+  libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \
+  libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \
+  libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \
+  libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \
+  libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \
+  libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \
+  libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \
+  libsrc/meshing/specials.hpp
+delaunay.o: libsrc/meshing/delaunay.cpp libsrc/include/mystdlib.h \
+  libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \
+  libsrc/general/myadt.hpp libsrc/include/mydefs.hpp \
+  libsrc/general/ngexception.hpp libsrc/general/parthreads.hpp \
+  libsrc/general/moveablemem.hpp libsrc/general/dynamicmem.hpp \
+  libsrc/general/template.hpp libsrc/general/array.hpp \
+  libsrc/general/table.hpp libsrc/general/hashtabl.hpp \
+  libsrc/general/symbolta.hpp libsrc/general/bitarray.hpp \
+  libsrc/general/flags.hpp libsrc/general/spbita2d.hpp \
+  libsrc/general/seti.hpp libsrc/general/optmem.hpp \
+  libsrc/general/autoptr.hpp libsrc/general/sort.hpp \
+  libsrc/general/stack.hpp libsrc/general/mystring.hpp \
+  libsrc/include/gprim.hpp libsrc/gprim/gprim.hpp \
+  libsrc/gprim/geomobjects.hpp libsrc/gprim/geomops.hpp \
+  libsrc/gprim/geomfuncs.hpp libsrc/gprim/geom2d.hpp \
+  libsrc/gprim/geom3d.hpp libsrc/gprim/geomtest3d.hpp \
+  libsrc/gprim/transform3d.hpp libsrc/gprim/adtree.hpp \
+  libsrc/include/linalg.hpp libsrc/linalg/linalg.hpp \
+  libsrc/linalg/vector.hpp libsrc/linalg/densemat.hpp \
+  libsrc/linalg/polynomial.hpp libsrc/include/opti.hpp \
+  libsrc/opti/opti.hpp libsrc/meshing/msghandler.hpp \
+  libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \
+  libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \
+  libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \
+  libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \
+  libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \
+  libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \
+  libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \
+  libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \
+  libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \
+  libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \
+  libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \
+  libsrc/meshing/specials.hpp
+boundarylayer.o: libsrc/meshing/boundarylayer.cpp \
+  libsrc/include/mystdlib.h libsrc/meshing/meshing.hpp \
+  libsrc/include/myadt.hpp libsrc/general/myadt.hpp \
+  libsrc/include/mydefs.hpp libsrc/general/ngexception.hpp \
+  libsrc/general/parthreads.hpp libsrc/general/moveablemem.hpp \
+  libsrc/general/dynamicmem.hpp libsrc/general/template.hpp \
+  libsrc/general/array.hpp libsrc/general/table.hpp \
+  libsrc/general/hashtabl.hpp libsrc/general/symbolta.hpp \
+  libsrc/general/bitarray.hpp libsrc/general/flags.hpp \
+  libsrc/general/spbita2d.hpp libsrc/general/seti.hpp \
+  libsrc/general/optmem.hpp libsrc/general/autoptr.hpp \
+  libsrc/general/sort.hpp libsrc/general/stack.hpp \
+  libsrc/general/mystring.hpp libsrc/include/gprim.hpp \
+  libsrc/gprim/gprim.hpp libsrc/gprim/geomobjects.hpp \
+  libsrc/gprim/geomops.hpp libsrc/gprim/geomfuncs.hpp \
+  libsrc/gprim/geom2d.hpp libsrc/gprim/geom3d.hpp \
+  libsrc/gprim/geomtest3d.hpp libsrc/gprim/transform3d.hpp \
+  libsrc/gprim/adtree.hpp libsrc/include/linalg.hpp \
+  libsrc/linalg/linalg.hpp libsrc/linalg/vector.hpp \
+  libsrc/linalg/densemat.hpp libsrc/linalg/polynomial.hpp \
+  libsrc/include/opti.hpp libsrc/opti/opti.hpp \
+  libsrc/meshing/msghandler.hpp libsrc/meshing/meshtype.hpp \
+  libsrc/meshing/localh.hpp libsrc/meshing/meshclass.hpp \
+  libsrc/meshing/global.hpp libsrc/meshing/meshtool.hpp \
+  libsrc/meshing/ruler2.hpp libsrc/meshing/adfront2.hpp \
+  libsrc/meshing/meshing2.hpp libsrc/meshing/improve2.hpp \
+  libsrc/meshing/geomsearch.hpp libsrc/meshing/adfront3.hpp \
+  libsrc/meshing/ruler3.hpp libsrc/meshing/meshing3.hpp \
+  libsrc/meshing/improve3.hpp libsrc/meshing/findip.hpp \
+  libsrc/meshing/topology.hpp libsrc/meshing/curvedelems.hpp \
+  libsrc/meshing/bisect.hpp libsrc/meshing/clusters.hpp \
+  libsrc/meshing/meshfunc.hpp libsrc/meshing/hprefinement.hpp \
+  libsrc/meshing/boundarylayer.hpp libsrc/meshing/specials.hpp
+msghandler.o: libsrc/meshing/msghandler.cpp libsrc/include/meshing.hpp \
+  libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \
+  libsrc/general/myadt.hpp libsrc/include/mystdlib.h \
+  libsrc/include/mydefs.hpp libsrc/general/ngexception.hpp \
+  libsrc/general/parthreads.hpp libsrc/general/moveablemem.hpp \
+  libsrc/general/dynamicmem.hpp libsrc/general/template.hpp \
+  libsrc/general/array.hpp libsrc/general/table.hpp \
+  libsrc/general/hashtabl.hpp libsrc/general/symbolta.hpp \
+  libsrc/general/bitarray.hpp libsrc/general/flags.hpp \
+  libsrc/general/spbita2d.hpp libsrc/general/seti.hpp \
+  libsrc/general/optmem.hpp libsrc/general/autoptr.hpp \
+  libsrc/general/sort.hpp libsrc/general/stack.hpp \
+  libsrc/general/mystring.hpp libsrc/include/gprim.hpp \
+  libsrc/gprim/gprim.hpp libsrc/gprim/geomobjects.hpp \
+  libsrc/gprim/geomops.hpp libsrc/gprim/geomfuncs.hpp \
+  libsrc/gprim/geom2d.hpp libsrc/gprim/geom3d.hpp \
+  libsrc/gprim/geomtest3d.hpp libsrc/gprim/transform3d.hpp \
+  libsrc/gprim/adtree.hpp libsrc/include/linalg.hpp \
+  libsrc/linalg/linalg.hpp libsrc/linalg/vector.hpp \
+  libsrc/linalg/densemat.hpp libsrc/linalg/polynomial.hpp \
+  libsrc/include/opti.hpp libsrc/opti/opti.hpp \
+  libsrc/meshing/msghandler.hpp libsrc/meshing/meshtype.hpp \
+  libsrc/meshing/localh.hpp libsrc/meshing/meshclass.hpp \
+  libsrc/meshing/global.hpp libsrc/meshing/meshtool.hpp \
+  libsrc/meshing/ruler2.hpp libsrc/meshing/adfront2.hpp \
+  libsrc/meshing/meshing2.hpp libsrc/meshing/improve2.hpp \
+  libsrc/meshing/geomsearch.hpp libsrc/meshing/adfront3.hpp \
+  libsrc/meshing/ruler3.hpp libsrc/meshing/meshing3.hpp \
+  libsrc/meshing/improve3.hpp libsrc/meshing/findip.hpp \
+  libsrc/meshing/topology.hpp libsrc/meshing/curvedelems.hpp \
+  libsrc/meshing/bisect.hpp libsrc/meshing/clusters.hpp \
+  libsrc/meshing/meshfunc.hpp libsrc/meshing/hprefinement.hpp \
+  libsrc/meshing/boundarylayer.hpp libsrc/meshing/specials.hpp
+meshfunc2d.o: libsrc/meshing/meshfunc2d.cpp libsrc/include/mystdlib.h \
+  libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \
+  libsrc/general/myadt.hpp libsrc/include/mydefs.hpp \
+  libsrc/general/ngexception.hpp libsrc/general/parthreads.hpp \
+  libsrc/general/moveablemem.hpp libsrc/general/dynamicmem.hpp \
+  libsrc/general/template.hpp libsrc/general/array.hpp \
+  libsrc/general/table.hpp libsrc/general/hashtabl.hpp \
+  libsrc/general/symbolta.hpp libsrc/general/bitarray.hpp \
+  libsrc/general/flags.hpp libsrc/general/spbita2d.hpp \
+  libsrc/general/seti.hpp libsrc/general/optmem.hpp \
+  libsrc/general/autoptr.hpp libsrc/general/sort.hpp \
+  libsrc/general/stack.hpp libsrc/general/mystring.hpp \
+  libsrc/include/gprim.hpp libsrc/gprim/gprim.hpp \
+  libsrc/gprim/geomobjects.hpp libsrc/gprim/geomops.hpp \
+  libsrc/gprim/geomfuncs.hpp libsrc/gprim/geom2d.hpp \
+  libsrc/gprim/geom3d.hpp libsrc/gprim/geomtest3d.hpp \
+  libsrc/gprim/transform3d.hpp libsrc/gprim/adtree.hpp \
+  libsrc/include/linalg.hpp libsrc/linalg/linalg.hpp \
+  libsrc/linalg/vector.hpp libsrc/linalg/densemat.hpp \
+  libsrc/linalg/polynomial.hpp libsrc/include/opti.hpp \
+  libsrc/opti/opti.hpp libsrc/meshing/msghandler.hpp \
+  libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \
+  libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \
+  libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \
+  libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \
+  libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \
+  libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \
+  libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \
+  libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \
+  libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \
+  libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \
+  libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \
+  libsrc/meshing/specials.hpp
+topology.o: libsrc/meshing/topology.cpp libsrc/include/mystdlib.h \
+  libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \
+  libsrc/general/myadt.hpp libsrc/include/mydefs.hpp \
+  libsrc/general/ngexception.hpp libsrc/general/parthreads.hpp \
+  libsrc/general/moveablemem.hpp libsrc/general/dynamicmem.hpp \
+  libsrc/general/template.hpp libsrc/general/array.hpp \
+  libsrc/general/table.hpp libsrc/general/hashtabl.hpp \
+  libsrc/general/symbolta.hpp libsrc/general/bitarray.hpp \
+  libsrc/general/flags.hpp libsrc/general/spbita2d.hpp \
+  libsrc/general/seti.hpp libsrc/general/optmem.hpp \
+  libsrc/general/autoptr.hpp libsrc/general/sort.hpp \
+  libsrc/general/stack.hpp libsrc/general/mystring.hpp \
+  libsrc/include/gprim.hpp libsrc/gprim/gprim.hpp \
+  libsrc/gprim/geomobjects.hpp libsrc/gprim/geomops.hpp \
+  libsrc/gprim/geomfuncs.hpp libsrc/gprim/geom2d.hpp \
+  libsrc/gprim/geom3d.hpp libsrc/gprim/geomtest3d.hpp \
+  libsrc/gprim/transform3d.hpp libsrc/gprim/adtree.hpp \
+  libsrc/include/linalg.hpp libsrc/linalg/linalg.hpp \
+  libsrc/linalg/vector.hpp libsrc/linalg/densemat.hpp \
+  libsrc/linalg/polynomial.hpp libsrc/include/opti.hpp \
+  libsrc/opti/opti.hpp libsrc/meshing/msghandler.hpp \
+  libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \
+  libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \
+  libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \
+  libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \
+  libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \
+  libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \
+  libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \
+  libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \
+  libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \
+  libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \
+  libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \
+  libsrc/meshing/specials.hpp
+clusters.o: libsrc/meshing/clusters.cpp libsrc/include/mystdlib.h \
+  libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \
+  libsrc/general/myadt.hpp libsrc/include/mydefs.hpp \
+  libsrc/general/ngexception.hpp libsrc/general/parthreads.hpp \
+  libsrc/general/moveablemem.hpp libsrc/general/dynamicmem.hpp \
+  libsrc/general/template.hpp libsrc/general/array.hpp \
+  libsrc/general/table.hpp libsrc/general/hashtabl.hpp \
+  libsrc/general/symbolta.hpp libsrc/general/bitarray.hpp \
+  libsrc/general/flags.hpp libsrc/general/spbita2d.hpp \
+  libsrc/general/seti.hpp libsrc/general/optmem.hpp \
+  libsrc/general/autoptr.hpp libsrc/general/sort.hpp \
+  libsrc/general/stack.hpp libsrc/general/mystring.hpp \
+  libsrc/include/gprim.hpp libsrc/gprim/gprim.hpp \
+  libsrc/gprim/geomobjects.hpp libsrc/gprim/geomops.hpp \
+  libsrc/gprim/geomfuncs.hpp libsrc/gprim/geom2d.hpp \
+  libsrc/gprim/geom3d.hpp libsrc/gprim/geomtest3d.hpp \
+  libsrc/gprim/transform3d.hpp libsrc/gprim/adtree.hpp \
+  libsrc/include/linalg.hpp libsrc/linalg/linalg.hpp \
+  libsrc/linalg/vector.hpp libsrc/linalg/densemat.hpp \
+  libsrc/linalg/polynomial.hpp libsrc/include/opti.hpp \
+  libsrc/opti/opti.hpp libsrc/meshing/msghandler.hpp \
+  libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \
+  libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \
+  libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \
+  libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \
+  libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \
+  libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \
+  libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \
+  libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \
+  libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \
+  libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \
+  libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \
+  libsrc/meshing/specials.hpp
+curvedelems.o: libsrc/meshing/curvedelems.cpp libsrc/include/mystdlib.h \
+  libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \
+  libsrc/general/myadt.hpp libsrc/include/mydefs.hpp \
+  libsrc/general/ngexception.hpp libsrc/general/parthreads.hpp \
+  libsrc/general/moveablemem.hpp libsrc/general/dynamicmem.hpp \
+  libsrc/general/template.hpp libsrc/general/array.hpp \
+  libsrc/general/table.hpp libsrc/general/hashtabl.hpp \
+  libsrc/general/symbolta.hpp libsrc/general/bitarray.hpp \
+  libsrc/general/flags.hpp libsrc/general/spbita2d.hpp \
+  libsrc/general/seti.hpp libsrc/general/optmem.hpp \
+  libsrc/general/autoptr.hpp libsrc/general/sort.hpp \
+  libsrc/general/stack.hpp libsrc/general/mystring.hpp \
+  libsrc/include/gprim.hpp libsrc/gprim/gprim.hpp \
+  libsrc/gprim/geomobjects.hpp libsrc/gprim/geomops.hpp \
+  libsrc/gprim/geomfuncs.hpp libsrc/gprim/geom2d.hpp \
+  libsrc/gprim/geom3d.hpp libsrc/gprim/geomtest3d.hpp \
+  libsrc/gprim/transform3d.hpp libsrc/gprim/adtree.hpp \
+  libsrc/include/linalg.hpp libsrc/linalg/linalg.hpp \
+  libsrc/linalg/vector.hpp libsrc/linalg/densemat.hpp \
+  libsrc/linalg/polynomial.hpp libsrc/include/opti.hpp \
+  libsrc/opti/opti.hpp libsrc/meshing/msghandler.hpp \
+  libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \
+  libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \
+  libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \
+  libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \
+  libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \
+  libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \
+  libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \
+  libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \
+  libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \
+  libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \
+  libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \
+  libsrc/meshing/specials.hpp
+curvedelems2.o: libsrc/meshing/curvedelems2.cpp libsrc/include/mystdlib.h \
+  libsrc/meshing/meshing.hpp libsrc/include/myadt.hpp \
+  libsrc/general/myadt.hpp libsrc/include/mydefs.hpp \
+  libsrc/general/ngexception.hpp libsrc/general/parthreads.hpp \
+  libsrc/general/moveablemem.hpp libsrc/general/dynamicmem.hpp \
+  libsrc/general/template.hpp libsrc/general/array.hpp \
+  libsrc/general/table.hpp libsrc/general/hashtabl.hpp \
+  libsrc/general/symbolta.hpp libsrc/general/bitarray.hpp \
+  libsrc/general/flags.hpp libsrc/general/spbita2d.hpp \
+  libsrc/general/seti.hpp libsrc/general/optmem.hpp \
+  libsrc/general/autoptr.hpp libsrc/general/sort.hpp \
+  libsrc/general/stack.hpp libsrc/general/mystring.hpp \
+  libsrc/include/gprim.hpp libsrc/gprim/gprim.hpp \
+  libsrc/gprim/geomobjects.hpp libsrc/gprim/geomops.hpp \
+  libsrc/gprim/geomfuncs.hpp libsrc/gprim/geom2d.hpp \
+  libsrc/gprim/geom3d.hpp libsrc/gprim/geomtest3d.hpp \
+  libsrc/gprim/transform3d.hpp libsrc/gprim/adtree.hpp \
+  libsrc/include/linalg.hpp libsrc/linalg/linalg.hpp \
+  libsrc/linalg/vector.hpp libsrc/linalg/densemat.hpp \
+  libsrc/linalg/polynomial.hpp libsrc/include/opti.hpp \
+  libsrc/opti/opti.hpp libsrc/meshing/msghandler.hpp \
+  libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \
+  libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \
+  libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \
+  libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \
+  libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \
+  libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \
+  libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \
+  libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \
+  libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \
+  libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \
+  libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \
+  libsrc/meshing/specials.hpp
+nglib.o: libsrc/interface/nglib.cpp libsrc/include/mystdlib.h \
+  libsrc/include/myadt.hpp libsrc/general/myadt.hpp \
+  libsrc/include/mydefs.hpp libsrc/general/ngexception.hpp \
+  libsrc/general/parthreads.hpp libsrc/general/moveablemem.hpp \
+  libsrc/general/dynamicmem.hpp libsrc/general/template.hpp \
+  libsrc/general/array.hpp libsrc/general/table.hpp \
+  libsrc/general/hashtabl.hpp libsrc/general/symbolta.hpp \
+  libsrc/general/bitarray.hpp libsrc/general/flags.hpp \
+  libsrc/general/spbita2d.hpp libsrc/general/seti.hpp \
+  libsrc/general/optmem.hpp libsrc/general/autoptr.hpp \
+  libsrc/general/sort.hpp libsrc/general/stack.hpp \
+  libsrc/general/mystring.hpp libsrc/include/linalg.hpp \
+  libsrc/linalg/linalg.hpp libsrc/linalg/vector.hpp \
+  libsrc/linalg/densemat.hpp libsrc/linalg/polynomial.hpp \
+  libsrc/include/csg.hpp libsrc/csg/csg.hpp libsrc/include/gprim.hpp \
+  libsrc/gprim/gprim.hpp libsrc/gprim/geomobjects.hpp \
+  libsrc/gprim/geomops.hpp libsrc/gprim/geomfuncs.hpp \
+  libsrc/gprim/geom2d.hpp libsrc/gprim/geom3d.hpp \
+  libsrc/gprim/geomtest3d.hpp libsrc/gprim/transform3d.hpp \
+  libsrc/gprim/adtree.hpp libsrc/include/meshing.hpp \
+  libsrc/meshing/meshing.hpp libsrc/include/opti.hpp libsrc/opti/opti.hpp \
+  libsrc/meshing/msghandler.hpp libsrc/meshing/meshtype.hpp \
+  libsrc/meshing/localh.hpp libsrc/meshing/meshclass.hpp \
+  libsrc/meshing/global.hpp libsrc/meshing/meshtool.hpp \
+  libsrc/meshing/ruler2.hpp libsrc/meshing/adfront2.hpp \
+  libsrc/meshing/meshing2.hpp libsrc/meshing/improve2.hpp \
+  libsrc/meshing/geomsearch.hpp libsrc/meshing/adfront3.hpp \
+  libsrc/meshing/ruler3.hpp libsrc/meshing/meshing3.hpp \
+  libsrc/meshing/improve3.hpp libsrc/meshing/findip.hpp \
+  libsrc/meshing/topology.hpp libsrc/meshing/curvedelems.hpp \
+  libsrc/meshing/bisect.hpp libsrc/meshing/clusters.hpp \
+  libsrc/meshing/meshfunc.hpp libsrc/meshing/hprefinement.hpp \
+  libsrc/meshing/boundarylayer.hpp libsrc/meshing/specials.hpp \
+  libsrc/csg/surface.hpp libsrc/csg/solid.hpp libsrc/csg/identify.hpp \
+  libsrc/csg/singularref.hpp libsrc/csg/csgeom.hpp \
+  libsrc/csg/triapprox.hpp libsrc/csg/algprim.hpp libsrc/csg/brick.hpp \
+  libsrc/csg/spline3d.hpp libsrc/csg/manifold.hpp libsrc/csg/curve2d.hpp \
+  libsrc/csg/explicitcurve2d.hpp libsrc/csg/gencyl.hpp \
+  libsrc/csg/polyhedra.hpp libsrc/csg/extrusion.hpp \
+  libsrc/csg/revolution.hpp libsrc/csg/specpoin.hpp \
+  libsrc/csg/edgeflw.hpp libsrc/csg/meshsurf.hpp \
+  libsrc/include/stlgeom.hpp libsrc/stlgeom/stlgeom.hpp \
+  libsrc/stlgeom/stltopology.hpp libsrc/stlgeom/stltool.hpp \
+  libsrc/stlgeom/stlline.hpp libsrc/stlgeom/meshstlsurface.hpp \
+  libsrc/include/geometry2d.hpp libsrc/geom2d/geometry2d.hpp \
+  libsrc/geom2d/spline2d.hpp libsrc/geom2d/splinegeometry2.hpp \
+  libsrc/geom2d/geom2dmesh.hpp libsrc/interface/nglib.h
+geomtest3d.o: libsrc/gprim/geomtest3d.cpp libsrc/include/mystdlib.h \
+  libsrc/include/myadt.hpp libsrc/general/myadt.hpp \
+  libsrc/include/mydefs.hpp libsrc/general/ngexception.hpp \
+  libsrc/general/parthreads.hpp libsrc/general/moveablemem.hpp \
+  libsrc/general/dynamicmem.hpp libsrc/general/template.hpp \
+  libsrc/general/array.hpp libsrc/general/table.hpp \
+  libsrc/general/hashtabl.hpp libsrc/general/symbolta.hpp \
+  libsrc/general/bitarray.hpp libsrc/general/flags.hpp \
+  libsrc/general/spbita2d.hpp libsrc/general/seti.hpp \
+  libsrc/general/optmem.hpp libsrc/general/autoptr.hpp \
+  libsrc/general/sort.hpp libsrc/general/stack.hpp \
+  libsrc/general/mystring.hpp libsrc/include/linalg.hpp \
+  libsrc/linalg/linalg.hpp libsrc/linalg/vector.hpp \
+  libsrc/linalg/densemat.hpp libsrc/linalg/polynomial.hpp \
+  libsrc/include/gprim.hpp libsrc/gprim/gprim.hpp \
+  libsrc/gprim/geomobjects.hpp libsrc/gprim/geomops.hpp \
+  libsrc/gprim/geomfuncs.hpp libsrc/gprim/geom2d.hpp \
+  libsrc/gprim/geom3d.hpp libsrc/gprim/geomtest3d.hpp \
+  libsrc/gprim/transform3d.hpp libsrc/gprim/adtree.hpp
+geom2d.o: libsrc/gprim/geom2d.cpp libsrc/include/mystdlib.h \
+  libsrc/include/myadt.hpp libsrc/general/myadt.hpp \
+  libsrc/include/mydefs.hpp libsrc/general/ngexception.hpp \
+  libsrc/general/parthreads.hpp libsrc/general/moveablemem.hpp \
+  libsrc/general/dynamicmem.hpp libsrc/general/template.hpp \
+  libsrc/general/array.hpp libsrc/general/table.hpp \
+  libsrc/general/hashtabl.hpp libsrc/general/symbolta.hpp \
+  libsrc/general/bitarray.hpp libsrc/general/flags.hpp \
+  libsrc/general/spbita2d.hpp libsrc/general/seti.hpp \
+  libsrc/general/optmem.hpp libsrc/general/autoptr.hpp \
+  libsrc/general/sort.hpp libsrc/general/stack.hpp \
+  libsrc/general/mystring.hpp libsrc/include/gprim.hpp \
+  libsrc/gprim/gprim.hpp libsrc/gprim/geomobjects.hpp \
+  libsrc/gprim/geomops.hpp libsrc/gprim/geomfuncs.hpp \
+  libsrc/gprim/geom2d.hpp libsrc/gprim/geom3d.hpp \
+  libsrc/gprim/geomtest3d.hpp libsrc/gprim/transform3d.hpp \
+  libsrc/gprim/adtree.hpp
+geom3d.o: libsrc/gprim/geom3d.cpp libsrc/include/mystdlib.h \
+  libsrc/include/myadt.hpp libsrc/general/myadt.hpp \
+  libsrc/include/mydefs.hpp libsrc/general/ngexception.hpp \
+  libsrc/general/parthreads.hpp libsrc/general/moveablemem.hpp \
+  libsrc/general/dynamicmem.hpp libsrc/general/template.hpp \
+  libsrc/general/array.hpp libsrc/general/table.hpp \
+  libsrc/general/hashtabl.hpp libsrc/general/symbolta.hpp \
+  libsrc/general/bitarray.hpp libsrc/general/flags.hpp \
+  libsrc/general/spbita2d.hpp libsrc/general/seti.hpp \
+  libsrc/general/optmem.hpp libsrc/general/autoptr.hpp \
+  libsrc/general/sort.hpp libsrc/general/stack.hpp \
+  libsrc/general/mystring.hpp libsrc/include/gprim.hpp \
+  libsrc/gprim/gprim.hpp libsrc/gprim/geomobjects.hpp \
+  libsrc/gprim/geomops.hpp libsrc/gprim/geomfuncs.hpp \
+  libsrc/gprim/geom2d.hpp libsrc/gprim/geom3d.hpp \
+  libsrc/gprim/geomtest3d.hpp libsrc/gprim/transform3d.hpp \
+  libsrc/gprim/adtree.hpp
+adtree.o: libsrc/gprim/adtree.cpp libsrc/include/mystdlib.h \
+  libsrc/include/myadt.hpp libsrc/general/myadt.hpp \
+  libsrc/include/mydefs.hpp libsrc/general/ngexception.hpp \
+  libsrc/general/parthreads.hpp libsrc/general/moveablemem.hpp \
+  libsrc/general/dynamicmem.hpp libsrc/general/template.hpp \
+  libsrc/general/array.hpp libsrc/general/table.hpp \
+  libsrc/general/hashtabl.hpp libsrc/general/symbolta.hpp \
+  libsrc/general/bitarray.hpp libsrc/general/flags.hpp \
+  libsrc/general/spbita2d.hpp libsrc/general/seti.hpp \
+  libsrc/general/optmem.hpp libsrc/general/autoptr.hpp \
+  libsrc/general/sort.hpp libsrc/general/stack.hpp \
+  libsrc/general/mystring.hpp libsrc/include/gprim.hpp \
+  libsrc/gprim/gprim.hpp libsrc/gprim/geomobjects.hpp \
+  libsrc/gprim/geomops.hpp libsrc/gprim/geomfuncs.hpp \
+  libsrc/gprim/geom2d.hpp libsrc/gprim/geom3d.hpp \
+  libsrc/gprim/geomtest3d.hpp libsrc/gprim/transform3d.hpp \
+  libsrc/gprim/adtree.hpp
+transform3d.o: libsrc/gprim/transform3d.cpp libsrc/include/mystdlib.h \
+  libsrc/include/myadt.hpp libsrc/general/myadt.hpp \
+  libsrc/include/mydefs.hpp libsrc/general/ngexception.hpp \
+  libsrc/general/parthreads.hpp libsrc/general/moveablemem.hpp \
+  libsrc/general/dynamicmem.hpp libsrc/general/template.hpp \
+  libsrc/general/array.hpp libsrc/general/table.hpp \
+  libsrc/general/hashtabl.hpp libsrc/general/symbolta.hpp \
+  libsrc/general/bitarray.hpp libsrc/general/flags.hpp \
+  libsrc/general/spbita2d.hpp libsrc/general/seti.hpp \
+  libsrc/general/optmem.hpp libsrc/general/autoptr.hpp \
+  libsrc/general/sort.hpp libsrc/general/stack.hpp \
+  libsrc/general/mystring.hpp libsrc/include/gprim.hpp \
+  libsrc/gprim/gprim.hpp libsrc/gprim/geomobjects.hpp \
+  libsrc/gprim/geomops.hpp libsrc/gprim/geomfuncs.hpp \
+  libsrc/gprim/geom2d.hpp libsrc/gprim/geom3d.hpp \
+  libsrc/gprim/geomtest3d.hpp libsrc/gprim/transform3d.hpp \
+  libsrc/gprim/adtree.hpp libsrc/include/linalg.hpp \
+  libsrc/linalg/linalg.hpp libsrc/linalg/vector.hpp \
+  libsrc/linalg/densemat.hpp libsrc/linalg/polynomial.hpp
+geomfuncs.o: libsrc/gprim/geomfuncs.cpp libsrc/include/mystdlib.h \
+  libsrc/include/myadt.hpp libsrc/general/myadt.hpp \
+  libsrc/include/mydefs.hpp libsrc/general/ngexception.hpp \
+  libsrc/general/parthreads.hpp libsrc/general/moveablemem.hpp \
+  libsrc/general/dynamicmem.hpp libsrc/general/template.hpp \
+  libsrc/general/array.hpp libsrc/general/table.hpp \
+  libsrc/general/hashtabl.hpp libsrc/general/symbolta.hpp \
+  libsrc/general/bitarray.hpp libsrc/general/flags.hpp \
+  libsrc/general/spbita2d.hpp libsrc/general/seti.hpp \
+  libsrc/general/optmem.hpp libsrc/general/autoptr.hpp \
+  libsrc/general/sort.hpp libsrc/general/stack.hpp \
+  libsrc/general/mystring.hpp libsrc/include/gprim.hpp \
+  libsrc/gprim/gprim.hpp libsrc/gprim/geomobjects.hpp \
+  libsrc/gprim/geomops.hpp libsrc/gprim/geomfuncs.hpp \
+  libsrc/gprim/geom2d.hpp libsrc/gprim/geom3d.hpp \
+  libsrc/gprim/geomtest3d.hpp libsrc/gprim/transform3d.hpp \
+  libsrc/gprim/adtree.hpp
+polynomial.o: libsrc/linalg/polynomial.cpp libsrc/include/mystdlib.h \
+  libsrc/include/linalg.hpp libsrc/linalg/linalg.hpp \
+  libsrc/include/myadt.hpp libsrc/general/myadt.hpp \
+  libsrc/include/mydefs.hpp libsrc/general/ngexception.hpp \
+  libsrc/general/parthreads.hpp libsrc/general/moveablemem.hpp \
+  libsrc/general/dynamicmem.hpp libsrc/general/template.hpp \
+  libsrc/general/array.hpp libsrc/general/table.hpp \
+  libsrc/general/hashtabl.hpp libsrc/general/symbolta.hpp \
+  libsrc/general/bitarray.hpp libsrc/general/flags.hpp \
+  libsrc/general/spbita2d.hpp libsrc/general/seti.hpp \
+  libsrc/general/optmem.hpp libsrc/general/autoptr.hpp \
+  libsrc/general/sort.hpp libsrc/general/stack.hpp \
+  libsrc/general/mystring.hpp libsrc/linalg/vector.hpp \
+  libsrc/linalg/densemat.hpp libsrc/linalg/polynomial.hpp
+densemat.o: libsrc/linalg/densemat.cpp libsrc/include/mystdlib.h \
+  libsrc/include/linalg.hpp libsrc/linalg/linalg.hpp \
+  libsrc/include/myadt.hpp libsrc/general/myadt.hpp \
+  libsrc/include/mydefs.hpp libsrc/general/ngexception.hpp \
+  libsrc/general/parthreads.hpp libsrc/general/moveablemem.hpp \
+  libsrc/general/dynamicmem.hpp libsrc/general/template.hpp \
+  libsrc/general/array.hpp libsrc/general/table.hpp \
+  libsrc/general/hashtabl.hpp libsrc/general/symbolta.hpp \
+  libsrc/general/bitarray.hpp libsrc/general/flags.hpp \
+  libsrc/general/spbita2d.hpp libsrc/general/seti.hpp \
+  libsrc/general/optmem.hpp libsrc/general/autoptr.hpp \
+  libsrc/general/sort.hpp libsrc/general/stack.hpp \
+  libsrc/general/mystring.hpp libsrc/linalg/vector.hpp \
+  libsrc/linalg/densemat.hpp libsrc/linalg/polynomial.hpp
+vector.o: libsrc/linalg/vector.cpp
+algprim.o: libsrc/csg/algprim.cpp libsrc/include/mystdlib.h \
+  libsrc/include/linalg.hpp libsrc/linalg/linalg.hpp \
+  libsrc/include/myadt.hpp libsrc/general/myadt.hpp \
+  libsrc/include/mydefs.hpp libsrc/general/ngexception.hpp \
+  libsrc/general/parthreads.hpp libsrc/general/moveablemem.hpp \
+  libsrc/general/dynamicmem.hpp libsrc/general/template.hpp \
+  libsrc/general/array.hpp libsrc/general/table.hpp \
+  libsrc/general/hashtabl.hpp libsrc/general/symbolta.hpp \
+  libsrc/general/bitarray.hpp libsrc/general/flags.hpp \
+  libsrc/general/spbita2d.hpp libsrc/general/seti.hpp \
+  libsrc/general/optmem.hpp libsrc/general/autoptr.hpp \
+  libsrc/general/sort.hpp libsrc/general/stack.hpp \
+  libsrc/general/mystring.hpp libsrc/linalg/vector.hpp \
+  libsrc/linalg/densemat.hpp libsrc/linalg/polynomial.hpp \
+  libsrc/include/csg.hpp libsrc/csg/csg.hpp libsrc/include/gprim.hpp \
+  libsrc/gprim/gprim.hpp libsrc/gprim/geomobjects.hpp \
+  libsrc/gprim/geomops.hpp libsrc/gprim/geomfuncs.hpp \
+  libsrc/gprim/geom2d.hpp libsrc/gprim/geom3d.hpp \
+  libsrc/gprim/geomtest3d.hpp libsrc/gprim/transform3d.hpp \
+  libsrc/gprim/adtree.hpp libsrc/include/meshing.hpp \
+  libsrc/meshing/meshing.hpp libsrc/include/opti.hpp libsrc/opti/opti.hpp \
+  libsrc/meshing/msghandler.hpp libsrc/meshing/meshtype.hpp \
+  libsrc/meshing/localh.hpp libsrc/meshing/meshclass.hpp \
+  libsrc/meshing/global.hpp libsrc/meshing/meshtool.hpp \
+  libsrc/meshing/ruler2.hpp libsrc/meshing/adfront2.hpp \
+  libsrc/meshing/meshing2.hpp libsrc/meshing/improve2.hpp \
+  libsrc/meshing/geomsearch.hpp libsrc/meshing/adfront3.hpp \
+  libsrc/meshing/ruler3.hpp libsrc/meshing/meshing3.hpp \
+  libsrc/meshing/improve3.hpp libsrc/meshing/findip.hpp \
+  libsrc/meshing/topology.hpp libsrc/meshing/curvedelems.hpp \
+  libsrc/meshing/bisect.hpp libsrc/meshing/clusters.hpp \
+  libsrc/meshing/meshfunc.hpp libsrc/meshing/hprefinement.hpp \
+  libsrc/meshing/boundarylayer.hpp libsrc/meshing/specials.hpp \
+  libsrc/csg/surface.hpp libsrc/csg/solid.hpp libsrc/csg/identify.hpp \
+  libsrc/csg/singularref.hpp libsrc/csg/csgeom.hpp \
+  libsrc/csg/triapprox.hpp libsrc/csg/algprim.hpp libsrc/csg/brick.hpp \
+  libsrc/csg/spline3d.hpp libsrc/csg/manifold.hpp libsrc/csg/curve2d.hpp \
+  libsrc/csg/explicitcurve2d.hpp libsrc/csg/gencyl.hpp \
+  libsrc/csg/polyhedra.hpp libsrc/csg/extrusion.hpp \
+  libsrc/csg/revolution.hpp libsrc/csg/specpoin.hpp \
+  libsrc/csg/edgeflw.hpp libsrc/csg/meshsurf.hpp
+brick.o: libsrc/csg/brick.cpp libsrc/include/mystdlib.h \
+  libsrc/include/linalg.hpp libsrc/linalg/linalg.hpp \
+  libsrc/include/myadt.hpp libsrc/general/myadt.hpp \
+  libsrc/include/mydefs.hpp libsrc/general/ngexception.hpp \
+  libsrc/general/parthreads.hpp libsrc/general/moveablemem.hpp \
+  libsrc/general/dynamicmem.hpp libsrc/general/template.hpp \
+  libsrc/general/array.hpp libsrc/general/table.hpp \
+  libsrc/general/hashtabl.hpp libsrc/general/symbolta.hpp \
+  libsrc/general/bitarray.hpp libsrc/general/flags.hpp \
+  libsrc/general/spbita2d.hpp libsrc/general/seti.hpp \
+  libsrc/general/optmem.hpp libsrc/general/autoptr.hpp \
+  libsrc/general/sort.hpp libsrc/general/stack.hpp \
+  libsrc/general/mystring.hpp libsrc/linalg/vector.hpp \
+  libsrc/linalg/densemat.hpp libsrc/linalg/polynomial.hpp \
+  libsrc/include/csg.hpp libsrc/csg/csg.hpp libsrc/include/gprim.hpp \
+  libsrc/gprim/gprim.hpp libsrc/gprim/geomobjects.hpp \
+  libsrc/gprim/geomops.hpp libsrc/gprim/geomfuncs.hpp \
+  libsrc/gprim/geom2d.hpp libsrc/gprim/geom3d.hpp \
+  libsrc/gprim/geomtest3d.hpp libsrc/gprim/transform3d.hpp \
+  libsrc/gprim/adtree.hpp libsrc/include/meshing.hpp \
+  libsrc/meshing/meshing.hpp libsrc/include/opti.hpp libsrc/opti/opti.hpp \
+  libsrc/meshing/msghandler.hpp libsrc/meshing/meshtype.hpp \
+  libsrc/meshing/localh.hpp libsrc/meshing/meshclass.hpp \
+  libsrc/meshing/global.hpp libsrc/meshing/meshtool.hpp \
+  libsrc/meshing/ruler2.hpp libsrc/meshing/adfront2.hpp \
+  libsrc/meshing/meshing2.hpp libsrc/meshing/improve2.hpp \
+  libsrc/meshing/geomsearch.hpp libsrc/meshing/adfront3.hpp \
+  libsrc/meshing/ruler3.hpp libsrc/meshing/meshing3.hpp \
+  libsrc/meshing/improve3.hpp libsrc/meshing/findip.hpp \
+  libsrc/meshing/topology.hpp libsrc/meshing/curvedelems.hpp \
+  libsrc/meshing/bisect.hpp libsrc/meshing/clusters.hpp \
+  libsrc/meshing/meshfunc.hpp libsrc/meshing/hprefinement.hpp \
+  libsrc/meshing/boundarylayer.hpp libsrc/meshing/specials.hpp \
+  libsrc/csg/surface.hpp libsrc/csg/solid.hpp libsrc/csg/identify.hpp \
+  libsrc/csg/singularref.hpp libsrc/csg/csgeom.hpp \
+  libsrc/csg/triapprox.hpp libsrc/csg/algprim.hpp libsrc/csg/brick.hpp \
+  libsrc/csg/spline3d.hpp libsrc/csg/manifold.hpp libsrc/csg/curve2d.hpp \
+  libsrc/csg/explicitcurve2d.hpp libsrc/csg/gencyl.hpp \
+  libsrc/csg/polyhedra.hpp libsrc/csg/extrusion.hpp \
+  libsrc/csg/revolution.hpp libsrc/csg/specpoin.hpp \
+  libsrc/csg/edgeflw.hpp libsrc/csg/meshsurf.hpp
+manifold.o: libsrc/csg/manifold.cpp libsrc/include/csg.hpp \
+  libsrc/csg/csg.hpp libsrc/include/myadt.hpp libsrc/general/myadt.hpp \
+  libsrc/include/mystdlib.h libsrc/include/mydefs.hpp \
+  libsrc/general/ngexception.hpp libsrc/general/parthreads.hpp \
+  libsrc/general/moveablemem.hpp libsrc/general/dynamicmem.hpp \
+  libsrc/general/template.hpp libsrc/general/array.hpp \
+  libsrc/general/table.hpp libsrc/general/hashtabl.hpp \
+  libsrc/general/symbolta.hpp libsrc/general/bitarray.hpp \
+  libsrc/general/flags.hpp libsrc/general/spbita2d.hpp \
+  libsrc/general/seti.hpp libsrc/general/optmem.hpp \
+  libsrc/general/autoptr.hpp libsrc/general/sort.hpp \
+  libsrc/general/stack.hpp libsrc/general/mystring.hpp \
+  libsrc/include/gprim.hpp libsrc/gprim/gprim.hpp \
+  libsrc/gprim/geomobjects.hpp libsrc/gprim/geomops.hpp \
+  libsrc/gprim/geomfuncs.hpp libsrc/gprim/geom2d.hpp \
+  libsrc/gprim/geom3d.hpp libsrc/gprim/geomtest3d.hpp \
+  libsrc/gprim/transform3d.hpp libsrc/gprim/adtree.hpp \
+  libsrc/include/meshing.hpp libsrc/meshing/meshing.hpp \
+  libsrc/include/linalg.hpp libsrc/linalg/linalg.hpp \
+  libsrc/linalg/vector.hpp libsrc/linalg/densemat.hpp \
+  libsrc/linalg/polynomial.hpp libsrc/include/opti.hpp \
+  libsrc/opti/opti.hpp libsrc/meshing/msghandler.hpp \
+  libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \
+  libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \
+  libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \
+  libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \
+  libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \
+  libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \
+  libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \
+  libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \
+  libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \
+  libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \
+  libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \
+  libsrc/meshing/specials.hpp libsrc/csg/surface.hpp libsrc/csg/solid.hpp \
+  libsrc/csg/identify.hpp libsrc/csg/singularref.hpp \
+  libsrc/csg/csgeom.hpp libsrc/csg/triapprox.hpp libsrc/csg/algprim.hpp \
+  libsrc/csg/brick.hpp libsrc/csg/spline3d.hpp libsrc/csg/manifold.hpp \
+  libsrc/csg/curve2d.hpp libsrc/csg/explicitcurve2d.hpp \
+  libsrc/csg/gencyl.hpp libsrc/csg/polyhedra.hpp libsrc/csg/extrusion.hpp \
+  libsrc/csg/revolution.hpp libsrc/csg/specpoin.hpp \
+  libsrc/csg/edgeflw.hpp libsrc/csg/meshsurf.hpp
+bspline2d.o: libsrc/csg/bspline2d.cpp libsrc/include/mystdlib.h \
+  libsrc/include/csg.hpp libsrc/csg/csg.hpp libsrc/include/myadt.hpp \
+  libsrc/general/myadt.hpp libsrc/include/mydefs.hpp \
+  libsrc/general/ngexception.hpp libsrc/general/parthreads.hpp \
+  libsrc/general/moveablemem.hpp libsrc/general/dynamicmem.hpp \
+  libsrc/general/template.hpp libsrc/general/array.hpp \
+  libsrc/general/table.hpp libsrc/general/hashtabl.hpp \
+  libsrc/general/symbolta.hpp libsrc/general/bitarray.hpp \
+  libsrc/general/flags.hpp libsrc/general/spbita2d.hpp \
+  libsrc/general/seti.hpp libsrc/general/optmem.hpp \
+  libsrc/general/autoptr.hpp libsrc/general/sort.hpp \
+  libsrc/general/stack.hpp libsrc/general/mystring.hpp \
+  libsrc/include/gprim.hpp libsrc/gprim/gprim.hpp \
+  libsrc/gprim/geomobjects.hpp libsrc/gprim/geomops.hpp \
+  libsrc/gprim/geomfuncs.hpp libsrc/gprim/geom2d.hpp \
+  libsrc/gprim/geom3d.hpp libsrc/gprim/geomtest3d.hpp \
+  libsrc/gprim/transform3d.hpp libsrc/gprim/adtree.hpp \
+  libsrc/include/meshing.hpp libsrc/meshing/meshing.hpp \
+  libsrc/include/linalg.hpp libsrc/linalg/linalg.hpp \
+  libsrc/linalg/vector.hpp libsrc/linalg/densemat.hpp \
+  libsrc/linalg/polynomial.hpp libsrc/include/opti.hpp \
+  libsrc/opti/opti.hpp libsrc/meshing/msghandler.hpp \
+  libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \
+  libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \
+  libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \
+  libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \
+  libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \
+  libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \
+  libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \
+  libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \
+  libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \
+  libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \
+  libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \
+  libsrc/meshing/specials.hpp libsrc/csg/surface.hpp libsrc/csg/solid.hpp \
+  libsrc/csg/identify.hpp libsrc/csg/singularref.hpp \
+  libsrc/csg/csgeom.hpp libsrc/csg/triapprox.hpp libsrc/csg/algprim.hpp \
+  libsrc/csg/brick.hpp libsrc/csg/spline3d.hpp libsrc/csg/manifold.hpp \
+  libsrc/csg/curve2d.hpp libsrc/csg/explicitcurve2d.hpp \
+  libsrc/csg/gencyl.hpp libsrc/csg/polyhedra.hpp libsrc/csg/extrusion.hpp \
+  libsrc/csg/revolution.hpp libsrc/csg/specpoin.hpp \
+  libsrc/csg/edgeflw.hpp libsrc/csg/meshsurf.hpp
+meshsurf.o: libsrc/csg/meshsurf.cpp libsrc/include/mystdlib.h \
+  libsrc/include/csg.hpp libsrc/csg/csg.hpp libsrc/include/myadt.hpp \
+  libsrc/general/myadt.hpp libsrc/include/mydefs.hpp \
+  libsrc/general/ngexception.hpp libsrc/general/parthreads.hpp \
+  libsrc/general/moveablemem.hpp libsrc/general/dynamicmem.hpp \
+  libsrc/general/template.hpp libsrc/general/array.hpp \
+  libsrc/general/table.hpp libsrc/general/hashtabl.hpp \
+  libsrc/general/symbolta.hpp libsrc/general/bitarray.hpp \
+  libsrc/general/flags.hpp libsrc/general/spbita2d.hpp \
+  libsrc/general/seti.hpp libsrc/general/optmem.hpp \
+  libsrc/general/autoptr.hpp libsrc/general/sort.hpp \
+  libsrc/general/stack.hpp libsrc/general/mystring.hpp \
+  libsrc/include/gprim.hpp libsrc/gprim/gprim.hpp \
+  libsrc/gprim/geomobjects.hpp libsrc/gprim/geomops.hpp \
+  libsrc/gprim/geomfuncs.hpp libsrc/gprim/geom2d.hpp \
+  libsrc/gprim/geom3d.hpp libsrc/gprim/geomtest3d.hpp \
+  libsrc/gprim/transform3d.hpp libsrc/gprim/adtree.hpp \
+  libsrc/include/meshing.hpp libsrc/meshing/meshing.hpp \
+  libsrc/include/linalg.hpp libsrc/linalg/linalg.hpp \
+  libsrc/linalg/vector.hpp libsrc/linalg/densemat.hpp \
+  libsrc/linalg/polynomial.hpp libsrc/include/opti.hpp \
+  libsrc/opti/opti.hpp libsrc/meshing/msghandler.hpp \
+  libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \
+  libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \
+  libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \
+  libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \
+  libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \
+  libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \
+  libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \
+  libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \
+  libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \
+  libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \
+  libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \
+  libsrc/meshing/specials.hpp libsrc/csg/surface.hpp libsrc/csg/solid.hpp \
+  libsrc/csg/identify.hpp libsrc/csg/singularref.hpp \
+  libsrc/csg/csgeom.hpp libsrc/csg/triapprox.hpp libsrc/csg/algprim.hpp \
+  libsrc/csg/brick.hpp libsrc/csg/spline3d.hpp libsrc/csg/manifold.hpp \
+  libsrc/csg/curve2d.hpp libsrc/csg/explicitcurve2d.hpp \
+  libsrc/csg/gencyl.hpp libsrc/csg/polyhedra.hpp libsrc/csg/extrusion.hpp \
+  libsrc/csg/revolution.hpp libsrc/csg/specpoin.hpp \
+  libsrc/csg/edgeflw.hpp libsrc/csg/meshsurf.hpp
+csgeom.o: libsrc/csg/csgeom.cpp libsrc/include/mystdlib.h \
+  libsrc/include/myadt.hpp libsrc/general/myadt.hpp \
+  libsrc/include/mydefs.hpp libsrc/general/ngexception.hpp \
+  libsrc/general/parthreads.hpp libsrc/general/moveablemem.hpp \
+  libsrc/general/dynamicmem.hpp libsrc/general/template.hpp \
+  libsrc/general/array.hpp libsrc/general/table.hpp \
+  libsrc/general/hashtabl.hpp libsrc/general/symbolta.hpp \
+  libsrc/general/bitarray.hpp libsrc/general/flags.hpp \
+  libsrc/general/spbita2d.hpp libsrc/general/seti.hpp \
+  libsrc/general/optmem.hpp libsrc/general/autoptr.hpp \
+  libsrc/general/sort.hpp libsrc/general/stack.hpp \
+  libsrc/general/mystring.hpp libsrc/include/linalg.hpp \
+  libsrc/linalg/linalg.hpp libsrc/linalg/vector.hpp \
+  libsrc/linalg/densemat.hpp libsrc/linalg/polynomial.hpp \
+  libsrc/include/csg.hpp libsrc/csg/csg.hpp libsrc/include/gprim.hpp \
+  libsrc/gprim/gprim.hpp libsrc/gprim/geomobjects.hpp \
+  libsrc/gprim/geomops.hpp libsrc/gprim/geomfuncs.hpp \
+  libsrc/gprim/geom2d.hpp libsrc/gprim/geom3d.hpp \
+  libsrc/gprim/geomtest3d.hpp libsrc/gprim/transform3d.hpp \
+  libsrc/gprim/adtree.hpp libsrc/include/meshing.hpp \
+  libsrc/meshing/meshing.hpp libsrc/include/opti.hpp libsrc/opti/opti.hpp \
+  libsrc/meshing/msghandler.hpp libsrc/meshing/meshtype.hpp \
+  libsrc/meshing/localh.hpp libsrc/meshing/meshclass.hpp \
+  libsrc/meshing/global.hpp libsrc/meshing/meshtool.hpp \
+  libsrc/meshing/ruler2.hpp libsrc/meshing/adfront2.hpp \
+  libsrc/meshing/meshing2.hpp libsrc/meshing/improve2.hpp \
+  libsrc/meshing/geomsearch.hpp libsrc/meshing/adfront3.hpp \
+  libsrc/meshing/ruler3.hpp libsrc/meshing/meshing3.hpp \
+  libsrc/meshing/improve3.hpp libsrc/meshing/findip.hpp \
+  libsrc/meshing/topology.hpp libsrc/meshing/curvedelems.hpp \
+  libsrc/meshing/bisect.hpp libsrc/meshing/clusters.hpp \
+  libsrc/meshing/meshfunc.hpp libsrc/meshing/hprefinement.hpp \
+  libsrc/meshing/boundarylayer.hpp libsrc/meshing/specials.hpp \
+  libsrc/csg/surface.hpp libsrc/csg/solid.hpp libsrc/csg/identify.hpp \
+  libsrc/csg/singularref.hpp libsrc/csg/csgeom.hpp \
+  libsrc/csg/triapprox.hpp libsrc/csg/algprim.hpp libsrc/csg/brick.hpp \
+  libsrc/csg/spline3d.hpp libsrc/csg/manifold.hpp libsrc/csg/curve2d.hpp \
+  libsrc/csg/explicitcurve2d.hpp libsrc/csg/gencyl.hpp \
+  libsrc/csg/polyhedra.hpp libsrc/csg/extrusion.hpp \
+  libsrc/csg/revolution.hpp libsrc/csg/specpoin.hpp \
+  libsrc/csg/edgeflw.hpp libsrc/csg/meshsurf.hpp
+polyhedra.o: libsrc/csg/polyhedra.cpp libsrc/include/mystdlib.h \
+  libsrc/include/linalg.hpp libsrc/linalg/linalg.hpp \
+  libsrc/include/myadt.hpp libsrc/general/myadt.hpp \
+  libsrc/include/mydefs.hpp libsrc/general/ngexception.hpp \
+  libsrc/general/parthreads.hpp libsrc/general/moveablemem.hpp \
+  libsrc/general/dynamicmem.hpp libsrc/general/template.hpp \
+  libsrc/general/array.hpp libsrc/general/table.hpp \
+  libsrc/general/hashtabl.hpp libsrc/general/symbolta.hpp \
+  libsrc/general/bitarray.hpp libsrc/general/flags.hpp \
+  libsrc/general/spbita2d.hpp libsrc/general/seti.hpp \
+  libsrc/general/optmem.hpp libsrc/general/autoptr.hpp \
+  libsrc/general/sort.hpp libsrc/general/stack.hpp \
+  libsrc/general/mystring.hpp libsrc/linalg/vector.hpp \
+  libsrc/linalg/densemat.hpp libsrc/linalg/polynomial.hpp \
+  libsrc/include/csg.hpp libsrc/csg/csg.hpp libsrc/include/gprim.hpp \
+  libsrc/gprim/gprim.hpp libsrc/gprim/geomobjects.hpp \
+  libsrc/gprim/geomops.hpp libsrc/gprim/geomfuncs.hpp \
+  libsrc/gprim/geom2d.hpp libsrc/gprim/geom3d.hpp \
+  libsrc/gprim/geomtest3d.hpp libsrc/gprim/transform3d.hpp \
+  libsrc/gprim/adtree.hpp libsrc/include/meshing.hpp \
+  libsrc/meshing/meshing.hpp libsrc/include/opti.hpp libsrc/opti/opti.hpp \
+  libsrc/meshing/msghandler.hpp libsrc/meshing/meshtype.hpp \
+  libsrc/meshing/localh.hpp libsrc/meshing/meshclass.hpp \
+  libsrc/meshing/global.hpp libsrc/meshing/meshtool.hpp \
+  libsrc/meshing/ruler2.hpp libsrc/meshing/adfront2.hpp \
+  libsrc/meshing/meshing2.hpp libsrc/meshing/improve2.hpp \
+  libsrc/meshing/geomsearch.hpp libsrc/meshing/adfront3.hpp \
+  libsrc/meshing/ruler3.hpp libsrc/meshing/meshing3.hpp \
+  libsrc/meshing/improve3.hpp libsrc/meshing/findip.hpp \
+  libsrc/meshing/topology.hpp libsrc/meshing/curvedelems.hpp \
+  libsrc/meshing/bisect.hpp libsrc/meshing/clusters.hpp \
+  libsrc/meshing/meshfunc.hpp libsrc/meshing/hprefinement.hpp \
+  libsrc/meshing/boundarylayer.hpp libsrc/meshing/specials.hpp \
+  libsrc/csg/surface.hpp libsrc/csg/solid.hpp libsrc/csg/identify.hpp \
+  libsrc/csg/singularref.hpp libsrc/csg/csgeom.hpp \
+  libsrc/csg/triapprox.hpp libsrc/csg/algprim.hpp libsrc/csg/brick.hpp \
+  libsrc/csg/spline3d.hpp libsrc/csg/manifold.hpp libsrc/csg/curve2d.hpp \
+  libsrc/csg/explicitcurve2d.hpp libsrc/csg/gencyl.hpp \
+  libsrc/csg/polyhedra.hpp libsrc/csg/extrusion.hpp \
+  libsrc/csg/revolution.hpp libsrc/csg/specpoin.hpp \
+  libsrc/csg/edgeflw.hpp libsrc/csg/meshsurf.hpp
+curve2d.o: libsrc/csg/curve2d.cpp libsrc/include/mystdlib.h \
+  libsrc/include/myadt.hpp libsrc/general/myadt.hpp \
+  libsrc/include/mydefs.hpp libsrc/general/ngexception.hpp \
+  libsrc/general/parthreads.hpp libsrc/general/moveablemem.hpp \
+  libsrc/general/dynamicmem.hpp libsrc/general/template.hpp \
+  libsrc/general/array.hpp libsrc/general/table.hpp \
+  libsrc/general/hashtabl.hpp libsrc/general/symbolta.hpp \
+  libsrc/general/bitarray.hpp libsrc/general/flags.hpp \
+  libsrc/general/spbita2d.hpp libsrc/general/seti.hpp \
+  libsrc/general/optmem.hpp libsrc/general/autoptr.hpp \
+  libsrc/general/sort.hpp libsrc/general/stack.hpp \
+  libsrc/general/mystring.hpp libsrc/include/csg.hpp libsrc/csg/csg.hpp \
+  libsrc/include/gprim.hpp libsrc/gprim/gprim.hpp \
+  libsrc/gprim/geomobjects.hpp libsrc/gprim/geomops.hpp \
+  libsrc/gprim/geomfuncs.hpp libsrc/gprim/geom2d.hpp \
+  libsrc/gprim/geom3d.hpp libsrc/gprim/geomtest3d.hpp \
+  libsrc/gprim/transform3d.hpp libsrc/gprim/adtree.hpp \
+  libsrc/include/meshing.hpp libsrc/meshing/meshing.hpp \
+  libsrc/include/linalg.hpp libsrc/linalg/linalg.hpp \
+  libsrc/linalg/vector.hpp libsrc/linalg/densemat.hpp \
+  libsrc/linalg/polynomial.hpp libsrc/include/opti.hpp \
+  libsrc/opti/opti.hpp libsrc/meshing/msghandler.hpp \
+  libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \
+  libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \
+  libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \
+  libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \
+  libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \
+  libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \
+  libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \
+  libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \
+  libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \
+  libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \
+  libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \
+  libsrc/meshing/specials.hpp libsrc/csg/surface.hpp libsrc/csg/solid.hpp \
+  libsrc/csg/identify.hpp libsrc/csg/singularref.hpp \
+  libsrc/csg/csgeom.hpp libsrc/csg/triapprox.hpp libsrc/csg/algprim.hpp \
+  libsrc/csg/brick.hpp libsrc/csg/spline3d.hpp libsrc/csg/manifold.hpp \
+  libsrc/csg/curve2d.hpp libsrc/csg/explicitcurve2d.hpp \
+  libsrc/csg/gencyl.hpp libsrc/csg/polyhedra.hpp libsrc/csg/extrusion.hpp \
+  libsrc/csg/revolution.hpp libsrc/csg/specpoin.hpp \
+  libsrc/csg/edgeflw.hpp libsrc/csg/meshsurf.hpp
+singularref.o: libsrc/csg/singularref.cpp libsrc/include/mystdlib.h \
+  libsrc/include/myadt.hpp libsrc/general/myadt.hpp \
+  libsrc/include/mydefs.hpp libsrc/general/ngexception.hpp \
+  libsrc/general/parthreads.hpp libsrc/general/moveablemem.hpp \
+  libsrc/general/dynamicmem.hpp libsrc/general/template.hpp \
+  libsrc/general/array.hpp libsrc/general/table.hpp \
+  libsrc/general/hashtabl.hpp libsrc/general/symbolta.hpp \
+  libsrc/general/bitarray.hpp libsrc/general/flags.hpp \
+  libsrc/general/spbita2d.hpp libsrc/general/seti.hpp \
+  libsrc/general/optmem.hpp libsrc/general/autoptr.hpp \
+  libsrc/general/sort.hpp libsrc/general/stack.hpp \
+  libsrc/general/mystring.hpp libsrc/include/linalg.hpp \
+  libsrc/linalg/linalg.hpp libsrc/linalg/vector.hpp \
+  libsrc/linalg/densemat.hpp libsrc/linalg/polynomial.hpp \
+  libsrc/include/csg.hpp libsrc/csg/csg.hpp libsrc/include/gprim.hpp \
+  libsrc/gprim/gprim.hpp libsrc/gprim/geomobjects.hpp \
+  libsrc/gprim/geomops.hpp libsrc/gprim/geomfuncs.hpp \
+  libsrc/gprim/geom2d.hpp libsrc/gprim/geom3d.hpp \
+  libsrc/gprim/geomtest3d.hpp libsrc/gprim/transform3d.hpp \
+  libsrc/gprim/adtree.hpp libsrc/include/meshing.hpp \
+  libsrc/meshing/meshing.hpp libsrc/include/opti.hpp libsrc/opti/opti.hpp \
+  libsrc/meshing/msghandler.hpp libsrc/meshing/meshtype.hpp \
+  libsrc/meshing/localh.hpp libsrc/meshing/meshclass.hpp \
+  libsrc/meshing/global.hpp libsrc/meshing/meshtool.hpp \
+  libsrc/meshing/ruler2.hpp libsrc/meshing/adfront2.hpp \
+  libsrc/meshing/meshing2.hpp libsrc/meshing/improve2.hpp \
+  libsrc/meshing/geomsearch.hpp libsrc/meshing/adfront3.hpp \
+  libsrc/meshing/ruler3.hpp libsrc/meshing/meshing3.hpp \
+  libsrc/meshing/improve3.hpp libsrc/meshing/findip.hpp \
+  libsrc/meshing/topology.hpp libsrc/meshing/curvedelems.hpp \
+  libsrc/meshing/bisect.hpp libsrc/meshing/clusters.hpp \
+  libsrc/meshing/meshfunc.hpp libsrc/meshing/hprefinement.hpp \
+  libsrc/meshing/boundarylayer.hpp libsrc/meshing/specials.hpp \
+  libsrc/csg/surface.hpp libsrc/csg/solid.hpp libsrc/csg/identify.hpp \
+  libsrc/csg/singularref.hpp libsrc/csg/csgeom.hpp \
+  libsrc/csg/triapprox.hpp libsrc/csg/algprim.hpp libsrc/csg/brick.hpp \
+  libsrc/csg/spline3d.hpp libsrc/csg/manifold.hpp libsrc/csg/curve2d.hpp \
+  libsrc/csg/explicitcurve2d.hpp libsrc/csg/gencyl.hpp \
+  libsrc/csg/polyhedra.hpp libsrc/csg/extrusion.hpp \
+  libsrc/csg/revolution.hpp libsrc/csg/specpoin.hpp \
+  libsrc/csg/edgeflw.hpp libsrc/csg/meshsurf.hpp
+edgeflw.o: libsrc/csg/edgeflw.cpp libsrc/include/mystdlib.h \
+  libsrc/include/meshing.hpp libsrc/meshing/meshing.hpp \
+  libsrc/include/myadt.hpp libsrc/general/myadt.hpp \
+  libsrc/include/mydefs.hpp libsrc/general/ngexception.hpp \
+  libsrc/general/parthreads.hpp libsrc/general/moveablemem.hpp \
+  libsrc/general/dynamicmem.hpp libsrc/general/template.hpp \
+  libsrc/general/array.hpp libsrc/general/table.hpp \
+  libsrc/general/hashtabl.hpp libsrc/general/symbolta.hpp \
+  libsrc/general/bitarray.hpp libsrc/general/flags.hpp \
+  libsrc/general/spbita2d.hpp libsrc/general/seti.hpp \
+  libsrc/general/optmem.hpp libsrc/general/autoptr.hpp \
+  libsrc/general/sort.hpp libsrc/general/stack.hpp \
+  libsrc/general/mystring.hpp libsrc/include/gprim.hpp \
+  libsrc/gprim/gprim.hpp libsrc/gprim/geomobjects.hpp \
+  libsrc/gprim/geomops.hpp libsrc/gprim/geomfuncs.hpp \
+  libsrc/gprim/geom2d.hpp libsrc/gprim/geom3d.hpp \
+  libsrc/gprim/geomtest3d.hpp libsrc/gprim/transform3d.hpp \
+  libsrc/gprim/adtree.hpp libsrc/include/linalg.hpp \
+  libsrc/linalg/linalg.hpp libsrc/linalg/vector.hpp \
+  libsrc/linalg/densemat.hpp libsrc/linalg/polynomial.hpp \
+  libsrc/include/opti.hpp libsrc/opti/opti.hpp \
+  libsrc/meshing/msghandler.hpp libsrc/meshing/meshtype.hpp \
+  libsrc/meshing/localh.hpp libsrc/meshing/meshclass.hpp \
+  libsrc/meshing/global.hpp libsrc/meshing/meshtool.hpp \
+  libsrc/meshing/ruler2.hpp libsrc/meshing/adfront2.hpp \
+  libsrc/meshing/meshing2.hpp libsrc/meshing/improve2.hpp \
+  libsrc/meshing/geomsearch.hpp libsrc/meshing/adfront3.hpp \
+  libsrc/meshing/ruler3.hpp libsrc/meshing/meshing3.hpp \
+  libsrc/meshing/improve3.hpp libsrc/meshing/findip.hpp \
+  libsrc/meshing/topology.hpp libsrc/meshing/curvedelems.hpp \
+  libsrc/meshing/bisect.hpp libsrc/meshing/clusters.hpp \
+  libsrc/meshing/meshfunc.hpp libsrc/meshing/hprefinement.hpp \
+  libsrc/meshing/boundarylayer.hpp libsrc/meshing/specials.hpp \
+  libsrc/include/csg.hpp libsrc/csg/csg.hpp libsrc/csg/surface.hpp \
+  libsrc/csg/solid.hpp libsrc/csg/identify.hpp libsrc/csg/singularref.hpp \
+  libsrc/csg/csgeom.hpp libsrc/csg/triapprox.hpp libsrc/csg/algprim.hpp \
+  libsrc/csg/brick.hpp libsrc/csg/spline3d.hpp libsrc/csg/manifold.hpp \
+  libsrc/csg/curve2d.hpp libsrc/csg/explicitcurve2d.hpp \
+  libsrc/csg/gencyl.hpp libsrc/csg/polyhedra.hpp libsrc/csg/extrusion.hpp \
+  libsrc/csg/revolution.hpp libsrc/csg/specpoin.hpp \
+  libsrc/csg/edgeflw.hpp libsrc/csg/meshsurf.hpp
+solid.o: libsrc/csg/solid.cpp libsrc/include/mystdlib.h \
+  libsrc/include/linalg.hpp libsrc/linalg/linalg.hpp \
+  libsrc/include/myadt.hpp libsrc/general/myadt.hpp \
+  libsrc/include/mydefs.hpp libsrc/general/ngexception.hpp \
+  libsrc/general/parthreads.hpp libsrc/general/moveablemem.hpp \
+  libsrc/general/dynamicmem.hpp libsrc/general/template.hpp \
+  libsrc/general/array.hpp libsrc/general/table.hpp \
+  libsrc/general/hashtabl.hpp libsrc/general/symbolta.hpp \
+  libsrc/general/bitarray.hpp libsrc/general/flags.hpp \
+  libsrc/general/spbita2d.hpp libsrc/general/seti.hpp \
+  libsrc/general/optmem.hpp libsrc/general/autoptr.hpp \
+  libsrc/general/sort.hpp libsrc/general/stack.hpp \
+  libsrc/general/mystring.hpp libsrc/linalg/vector.hpp \
+  libsrc/linalg/densemat.hpp libsrc/linalg/polynomial.hpp \
+  libsrc/include/csg.hpp libsrc/csg/csg.hpp libsrc/include/gprim.hpp \
+  libsrc/gprim/gprim.hpp libsrc/gprim/geomobjects.hpp \
+  libsrc/gprim/geomops.hpp libsrc/gprim/geomfuncs.hpp \
+  libsrc/gprim/geom2d.hpp libsrc/gprim/geom3d.hpp \
+  libsrc/gprim/geomtest3d.hpp libsrc/gprim/transform3d.hpp \
+  libsrc/gprim/adtree.hpp libsrc/include/meshing.hpp \
+  libsrc/meshing/meshing.hpp libsrc/include/opti.hpp libsrc/opti/opti.hpp \
+  libsrc/meshing/msghandler.hpp libsrc/meshing/meshtype.hpp \
+  libsrc/meshing/localh.hpp libsrc/meshing/meshclass.hpp \
+  libsrc/meshing/global.hpp libsrc/meshing/meshtool.hpp \
+  libsrc/meshing/ruler2.hpp libsrc/meshing/adfront2.hpp \
+  libsrc/meshing/meshing2.hpp libsrc/meshing/improve2.hpp \
+  libsrc/meshing/geomsearch.hpp libsrc/meshing/adfront3.hpp \
+  libsrc/meshing/ruler3.hpp libsrc/meshing/meshing3.hpp \
+  libsrc/meshing/improve3.hpp libsrc/meshing/findip.hpp \
+  libsrc/meshing/topology.hpp libsrc/meshing/curvedelems.hpp \
+  libsrc/meshing/bisect.hpp libsrc/meshing/clusters.hpp \
+  libsrc/meshing/meshfunc.hpp libsrc/meshing/hprefinement.hpp \
+  libsrc/meshing/boundarylayer.hpp libsrc/meshing/specials.hpp \
+  libsrc/csg/surface.hpp libsrc/csg/solid.hpp libsrc/csg/identify.hpp \
+  libsrc/csg/singularref.hpp libsrc/csg/csgeom.hpp \
+  libsrc/csg/triapprox.hpp libsrc/csg/algprim.hpp libsrc/csg/brick.hpp \
+  libsrc/csg/spline3d.hpp libsrc/csg/manifold.hpp libsrc/csg/curve2d.hpp \
+  libsrc/csg/explicitcurve2d.hpp libsrc/csg/gencyl.hpp \
+  libsrc/csg/polyhedra.hpp libsrc/csg/extrusion.hpp \
+  libsrc/csg/revolution.hpp libsrc/csg/specpoin.hpp \
+  libsrc/csg/edgeflw.hpp libsrc/csg/meshsurf.hpp
+explicitcurve2d.o: libsrc/csg/explicitcurve2d.cpp \
+  libsrc/include/mystdlib.h libsrc/include/csg.hpp libsrc/csg/csg.hpp \
+  libsrc/include/myadt.hpp libsrc/general/myadt.hpp \
+  libsrc/include/mydefs.hpp libsrc/general/ngexception.hpp \
+  libsrc/general/parthreads.hpp libsrc/general/moveablemem.hpp \
+  libsrc/general/dynamicmem.hpp libsrc/general/template.hpp \
+  libsrc/general/array.hpp libsrc/general/table.hpp \
+  libsrc/general/hashtabl.hpp libsrc/general/symbolta.hpp \
+  libsrc/general/bitarray.hpp libsrc/general/flags.hpp \
+  libsrc/general/spbita2d.hpp libsrc/general/seti.hpp \
+  libsrc/general/optmem.hpp libsrc/general/autoptr.hpp \
+  libsrc/general/sort.hpp libsrc/general/stack.hpp \
+  libsrc/general/mystring.hpp libsrc/include/gprim.hpp \
+  libsrc/gprim/gprim.hpp libsrc/gprim/geomobjects.hpp \
+  libsrc/gprim/geomops.hpp libsrc/gprim/geomfuncs.hpp \
+  libsrc/gprim/geom2d.hpp libsrc/gprim/geom3d.hpp \
+  libsrc/gprim/geomtest3d.hpp libsrc/gprim/transform3d.hpp \
+  libsrc/gprim/adtree.hpp libsrc/include/meshing.hpp \
+  libsrc/meshing/meshing.hpp libsrc/include/linalg.hpp \
+  libsrc/linalg/linalg.hpp libsrc/linalg/vector.hpp \
+  libsrc/linalg/densemat.hpp libsrc/linalg/polynomial.hpp \
+  libsrc/include/opti.hpp libsrc/opti/opti.hpp \
+  libsrc/meshing/msghandler.hpp libsrc/meshing/meshtype.hpp \
+  libsrc/meshing/localh.hpp libsrc/meshing/meshclass.hpp \
+  libsrc/meshing/global.hpp libsrc/meshing/meshtool.hpp \
+  libsrc/meshing/ruler2.hpp libsrc/meshing/adfront2.hpp \
+  libsrc/meshing/meshing2.hpp libsrc/meshing/improve2.hpp \
+  libsrc/meshing/geomsearch.hpp libsrc/meshing/adfront3.hpp \
+  libsrc/meshing/ruler3.hpp libsrc/meshing/meshing3.hpp \
+  libsrc/meshing/improve3.hpp libsrc/meshing/findip.hpp \
+  libsrc/meshing/topology.hpp libsrc/meshing/curvedelems.hpp \
+  libsrc/meshing/bisect.hpp libsrc/meshing/clusters.hpp \
+  libsrc/meshing/meshfunc.hpp libsrc/meshing/hprefinement.hpp \
+  libsrc/meshing/boundarylayer.hpp libsrc/meshing/specials.hpp \
+  libsrc/csg/surface.hpp libsrc/csg/solid.hpp libsrc/csg/identify.hpp \
+  libsrc/csg/singularref.hpp libsrc/csg/csgeom.hpp \
+  libsrc/csg/triapprox.hpp libsrc/csg/algprim.hpp libsrc/csg/brick.hpp \
+  libsrc/csg/spline3d.hpp libsrc/csg/manifold.hpp libsrc/csg/curve2d.hpp \
+  libsrc/csg/explicitcurve2d.hpp libsrc/csg/gencyl.hpp \
+  libsrc/csg/polyhedra.hpp libsrc/csg/extrusion.hpp \
+  libsrc/csg/revolution.hpp libsrc/csg/specpoin.hpp \
+  libsrc/csg/edgeflw.hpp libsrc/csg/meshsurf.hpp
+specpoin.o: libsrc/csg/specpoin.cpp libsrc/include/mystdlib.h \
+  libsrc/include/meshing.hpp libsrc/meshing/meshing.hpp \
+  libsrc/include/myadt.hpp libsrc/general/myadt.hpp \
+  libsrc/include/mydefs.hpp libsrc/general/ngexception.hpp \
+  libsrc/general/parthreads.hpp libsrc/general/moveablemem.hpp \
+  libsrc/general/dynamicmem.hpp libsrc/general/template.hpp \
+  libsrc/general/array.hpp libsrc/general/table.hpp \
+  libsrc/general/hashtabl.hpp libsrc/general/symbolta.hpp \
+  libsrc/general/bitarray.hpp libsrc/general/flags.hpp \
+  libsrc/general/spbita2d.hpp libsrc/general/seti.hpp \
+  libsrc/general/optmem.hpp libsrc/general/autoptr.hpp \
+  libsrc/general/sort.hpp libsrc/general/stack.hpp \
+  libsrc/general/mystring.hpp libsrc/include/gprim.hpp \
+  libsrc/gprim/gprim.hpp libsrc/gprim/geomobjects.hpp \
+  libsrc/gprim/geomops.hpp libsrc/gprim/geomfuncs.hpp \
+  libsrc/gprim/geom2d.hpp libsrc/gprim/geom3d.hpp \
+  libsrc/gprim/geomtest3d.hpp libsrc/gprim/transform3d.hpp \
+  libsrc/gprim/adtree.hpp libsrc/include/linalg.hpp \
+  libsrc/linalg/linalg.hpp libsrc/linalg/vector.hpp \
+  libsrc/linalg/densemat.hpp libsrc/linalg/polynomial.hpp \
+  libsrc/include/opti.hpp libsrc/opti/opti.hpp \
+  libsrc/meshing/msghandler.hpp libsrc/meshing/meshtype.hpp \
+  libsrc/meshing/localh.hpp libsrc/meshing/meshclass.hpp \
+  libsrc/meshing/global.hpp libsrc/meshing/meshtool.hpp \
+  libsrc/meshing/ruler2.hpp libsrc/meshing/adfront2.hpp \
+  libsrc/meshing/meshing2.hpp libsrc/meshing/improve2.hpp \
+  libsrc/meshing/geomsearch.hpp libsrc/meshing/adfront3.hpp \
+  libsrc/meshing/ruler3.hpp libsrc/meshing/meshing3.hpp \
+  libsrc/meshing/improve3.hpp libsrc/meshing/findip.hpp \
+  libsrc/meshing/topology.hpp libsrc/meshing/curvedelems.hpp \
+  libsrc/meshing/bisect.hpp libsrc/meshing/clusters.hpp \
+  libsrc/meshing/meshfunc.hpp libsrc/meshing/hprefinement.hpp \
+  libsrc/meshing/boundarylayer.hpp libsrc/meshing/specials.hpp \
+  libsrc/include/csg.hpp libsrc/csg/csg.hpp libsrc/csg/surface.hpp \
+  libsrc/csg/solid.hpp libsrc/csg/identify.hpp libsrc/csg/singularref.hpp \
+  libsrc/csg/csgeom.hpp libsrc/csg/triapprox.hpp libsrc/csg/algprim.hpp \
+  libsrc/csg/brick.hpp libsrc/csg/spline3d.hpp libsrc/csg/manifold.hpp \
+  libsrc/csg/curve2d.hpp libsrc/csg/explicitcurve2d.hpp \
+  libsrc/csg/gencyl.hpp libsrc/csg/polyhedra.hpp libsrc/csg/extrusion.hpp \
+  libsrc/csg/revolution.hpp libsrc/csg/specpoin.hpp \
+  libsrc/csg/edgeflw.hpp libsrc/csg/meshsurf.hpp
+gencyl.o: libsrc/csg/gencyl.cpp libsrc/include/linalg.hpp \
+  libsrc/linalg/linalg.hpp libsrc/include/myadt.hpp \
+  libsrc/general/myadt.hpp libsrc/include/mystdlib.h \
+  libsrc/include/mydefs.hpp libsrc/general/ngexception.hpp \
+  libsrc/general/parthreads.hpp libsrc/general/moveablemem.hpp \
+  libsrc/general/dynamicmem.hpp libsrc/general/template.hpp \
+  libsrc/general/array.hpp libsrc/general/table.hpp \
+  libsrc/general/hashtabl.hpp libsrc/general/symbolta.hpp \
+  libsrc/general/bitarray.hpp libsrc/general/flags.hpp \
+  libsrc/general/spbita2d.hpp libsrc/general/seti.hpp \
+  libsrc/general/optmem.hpp libsrc/general/autoptr.hpp \
+  libsrc/general/sort.hpp libsrc/general/stack.hpp \
+  libsrc/general/mystring.hpp libsrc/linalg/vector.hpp \
+  libsrc/linalg/densemat.hpp libsrc/linalg/polynomial.hpp \
+  libsrc/include/csg.hpp libsrc/csg/csg.hpp libsrc/include/gprim.hpp \
+  libsrc/gprim/gprim.hpp libsrc/gprim/geomobjects.hpp \
+  libsrc/gprim/geomops.hpp libsrc/gprim/geomfuncs.hpp \
+  libsrc/gprim/geom2d.hpp libsrc/gprim/geom3d.hpp \
+  libsrc/gprim/geomtest3d.hpp libsrc/gprim/transform3d.hpp \
+  libsrc/gprim/adtree.hpp libsrc/include/meshing.hpp \
+  libsrc/meshing/meshing.hpp libsrc/include/opti.hpp libsrc/opti/opti.hpp \
+  libsrc/meshing/msghandler.hpp libsrc/meshing/meshtype.hpp \
+  libsrc/meshing/localh.hpp libsrc/meshing/meshclass.hpp \
+  libsrc/meshing/global.hpp libsrc/meshing/meshtool.hpp \
+  libsrc/meshing/ruler2.hpp libsrc/meshing/adfront2.hpp \
+  libsrc/meshing/meshing2.hpp libsrc/meshing/improve2.hpp \
+  libsrc/meshing/geomsearch.hpp libsrc/meshing/adfront3.hpp \
+  libsrc/meshing/ruler3.hpp libsrc/meshing/meshing3.hpp \
+  libsrc/meshing/improve3.hpp libsrc/meshing/findip.hpp \
+  libsrc/meshing/topology.hpp libsrc/meshing/curvedelems.hpp \
+  libsrc/meshing/bisect.hpp libsrc/meshing/clusters.hpp \
+  libsrc/meshing/meshfunc.hpp libsrc/meshing/hprefinement.hpp \
+  libsrc/meshing/boundarylayer.hpp libsrc/meshing/specials.hpp \
+  libsrc/csg/surface.hpp libsrc/csg/solid.hpp libsrc/csg/identify.hpp \
+  libsrc/csg/singularref.hpp libsrc/csg/csgeom.hpp \
+  libsrc/csg/triapprox.hpp libsrc/csg/algprim.hpp libsrc/csg/brick.hpp \
+  libsrc/csg/spline3d.hpp libsrc/csg/manifold.hpp libsrc/csg/curve2d.hpp \
+  libsrc/csg/explicitcurve2d.hpp libsrc/csg/gencyl.hpp \
+  libsrc/csg/polyhedra.hpp libsrc/csg/extrusion.hpp \
+  libsrc/csg/revolution.hpp libsrc/csg/specpoin.hpp \
+  libsrc/csg/edgeflw.hpp libsrc/csg/meshsurf.hpp
+revolution.o: libsrc/csg/revolution.cpp libsrc/include/mystdlib.h \
+  libsrc/include/linalg.hpp libsrc/linalg/linalg.hpp \
+  libsrc/include/myadt.hpp libsrc/general/myadt.hpp \
+  libsrc/include/mydefs.hpp libsrc/general/ngexception.hpp \
+  libsrc/general/parthreads.hpp libsrc/general/moveablemem.hpp \
+  libsrc/general/dynamicmem.hpp libsrc/general/template.hpp \
+  libsrc/general/array.hpp libsrc/general/table.hpp \
+  libsrc/general/hashtabl.hpp libsrc/general/symbolta.hpp \
+  libsrc/general/bitarray.hpp libsrc/general/flags.hpp \
+  libsrc/general/spbita2d.hpp libsrc/general/seti.hpp \
+  libsrc/general/optmem.hpp libsrc/general/autoptr.hpp \
+  libsrc/general/sort.hpp libsrc/general/stack.hpp \
+  libsrc/general/mystring.hpp libsrc/linalg/vector.hpp \
+  libsrc/linalg/densemat.hpp libsrc/linalg/polynomial.hpp \
+  libsrc/include/csg.hpp libsrc/csg/csg.hpp libsrc/include/gprim.hpp \
+  libsrc/gprim/gprim.hpp libsrc/gprim/geomobjects.hpp \
+  libsrc/gprim/geomops.hpp libsrc/gprim/geomfuncs.hpp \
+  libsrc/gprim/geom2d.hpp libsrc/gprim/geom3d.hpp \
+  libsrc/gprim/geomtest3d.hpp libsrc/gprim/transform3d.hpp \
+  libsrc/gprim/adtree.hpp libsrc/include/meshing.hpp \
+  libsrc/meshing/meshing.hpp libsrc/include/opti.hpp libsrc/opti/opti.hpp \
+  libsrc/meshing/msghandler.hpp libsrc/meshing/meshtype.hpp \
+  libsrc/meshing/localh.hpp libsrc/meshing/meshclass.hpp \
+  libsrc/meshing/global.hpp libsrc/meshing/meshtool.hpp \
+  libsrc/meshing/ruler2.hpp libsrc/meshing/adfront2.hpp \
+  libsrc/meshing/meshing2.hpp libsrc/meshing/improve2.hpp \
+  libsrc/meshing/geomsearch.hpp libsrc/meshing/adfront3.hpp \
+  libsrc/meshing/ruler3.hpp libsrc/meshing/meshing3.hpp \
+  libsrc/meshing/improve3.hpp libsrc/meshing/findip.hpp \
+  libsrc/meshing/topology.hpp libsrc/meshing/curvedelems.hpp \
+  libsrc/meshing/bisect.hpp libsrc/meshing/clusters.hpp \
+  libsrc/meshing/meshfunc.hpp libsrc/meshing/hprefinement.hpp \
+  libsrc/meshing/boundarylayer.hpp libsrc/meshing/specials.hpp \
+  libsrc/csg/surface.hpp libsrc/csg/solid.hpp libsrc/csg/identify.hpp \
+  libsrc/csg/singularref.hpp libsrc/csg/csgeom.hpp \
+  libsrc/csg/triapprox.hpp libsrc/csg/algprim.hpp libsrc/csg/brick.hpp \
+  libsrc/csg/spline3d.hpp libsrc/csg/manifold.hpp libsrc/csg/curve2d.hpp \
+  libsrc/csg/explicitcurve2d.hpp libsrc/csg/gencyl.hpp \
+  libsrc/csg/polyhedra.hpp libsrc/csg/extrusion.hpp \
+  libsrc/csg/revolution.hpp libsrc/csg/specpoin.hpp \
+  libsrc/csg/edgeflw.hpp libsrc/csg/meshsurf.hpp
+genmesh.o: libsrc/csg/genmesh.cpp libsrc/include/mystdlib.h \
+  libsrc/include/myadt.hpp libsrc/general/myadt.hpp \
+  libsrc/include/mydefs.hpp libsrc/general/ngexception.hpp \
+  libsrc/general/parthreads.hpp libsrc/general/moveablemem.hpp \
+  libsrc/general/dynamicmem.hpp libsrc/general/template.hpp \
+  libsrc/general/array.hpp libsrc/general/table.hpp \
+  libsrc/general/hashtabl.hpp libsrc/general/symbolta.hpp \
+  libsrc/general/bitarray.hpp libsrc/general/flags.hpp \
+  libsrc/general/spbita2d.hpp libsrc/general/seti.hpp \
+  libsrc/general/optmem.hpp libsrc/general/autoptr.hpp \
+  libsrc/general/sort.hpp libsrc/general/stack.hpp \
+  libsrc/general/mystring.hpp libsrc/include/linalg.hpp \
+  libsrc/linalg/linalg.hpp libsrc/linalg/vector.hpp \
+  libsrc/linalg/densemat.hpp libsrc/linalg/polynomial.hpp \
+  libsrc/include/csg.hpp libsrc/csg/csg.hpp libsrc/include/gprim.hpp \
+  libsrc/gprim/gprim.hpp libsrc/gprim/geomobjects.hpp \
+  libsrc/gprim/geomops.hpp libsrc/gprim/geomfuncs.hpp \
+  libsrc/gprim/geom2d.hpp libsrc/gprim/geom3d.hpp \
+  libsrc/gprim/geomtest3d.hpp libsrc/gprim/transform3d.hpp \
+  libsrc/gprim/adtree.hpp libsrc/include/meshing.hpp \
+  libsrc/meshing/meshing.hpp libsrc/include/opti.hpp libsrc/opti/opti.hpp \
+  libsrc/meshing/msghandler.hpp libsrc/meshing/meshtype.hpp \
+  libsrc/meshing/localh.hpp libsrc/meshing/meshclass.hpp \
+  libsrc/meshing/global.hpp libsrc/meshing/meshtool.hpp \
+  libsrc/meshing/ruler2.hpp libsrc/meshing/adfront2.hpp \
+  libsrc/meshing/meshing2.hpp libsrc/meshing/improve2.hpp \
+  libsrc/meshing/geomsearch.hpp libsrc/meshing/adfront3.hpp \
+  libsrc/meshing/ruler3.hpp libsrc/meshing/meshing3.hpp \
+  libsrc/meshing/improve3.hpp libsrc/meshing/findip.hpp \
+  libsrc/meshing/topology.hpp libsrc/meshing/curvedelems.hpp \
+  libsrc/meshing/bisect.hpp libsrc/meshing/clusters.hpp \
+  libsrc/meshing/meshfunc.hpp libsrc/meshing/hprefinement.hpp \
+  libsrc/meshing/boundarylayer.hpp libsrc/meshing/specials.hpp \
+  libsrc/csg/surface.hpp libsrc/csg/solid.hpp libsrc/csg/identify.hpp \
+  libsrc/csg/singularref.hpp libsrc/csg/csgeom.hpp \
+  libsrc/csg/triapprox.hpp libsrc/csg/algprim.hpp libsrc/csg/brick.hpp \
+  libsrc/csg/spline3d.hpp libsrc/csg/manifold.hpp libsrc/csg/curve2d.hpp \
+  libsrc/csg/explicitcurve2d.hpp libsrc/csg/gencyl.hpp \
+  libsrc/csg/polyhedra.hpp libsrc/csg/extrusion.hpp \
+  libsrc/csg/revolution.hpp libsrc/csg/specpoin.hpp \
+  libsrc/csg/edgeflw.hpp libsrc/csg/meshsurf.hpp \
+  libsrc/include/stlgeom.hpp libsrc/stlgeom/stlgeom.hpp \
+  libsrc/stlgeom/stltopology.hpp libsrc/stlgeom/stltool.hpp \
+  libsrc/stlgeom/stlline.hpp libsrc/stlgeom/meshstlsurface.hpp
+spline3d.o: libsrc/csg/spline3d.cpp libsrc/include/mystdlib.h \
+  libsrc/include/myadt.hpp libsrc/general/myadt.hpp \
+  libsrc/include/mydefs.hpp libsrc/general/ngexception.hpp \
+  libsrc/general/parthreads.hpp libsrc/general/moveablemem.hpp \
+  libsrc/general/dynamicmem.hpp libsrc/general/template.hpp \
+  libsrc/general/array.hpp libsrc/general/table.hpp \
+  libsrc/general/hashtabl.hpp libsrc/general/symbolta.hpp \
+  libsrc/general/bitarray.hpp libsrc/general/flags.hpp \
+  libsrc/general/spbita2d.hpp libsrc/general/seti.hpp \
+  libsrc/general/optmem.hpp libsrc/general/autoptr.hpp \
+  libsrc/general/sort.hpp libsrc/general/stack.hpp \
+  libsrc/general/mystring.hpp libsrc/include/linalg.hpp \
+  libsrc/linalg/linalg.hpp libsrc/linalg/vector.hpp \
+  libsrc/linalg/densemat.hpp libsrc/linalg/polynomial.hpp \
+  libsrc/include/csg.hpp libsrc/csg/csg.hpp libsrc/include/gprim.hpp \
+  libsrc/gprim/gprim.hpp libsrc/gprim/geomobjects.hpp \
+  libsrc/gprim/geomops.hpp libsrc/gprim/geomfuncs.hpp \
+  libsrc/gprim/geom2d.hpp libsrc/gprim/geom3d.hpp \
+  libsrc/gprim/geomtest3d.hpp libsrc/gprim/transform3d.hpp \
+  libsrc/gprim/adtree.hpp libsrc/include/meshing.hpp \
+  libsrc/meshing/meshing.hpp libsrc/include/opti.hpp libsrc/opti/opti.hpp \
+  libsrc/meshing/msghandler.hpp libsrc/meshing/meshtype.hpp \
+  libsrc/meshing/localh.hpp libsrc/meshing/meshclass.hpp \
+  libsrc/meshing/global.hpp libsrc/meshing/meshtool.hpp \
+  libsrc/meshing/ruler2.hpp libsrc/meshing/adfront2.hpp \
+  libsrc/meshing/meshing2.hpp libsrc/meshing/improve2.hpp \
+  libsrc/meshing/geomsearch.hpp libsrc/meshing/adfront3.hpp \
+  libsrc/meshing/ruler3.hpp libsrc/meshing/meshing3.hpp \
+  libsrc/meshing/improve3.hpp libsrc/meshing/findip.hpp \
+  libsrc/meshing/topology.hpp libsrc/meshing/curvedelems.hpp \
+  libsrc/meshing/bisect.hpp libsrc/meshing/clusters.hpp \
+  libsrc/meshing/meshfunc.hpp libsrc/meshing/hprefinement.hpp \
+  libsrc/meshing/boundarylayer.hpp libsrc/meshing/specials.hpp \
+  libsrc/csg/surface.hpp libsrc/csg/solid.hpp libsrc/csg/identify.hpp \
+  libsrc/csg/singularref.hpp libsrc/csg/csgeom.hpp \
+  libsrc/csg/triapprox.hpp libsrc/csg/algprim.hpp libsrc/csg/brick.hpp \
+  libsrc/csg/spline3d.hpp libsrc/csg/manifold.hpp libsrc/csg/curve2d.hpp \
+  libsrc/csg/explicitcurve2d.hpp libsrc/csg/gencyl.hpp \
+  libsrc/csg/polyhedra.hpp libsrc/csg/extrusion.hpp \
+  libsrc/csg/revolution.hpp libsrc/csg/specpoin.hpp \
+  libsrc/csg/edgeflw.hpp libsrc/csg/meshsurf.hpp
+surface.o: libsrc/csg/surface.cpp libsrc/include/mystdlib.h \
+  libsrc/include/myadt.hpp libsrc/general/myadt.hpp \
+  libsrc/include/mydefs.hpp libsrc/general/ngexception.hpp \
+  libsrc/general/parthreads.hpp libsrc/general/moveablemem.hpp \
+  libsrc/general/dynamicmem.hpp libsrc/general/template.hpp \
+  libsrc/general/array.hpp libsrc/general/table.hpp \
+  libsrc/general/hashtabl.hpp libsrc/general/symbolta.hpp \
+  libsrc/general/bitarray.hpp libsrc/general/flags.hpp \
+  libsrc/general/spbita2d.hpp libsrc/general/seti.hpp \
+  libsrc/general/optmem.hpp libsrc/general/autoptr.hpp \
+  libsrc/general/sort.hpp libsrc/general/stack.hpp \
+  libsrc/general/mystring.hpp libsrc/include/csg.hpp libsrc/csg/csg.hpp \
+  libsrc/include/gprim.hpp libsrc/gprim/gprim.hpp \
+  libsrc/gprim/geomobjects.hpp libsrc/gprim/geomops.hpp \
+  libsrc/gprim/geomfuncs.hpp libsrc/gprim/geom2d.hpp \
+  libsrc/gprim/geom3d.hpp libsrc/gprim/geomtest3d.hpp \
+  libsrc/gprim/transform3d.hpp libsrc/gprim/adtree.hpp \
+  libsrc/include/meshing.hpp libsrc/meshing/meshing.hpp \
+  libsrc/include/linalg.hpp libsrc/linalg/linalg.hpp \
+  libsrc/linalg/vector.hpp libsrc/linalg/densemat.hpp \
+  libsrc/linalg/polynomial.hpp libsrc/include/opti.hpp \
+  libsrc/opti/opti.hpp libsrc/meshing/msghandler.hpp \
+  libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \
+  libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \
+  libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \
+  libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \
+  libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \
+  libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \
+  libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \
+  libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \
+  libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \
+  libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \
+  libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \
+  libsrc/meshing/specials.hpp libsrc/csg/surface.hpp libsrc/csg/solid.hpp \
+  libsrc/csg/identify.hpp libsrc/csg/singularref.hpp \
+  libsrc/csg/csgeom.hpp libsrc/csg/triapprox.hpp libsrc/csg/algprim.hpp \
+  libsrc/csg/brick.hpp libsrc/csg/spline3d.hpp libsrc/csg/manifold.hpp \
+  libsrc/csg/curve2d.hpp libsrc/csg/explicitcurve2d.hpp \
+  libsrc/csg/gencyl.hpp libsrc/csg/polyhedra.hpp libsrc/csg/extrusion.hpp \
+  libsrc/csg/revolution.hpp libsrc/csg/specpoin.hpp \
+  libsrc/csg/edgeflw.hpp libsrc/csg/meshsurf.hpp
+identify.o: libsrc/csg/identify.cpp libsrc/include/mystdlib.h \
+  libsrc/include/myadt.hpp libsrc/general/myadt.hpp \
+  libsrc/include/mydefs.hpp libsrc/general/ngexception.hpp \
+  libsrc/general/parthreads.hpp libsrc/general/moveablemem.hpp \
+  libsrc/general/dynamicmem.hpp libsrc/general/template.hpp \
+  libsrc/general/array.hpp libsrc/general/table.hpp \
+  libsrc/general/hashtabl.hpp libsrc/general/symbolta.hpp \
+  libsrc/general/bitarray.hpp libsrc/general/flags.hpp \
+  libsrc/general/spbita2d.hpp libsrc/general/seti.hpp \
+  libsrc/general/optmem.hpp libsrc/general/autoptr.hpp \
+  libsrc/general/sort.hpp libsrc/general/stack.hpp \
+  libsrc/general/mystring.hpp libsrc/include/linalg.hpp \
+  libsrc/linalg/linalg.hpp libsrc/linalg/vector.hpp \
+  libsrc/linalg/densemat.hpp libsrc/linalg/polynomial.hpp \
+  libsrc/include/csg.hpp libsrc/csg/csg.hpp libsrc/include/gprim.hpp \
+  libsrc/gprim/gprim.hpp libsrc/gprim/geomobjects.hpp \
+  libsrc/gprim/geomops.hpp libsrc/gprim/geomfuncs.hpp \
+  libsrc/gprim/geom2d.hpp libsrc/gprim/geom3d.hpp \
+  libsrc/gprim/geomtest3d.hpp libsrc/gprim/transform3d.hpp \
+  libsrc/gprim/adtree.hpp libsrc/include/meshing.hpp \
+  libsrc/meshing/meshing.hpp libsrc/include/opti.hpp libsrc/opti/opti.hpp \
+  libsrc/meshing/msghandler.hpp libsrc/meshing/meshtype.hpp \
+  libsrc/meshing/localh.hpp libsrc/meshing/meshclass.hpp \
+  libsrc/meshing/global.hpp libsrc/meshing/meshtool.hpp \
+  libsrc/meshing/ruler2.hpp libsrc/meshing/adfront2.hpp \
+  libsrc/meshing/meshing2.hpp libsrc/meshing/improve2.hpp \
+  libsrc/meshing/geomsearch.hpp libsrc/meshing/adfront3.hpp \
+  libsrc/meshing/ruler3.hpp libsrc/meshing/meshing3.hpp \
+  libsrc/meshing/improve3.hpp libsrc/meshing/findip.hpp \
+  libsrc/meshing/topology.hpp libsrc/meshing/curvedelems.hpp \
+  libsrc/meshing/bisect.hpp libsrc/meshing/clusters.hpp \
+  libsrc/meshing/meshfunc.hpp libsrc/meshing/hprefinement.hpp \
+  libsrc/meshing/boundarylayer.hpp libsrc/meshing/specials.hpp \
+  libsrc/csg/surface.hpp libsrc/csg/solid.hpp libsrc/csg/identify.hpp \
+  libsrc/csg/singularref.hpp libsrc/csg/csgeom.hpp \
+  libsrc/csg/triapprox.hpp libsrc/csg/algprim.hpp libsrc/csg/brick.hpp \
+  libsrc/csg/spline3d.hpp libsrc/csg/manifold.hpp libsrc/csg/curve2d.hpp \
+  libsrc/csg/explicitcurve2d.hpp libsrc/csg/gencyl.hpp \
+  libsrc/csg/polyhedra.hpp libsrc/csg/extrusion.hpp \
+  libsrc/csg/revolution.hpp libsrc/csg/specpoin.hpp \
+  libsrc/csg/edgeflw.hpp libsrc/csg/meshsurf.hpp
+triapprox.o: libsrc/csg/triapprox.cpp libsrc/include/mystdlib.h \
+  libsrc/include/myadt.hpp libsrc/general/myadt.hpp \
+  libsrc/include/mydefs.hpp libsrc/general/ngexception.hpp \
+  libsrc/general/parthreads.hpp libsrc/general/moveablemem.hpp \
+  libsrc/general/dynamicmem.hpp libsrc/general/template.hpp \
+  libsrc/general/array.hpp libsrc/general/table.hpp \
+  libsrc/general/hashtabl.hpp libsrc/general/symbolta.hpp \
+  libsrc/general/bitarray.hpp libsrc/general/flags.hpp \
+  libsrc/general/spbita2d.hpp libsrc/general/seti.hpp \
+  libsrc/general/optmem.hpp libsrc/general/autoptr.hpp \
+  libsrc/general/sort.hpp libsrc/general/stack.hpp \
+  libsrc/general/mystring.hpp libsrc/include/linalg.hpp \
+  libsrc/linalg/linalg.hpp libsrc/linalg/vector.hpp \
+  libsrc/linalg/densemat.hpp libsrc/linalg/polynomial.hpp \
+  libsrc/include/csg.hpp libsrc/csg/csg.hpp libsrc/include/gprim.hpp \
+  libsrc/gprim/gprim.hpp libsrc/gprim/geomobjects.hpp \
+  libsrc/gprim/geomops.hpp libsrc/gprim/geomfuncs.hpp \
+  libsrc/gprim/geom2d.hpp libsrc/gprim/geom3d.hpp \
+  libsrc/gprim/geomtest3d.hpp libsrc/gprim/transform3d.hpp \
+  libsrc/gprim/adtree.hpp libsrc/include/meshing.hpp \
+  libsrc/meshing/meshing.hpp libsrc/include/opti.hpp libsrc/opti/opti.hpp \
+  libsrc/meshing/msghandler.hpp libsrc/meshing/meshtype.hpp \
+  libsrc/meshing/localh.hpp libsrc/meshing/meshclass.hpp \
+  libsrc/meshing/global.hpp libsrc/meshing/meshtool.hpp \
+  libsrc/meshing/ruler2.hpp libsrc/meshing/adfront2.hpp \
+  libsrc/meshing/meshing2.hpp libsrc/meshing/improve2.hpp \
+  libsrc/meshing/geomsearch.hpp libsrc/meshing/adfront3.hpp \
+  libsrc/meshing/ruler3.hpp libsrc/meshing/meshing3.hpp \
+  libsrc/meshing/improve3.hpp libsrc/meshing/findip.hpp \
+  libsrc/meshing/topology.hpp libsrc/meshing/curvedelems.hpp \
+  libsrc/meshing/bisect.hpp libsrc/meshing/clusters.hpp \
+  libsrc/meshing/meshfunc.hpp libsrc/meshing/hprefinement.hpp \
+  libsrc/meshing/boundarylayer.hpp libsrc/meshing/specials.hpp \
+  libsrc/csg/surface.hpp libsrc/csg/solid.hpp libsrc/csg/identify.hpp \
+  libsrc/csg/singularref.hpp libsrc/csg/csgeom.hpp \
+  libsrc/csg/triapprox.hpp libsrc/csg/algprim.hpp libsrc/csg/brick.hpp \
+  libsrc/csg/spline3d.hpp libsrc/csg/manifold.hpp libsrc/csg/curve2d.hpp \
+  libsrc/csg/explicitcurve2d.hpp libsrc/csg/gencyl.hpp \
+  libsrc/csg/polyhedra.hpp libsrc/csg/extrusion.hpp \
+  libsrc/csg/revolution.hpp libsrc/csg/specpoin.hpp \
+  libsrc/csg/edgeflw.hpp libsrc/csg/meshsurf.hpp
+geom2dmesh.o: libsrc/geom2d/geom2dmesh.cpp libsrc/include/mystdlib.h \
+  libsrc/include/csg.hpp libsrc/csg/csg.hpp libsrc/include/myadt.hpp \
+  libsrc/general/myadt.hpp libsrc/include/mydefs.hpp \
+  libsrc/general/ngexception.hpp libsrc/general/parthreads.hpp \
+  libsrc/general/moveablemem.hpp libsrc/general/dynamicmem.hpp \
+  libsrc/general/template.hpp libsrc/general/array.hpp \
+  libsrc/general/table.hpp libsrc/general/hashtabl.hpp \
+  libsrc/general/symbolta.hpp libsrc/general/bitarray.hpp \
+  libsrc/general/flags.hpp libsrc/general/spbita2d.hpp \
+  libsrc/general/seti.hpp libsrc/general/optmem.hpp \
+  libsrc/general/autoptr.hpp libsrc/general/sort.hpp \
+  libsrc/general/stack.hpp libsrc/general/mystring.hpp \
+  libsrc/include/gprim.hpp libsrc/gprim/gprim.hpp \
+  libsrc/gprim/geomobjects.hpp libsrc/gprim/geomops.hpp \
+  libsrc/gprim/geomfuncs.hpp libsrc/gprim/geom2d.hpp \
+  libsrc/gprim/geom3d.hpp libsrc/gprim/geomtest3d.hpp \
+  libsrc/gprim/transform3d.hpp libsrc/gprim/adtree.hpp \
+  libsrc/include/meshing.hpp libsrc/meshing/meshing.hpp \
+  libsrc/include/linalg.hpp libsrc/linalg/linalg.hpp \
+  libsrc/linalg/vector.hpp libsrc/linalg/densemat.hpp \
+  libsrc/linalg/polynomial.hpp libsrc/include/opti.hpp \
+  libsrc/opti/opti.hpp libsrc/meshing/msghandler.hpp \
+  libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \
+  libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \
+  libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \
+  libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \
+  libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \
+  libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \
+  libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \
+  libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \
+  libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \
+  libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \
+  libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \
+  libsrc/meshing/specials.hpp libsrc/csg/surface.hpp libsrc/csg/solid.hpp \
+  libsrc/csg/identify.hpp libsrc/csg/singularref.hpp \
+  libsrc/csg/csgeom.hpp libsrc/csg/triapprox.hpp libsrc/csg/algprim.hpp \
+  libsrc/csg/brick.hpp libsrc/csg/spline3d.hpp libsrc/csg/manifold.hpp \
+  libsrc/csg/curve2d.hpp libsrc/csg/explicitcurve2d.hpp \
+  libsrc/csg/gencyl.hpp libsrc/csg/polyhedra.hpp libsrc/csg/extrusion.hpp \
+  libsrc/csg/revolution.hpp libsrc/csg/specpoin.hpp \
+  libsrc/csg/edgeflw.hpp libsrc/csg/meshsurf.hpp \
+  libsrc/include/geometry2d.hpp libsrc/geom2d/geometry2d.hpp \
+  libsrc/geom2d/spline2d.hpp libsrc/geom2d/splinegeometry2.hpp \
+  libsrc/geom2d/geom2dmesh.hpp
+spline2d.o: libsrc/geom2d/spline2d.cpp libsrc/include/mystdlib.h \
+  libsrc/include/csg.hpp libsrc/csg/csg.hpp libsrc/include/myadt.hpp \
+  libsrc/general/myadt.hpp libsrc/include/mydefs.hpp \
+  libsrc/general/ngexception.hpp libsrc/general/parthreads.hpp \
+  libsrc/general/moveablemem.hpp libsrc/general/dynamicmem.hpp \
+  libsrc/general/template.hpp libsrc/general/array.hpp \
+  libsrc/general/table.hpp libsrc/general/hashtabl.hpp \
+  libsrc/general/symbolta.hpp libsrc/general/bitarray.hpp \
+  libsrc/general/flags.hpp libsrc/general/spbita2d.hpp \
+  libsrc/general/seti.hpp libsrc/general/optmem.hpp \
+  libsrc/general/autoptr.hpp libsrc/general/sort.hpp \
+  libsrc/general/stack.hpp libsrc/general/mystring.hpp \
+  libsrc/include/gprim.hpp libsrc/gprim/gprim.hpp \
+  libsrc/gprim/geomobjects.hpp libsrc/gprim/geomops.hpp \
+  libsrc/gprim/geomfuncs.hpp libsrc/gprim/geom2d.hpp \
+  libsrc/gprim/geom3d.hpp libsrc/gprim/geomtest3d.hpp \
+  libsrc/gprim/transform3d.hpp libsrc/gprim/adtree.hpp \
+  libsrc/include/meshing.hpp libsrc/meshing/meshing.hpp \
+  libsrc/include/linalg.hpp libsrc/linalg/linalg.hpp \
+  libsrc/linalg/vector.hpp libsrc/linalg/densemat.hpp \
+  libsrc/linalg/polynomial.hpp libsrc/include/opti.hpp \
+  libsrc/opti/opti.hpp libsrc/meshing/msghandler.hpp \
+  libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \
+  libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \
+  libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \
+  libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \
+  libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \
+  libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \
+  libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \
+  libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \
+  libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \
+  libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \
+  libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \
+  libsrc/meshing/specials.hpp libsrc/csg/surface.hpp libsrc/csg/solid.hpp \
+  libsrc/csg/identify.hpp libsrc/csg/singularref.hpp \
+  libsrc/csg/csgeom.hpp libsrc/csg/triapprox.hpp libsrc/csg/algprim.hpp \
+  libsrc/csg/brick.hpp libsrc/csg/spline3d.hpp libsrc/csg/manifold.hpp \
+  libsrc/csg/curve2d.hpp libsrc/csg/explicitcurve2d.hpp \
+  libsrc/csg/gencyl.hpp libsrc/csg/polyhedra.hpp libsrc/csg/extrusion.hpp \
+  libsrc/csg/revolution.hpp libsrc/csg/specpoin.hpp \
+  libsrc/csg/edgeflw.hpp libsrc/csg/meshsurf.hpp \
+  libsrc/geom2d/spline2d.hpp
+splinegeometry2.o: libsrc/geom2d/splinegeometry2.cpp \
+  libsrc/include/mystdlib.h libsrc/include/csg.hpp libsrc/csg/csg.hpp \
+  libsrc/include/myadt.hpp libsrc/general/myadt.hpp \
+  libsrc/include/mydefs.hpp libsrc/general/ngexception.hpp \
+  libsrc/general/parthreads.hpp libsrc/general/moveablemem.hpp \
+  libsrc/general/dynamicmem.hpp libsrc/general/template.hpp \
+  libsrc/general/array.hpp libsrc/general/table.hpp \
+  libsrc/general/hashtabl.hpp libsrc/general/symbolta.hpp \
+  libsrc/general/bitarray.hpp libsrc/general/flags.hpp \
+  libsrc/general/spbita2d.hpp libsrc/general/seti.hpp \
+  libsrc/general/optmem.hpp libsrc/general/autoptr.hpp \
+  libsrc/general/sort.hpp libsrc/general/stack.hpp \
+  libsrc/general/mystring.hpp libsrc/include/gprim.hpp \
+  libsrc/gprim/gprim.hpp libsrc/gprim/geomobjects.hpp \
+  libsrc/gprim/geomops.hpp libsrc/gprim/geomfuncs.hpp \
+  libsrc/gprim/geom2d.hpp libsrc/gprim/geom3d.hpp \
+  libsrc/gprim/geomtest3d.hpp libsrc/gprim/transform3d.hpp \
+  libsrc/gprim/adtree.hpp libsrc/include/meshing.hpp \
+  libsrc/meshing/meshing.hpp libsrc/include/linalg.hpp \
+  libsrc/linalg/linalg.hpp libsrc/linalg/vector.hpp \
+  libsrc/linalg/densemat.hpp libsrc/linalg/polynomial.hpp \
+  libsrc/include/opti.hpp libsrc/opti/opti.hpp \
+  libsrc/meshing/msghandler.hpp libsrc/meshing/meshtype.hpp \
+  libsrc/meshing/localh.hpp libsrc/meshing/meshclass.hpp \
+  libsrc/meshing/global.hpp libsrc/meshing/meshtool.hpp \
+  libsrc/meshing/ruler2.hpp libsrc/meshing/adfront2.hpp \
+  libsrc/meshing/meshing2.hpp libsrc/meshing/improve2.hpp \
+  libsrc/meshing/geomsearch.hpp libsrc/meshing/adfront3.hpp \
+  libsrc/meshing/ruler3.hpp libsrc/meshing/meshing3.hpp \
+  libsrc/meshing/improve3.hpp libsrc/meshing/findip.hpp \
+  libsrc/meshing/topology.hpp libsrc/meshing/curvedelems.hpp \
+  libsrc/meshing/bisect.hpp libsrc/meshing/clusters.hpp \
+  libsrc/meshing/meshfunc.hpp libsrc/meshing/hprefinement.hpp \
+  libsrc/meshing/boundarylayer.hpp libsrc/meshing/specials.hpp \
+  libsrc/csg/surface.hpp libsrc/csg/solid.hpp libsrc/csg/identify.hpp \
+  libsrc/csg/singularref.hpp libsrc/csg/csgeom.hpp \
+  libsrc/csg/triapprox.hpp libsrc/csg/algprim.hpp libsrc/csg/brick.hpp \
+  libsrc/csg/spline3d.hpp libsrc/csg/manifold.hpp libsrc/csg/curve2d.hpp \
+  libsrc/csg/explicitcurve2d.hpp libsrc/csg/gencyl.hpp \
+  libsrc/csg/polyhedra.hpp libsrc/csg/extrusion.hpp \
+  libsrc/csg/revolution.hpp libsrc/csg/specpoin.hpp \
+  libsrc/csg/edgeflw.hpp libsrc/csg/meshsurf.hpp \
+  libsrc/geom2d/spline2d.hpp libsrc/geom2d/splinegeometry2.hpp
+genmesh2d.o: libsrc/geom2d/genmesh2d.cpp libsrc/include/mystdlib.h \
+  libsrc/include/csg.hpp libsrc/csg/csg.hpp libsrc/include/myadt.hpp \
+  libsrc/general/myadt.hpp libsrc/include/mydefs.hpp \
+  libsrc/general/ngexception.hpp libsrc/general/parthreads.hpp \
+  libsrc/general/moveablemem.hpp libsrc/general/dynamicmem.hpp \
+  libsrc/general/template.hpp libsrc/general/array.hpp \
+  libsrc/general/table.hpp libsrc/general/hashtabl.hpp \
+  libsrc/general/symbolta.hpp libsrc/general/bitarray.hpp \
+  libsrc/general/flags.hpp libsrc/general/spbita2d.hpp \
+  libsrc/general/seti.hpp libsrc/general/optmem.hpp \
+  libsrc/general/autoptr.hpp libsrc/general/sort.hpp \
+  libsrc/general/stack.hpp libsrc/general/mystring.hpp \
+  libsrc/include/gprim.hpp libsrc/gprim/gprim.hpp \
+  libsrc/gprim/geomobjects.hpp libsrc/gprim/geomops.hpp \
+  libsrc/gprim/geomfuncs.hpp libsrc/gprim/geom2d.hpp \
+  libsrc/gprim/geom3d.hpp libsrc/gprim/geomtest3d.hpp \
+  libsrc/gprim/transform3d.hpp libsrc/gprim/adtree.hpp \
+  libsrc/include/meshing.hpp libsrc/meshing/meshing.hpp \
+  libsrc/include/linalg.hpp libsrc/linalg/linalg.hpp \
+  libsrc/linalg/vector.hpp libsrc/linalg/densemat.hpp \
+  libsrc/linalg/polynomial.hpp libsrc/include/opti.hpp \
+  libsrc/opti/opti.hpp libsrc/meshing/msghandler.hpp \
+  libsrc/meshing/meshtype.hpp libsrc/meshing/localh.hpp \
+  libsrc/meshing/meshclass.hpp libsrc/meshing/global.hpp \
+  libsrc/meshing/meshtool.hpp libsrc/meshing/ruler2.hpp \
+  libsrc/meshing/adfront2.hpp libsrc/meshing/meshing2.hpp \
+  libsrc/meshing/improve2.hpp libsrc/meshing/geomsearch.hpp \
+  libsrc/meshing/adfront3.hpp libsrc/meshing/ruler3.hpp \
+  libsrc/meshing/meshing3.hpp libsrc/meshing/improve3.hpp \
+  libsrc/meshing/findip.hpp libsrc/meshing/topology.hpp \
+  libsrc/meshing/curvedelems.hpp libsrc/meshing/bisect.hpp \
+  libsrc/meshing/clusters.hpp libsrc/meshing/meshfunc.hpp \
+  libsrc/meshing/hprefinement.hpp libsrc/meshing/boundarylayer.hpp \
+  libsrc/meshing/specials.hpp libsrc/csg/surface.hpp libsrc/csg/solid.hpp \
+  libsrc/csg/identify.hpp libsrc/csg/singularref.hpp \
+  libsrc/csg/csgeom.hpp libsrc/csg/triapprox.hpp libsrc/csg/algprim.hpp \
+  libsrc/csg/brick.hpp libsrc/csg/spline3d.hpp libsrc/csg/manifold.hpp \
+  libsrc/csg/curve2d.hpp libsrc/csg/explicitcurve2d.hpp \
+  libsrc/csg/gencyl.hpp libsrc/csg/polyhedra.hpp libsrc/csg/extrusion.hpp \
+  libsrc/csg/revolution.hpp libsrc/csg/specpoin.hpp \
+  libsrc/csg/edgeflw.hpp libsrc/csg/meshsurf.hpp \
+  libsrc/include/geometry2d.hpp libsrc/geom2d/geometry2d.hpp \
+  libsrc/geom2d/spline2d.hpp libsrc/geom2d/splinegeometry2.hpp \
+  libsrc/geom2d/geom2dmesh.hpp
+meshstlsurface.o: libsrc/stlgeom/meshstlsurface.cpp \
+  libsrc/include/mystdlib.h libsrc/include/myadt.hpp \
+  libsrc/general/myadt.hpp libsrc/include/mydefs.hpp \
+  libsrc/general/ngexception.hpp libsrc/general/parthreads.hpp \
+  libsrc/general/moveablemem.hpp libsrc/general/dynamicmem.hpp \
+  libsrc/general/template.hpp libsrc/general/array.hpp \
+  libsrc/general/table.hpp libsrc/general/hashtabl.hpp \
+  libsrc/general/symbolta.hpp libsrc/general/bitarray.hpp \
+  libsrc/general/flags.hpp libsrc/general/spbita2d.hpp \
+  libsrc/general/seti.hpp libsrc/general/optmem.hpp \
+  libsrc/general/autoptr.hpp libsrc/general/sort.hpp \
+  libsrc/general/stack.hpp libsrc/general/mystring.hpp \
+  libsrc/include/linalg.hpp libsrc/linalg/linalg.hpp \
+  libsrc/linalg/vector.hpp libsrc/linalg/densemat.hpp \
+  libsrc/linalg/polynomial.hpp libsrc/include/gprim.hpp \
+  libsrc/gprim/gprim.hpp libsrc/gprim/geomobjects.hpp \
+  libsrc/gprim/geomops.hpp libsrc/gprim/geomfuncs.hpp \
+  libsrc/gprim/geom2d.hpp libsrc/gprim/geom3d.hpp \
+  libsrc/gprim/geomtest3d.hpp libsrc/gprim/transform3d.hpp \
+  libsrc/gprim/adtree.hpp libsrc/include/meshing.hpp \
+  libsrc/meshing/meshing.hpp libsrc/include/opti.hpp libsrc/opti/opti.hpp \
+  libsrc/meshing/msghandler.hpp libsrc/meshing/meshtype.hpp \
+  libsrc/meshing/localh.hpp libsrc/meshing/meshclass.hpp \
+  libsrc/meshing/global.hpp libsrc/meshing/meshtool.hpp \
+  libsrc/meshing/ruler2.hpp libsrc/meshing/adfront2.hpp \
+  libsrc/meshing/meshing2.hpp libsrc/meshing/improve2.hpp \
+  libsrc/meshing/geomsearch.hpp libsrc/meshing/adfront3.hpp \
+  libsrc/meshing/ruler3.hpp libsrc/meshing/meshing3.hpp \
+  libsrc/meshing/improve3.hpp libsrc/meshing/findip.hpp \
+  libsrc/meshing/topology.hpp libsrc/meshing/curvedelems.hpp \
+  libsrc/meshing/bisect.hpp libsrc/meshing/clusters.hpp \
+  libsrc/meshing/meshfunc.hpp libsrc/meshing/hprefinement.hpp \
+  libsrc/meshing/boundarylayer.hpp libsrc/meshing/specials.hpp \
+  libsrc/stlgeom/stlgeom.hpp libsrc/stlgeom/stltopology.hpp \
+  libsrc/stlgeom/stltool.hpp libsrc/stlgeom/stlline.hpp \
+  libsrc/stlgeom/meshstlsurface.hpp
+stlline.o: libsrc/stlgeom/stlline.cpp libsrc/include/mystdlib.h \
+  libsrc/include/myadt.hpp libsrc/general/myadt.hpp \
+  libsrc/include/mydefs.hpp libsrc/general/ngexception.hpp \
+  libsrc/general/parthreads.hpp libsrc/general/moveablemem.hpp \
+  libsrc/general/dynamicmem.hpp libsrc/general/template.hpp \
+  libsrc/general/array.hpp libsrc/general/table.hpp \
+  libsrc/general/hashtabl.hpp libsrc/general/symbolta.hpp \
+  libsrc/general/bitarray.hpp libsrc/general/flags.hpp \
+  libsrc/general/spbita2d.hpp libsrc/general/seti.hpp \
+  libsrc/general/optmem.hpp libsrc/general/autoptr.hpp \
+  libsrc/general/sort.hpp libsrc/general/stack.hpp \
+  libsrc/general/mystring.hpp libsrc/include/linalg.hpp \
+  libsrc/linalg/linalg.hpp libsrc/linalg/vector.hpp \
+  libsrc/linalg/densemat.hpp libsrc/linalg/polynomial.hpp \
+  libsrc/include/gprim.hpp libsrc/gprim/gprim.hpp \
+  libsrc/gprim/geomobjects.hpp libsrc/gprim/geomops.hpp \
+  libsrc/gprim/geomfuncs.hpp libsrc/gprim/geom2d.hpp \
+  libsrc/gprim/geom3d.hpp libsrc/gprim/geomtest3d.hpp \
+  libsrc/gprim/transform3d.hpp libsrc/gprim/adtree.hpp \
+  libsrc/include/meshing.hpp libsrc/meshing/meshing.hpp \
+  libsrc/include/opti.hpp libsrc/opti/opti.hpp \
+  libsrc/meshing/msghandler.hpp libsrc/meshing/meshtype.hpp \
+  libsrc/meshing/localh.hpp libsrc/meshing/meshclass.hpp \
+  libsrc/meshing/global.hpp libsrc/meshing/meshtool.hpp \
+  libsrc/meshing/ruler2.hpp libsrc/meshing/adfront2.hpp \
+  libsrc/meshing/meshing2.hpp libsrc/meshing/improve2.hpp \
+  libsrc/meshing/geomsearch.hpp libsrc/meshing/adfront3.hpp \
+  libsrc/meshing/ruler3.hpp libsrc/meshing/meshing3.hpp \
+  libsrc/meshing/improve3.hpp libsrc/meshing/findip.hpp \
+  libsrc/meshing/topology.hpp libsrc/meshing/curvedelems.hpp \
+  libsrc/meshing/bisect.hpp libsrc/meshing/clusters.hpp \
+  libsrc/meshing/meshfunc.hpp libsrc/meshing/hprefinement.hpp \
+  libsrc/meshing/boundarylayer.hpp libsrc/meshing/specials.hpp \
+  libsrc/stlgeom/stlgeom.hpp libsrc/stlgeom/stltopology.hpp \
+  libsrc/stlgeom/stltool.hpp libsrc/stlgeom/stlline.hpp \
+  libsrc/stlgeom/meshstlsurface.hpp
+stltopology.o: libsrc/stlgeom/stltopology.cpp libsrc/include/mystdlib.h \
+  libsrc/include/myadt.hpp libsrc/general/myadt.hpp \
+  libsrc/include/mydefs.hpp libsrc/general/ngexception.hpp \
+  libsrc/general/parthreads.hpp libsrc/general/moveablemem.hpp \
+  libsrc/general/dynamicmem.hpp libsrc/general/template.hpp \
+  libsrc/general/array.hpp libsrc/general/table.hpp \
+  libsrc/general/hashtabl.hpp libsrc/general/symbolta.hpp \
+  libsrc/general/bitarray.hpp libsrc/general/flags.hpp \
+  libsrc/general/spbita2d.hpp libsrc/general/seti.hpp \
+  libsrc/general/optmem.hpp libsrc/general/autoptr.hpp \
+  libsrc/general/sort.hpp libsrc/general/stack.hpp \
+  libsrc/general/mystring.hpp libsrc/include/linalg.hpp \
+  libsrc/linalg/linalg.hpp libsrc/linalg/vector.hpp \
+  libsrc/linalg/densemat.hpp libsrc/linalg/polynomial.hpp \
+  libsrc/include/gprim.hpp libsrc/gprim/gprim.hpp \
+  libsrc/gprim/geomobjects.hpp libsrc/gprim/geomops.hpp \
+  libsrc/gprim/geomfuncs.hpp libsrc/gprim/geom2d.hpp \
+  libsrc/gprim/geom3d.hpp libsrc/gprim/geomtest3d.hpp \
+  libsrc/gprim/transform3d.hpp libsrc/gprim/adtree.hpp \
+  libsrc/include/meshing.hpp libsrc/meshing/meshing.hpp \
+  libsrc/include/opti.hpp libsrc/opti/opti.hpp \
+  libsrc/meshing/msghandler.hpp libsrc/meshing/meshtype.hpp \
+  libsrc/meshing/localh.hpp libsrc/meshing/meshclass.hpp \
+  libsrc/meshing/global.hpp libsrc/meshing/meshtool.hpp \
+  libsrc/meshing/ruler2.hpp libsrc/meshing/adfront2.hpp \
+  libsrc/meshing/meshing2.hpp libsrc/meshing/improve2.hpp \
+  libsrc/meshing/geomsearch.hpp libsrc/meshing/adfront3.hpp \
+  libsrc/meshing/ruler3.hpp libsrc/meshing/meshing3.hpp \
+  libsrc/meshing/improve3.hpp libsrc/meshing/findip.hpp \
+  libsrc/meshing/topology.hpp libsrc/meshing/curvedelems.hpp \
+  libsrc/meshing/bisect.hpp libsrc/meshing/clusters.hpp \
+  libsrc/meshing/meshfunc.hpp libsrc/meshing/hprefinement.hpp \
+  libsrc/meshing/boundarylayer.hpp libsrc/meshing/specials.hpp \
+  libsrc/stlgeom/stlgeom.hpp libsrc/stlgeom/stltopology.hpp \
+  libsrc/stlgeom/stltool.hpp libsrc/stlgeom/stlline.hpp \
+  libsrc/stlgeom/meshstlsurface.hpp
+stltool.o: libsrc/stlgeom/stltool.cpp libsrc/include/mystdlib.h \
+  libsrc/include/myadt.hpp libsrc/general/myadt.hpp \
+  libsrc/include/mydefs.hpp libsrc/general/ngexception.hpp \
+  libsrc/general/parthreads.hpp libsrc/general/moveablemem.hpp \
+  libsrc/general/dynamicmem.hpp libsrc/general/template.hpp \
+  libsrc/general/array.hpp libsrc/general/table.hpp \
+  libsrc/general/hashtabl.hpp libsrc/general/symbolta.hpp \
+  libsrc/general/bitarray.hpp libsrc/general/flags.hpp \
+  libsrc/general/spbita2d.hpp libsrc/general/seti.hpp \
+  libsrc/general/optmem.hpp libsrc/general/autoptr.hpp \
+  libsrc/general/sort.hpp libsrc/general/stack.hpp \
+  libsrc/general/mystring.hpp libsrc/include/linalg.hpp \
+  libsrc/linalg/linalg.hpp libsrc/linalg/vector.hpp \
+  libsrc/linalg/densemat.hpp libsrc/linalg/polynomial.hpp \
+  libsrc/include/gprim.hpp libsrc/gprim/gprim.hpp \
+  libsrc/gprim/geomobjects.hpp libsrc/gprim/geomops.hpp \
+  libsrc/gprim/geomfuncs.hpp libsrc/gprim/geom2d.hpp \
+  libsrc/gprim/geom3d.hpp libsrc/gprim/geomtest3d.hpp \
+  libsrc/gprim/transform3d.hpp libsrc/gprim/adtree.hpp \
+  libsrc/include/meshing.hpp libsrc/meshing/meshing.hpp \
+  libsrc/include/opti.hpp libsrc/opti/opti.hpp \
+  libsrc/meshing/msghandler.hpp libsrc/meshing/meshtype.hpp \
+  libsrc/meshing/localh.hpp libsrc/meshing/meshclass.hpp \
+  libsrc/meshing/global.hpp libsrc/meshing/meshtool.hpp \
+  libsrc/meshing/ruler2.hpp libsrc/meshing/adfront2.hpp \
+  libsrc/meshing/meshing2.hpp libsrc/meshing/improve2.hpp \
+  libsrc/meshing/geomsearch.hpp libsrc/meshing/adfront3.hpp \
+  libsrc/meshing/ruler3.hpp libsrc/meshing/meshing3.hpp \
+  libsrc/meshing/improve3.hpp libsrc/meshing/findip.hpp \
+  libsrc/meshing/topology.hpp libsrc/meshing/curvedelems.hpp \
+  libsrc/meshing/bisect.hpp libsrc/meshing/clusters.hpp \
+  libsrc/meshing/meshfunc.hpp libsrc/meshing/hprefinement.hpp \
+  libsrc/meshing/boundarylayer.hpp libsrc/meshing/specials.hpp \
+  libsrc/stlgeom/stlgeom.hpp libsrc/stlgeom/stltopology.hpp \
+  libsrc/stlgeom/stltool.hpp libsrc/stlgeom/stlline.hpp \
+  libsrc/stlgeom/meshstlsurface.hpp
+stlgeom.o: libsrc/stlgeom/stlgeom.cpp libsrc/include/mystdlib.h \
+  libsrc/include/myadt.hpp libsrc/general/myadt.hpp \
+  libsrc/include/mydefs.hpp libsrc/general/ngexception.hpp \
+  libsrc/general/parthreads.hpp libsrc/general/moveablemem.hpp \
+  libsrc/general/dynamicmem.hpp libsrc/general/template.hpp \
+  libsrc/general/array.hpp libsrc/general/table.hpp \
+  libsrc/general/hashtabl.hpp libsrc/general/symbolta.hpp \
+  libsrc/general/bitarray.hpp libsrc/general/flags.hpp \
+  libsrc/general/spbita2d.hpp libsrc/general/seti.hpp \
+  libsrc/general/optmem.hpp libsrc/general/autoptr.hpp \
+  libsrc/general/sort.hpp libsrc/general/stack.hpp \
+  libsrc/general/mystring.hpp libsrc/include/linalg.hpp \
+  libsrc/linalg/linalg.hpp libsrc/linalg/vector.hpp \
+  libsrc/linalg/densemat.hpp libsrc/linalg/polynomial.hpp \
+  libsrc/include/gprim.hpp libsrc/gprim/gprim.hpp \
+  libsrc/gprim/geomobjects.hpp libsrc/gprim/geomops.hpp \
+  libsrc/gprim/geomfuncs.hpp libsrc/gprim/geom2d.hpp \
+  libsrc/gprim/geom3d.hpp libsrc/gprim/geomtest3d.hpp \
+  libsrc/gprim/transform3d.hpp libsrc/gprim/adtree.hpp \
+  libsrc/include/meshing.hpp libsrc/meshing/meshing.hpp \
+  libsrc/include/opti.hpp libsrc/opti/opti.hpp \
+  libsrc/meshing/msghandler.hpp libsrc/meshing/meshtype.hpp \
+  libsrc/meshing/localh.hpp libsrc/meshing/meshclass.hpp \
+  libsrc/meshing/global.hpp libsrc/meshing/meshtool.hpp \
+  libsrc/meshing/ruler2.hpp libsrc/meshing/adfront2.hpp \
+  libsrc/meshing/meshing2.hpp libsrc/meshing/improve2.hpp \
+  libsrc/meshing/geomsearch.hpp libsrc/meshing/adfront3.hpp \
+  libsrc/meshing/ruler3.hpp libsrc/meshing/meshing3.hpp \
+  libsrc/meshing/improve3.hpp libsrc/meshing/findip.hpp \
+  libsrc/meshing/topology.hpp libsrc/meshing/curvedelems.hpp \
+  libsrc/meshing/bisect.hpp libsrc/meshing/clusters.hpp \
+  libsrc/meshing/meshfunc.hpp libsrc/meshing/hprefinement.hpp \
+  libsrc/meshing/boundarylayer.hpp libsrc/meshing/specials.hpp \
+  libsrc/stlgeom/stlgeom.hpp libsrc/stlgeom/stltopology.hpp \
+  libsrc/stlgeom/stltool.hpp libsrc/stlgeom/stlline.hpp \
+  libsrc/stlgeom/meshstlsurface.hpp
+stlgeomchart.o: libsrc/stlgeom/stlgeomchart.cpp libsrc/include/mystdlib.h \
+  libsrc/include/myadt.hpp libsrc/general/myadt.hpp \
+  libsrc/include/mydefs.hpp libsrc/general/ngexception.hpp \
+  libsrc/general/parthreads.hpp libsrc/general/moveablemem.hpp \
+  libsrc/general/dynamicmem.hpp libsrc/general/template.hpp \
+  libsrc/general/array.hpp libsrc/general/table.hpp \
+  libsrc/general/hashtabl.hpp libsrc/general/symbolta.hpp \
+  libsrc/general/bitarray.hpp libsrc/general/flags.hpp \
+  libsrc/general/spbita2d.hpp libsrc/general/seti.hpp \
+  libsrc/general/optmem.hpp libsrc/general/autoptr.hpp \
+  libsrc/general/sort.hpp libsrc/general/stack.hpp \
+  libsrc/general/mystring.hpp libsrc/include/linalg.hpp \
+  libsrc/linalg/linalg.hpp libsrc/linalg/vector.hpp \
+  libsrc/linalg/densemat.hpp libsrc/linalg/polynomial.hpp \
+  libsrc/include/gprim.hpp libsrc/gprim/gprim.hpp \
+  libsrc/gprim/geomobjects.hpp libsrc/gprim/geomops.hpp \
+  libsrc/gprim/geomfuncs.hpp libsrc/gprim/geom2d.hpp \
+  libsrc/gprim/geom3d.hpp libsrc/gprim/geomtest3d.hpp \
+  libsrc/gprim/transform3d.hpp libsrc/gprim/adtree.hpp \
+  libsrc/include/meshing.hpp libsrc/meshing/meshing.hpp \
+  libsrc/include/opti.hpp libsrc/opti/opti.hpp \
+  libsrc/meshing/msghandler.hpp libsrc/meshing/meshtype.hpp \
+  libsrc/meshing/localh.hpp libsrc/meshing/meshclass.hpp \
+  libsrc/meshing/global.hpp libsrc/meshing/meshtool.hpp \
+  libsrc/meshing/ruler2.hpp libsrc/meshing/adfront2.hpp \
+  libsrc/meshing/meshing2.hpp libsrc/meshing/improve2.hpp \
+  libsrc/meshing/geomsearch.hpp libsrc/meshing/adfront3.hpp \
+  libsrc/meshing/ruler3.hpp libsrc/meshing/meshing3.hpp \
+  libsrc/meshing/improve3.hpp libsrc/meshing/findip.hpp \
+  libsrc/meshing/topology.hpp libsrc/meshing/curvedelems.hpp \
+  libsrc/meshing/bisect.hpp libsrc/meshing/clusters.hpp \
+  libsrc/meshing/meshfunc.hpp libsrc/meshing/hprefinement.hpp \
+  libsrc/meshing/boundarylayer.hpp libsrc/meshing/specials.hpp \
+  libsrc/stlgeom/stlgeom.hpp libsrc/stlgeom/stltopology.hpp \
+  libsrc/stlgeom/stltool.hpp libsrc/stlgeom/stlline.hpp \
+  libsrc/stlgeom/meshstlsurface.hpp
+stlgeommesh.o: libsrc/stlgeom/stlgeommesh.cpp libsrc/include/mystdlib.h \
+  libsrc/include/myadt.hpp libsrc/general/myadt.hpp \
+  libsrc/include/mydefs.hpp libsrc/general/ngexception.hpp \
+  libsrc/general/parthreads.hpp libsrc/general/moveablemem.hpp \
+  libsrc/general/dynamicmem.hpp libsrc/general/template.hpp \
+  libsrc/general/array.hpp libsrc/general/table.hpp \
+  libsrc/general/hashtabl.hpp libsrc/general/symbolta.hpp \
+  libsrc/general/bitarray.hpp libsrc/general/flags.hpp \
+  libsrc/general/spbita2d.hpp libsrc/general/seti.hpp \
+  libsrc/general/optmem.hpp libsrc/general/autoptr.hpp \
+  libsrc/general/sort.hpp libsrc/general/stack.hpp \
+  libsrc/general/mystring.hpp libsrc/include/linalg.hpp \
+  libsrc/linalg/linalg.hpp libsrc/linalg/vector.hpp \
+  libsrc/linalg/densemat.hpp libsrc/linalg/polynomial.hpp \
+  libsrc/include/gprim.hpp libsrc/gprim/gprim.hpp \
+  libsrc/gprim/geomobjects.hpp libsrc/gprim/geomops.hpp \
+  libsrc/gprim/geomfuncs.hpp libsrc/gprim/geom2d.hpp \
+  libsrc/gprim/geom3d.hpp libsrc/gprim/geomtest3d.hpp \
+  libsrc/gprim/transform3d.hpp libsrc/gprim/adtree.hpp \
+  libsrc/include/meshing.hpp libsrc/meshing/meshing.hpp \
+  libsrc/include/opti.hpp libsrc/opti/opti.hpp \
+  libsrc/meshing/msghandler.hpp libsrc/meshing/meshtype.hpp \
+  libsrc/meshing/localh.hpp libsrc/meshing/meshclass.hpp \
+  libsrc/meshing/global.hpp libsrc/meshing/meshtool.hpp \
+  libsrc/meshing/ruler2.hpp libsrc/meshing/adfront2.hpp \
+  libsrc/meshing/meshing2.hpp libsrc/meshing/improve2.hpp \
+  libsrc/meshing/geomsearch.hpp libsrc/meshing/adfront3.hpp \
+  libsrc/meshing/ruler3.hpp libsrc/meshing/meshing3.hpp \
+  libsrc/meshing/improve3.hpp libsrc/meshing/findip.hpp \
+  libsrc/meshing/topology.hpp libsrc/meshing/curvedelems.hpp \
+  libsrc/meshing/bisect.hpp libsrc/meshing/clusters.hpp \
+  libsrc/meshing/meshfunc.hpp libsrc/meshing/hprefinement.hpp \
+  libsrc/meshing/boundarylayer.hpp libsrc/meshing/specials.hpp \
+  libsrc/stlgeom/stlgeom.hpp libsrc/stlgeom/stltopology.hpp \
+  libsrc/stlgeom/stltool.hpp libsrc/stlgeom/stlline.hpp \
+  libsrc/stlgeom/meshstlsurface.hpp
+moveablemem.o: libsrc/general/moveablemem.cpp libsrc/include/myadt.hpp \
+  libsrc/general/myadt.hpp libsrc/include/mystdlib.h \
+  libsrc/include/mydefs.hpp libsrc/general/ngexception.hpp \
+  libsrc/general/parthreads.hpp libsrc/general/moveablemem.hpp \
+  libsrc/general/dynamicmem.hpp libsrc/general/template.hpp \
+  libsrc/general/array.hpp libsrc/general/table.hpp \
+  libsrc/general/hashtabl.hpp libsrc/general/symbolta.hpp \
+  libsrc/general/bitarray.hpp libsrc/general/flags.hpp \
+  libsrc/general/spbita2d.hpp libsrc/general/seti.hpp \
+  libsrc/general/optmem.hpp libsrc/general/autoptr.hpp \
+  libsrc/general/sort.hpp libsrc/general/stack.hpp \
+  libsrc/general/mystring.hpp
+ngexception.o: libsrc/general/ngexception.cpp libsrc/include/myadt.hpp \
+  libsrc/general/myadt.hpp libsrc/include/mystdlib.h \
+  libsrc/include/mydefs.hpp libsrc/general/ngexception.hpp \
+  libsrc/general/parthreads.hpp libsrc/general/moveablemem.hpp \
+  libsrc/general/dynamicmem.hpp libsrc/general/template.hpp \
+  libsrc/general/array.hpp libsrc/general/table.hpp \
+  libsrc/general/hashtabl.hpp libsrc/general/symbolta.hpp \
+  libsrc/general/bitarray.hpp libsrc/general/flags.hpp \
+  libsrc/general/spbita2d.hpp libsrc/general/seti.hpp \
+  libsrc/general/optmem.hpp libsrc/general/autoptr.hpp \
+  libsrc/general/sort.hpp libsrc/general/stack.hpp \
+  libsrc/general/mystring.hpp
+table.o: libsrc/general/table.cpp libsrc/include/mystdlib.h \
+  libsrc/include/myadt.hpp libsrc/general/myadt.hpp \
+  libsrc/include/mydefs.hpp libsrc/general/ngexception.hpp \
+  libsrc/general/parthreads.hpp libsrc/general/moveablemem.hpp \
+  libsrc/general/dynamicmem.hpp libsrc/general/template.hpp \
+  libsrc/general/array.hpp libsrc/general/table.hpp \
+  libsrc/general/hashtabl.hpp libsrc/general/symbolta.hpp \
+  libsrc/general/bitarray.hpp libsrc/general/flags.hpp \
+  libsrc/general/spbita2d.hpp libsrc/general/seti.hpp \
+  libsrc/general/optmem.hpp libsrc/general/autoptr.hpp \
+  libsrc/general/sort.hpp libsrc/general/stack.hpp \
+  libsrc/general/mystring.hpp
+optmem.o: libsrc/general/optmem.cpp libsrc/include/mystdlib.h \
+  libsrc/include/myadt.hpp libsrc/general/myadt.hpp \
+  libsrc/include/mydefs.hpp libsrc/general/ngexception.hpp \
+  libsrc/general/parthreads.hpp libsrc/general/moveablemem.hpp \
+  libsrc/general/dynamicmem.hpp libsrc/general/template.hpp \
+  libsrc/general/array.hpp libsrc/general/table.hpp \
+  libsrc/general/hashtabl.hpp libsrc/general/symbolta.hpp \
+  libsrc/general/bitarray.hpp libsrc/general/flags.hpp \
+  libsrc/general/spbita2d.hpp libsrc/general/seti.hpp \
+  libsrc/general/optmem.hpp libsrc/general/autoptr.hpp \
+  libsrc/general/sort.hpp libsrc/general/stack.hpp \
+  libsrc/general/mystring.hpp
+spbita2d.o: libsrc/general/spbita2d.cpp libsrc/include/mystdlib.h \
+  libsrc/include/myadt.hpp libsrc/general/myadt.hpp \
+  libsrc/include/mydefs.hpp libsrc/general/ngexception.hpp \
+  libsrc/general/parthreads.hpp libsrc/general/moveablemem.hpp \
+  libsrc/general/dynamicmem.hpp libsrc/general/template.hpp \
+  libsrc/general/array.hpp libsrc/general/table.hpp \
+  libsrc/general/hashtabl.hpp libsrc/general/symbolta.hpp \
+  libsrc/general/bitarray.hpp libsrc/general/flags.hpp \
+  libsrc/general/spbita2d.hpp libsrc/general/seti.hpp \
+  libsrc/general/optmem.hpp libsrc/general/autoptr.hpp \
+  libsrc/general/sort.hpp libsrc/general/stack.hpp \
+  libsrc/general/mystring.hpp
+hashtabl.o: libsrc/general/hashtabl.cpp libsrc/include/mystdlib.h \
+  libsrc/include/myadt.hpp libsrc/general/myadt.hpp \
+  libsrc/include/mydefs.hpp libsrc/general/ngexception.hpp \
+  libsrc/general/parthreads.hpp libsrc/general/moveablemem.hpp \
+  libsrc/general/dynamicmem.hpp libsrc/general/template.hpp \
+  libsrc/general/array.hpp libsrc/general/table.hpp \
+  libsrc/general/hashtabl.hpp libsrc/general/symbolta.hpp \
+  libsrc/general/bitarray.hpp libsrc/general/flags.hpp \
+  libsrc/general/spbita2d.hpp libsrc/general/seti.hpp \
+  libsrc/general/optmem.hpp libsrc/general/autoptr.hpp \
+  libsrc/general/sort.hpp libsrc/general/stack.hpp \
+  libsrc/general/mystring.hpp
+sort.o: libsrc/general/sort.cpp libsrc/include/mystdlib.h \
+  libsrc/include/myadt.hpp libsrc/general/myadt.hpp \
+  libsrc/include/mydefs.hpp libsrc/general/ngexception.hpp \
+  libsrc/general/parthreads.hpp libsrc/general/moveablemem.hpp \
+  libsrc/general/dynamicmem.hpp libsrc/general/template.hpp \
+  libsrc/general/array.hpp libsrc/general/table.hpp \
+  libsrc/general/hashtabl.hpp libsrc/general/symbolta.hpp \
+  libsrc/general/bitarray.hpp libsrc/general/flags.hpp \
+  libsrc/general/spbita2d.hpp libsrc/general/seti.hpp \
+  libsrc/general/optmem.hpp libsrc/general/autoptr.hpp \
+  libsrc/general/sort.hpp libsrc/general/stack.hpp \
+  libsrc/general/mystring.hpp
+flags.o: libsrc/general/flags.cpp libsrc/include/mystdlib.h \
+  libsrc/include/myadt.hpp libsrc/general/myadt.hpp \
+  libsrc/include/mydefs.hpp libsrc/general/ngexception.hpp \
+  libsrc/general/parthreads.hpp libsrc/general/moveablemem.hpp \
+  libsrc/general/dynamicmem.hpp libsrc/general/template.hpp \
+  libsrc/general/array.hpp libsrc/general/table.hpp \
+  libsrc/general/hashtabl.hpp libsrc/general/symbolta.hpp \
+  libsrc/general/bitarray.hpp libsrc/general/flags.hpp \
+  libsrc/general/spbita2d.hpp libsrc/general/seti.hpp \
+  libsrc/general/optmem.hpp libsrc/general/autoptr.hpp \
+  libsrc/general/sort.hpp libsrc/general/stack.hpp \
+  libsrc/general/mystring.hpp
+seti.o: libsrc/general/seti.cpp libsrc/include/mystdlib.h \
+  libsrc/include/myadt.hpp libsrc/general/myadt.hpp \
+  libsrc/include/mydefs.hpp libsrc/general/ngexception.hpp \
+  libsrc/general/parthreads.hpp libsrc/general/moveablemem.hpp \
+  libsrc/general/dynamicmem.hpp libsrc/general/template.hpp \
+  libsrc/general/array.hpp libsrc/general/table.hpp \
+  libsrc/general/hashtabl.hpp libsrc/general/symbolta.hpp \
+  libsrc/general/bitarray.hpp libsrc/general/flags.hpp \
+  libsrc/general/spbita2d.hpp libsrc/general/seti.hpp \
+  libsrc/general/optmem.hpp libsrc/general/autoptr.hpp \
+  libsrc/general/sort.hpp libsrc/general/stack.hpp \
+  libsrc/general/mystring.hpp
+bitarray.o: libsrc/general/bitarray.cpp libsrc/include/mystdlib.h \
+  libsrc/include/myadt.hpp libsrc/general/myadt.hpp \
+  libsrc/include/mydefs.hpp libsrc/general/ngexception.hpp \
+  libsrc/general/parthreads.hpp libsrc/general/moveablemem.hpp \
+  libsrc/general/dynamicmem.hpp libsrc/general/template.hpp \
+  libsrc/general/array.hpp libsrc/general/table.hpp \
+  libsrc/general/hashtabl.hpp libsrc/general/symbolta.hpp \
+  libsrc/general/bitarray.hpp libsrc/general/flags.hpp \
+  libsrc/general/spbita2d.hpp libsrc/general/seti.hpp \
+  libsrc/general/optmem.hpp libsrc/general/autoptr.hpp \
+  libsrc/general/sort.hpp libsrc/general/stack.hpp \
+  libsrc/general/mystring.hpp
+array.o: libsrc/general/array.cpp libsrc/include/mystdlib.h \
+  libsrc/include/myadt.hpp libsrc/general/myadt.hpp \
+  libsrc/include/mydefs.hpp libsrc/general/ngexception.hpp \
+  libsrc/general/parthreads.hpp libsrc/general/moveablemem.hpp \
+  libsrc/general/dynamicmem.hpp libsrc/general/template.hpp \
+  libsrc/general/array.hpp libsrc/general/table.hpp \
+  libsrc/general/hashtabl.hpp libsrc/general/symbolta.hpp \
+  libsrc/general/bitarray.hpp libsrc/general/flags.hpp \
+  libsrc/general/spbita2d.hpp libsrc/general/seti.hpp \
+  libsrc/general/optmem.hpp libsrc/general/autoptr.hpp \
+  libsrc/general/sort.hpp libsrc/general/stack.hpp \
+  libsrc/general/mystring.hpp
+symbolta.o: libsrc/general/symbolta.cpp libsrc/include/mystdlib.h \
+  libsrc/include/myadt.hpp libsrc/general/myadt.hpp \
+  libsrc/include/mydefs.hpp libsrc/general/ngexception.hpp \
+  libsrc/general/parthreads.hpp libsrc/general/moveablemem.hpp \
+  libsrc/general/dynamicmem.hpp libsrc/general/template.hpp \
+  libsrc/general/array.hpp libsrc/general/table.hpp \
+  libsrc/general/hashtabl.hpp libsrc/general/symbolta.hpp \
+  libsrc/general/bitarray.hpp libsrc/general/flags.hpp \
+  libsrc/general/spbita2d.hpp libsrc/general/seti.hpp \
+  libsrc/general/optmem.hpp libsrc/general/autoptr.hpp \
+  libsrc/general/sort.hpp libsrc/general/stack.hpp \
+  libsrc/general/mystring.hpp
+mystring.o: libsrc/general/mystring.cpp libsrc/include/mystdlib.h \
+  libsrc/include/myadt.hpp libsrc/general/myadt.hpp \
+  libsrc/include/mydefs.hpp libsrc/general/ngexception.hpp \
+  libsrc/general/parthreads.hpp libsrc/general/moveablemem.hpp \
+  libsrc/general/dynamicmem.hpp libsrc/general/template.hpp \
+  libsrc/general/array.hpp libsrc/general/table.hpp \
+  libsrc/general/hashtabl.hpp libsrc/general/symbolta.hpp \
+  libsrc/general/bitarray.hpp libsrc/general/flags.hpp \
+  libsrc/general/spbita2d.hpp libsrc/general/seti.hpp \
+  libsrc/general/optmem.hpp libsrc/general/autoptr.hpp \
+  libsrc/general/sort.hpp libsrc/general/stack.hpp \
+  libsrc/general/mystring.hpp libsrc/include/linalg.hpp \
+  libsrc/linalg/linalg.hpp libsrc/linalg/vector.hpp \
+  libsrc/linalg/densemat.hpp libsrc/linalg/polynomial.hpp \
+  libsrc/include/gprim.hpp libsrc/gprim/gprim.hpp \
+  libsrc/gprim/geomobjects.hpp libsrc/gprim/geomops.hpp \
+  libsrc/gprim/geomfuncs.hpp libsrc/gprim/geom2d.hpp \
+  libsrc/gprim/geom3d.hpp libsrc/gprim/geomtest3d.hpp \
+  libsrc/gprim/transform3d.hpp libsrc/gprim/adtree.hpp
diff --git a/Netgen/NEWS b/Netgen/NEWS
new file mode 100644
index 0000000000..76efa8384b
--- /dev/null
+++ b/Netgen/NEWS
@@ -0,0 +1,9 @@
+New features and improvements in NG4.3:
+
+- support for high order curved elements
+- new, hand written CSG parser
+- CSG primitives 'ellipticcylinder' and 'ellipsoid'
+- improvements for Delaunay meshing
+- improvements in surface optimization
+- mesh interface with full topology (element-face-edge-vertex)
+
diff --git a/Netgen/README.GMSH b/Netgen/README.GMSH
new file mode 100644
index 0000000000..bfc68ef9f0
--- /dev/null
+++ b/Netgen/README.GMSH
@@ -0,0 +1,69 @@
+
+This directory may contain a modified version of Joachim Schoberl's
+NETGEN mesh generator: 
+
+- only the libsrc directory was kept from the original distribution
+- the file meshing/improve2d.cpp was slightly modified
+
+**IMPORTANT NOTICE** 
+
+Netgen requires the boundary mesh to be oriented with exterior
+pointing normals. You HAVE TO define your geometry so that this
+criterion is fulfilled (i.e., correctly orient the geometry surfaces
+and the surface loops). Failing to do so will result in NETGEN to
+fail (and exit).
+
+**************************************************************
+
+From NETGEN's documentation:
+
+What is NETGEN
+==============
+
+NETGEN is an automatic mesh generation tool for two and three
+dimensions. Netgen is open source under the conditions of the LGPL.
+It comes as stand alone programme with graphical user
+interface, or as C++ library to be linked into an other application.
+Netgen is available for Unix/Linux and Windows 98/NT.  Netgen
+generates triangular or quadrilateral meshes in 2D, and tetrahedral
+meshes in 3D. The input for 2D is described by spline curves, and the
+input for 3D problems is either defined by constructive solid
+geometries (CSG), see Chapter \ref{chap_csg}, or by the standard STL
+file format.  NETGEN contains modules for mesh optimization and
+hierarchical mesh refinement. Curved elements are supported of arbitrary
+order.
+
+The history of NETGEN
+=====================
+
+The NETGEN project was started 1994 in the master's programme of
+Joachim Sch\"oberl, under supervision of Prof. Ulrich Langer, at the
+Department of Computational Mathematics and Optimization, University
+Linz, Austria.  Its further development was supported by the Austrian
+science Fund ``Fonds zur F\"orderung der wissenschaftlichen
+Forschung'' (http://www.fwf.ac.at) under projects P 10643-TEC and SFB
+1306.  The current home of Netgen is the Start project ``hp-FEM''
+(http://www.hpfem.jku.at) granted by the FWF.
+
+Special thanks go to
+- Robert Gaisbauer: High order curved elements
+- Hannes Gerstmayr: Meshing of STL geometry
+
+How to receive NETGEN
+=====================
+
+NETGEN is available from the WEB at http://www.hpfem.jku.at/netgen
+You find there source code releases for Linux/Unix/Windows, as well
+as compiled versions for Windows. You can use CVS access to receive
+the most up to date version.
+
+**************************************************************
+
+From NETGEN's README.install file:
+
+Latest information is available from:
+http://www.sfb013.uni-linz.ac.at/~joachim/netgen
+
+People might have asked similar questions on
+https://www.sfb013.uni-linz.ac.at/mailman/listinfo/netgen
+(please note the s in https)
diff --git a/Netgen/VERSION b/Netgen/VERSION
new file mode 100644
index 0000000000..74c0c9cbcc
--- /dev/null
+++ b/Netgen/VERSION
@@ -0,0 +1 @@
+NG Version 4.3.1
\ No newline at end of file
diff --git a/Netgen/libsrc/Makefile b/Netgen/libsrc/Makefile
new file mode 100644
index 0000000000..4bf820bc2a
--- /dev/null
+++ b/Netgen/libsrc/Makefile
@@ -0,0 +1,38 @@
+#
+#
+appl = NETGEN
+.default all:
+#
+#	
+all:
+	@ (cd linalg; $(MAKE) -f Makefile) 
+	@ (cd general; $(MAKE) -f Makefile)  
+	@ (cd gprim; $(MAKE) -f Makefile)
+	@ (cd csg; $(MAKE) -f Makefile)  
+	@ (cd geom2d; $(MAKE) -f Makefile)
+	@ (cd stlgeom; $(MAKE) -f Makefile)
+	@ (cd occ; $(MAKE) -f Makefile)
+	@ (cd meshing; $(MAKE) -f Makefile)
+	@ (cd opti; $(MAKE) -f Makefile)
+	@ (cd visualization; $(MAKE) -f Makefile)
+	@ (cd interface; $(MAKE) -f Makefile)
+#
+#	@ (cd step; $(MAKE) -f Makefile)
+#	@ (cd stepgeom; $(MAKE) -f Makefile)
+#	@ (cd graphics; $(MAKE) -f Makefile)
+
+tar:
+	tar cvf ../../libsrc.tar Makefile
+	tar rf ../../libsrc.tar linalg/Makefile linalg/*.hh linalg/*.cc
+	tar rf ../../libsrc.tar general/Makefile general/*.hh general/*.cc
+	tar rf ../../libsrc.tar gprim/Makefile gprim/*.hh gprim/*.cc
+	tar rf ../../libsrc.tar csg/Makefile csg/*.hh csg/*.cc
+	tar rf ../../libsrc.tar stlgeom/Makefile stlgeom/*.hh stlgeom/*.cc
+	tar rf ../../libsrc.tar occ/Makefile occ/*.h* occ/*.c*
+	tar rf ../../libsrc.tar meshing/Makefile meshing/*.hh meshing/*.cc meshing/*.h
+	tar rf ../../libsrc.tar opti/Makefile opti/*.hh opti/*.cc
+	tar rf ../../libsrc.tar step/Makefile step/*.h step/*.cc
+	tar rf ../../libsrc.tar stepgeom/Makefile stepgeom/*.hh stepgeom/*.cc
+	tar tf ../../libsrc.tar include/*.h include/*.hh
+	gzip -9 ../../libsrc.tar
+
diff --git a/Netgen/libsrc/csg/Makefile b/Netgen/libsrc/csg/Makefile
new file mode 100644
index 0000000000..e8c51dc218
--- /dev/null
+++ b/Netgen/libsrc/csg/Makefile
@@ -0,0 +1,26 @@
+#
+# Makefile for geometric library
+#
+src =  csgparser.cpp algprim.cpp curve2d.cpp brick.cpp  \
+	solid.cpp spline3d.cpp surface.cpp bspline2d.cpp \
+	explicitcurve2d.cpp gencyl.cpp csgeom.cpp polyhedra.cpp extrusion.cpp revolution.cpp  \
+	manifold.cpp curve2d.cpp triapprox.cpp identify.cpp \
+	singularref.cpp  \
+	edgeflw.cpp specpoin.cpp meshsurf.cpp genmesh.cpp 
+#
+#  lex.yy.cpp geometry.cpp
+# 
+lib = csg
+libpath = libsrc/csg
+#
+#
+include ../makefile.inc
+#
+# geometry.cpp : geometry.yy 
+#	bison -d -o geometry.c geometry.yy
+#	mv -f geometry.c geometry.cpp
+#
+# lex.yy.cpp : geometry.yy geometry.ll
+#	flex  -+ -d -I geometry.ll
+#	mv lex.yy.cc lex.yy.cpp
+
diff --git a/Netgen/libsrc/csg/algprim.cpp b/Netgen/libsrc/csg/algprim.cpp
new file mode 100644
index 0000000000..756e4bd1af
--- /dev/null
+++ b/Netgen/libsrc/csg/algprim.cpp
@@ -0,0 +1,1371 @@
+#include <mystdlib.h>
+
+
+#include <linalg.hpp>
+#include <csg.hpp>
+
+
+namespace netgen
+{
+
+double 
+QuadraticSurface :: CalcFunctionValue (const Point<3> & p) const
+{
+  return p(0) * (cxx * p(0) + cxy * p(1) + cxz * p(2) + cx) +
+    p(1) * (cyy * p(1) + cyz * p(2) + cy) +
+    p(2) * (czz * p(2) + cz) + c1;
+}
+
+void 
+QuadraticSurface :: CalcGradient (const Point<3> & p, Vec<3> & grad) const
+{
+  grad(0) = 2 * cxx * p(0) + cxy * p(1) + cxz * p(2) + cx;
+  grad(1) = 2 * cyy * p(1) + cxy * p(0) + cyz * p(2) + cy;
+  grad(2) = 2 * czz * p(2) + cxz * p(0) + cyz * p(1) + cz;
+}
+
+void 
+QuadraticSurface :: CalcHesse (const Point<3> & /* p */, Mat<3> & hesse) const
+{
+  hesse(0,0) = 2 * cxx;
+  hesse(1,1) = 2 * cyy;
+  hesse(2,2) = 2 * czz;
+  hesse(0,1) = hesse(1,0) = cxy;
+  hesse(0,2) = hesse(2,0) = cxz;
+  hesse(1,2) = hesse(2,1) = cyz;
+}
+
+
+void QuadraticSurface :: Read (istream & ist)
+{
+  ist >> cxx >> cyy >> czz >> cxy >> cxz >> cyz >> cx >> cy >> cz >> c1;
+}
+
+void QuadraticSurface :: Print (ostream & ost) const
+{
+  ost << cxx << "  " << cyy << "  " << czz << "  "
+      << cxy << "  " << cxz << "  " << cyz << "  "
+      << cx << "  " << cy << "  " << cz << "  "
+      << c1 << endl;
+}
+
+
+void QuadraticSurface :: PrintCoeff (ostream & ost) const
+{
+  ost << " cxx = " << cxx
+      << " cyy = " << cyy
+      << " czz = " << czz
+      << " cxy = " << cxy
+      << " cxz = " << cxz
+      << " cyz = " << cyz
+      << " cx = " << cx
+      << " cy = " << cy
+      << " cz = " << cz
+      << " c1 = " << c1 << endl;
+}
+
+
+Point<3> QuadraticSurface :: GetSurfacePoint () const
+{
+  MyError ("GetSurfacePoint called for QuadraticSurface");
+  return Point<3> (0, 0, 0);
+}
+
+
+Plane :: Plane (const Point<3> & ap, Vec<3> an)
+{
+  p = ap;
+  n = an;
+  n.Normalize();
+
+  cxx = cyy = czz = cxy = cxz = cyz = 0;
+  cx = n(0); cy = n(1); cz = n(2);
+  c1 = - (cx * p(0) + cy * p(1) + cz * p(2));
+}
+
+Primitive * Plane :: Copy () const
+{
+  return new Plane (p, n);
+}
+
+void Plane :: Transform (Transformation<3> & trans)
+{
+  Point<3> hp;
+  Vec<3> hn;
+  trans.Transform (p, hp);
+  trans.Transform (n, hn);
+  p = hp;
+  n = hn;
+
+  cxx = cyy = czz = cxy = cxz = cyz = 0;
+  cx = n(0); cy = n(1); cz = n(2);
+  c1 = - (cx * p(0) + cy * p(1) + cz * p(2));
+}
+
+
+
+void Plane :: GetPrimitiveData (char *& classname, 
+				ARRAY<double> & coeffs) const
+{
+  classname = "plane";
+  coeffs.SetSize (6);
+  coeffs.Elem(1) = p(0);
+  coeffs.Elem(2) = p(1);
+  coeffs.Elem(3) = p(2);
+  coeffs.Elem(4) = n(0);
+  coeffs.Elem(5) = n(1);
+  coeffs.Elem(6) = n(2);
+}
+
+void Plane :: SetPrimitiveData (ARRAY<double> & coeffs)
+{
+  p(0) = coeffs.Elem(1);
+  p(1) = coeffs.Elem(2);
+  p(2) = coeffs.Elem(3);
+  n(0) = coeffs.Elem(4);
+  n(1) = coeffs.Elem(5);
+  n(2) = coeffs.Elem(6);
+
+  n.Normalize();
+
+  cxx = cyy = czz = cxy = cxz = cyz = 0;
+  cx = n(0); cy = n(1); cz = n(2);
+  c1 = - (cx * p(0) + cy * p(1) + cz * p(2));
+}
+
+Primitive * Plane :: CreateDefault ()
+{
+  return new Plane (Point<3> (0,0,0), Vec<3> (0,0,1));
+}
+
+
+int Plane :: IsIdentic (const Surface & s2, int & inv, double eps) const
+{
+  if (fabs (s2.CalcFunctionValue(p)) > eps) return 0;
+  Vec<3> hv1, hv2;
+  hv1 = n.GetNormal ();
+  hv2 = Cross (n, hv1);
+
+  Point<3> hp = p + hv1;
+  if (fabs (s2.CalcFunctionValue(hp)) > eps) return 0;
+  hp = p + hv2;
+  if (fabs (s2.CalcFunctionValue(hp)) > eps) return 0;
+
+  Vec<3> n1, n2;
+  GetNormalVector (p, n1);
+  s2.GetNormalVector (p, n2);
+  inv = (n1 * n2 < 0);
+  return 1;
+}
+
+
+
+void Plane :: DefineTangentialPlane (const Point<3> & ap1, const Point<3> & ap2)
+{
+  Surface::DefineTangentialPlane (ap1, ap2);
+}
+
+
+void Plane :: ToPlane (const Point<3> & p3d, 
+		       Point<2> & pplane, 
+		       double h, int & zone) const
+{
+  Vec<3> p1p;
+
+  p1p = p3d - p1;
+  p1p /= h;
+  pplane(0) = p1p * ex;
+  pplane(1) = p1p * ey;
+  zone = 0;
+}
+
+void Plane :: FromPlane (const Point<2> & pplane, Point<3> & p3d, double h) const
+{
+  /*
+  Vec<3> p1p;
+  Point<2> pplane2 = pplane;
+  
+  pplane2 *= h;
+  p1p = pplane2(0) * ex + pplane2(1) * ey;
+  p3d = p1 + p1p;
+  */
+  p3d = p1 + (h * pplane(0)) * ex + (h * pplane(1)) * ey;
+}
+
+
+void Plane :: Project (Point<3> & p3d) const
+{
+  double val = CalcFunctionValue (p3d);
+  p3d -= val * n;
+}
+
+INSOLID_TYPE Plane :: BoxInSolid (const BoxSphere<3> & box) const
+{
+  int i;
+  double val;
+  Point<3> p;
+
+  val = CalcFunctionValue (box.Center());
+  if (val > box.Diam() / 2) return IS_OUTSIDE;
+  if (val < -box.Diam() / 2) return IS_INSIDE;
+
+  if (val > 0)
+    {
+      /*
+      double modify = 
+	((box.MaxX()-box.MinX()) * fabs (cx) + 
+	 (box.MaxY()-box.MinY()) * fabs (cy) + 
+	 (box.MaxZ()-box.MinZ()) * fabs (cz)) / 2;
+      */
+      Vec<3> vdiag = box.PMax() - box.PMin();
+      double modify = (vdiag(0) * fabs (cx) + 
+		       vdiag(1) * fabs (cy) + 
+		       vdiag(2) * fabs (cz) ) / 2;
+
+      if (val - modify < 0)
+	return DOES_INTERSECT;
+      return IS_OUTSIDE;
+
+      // only outside or intersect possible
+      for (i = 0; i < 8; i++)
+	{
+	  p = box.GetPointNr (i);
+	  val = CalcFunctionValue (p);
+	  if (val < 0) 
+	    return DOES_INTERSECT;
+	}
+      return IS_OUTSIDE;
+    }
+  else
+    {
+      /*
+	double modify = 
+	((box.MaxX()-box.MinX()) * fabs (cx) + 
+	(box.MaxY()-box.MinY()) * fabs (cy) + 
+	(box.MaxZ()-box.MinZ()) * fabs (cz)) / 2;
+      */
+      Vec<3> vdiag = box.PMax() - box.PMin();
+      double modify =  (vdiag(0) * fabs (cx) + 
+			vdiag(1) * fabs (cy) + 
+			vdiag(2) * fabs (cz) ) / 2;
+      if (val + modify > 0)
+	return DOES_INTERSECT;
+      return IS_INSIDE;
+
+
+      // only inside or intersect possible
+      for (i = 0; i < 8; i++)
+	{
+	  p = box.GetPointNr (i);
+	  val = CalcFunctionValue (p);
+	  if (val > 0) 
+	    return DOES_INTERSECT;
+	}
+      return IS_INSIDE;
+    }
+
+
+
+  /*
+  for (i = 1; i <= 8; i++)
+    {
+      box.GetPointNr (i, p);
+      val = CalcFunctionValue (p);
+      if (val > 0) inside = 0;
+      if (val < 0) outside = 0;
+    }
+
+  if (inside) return IS_INSIDE;
+  if (outside) return IS_OUTSIDE;
+  return DOES_INTERSECT;
+  */
+}
+
+
+
+double Plane :: CalcFunctionValue (const Point<3> & p3d) const
+{
+  return cx * p3d(0) + cy * p3d(1) + cz * p3d(2) + c1;
+}
+
+void Plane :: CalcGradient (const Point<3> & /* p */, Vec<3> & grad) const
+{
+  grad(0) = cx;
+  grad(1) = cy;
+  grad(2) = cz;
+}
+
+void Plane :: CalcHesse (const Point<3> & /* p */, Mat<3> & hesse) const
+{
+  hesse = 0;
+}
+
+double Plane :: HesseNorm () const
+{
+  return 0;
+}
+
+
+Point<3> Plane :: GetSurfacePoint () const
+{
+  return p;
+}
+
+
+void Plane :: GetTriangleApproximation 
+(TriangleApproximation & tas, 
+ const Box<3> & boundingbox, double facets) const
+{
+  // find triangle, such that
+  // boundingbox /cap plane is contained in it
+
+  Point<3> c = boundingbox.Center();
+  double r = boundingbox.Diam();
+
+  Project (c);
+  Vec<3> t1 = n.GetNormal();
+  Vec<3> t2 = Cross (n, t1);
+
+  t1.Normalize();
+  t2.Normalize();
+
+  tas.AddPoint (c + (-0.5 * r) * t2 + (sqrt(0.75) * r) * t1);
+  tas.AddPoint (c + (-0.5 * r) * t2 + (-sqrt(0.75) * r) * t1);
+  tas.AddPoint (c +  r * t2);
+
+  tas.AddTriangle (TATriangle (0, 0, 1, 2));
+}
+
+
+
+
+Sphere :: Sphere (const Point<3> & ac, double ar)
+{
+  c = ac;
+  r = ar;
+  
+  cxx = cyy = czz = 0.5 / r;
+  cxy = cxz = cyz = 0;
+  cx = - c(0) / r;
+  cy = - c(1) / r;
+  cz = - c(2) / r;
+  c1 = (c(0) * c(0) + c(1) * c(1) + c(2) * c(2)) / (2 * r) - r / 2;
+}
+
+void Sphere :: GetPrimitiveData (char *& classname, ARRAY<double> & coeffs) const
+{
+  classname = "sphere";
+  coeffs.SetSize (4);
+  coeffs.Elem(1) = c(0);
+  coeffs.Elem(2) = c(1);
+  coeffs.Elem(3) = c(2);
+  coeffs.Elem(4) = r;
+}
+
+void Sphere :: SetPrimitiveData (ARRAY<double> & coeffs)
+{
+  c(0) = coeffs.Elem(1);
+  c(1) = coeffs.Elem(2);
+  c(2) = coeffs.Elem(3);
+  r = coeffs.Elem(4);
+
+  cxx = cyy = czz = 0.5 / r;
+  cxy = cxz = cyz = 0;
+  cx = - c(0) / r;
+  cy = - c(1) / r;
+  cz = - c(2) / r;
+  c1 = (c(0) * c(0) + c(1) * c(1) + c(2) * c(2)) / (2 * r) - r / 2;
+}
+
+Primitive * Sphere :: CreateDefault ()
+{
+  return new Sphere (Point<3> (0,0,0), 1);
+}
+
+
+
+Primitive * Sphere :: Copy () const
+{
+  return new Sphere (c, r);
+}
+
+void Sphere :: Transform (Transformation<3> & trans)
+{
+  Point<3> hp;
+  trans.Transform (c, hp);
+  c = hp;
+
+  cxx = cyy = czz = 0.5 / r;
+  cxy = cxz = cyz = 0;
+  cx = - c(0) / r;
+  cy = - c(1) / r;
+  cz = - c(2) / r;
+  c1 = (c(0) * c(0) + c(1) * c(1) + c(2) * c(2)) / (2 * r) - r / 2;
+}
+
+
+
+
+int Sphere :: IsIdentic (const Surface & s2, int & inv, double eps) const
+{
+  const Sphere * sp2 = dynamic_cast<const Sphere*>  (&s2);
+
+  if (!sp2) return 0;
+
+  if (Dist (sp2->c, c) > eps) return 0;
+  if (fabs (sp2->r - r) > eps) return 0;
+
+  inv = 0;
+
+  return 1;
+}
+
+
+void Sphere :: DefineTangentialPlane (const Point<3> & ap1, const Point<3> & ap2)
+{
+  Surface::DefineTangentialPlane (ap1, ap2);
+
+  ez = p1 - c;
+  ez /= ez.Length();
+
+  ex = p2 - p1;
+  ex -= (ex * ez) * ez;
+  ex /= ex.Length();
+
+  ey = Cross (ez, ex);
+}
+
+
+void Sphere :: ToPlane (const Point<3> & p, Point<2> & pplane, double h, int & zone) const
+{
+  Vec<3> p1p;
+  
+  p1p = p - p1;
+  
+  /*
+  if (p1p * ez < -r)
+    {
+      zone = -1;
+      pplane = Point<2> (1E8, 1E8);
+    }
+  else
+    { 
+      zone = 0;
+      p1p /= h;
+      pplane(0) = p1p * ex;
+      pplane(1) = p1p * ey;
+    }
+  */
+
+  Point<3> p1top = c + (c - p1);
+
+  Vec<3> p1topp = p - p1top;
+  Vec<3> p1topp1 = p1 - p1top;
+  Vec<3> lam;
+  //  SolveLinearSystem (ex, ey, p1topp, p1topp1, lam);
+
+  Mat<3> m;
+  for (int i = 0; i < 3; i++)
+    {
+      m(i, 0) = ex(i);
+      m(i, 1) = ey(i);
+      m(i, 2) = p1topp(i);
+    }
+  m.Solve (p1topp1, lam);
+
+  pplane(0) = -lam(0) / h;
+  pplane(1) = -lam(1) / h;
+  
+  if (lam(2) > 2)
+    zone = -1;
+  else 
+    zone = 0;
+}
+
+void Sphere :: FromPlane (const Point<2> & pplane, Point<3> & p, double h) const
+{
+  /*
+    //  Vec<3> p1p;
+    double z;
+    Point<2> pplane2 (pplane);
+
+    pplane2(0) *= h;
+    pplane2(1) *= h;
+    z = -r + sqrt (sqr (r) - sqr (pplane2(0)) - sqr (pplane2(1)));
+    //  p = p1;
+    p(0) = p1(0) + pplane2(0) * ex(0) + pplane2(1) * ey(0) + z * ez(0);
+    p(1) = p1(1) + pplane2(0) * ex(1) + pplane2(1) * ey(1) + z * ez(1);
+    p(2) = p1(2) + pplane2(0) * ex(2) + pplane2(1) * ey(2) + z * ez(2);
+    */
+
+  Point<2> pplane2 (pplane);
+
+  pplane2(0) *= h;
+  pplane2(1) *= h;
+
+  p(0) = p1(0) + pplane2(0) * ex(0) + pplane2(1) * ey(0);
+  p(1) = p1(1) + pplane2(0) * ex(1) + pplane2(1) * ey(1);
+  p(2) = p1(2) + pplane2(0) * ex(2) + pplane2(1) * ey(2);
+  Project (p);
+}
+
+
+void Sphere :: Project (Point<3> & p) const
+{
+  Vec<3> v;
+  v = p - c;
+  v *= (r / v.Length());
+  p = c + v;
+}
+
+
+INSOLID_TYPE Sphere :: BoxInSolid (const BoxSphere<3> & box) const
+{
+  double dist;
+  dist = Dist (box.Center(), c);
+
+  if (dist - box.Diam()/2 > r) return IS_OUTSIDE;
+  if (dist + box.Diam()/2 < r) return IS_INSIDE;
+  return DOES_INTERSECT;
+}
+
+double Sphere :: HesseNorm () const
+{
+  return 2 / r;
+}
+
+
+Point<3> Sphere :: GetSurfacePoint () const
+{
+  return c + Vec<3> (r, 0, 0);
+}
+
+
+void Sphere :: GetTriangleApproximation 
+(TriangleApproximation & tas, 
+ const Box<3> & boundingbox, double facets) const
+{
+  int i, j;
+  double lg, bg;
+  int n = int(facets) + 1;  
+
+  for (j = 0; j <= n; j++)
+    for (i = 0; i <= n; i++)
+      {
+	lg = 2 * M_PI * double (i) / n;
+	bg = M_PI * (double(j) / n - 0.5);
+
+	Point<3> p(c(0) + r * cos(bg) * sin (lg),
+		  c(1) + r * cos(bg) * cos (lg),
+		  c(2) + r * sin(bg));
+	tas.AddPoint (p);
+      }
+
+  for (j = 0; j < n; j++)
+    for (i = 0; i < n; i++)
+      {
+	int pi = i + (n+1) * j;
+	tas.AddTriangle (TATriangle (0, pi, pi+1, pi+n+2));
+	tas.AddTriangle (TATriangle (0, pi, pi+n+2, pi+n+1));
+      }
+}
+
+
+
+
+
+Ellipsoid :: 
+Ellipsoid (const Point<3> & aa,
+	   const Vec<3> & av1, const Vec<3> & av2, const Vec<3> & av3)
+{
+  a = aa;
+  v1 = av1;
+  v2 = av2;
+  v3 = av3;
+
+  cout << "orhtogonal ? " << (v1*v2) << ", " << (v1*v3) << ", " << (v2*v3) << endl;
+  CalcData();
+}
+
+
+void Ellipsoid :: CalcData ()
+{
+  // f = (x-a, vl)^2 / |vl|^2 + (x-a, vs)^2 / |vs|^2 -1
+  // f = sum_{i=1}^3  (x-a,v_i)^2 / |vi|^4 - 1   =  sum (x-a,hv_i)^2
+  
+  Vec<3> hv1, hv2, hv3;
+  double lv1 = v1.Length2 ();
+  if (!lv1) lv1 = 1;
+  double lv2 = v2.Length2 ();
+  if (!lv2) lv2 = 1;
+  double lv3 = v3.Length2 ();
+  if (!lv3) lv3 = 1;
+
+  rmin = sqrt (min3 (lv1, lv2, lv3));
+
+  hv1 = (1.0 / lv1) * v1;
+  hv2 = (1.0 / lv2) * v2;
+  hv3 = (1.0 / lv3) * v3;
+
+  cxx = hv1(0) * hv1(0) + hv2(0) * hv2(0) + hv3(0) * hv3(0);
+  cyy = hv1(1) * hv1(1) + hv2(1) * hv2(1) + hv3(1) * hv3(1);
+  czz = hv1(2) * hv1(2) + hv2(2) * hv2(2) + hv3(2) * hv3(2);
+
+  cxy = 2 * (hv1(0) * hv1(1) + hv2(0) * hv2(1) + hv3(0) * hv3(1));
+  cxz = 2 * (hv1(0) * hv1(2) + hv2(0) * hv2(2) + hv3(0) * hv3(2));
+  cyz = 2 * (hv1(1) * hv1(2) + hv2(1) * hv2(2) + hv3(1) * hv3(2));
+
+  Vec<3> va (a);
+  c1 = sqr(va * hv1) + sqr(va * hv2) + sqr(va * hv3) - 1;
+  
+  Vec<3> v = -2 * (va * hv1) * hv1 - 2 * (va * hv2) * hv2  - 2 * (va * hv3) * hv3;
+  cx = v(0);
+  cy = v(1);
+  cz = v(2);
+}
+
+
+INSOLID_TYPE Ellipsoid :: BoxInSolid (const BoxSphere<3> & box) const
+{
+  // double grad = 2.0 / rmin;
+  // double grad = 3*(box.Center()-a).Length() / (rmin*rmin*rmin);
+
+  double ggrad = 1.0 / (rmin*rmin);
+  Vec<3> g;
+  double val = CalcFunctionValue (box.Center());
+  CalcGradient (box.Center(), g);
+  double grad = g.Length();
+
+  double r = box.Diam() / 2;
+  double maxval = grad * r + ggrad * r * r;
+
+  //  (*testout) << "box = " << box << ", val = " << val << ", maxval = " << maxval << endl;
+
+  if (val > maxval) return IS_OUTSIDE;
+  if (val < -maxval) return IS_INSIDE;
+  return DOES_INTERSECT;
+}
+
+
+double Ellipsoid :: HesseNorm () const
+{
+  return 1.0/ (rmin * rmin);
+}
+
+Point<3> Ellipsoid :: GetSurfacePoint () const
+{
+  return a + v1;
+}
+
+
+
+void Ellipsoid :: GetTriangleApproximation 
+(TriangleApproximation & tas, 
+ const Box<3> & boundingbox, double facets) const
+{
+  int i, j;
+  double lg, bg;
+  int n = int(facets) + 1;  
+
+  for (j = 0; j <= n; j++)
+    for (i = 0; i <= n; i++)
+      {
+	lg = 2 * M_PI * double (i) / n;
+	bg = M_PI * (double(j) / n - 0.5);
+
+
+	Point<3> p(a + 
+		   sin (bg) * v1 + 
+		   cos (bg) * sin (lg) * v2 +
+		   cos (bg) * cos (lg) * v3);
+
+	tas.AddPoint (p);
+      }
+
+  for (j = 0; j < n; j++)
+    for (i = 0; i < n; i++)
+      {
+	int pi = i + (n+1) * j;
+	tas.AddTriangle (TATriangle (0, pi, pi+1, pi+n+2));
+	tas.AddTriangle (TATriangle (0, pi, pi+n+2, pi+n+1));
+      }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Cylinder :: Cylinder (const Point<3> & aa, const Point<3> & ab, double ar)
+{
+  a = aa;
+  b = ab;
+  vab = (b - a);
+  vab /= vab.Length();
+  r = ar;
+
+  // ( <x,x> - 2 <x,a> + <a,a>
+  //   - <x,vab>^2 + 2 <x,vab> <a, vab> - <a, vab>^2
+  //   - r^2) / (2r) = 0
+
+  double hv;
+  cxx = cyy = czz = 0.5 / r;
+  cxy = cxz = cyz = 0;
+  cx = - a(0) / r;
+  cy = - a(1) / r;
+  cz = - a(2) / r;
+  c1 = (a(0) * a(0) + a(1) * a(1) + a(2) * a(2)) / (2 * r);
+  hv = a(0) * vab(0) + a(1) * vab(1) + a(2) * vab(2);
+  cxx -= vab(0) * vab(0) / (2 * r);
+  cyy -= vab(1) * vab(1) / (2 * r);
+  czz -= vab(2) * vab(2) / (2 * r);
+  cxy -= vab(0) * vab(1) / r;
+  cxz -= vab(0) * vab(2) / r;
+  cyz -= vab(1) * vab(2) / r;
+  cx += vab(0) * hv / r;
+  cy += vab(1) * hv / r;
+  cz += vab(2) * hv / r;
+  c1 -= hv * hv / (2 * r);
+  c1 -= r / 2;
+  //  PrintCoeff ();
+}
+
+
+
+void Cylinder :: GetPrimitiveData (char *& classname, ARRAY<double> & coeffs) const
+{
+  classname = "cylinder";
+  coeffs.SetSize (7);
+  coeffs.Elem(1) = a(0);
+  coeffs.Elem(2) = a(1);
+  coeffs.Elem(3) = a(2);
+  coeffs.Elem(4) = b(0);
+  coeffs.Elem(5) = b(1);
+  coeffs.Elem(6) = b(2);
+  coeffs.Elem(7) = r;
+}
+
+void Cylinder :: SetPrimitiveData (ARRAY<double> & coeffs)
+{
+  a(0) = coeffs.Elem(1);
+  a(1) = coeffs.Elem(2);
+  a(2) = coeffs.Elem(3);
+  b(0) = coeffs.Elem(4);
+  b(1) = coeffs.Elem(5);
+  b(2) = coeffs.Elem(6);
+  r = coeffs.Elem(7);
+
+
+  vab = (b - a);
+  vab /= vab.Length();
+
+
+  double hv;
+  cxx = cyy = czz = 0.5 / r;
+  cxy = cxz = cyz = 0;
+  cx = - a(0) / r;
+  cy = - a(1) / r;
+  cz = - a(2) / r;
+  c1 = (a(0) * a(0) + a(1) * a(1) + a(2) * a(2)) / (2 * r);
+  hv = a(0) * vab(0) + a(1) * vab(1) + a(2) * vab(2);
+  cxx -= vab(0) * vab(0) / (2 * r);
+  cyy -= vab(1) * vab(1) / (2 * r);
+  czz -= vab(2) * vab(2) / (2 * r);
+  cxy -= vab(0) * vab(1) / r;
+  cxz -= vab(0) * vab(2) / r;
+  cyz -= vab(1) * vab(2) / r;
+  cx += vab(0) * hv / r;
+  cy += vab(1) * hv / r;
+  cz += vab(2) * hv / r;
+  c1 -= hv * hv / (2 * r);
+  c1 -= r / 2;
+}
+
+Primitive * Cylinder :: CreateDefault ()
+{
+  return new Cylinder (Point<3> (0,0,0), Point<3> (1,0,0), 1);
+}
+
+
+
+
+Primitive * Cylinder :: Copy () const
+{
+  return new Cylinder (a, b, r);
+}
+
+
+int Cylinder :: IsIdentic (const Surface & s2, int & inv, double eps) const
+{
+  const Cylinder * cyl2 = dynamic_cast<const Cylinder*>  (&s2);
+
+  if (!cyl2) return 0;
+
+  if (fabs (cyl2->r - r) > eps) return 0;
+
+  Vec<3> v1 = b - a;
+  Vec<3> v2 = cyl2->a - a;
+
+  if ( fabs (v1 * v2) < (1-eps) * v1.Length() * v2.Length()) return 0;
+  v2 = cyl2->b - a;
+  if ( fabs (v1 * v2) < (1-eps) * v1.Length() * v2.Length()) return 0;
+
+  inv = 0;
+  return 1;
+}
+
+
+
+void Cylinder :: Transform (Transformation<3> & trans)
+{
+  Point<3> hp;
+  trans.Transform (a, hp);
+  a = hp;
+  trans.Transform (b, hp);
+  b = hp;
+
+  vab = (b - a);
+  vab /= vab.Length();
+
+  // ( <x,x> - 2 <x,a> + <a,a>
+  //   - <x,vab>^2 + 2 <x,vab> <a, vab> - <a, vab>^2
+  //   - r^2) / (2r) = 0
+
+  double hv;
+  cxx = cyy = czz = 0.5 / r;
+  cxy = cxz = cyz = 0;
+  cx = - a(0) / r;
+  cy = - a(1) / r;
+  cz = - a(2) / r;
+  c1 = (a(0) * a(0) + a(1) * a(1) + a(2) * a(2)) / (2 * r);
+  hv = a(0) * vab(0) + a(1) * vab(1) + a(2) * vab(2);
+  cxx -= vab(0) * vab(0) / (2 * r);
+  cyy -= vab(1) * vab(1) / (2 * r);
+  czz -= vab(2) * vab(2) / (2 * r);
+  cxy -= vab(0) * vab(1) / r;
+  cxz -= vab(0) * vab(2) / r;
+  cyz -= vab(1) * vab(2) / r;
+  cx += vab(0) * hv / r;
+  cy += vab(1) * hv / r;
+  cz += vab(2) * hv / r;
+  c1 -= hv * hv / (2 * r);
+  c1 -= r / 2;
+  //  PrintCoeff ();
+}
+
+
+
+
+
+
+
+
+
+void Cylinder :: DefineTangentialPlane (const Point<3> & ap1, const Point<3> & ap2)
+{
+  Surface::DefineTangentialPlane (ap1, ap2);
+
+  ez = Center (p1, p2) - a;
+  ez -= (ez * vab) * vab;
+  ez /= ez.Length();
+
+  ex = p2 - p1;
+  ex -= (ex * ez) * ez;
+  ex /= ex.Length();
+
+  ey = Cross (ez, ex);
+
+  /*
+    ez = p1 - a;
+    ez -= (ez * vab) * vap;
+    ez /= ez.Length();
+  
+    ezt = Cross (vab, ez);
+    */
+  
+}
+
+
+void Cylinder :: ToPlane (const Point<3> & p, 
+			  Point<2> & pplane, 
+			  double h, int & zone) const
+{
+  Point<3> cp1p2 = Center (p1, p2);
+  Project (cp1p2);
+  
+  Point<3> ccp1p2 = a + ( (cp1p2 - a) * vab ) * vab;
+
+  Vec<3> er = cp1p2 - ccp1p2;
+  er.Normalize();
+  Vec<3> ephi = Cross (vab, er);
+
+  double co, si;
+  Point<2> p1p, p2p, pp;
+
+  co = er * (p1 - ccp1p2);
+  si = ephi * (p1 - ccp1p2);
+  p1p(0) = r * atan2 (si, co);
+  p1p(1) = vab * (p1 - ccp1p2);
+
+  co = er * (p2 - ccp1p2);
+  si = ephi * (p2 - ccp1p2);
+  p2p(0) = r * atan2 (si, co);
+  p2p(1) = vab * (p2 - ccp1p2);
+  
+  co = er * (p - ccp1p2);
+  si = ephi * (p - ccp1p2);
+
+  double phi = atan2 (si, co);
+  pp(0) = r * phi;
+  pp(1) = vab * (p - ccp1p2);
+  
+  zone = 0;
+  if (phi > 1.57) zone = 1;
+  if (phi < -1.57) zone = 2;
+
+
+
+  Vec<2> e2x = p2p - p1p;
+  e2x /= e2x.Length();
+
+  Vec<2> e2y (-e2x(1), e2x(0));
+
+  Vec<2> p1pp = pp - p1p;
+
+
+  pplane(0) = (p1pp * e2x) / h;
+  pplane(1) = (p1pp * e2y) / h;
+
+  /*
+  (*testout) << "p1 = " << p1 << ",  p2 = " << p2 << endl;
+  (*testout) << "p = " << p << ",  pp = " << pp << ",  pplane = " << pplane << endl;
+  */
+
+  /*
+  Vec<3> p1p;
+
+  p1p = p - p1;
+
+  if (p1p * ez < -1 * r)
+    {
+      zone = -1;
+      pplane(0) = 1e8;
+      pplane(1) = 1e8;
+    }
+  else
+    {
+      zone = 0;
+      p1p /= h;
+      pplane(0) = p1p * ex;
+      pplane(1) = p1p * ey;
+    }
+    */
+}
+
+void Cylinder :: FromPlane (const Point<2> & pplane, Point<3> & p, double h) const
+{
+  Point<2> pplane2 (pplane);
+
+  pplane2(0) *= h;
+  pplane2(1) *= h;
+
+  p(0) = p1(0) + pplane2(0) * ex(0) + pplane2(1) * ey(0);
+  p(1) = p1(1) + pplane2(0) * ex(1) + pplane2(1) * ey(1);
+  p(2) = p1(2) + pplane2(0) * ex(2) + pplane2(1) * ey(2);
+  Project (p);
+}
+
+
+void Cylinder :: Project (Point<3> & p) const
+{
+  Vec<3> v;
+  Point<3> c;
+
+  c = a + ((p - a) * vab) * vab;
+  v = p - c;
+  v *= (r / v.Length());
+  p = c + v;
+}
+/*
+int Cylinder :: RootInBox (const BoxSphere<3> & box) const
+  {
+  double dist;
+  dist = sqrt (2 * CalcFunctionValue(box.Center()) * r + r * r);
+  if (fabs (dist - r) > box.Diam()/2) return 0;
+  return 2;
+  }
+*/
+
+INSOLID_TYPE Cylinder :: BoxInSolid (const BoxSphere<3> & box) const
+{
+  double dist;
+  //  dist = sqrt (2 * CalcFunctionValue(box.Center()) * r + r * r);
+
+  dist =  (2 * CalcFunctionValue(box.Center()) * r + r * r);
+  if (dist <= 0) dist = 0;
+  else dist = sqrt (dist + 1e-16);
+
+  if (dist - box.Diam()/2 > r) return IS_OUTSIDE;
+  if (dist + box.Diam()/2 < r) return IS_INSIDE;
+  return DOES_INTERSECT;
+}
+
+
+double Cylinder :: HesseNorm () const
+{
+  return 2 / r;
+}
+
+Point<3> Cylinder :: GetSurfacePoint () const
+{
+  Vec<3> vr;
+  if (fabs (vab(0)) > fabs(vab(2)))
+    vr = Vec<3> (vab(1), -vab(0), 0);
+  else
+    vr = Vec<3> (0, -vab(2), vab(1));
+    
+  vr *= (r / vr.Length());
+  return a + vr;
+}
+
+void Cylinder :: GetTriangleApproximation 
+(TriangleApproximation & tas, 
+ const Box<3> & boundingbox, double facets) const
+{
+  int i, j;
+  double lg, bg;
+  int n = int(facets) + 1;  
+
+  Vec<3> lvab = b - a;
+  Vec<3> n1 = lvab.GetNormal();
+  Vec<3> n2 = Cross (lvab, n1);
+  
+  n1.Normalize();
+  n2.Normalize();
+
+
+  for (j = 0; j <= n; j++)
+    for (i = 0; i <= n; i++)
+      {
+	lg = 2 * M_PI * double (i) / n;
+	bg = double(j) / n;
+
+	Point<3> p = a + (bg * lvab) 
+	  + ((r * cos(lg)) * n1) 
+	  + ((r * sin(lg)) * n2);
+
+	tas.AddPoint (p);
+      }
+
+  for (j = 0; j < n; j++)
+    for (i = 0; i < n; i++)
+      {
+	int pi = i + (n+1) * j;
+	tas.AddTriangle (TATriangle (0, pi, pi+1, pi+n+2));
+	tas.AddTriangle (TATriangle (0, pi, pi+n+2, pi+n+1));
+      }
+}
+
+
+
+
+
+
+
+
+
+EllipticCylinder :: 
+EllipticCylinder (const Point<3> & aa,
+		  const Vec<3> & avl, const Vec<3> & avs)
+{
+  a = aa;
+  vl = avl;
+  vs = avs;
+
+  CalcData();
+  Print (cout);
+}
+
+
+void EllipticCylinder :: CalcData ()
+{
+  // f = (x-a, vl)^2 / |vl|^2 + (x-a, vs)^2 / |vs|^2 -1
+
+  Vec<3> hvl, hvs;
+  double lvl = vl.Length2 ();
+  if (!lvl) lvl = 1;
+  double lvs = vs.Length2 ();
+  if (!lvs) lvs = 1;
+
+  hvl = (1.0 / lvl) * vl;
+  hvs = (1.0 / lvs) * vs;
+
+  cxx = hvl(0) * hvl(0) + hvs(0) * hvs(0);
+  cyy = hvl(1) * hvl(1) + hvs(1) * hvs(1);
+  czz = hvl(2) * hvl(2) + hvs(2) * hvs(2);
+
+  cxy = 2 * (hvl(0) * hvl(1) + hvs(0) * hvs(1));
+  cxz = 2 * (hvl(0) * hvl(2) + hvs(0) * hvs(2));
+  cyz = 2 * (hvl(1) * hvl(2) + hvs(1) * hvs(2));
+
+  Vec<3> va (a);
+  c1 = va * hvl + va * hvs - 1;
+  
+  Vec<3> v = -2 * (va * hvl) * hvl - 2 * (va * hvs) * hvs;
+  cx = v(0);
+  cy = v(1);
+  cz = v(2);
+}
+
+
+INSOLID_TYPE EllipticCylinder :: BoxInSolid (const BoxSphere<3> & box) const
+{
+  double grad = 2.0 / vs.Length ();
+  double ggrad = 1.0 / vs.Length2 ();
+
+  double val = CalcFunctionValue (box.Center());
+  double r = box.Diam() / 2;
+  double maxval = grad * r + ggrad * r * r;
+
+  // (*testout) << "box = " << box << ", val = " << val << ", maxval = " << maxval << endl;
+
+  if (val > maxval) return IS_OUTSIDE;
+  if (val < -maxval) return IS_INSIDE;
+  return DOES_INTERSECT;
+}
+
+
+double EllipticCylinder :: HesseNorm () const
+{
+  return 1.0/vs.Length2 ();
+}
+
+Point<3> EllipticCylinder :: GetSurfacePoint () const
+{
+  return a + vl;
+}
+
+
+
+void EllipticCylinder :: GetTriangleApproximation 
+(TriangleApproximation & tas, 
+ const Box<3> & boundingbox, double facets) const
+{
+  int i, j;
+  double lg, bg;
+  int n = int(facets) + 1;  
+
+  Vec<3> axis = Cross (vl, vs);
+
+  for (j = 0; j <= n; j++)
+    for (i = 0; i <= n; i++)
+      {
+	lg = 2 * M_PI * double (i) / n;
+	bg = double(j) / n;
+
+	Point<3> p = a + (bg * axis)
+	  + cos(lg) * vl + sin(lg) * vs;
+
+	tas.AddPoint (p);
+      }
+
+  for (j = 0; j < n; j++)
+    for (i = 0; i < n; i++)
+      {
+	int pi = i + (n+1) * j;
+	tas.AddTriangle (TATriangle (0, pi, pi+1, pi+n+2));
+	tas.AddTriangle (TATriangle (0, pi, pi+n+2, pi+n+1));
+      }
+}
+
+
+
+
+
+
+
+
+
+
+Cone :: Cone (const Point<3> & aa, const Point<3> & ab, 
+	      double ara, double arb)
+{
+  a = aa;
+  b = ab;
+  ra = ara;
+  rb = arb;
+
+  CalcData();
+  Print (cout);
+}
+
+
+Primitive * Cone :: CreateDefault ()
+{
+  return new Cone (Point<3> (0,0,0), Point<3> (1,0,0), 0.5, 0.2);
+}
+
+
+
+
+void Cone :: GetPrimitiveData (char *& classname, ARRAY<double> & coeffs) const
+{
+  classname = "cone";
+  coeffs.SetSize (8);
+  coeffs.Elem(1) = a(0);
+  coeffs.Elem(2) = a(1);
+  coeffs.Elem(3) = a(2);
+  coeffs.Elem(4) = b(0);
+  coeffs.Elem(5) = b(1);
+  coeffs.Elem(6) = b(2);
+  coeffs.Elem(7) = ra;
+  coeffs.Elem(8) = rb;
+}
+
+void Cone :: SetPrimitiveData (ARRAY<double> & coeffs)
+{
+  a(0) = coeffs.Elem(1);
+  a(1) = coeffs.Elem(2);
+  a(2) = coeffs.Elem(3);
+  b(0) = coeffs.Elem(4);
+  b(1) = coeffs.Elem(5);
+  b(2) = coeffs.Elem(6);
+  ra = coeffs.Elem(7);
+  rb = coeffs.Elem(8);
+
+  CalcData();
+}
+
+void Cone :: CalcData ()
+{
+
+  minr = (ra < rb) ? ra : rb;
+
+  vab = (b - a);
+  vabl = vab.Length();
+
+  Vec<3> va (a);
+
+  //
+  //   f = r(P)^2 - R(z(P))^2
+  //
+  //   z(P) = t0vec * P + t0 = (P-a, b-a)/(b-a,b-a)
+  //   R(z(P)) = t1vec * P + t1 = rb * z + ra * (1-z)
+  //   r(P)^2 =||P-a||^2 - ||a-b||^2 z^2
+
+
+  t0vec = vab;
+  t0vec /= (vabl * vabl);
+  t0 = -(va * vab) / (vabl * vabl);
+
+  t1vec = t0vec;
+  t1vec *= (rb - ra);
+  t1 = ra + (rb - ra) * t0; 
+
+  cxx = cyy = czz = 1;
+  cxy = cxz = cyz = 0;
+
+  cxx = 1 - (vab*vab) * t0vec(0) * t0vec(0) - t1vec(0) * t1vec(0);
+  cyy = 1 - (vab*vab) * t0vec(1) * t0vec(1) - t1vec(1) * t1vec(1);
+  czz = 1 - (vab*vab) * t0vec(2) * t0vec(2) - t1vec(2) * t1vec(2);
+  
+  cxy = -2 * (vab * vab) * t0vec(0) * t0vec(1) - 2 * t1vec(0) * t1vec(1);
+  cxz = -2 * (vab * vab) * t0vec(0) * t0vec(2) - 2 * t1vec(0) * t1vec(2);
+  cyz = -2 * (vab * vab) * t0vec(1) * t0vec(2) - 2 * t1vec(1) * t1vec(2);
+
+  cx = -2 * a(0) - 2 * (vab * vab) * t0 * t0vec(0) - 2 * t1 * t1vec(0);
+  cy = -2 * a(1) - 2 * (vab * vab) * t0 * t0vec(1) - 2 * t1 * t1vec(1);
+  cz = -2 * a(2) - 2 * (vab * vab) * t0 * t0vec(2) - 2 * t1 * t1vec(2);
+
+  c1 = va.Length2() - (vab * vab) * t0 * t0 - t1 * t1;
+
+  (*testout) << "t0vec = " << t0vec << " t0 = " << t0 << endl;
+  (*testout) << "t1vec = " << t1vec << " t1 = " << t1 << endl;
+  PrintCoeff (*testout);
+}
+
+
+INSOLID_TYPE Cone :: BoxInSolid (const BoxSphere<3> & box) const
+{
+  double rp, dist;
+
+  Vec<3> cv(box.Center());
+
+  rp = cv * t1vec + t1;
+  dist = sqrt (CalcFunctionValue(box.Center()) + rp * rp) - rp;
+
+  if (dist - box.Diam() > 0) return IS_OUTSIDE;
+  if (dist + box.Diam() < 0) return IS_INSIDE;
+  return DOES_INTERSECT;
+}
+
+
+double Cone :: HesseNorm () const
+{
+  return 2 / minr;   // old: 2 / minr
+}
+
+Point<3> Cone :: GetSurfacePoint () const
+{
+  Vec<3> vr = vab.GetNormal ();
+  
+  vr *= (ra / vr.Length());
+  return a + vr;
+}
+
+
+
+
+
+void Cone :: GetTriangleApproximation 
+(TriangleApproximation & tas, 
+ const Box<3> & boundingbox, double facets) const
+{
+  int i, j;
+  double lg, bg;
+  int n = int(facets) + 1;  
+
+  Vec<3> lvab = b - a;
+  Vec<3> n1 = lvab.GetNormal();
+  Vec<3> n2 = Cross (lvab, n1);
+  
+  n1.Normalize();
+  n2.Normalize();
+
+
+  for (j = 0; j <= n; j++)
+    for (i = 0; i <= n; i++)
+      {
+	lg = 2 * M_PI * double (i) / n;
+	bg = double(j) / n;
+
+	Point<3> p = a + (bg * lvab) 
+	  + (( (ra+(rb-ra)*bg)  * cos(lg)) * n1) 
+	  + (( (ra+(rb-ra)*bg)  * sin(lg)) * n2);
+
+	tas.AddPoint (p);
+      }
+
+  for (j = 0; j < n; j++)
+    for (i = 0; i < n; i++)
+      {
+	int pi = i + (n+1) * j;
+	tas.AddTriangle (TATriangle (0, pi, pi+1, pi+n+2));
+	tas.AddTriangle (TATriangle (0, pi, pi+n+2, pi+n+1));
+      }
+}
+}
diff --git a/Netgen/libsrc/csg/algprim.hpp b/Netgen/libsrc/csg/algprim.hpp
new file mode 100644
index 0000000000..83261edd16
--- /dev/null
+++ b/Netgen/libsrc/csg/algprim.hpp
@@ -0,0 +1,331 @@
+#ifndef FILE_ALGPRIM
+#define FILE_ALGPRIM
+
+
+/**************************************************************************/
+/* File:   algprim.hh                                                     */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   1. Dez. 95                                                     */
+/**************************************************************************/
+
+/*
+
+Quadric Surfaces (Plane, Sphere, Cylinder)
+  
+*/
+
+
+/**
+   A quadric surface.
+   surface defined by
+   cxx x^2 + cyy y^2 + czz z^2 + cxy x y + cxz x z + cyz y z +
+   cx x + cy y + cz z + c1 = 0.
+ **/
+class QuadraticSurface : public  OneSurfacePrimitive
+{
+protected:
+  double cxx, cyy, czz, cxy, cxz, cyz, cx, cy, cz, c1;
+
+public:
+
+  virtual double CalcFunctionValue (const Point<3> & point) const;
+  virtual void CalcGradient (const Point<3> & point, Vec<3> & grad) const;
+  virtual void CalcHesse (const Point<3> & point, Mat<3> & hesse) const;
+  /*
+  virtual int RootInBox (const Box<3> & box) 
+    const { return 0; }
+  virtual INSOLID_TYPE BoxInSolid (const BoxSphere<3> & box) 
+    const { return DOES_INTERSECT; }
+*/
+  virtual double HesseNorm () const { return cxx + cyy + czz; }
+  virtual Point<3> GetSurfacePoint () const;
+
+  virtual void Print (ostream & ist) const;
+  virtual void Read (istream & ist);
+  void PrintCoeff (ostream & ost) const;
+};
+
+
+/// A Plane (i.e., the plane and everything behind it).
+class Plane : public QuadraticSurface
+{
+  /// a point in the plane
+  Point<3> p;
+  /// outward normal vector 
+  Vec<3> n;
+public:
+  ///
+  Plane (const Point<3> & ap, Vec<3> an);
+
+  virtual void GetPrimitiveData (char *& classname, 
+				 ARRAY<double> & coeffs) const;
+  virtual void SetPrimitiveData (ARRAY<double> & coeffs);
+  static Primitive * CreateDefault ();
+
+  virtual Primitive * Copy () const;
+  virtual void Transform (Transformation<3> & trans);
+
+
+  virtual int IsIdentic (const Surface & s2, int & inv, double eps) const;
+
+  ///
+  virtual void DefineTangentialPlane (const Point<3> & ap1, 
+				      const Point<3> & ap2);
+  ///
+  virtual void ToPlane (const Point<3> & p3d, 
+			Point<2> & pplane, double h,
+			int & zone) const;
+  ///
+  virtual void FromPlane (const Point<2> & pplane, 
+			  Point<3> & p3d, 
+			  double h) const;
+  ///
+  virtual void Project (Point<3> & p) const;
+
+  ///
+  virtual INSOLID_TYPE BoxInSolid (const BoxSphere<3> & box) const;
+
+  ///
+  virtual double CalcFunctionValue (const Point<3> & point) const;
+  ///
+  virtual void CalcGradient (const Point<3> & point, 
+			     Vec<3> & grad) const;
+  ///
+  virtual void CalcHesse (const Point<3> & point, 
+			  Mat<3> & hesse) const;
+  ///
+  virtual double HesseNorm () const;
+  ///
+  virtual Point<3> GetSurfacePoint () const;
+  ///
+  virtual void GetTriangleApproximation 
+  (TriangleApproximation & tas, 
+   const Box<3> & boundingbox, double facets) const;
+
+};
+
+// typedef Plane Plane;
+
+
+///
+class Sphere : public QuadraticSurface
+{
+  ///
+  Point<3> c;
+  ///
+  double r;
+public:
+  ///
+  Sphere (const Point<3> & ac, double ar);
+
+  virtual void GetPrimitiveData (char *& classname, 
+				 ARRAY<double> & coeffs) const;
+  virtual void SetPrimitiveData (ARRAY<double> & coeffs);
+  static Primitive * CreateDefault ();
+
+  virtual Primitive * Copy () const;
+  virtual void Transform (Transformation<3> & trans);
+
+
+  virtual int IsIdentic (const Surface & s2, int & inv, double eps) const;
+
+  ///
+  virtual void DefineTangentialPlane (const Point<3> & ap1, 
+				      const Point<3> & ap2);
+  ///
+  virtual void ToPlane (const Point<3> & p3d, 
+			Point<2> & pplane, double h,
+			int & zone) const;
+  ///
+  virtual void FromPlane (const Point<2> & pplane, 
+			  Point<3> & p, double h) const;
+  ///
+  virtual void Project (Point<3> & p) const;
+
+  ///
+  virtual INSOLID_TYPE BoxInSolid (const BoxSphere<3> & box) const;
+  ///
+  virtual double HesseNorm () const;
+  ///
+  virtual Point<3> GetSurfacePoint () const;
+  ///
+  const Point<3> & Center () const { return c; }
+  ///
+  double Radius () const { return r; }
+
+  ///
+  virtual void GetTriangleApproximation (TriangleApproximation & tas, 
+					 const Box<3> & bbox, 
+					 double facets) const;
+};
+
+
+///
+class Cylinder : public QuadraticSurface
+{
+  ///
+  Point<3> a, b;
+  ///
+  double r;
+  ///
+  Vec<3> vab;
+
+public:
+  Cylinder (const Point<3> & aa, const Point<3> & ab, double ar);
+
+  virtual void GetPrimitiveData (char *& classname, ARRAY<double> & coeffs) const;
+  virtual void SetPrimitiveData (ARRAY<double> & coeffs);
+  static Primitive * CreateDefault ();
+
+  virtual Primitive * Copy () const;
+  virtual void Transform (Transformation<3> & trans);
+
+  ///
+  virtual int IsIdentic (const Surface & s2, int & inv, double eps) const;
+  ///
+  virtual void DefineTangentialPlane (const Point<3> & ap1, 
+				      const Point<3> & ap2);
+  ///
+  virtual void ToPlane (const Point<3> & p, 
+			Point<2> & pplane, 
+			double h,
+			int & zone) const;
+  ///
+  virtual void FromPlane (const Point<2> & pplane, 
+			  Point<3> & p, 
+			  double h) const;
+  ///
+  virtual void Project (Point<3> & p) const;
+
+  ///
+  virtual INSOLID_TYPE BoxInSolid (const BoxSphere<3> & box) const;
+  ///
+  virtual double HesseNorm () const;
+  ///
+  virtual Point<3> GetSurfacePoint () const;
+  ///
+  virtual void GetTriangleApproximation (TriangleApproximation & tas, 
+					 const Box<3> & bbox, 
+					 double facets) const;
+};
+
+
+
+
+
+///
+class EllipticCylinder : public QuadraticSurface
+{
+private:
+  ///
+  Point<3> a;
+  ///
+  Vec<3> vl, vs;
+  ///
+  Vec<3> vab, t0vec, t1vec;
+  ///
+  double vabl, t0, t1;
+public:
+  ///
+  EllipticCylinder (const Point<3> & aa,
+		    const Vec<3> & avl, const Vec<3> & avs);
+
+  /*
+  static Primitive * CreateDefault ();
+  virtual void GetPrimitiveData (char *& classname, ARRAY<double> & coeffs) const;
+  virtual void SetPrimitiveData (ARRAY<double> & coeffs);
+  */
+  ///
+  virtual INSOLID_TYPE BoxInSolid (const BoxSphere<3> & box) const;
+  ///
+  virtual double HesseNorm () const;
+  ///
+  virtual Point<3> GetSurfacePoint () const;
+
+  virtual void GetTriangleApproximation (TriangleApproximation & tas, 
+					 const Box<3> & bbox, 
+					 double facets) const;
+
+private:
+  void CalcData();
+};
+
+
+
+
+
+
+///
+class Ellipsoid : public QuadraticSurface
+{
+private:
+  ///
+  Point<3> a;
+  ///
+  Vec<3> v1, v2, v3;
+  ///
+  double rmin;
+public:
+  ///
+  Ellipsoid (const Point<3> & aa,
+	     const Vec<3> & av1, 
+	     const Vec<3> & av2,
+	     const Vec<3> & av3);
+  ///
+  virtual INSOLID_TYPE BoxInSolid (const BoxSphere<3> & box) const;
+  ///
+  virtual double HesseNorm () const;
+  ///
+  virtual Point<3> GetSurfacePoint () const;
+
+  virtual void GetTriangleApproximation (TriangleApproximation & tas, 
+					 const Box<3> & bbox, 
+					 double facets) const;
+
+private:
+  void CalcData();
+};
+
+
+
+
+
+
+
+
+///
+class Cone : public QuadraticSurface
+{
+  ///
+  Point<3> a, b;
+  ///
+  double ra, rb, minr;
+  ///
+  Vec<3> vab, t0vec, t1vec;
+  ///
+  double vabl, t0, t1;
+public:
+  ///
+  Cone (const Point<3> & aa, const Point<3> & ab, double ara, double arb);
+  ///
+  static Primitive * CreateDefault ();
+  virtual void GetPrimitiveData (char *& classname, ARRAY<double> & coeffs) const;
+  virtual void SetPrimitiveData (ARRAY<double> & coeffs);
+
+  ///
+  virtual INSOLID_TYPE BoxInSolid (const BoxSphere<3> & box) const;
+  ///
+  virtual double HesseNorm () const;
+  ///
+  virtual Point<3> GetSurfacePoint () const;
+
+  virtual void GetTriangleApproximation (TriangleApproximation & tas, 
+					 const Box<3> & bbox, 
+					 double facets) const;
+
+private:
+  void CalcData();
+};
+
+
+#endif
diff --git a/Netgen/libsrc/csg/brick.cpp b/Netgen/libsrc/csg/brick.cpp
new file mode 100644
index 0000000000..e4224ae512
--- /dev/null
+++ b/Netgen/libsrc/csg/brick.cpp
@@ -0,0 +1,409 @@
+#include <mystdlib.h>
+
+#include <linalg.hpp>
+#include <csg.hpp>
+
+namespace netgen
+{
+
+Parallelogram3d :: Parallelogram3d (Point<3> ap1, Point<3> ap2, Point<3> ap3)
+{
+  p1 = ap1;
+  p2 = ap2;
+  p3 = ap3;
+
+  CalcData();
+}
+
+Parallelogram3d ::~Parallelogram3d ()
+{
+  ;
+}
+
+void Parallelogram3d :: SetPoints (Point<3> ap1, 
+				   Point<3> ap2, 
+				   Point<3> ap3)
+{
+  p1 = ap1;
+  p2 = ap2;
+  p3 = ap3;
+
+  CalcData();
+}
+
+void Parallelogram3d :: CalcData()
+{
+  v12 = p2 - p1;
+  v13 = p3 - p1;
+  p4 = p2 + v13;
+
+  n = Cross (v12, v13);
+  n.Normalize();
+}
+
+int Parallelogram3d :: 
+IsIdentic (const Surface & s2, int & inv, double eps) const
+{
+  int id = 
+    (fabs (s2.CalcFunctionValue (p1)) <= eps) &&
+    (fabs (s2.CalcFunctionValue (p2)) <= eps) &&
+    (fabs (s2.CalcFunctionValue (p3)) <= eps);
+
+  if (id)
+    {
+      Vec<3> n2;
+      s2.GetNormalVector(p1, n2);
+      inv = (n * n2) < 0;
+    }
+  return id;
+}
+
+
+double Parallelogram3d :: CalcFunctionValue (const Point<3> & point) const
+{
+  return n * (point - p1);
+}
+
+void Parallelogram3d :: CalcGradient (const Point<3> & point, 
+				      Vec<3> & grad) const
+{
+  grad = n;
+}
+
+void Parallelogram3d :: CalcHesse (const Point<3> & point, Mat<3> & hesse) const
+{
+  hesse = 0;
+}
+
+double Parallelogram3d :: HesseNorm () const
+{
+  return 0;
+}
+
+Point<3> Parallelogram3d :: GetSurfacePoint () const
+{
+  return p1;
+}
+
+void Parallelogram3d :: Print (ostream & str) const
+{
+  str << "Parallelogram3d " << p1 << " - " << p2 << " - " << p3 << endl;
+}
+
+  
+void Parallelogram3d :: 
+GetTriangleApproximation (TriangleApproximation & tas, 
+			  const Box<3> & bbox, 
+			  double facets) const
+{
+  tas.AddPoint (p1);
+  tas.AddPoint (p2);
+  tas.AddPoint (p3);
+  tas.AddPoint (p4);
+  tas.AddTriangle (TATriangle (0, 0, 1, 2));
+  tas.AddTriangle (TATriangle (0, 2, 1, 3));
+}
+
+
+
+
+
+
+
+
+
+
+Brick :: Brick (Point<3> ap1, Point<3> ap2, 
+		Point<3> ap3, Point<3> ap4)
+{
+  faces.SetSize (6);
+  surfaceids.SetSize (6);
+  surfaceactive.SetSize(6);
+
+  p1 = ap1; p2 = ap2;
+  p3 = ap3; p4 = ap4;
+
+  for (int i = 0; i < 6; i++)
+    {
+      faces[i] = new Plane (Point<3>(0,0,0), Vec<3> (0,0,1));
+      surfaceactive[i] = 1;
+    }
+
+  CalcData();
+}
+
+Brick :: ~Brick ()
+{
+  for (int i = 0; i < 6; i++)
+    delete faces[i];
+}
+
+Primitive * Brick :: CreateDefault ()
+{
+  return new Brick (Point<3> (0,0,0),
+		    Point<3> (1,0,0),
+		    Point<3> (0,1,0),
+		    Point<3> (0,0,1));
+}
+
+
+INSOLID_TYPE Brick :: BoxInSolid (const BoxSphere<3> & box) const
+{
+  /*
+  int i;
+  double maxval;
+  for (i = 1; i <= 6; i++)
+    {
+      double val = faces.Get(i)->CalcFunctionValue (box.Center());
+      if (i == 1 || val > maxval)
+	maxval = val;
+    }
+  
+  if (maxval > box.Diam()) return IS_OUTSIDE;
+  if (maxval < -box.Diam()) return IS_INSIDE;
+  return DOES_INTERSECT;
+  */
+
+  bool inside = 1;
+  bool outside = 0;
+
+  for (int i = 0; i < 6; i++)
+    {
+      bool outsidei = 1;
+      for (int j = 0; j < 8; j++)
+	{
+	  Point<3> p = box.GetPointNr (j);
+	  double val = faces[i]->CalcFunctionValue (p);
+
+	  if (val > 0)  inside = 0;
+	  if (val < 0)  outsidei = 0;
+	}
+      if (outsidei) outside = 1;
+    }
+
+  if (outside) return IS_OUTSIDE;
+  if (inside) return IS_INSIDE;
+  return DOES_INTERSECT;
+}
+
+INSOLID_TYPE Brick :: PointInSolid (const Point<3> & p,
+			   double eps) const
+{
+  double maxval = faces[0] -> CalcFunctionValue (p);
+  for (int i = 1; i < 6; i++)
+    {
+      double val = faces[i] -> CalcFunctionValue (p);
+      if (val > maxval) maxval = val;
+    }
+
+  if (maxval > eps) return IS_OUTSIDE;
+  if (maxval < -eps) return IS_INSIDE;
+  return DOES_INTERSECT;
+}
+
+INSOLID_TYPE Brick :: VecInSolid (const Point<3> & p,
+				  const Vec<3> & v,
+				  double eps) const
+{
+  INSOLID_TYPE is = IS_INSIDE;
+  Vec<3> grad;
+  double scal;
+
+  for (int i = 0; i < faces.Size(); i++)
+    {
+      if (faces[i] -> PointOnSurface (p, eps))
+	{
+	  GetSurface(i).CalcGradient (p, grad);
+	  scal = v * grad;
+	  
+	  if (scal >= eps) 
+	    is = IS_OUTSIDE;
+	  if (scal >= -eps && is == IS_INSIDE)
+	    is = DOES_INTERSECT;
+	}
+    }
+  return is;
+  /*
+  Point<3> p2 = p + 1e-2 * v;
+  return PointInSolid (p2, eps);
+  */
+}
+
+
+void Brick :: 
+GetPrimitiveData (char *& classname, ARRAY<double> & coeffs) const
+{
+  classname = "brick";
+  coeffs.SetSize(12);
+  coeffs.Elem(1) = p1(0);
+  coeffs.Elem(2) = p1(1);
+  coeffs.Elem(3) = p1(2);
+
+  coeffs.Elem(4) = p2(0);
+  coeffs.Elem(5) = p2(1);
+  coeffs.Elem(6) = p2(2);
+
+  coeffs.Elem(7) = p3(0);
+  coeffs.Elem(8) = p3(1);
+  coeffs.Elem(9) = p3(2);
+
+  coeffs.Elem(10) = p4(0);
+  coeffs.Elem(11) = p4(1);
+  coeffs.Elem(12) = p4(2);
+}
+
+void Brick :: SetPrimitiveData (ARRAY<double> & coeffs)
+{
+  p1(0) = coeffs.Elem(1);
+  p1(1) = coeffs.Elem(2);
+  p1(2) = coeffs.Elem(3);
+
+  p2(0) = coeffs.Elem(4);
+  p2(1) = coeffs.Elem(5);
+  p2(2) = coeffs.Elem(6);
+
+  p3(0) = coeffs.Elem(7);
+  p3(1) = coeffs.Elem(8);
+  p3(2) = coeffs.Elem(9);
+
+  p4(0) = coeffs.Elem(10);
+  p4(1) = coeffs.Elem(11);
+  p4(2) = coeffs.Elem(12);
+
+  CalcData();
+}
+
+
+
+void Brick :: CalcData()
+{
+  v12 = p2 - p1;
+  v13 = p3 - p1;
+  v14 = p4 - p1;
+
+  Point<3> pi[8];
+  int i1, i2, i3;
+  int i, j;
+  
+  i = 0;
+  for (i3 = 0; i3 <= 1; i3++)
+    for (i2 = 0; i2 <= 1; i2++)
+      for (i1 = 0; i1 <= 1; i1++)
+	{
+	  pi[i] = p1 + i1 * v12 + i2 * v13 + i3 * v14;
+	  i++;
+	}
+
+  static int lface[6][4] =
+  { { 1, 3, 2, 4 },
+    { 5, 6, 7, 8 },
+    { 1, 2, 5, 6 },
+    { 3, 7, 4, 8 },
+    { 1, 5, 3, 7 },
+    { 2, 4, 6, 8 } };
+  
+  ARRAY<double> data(6);
+  for (i = 0; i < 6; i++)
+    {
+      const Point<3> p1 = pi[lface[i][0]-1];
+      const Point<3> p2 = pi[lface[i][1]-1];
+      const Point<3> p3 = pi[lface[i][2]-1];
+
+      Vec<3> n = Cross ((p2-p1), (p3-p1));
+      n.Normalize();
+      
+      for (j = 0; j < 3; j++)
+	{
+	  data[j] = p1(j);
+	  data[j+3] = n(j);
+	}
+      faces[i] -> SetPrimitiveData (data);
+      /* 
+	 {
+	 faces.Elem(i+1) -> SetPoints
+	 (pi[lface[i][0]-1],
+	 pi[lface[i][1]-1],
+	 pi[lface[i][2]-1]);
+	 }
+      */
+    }
+}
+
+
+void Brick :: Reduce (const BoxSphere<3> & box)
+{
+  double val;
+  Point<3> p;
+  for (int i = 0; i < 6; i++)
+    {
+      bool hasout = 0;
+      bool hasin = 0;
+      for (int j = 0; j < 8; j++)
+	{
+	  p = box.GetPointNr (j);
+	  val = faces[i]->CalcFunctionValue (p);
+	  if (val > 0)  hasout = 1;
+	  else if (val < 0)  hasin = 1;
+	}
+      surfaceactive[i] =  hasout && hasin;
+    }
+}
+
+void Brick :: UnReduce ()
+{ 
+  for (int i = 0; i < 6; i++)
+    surfaceactive[i] = 1;
+}
+
+
+
+OrthoBrick :: OrthoBrick (const Point<3> & ap1, const Point<3> & ap2)
+  : Brick (ap1, 
+	   Point<3> (ap2(0), ap1(1), ap1(2)),
+	   Point<3> (ap1(0), ap2(1), ap1(2)),
+	   Point<3> (ap1(0), ap1(1), ap2(2)))
+{
+  pmin = ap1;
+  pmax = ap2;
+}
+	 
+INSOLID_TYPE OrthoBrick :: BoxInSolid (const BoxSphere<3> & box) const
+{
+  if (pmin(0) > box.PMax()(0) ||
+      pmin(1) > box.PMax()(1) ||
+      pmin(2) > box.PMax()(2) ||
+      pmax(0) < box.PMin()(0) ||
+      pmax(1) < box.PMin()(1) ||
+      pmax(2) < box.PMin()(2))
+    return IS_OUTSIDE;
+
+  if (pmin(0) < box.PMin()(0) &&
+      pmin(1) < box.PMin()(1) &&
+      pmin(2) < box.PMin()(2) &&
+      pmax(0) > box.PMax()(0) &&
+      pmax(1) > box.PMax()(1) &&
+      pmax(2) > box.PMax()(2))
+    return IS_INSIDE;
+
+  return DOES_INTERSECT;
+}
+
+
+void OrthoBrick :: Reduce (const BoxSphere<3> & box)
+{
+  surfaceactive.Elem(1) =
+    (box.PMin()(2) < pmin(2)) && (pmin(2) < box.PMax()(2));
+  surfaceactive.Elem(2) =
+    (box.PMin()(2) < pmax(2)) && (pmax(2) < box.PMax()(2));
+
+  surfaceactive.Elem(3) =
+    (box.PMin()(1) < pmin(1)) && (pmin(1) < box.PMax()(1));
+  surfaceactive.Elem(4) =
+    (box.PMin()(1) < pmax(1)) && (pmax(1) < box.PMax()(1));
+
+  surfaceactive.Elem(5) =
+    (box.PMin()(0) < pmin(0)) && (pmin(0) < box.PMax()(0));
+  surfaceactive.Elem(6) =
+    (box.PMin()(0) < pmax(0)) && (pmax(0) < box.PMax()(0));
+}
+}
diff --git a/Netgen/libsrc/csg/brick.hpp b/Netgen/libsrc/csg/brick.hpp
new file mode 100644
index 0000000000..1733335101
--- /dev/null
+++ b/Netgen/libsrc/csg/brick.hpp
@@ -0,0 +1,97 @@
+#ifndef FILE_BRICK
+#define FILE_BRICK
+
+
+/**************************************************************************/
+/* File:   brick.hh                                                       */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   11. Mar. 98                                                    */
+/**************************************************************************/
+
+/*
+
+  brick geometry, has several surfaces
+  
+*/
+
+
+
+class Parallelogram3d : public Surface
+{
+  Point<3> p1, p2, p3, p4;
+  Vec<3> v12, v13;
+  Vec<3> n;
+
+public:
+  Parallelogram3d (Point<3> ap1, Point<3> ap2, Point<3> ap3);
+  virtual ~Parallelogram3d ();
+  void SetPoints (Point<3> ap1, Point<3> ap2, Point<3> ap3);
+
+  virtual int IsIdentic (const Surface & s2, int & inv, double eps) const; 
+
+  virtual double CalcFunctionValue (const Point<3> & point) const;
+  virtual void CalcGradient (const Point<3> & point, Vec<3> & grad) const;
+  virtual void CalcHesse (const Point<3> & point, Mat<3> & hesse) const;
+  virtual double HesseNorm () const;
+
+  virtual Point<3> GetSurfacePoint () const;
+  virtual void Print (ostream & str) const;
+  
+  virtual void GetTriangleApproximation (TriangleApproximation & tas, 
+					 const Box<3> & boundingbox, 
+					 double facets) const;
+
+protected:
+  void CalcData();
+};
+
+
+class Brick : public Primitive
+{
+  Point<3> p1, p2, p3, p4;
+  Vec<3> v12, v13, v14;
+  ARRAY<OneSurfacePrimitive*> faces;
+
+public:
+  Brick (Point<3> ap1, Point<3> ap2, Point<3> ap3, Point<3> ap4);
+  ~Brick ();
+  static Primitive * CreateDefault ();
+
+
+  virtual INSOLID_TYPE BoxInSolid (const BoxSphere<3> & box) const;
+  virtual INSOLID_TYPE PointInSolid (const Point<3> & p,
+				     double eps) const;
+  virtual INSOLID_TYPE VecInSolid (const Point<3> & p,
+				   const Vec<3> & v,
+				   double eps) const;
+
+  virtual int GetNSurfaces() const 
+    { return 6; }
+  virtual Surface & GetSurface (int i) 
+    { return *faces[i]; }
+  virtual const Surface & GetSurface (int i) const
+    { return *faces[i]; }
+
+
+  virtual void GetPrimitiveData (char *& classname, ARRAY<double> & coeffs) const;
+  virtual void SetPrimitiveData (ARRAY<double> & coeffs);
+
+  virtual void Reduce (const BoxSphere<3> & box);
+  virtual void UnReduce ();
+
+protected:
+  void CalcData();
+};
+
+
+class OrthoBrick : public Brick 
+{
+protected:
+  Point<3> pmin, pmax;
+public:
+  OrthoBrick (const Point<3> & ap1, const Point<3> & ap2);
+  virtual INSOLID_TYPE BoxInSolid (const BoxSphere<3> & box) const;
+  virtual void Reduce (const BoxSphere<3> & box);
+};
+
+#endif
diff --git a/Netgen/libsrc/csg/bspline2d.cpp b/Netgen/libsrc/csg/bspline2d.cpp
new file mode 100644
index 0000000000..ebb284a28b
--- /dev/null
+++ b/Netgen/libsrc/csg/bspline2d.cpp
@@ -0,0 +1,243 @@
+#include <mystdlib.h>
+
+#include <csg.hpp>
+
+namespace netgen
+{
+
+BSplineCurve2d :: BSplineCurve2d ()
+{
+  redlevel = 0;
+}
+
+
+void BSplineCurve2d :: AddPoint (const Point<2> & apoint)
+{
+  points.Append (apoint);
+  intervallused.Append (0);
+}
+
+bool BSplineCurve2d :: Inside (const Point<2> & p, double & dist) const
+{
+  Point<2> hp = p;
+  double t = ProjectParam (p);
+  hp = Eval(t);
+  Vec<2> v = EvalPrime (t);
+
+  Vec<2> n (v(0), -v(1));
+  
+  cout << "p = " << p << ", hp = " << hp << endl;
+  dist = Dist (p, hp);
+  double scal = (hp-p) * n;
+  cout << "scal = " << scal << endl;
+  char ch;
+  //  cin >> ch;
+  return scal >= 0;
+}
+  
+double BSplineCurve2d :: ProjectParam (const Point<2> & p) const
+{
+  double t, dt, mindist, mint;
+  int n1;
+  
+  mindist = 1e10;
+  dt = 0.2;
+  for (n1 = 1; n1 <= points.Size(); n1++)
+    if (intervallused.Get(n1) == 0)
+      for (t = n1; t <= n1+1; t += dt)
+        if (Dist (Eval(t), p) < mindist)
+          {
+	    mint = t;
+	    mindist = Dist (Eval(t), p);
+          }
+    
+  if (mindist > 1e9) 
+    {
+      for (t = 0; t <= points.Size(); t += dt)
+	if (Dist (Eval(t), p) < mindist)
+	  {
+	    mint = t;
+	    mindist = Dist (Eval(t), p);
+	  }   
+    }
+
+  while (Dist (Eval (mint-dt), p) < mindist)
+    {
+      mindist = Dist (Eval (mint-dt), p);
+      mint -= dt;
+    }
+  while (Dist (Eval (mint+dt), p) < mindist)
+    {
+      mindist = Dist (Eval (mint+dt), p);
+      mint += dt;
+    }
+
+
+  return NumericalProjectParam (p, mint-dt, mint+dt);  
+}
+  
+  
+// t \in (n1, n2)  
+  
+Point<2> BSplineCurve2d :: Eval (double t) const
+{
+  int n, n1, n2, n3, n4;
+  double loct, b1, b2, b3, b4;
+  Point<2> hp;
+
+  static int cnt = 0;
+  cnt++;
+  if (cnt % 100000 == 0) (*mycout) << "cnt = " << cnt << endl;
+  
+  n = int(t);   
+  loct = t - n;
+  
+  b1 = 0.25 * (1 - loct) * (1 - loct);
+  b4 = 0.25 * loct * loct;
+  b2 = 0.5 - b4;
+  b3 = 0.5 - b1;
+  
+  n1 = (n + 10 * points.Size() -1) % points.Size() + 1;
+  n2 = n1+1;
+  if (n2 > points.Size()) n2 = 1;
+  n3 = n2+1;
+  if (n3 > points.Size()) n3 = 1;
+  n4 = n3+1;
+  if (n4 > points.Size()) n4 = 1;
+
+  //  (*mycout) << "t = " << t << " n = " << n << " loct = " << loct 
+  //      << " n1 = " << n1 << endl;
+
+  
+  hp(0) = b1 * points.Get(n1)(0) + b2 * points.Get(n2)(0) +
+    b3 * points.Get(n3)(0) + b4 * points.Get(n4)(0);
+  hp(1) = b1 * points.Get(n1)(1) + b2 * points.Get(n2)(1) +
+    b3 * points.Get(n3)(1) + b4 * points.Get(n4)(1);
+  return hp;
+}
+  
+Vec<2> BSplineCurve2d :: EvalPrime (double t) const
+{
+  int n, n1, n2, n3, n4;
+  double loct, db1, db2, db3, db4;
+  Vec<2> hv;
+  
+  n = int(t);   
+  loct = t - n;
+  
+  db1 = 0.5 * (loct - 1);
+  db4 = 0.5 * loct;
+  db2 = -db4;
+  db3 = -db1;
+  
+  n1 = (n + 10 * points.Size() -1) % points.Size() + 1;
+  n2 = n1+1;
+  if (n2 > points.Size()) n2 = 1;
+  n3 = n2+1;
+  if (n3 > points.Size()) n3 = 1;
+  n4 = n3+1;
+  if (n4 > points.Size()) n4 = 1;
+  
+  hv(0) = db1 * points.Get(n1)(0) + db2 * points.Get(n2)(0) +
+    db3 * points.Get(n3)(0) + db4 * points.Get(n4)(0);
+  hv(1) = db1 * points.Get(n1)(1) + db2 * points.Get(n2)(1) +
+    db3 * points.Get(n3)(1) + db4 * points.Get(n4)(1);
+  return hv;
+}
+
+Vec<2> BSplineCurve2d :: EvalPrimePrime (double t) const
+{
+  int n, n1, n2, n3, n4;
+  double loct, ddb1, ddb2, ddb3, ddb4;
+  Vec<2> hv;
+  
+  n = int(t);   
+  //  loct = t - n;
+  
+  ddb1 = 0.5;
+  ddb4 = 0.5;
+  ddb2 = -0.5;
+  ddb3 = -0.5;
+  
+  n1 = (n + 10 * points.Size() -1) % points.Size() + 1;
+  n2 = n1+1;
+  if (n2 > points.Size()) n2 = 1;
+  n3 = n2+1;
+  if (n3 > points.Size()) n3 = 1;
+  n4 = n3+1;
+  if (n4 > points.Size()) n4 = 1;
+  
+  hv(0) = ddb1 * points.Get(n1)(0) + ddb2 * points.Get(n2)(0) +
+    ddb3 * points.Get(n3)(0) + ddb4 * points.Get(n4)(0);
+  hv(1) = ddb1 * points.Get(n1)(1) + ddb2 * points.Get(n2)(1) +
+    ddb3 * points.Get(n3)(1) + ddb4 * points.Get(n4)(1);
+  return hv;
+}
+  
+
+int BSplineCurve2d :: SectionUsed (double t) const
+{
+  int n1 = int(t);   
+  n1 = (n1 + 10 * points.Size() - 1) % points.Size() + 1;
+  return (intervallused.Get(n1) == 0);
+}
+
+void BSplineCurve2d :: Reduce (const Point<2> & p, double rad)
+{
+  int n1, n;
+  int j; 
+  double minx, miny, maxx, maxy;
+  
+  //  (*testout) << "Reduce: " << p << "," << rad << endl;
+  
+  redlevel++;
+  
+  for (n1 = 1; n1 <= points.Size(); n1++)
+    {
+      if (intervallused.Get(n1) != 0) continue;
+    
+      minx = maxx = points.Get(n1)(0);
+      miny = maxy = points.Get(n1)(1);
+    
+      n = n1;
+      for (j = 1; j <= 3; j++)
+	{
+	  n++;
+	  if (n > points.Size()) n = 1;
+	  if (points.Get(n)(0) < minx) minx = points.Get(n)(0);
+	  if (points.Get(n)(1) < miny) miny = points.Get(n)(1);
+	  if (points.Get(n)(0) > maxx) maxx = points.Get(n)(0);
+	  if (points.Get(n)(1) > maxy) maxy = points.Get(n)(1);
+	}
+      
+      if (minx > p(0) + rad || maxx < p(0) - rad ||
+	  miny > p(1) + rad || maxy < p(1) - rad)
+	{
+	  intervallused.Elem(n1) = redlevel;
+	  //      (*testout) << 0;
+	}
+      else
+	{
+	  //      (*testout) << 1;
+	  intervallused.Elem(n1) = 0;
+	}
+    }
+  //  (*testout) << endl;
+}
+
+void BSplineCurve2d :: UnReduce () 
+{
+  int i;
+  for (i = 1; i <= intervallused.Size(); i++)
+    if (intervallused.Get(i) == redlevel)
+      intervallused.Set (i, 0);
+  redlevel--;
+}
+  
+void BSplineCurve2d :: Print (ostream & ost) const
+{
+  ost << "SplineCurve: " << points.Size() << " points." << endl;
+  for (int i = 1; i <= points.Size(); i++)
+    ost << "P" << i << " = " << points.Get(i) << endl;
+}
+}
diff --git a/Netgen/libsrc/csg/csg.hpp b/Netgen/libsrc/csg/csg.hpp
new file mode 100644
index 0000000000..08dd054901
--- /dev/null
+++ b/Netgen/libsrc/csg/csg.hpp
@@ -0,0 +1,43 @@
+#ifndef FILE_CSG
+#define FILE_CSG
+
+/* *************************************************************************/
+/* File:   geoml.hpp                                                        */
+/* Author: Joachim Schoeberl                                               */
+/* Date:   21. Jun. 98                                                     */
+/* *************************************************************************/
+
+#include <myadt.hpp>
+#include <gprim.hpp>
+#include <meshing.hpp>
+
+namespace netgen
+{
+#include "surface.hpp"
+#include "solid.hpp"
+#include "identify.hpp"
+#include "singularref.hpp"
+
+#include "csgeom.hpp"
+#include "triapprox.hpp"
+
+
+#include "algprim.hpp"
+#include "brick.hpp"
+#include "spline3d.hpp"
+// #include "spline2d.hpp"
+#include "manifold.hpp"
+#include "curve2d.hpp"
+#include "explicitcurve2d.hpp"
+#include "gencyl.hpp"
+#include "polyhedra.hpp"
+#include "extrusion.hpp"
+#include "revolution.hpp"
+
+// #include "geom2dmesh.hpp"
+#include "specpoin.hpp"
+#include "edgeflw.hpp"
+#include "meshsurf.hpp" 
+}
+
+#endif
diff --git a/Netgen/libsrc/csg/csgeom.cpp b/Netgen/libsrc/csg/csgeom.cpp
new file mode 100644
index 0000000000..7e1051b781
--- /dev/null
+++ b/Netgen/libsrc/csg/csgeom.cpp
@@ -0,0 +1,1067 @@
+#include <mystdlib.h>
+#include <myadt.hpp>
+
+#include <linalg.hpp>
+#include <csg.hpp>
+
+
+namespace netgen
+{
+
+int CSGeometry :: changeval = 0;
+
+
+
+TopLevelObject ::  
+TopLevelObject (Solid * asolid,
+		Surface * asurface)
+{
+  solid = asolid;
+  surface = asurface;
+
+  SetRGB (0, 0, 1);
+  SetTransparent (0);
+  SetVisible (1); 
+  SetLayer (1);
+
+  if (!surface)
+    maxh = solid->GetMaxH();
+  else
+    maxh = surface->GetMaxH();
+
+  SetBCProp (-1);
+}
+
+void TopLevelObject :: GetData (ostream & ost)
+{
+  ost << red << " " << green << " " << blue << " " 
+      << transp << " " << visible << " ";
+}
+
+void TopLevelObject :: SetData (istream & ist)
+{
+  ist >> red >> green >> blue >> transp >> visible;
+}
+
+
+
+
+
+CSGeometry :: CSGeometry ()
+  : boundingbox (Point<3> (-1000, -1000, -1000),
+		 Point<3> (1000, 1000, 1000)),
+    identicsurfaces (100), filename("")
+{
+  ;
+}
+
+
+
+CSGeometry :: CSGeometry (const string & afilename)
+  : boundingbox (Point<3> (-1000, -1000, -1000),
+		 Point<3> (1000, 1000, 1000)),
+    identicsurfaces (100), filename(afilename)
+{
+  changeval++;
+}
+
+CSGeometry :: ~CSGeometry ()
+{
+  Clean();
+}
+
+
+void CSGeometry :: Clean ()
+{
+  int i;
+
+  //  for (i = 0; i < solids.Size(); i++)
+  //    delete solids[i];
+  solids.DeleteAll ();
+
+  for (i = 0; i < surfaces.Size(); i++)
+    delete surfaces[i];
+  surfaces.DeleteAll ();
+  
+  for (i = 0; i < toplevelobjects.Size(); i++)
+    delete toplevelobjects[i];
+  toplevelobjects.DeleteAll ();
+
+  for (i = 0; i < triapprox.Size(); i++)
+    delete triapprox[i];
+  triapprox.DeleteAll();
+
+  changeval++;
+}
+
+
+
+
+
+class WritePrimitivesIt : public SolidIterator
+{
+  ostream & ost;
+public:
+  WritePrimitivesIt (ostream & aost);
+  ~WritePrimitivesIt ();
+  virtual void Do (Solid * sol);
+};
+
+WritePrimitivesIt :: WritePrimitivesIt (ostream & aost)
+  : SolidIterator(), ost(aost)
+{
+  ;
+}
+WritePrimitivesIt :: ~WritePrimitivesIt ()
+{
+  ;
+}
+
+void WritePrimitivesIt :: Do (Solid * sol) 
+{
+  Primitive * prim = sol->GetPrimitive();
+  if (prim)
+    {
+      char * classname;
+      ARRAY<double> coeffs;
+
+      prim -> GetPrimitiveData (classname, coeffs);
+
+      if (sol->Name())
+	ost << "primitive " 
+	    << sol->Name() << " "
+	    << classname << "  " << coeffs.Size();
+      for (int i = 0; i < coeffs.Size(); i++)
+	ost << " " << coeffs[i];
+      ost << endl;
+    }
+}
+
+
+
+
+void CSGeometry :: Save (ostream & ost) 
+{
+  ost << "boundingbox "
+      << boundingbox.PMin()(0) << " "
+      << boundingbox.PMin()(1) << " "
+      << boundingbox.PMin()(2) << " "
+      << boundingbox.PMax()(0) << " "
+      << boundingbox.PMax()(1) << " "
+      << boundingbox.PMax()(2) << endl;
+
+
+  WritePrimitivesIt wpi(ost);
+  IterateAllSolids (wpi, 1);
+
+  int i;
+  for (i = 0; i < solids.Size(); i++)
+    {
+      if (!solids[i]->GetPrimitive())
+	{
+	  ost << "solid " << solids.GetName(i) << " ";
+	  solids[i] -> GetSolidData (ost);
+	  ost << endl;
+	}
+    }
+
+  for (i = 0; i < GetNTopLevelObjects(); i++)
+    {
+      TopLevelObject * tlo = GetTopLevelObject (i);
+      ost << "toplevel ";
+      if (tlo -> GetSurface())
+	ost << "surface " << tlo->GetSolid()->Name() << " "
+	    << tlo->GetSurface()->Name() << " ";
+      else
+	ost << "solid " << tlo->GetSolid()->Name() << " ";
+      tlo->GetData(ost);
+      ost << endl;
+    }
+
+  for (i = 0; i < identifications.Size(); i++)
+    {
+      ost << "identify ";
+      identifications[i] -> GetData (ost);
+      ost << endl;
+    }
+
+  ost << "end" << endl;
+}
+
+ 
+void CSGeometry :: Load (istream & ist)
+{
+  //  CSGeometry * geo = new CSGeometry;
+  
+  char key[100], name[100], classname[100], sname[100];
+  int ncoeff, i, j;
+  ARRAY<double> coeff;
+
+  while (ist.good())
+    {
+      ist >> key;
+      if (strcmp (key, "boundingbox") == 0)
+	{
+	  Point<3> pmin, pmax;
+	  ist >> pmin(0) >> pmin(1) >> pmin(2);
+	  ist >> pmax(0) >> pmax(1) >> pmax(2);
+	  SetBoundingBox (Box<3> (pmin, pmax));
+	}
+      if (strcmp (key, "primitive") == 0)
+	{
+	  ist >> name >> classname >> ncoeff;
+	  coeff.SetSize (ncoeff);
+	  for (i = 0; i < ncoeff; i++)
+	    ist >> coeff[i];
+
+	  Primitive * nprim = Primitive::CreatePrimitive (classname);
+	  nprim -> SetPrimitiveData (coeff);
+	  Solid * nsol = new Solid (nprim);
+
+	  for (j = 0; j < nprim->GetNSurfaces(); j++)
+	    {
+	      sprintf (sname, "%s,%d", name, j);
+	      AddSurface (sname, &nprim->GetSurface(j));
+	      nprim -> SetSurfaceId (j, GetNSurf());
+	    }
+	  SetSolid (name, nsol);
+	}
+      else if (strcmp (key, "solid") == 0)
+	{
+	  ist >> name;
+	  Solid * nsol = Solid::CreateSolid (ist, solids);
+
+	  cout << " I have found solid " << name << " = ";
+	  nsol -> GetSolidData (cout);
+	  cout << endl;
+
+	  SetSolid (name, nsol);
+	}
+      else if (strcmp (key, "toplevel") == 0)
+	{
+	  char type[20], solname[50], surfname[50];
+	  const Solid * sol = NULL;
+	  const Surface * surf = NULL;
+	  int nr;
+
+	  ist >> type;
+	  if (strcmp (type, "solid") == 0)
+	    {
+	      ist >> solname;
+	      sol = GetSolid (solname);
+	    }
+	  if (strcmp (type, "surface") == 0)
+	    {
+	      ist >> solname >> surfname;
+	      sol = GetSolid (solname);
+	      surf = GetSurface (surfname);
+	    }
+	  nr = SetTopLevelObject ((Solid*)sol, (Surface*)surf);
+	  GetTopLevelObject (nr) -> SetData (ist);
+	}
+      else if (strcmp (key, "identify") == 0)
+	{
+	  char type[10], surfname1[50], surfname2[50];
+	  const Surface * surf1;
+	  const Surface * surf2;
+
+
+	  ist >> type >> surfname1 >> surfname2;
+	  surf1 = GetSurface(surfname1);
+	  surf2 = GetSurface(surfname2);
+	  
+	  AddIdentification (new PeriodicIdentification 
+			     (GetNIdentifications(),
+			      *this, surf1, surf2));
+	}
+      else if (strcmp (key, "end") == 0)
+	break;
+    }
+
+  changeval++;
+}
+
+
+
+
+
+void CSGeometry :: AddSurface (Surface * surf)
+{
+  static int cntsurfs = 0;
+  cntsurfs++;
+  char name[15];
+  sprintf (name, "nnsurf%d", cntsurfs);
+  AddSurface (name, surf);
+}
+ 
+void CSGeometry :: AddSurface (char * name, Surface * surf)
+{ 
+  surfaces.Set (name, surf); 
+  surf->SetName (name);
+  changeval++; 
+}
+
+
+const Surface * CSGeometry :: GetSurface (const char * name) const
+{
+  if (surfaces.Used(name))
+    return surfaces.Get(name);
+  else
+    return NULL;
+}
+
+const Surface * CSGeometry :: GetSurface (int i) const
+{
+  if (i >= 0 && i < surfaces.Size()) 
+    return surfaces[i];
+  else
+    return NULL;
+}
+
+
+
+
+
+void CSGeometry :: SetSolid (const char * name, Solid * sol)
+{
+  Solid * oldsol = NULL;
+
+  if (solids.Used (name))
+    oldsol = solids.Get(name);
+
+  solids.Set (name, sol);
+  sol->SetName (name);
+
+  if (oldsol)
+    {
+      if (oldsol->op != Solid::ROOT ||
+	  sol->op != Solid::ROOT)
+	{
+	  cerr << "Setsolid: old or new no root" << endl;
+	}
+      oldsol -> s1 = sol -> s1;
+    }
+  changeval++;
+}
+
+const Solid * CSGeometry :: GetSolid (const char * name) const
+{
+  if (solids.Used(name))
+    return solids.Get(name);
+  else
+    return NULL;
+}
+
+
+
+const Solid * CSGeometry :: GetSolid (const string & name) const
+{
+  if (solids.Used(name.c_str()))
+    return solids.Get(name.c_str());
+  else
+    return NULL;
+}
+
+
+
+
+
+
+
+
+class RemoveDummyIterator : public SolidIterator
+{
+public:
+  
+  RemoveDummyIterator();
+  ~RemoveDummyIterator();
+  virtual void Do(Solid * sol);
+};
+
+RemoveDummyIterator :: RemoveDummyIterator()
+{
+  ;
+}
+
+RemoveDummyIterator :: ~RemoveDummyIterator()
+{
+  ;
+}
+
+void RemoveDummyIterator :: Do(Solid * sol)
+{
+  if ( (sol->op == Solid::SUB || sol->op == Solid::SECTION || 
+	sol->op == Solid::UNION)
+       && sol->s1->op == Solid::DUMMY)
+    sol->s1 = sol->s1->s1;
+  if ( (sol->op == Solid::SECTION || sol->op == Solid::UNION)
+       && sol->s2->op == Solid::DUMMY)
+    sol->s2 = sol->s2->s1;
+}
+
+
+
+
+
+
+int CSGeometry :: SetTopLevelObject (Solid * sol, Surface * surf)
+{
+  return toplevelobjects.Append (new TopLevelObject (sol, surf)) - 1;
+}
+
+void CSGeometry :: GetTopLevelObject (int nr, Solid *& sol, Surface *& surf)
+{
+  sol = toplevelobjects[nr]->GetSolid();
+  surf = toplevelobjects[nr]->GetSurface();
+}
+
+
+void CSGeometry :: GetTopLevelObject (int nr, const Solid *& sol, const Surface *& surf) const
+{
+  sol = toplevelobjects[nr]->GetSolid();
+  surf = toplevelobjects[nr]->GetSurface();
+}
+
+TopLevelObject * CSGeometry :: 
+GetTopLevelObject (const Solid * sol, const Surface * surf)
+{
+  for (int i = 0; i < toplevelobjects.Size(); i++)
+    {
+      if (toplevelobjects[i]->GetSolid() == sol &&
+	  toplevelobjects[i]->GetSurface() == surf)
+	return (toplevelobjects[i]);
+    }
+  return NULL;
+}
+
+void CSGeometry :: RemoveTopLevelObject (Solid * sol, Surface * surf)
+{
+  for (int i = 0; i < toplevelobjects.Size(); i++)
+    {
+      if (toplevelobjects[i]->GetSolid() == sol &&
+	  toplevelobjects[i]->GetSurface() == surf)
+	{
+	  delete toplevelobjects[i];
+	  toplevelobjects.DeleteElement (i+1);
+	  changeval++;
+	  break;
+	}
+    }
+}
+
+void CSGeometry :: AddIdentification (Identification * ident)
+{
+  identifications.Append (ident);
+}
+
+void CSGeometry :: SetFlags (const char * solidname, const Flags & flags)
+{
+  Solid * solid = solids.Elem(solidname);
+  ARRAY<int> surfind;
+
+  int i;
+  double maxh = flags.GetNumFlag ("maxh", -1);
+  if (maxh > 0 && solid)
+    {
+      solid->GetSurfaceIndices (surfind);
+
+      for (i = 0; i < surfind.Size(); i++)
+	{
+	  if (surfaces[surfind[i]]->GetMaxH() > maxh)
+	    surfaces[surfind[i]] -> SetMaxH (maxh);
+	}
+
+      solid->SetMaxH (maxh);
+    }
+
+  if (flags.NumFlagDefined ("bc"))
+    {
+      solid->GetSurfaceIndices (surfind);
+      int bc = int (flags.GetNumFlag("bc", -1));
+      for (i = 0; i < surfind.Size(); i++)
+	{
+	  if (surfaces[surfind[i]]->GetBCProperty() == -1)
+	    surfaces[surfind[i]]->SetBCProperty(bc);
+	}
+    }
+}
+
+void CSGeometry :: FindIdenticSurfaces (double eps)
+{
+  int i, j;
+  int inv;
+  int nsurf = GetNSurf();
+
+  isidenticto.SetSize(nsurf);
+  for (i = 0; i < nsurf; i++)
+    isidenticto[i] = i;
+  
+  for (i = 0; i < nsurf; i++)
+    for (j = i+1; j < nsurf; j++)
+      if (GetSurface(j) -> IsIdentic (*GetSurface(i), inv, eps))
+	{
+	  INDEX_2 i2(i, j);
+	  identicsurfaces.Set (i2, inv);
+	  isidenticto[j] = isidenticto[i];
+	  // (*testout) << "surfaces " << i2 << " are identic" << endl;
+	}
+
+  /*
+  (*testout) << "identicmap:" << endl;
+  for (i = 0; i < isidenticto.Size(); i++)
+    (*testout) << i << " -> " << isidenticto[i] << endl;
+
+  for (i = 0; i < nsurf; i++)
+    GetSurface(i)->Print (*testout);
+  */
+}
+
+
+void CSGeometry ::
+GetIndependentSurfaceIndices (const Solid * sol, 
+			      const BoxSphere<3> & box, 
+			      ARRAY<int> & locsurf) const
+{
+  int i, j;
+
+  ReducePrimitiveIterator rpi(box);
+  UnReducePrimitiveIterator urpi;
+
+  ((Solid*)sol) -> IterateSolid (rpi);
+  sol -> GetSurfaceIndices (locsurf);
+  ((Solid*)sol) -> IterateSolid (urpi);
+  
+  int cntindep = 0;
+  bool indep;
+  for (i = locsurf.Size()-1; i >= 0; i--)
+    {
+      indep = 1;
+      for (j = 0; j < i; j++)
+	{
+	  INDEX_2 i2(locsurf[i], locsurf[j]);
+	  i2.Sort();
+	  if (identicsurfaces.Used (i2))
+	    {
+	      indep = 0;
+	      break;
+	    }
+	}
+      if (!indep)
+	locsurf.Delete(i);
+    }
+
+  for (i = 0; i < locsurf.Size(); i++)
+    locsurf[i] = isidenticto[locsurf[i]];
+}
+
+
+void CSGeometry ::
+GetIndependentSurfaceIndices (const Solid * sol, 
+			      const Point<3> & p, Vec<3> & v,
+			      ARRAY<int> & locsurf) const
+{
+  Point<3> p2 = p + 1e-2 * v;
+  BoxSphere<3> box (p2, p2);
+  box.Increase (1e-3);
+  box.CalcDiamCenter();
+  GetIndependentSurfaceIndices (sol, box, locsurf);
+}
+
+
+void CSGeometry :: 
+CalcTriangleApproximation(const Box<3> & boundingbox,
+			  double detail, double facets)
+{
+  PrintMessage (1, "Calc Triangle Approximation");
+
+  FindIdenticSurfaces (1e-6);
+  
+  int i, j, k;
+  //  int nms = GetNMainSolids ();
+  int ntlo = GetNTopLevelObjects();
+
+  triapprox.SetSize (ntlo);
+  ARRAY<int> surfind;
+
+  //  cout << "bb = " << boundingbox.PMin () << " - " << boundingbox.PMax() << endl;
+
+  for (i = 0; i < ntlo; i++)
+    {
+      Solid * sol;
+      Surface * surf;
+      GetTopLevelObject (i, sol, surf);
+
+      //      ((Solid*)MainSolid (i)) -> CalcSurfaceInverse ();
+      sol -> CalcSurfaceInverse ();
+
+      TriangleApproximation * tams = new TriangleApproximation();
+      triapprox[i] = tams;
+
+      for (j = 0; j < GetNSurf(); j++)
+	{
+	  PrintMessageCR (3, "Surface ", j, "/", GetNSurf());
+	  if (surf && surf != GetSurface(j))
+	    continue;
+
+	  TriangleApproximation tas;
+	  GetSurface (j) -> GetTriangleApproximation (tas, boundingbox, facets);
+	  
+
+	  int oldnp = tams -> GetNP();
+
+	  if (!tas.GetNP())
+	    continue;
+
+	  for (k = 0; k < tas.GetNP(); k++)
+	    {
+	      Vec<3> n;
+
+	      tams -> AddPoint (tas.GetPoint(k));
+	      GetSurface(j) -> GetNormalVector (tas.GetPoint(k), n);
+	      n.Normalize();
+	      if (GetSurface(j)->Inverse()) n *= -1;
+	      tams -> AddNormal (n);
+	    }
+
+	  
+	  BoxSphere<3> surfbox;
+
+	  if (tas.GetNP())
+	    surfbox.Set (tas.GetPoint(0));
+	  for (k = 1; k < tas.GetNP(); k++)
+	    surfbox.Add (tas.GetPoint(k));
+	  surfbox.Increase (1e-6);
+	  surfbox.CalcDiamCenter();
+
+	  Solid * surflocsol = sol -> GetReducedSolid (surfbox);
+	  if (!surflocsol)
+	    continue;
+
+	  for (k = 0; k < tas.GetNT(); k++)
+	    {
+	      const TATriangle & tri = tas.GetTriangle (k);
+
+	      // check triangle
+	      BoxSphere<3> box;
+	      box.Set (tas.GetPoint (tri[0]));
+	      box.Add (tas.GetPoint (tri[1]));
+	      box.Add (tas.GetPoint (tri[2]));
+	      box.Increase (1e-6);
+	      box.CalcDiamCenter();
+
+
+	      Solid * locsol = surflocsol -> GetReducedSolid (box);
+
+	      if (locsol)
+		{
+		  TATriangle tria(j, 
+				  tri[0] + oldnp,
+				  tri[1] + oldnp,
+				  tri[2] + oldnp);
+		  //		  tams->AddTriangle (tria);
+		  RefineTriangleApprox (locsol, j, box, detail, 
+					tria, *tams);
+		  delete locsol;
+		}
+	    }
+
+	}
+
+      tams->RemoveUnusedPoints ();
+      PrintMessage (2, "Object ", i, " has ", tams->GetNT(), " triangles");
+    }
+
+  Change();
+}
+
+
+
+void CSGeometry ::
+RefineTriangleApprox (Solid * locsol, 
+		      int surfind,
+		      const BoxSphere<3> & box, 
+		      double detail,
+		      const TATriangle & tria, 
+		      TriangleApproximation & tams)
+{
+  int i, j;
+
+  //  ARRAY<int> lsurfi;
+  int pinds[6];
+
+  static ARRAY<int> surfused;
+  surfused.SetSize(GetNSurf());
+
+  
+  ReducePrimitiveIterator rpi(box);
+  UnReducePrimitiveIterator urpi;
+
+
+  locsol -> IterateSolid (rpi);
+  //  locsol -> GetSurfaceIndices (lsurfi);
+
+
+  IndexSet iset(GetNSurf());
+  locsol -> GetSurfaceIndices (iset);
+  const ARRAY<int> & lsurfi = iset.Array();
+
+  locsol -> IterateSolid (urpi);
+
+
+  int surfii = -1;
+  for (i = 0; i < lsurfi.Size(); i++)
+    if (lsurfi[i] == surfind)
+      {
+	surfii = i;
+	break;
+      }
+
+  if (surfii == -1) 
+    return;
+
+
+  int cntindep = 0;
+
+  for (i = 0; i < lsurfi.Size(); i++)
+    {
+      int linkto = isidenticto[lsurfi[i]];
+      surfused[linkto] = 0;
+    }
+
+  for (i = 0; i < lsurfi.Size(); i++)
+    {
+      int linkto = isidenticto[lsurfi[i]];
+      if (!surfused[linkto])
+	{
+	  surfused[linkto] = 1;
+	  cntindep++;
+	}
+    }
+
+  int inverse = surfaces[surfind]->Inverse();
+
+  if (cntindep == 1)
+    {
+      //      (*testout) << "add trig of surf " << surfind << endl;
+      if (cntindep > 1) (*testout) << "not unique" << endl;
+      tams.AddTriangle (tria);
+      return;
+    }
+
+  if (cntindep == 2)
+    {
+      // just 2 surfaces:
+      // if smooth, project inner points to edge and finish
+
+      int otherind;
+
+      for (i = 0; i < lsurfi.Size(); i++)
+	{
+	  INDEX_2 i2 (lsurfi[i], surfind);
+	  i2.Sort();
+	  
+	  if (i != surfii && !identicsurfaces.Used(i2))
+	    otherind = lsurfi[i];
+	}
+
+      double kappa = GetSurface(otherind)->
+	MaxCurvature (); // Loc (box.Center(), box.Diam());
+
+      if (kappa * box.Diam() < 0.1)
+	{
+	  int pnums[6];
+	  static int between[3][3] =
+	  { { 1, 2, 3 },
+	    { 0, 2, 4 },
+	    { 0, 1, 5 } };
+	  int onsurface[3];
+
+	  for (j = 0; j < 3; j++)
+	    {
+	      int pi = tria[j];
+	      pnums[j] = pi;
+	      onsurface[j] =  
+		!locsol->IsStrictIn (tams.GetPoint (pi), 1e-6) &&
+		locsol->IsIn (tams.GetPoint (pi), 1e-6);
+	    }
+	  
+	  for (j = 0; j < 3; j++)
+	    {
+	      int lpi1 = between[j][0];
+	      int lpi2 = between[j][1];
+	      int lpin = between[j][2];
+	      if (onsurface[lpi1] == onsurface[lpi2])
+		pnums[lpin] = -1;
+	      else
+		{
+		  const Point<3> & p1 = tams.GetPoint (pnums[lpi1]);
+		  const Point<3> & p2 = tams.GetPoint (pnums[lpi2]);
+		  double f1 = GetSurface(otherind)->CalcFunctionValue (p1);
+		  double f2 = GetSurface(otherind)->CalcFunctionValue (p2);
+		  //		  Point<3> pn = Center (p1, p2);
+
+		  Point<3> pn;
+		  if ( fabs (f1-f2) > 1e-20 )
+		    {
+		      double l2 = -f1/(f2-f1);
+		      double l1 = f2/(f2-f1);
+		      pn = Point<3>(l1 * p1(0) + l2 * p2(0),
+				    l1 * p1(1) + l2 * p2(1),
+				    l1 * p1(2) + l2 * p2(2));
+		    }
+		  else
+		    {
+		      pn = p1;
+		    }
+
+		  pnums[lpin] = tams.AddPoint (pn);
+
+		  GetSurface (surfind)->Project (pn);
+		  
+		  Vec<3> n;
+		  GetSurface (surfind)->GetNormalVector (pn, n);
+		  if (inverse) n *= -1;
+		  tams.AddNormal(n);
+		}
+	    }
+	  
+	  int vcase = 0;
+	  if (onsurface[0]) vcase++;
+	  if (onsurface[1]) vcase+=2;
+	  if (onsurface[2]) vcase+=4;
+	  
+	  static int trias[8][6] =
+	  { { 0, 0, 0,   0, 0, 0 },
+	    { 1, 6, 5,   0, 0, 0 },
+	    { 2, 4, 6,   0, 0, 0 },
+	    { 1, 2, 4,   1, 4, 5 },
+	    { 3, 5, 4,   0, 0, 0 },
+	    { 1, 6, 4,   1, 4, 3 },
+	    { 2, 3, 6,   3, 5, 6 },
+	    { 1, 2, 3,   0, 0, 0 } };
+	  static int ntrias[4] =
+	  { 0, 1, 2, 1 };
+
+	  int nvis = 0;
+	  for (j = 0; j < 3; j++)
+	    if (onsurface[j])
+	      nvis++;
+
+	  for (j = 0; j < ntrias[nvis]; j++)
+	    {
+	      TATriangle ntria(tria.SurfaceIndex(),
+			       pnums[trias[vcase][3*j]-1],
+			       pnums[trias[vcase][3*j+1]-1],
+			       pnums[trias[vcase][3*j+2]-1]);
+	      tams.AddTriangle (ntria);
+	    }
+
+	  /* saturn changes:
+
+	  int pvis[3];
+	  for (j = 0; j < 3; j++)
+	    pvis[j] = !locsol->IsStrictIn (tams.GetPoint (j+1), 1e-6) &&
+	      locsol->IsIn (tams.GetPoint (j+1), 1e-6);
+	  
+	  int newpi[3];
+	  for (j = 0; j < 3; j++)
+	    {
+	      int pi1 = j;
+	      int pi2 = (j+1) % 3;
+	      int pic = j;
+
+	      if (pvis[pi1] != pvis[pi2])
+		{
+		  Point<3> hp = Center (tams.GetPoint (tria.PNum (pi1+1)),
+				       tams.GetPoint (tria.PNum (pi2+1)));
+
+		  newpi[j] = tams.AddPoint (hp);
+		  Vec<3> n = tams.GetNormal (pi1);
+		  tams.AddNormal (n);
+		}
+	      else
+		newpi[j] = 0;
+	    }
+
+	  int nvis = 0;
+	  for (j = 0; j <= nvis; j++)
+	    if (pvis[j]) nvis++;
+
+	  int si = tria.SurfaceIndex();
+	  switch (nvis)
+	    {
+	    case 0:
+	      break;
+	    case 1:
+	      {
+		int visj;
+		for (j = 0; j < 3; j++)
+		  if (pvis[j]) visj = j;
+		int pivis = tria.PNum (visj+1);
+		int pic1 = newpi[(visj+1)%3];
+		int pic2 = newpi[(visj+2)%3];
+		
+		cout << pivis << "," << pic1 << "," << pic2 << endl;
+		
+		tams.AddTriangle (TATriangle (si, pivis, pic1,pic2));
+		break;
+	      }
+	    case 2:
+	      {
+		int nvisj;
+		for (j = 0; j < 3; j++)
+		  if (!pvis[j]) nvisj = j;
+
+		int pivis1 = tria.PNum ((nvisj+1)%3+1);
+		int pivis2 = tria.PNum ((nvisj+2)%3+1);
+		int pic1 = newpi[nvisj];
+		int pic2 = newpi[(nvisj+2)%3];
+
+		tams.AddTriangle (TATriangle (si, pivis1, pic1,pic2));
+		tams.AddTriangle (TATriangle (si, pivis1, pic1,pivis2));
+		break;
+	      }
+	    case 3:
+	      {
+		tams.AddTriangle (tria);
+		break;
+	      }
+	    }
+
+	  */
+	  return;
+	}
+    }
+
+  // bisection
+  if (box.Diam() < detail)
+    return;
+  
+  for (i = 0; i < 3; i++)
+    pinds[i] = tria[i];
+  
+  static int between[3][3] =
+  { { 0, 1, 5 },
+    { 0, 2, 4 },
+    { 1, 2, 3 } };
+  
+  for (i = 0; i < 3; i++)
+    {
+      int pi1 = tria[between[i][0]];
+
+      Point<3> newp = Center (tams.GetPoint (tria[between[i][0]]),
+			      tams.GetPoint (tria[between[i][1]]));
+      Vec<3> n;
+      
+      GetSurface(surfind)->Project (newp);
+      GetSurface(surfind)->GetNormalVector (newp, n);
+      
+      pinds[between[i][2]] = tams.AddPoint (newp);
+      if (inverse) n *= -1;
+      tams.AddNormal (n);
+    }
+  
+  static int trias[4][4] =
+  { { 0, 5, 4 },
+    { 5, 1, 3 },
+    { 4, 3, 2 },
+    { 3, 4, 5 } };
+  
+  for (i = 0; i < 4; i++)
+    {
+      TATriangle ntri(surfind,
+		      pinds[trias[i][0]],
+		      pinds[trias[i][1]],
+		      pinds[trias[i][2]]);
+
+      // check triangle
+      BoxSphere<3> nbox;
+      nbox.Set (tams.GetPoint (ntri[0]));
+      nbox.Add (tams.GetPoint (ntri[1]));
+      nbox.Add (tams.GetPoint (ntri[2]));
+      nbox.Increase (1e-6);
+      nbox.CalcDiamCenter();
+
+      Solid * nsol = locsol -> GetReducedSolid (nbox);
+
+      if (nsol)
+	{
+	  RefineTriangleApprox (nsol, surfind, nbox, 
+				detail, ntri, tams);
+	  
+	  delete nsol;
+	}
+    }
+}
+
+
+
+
+
+class ClearVisitedIt : public SolidIterator
+{
+public:
+  ClearVisitedIt ();
+  ~ClearVisitedIt ();
+  virtual void Do (Solid * sol);
+};
+
+ClearVisitedIt :: ClearVisitedIt ()
+{
+  ;
+}
+ClearVisitedIt :: ~ClearVisitedIt ()
+{
+  ;
+}
+
+void ClearVisitedIt :: Do (Solid * sol)
+{
+  sol -> visited = 0;
+}
+
+
+
+void CSGeometry :: 
+IterateAllSolids (SolidIterator & it, int only_once)
+{
+  int i;
+
+  if (only_once)
+    {
+      ClearVisitedIt clit;
+      for (i = 0; i < solids.Size(); i++)
+	solids[i] -> IterateSolid (clit, 0);
+      
+    }
+
+  for (i = 0; i < solids.Size(); i++)
+    solids[i] -> IterateSolid (it, only_once);
+}
+
+
+
+/*
+const Box<3> & CSGeometry :: BoundingBox () const
+{
+  return boundingbox;
+}
+*/
+
+void CSGeometry :: SetBoundingBox (const Box<3> & abox)
+{
+  boundingbox = abox;
+}
+
+double CSGeometry ::  MaxSize () const
+{
+  double maxs, mins;
+  maxs = max3 (boundingbox.PMax()(0), 
+	       boundingbox.PMax()(1), 
+	       boundingbox.PMax()(2));
+  mins = min3 (boundingbox.PMin()(0), 
+	       boundingbox.PMin()(1), 
+	       boundingbox.PMin()(2));
+  return max2 (maxs, -mins) * 1.1;
+}
+}
diff --git a/Netgen/libsrc/csg/csgeom.hpp b/Netgen/libsrc/csg/csgeom.hpp
new file mode 100644
index 0000000000..4a8e32b28f
--- /dev/null
+++ b/Netgen/libsrc/csg/csgeom.hpp
@@ -0,0 +1,241 @@
+#ifndef FILE_CSGEOM
+#define FILE_CSGEOM
+
+/**************************************************************************/
+/* File:   csgeom.hh                                                      */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   27. Nov. 97                                                    */
+/**************************************************************************/
+
+/**
+  Constructive Solid Geometry
+*/
+
+
+class TriangleApproximation;
+class TATriangle;
+
+
+/**
+   A top level object is an entity to be meshed.
+   I can be either a solid, or one surface patch of a solid.
+ */
+class TopLevelObject
+{
+  Solid * solid;
+  Surface * surface;
+
+  double red, blue, green;
+  bool visible, transp;
+  double maxh;
+  string material;
+  int layer;
+  int bc;     // for surface patches, only
+public:
+  TopLevelObject (Solid * asolid,
+		  Surface * asurface = NULL);
+
+  const Solid * GetSolid() const { return solid; }
+  Solid * GetSolid() { return solid; }
+
+  const Surface * GetSurface () const { return surface; }
+  Surface  * GetSurface () { return surface; }
+
+  void GetData (ostream & ost);
+  void SetData (istream & ist);
+
+  void SetMaxH (double amaxh) { maxh = amaxh; } 
+  double GetMaxH () const { return maxh; }
+
+  void SetRGB (double ared, double agreen, double ablue)
+  {
+    red = ared;
+    green = agreen;
+    blue = ablue;
+  }
+
+  double GetRed () const { return red; }
+  double GetGreen () const { return green; }
+  double GetBlue () const { return blue; }
+
+  void SetTransparent (bool atransp) 
+  { transp = atransp; }
+  bool GetTransparent () const { return transp; }
+
+  void SetVisible (bool avisible)
+  { visible = avisible; }
+  bool GetVisible () const { return visible; }
+
+  const string GetMaterial () const { return material; }
+  void SetMaterial (const string & mat) { material = mat; }
+
+  int GetLayer () const { return layer; }
+  void SetLayer (int alayer) { layer = alayer; }
+
+  void SetBCProp (int abc) { bc = abc; }
+  int GetBCProp () const { return bc; }
+};
+
+
+/**
+   CSGeometry has the whole geometric information
+ */
+class CSGeometry
+{
+private:
+  /// all surfaces
+  SYMBOLTABLE<Surface*> surfaces;
+
+  /// all named solids
+  SYMBOLTABLE<Solid*> solids;
+
+  /// all top level objects: solids and surfaces
+  ARRAY<TopLevelObject*> toplevelobjects;
+
+  /// additional points specified by user
+  ARRAY<Point<3> > userpoints;
+
+  /// triangular approximation of top level objects
+  ARRAY<TriangleApproximation*> triapprox;
+
+  /// increment, if geometry is changed
+  static int changeval;
+  
+  /// bounding box of geometry
+  Box<3> boundingbox;
+
+  /// identic surfaces are stored by pair of indizes, val = inverse
+  INDEX_2_HASHTABLE<int> identicsurfaces;
+  ARRAY<int> isidenticto;
+
+  /// identification of boundaries (periodic, thin domains, ...)
+
+
+
+  /// filename of inputfile
+  string filename;
+
+public:
+  CSGeometry ();
+  CSGeometry (const string & afilename);
+  ~CSGeometry ();
+
+  void Clean ();
+
+  void Save (ostream & ost);
+  void Load (istream & ist);
+
+  int GetChangeVal() { return changeval; }
+  void Change() { changeval++; }
+
+  void AddSurface (Surface * surf);
+  void AddSurface (char * name, Surface * surf);
+
+  int GetNSurf () const { return surfaces.Size(); }
+  const Surface * GetSurface (const char * name) const;
+  const Surface * GetSurface (int i) const;
+
+  void SetSolid (const char * name, Solid * sol);
+  const Solid * GetSolid (const char * name) const;
+  const Solid * GetSolid (const string & name) const;
+  int GetNSolids () const { return solids.Size(); }
+  const Solid * GetSolid (int i) { return solids[i]; }
+  const SYMBOLTABLE<Solid*> & GetSolids () const { return solids; }
+
+
+  void SetFlags (const char * solidname, const Flags & flags);
+
+  /*
+  ///
+  void FindMainSolids ();
+  ///
+  int GetNMainSolids () const
+    { return mainsolids.Size(); }
+  ///
+  const Solid* MainSolid(int i) const
+    { return mainsolids.Get(i); }
+  */
+
+
+  int GetNTopLevelObjects () const { return toplevelobjects.Size(); }
+  int SetTopLevelObject (Solid * sol, Surface * surf = NULL);
+  void GetTopLevelObject (int nr, Solid *& sol, Surface *& surf);
+  void GetTopLevelObject (int nr, const Solid *& sol, const Surface *& surf) const;
+  TopLevelObject * GetTopLevelObject (const Solid * sol, const Surface * surf = NULL);
+  TopLevelObject * GetTopLevelObject (int nr)
+  { return toplevelobjects[nr]; }
+  const TopLevelObject * GetTopLevelObject (int nr) const
+  { return toplevelobjects[nr]; }
+  void RemoveTopLevelObject (Solid * sol, Surface * surf = NULL); 
+
+
+  void AddUserPoint (const Point<3> & p)
+  { userpoints.Append (p); }
+  int GetNUserPoints () const
+  { return userpoints.Size(); }
+  const Point<3> & GetUserPoint (int nr) const
+  { return userpoints[nr]; }
+  
+
+  // quick implementations:
+  ARRAY<SingularEdge*> singedges;
+  ARRAY<SingularPoint*> singpoints;
+  ARRAY<Identification*> identifications;
+
+  int GetNIdentifications () { return identifications.Size(); }
+  void AddIdentification (Identification * ident);
+
+
+  ///
+  void CalcTriangleApproximation(const Box<3> & boundingbox,
+				 double detail, double facets);
+
+  ///
+  void FindIdenticSurfaces (double eps);
+  ///
+  void GetIndependentSurfaceIndices (const Solid * sol, 
+				     const BoxSphere<3> & box, 
+				     ARRAY<int> & locsurf) const;
+  ///
+  void GetIndependentSurfaceIndices (const Solid * sol, 
+				     const Point<3> & p, Vec<3> & v,
+				     ARRAY<int> & locsurf) const;
+  ///
+  int GetSurfaceClassRepresentant (int si) const
+    { return isidenticto[si]; }
+  ///
+  const TriangleApproximation * GetTriApprox (int msnr)
+  {
+    if (msnr < triapprox.Size())
+      return triapprox[msnr];
+    return 0;
+  }
+  
+
+  void IterateAllSolids (SolidIterator & it, int only_once = 0);
+
+  void RefineTriangleApprox (Solid * locsol, 
+			     int surfind,
+			     const BoxSphere<3> & box, 
+			     double detail,
+			     const TATriangle & tria, 
+			     TriangleApproximation & tams);
+
+  const Box<3> & BoundingBox () const { return boundingbox; }
+  void SetBoundingBox (const Box<3> & abox);
+
+  double MaxSize () const;
+
+
+
+  class BCModification {
+  public:
+    int si;
+    int tlonr;
+    int bcnr;
+  };
+  ARRAY<BCModification> bcmodifications;
+
+};
+#endif
+
diff --git a/Netgen/libsrc/csg/csgparser.cpp b/Netgen/libsrc/csg/csgparser.cpp
new file mode 100644
index 0000000000..9372d5675d
--- /dev/null
+++ b/Netgen/libsrc/csg/csgparser.cpp
@@ -0,0 +1,1186 @@
+#include <mystdlib.h>
+#include <myadt.hpp>
+
+#include <linalg.hpp>
+#include <csg.hpp>
+
+
+namespace netgen
+{
+  using namespace netgen;
+
+
+  enum TOKEN_TYPE
+    { 
+      TOK_MINUS = '-', TOK_LP = '(', OK_RP = ')', TOK_LSP = '[', TOK_RSP = ']',
+      TOK_EQU = '=', TOK_COMMA = ',', TOK_SEMICOLON = ';',
+      TOK_NUM = 100, TOK_STRING, TOK_NAMED_SOLID, TOK_PRIMITIVE, 
+      TOK_OR, TOK_AND, TOK_NOT, 
+      TOK_SINGULAR, TOK_EDGE, TOK_POINT, TOK_IDENTIFY, TOK_CLOSESURFACES,
+      TOK_CLOSEEDGES, TOK_PERIODIC,
+      TOK_SOLID, TOK_RECO, TOK_TLO, TOK_BOUNDINGBOX, TOK_BOUNDARYCONDITION,
+      TOK_END };
+
+  struct kwstruct
+  {
+    TOKEN_TYPE kw; 
+    char * name;
+  };
+
+  static kwstruct defkw[] =
+    {
+      { TOK_RECO,    "algebraic3d" },
+      { TOK_SOLID,   "solid" },
+      { TOK_TLO,     "tlo" },
+      { TOK_BOUNDINGBOX, "boundingbox" },
+      { TOK_OR,      "or" },
+      { TOK_AND,     "and" },
+      { TOK_NOT,     "not" },
+      { TOK_SINGULAR, "singular" },
+      { TOK_EDGE,     "edge" },
+      { TOK_POINT,    "point" },
+      { TOK_IDENTIFY, "identify" },
+      { TOK_CLOSESURFACES, "closesurfaces" },
+      { TOK_CLOSEEDGES, "closeedges" },
+      { TOK_PERIODIC,  "periodic" },
+      { TOK_BOUNDARYCONDITION, "boundarycondition" },
+      { TOKEN_TYPE(0) }
+    };
+
+  enum PRIMITIVE_TYPE
+    { TOK_SPHERE = 1, TOK_CYLINDER, TOK_PLANE, TOK_ELLIPTICCYLINDER, 
+      TOK_ELLIPSOID,
+      TOK_CONE, TOK_TUBE,
+      TOK_GENCYL, TOK_ORTHOBRICK, TOK_POLYHEDRON, TOK_EXTRUSION, TOK_REVOLUTION,
+      TOK_TRANSLATE, TOK_MULTITRANSLATE, TOK_ROTATE, TOK_MULTIROTATE
+    };
+
+  struct primstruct
+  {
+    PRIMITIVE_TYPE kw; 
+    char * name;
+  };
+
+  static primstruct defprim[] =
+    {
+      { TOK_PLANE,     "plane" },
+      { TOK_SPHERE,    "sphere" },
+      { TOK_CYLINDER,  "cylinder" },
+      { TOK_CONE,      "cone" },
+      { TOK_ELLIPTICCYLINDER, "ellipticcylinder" },
+      { TOK_ELLIPSOID, "ellipsoid" },
+      { TOK_TUBE,      "tube" },
+      { TOK_GENCYL,    "gencyl" },
+      { TOK_ORTHOBRICK, "orthobrick" },
+      { TOK_POLYHEDRON, "polyhedron" },
+      { TOK_EXTRUSION,  "extrusion" },
+      { TOK_REVOLUTION, "revolution" },
+
+      { TOK_TRANSLATE, "translate" },
+      { TOK_MULTITRANSLATE, "multitranslate" },
+      { TOK_ROTATE,   "rotate" },
+      { TOK_MULTIROTATE, "multirotate" },
+      { PRIMITIVE_TYPE(0) }
+    };
+
+
+
+  static CSGeometry * geom;
+
+  /*
+%token <solidtype> TOK_SPHERE TOK_CYLINDER TOK_CONE TOK_PLAIN TOK_TUBE TOK_GENCYL TOK_ORTHOBRICK TOK_POLYHEDRON TOK_REVOLUTION
+%left <solidtype> TOK_OR TOK_AND TOK_NOT
+%token <solidtype> TOK_TRANSLATE TOK_MULTITRANSLATE TOK_ROTATE TOK_MULTIROTATE
+%type <solidtype> solid solidprimitive 
+%type <void> splinesegmentlist splinesegment readbspline bsplinepointlist
+%type <chptr> anyident
+%token TOK_SINGULAR TOK_EDGE TOK_POINT
+%token TOK_IDENTIFY TOK_CLOSESURFACES TOK_CLOSEEDGES TOK_PERIODIC
+%token TOK_BOUNDARYCONDITION
+%type <void> polyhedronpoints polyhedronfaces polyhedronpoint polyhedronface
+%type <void> revolutionpoints revolutionpoint
+  */
+
+
+  
+  class CSGScanner
+  {
+    TOKEN_TYPE token;
+    PRIMITIVE_TYPE prim_token;
+    double num_value;
+    string string_value;
+    
+    int linenum;
+    istream * scanin;
+
+  public:
+
+    CSGScanner (istream & ascanin);
+
+    TOKEN_TYPE GetToken() const
+    { return token; }
+
+    double GetNumValue() const
+    { return num_value; }
+
+    const string & GetStringValue() const
+    { return string_value; }
+
+    char GetCharValue() const
+    { return string_value[0]; }
+
+    PRIMITIVE_TYPE GetPrimitiveToken() const
+    { return prim_token; }
+  
+    void ReadNext();
+    void Error (const string & err);
+  };
+
+
+  CSGScanner :: CSGScanner (istream & ascanin)
+  {
+    scanin = &ascanin;
+    token = TOK_END;
+    num_value = 0;
+    linenum = 1;
+  }
+
+
+  void CSGScanner :: ReadNext ()
+  {
+    char ch;
+  
+
+    // whitespaces ueberspringen
+    do
+      { 
+	scanin->get(ch);
+
+	if (ch == '\n') 
+	  linenum++;
+
+	// end of file reached
+	if (scanin->eof())
+	  {
+	    token = TOK_END;
+	    return;
+	  }
+
+	// skip comment line
+	if (ch == '#')
+	  {
+	    while (ch != '\n')
+	      {
+		scanin->get(ch);
+		if (scanin->eof())
+		  {
+		    token = TOK_END;
+		    return;
+		  }
+	      }
+	    linenum++;
+	  }	
+      }
+    while (isspace(ch));
+  
+    switch (ch)
+      {
+      case '(': case ')': 
+      case '[': case ']': 
+      case '-':
+      case '=': case ',': case ';':
+	{
+	  token = TOKEN_TYPE (ch);
+	  break;
+	}
+  
+      default:
+	{
+	  if (isdigit (ch) || ch == '.')
+	    {
+	      scanin->putback (ch);
+	      (*scanin) >> num_value;
+	      token = TOK_NUM;
+	      return;
+	    }
+
+	  if (isalpha (ch))
+	    {
+	      string_value = string (1, ch);
+	      scanin->get(ch);
+	      while (isalnum(ch))
+		{
+		  string_value += ch;
+		  scanin->get(ch);
+		}
+	      scanin->putback (ch);
+	    }
+	  /*
+	  (*scanin).putback (ch);
+	  (*scanin) >> string_value;
+	  */
+	  int nr = 0;
+	  while (defkw[nr].kw)
+	    {
+	      if (string_value == defkw[nr].name)
+		{
+		  token = defkw[nr].kw;
+		  return;
+		}
+	      nr++;
+	    }
+
+	  nr = 0;
+	  while (defprim[nr].kw)
+	    {
+	      if (string_value == defprim[nr].name)
+		{
+		  token = TOK_PRIMITIVE;
+		  prim_token = defprim[nr].kw;
+		  return;
+		}
+	      nr++;
+	    }
+
+	  token = TOK_STRING;
+	}
+      }
+  }
+
+  void CSGScanner :: Error (const string & err)
+  {
+    stringstream errstr;
+    errstr << "Parsing error in line " << linenum << ": " << endl << err << endl;
+    throw string(errstr.str());
+  }
+
+
+  /*
+    Solid = Term { OR Term }
+    Term  = Primary { AND Primary }
+    Primary = PRIM | IDENT | ( Solid ) | NOT Primary
+   */
+
+  void ParseChar (CSGScanner & scan, char ch)
+  {
+    char str[2];
+    str[0] = ch;
+    str[1] = 0;
+    if (scan.GetToken() != TOKEN_TYPE(ch)) 
+      scan.Error (string ("token '") + string(str) + string("' expected"));
+    scan.ReadNext();
+  }
+  
+  double ParseNumber(CSGScanner & scan)
+  {
+    if (scan.GetToken() == '-')
+      {
+	scan.ReadNext();
+	return -ParseNumber (scan);
+      }
+    if (scan.GetToken() != TOK_NUM) scan.Error ("number expected");
+    double val = scan.GetNumValue();
+    scan.ReadNext();
+    return val;
+  }
+
+
+  Solid * ParseSolid (CSGScanner & scan);
+  Solid * ParseTerm (CSGScanner & scan);
+  Solid * ParsePrimary (CSGScanner & scan);
+ 
+
+  Solid * ParsePrimary (CSGScanner & scan)
+  {
+    if (scan.GetToken() == TOK_PRIMITIVE)
+      {
+	//	cout << "prim token = " << int (scan.GetPrimitiveToken()) << endl;
+	switch (scan.GetPrimitiveToken())
+	  {
+	  case TOK_PLANE:
+	    {
+	      Point<3> p;
+	      Vec<3> v;
+	      
+	      scan.ReadNext();
+	      
+	      ParseChar (scan, '(');
+	      p(0) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      p(1) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      p(2) = ParseNumber (scan);
+	      ParseChar (scan, ';');
+	      v(0) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      v(1) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      v(2) = ParseNumber (scan);
+	      ParseChar (scan, ')');
+
+	      // cout << "define plane, p = " << p << "; v = " << v << endl;
+	      OneSurfacePrimitive * surf = new Plane ( p, v );
+
+	      geom->AddSurface (surf);
+	      surf->SetSurfaceId (0, geom->GetNSurf()-1);
+
+	      return new Solid (surf);
+	    }
+	  case TOK_CYLINDER:
+	    {
+	      Point<3> pa, pb;
+	      double r;
+	      
+	      scan.ReadNext();
+	      
+	      ParseChar (scan, '(');
+	      pa(0) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      pa(1) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      pa(2) = ParseNumber (scan);
+	      ParseChar (scan, ';');
+	      pb(0) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      pb(1) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      pb(2) = ParseNumber (scan);
+	      ParseChar (scan, ';');
+	      r = ParseNumber (scan);
+	      ParseChar (scan, ')');
+	      
+	      OneSurfacePrimitive * surf = new Cylinder ( pa, pb, r );
+
+	      geom->AddSurface (surf);
+	      surf->SetSurfaceId (0, geom->GetNSurf()-1);
+
+	      return new Solid (surf);
+	    }
+
+	  case TOK_ELLIPTICCYLINDER:
+	    {
+	      Point<3> pa;
+	      Vec<3> vl, vs;
+	      
+	      scan.ReadNext();
+	      
+	      ParseChar (scan, '(');
+	      pa(0) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      pa(1) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      pa(2) = ParseNumber (scan);
+	      ParseChar (scan, ';');
+
+	      vl(0) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      vl(1) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      vl(2) = ParseNumber (scan);
+	      ParseChar (scan, ';');
+
+	      vs(0) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      vs(1) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      vs(2) = ParseNumber (scan);
+	      ParseChar (scan, ')');
+	      
+	      OneSurfacePrimitive * surf = new EllipticCylinder ( pa, vl, vs);
+
+	      geom->AddSurface (surf);
+	      surf->SetSurfaceId (0, geom->GetNSurf()-1);
+
+	      return new Solid (surf);
+	    }
+
+
+	  case TOK_ELLIPSOID:
+	    {
+	      Point<3> pa;
+	      Vec<3> v1, v2, v3;
+	      
+	      scan.ReadNext();
+	      
+	      ParseChar (scan, '(');
+	      pa(0) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      pa(1) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      pa(2) = ParseNumber (scan);
+	      ParseChar (scan, ';');
+
+	      v1(0) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      v1(1) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      v1(2) = ParseNumber (scan);
+	      ParseChar (scan, ';');
+
+	      v2(0) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      v2(1) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      v2(2) = ParseNumber (scan);
+	      ParseChar (scan, ';');
+
+	      v3(0) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      v3(1) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      v3(2) = ParseNumber (scan);
+	      ParseChar (scan, ')');
+	      
+	      OneSurfacePrimitive * surf = new Ellipsoid ( pa, v1, v2, v3);
+
+	      geom->AddSurface (surf);
+	      surf->SetSurfaceId (0, geom->GetNSurf()-1);
+
+	      return new Solid (surf);
+	    }
+
+
+	  case TOK_CONE:
+	    {
+	      Point<3> pa, pb;
+	      double ra, rb;
+	      
+	      scan.ReadNext();
+	      
+	      ParseChar (scan, '(');
+	      pa(0) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      pa(1) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      pa(2) = ParseNumber (scan);
+	      ParseChar (scan, ';');
+	      ra = ParseNumber (scan);
+	      ParseChar (scan, ';');
+	      pb(0) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      pb(1) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      pb(2) = ParseNumber (scan);
+	      ParseChar (scan, ';');
+	      rb = ParseNumber (scan);
+	      ParseChar (scan, ')');
+	      
+	      OneSurfacePrimitive * surf = new Cone ( pa, pb, ra, rb);
+
+	      geom->AddSurface (surf);
+	      surf->SetSurfaceId (0, geom->GetNSurf()-1);
+
+	      return new Solid (surf);
+	    }
+
+
+
+
+	  case TOK_SPHERE:
+	    {
+	      Point<3> p;
+	      double r;
+	      
+	      scan.ReadNext();
+	      
+	      ParseChar (scan, '(');
+	      p(0) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      p(1) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      p(2) = ParseNumber (scan);
+	      ParseChar (scan, ';');
+	      r = ParseNumber (scan);
+	      ParseChar (scan, ')');
+	      
+	      // cout << "define sphere, c = " << p << ", rad = " << r << endl;
+	      OneSurfacePrimitive * surf = new Sphere ( p, r );
+
+	      geom->AddSurface (surf);
+	      surf->SetSurfaceId (0, geom->GetNSurf()-1);
+
+	      return new Solid (surf);
+	    }
+
+	  case TOK_ORTHOBRICK:
+	    {
+	      Point<3> pa, pb;
+	      
+	      scan.ReadNext();
+	      
+	      ParseChar (scan, '(');
+	      pa(0) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      pa(1) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      pa(2) = ParseNumber (scan);
+	      ParseChar (scan, ';');
+	      pb(0) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      pb(1) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      pb(2) = ParseNumber (scan);
+	      ParseChar (scan, ')');
+	      
+	      // cout << "define orthobrick, p1 = " << pa << "; p2 = " << pb << endl;
+
+	      Primitive * nprim = new OrthoBrick (pa, pb);
+	      
+	      for (int j = 0; j < nprim->GetNSurfaces(); j++)
+		{
+		  geom->AddSurface (&nprim->GetSurface(j));
+		  nprim->SetSurfaceId (j, geom->GetNSurf()-1);
+		}
+	      return new Solid (nprim);
+	    } 
+
+
+	    
+
+	  case TOK_POLYHEDRON:
+	    {
+	      // Added by Dalibor Lukas, October 15, 2003
+
+	      Point<3> p;
+	      int pi1, pi2, pi3, pi4;
+	      
+	      scan.ReadNext();
+	      ParseChar (scan, '(');
+	      
+	      Polyhedra * polyhedron = new Polyhedra;
+
+	      // scanning the points
+	      while (1)
+		{
+		  p(0) = ParseNumber (scan);
+		  ParseChar (scan, ',');
+		  p(1) = ParseNumber (scan);
+		  ParseChar (scan, ',');
+		  p(2) = ParseNumber (scan);
+		  ParseChar (scan, ';');
+
+		  // cout << "point = " << p << endl;
+
+		  polyhedron->AddPoint(p);
+
+		  if (scan.GetToken() == ';')
+		    {
+		      scan.ReadNext();
+		      break;
+		    }
+		}
+
+	      // scanning the faces
+	      while (1)
+		{
+		  pi1 = (int) (ParseNumber (scan));
+		  ParseChar (scan, ',');
+		  pi2 = (int) (ParseNumber (scan));
+		  ParseChar (scan, ',');
+		  pi3 = (int) (ParseNumber (scan));
+
+		  polyhedron->AddFace(pi1-1,pi2-1,pi3-1);
+
+		  if (scan.GetToken() == TOK_COMMA)
+		    {
+		      ParseChar (scan, ',');
+		      pi4 = (int) (ParseNumber (scan));
+		      polyhedron->AddFace(pi1-1,pi3-1,pi4-1);
+		    }
+
+		  if (scan.GetToken() == ')')
+		    {
+		      scan.ReadNext();
+		      break;
+		    }
+		  scan.ReadNext();
+		}
+	      
+	      for (int j = 0; j < polyhedron->GetNSurfaces(); j++)
+		{
+		  geom->AddSurface (&polyhedron->GetSurface(j));
+		  polyhedron->SetSurfaceId (j, geom->GetNSurf()-1);
+		}
+
+	      return new Solid (polyhedron);
+	    }
+
+
+	  case TOK_EXTRUSION:
+	    {
+	      Point<3> p0;
+	      Vec<3> ex, ey;
+	      ARRAY<Point<2> > points;
+
+	      scan.ReadNext();
+	      
+	      ParseChar (scan, '(');
+	      p0(0) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      p0(1) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      p0(2) = ParseNumber (scan);
+	      ParseChar (scan, ';');
+
+	      ex(0) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      ex(1) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      ex(2) = ParseNumber (scan);
+	      ParseChar (scan, ';');
+
+	      ey(0) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      ey(1) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      ey(2) = ParseNumber (scan);
+	      ParseChar (scan, ';');
+
+	      cout << "p0 = " << p0 << endl;
+
+	      int npseg = 0;
+	      int nseg = 0;
+	      while (1)
+		{
+		  Point<2> p1, p2, p3;
+
+		  p1(0) = ParseNumber(scan);
+		  ParseChar (scan, ',');
+		  p1(1) = ParseNumber(scan);
+		  points.Append (p1);
+		  if (scan.GetToken() == ')')
+		    {
+		      scan.ReadNext();
+		      break;
+		    }
+		  scan.ReadNext();
+		}
+
+
+	      /*
+	      while (1)
+		{
+		  Point<2> p1, p2, p3;
+		  
+		  p3 = p2;
+		  p2 = p1;
+		  p1(0) = ParseNumber(scan);
+		  ParseChar (scan, ',');
+		  p1(1) = ParseNumber(scan);
+		  npseg++;
+		  
+		  cout << "p1 = " << p1 << endl;
+
+		  if (scan.GetToken() == ';' || scan.GetToken() == ')')
+		    {
+		      if (npseg == 2)
+			{
+			  p3 = p2;
+			  p2 = Center (p1, p3);
+			}
+		      if (nseg == 0)
+			points.Append (p3);
+		      points.Append (p2);
+		      points.Append (p1);
+		      npseg = 1;
+		      nseg++;
+
+		      cout << "p1, = " << p1 << ", p2 = " << p2 << ", p3 = " << p3 << endl;
+		    }
+		  
+		  if (scan.GetToken() == ')')
+		    {
+		      scan.ReadNext();
+		      break;
+		    }
+		  if (scan.GetToken() == ';' || scan.GetToken() == ',')
+		    {
+		      scan.ReadNext();
+		    }
+		}
+	      */
+	      cout << "p0 = " << p0 << endl;
+	      cout << ", ex = " << ex << ", ey = " << ey << endl;
+	      cout << "points = " << points << endl;
+	      
+	      Extrusion * extrusion = new Extrusion (p0, ex, ey, points);
+	      
+	      for (int i = 0; i < extrusion->GetNSurfaces(); i++)
+		{
+		  geom->AddSurface (&extrusion->GetSurface(i));
+		  extrusion->SetSurfaceId(i, geom->GetNSurf()-1);
+		}
+	      return new Solid (extrusion);
+		    
+	      /*
+	      // cout << "define cylinder, pa = " << pa << "; pb = " << pb
+	      // << ", rad = " << r << endl;
+	      OneSurfacePrimitive * surf = new Cylinder ( pa, pb, r );
+
+	      geom->AddSurface (surf);
+	      surf->SetSurfaceId (0, geom->GetNSurf()-1);
+
+	      return new Solid (surf);
+	      */
+	    }
+
+
+
+
+
+	  case TOK_TRANSLATE: 
+	    {
+	      Vec<3> v;
+	      scan.ReadNext();
+	      ParseChar (scan, '(');
+	      v(0) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      v(1) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      v(2) = ParseNumber (scan);
+	      ParseChar (scan, ';');
+	      
+	      Solid * sol1 = ParseSolid (scan);
+
+	      ParseChar (scan, ')');
+
+	      Solid * nsol = sol1 -> Copy(*geom);
+	      Transformation<3> trans(v);
+	      nsol -> Transform (trans);
+	      return nsol;
+	    }
+
+
+	  case TOK_MULTITRANSLATE: 
+	    {
+	      Vec<3> v;
+	      int n;
+	      
+	      scan.ReadNext();
+	      ParseChar (scan, '(');
+	      v(0) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      v(1) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      v(2) = ParseNumber (scan);
+	      ParseChar (scan, ';');
+	      
+	      n = int (ParseNumber (scan));
+	      ParseChar (scan, ';');
+	      
+	      Solid * sol1 = ParseSolid (scan);
+	      
+	      ParseChar (scan, ')');
+	      
+	      int i;
+	      Solid * hsol = sol1;
+	      for (i = 1; i <= n; i++)
+		{
+		  Solid * nsol = sol1 -> Copy(*geom);
+		  Transformation<3> trans(double(i) * v);
+		  
+		  nsol -> Transform (trans);
+		  hsol = new Solid (Solid::UNION, hsol, nsol); 
+		}
+	      return hsol;
+	    }
+
+
+	  default:
+	    {
+	      scan.Error (string ("unknown primary ") + scan.GetStringValue());
+	    }
+
+	  }
+      }
+
+    else if (scan.GetToken() == TOK_STRING &&
+	     geom->GetSolid(scan.GetStringValue()))
+
+      {
+	Solid * sol = const_cast<Solid*> (geom->GetSolid(scan.GetStringValue()));
+	scan.ReadNext();
+	return sol;
+      }
+
+    else if (scan.GetToken() == TOK_NOT)
+
+      {
+	scan.ReadNext();
+	Solid * sol1 = ParsePrimary (scan);
+	return new Solid (Solid::SUB, sol1);
+      }
+
+    else if (scan.GetToken() == '(')
+
+      {
+	scan.ReadNext();
+	Solid * sol1 = ParseSolid (scan);
+	scan.ReadNext();
+	return sol1;
+      }
+
+    scan.Error (string ("not a primary, name = ")+
+		scan.GetStringValue());
+    return 0;
+  }
+
+
+  Solid * ParseTerm (CSGScanner & scan)
+  {
+    Solid * sol = ParsePrimary(scan);
+    while (scan.GetToken() == TOK_AND)
+      {
+	scan.ReadNext();
+	Solid * sol2 = ParsePrimary(scan);
+	sol = new Solid (Solid::SECTION, sol, sol2);
+      }
+    return sol;
+  }
+
+  Solid * ParseSolid (CSGScanner & scan)
+  {
+    Solid * sol = ParseTerm(scan);
+    while (scan.GetToken() == TOK_OR)
+      {
+	scan.ReadNext();
+	Solid * sol2 = ParseTerm(scan);
+	sol = new Solid (Solid::UNION, sol, sol2);
+      }
+    return sol;
+  }
+
+
+
+  void ParseFlags (CSGScanner & scan, Flags & flags)
+  {
+    while (scan.GetToken() == '-')
+      {
+	scan.ReadNext();
+	string name = scan.GetStringValue();
+	scan.ReadNext();
+	if (scan.GetToken() == '=')
+	  {
+	    scan.ReadNext();
+	    if (scan.GetToken() == TOK_STRING)
+	      {
+		flags.SetFlag (name.c_str(), scan.GetStringValue().c_str());
+		scan.ReadNext();
+	      }
+	    else if (scan.GetToken() == '[')
+	      {
+		scan.ReadNext();
+		ARRAY<double> vals;
+		vals.Append (ParseNumber(scan));
+		while (scan.GetToken() == ',')
+		  {
+		    scan.ReadNext();
+		    vals.Append (ParseNumber(scan));
+		  }
+		ParseChar (scan, ']');
+		flags.SetFlag (name.c_str(), vals);
+	      }
+	    else if (scan.GetToken() == TOK_NUM)
+	      {
+		flags.SetFlag (name.c_str(), scan.GetNumValue());
+		scan.ReadNext();
+	      }
+	  }
+	else
+	  {
+	    flags.SetFlag (name.c_str());
+	  }
+      }
+  }
+
+
+  /*
+    Main parsing function for CSG geometry
+   */
+  CSGeometry * ParseCSG (istream & istr)
+  {
+    CSGScanner scan(istr);
+    
+    geom = new CSGeometry;
+
+    scan.ReadNext();
+    if (scan.GetToken() != TOK_RECO)  // keyword 'algebraic3d'
+      {
+	return 0;
+      }
+    scan.ReadNext();
+
+    try
+      {
+	while (1)
+	  {
+	    if (scan.GetToken() == TOK_END) break;
+	    
+	    if (scan.GetToken() == TOK_SOLID)
+	      {
+		scan.ReadNext();
+		if (scan.GetToken() != TOK_STRING)
+		  scan.Error ("name identifier expected");
+		string solidname = scan.GetStringValue();
+
+		scan.ReadNext();
+
+		ParseChar (scan, '=');
+		Solid * solid = ParseSolid (scan);
+
+		Flags flags;
+		ParseFlags (scan, flags);
+
+		geom->SetSolid (solidname.c_str(), new Solid (Solid::ROOT, solid)); 
+		geom->SetFlags (solidname.c_str(), flags); 
+		
+		ParseChar (scan, ';');
+		
+		PrintMessage (4, "define solid ", solidname);
+	      }
+
+	    else if (scan.GetToken() == TOK_TLO)
+
+	      { // a TopLevelObject definition
+
+		scan.ReadNext();
+		
+		string name = scan.GetStringValue();
+		scan.ReadNext();
+
+		if (scan.GetToken() != TOK_STRING)
+
+		  { // a solid TLO
+
+		    Flags flags;
+		    ParseFlags (scan, flags);
+		    
+		    ParseChar (scan, ';');
+
+		    int tlonr = 
+		      geom->SetTopLevelObject ((Solid*)geom->GetSolid(name));
+		    TopLevelObject * tlo = geom->GetTopLevelObject (tlonr);
+		    if (flags.NumListFlagDefined ("col"))
+		      {
+			const ARRAY<double> & col =
+			  flags.GetNumListFlag ("col");
+			tlo->SetRGB (col[0], col[1], col[2]);
+		      }
+
+		    if (flags.GetDefineFlag ("transparent"))
+		      tlo->SetTransparent (1);
+
+		    tlo->SetMaterial (flags.GetStringFlag ("material", ""));
+		    tlo->SetLayer (int(flags.GetNumFlag ("layer", 1)));
+		    if (flags.NumFlagDefined ("maxh"))
+		      tlo->SetMaxH (flags.GetNumFlag("maxh", 1e10));
+		  }
+
+		else
+		  
+		  { // a surface TLO
+
+		    string surfname = scan.GetStringValue();
+		    scan.ReadNext();
+
+		    Flags flags;
+		    ParseFlags (scan, flags);
+		    
+		    ParseChar (scan, ';');
+
+		    ARRAY<int> si;
+		    geom->GetSolid(surfname)->GetSurfaceIndices(si);
+		    int tlonr = 
+		      geom->SetTopLevelObject ((Solid*)geom->GetSolid(name),
+					       (Surface*)geom->GetSurface(si.Get(1)));
+		    TopLevelObject * tlo = geom->GetTopLevelObject (tlonr);
+		    if (flags.NumListFlagDefined ("col"))
+		      {
+			const ARRAY<double> & col = flags.GetNumListFlag ("col");
+			tlo->SetRGB (col.Get(1), col.Get(2), col.Get(3));
+		      }
+		    if (flags.GetDefineFlag ("transparent"))
+		      tlo->SetTransparent (1);
+
+		    if (flags.NumFlagDefined ("maxh"))
+		      tlo->SetMaxH (flags.GetNumFlag("maxh", 1e10));
+		    tlo->SetLayer (int(flags.GetNumFlag ("layer", 1)));
+		    tlo->SetBCProp (int(flags.GetNumFlag ("bc", -1)));
+		  }
+	      }
+	    
+	    else if (scan.GetToken() == TOK_IDENTIFY)
+
+	      {
+		
+		scan.ReadNext();
+		switch (scan.GetToken())
+		  {
+		  case TOK_CLOSESURFACES:
+		    {
+		      scan.ReadNext();
+		      
+		      string name1 = scan.GetStringValue();
+		      scan.ReadNext();
+		      
+		      string name2 = scan.GetStringValue();
+		      scan.ReadNext();
+		      
+		      Flags flags;
+		      ParseFlags (scan, flags);
+		      
+		      ParseChar (scan, ';');
+		      
+		      
+		      ARRAY<int> si1, si2;
+		      geom->GetSolid(name1)->GetSurfaceIndices(si1);
+		      geom->GetSolid(name2)->GetSurfaceIndices(si2);
+		      
+		      geom->AddIdentification 
+			(new CloseSurfaceIdentification 
+			 (geom->GetNIdentifications()+1, *geom, 
+			  geom->GetSurface (si1[0]), geom->GetSurface (si2[0]),
+			  flags));
+		      break;
+		    }
+		    
+		  case TOK_PERIODIC:
+		    {
+		      scan.ReadNext();
+		      
+		      string name1 = scan.GetStringValue();
+		      scan.ReadNext();
+
+		      string name2 = scan.GetStringValue();
+		      scan.ReadNext();
+
+		      ParseChar (scan, ';');
+
+		      
+		      ARRAY<int> si1, si2;
+		      geom->GetSolid(name1)->GetSurfaceIndices(si1);
+		      geom->GetSolid(name2)->GetSurfaceIndices(si2);
+		      
+		      geom->AddIdentification 
+			(new PeriodicIdentification 
+			 (geom->GetNIdentifications()+1,
+			  *geom,
+			  geom->GetSurface (si1.Get(1)),
+			  geom->GetSurface (si2.Get(1))));
+		      break;
+		    }
+
+		  default:
+		    scan.Error ("keyword 'closesurfaces' or 'periodic' expected");
+		  }
+		
+	      }
+	    
+	    else if (scan.GetToken() == TOK_POINT)
+	      {
+		Point<3> p;
+
+		scan.ReadNext();
+		ParseChar (scan, '(');
+		p(0) = ParseNumber (scan);
+		ParseChar (scan, ',');
+		p(1) = ParseNumber (scan);
+		ParseChar (scan, ',');
+		p(2) = ParseNumber (scan);
+		ParseChar (scan, ')');
+		ParseChar (scan, ';');
+
+		geom->AddUserPoint (p);
+	      }
+
+	    else if (scan.GetToken() == TOK_BOUNDINGBOX)
+	      {
+		Point<3> p1, p2;
+		
+		scan.ReadNext();
+		ParseChar (scan, '(');
+		p1(0) = ParseNumber (scan);
+		ParseChar (scan, ',');
+		p1(1) = ParseNumber (scan);
+		ParseChar (scan, ',');
+		p1(2) = ParseNumber (scan);
+		ParseChar (scan, ';');
+		p2(0) = ParseNumber (scan);
+		ParseChar (scan, ',');
+		p2(1) = ParseNumber (scan);
+		ParseChar (scan, ',');
+		p2(2) = ParseNumber (scan);
+		ParseChar (scan, ')');
+		ParseChar (scan, ';');
+
+		geom->SetBoundingBox (Box<3> (p1, p2));
+	      }
+
+	    else if (scan.GetToken() == TOK_BOUNDARYCONDITION)
+	      {
+		scan.ReadNext();
+		
+		string name1 = scan.GetStringValue();
+		scan.ReadNext();
+		
+		string name2 = scan.GetStringValue();
+		scan.ReadNext();
+		
+		int num = int (ParseNumber (scan));
+		ParseChar (scan, ';');
+
+
+		CSGeometry::BCModification bcm;
+		ARRAY<int> si;
+		
+		geom->GetSolid(name1)->GetSurfaceIndices(si);
+	
+		bcm.tlonr = -1;
+		int i;	
+		for (i = 0; i < geom->GetNTopLevelObjects(); i++)
+		  if (string (geom->GetTopLevelObject(i)->GetSolid()->Name())
+		      == name2)
+		    {
+		      bcm.tlonr = i;
+		      break;
+		    }
+		
+		bcm.bcnr = num;
+		for (i = 0; i < si.Size(); i++)
+		  {
+		    bcm.si = si[i];
+		    geom->bcmodifications.Append (bcm);
+		  }
+	      }
+
+	    else
+	      {
+		cout << "read unidentified token " << scan.GetToken() 
+		     << " string = " << scan.GetStringValue() << endl;
+		scan.ReadNext();
+	      }
+	  }
+      }
+    catch (string errstr)
+      {
+	cout << "caught error " << errstr << endl;
+      }
+
+
+    return geom;
+    /*
+    do
+      {
+	scan.ReadNext();
+	if (scan.GetToken() == TOK_STRING)
+	  cout << "found string " << scan.GetStringValue() << endl;
+	else
+	  cout << "token = " << int(scan.GetToken()) << endl;
+      }
+    while (scan.GetToken() != TOK_END);
+    */
+  }
+
+
+};
+
diff --git a/Netgen/libsrc/csg/csgparser_dalibor.cpp b/Netgen/libsrc/csg/csgparser_dalibor.cpp
new file mode 100644
index 0000000000..7f640864a3
--- /dev/null
+++ b/Netgen/libsrc/csg/csgparser_dalibor.cpp
@@ -0,0 +1,1111 @@
+#include <mystdlib.h>
+#include <myadt.hpp>
+
+#include <linalg.hpp>
+#include <csg.hpp>
+
+
+namespace netgen
+{
+  using namespace netgen;
+
+
+  enum TOKEN_TYPE
+    { 
+      TOK_MINUS = '-', TOK_LP = '(', OK_RP = ')', TOK_LSP = '[', TOK_RSP = ']',
+      TOK_EQU = '=', TOK_COMMA = ',', TOK_SEMICOLON = ';',
+      TOK_NUM = 100, TOK_STRING, TOK_NAMED_SOLID, TOK_PRIMITIVE, 
+      TOK_OR, TOK_AND, TOK_NOT, 
+      TOK_TRANSLATE, TOK_MULTITRANSLATE, TOK_ROTATE, TOK_MULTIROTATE,
+      TOK_SINGULAR, TOK_EDGE, TOK_POINT, TOK_IDENTIFY, TOK_CLOSESURFACES,
+      TOK_CLOSEEDGES, TOK_PERIODIC,
+      TOK_SOLID, TOK_RECO, TOK_TLO, TOK_BOUNDINGBOX, TOK_BOUNDARYCONDITION,
+      TOK_END };
+
+  struct kwstruct
+  {
+    TOKEN_TYPE kw; 
+    char * name;
+  };
+
+  static kwstruct defkw[] =
+    {
+      { TOK_RECO,    "algebraic3d" },
+      { TOK_SOLID,   "solid" },
+      { TOK_TLO,     "tlo" },
+      { TOK_BOUNDINGBOX, "boundingbox" },
+      { TOK_OR,      "or" },
+      { TOK_AND,     "and" },
+      { TOK_NOT,     "not" },
+      { TOK_TRANSLATE, "translate" },
+      { TOK_MULTITRANSLATE, "multitranslate" },
+      { TOK_ROTATE,   "rotate" },
+      { TOK_MULTIROTATE, "multirotate" },
+      { TOK_SINGULAR, "singular" },
+      { TOK_EDGE,     "edge" },
+      { TOK_POINT,    "point" },
+      { TOK_IDENTIFY, "identify" },
+      { TOK_CLOSESURFACES, "closesurfaces" },
+      { TOK_CLOSEEDGES, "closeedges" },
+      { TOK_PERIODIC,  "periodic" },
+      { TOK_BOUNDARYCONDITION, "boundarycondition" },
+      { TOKEN_TYPE(0) }
+    };
+
+  enum PRIMITIVE_TYPE
+    { TOK_SPHERE = 1, TOK_CYLINDER, TOK_PLANE, TOK_ELLIPTICCYLINDER, 
+      TOK_ELLIPSOID,
+      TOK_CONE, TOK_TUBE,
+      TOK_GENCYL, TOK_ORTHOBRICK, TOK_POLYHEDRON, TOK_EXTRUSION, TOK_REVOLUTION };
+
+  struct primstruct
+  {
+    PRIMITIVE_TYPE kw; 
+    char * name;
+  };
+
+  static primstruct defprim[] =
+    {
+      { TOK_PLANE,     "plane" },
+      { TOK_SPHERE,    "sphere" },
+      { TOK_CYLINDER,  "cylinder" },
+      { TOK_CONE,      "cone" },
+      { TOK_ELLIPTICCYLINDER, "ellipticcylinder" },
+      { TOK_ELLIPSOID, "ellipsoid" },
+      { TOK_TUBE,      "tube" },
+      { TOK_GENCYL,    "gencyl" },
+      { TOK_ORTHOBRICK, "orthobrick" },
+      { TOK_POLYHEDRON, "polyhedron" },
+      { TOK_EXTRUSION,  "extrusion" },
+      { TOK_REVOLUTION, "revolution" },
+      { PRIMITIVE_TYPE(0) }
+    };
+
+
+
+  static CSGeometry * geom;
+
+  /*
+%token <solidtype> TOK_SPHERE TOK_CYLINDER TOK_CONE TOK_PLAIN TOK_TUBE TOK_GENCYL TOK_ORTHOBRICK TOK_POLYHEDRON TOK_REVOLUTION
+%left <solidtype> TOK_OR TOK_AND TOK_NOT
+%token <solidtype> TOK_TRANSLATE TOK_MULTITRANSLATE TOK_ROTATE TOK_MULTIROTATE
+%type <solidtype> solid solidprimitive 
+%type <void> splinesegmentlist splinesegment readbspline bsplinepointlist
+%type <chptr> anyident
+%token TOK_SINGULAR TOK_EDGE TOK_POINT
+%token TOK_IDENTIFY TOK_CLOSESURFACES TOK_CLOSEEDGES TOK_PERIODIC
+%token TOK_BOUNDARYCONDITION
+%type <void> polyhedronpoints polyhedronfaces polyhedronpoint polyhedronface
+%type <void> revolutionpoints revolutionpoint
+  */
+
+
+  
+  class CSGScanner
+  {
+    TOKEN_TYPE token;
+    PRIMITIVE_TYPE prim_token;
+    double num_value;
+    string string_value;
+    
+    int linenum;
+    istream * scanin;
+
+  public:
+
+    CSGScanner (istream & ascanin);
+
+    TOKEN_TYPE GetToken() const
+    { return token; }
+
+    double GetNumValue() const
+    { return num_value; }
+
+    const string & GetStringValue() const
+    { return string_value; }
+
+    PRIMITIVE_TYPE GetPrimitiveToken() const
+    { return prim_token; }
+  
+    void ReadNext();
+    void Error (const string & err);
+  };
+
+
+  CSGScanner :: CSGScanner (istream & ascanin)
+  {
+    int i;
+
+    scanin = &ascanin;
+    token = TOK_END;
+    num_value = 0;
+    linenum = 1;
+  }
+
+
+  void CSGScanner :: ReadNext ()
+  {
+    char ch;
+  
+
+    // whitespaces ueberspringen
+    do
+      { 
+	scanin->get(ch);
+
+	if (ch == '\n') 
+	  linenum++;
+
+	// end of file reached
+	if (scanin->eof())
+	  {
+	    token = TOK_END;
+	    return;
+	  }
+
+	// skip comment line
+	if (ch == '#')
+	  {
+	    while (ch != '\n')
+	      {
+		scanin->get(ch);
+		if (scanin->eof())
+		  {
+		    token = TOK_END;
+		    return;
+		  }
+	      }
+	    linenum++;
+	  }	
+      }
+    while (isspace(ch));
+  
+    switch (ch)
+      {
+      case '(': case ')': 
+      case '[': case ']': 
+      case '-':
+      case '=': case ',': case ';':
+	{
+	  token = TOKEN_TYPE (ch);
+	  break;
+	}
+  
+      default:
+	{
+	  if (isdigit (ch) || ch == '.')
+	    {
+	      scanin->putback (ch);
+	      (*scanin) >> num_value;
+	      token = TOK_NUM;
+	      return;
+	    }
+
+	  if (isalpha (ch))
+	    {
+	      string_value = string (1, ch);
+	      scanin->get(ch);
+	      while (isalnum(ch))
+		{
+		  string_value += ch;
+		  scanin->get(ch);
+		}
+	      scanin->putback (ch);
+	    }
+	  /*
+	  (*scanin).putback (ch);
+	  (*scanin) >> string_value;
+	  */
+	  int nr = 0;
+	  while (defkw[nr].kw)
+	    {
+	      if (string_value == defkw[nr].name)
+		{
+		  token = defkw[nr].kw;
+		  return;
+		}
+	      nr++;
+	    }
+
+	  nr = 0;
+	  while (defprim[nr].kw)
+	    {
+	      if (string_value == defprim[nr].name)
+		{
+		  token = TOK_PRIMITIVE;
+		  prim_token = defprim[nr].kw;
+		  return;
+		}
+	      nr++;
+	    }
+
+	  token = TOK_STRING;
+	}
+      }
+  }
+
+  void CSGScanner :: Error (const string & err)
+  {
+    stringstream errstr;
+    errstr << "Parsing error in line " << linenum << ": " << endl << err << endl;
+    throw string(errstr.str());
+  }
+
+
+  /*
+    Solid = Term { OR Term }
+    Term  = Primary { AND Primary }
+    Primary = PRIM | IDENT | ( Solid ) | NOT Primary
+   */
+
+  void ParseChar (CSGScanner & scan, char ch)
+  {
+    char str[2];
+    str[0] = ch;
+    str[1] = 0;
+    if (scan.GetToken() != TOKEN_TYPE(ch)) 
+      scan.Error (string ("token '") + string(str) + string("' expected"));
+    scan.ReadNext();
+  }
+  
+  double ParseNumber(CSGScanner & scan)
+  {
+    if (scan.GetToken() == '-')
+      {
+	scan.ReadNext();
+	return -ParseNumber (scan);
+      }
+    if (scan.GetToken() != TOK_NUM) scan.Error ("number expected");
+    double val = scan.GetNumValue();
+    scan.ReadNext();
+    return val;
+  }
+
+
+  Solid * ParseSolid (CSGScanner & scan);
+  Solid * ParseTerm (CSGScanner & scan);
+  Solid * ParsePrimary (CSGScanner & scan);
+ 
+
+  Solid * ParsePrimary (CSGScanner & scan)
+  {
+    if (scan.GetToken() == TOK_PRIMITIVE)
+      {
+	//	cout << "prim token = " << int (scan.GetPrimitiveToken()) << endl;
+	switch (scan.GetPrimitiveToken())
+	  {
+	  case TOK_PLANE:
+	    {
+	      Point<3> p;
+	      Vec<3> v;
+	      
+	      scan.ReadNext();
+	      
+	      ParseChar (scan, '(');
+	      p(0) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      p(1) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      p(2) = ParseNumber (scan);
+	      ParseChar (scan, ';');
+	      v(0) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      v(1) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      v(2) = ParseNumber (scan);
+	      ParseChar (scan, ')');
+
+	      // cout << "define plane, p = " << p << "; v = " << v << endl;
+	      OneSurfacePrimitive * surf = new Plane ( p, v );
+
+	      geom->AddSurface (surf);
+	      surf->SetSurfaceId (0, geom->GetNSurf()-1);
+
+	      return new Solid (surf);
+	    }
+	  case TOK_CYLINDER:
+	    {
+	      Point<3> pa, pb;
+	      double r;
+	      
+	      scan.ReadNext();
+	      
+	      ParseChar (scan, '(');
+	      pa(0) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      pa(1) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      pa(2) = ParseNumber (scan);
+	      ParseChar (scan, ';');
+	      pb(0) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      pb(1) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      pb(2) = ParseNumber (scan);
+	      ParseChar (scan, ';');
+	      r = ParseNumber (scan);
+	      ParseChar (scan, ')');
+	      
+	      OneSurfacePrimitive * surf = new Cylinder ( pa, pb, r );
+
+	      geom->AddSurface (surf);
+	      surf->SetSurfaceId (0, geom->GetNSurf()-1);
+
+	      return new Solid (surf);
+	    }
+
+	  case TOK_ELLIPTICCYLINDER:
+	    {
+	      Point<3> pa;
+	      Vec<3> vl, vs;
+	      
+	      scan.ReadNext();
+	      
+	      ParseChar (scan, '(');
+	      pa(0) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      pa(1) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      pa(2) = ParseNumber (scan);
+	      ParseChar (scan, ';');
+
+	      vl(0) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      vl(1) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      vl(2) = ParseNumber (scan);
+	      ParseChar (scan, ';');
+
+	      vs(0) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      vs(1) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      vs(2) = ParseNumber (scan);
+	      ParseChar (scan, ')');
+	      
+	      OneSurfacePrimitive * surf = new EllipticCylinder ( pa, vl, vs);
+
+	      geom->AddSurface (surf);
+	      surf->SetSurfaceId (0, geom->GetNSurf()-1);
+
+	      return new Solid (surf);
+	    }
+
+
+	  case TOK_ELLIPSOID:
+	    {
+	      Point<3> pa;
+	      Vec<3> v1, v2, v3;
+	      
+	      scan.ReadNext();
+	      
+	      ParseChar (scan, '(');
+	      pa(0) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      pa(1) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      pa(2) = ParseNumber (scan);
+	      ParseChar (scan, ';');
+
+	      v1(0) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      v1(1) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      v1(2) = ParseNumber (scan);
+	      ParseChar (scan, ';');
+
+	      v2(0) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      v2(1) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      v2(2) = ParseNumber (scan);
+	      ParseChar (scan, ';');
+
+	      v3(0) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      v3(1) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      v3(2) = ParseNumber (scan);
+	      ParseChar (scan, ')');
+	      
+	      OneSurfacePrimitive * surf = new Ellipsoid ( pa, v1, v2, v3);
+
+	      geom->AddSurface (surf);
+	      surf->SetSurfaceId (0, geom->GetNSurf()-1);
+
+	      return new Solid (surf);
+	    }
+
+
+	  case TOK_CONE:
+	    {
+	      Point<3> pa, pb;
+	      double ra, rb;
+	      
+	      scan.ReadNext();
+	      
+	      ParseChar (scan, '(');
+	      pa(0) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      pa(1) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      pa(2) = ParseNumber (scan);
+	      ParseChar (scan, ';');
+	      ra = ParseNumber (scan);
+	      ParseChar (scan, ';');
+	      pb(0) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      pb(1) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      pb(2) = ParseNumber (scan);
+	      ParseChar (scan, ';');
+	      rb = ParseNumber (scan);
+	      ParseChar (scan, ')');
+	      
+	      OneSurfacePrimitive * surf = new Cone ( pa, pb, ra, rb);
+
+	      geom->AddSurface (surf);
+	      surf->SetSurfaceId (0, geom->GetNSurf()-1);
+
+	      return new Solid (surf);
+	    }
+
+
+
+
+	  case TOK_SPHERE:
+	    {
+	      Point<3> p;
+	      double r;
+	      
+	      scan.ReadNext();
+	      
+	      ParseChar (scan, '(');
+	      p(0) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      p(1) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      p(2) = ParseNumber (scan);
+	      ParseChar (scan, ';');
+	      r = ParseNumber (scan);
+	      ParseChar (scan, ')');
+	      
+	      // cout << "define sphere, c = " << p << ", rad = " << r << endl;
+	      OneSurfacePrimitive * surf = new Sphere ( p, r );
+
+	      geom->AddSurface (surf);
+	      surf->SetSurfaceId (0, geom->GetNSurf()-1);
+
+	      return new Solid (surf);
+	    }
+
+	  case TOK_ORTHOBRICK:
+	    {
+	      Point<3> pa, pb;
+	      
+	      scan.ReadNext();
+	      
+	      ParseChar (scan, '(');
+	      pa(0) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      pa(1) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      pa(2) = ParseNumber (scan);
+	      ParseChar (scan, ';');
+	      pb(0) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      pb(1) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      pb(2) = ParseNumber (scan);
+	      ParseChar (scan, ')');
+	      
+	      // cout << "define orthobrick, p1 = " << pa << "; p2 = " << pb << endl;
+
+	      Primitive * nprim = new OrthoBrick (pa, pb);
+	      
+	      for (int j = 0; j < nprim->GetNSurfaces(); j++)
+		{
+		  geom->AddSurface (&nprim->GetSurface(j));
+		  nprim->SetSurfaceId (j, geom->GetNSurf()-1);
+		}
+	      return new Solid (nprim);
+	    } 
+
+
+	  case TOK_EXTRUSION:
+	    {
+	      Point<3> p0;
+	      Vec<3> ex, ey;
+	      ARRAY<Point<2> > points;
+
+	      scan.ReadNext();
+	      
+	      ParseChar (scan, '(');
+	      p0(0) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      p0(1) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      p0(2) = ParseNumber (scan);
+	      ParseChar (scan, ';');
+
+	      ex(0) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      ex(1) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      ex(2) = ParseNumber (scan);
+	      ParseChar (scan, ';');
+
+	      ey(0) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      ey(1) = ParseNumber (scan);
+	      ParseChar (scan, ',');
+	      ey(2) = ParseNumber (scan);
+	      ParseChar (scan, ';');
+
+	      cout << "p0 = " << p0 << endl;
+
+	      int npseg = 0;
+	      int nseg = 0;
+	      while (1)
+		{
+		  Point<2> p1, p2, p3;
+
+		  p1(0) = ParseNumber(scan);
+		  ParseChar (scan, ',');
+		  p1(1) = ParseNumber(scan);
+		  points.Append (p1);
+		  if (scan.GetToken() == ')')
+		    {
+		      scan.ReadNext();
+		      break;
+		    }
+		  scan.ReadNext();
+		}
+
+
+	      /*
+	      while (1)
+		{
+		  Point<2> p1, p2, p3;
+		  
+		  p3 = p2;
+		  p2 = p1;
+		  p1(0) = ParseNumber(scan);
+		  ParseChar (scan, ',');
+		  p1(1) = ParseNumber(scan);
+		  npseg++;
+		  
+		  cout << "p1 = " << p1 << endl;
+
+		  if (scan.GetToken() == ';' || scan.GetToken() == ')')
+		    {
+		      if (npseg == 2)
+			{
+			  p3 = p2;
+			  p2 = Center (p1, p3);
+			}
+		      if (nseg == 0)
+			points.Append (p3);
+		      points.Append (p2);
+		      points.Append (p1);
+		      npseg = 1;
+		      nseg++;
+
+		      cout << "p1, = " << p1 << ", p2 = " << p2 << ", p3 = " << p3 << endl;
+		    }
+		  
+		  if (scan.GetToken() == ')')
+		    {
+		      scan.ReadNext();
+		      break;
+		    }
+		  if (scan.GetToken() == ';' || scan.GetToken() == ',')
+		    {
+		      scan.ReadNext();
+		    }
+		}
+	      */
+	      cout << "p0 = " << p0 << endl;
+	      cout << ", ex = " << ex << ", ey = " << ey << endl;
+	      cout << "points = " << points << endl;
+	      
+	      Extrusion * extrusion = new Extrusion (p0, ex, ey, points);
+	      
+	      for (int i = 0; i < extrusion->GetNSurfaces(); i++)
+		{
+		  geom->AddSurface (&extrusion->GetSurface(i));
+		  extrusion->SetSurfaceId(i, geom->GetNSurf()-1);
+		}
+	      return new Solid (extrusion);
+		    
+	      /*
+	      // cout << "define cylinder, pa = " << pa << "; pb = " << pb
+	      // << ", rad = " << r << endl;
+	      OneSurfacePrimitive * surf = new Cylinder ( pa, pb, r );
+
+	      geom->AddSurface (surf);
+	      surf->SetSurfaceId (0, geom->GetNSurf()-1);
+
+	      return new Solid (surf);
+	      */
+	    }
+
+
+// Added by Dalibor Lukas, October 15, 2003
+	  case TOK_POLYHEDRON:
+	    {
+	      Point<3> p;
+	      int pi1, pi2, pi3, pi4;
+	      
+	      scan.ReadNext();
+	      ParseChar (scan, '(');
+	      
+	      Polyhedra * polyhedron = new Polyhedra;
+
+	      // scanning the points
+	      while (1)
+		{
+		  p(0) = ParseNumber (scan);
+		  ParseChar (scan, ',');
+		  p(1) = ParseNumber (scan);
+		  ParseChar (scan, ',');
+		  p(2) = ParseNumber (scan);
+		  ParseChar (scan, ';');
+
+		  cout << "point = " << p << endl;
+
+		  polyhedron->AddPoint(p);
+
+		  if (scan.GetToken() == ';')
+		    {
+		      scan.ReadNext();
+		      break;
+		    }
+		}
+
+	      // scanning the faces
+	      while (1)
+		{
+		  pi1 = (int) (ParseNumber (scan));
+		  ParseChar (scan, ',');
+		  pi2 = (int) (ParseNumber (scan));
+		  ParseChar (scan, ',');
+		  pi3 = (int) (ParseNumber (scan));
+		  ParseChar (scan, ',');
+		  pi4 = (int) (ParseNumber (scan));
+
+		  cout << "face = (" << pi1 << ", " << pi2 << ", " << pi3
+		       << ", " << pi4 << ")" << endl;
+
+		  polyhedron->AddFace(pi1-1,pi2-1,pi3-1);
+		  polyhedron->AddFace(pi1-1,pi3-1,pi4-1);
+
+		  if (scan.GetToken() == ')')
+		    {
+		      scan.ReadNext();
+		      break;
+		    }
+		  scan.ReadNext();
+		}
+	      
+	      int j;
+	      for (j = 0; j < polyhedron->GetNSurfaces(); j++)
+		{
+		  geom->AddSurface (&polyhedron->GetSurface(j));
+		  polyhedron->SetSurfaceId (j, geom->GetNSurf()-1);
+		}
+
+	      return new Solid (polyhedron);
+	    }
+// DL
+
+
+	  }
+	cout << "unknown primary " << scan.GetStringValue() << endl;
+      }
+
+    else if (scan.GetToken() == TOK_STRING &&
+	     geom->GetSolid(scan.GetStringValue()))
+
+      {
+	Solid * sol = const_cast<Solid*> (geom->GetSolid(scan.GetStringValue()));
+	scan.ReadNext();
+	return sol;
+      }
+
+    else if (scan.GetToken() == TOK_NOT)
+
+      {
+	scan.ReadNext();
+	Solid * sol1 = ParsePrimary (scan);
+	return new Solid (Solid::SUB, sol1);
+      }
+
+    else if (scan.GetToken() == '(')
+
+      {
+	scan.ReadNext();
+	Solid * sol1 = ParseSolid (scan);
+	scan.ReadNext();
+	return sol1;
+      }
+
+    scan.Error (string ("not a primary, name = ")+
+		scan.GetStringValue());
+    return 0;
+  }
+
+
+  Solid * ParseTerm (CSGScanner & scan)
+  {
+    Solid * sol = ParsePrimary(scan);
+    while (scan.GetToken() == TOK_AND)
+      {
+	scan.ReadNext();
+	Solid * sol2 = ParsePrimary(scan);
+	sol = new Solid (Solid::SECTION, sol, sol2);
+      }
+    return sol;
+  }
+
+  Solid * ParseSolid (CSGScanner & scan)
+  {
+    Solid * sol = ParseTerm(scan);
+    while (scan.GetToken() == TOK_OR)
+      {
+	scan.ReadNext();
+	Solid * sol2 = ParseTerm(scan);
+	sol = new Solid (Solid::UNION, sol, sol2);
+      }
+    return sol;
+  }
+
+
+
+  void ParseFlags (CSGScanner & scan, Flags & flags)
+  {
+    while (scan.GetToken() == '-')
+      {
+	scan.ReadNext();
+	string name = scan.GetStringValue();
+	scan.ReadNext();
+	if (scan.GetToken() == '=')
+	  {
+	    scan.ReadNext();
+	    if (scan.GetToken() == TOK_STRING)
+	      {
+		flags.SetFlag (name.c_str(), scan.GetStringValue().c_str());
+		scan.ReadNext();
+	      }
+	    else if (scan.GetToken() == '[')
+	      {
+		scan.ReadNext();
+		ARRAY<double> vals;
+		vals.Append (ParseNumber(scan));
+		while (scan.GetToken() == ',')
+		  {
+		    scan.ReadNext();
+		    vals.Append (ParseNumber(scan));
+		  }
+		ParseChar (scan, ']');
+		flags.SetFlag (name.c_str(), vals);
+	      }
+	    else if (scan.GetToken() == TOK_NUM)
+	      {
+		flags.SetFlag (name.c_str(), scan.GetNumValue());
+		scan.ReadNext();
+	      }
+	  }
+	else
+	  {
+	    flags.SetFlag (name.c_str());
+	  }
+      }
+  }
+
+
+  /*
+    Main parsing function for CSG geometry
+   */
+  CSGeometry * ParseCSG (istream & istr)
+  {
+    CSGScanner scan(istr);
+    
+    geom = new CSGeometry;
+
+    scan.ReadNext();
+    if (scan.GetToken() != TOK_RECO)  // keyword 'algebraic3d'
+      return 0;
+    scan.ReadNext();
+
+    try
+      {
+	while (1)
+	  {
+	    if (scan.GetToken() == TOK_END) break;
+	    
+	    if (scan.GetToken() == TOK_SOLID)
+	      {
+		scan.ReadNext();
+		if (scan.GetToken() != TOK_STRING)
+		  scan.Error ("name identifier expected");
+		string solidname = scan.GetStringValue();
+
+		scan.ReadNext();
+
+		ParseChar (scan, '=');
+		Solid * solid = ParseSolid (scan);
+
+		Flags flags;
+		ParseFlags (scan, flags);
+
+		geom->SetSolid (solidname.c_str(), new Solid (Solid::ROOT, solid)); 
+		geom->SetFlags (solidname.c_str(), flags); 
+		
+		ParseChar (scan, ';');
+		
+		PrintMessage (4, "define solid ", solidname);
+	      }
+
+	    else if (scan.GetToken() == TOK_TLO)
+
+	      { // a TopLevelObject definition
+
+		scan.ReadNext();
+		
+		string name = scan.GetStringValue();
+		scan.ReadNext();
+
+		if (scan.GetToken() != TOK_STRING)
+
+		  { // a solid TLO
+
+		    Flags flags;
+		    ParseFlags (scan, flags);
+		    
+		    ParseChar (scan, ';');
+
+		    int tlonr = 
+		      geom->SetTopLevelObject ((Solid*)geom->GetSolid(name));
+		    TopLevelObject * tlo = geom->GetTopLevelObject (tlonr);
+		    if (flags.NumListFlagDefined ("col"))
+		      {
+			const ARRAY<double> & col =
+			  flags.GetNumListFlag ("col");
+			tlo->SetRGB (col[0], col[1], col[2]);
+		      }
+
+		    if (flags.GetDefineFlag ("transparent"))
+		      tlo->SetTransparent (1);
+
+		    tlo->SetMaterial (flags.GetStringFlag ("material", ""));
+		    tlo->SetLayer (int(flags.GetNumFlag ("layer", 1)));
+		    if (flags.NumFlagDefined ("maxh"))
+		      tlo->SetMaxH (flags.GetNumFlag("maxh", 1e10));
+		  }
+
+		else
+		  
+		  { // a surface TLO
+
+		    string surfname = scan.GetStringValue();
+		    scan.ReadNext();
+
+		    Flags flags;
+		    ParseFlags (scan, flags);
+		    
+		    ParseChar (scan, ';');
+
+		    ARRAY<int> si;
+		    geom->GetSolid(surfname)->GetSurfaceIndices(si);
+		    int tlonr = 
+		      geom->SetTopLevelObject ((Solid*)geom->GetSolid(name),
+					       (Surface*)geom->GetSurface(si.Get(1)));
+		    TopLevelObject * tlo = geom->GetTopLevelObject (tlonr);
+		    if (flags.NumListFlagDefined ("col"))
+		      {
+			const ARRAY<double> & col = flags.GetNumListFlag ("col");
+			tlo->SetRGB (col.Get(1), col.Get(2), col.Get(3));
+		      }
+		    if (flags.GetDefineFlag ("transparent"))
+		      tlo->SetTransparent (1);
+
+		    if (flags.NumFlagDefined ("maxh"))
+		      tlo->SetMaxH (flags.GetNumFlag("maxh", 1e10));
+		    tlo->SetLayer (int(flags.GetNumFlag ("layer", 1)));
+		    tlo->SetBCProp (int(flags.GetNumFlag ("bc", -1)));
+		  }
+	      }
+	    
+	    else if (scan.GetToken() == TOK_IDENTIFY)
+
+	      {
+		
+		scan.ReadNext();
+		switch (scan.GetToken())
+		  {
+		  case TOK_CLOSESURFACES:
+		    {
+		      scan.ReadNext();
+		      
+		      string name1 = scan.GetStringValue();
+		      scan.ReadNext();
+		      
+		      string name2 = scan.GetStringValue();
+		      scan.ReadNext();
+		      
+		      Flags flags;
+		      ParseFlags (scan, flags);
+		      
+		      ParseChar (scan, ';');
+		      
+		      
+		      ARRAY<int> si1, si2;
+		      geom->GetSolid(name1)->GetSurfaceIndices(si1);
+		      geom->GetSolid(name2)->GetSurfaceIndices(si2);
+		      
+		      geom->AddIdentification 
+			(new CloseSurfaceIdentification 
+			 (geom->GetNIdentifications()+1, *geom, 
+			  geom->GetSurface (si1[0]), geom->GetSurface (si2[0]),
+			  flags));
+		      break;
+		    }
+		    
+		  case TOK_PERIODIC:
+		    {
+		      scan.ReadNext();
+		      
+		      string name1 = scan.GetStringValue();
+		      scan.ReadNext();
+
+		      string name2 = scan.GetStringValue();
+		      scan.ReadNext();
+
+		      ParseChar (scan, ';');
+
+		      
+		      ARRAY<int> si1, si2;
+		      geom->GetSolid(name1)->GetSurfaceIndices(si1);
+		      geom->GetSolid(name2)->GetSurfaceIndices(si2);
+		      
+		      geom->AddIdentification 
+			(new PeriodicIdentification 
+			 (geom->GetNIdentifications()+1,
+			  *geom,
+			  geom->GetSurface (si1.Get(1)),
+			  geom->GetSurface (si2.Get(1))));
+		      break;
+		    }
+		  }
+		
+	      }
+	    
+	    else if (scan.GetToken() == TOK_POINT)
+	      {
+		Point<3> p;
+
+		scan.ReadNext();
+		ParseChar (scan, '(');
+		p(0) = ParseNumber (scan);
+		ParseChar (scan, ',');
+		p(1) = ParseNumber (scan);
+		ParseChar (scan, ',');
+		p(2) = ParseNumber (scan);
+		ParseChar (scan, ')');
+		ParseChar (scan, ';');
+
+		geom->AddUserPoint (p);
+	      }
+
+	    else if (scan.GetToken() == TOK_BOUNDINGBOX)
+	      {
+		Point<3> p1, p2;
+		
+		scan.ReadNext();
+		ParseChar (scan, '(');
+		p1(0) = ParseNumber (scan);
+		ParseChar (scan, ',');
+		p1(1) = ParseNumber (scan);
+		ParseChar (scan, ',');
+		p1(2) = ParseNumber (scan);
+		ParseChar (scan, ';');
+		p2(0) = ParseNumber (scan);
+		ParseChar (scan, ',');
+		p2(1) = ParseNumber (scan);
+		ParseChar (scan, ',');
+		p2(2) = ParseNumber (scan);
+		ParseChar (scan, ')');
+		ParseChar (scan, ';');
+
+		geom->SetBoundingBox (Box<3> (p1, p2));
+	      }
+
+	    else if (scan.GetToken() == TOK_BOUNDARYCONDITION)
+	      {
+		scan.ReadNext();
+		
+		string name1 = scan.GetStringValue();
+		scan.ReadNext();
+		
+		string name2 = scan.GetStringValue();
+		scan.ReadNext();
+		
+		int num = int (ParseNumber (scan));
+		ParseChar (scan, ';');
+
+
+		CSGeometry::BCModification bcm;
+		ARRAY<int> si;
+		
+		geom->GetSolid(name1)->GetSurfaceIndices(si);
+	
+		bcm.tlonr = -1;
+		int i;	
+		for (i = 0; i < geom->GetNTopLevelObjects(); i++)
+		  if (string (geom->GetTopLevelObject(i)->GetSolid()->Name())
+		      == name2)
+		    {
+		      bcm.tlonr = i;
+		      break;
+		    }
+		
+		bcm.bcnr = num;
+		for (i = 0; i < si.Size(); i++)
+		  {
+		    bcm.si = si[i];
+		    geom->bcmodifications.Append (bcm);
+		  }
+	      }
+
+	    else
+	      {
+		cout << "read unidentified token " << scan.GetToken() 
+		     << " string = " << scan.GetStringValue() << endl;
+		scan.ReadNext();
+	      }
+	  }
+      }
+    catch (string errstr)
+      {
+	cout << "caught error " << errstr << endl;
+      }
+
+
+    return geom;
+    /*
+    do
+      {
+	scan.ReadNext();
+	if (scan.GetToken() == TOK_STRING)
+	  cout << "found string " << scan.GetStringValue() << endl;
+	else
+	  cout << "token = " << int(scan.GetToken()) << endl;
+      }
+    while (scan.GetToken() != TOK_END);
+    */
+  }
+
+
+};
+
diff --git a/Netgen/libsrc/csg/csgscanner.cpp b/Netgen/libsrc/csg/csgscanner.cpp
new file mode 100644
index 0000000000..50e2213ea6
--- /dev/null
+++ b/Netgen/libsrc/csg/csgscanner.cpp
@@ -0,0 +1,205 @@
+#include <mystdlib.h>
+#include <myadt.hpp>
+
+#include <linalg.hpp>
+#include <csg.hpp>
+
+
+namespace netgen
+{
+  using namespace netgen;
+
+
+  enum TOKEN_TYPE
+    { 
+      LP = '(', RP = ')', EQU = '=', COMMA = ',', SEMICOLON = ';',
+      TOK_NUM, TOK_STRING, TOK_NAMED_SOLID, TOK_PRIMITIVE, 
+      TOK_OR, TOK_AND, TOK_NOT,
+      TOK_SOLID, TOK_RECO, TOK_TLO, TOK_BOUNDINGBOX,
+      TOK_END };
+
+  struct kwstruct
+  {
+    TOKEN_TYPE kw; 
+    string name;
+  };
+
+  static kwstruct defkw[] =
+    {
+      { TOK_OR,      "or" },
+      { TOK_AND,     "and" },
+      { TOKEN_TYPE(0) }
+    };
+
+  enum PRIMITIVE_TYPE { TOK_SPHERE, TOK_CYLINDER, TOK_PLANE };
+
+  /*
+%token <solidtype> TOK_SPHERE TOK_CYLINDER TOK_CONE TOK_PLAIN TOK_TUBE TOK_GENCYL TOK_ORTHOBRICK TOK_POLYHEDRON TOK_REVOLUTION
+%left <solidtype> TOK_OR TOK_AND TOK_NOT
+%token <solidtype> TOK_TRANSLATE TOK_MULTITRANSLATE TOK_ROTATE TOK_MULTIROTATE
+%type <solidtype> solid solidprimitive 
+%type <void> splinesegmentlist splinesegment readbspline bsplinepointlist
+%type <chptr> anyident
+%token TOK_SINGULAR TOK_EDGE TOK_POINT
+%token TOK_IDENTIFY TOK_CLOSESURFACES TOK_CLOSEEDGES TOK_PERIODIC
+%token TOK_BOUNDARYCONDITION
+%type <void> polyhedronpoints polyhedronfaces polyhedronpoint polyhedronface
+%type <void> revolutionpoints revolutionpoint
+  */
+
+
+  
+  class CSGScanner
+  {
+    TOKEN_TYPE token;
+    double num_value;
+    string string_value;
+
+    int linenum;
+    istream * scanin;
+
+  public:
+
+    CSGScanner (istream & ascanin);
+
+    TOKEN_TYPE GetToken() const
+    { return token; }
+
+    double GetNumValue() const
+    { return num_value; }
+
+    const string & GetStringValue() const
+    { return string_value; }
+  
+    void ReadNext();
+
+    void Error (const string & err);
+  };
+
+
+  CSGScanner :: CSGScanner (istream & ascanin)
+  {
+    int i;
+
+    scanin = &ascanin;
+    token = TOK_END;
+    num_value = 0;
+    linenum = 1;
+  }
+
+
+  void CSGScanner :: ReadNext ()
+  {
+    char ch;
+  
+
+    // whitespaces ueberspringen
+    do
+      { 
+	scanin->get(ch);
+
+	if (ch == '\n') 
+	  linenum++;
+
+	// end of file reached
+	if (scanin->eof())
+	  {
+	    token = TOK_END;
+	    return;
+	  }
+
+	// skip comment line
+	if (ch == '#')
+	  {
+	    while (ch != '\n')
+	      {
+		scanin->get(ch);
+		if (scanin->eof())
+		  {
+		    token = TOK_END;
+		    return;
+		  }
+	      }
+	    linenum++;
+	  }	
+      }
+    while (isspace(ch));
+  
+    switch (ch)
+      {
+      case '(': case ')':
+      case '=': case ',': case ';':
+	{
+	  token = TOKEN_TYPE (ch);
+	  break;
+	}
+  
+      default:
+	{
+	  if (isdigit (ch) || ch == '.' || ch == '-')
+	    {
+	      scanin->putback (ch);
+	      (*scanin) >> num_value;
+	      token = TOK_NUM;
+	      return;
+	    }
+
+	  (*scanin).putback (ch);
+	  (*scanin) >> string_value;
+
+	  int nr = 0;
+	  while (defkw[nr].kw)
+	    {
+	      if (string_value == defkw[nr].name)
+		{
+		  token = defkw[nr].kw;
+		  return;
+		}
+	    }
+	
+	  token = TOK_STRING;
+	}
+      }
+  }
+
+  void CSGScanner :: Error (const string & err)
+  {
+    stringstream errstr;
+    errstr << "Parsing error in line " << linenum << ": " << endl << err << endl;
+    /*
+    errstr << "input continues with <<<";
+    for (int i = 0; i < 50; i++)
+      {
+	char ch;
+	scanin->get(ch);
+	errstr << ch;
+	if (scanin->eof())
+	  {
+	    errstr << "(end of file)";
+	    break;
+	  }
+      }
+    errstr << endl << ">>> stop parsing" << endl;
+    throw Exception (errstr.str());
+    */
+  }
+  
+
+
+  
+  
+  void ParseCSG (istream & istr)
+  {
+    CSGScanner scan(istr);
+
+    do
+      {
+	scan.ReadNext();
+	cout << "token = " << int(scan.GetToken()) << endl;
+      }
+    while (scan.GetToken() != TOK_END);
+  }
+
+
+};
+
diff --git a/Netgen/libsrc/csg/curve2d.cpp b/Netgen/libsrc/csg/curve2d.cpp
new file mode 100644
index 0000000000..7091e87af9
--- /dev/null
+++ b/Netgen/libsrc/csg/curve2d.cpp
@@ -0,0 +1,78 @@
+#include <mystdlib.h>
+
+#include <myadt.hpp>
+#include <csg.hpp>
+
+namespace netgen
+{
+CircleCurve2d :: CircleCurve2d (const Point<2> & acenter, double arad)
+  {
+  center = acenter;
+  rad = arad;
+  }
+  
+void CircleCurve2d :: Project (Point<2> & p) const
+  {
+  Vec<2> v = p - center;
+  v *= rad/v.Length();
+  p = center + v;
+  }
+
+void CircleCurve2d :: NormalVector (const Point<2> & p, Vec<2> & n) const
+  {
+  n = p - center;
+  n /= n.Length();
+  }
+
+
+
+
+
+
+QuadraticCurve2d ::  QuadraticCurve2d ()
+{
+  cxx = cyy = cxy = cx = cy = c = 0;
+}
+
+void QuadraticCurve2d :: Read (istream & ist)
+{
+  ist >> cxx >> cyy >> cxy >> cx >> cy >> c;
+}
+
+
+void QuadraticCurve2d :: Project (Point<2> & p) const
+{
+  double f, x, y, gradx, grady, grad2;
+  int its = 0;
+
+  x = p(0);
+  y = p(1);
+
+  do
+    {
+      f = cxx * x * x + cyy * y * y + cxy * x * y + cx * x + cy * y + c;
+      gradx = 2 * cxx * x + cxy * y + cx;
+      grady = 2 * cyy * y + cxy * x + cy;
+      grad2 = gradx * gradx + grady * grady;
+      
+      x -= f * gradx / grad2;
+      y -= f * grady / grad2;
+
+      //      (*mycout) << "x = " << x << " y = " << y << " f = " << f << endl;
+      its++;
+    }
+  while (fabs (f) > 1e-8 && its < 20);
+  if (its >= 20)
+    cerr << "QuadraticCurve2d::Project:  many iterations, f = " << f << endl;
+  p(0) = x;
+  p(1) = y;
+}
+
+
+void QuadraticCurve2d :: NormalVector (const Point<2> & p, Vec<2> & n) const
+{
+  n(0) = 2 * cxx * p(0) + cxy * p(1) + cx;
+  n(1) = 2 * cyy * p(1) + cxy * p(0) + cy;
+  n.Normalize();
+}
+}
diff --git a/Netgen/libsrc/csg/curve2d.hpp b/Netgen/libsrc/csg/curve2d.hpp
new file mode 100644
index 0000000000..917bd53205
--- /dev/null
+++ b/Netgen/libsrc/csg/curve2d.hpp
@@ -0,0 +1,59 @@
+#ifndef FILE_CURVE2D
+#define FILE_CURVE2D
+
+/**************************************************************************/
+/* File:   curve2d.hh                                                     */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   24. Jul. 96                                                    */
+/**************************************************************************/
+
+/*
+
+  2D Curve repesentation
+
+*/
+
+
+
+///
+class Curve2d : public Manifold
+  {
+  public:
+  ///
+  virtual void Project (Point<2> & p) const = 0;
+  ///
+  virtual void NormalVector (const Point<2> & p, Vec<2> & n) const = 0;
+  };
+  
+///
+class CircleCurve2d : public Curve2d
+  {
+  ///
+  Point<2> center;
+  ///
+  double rad;
+  public:
+  ///
+  CircleCurve2d (const Point<2> & acenter, double arad);
+  ///
+  virtual void Project (Point<2> & p) const;
+  ///
+  virtual void NormalVector (const Point<2> & p, Vec<2> & n) const;
+  };
+  
+///
+class QuadraticCurve2d : public Curve2d
+{
+  ///
+  double cxx, cyy, cxy, cx, cy, c;
+public:
+  ///
+  QuadraticCurve2d ();
+  ///
+  void Read (istream & ist);
+  ///
+  virtual void Project (Point<2> & p) const;
+  ///
+  virtual void NormalVector (const Point<2> & p, Vec<2> & n) const;
+};
+#endif
diff --git a/Netgen/libsrc/csg/edgeflw.cpp b/Netgen/libsrc/csg/edgeflw.cpp
new file mode 100644
index 0000000000..0e5418ad69
--- /dev/null
+++ b/Netgen/libsrc/csg/edgeflw.cpp
@@ -0,0 +1,1399 @@
+#include <mystdlib.h>
+#include <meshing.hpp>
+#include <csg.hpp>
+
+#undef DEVELOP
+
+namespace netgen
+{
+
+  EdgeCalculation :: 
+  EdgeCalculation (const CSGeometry & ageometry,
+		   const ARRAY<SpecialPoint> & aspecpoints)
+    : geometry(ageometry), specpoints(aspecpoints)
+  {
+    ;
+  }
+
+
+
+  void EdgeCalculation :: Calc(double h, Mesh & mesh)
+  {
+    (*testout) << "Find edges" << endl;
+    PrintMessage (1, "Find edges");
+    PushStatus ("Find edges");
+
+    CalcEdges1 (h, mesh);
+    SplitEqualOneSegEdges (mesh);
+    FindClosedSurfaces (h, mesh);
+    PrintMessage (3, cntedge, " edges found");
+    PopStatus ();
+  }
+
+
+
+
+
+  void EdgeCalculation :: CalcEdges1 (double h, Mesh & mesh)
+  {
+    ARRAY<SpecialPoint> hsp(specpoints.Size());
+    ARRAY<SpecialPoint> startpoints, endpoints;
+
+    int i, j, k, l, hi, pos, ep, ne;
+    int layer;
+
+    Vec<3> a1, a2, t, n, m;
+    Point<3> p, np, pnp, hp;
+
+    Segment seg;
+    int pi1, s1, s2;
+    int lastpi, thispi;
+
+    ARRAY<Point<3> > edgepoints;
+    ARRAY<double> curvelength;
+    int copyedge, copyfromedge, copyedgeidentification;
+
+    ARRAY<int> locsurfind;
+
+    double len, corr, lam;
+    double steplen, cursteplen, loch, hd;
+
+    int checkedcopy = 0;
+
+    double size = geometry.MaxSize(); // globflags.GetNumFlag ("maxsize", 500);
+    double epspointdist2 = size * 1e-6; // globflags.GetNumFlag ("epspointdist", size * 1e-6);
+    epspointdist2 = sqr (epspointdist2);
+
+
+    Solid * locsol;
+
+
+    // copy special points to work with
+    for (i = 0; i < specpoints.Size(); i++)
+      hsp[i] = specpoints[i];
+
+
+    cntedge = 0;
+
+    while (hsp.Size())
+      {
+	SetThreadPercent(100 - 100 * double (hsp.Size()) / specpoints.Size());
+
+	edgepoints.SetSize (0);
+	curvelength.SetSize (0);
+      
+
+	pi1 = 0;
+	copyedge = 0;
+	// identifyable point available ?
+
+	//      (*testout) << endl;
+
+	for (i = 1; i <= geometry.identifications.Size() && !pi1; i++)
+	  {
+	    for (j = checkedcopy+1; j <= startpoints.Size() && !pi1; j++)
+	      {
+
+		if (geometry.identifications.Get(i)->IdentifyableCandidate (startpoints.Get(j)))
+		
+		  {
+		    int pi1cand = 0;
+		    double mindist = 1e10;
+		  
+		    for (k = 1; k <= hsp.Size() && !pi1; k++)
+		      {
+#ifdef DEVELOP
+			(*testout) << "check kand = " << hsp.Get(k).p 
+				   << ", v = " << hsp.Get(k).v 
+				   << endl;		      
+#endif
+			if (geometry.identifications.Get(i)
+			    ->Identifyable(startpoints.Get(j), hsp.Get(k)) ||
+			    geometry.identifications.Get(i)
+			    ->Identifyable(hsp.Get(k), startpoints.Get(j)))
+			  {
+
+#ifdef DEVELOP
+			    (*testout) << "identifiable, dist = "
+				       << Dist (startpoints.Get(j).p, hsp.Get(k).p) << endl;
+#endif
+
+			    if (Dist (startpoints.Get(j).p, hsp.Get(k).p) < mindist)
+			      {
+				mindist = Dist (startpoints.Get(j).p, hsp.Get(k).p);
+				pi1cand = k;
+			      }
+			    /*
+			      pi1 = k;
+			      copyedge = 1;
+			      copyfromedge = j;
+			      copyedgeidentification = i;
+			  
+			      (*testout) << "copy edge startpoint from "
+			      << startpoints.Get(j).p << " - " 
+			      << startpoints.Get(j).v 
+			      << " to " 
+			      << hsp.Get(k).p << " - " << hsp.Get(k).v << endl;
+			    */
+			  }
+		      }
+
+		    if (pi1cand)
+		      {
+			pi1 = pi1cand;
+			copyedge = 1;
+			copyfromedge = j;
+			copyedgeidentification = i;
+#ifdef DEVELOP
+			(*testout) << "copy edge startpoint from "
+				   << startpoints.Get(j).p << " - " 
+				   << startpoints.Get(j).v 
+				   << " to " 
+				   << hsp.Get(pi1).p << " - " << hsp.Get(pi1).v << endl;
+#endif
+		      }
+		  }
+	      }
+	  }
+      
+      
+	// cannot copy from other ege ?
+	if (!pi1)
+	  checkedcopy = startpoints.Size();
+      
+	// unconditional special point available ?
+	if (!pi1)
+	  for (i = 1; i <= hsp.Size() && pi1 == 0; i++)
+	    if (hsp.Get(i).unconditional == 1)
+	      pi1 = i;
+ 
+     
+	if (!pi1)
+	  {
+	    // only unconditional points available, choose first
+	    pi1 = 1;
+	  }
+
+	layer = hsp.Get(pi1).GetLayer();
+      
+
+	if (!hsp.Get(pi1).unconditional)
+	  {
+	    hsp.Elem(pi1).unconditional = 1;
+	    for (i = 1; i <= hsp.Size(); i++)
+	      if (i != pi1 && Dist (hsp.Get(pi1).p, hsp.Get(i).p) < 1e-8 &&
+		  (hsp.Get(pi1).v + hsp.Get(i).v).Length() < 1e-4)
+		{
+		  // opposite direction
+		  hsp.Elem(i).unconditional = 1;
+		}
+	  }
+
+	cntedge++;
+	startpoints.Append (hsp.Get(pi1));
+
+#ifdef DEVELOP
+	(*testout) << "edge nr " << cntedge << endl;
+	(*testout) << "start followedge: p1 = " << hsp.Get(pi1).p << ", v = " << hsp.Get(pi1).v << endl;
+#endif
+
+	FollowEdge (pi1, ep, pos, hsp, h, mesh,
+		    edgepoints, curvelength);
+
+
+	if (multithread.terminate)
+	  return;
+      
+	if (!ep)
+	  {
+	    // ignore starting point
+	    hsp.DeleteElement (pi1);
+	    continue;
+	  }
+
+
+
+	endpoints.Append (hsp.Get(ep));
+
+
+	double elen = 0;
+	for (i = 1; i <= edgepoints.Size()-1; i++)
+	  elen += Dist (edgepoints.Get(i), edgepoints.Get(i+1));
+
+
+	int shortedge = 0;
+	for (i = 1; i <= geometry.identifications.Size(); i++)
+	  if (geometry.identifications.Get(i)->ShortEdge(hsp.Get(pi1), hsp.Get(ep)))
+	    shortedge = 1;
+	(*testout) << "shortedge = " << shortedge << endl;
+
+
+	if (!shortedge)
+	  {
+	    mesh.RestrictLocalHLine (Point3d (hsp.Get(pi1).p), 
+				     Point3d (hsp.Get(ep).p), 
+				     elen / mparam.segmentsperedge);
+	  }
+      
+	s1 = hsp.Get(pi1).s1;
+	s2 = hsp.Get(pi1).s2;
+
+
+	// delete initial, terminal and conditional points
+
+#ifdef DEVELOP
+	(*testout) << "terminal point: p = " << hsp.Get(ep).p << ", v = " << hsp.Get(ep).v << endl;      
+#endif
+	if (ep > pi1)
+	  {
+	    hsp.DeleteElement (ep);
+	    hsp.DeleteElement (pi1);
+	  }
+	else
+	  {
+	    hsp.DeleteElement (pi1);
+	    hsp.DeleteElement (ep);
+	  }
+
+
+	for (j = 1; j <= edgepoints.Size()-1; j++)
+	  {
+	    p = edgepoints.Get(j);
+	    np = Center (p, edgepoints.Get(j+1));
+	    hd = Dist2 (p, np);
+ 
+	    for (i = 1; i <= hsp.Size(); i++)
+	      if ( hsp.Get(i).HasSurfaces (s1, s2) &&
+		   hsp.Get(i).unconditional == 0 &&
+		   Dist2 (np, hsp.Get(i).p) < 1.2 * hd)
+		{
+		  hsp.DeleteElement (i);
+		  i--;
+		}
+	  }
+
+      
+	ARRAY<Segment> refedges;
+	ARRAY<int> refedgesinv;
+      
+
+	AnalyzeEdge (s1, s2, pos, layer,
+		     edgepoints,
+		     refedges, refedgesinv);
+
+	for (i = 1; i <= refedges.Size(); i++)
+	  refedges.Elem(i).edgenr = cntedge;
+
+
+#ifdef DEVELOP
+	(*testout) << "edge " << cntedge << endl
+		   << "startp: " << startpoints.Last().p 
+		   << ", v = " << startpoints.Last().v << endl
+		   << "copy = " << copyedge << endl
+		   << refedges.Size() << " refedges: ";
+	for (i = 1; i <= refedges.Size(); i++)
+	  (*testout) << " " << refedges.Get(i).si;
+	(*testout) << endl;
+	(*testout) << "inv[1] = " << refedgesinv.Get(1) << endl;
+#endif
+      
+	if (!copyedge)
+	  {
+	    int oldnseg = mesh.GetNSeg();
+
+	    if (!shortedge)
+	      StoreEdge (refedges, refedgesinv, 
+			 edgepoints, curvelength, layer, mesh);
+	    else
+	      StoreShortEdge (refedges, refedgesinv, 
+			      edgepoints, curvelength, layer, mesh);
+
+
+	    /*
+	      for (i = oldnseg+1; i <= mesh.GetNSeg(); i++)
+	      for (j = 1; j <= oldnseg; j++)
+	      {
+	      const Point<3> & l1p1 = mesh.Point (mesh.LineSegment(i).p1);
+	      const Point<3> & l1p2 = mesh.Point (mesh.LineSegment(i).p2);
+	      const Point<3> & l2p1 = mesh.Point (mesh.LineSegment(j).p1);
+	      const Point<3> & l2p2 = mesh.Point (mesh.LineSegment(j).p2);
+	      Vec<3> vl1(l1p1, l1p2);
+	      for (double lamk = 0; lamk <= 1; lamk += 0.1)
+	      {
+	      Point<3> l2p = l1p1 + lamk * vl1;
+	      double dist = sqrt (MinDistLP2 (l2p1, l2p2, l2p));
+	      if (dist > 1e-12)
+	      mesh.RestrictLocalH (l2p, 3*dist);
+	      }
+	      }
+	    */
+	  }
+	else
+	  {
+	    CopyEdge (refedges, refedgesinv,
+		      copyfromedge, 
+		      startpoints.Get(copyfromedge).p,
+		      endpoints.Get(copyfromedge).p,
+		      edgepoints.Get(1), edgepoints.Last(),
+		      copyedgeidentification, 
+		      layer,
+		      mesh);
+	  }
+
+      }
+  }
+
+
+
+  /*
+    If two or more edges share the same initial and end-points,
+    then they need at least two segments 
+  */
+  void EdgeCalculation ::
+  SplitEqualOneSegEdges (Mesh & mesh)
+  {
+    int i, j, k;
+    SegmentIndex si;
+    PointIndex pi;
+
+    ARRAY<int> osedges(cntedge);
+    INDEX_2_HASHTABLE<int> osedgesht (cntedge+1);
+
+    osedges = 2;
+
+    // count segments on edges
+    for (si = 0; si < mesh.GetNSeg(); si++)
+      {
+	const Segment & seg = mesh[si];
+	if (seg.seginfo && seg.edgenr >= 1 && seg.edgenr <= cntedge)
+	  osedges.Elem(seg.edgenr)--;
+      }
+
+    // flag one segment edges
+    for (i = 0; i < cntedge; i++)
+      osedges[i] = (osedges[i] > 0) ? 1 : 0;
+
+
+    for (si = 0; si < mesh.GetNSeg(); si++)
+      {
+	const Segment & seg = mesh[si];
+	if (seg.seginfo && seg.edgenr >= 1 && seg.edgenr <= cntedge)
+	  {
+	    if (osedges.Get(seg.edgenr))
+	      {
+		INDEX_2 i2(seg.p1, seg.p2);
+		i2.Sort ();
+		if (osedgesht.Used (i2))
+		  osedgesht.Set (i2, 2);
+		else
+		  osedgesht.Set (i2, 1);
+	      }
+	  }
+      }
+
+
+    // one edge 1 segment, other 2 segments 
+    // yes, it happens !
+  
+    for (i = 1; i <= osedgesht.GetNBags(); i++)
+      for (j = 1; j <= osedgesht.GetBagSize(i); j++)
+	{
+	  INDEX_2 i2; 
+	  int val;
+	  osedgesht.GetData (i, j, i2, val);
+
+	  const Point<3> & p1 = mesh[PointIndex(i2.I1())];
+	  const Point<3> & p2 = mesh[PointIndex(i2.I2())];
+	  Vec<3> v = p2 - p1;
+	  double vlen = v.Length();
+	  v /= vlen;
+	  for (pi = PointIndex::BASE; 
+	       pi < mesh.GetNP()+PointIndex::BASE; pi++)
+
+	    if (pi != i2.I1() && pi != i2.I2())
+	      {
+		const Point<3> & p = mesh[pi];
+		Vec<3> v2 = p - p1;
+		double lam = (v2 * v);
+		if (lam > 0 && lam < vlen)
+		  {
+		    Point<3> hp = p1 + lam * v;
+		    if (Dist (p, hp) < 1e-4 * vlen)
+		      {
+			PrintSysError ("Point on edge !!!");
+			cout << "seg: " << i2 << ", p = " << k << endl;
+			osedgesht.Set (i2, 2);		      
+		      }
+		  }
+	      }
+	}
+
+
+    // insert new points
+    osedges = -1;
+
+    int nseg = mesh.GetNSeg();
+    for (si = 0; si < nseg; si++)
+      {
+	const Segment & seg = mesh[si];
+	if (seg.seginfo && seg.edgenr >= 1 && seg.edgenr <= cntedge)
+	  {
+	    INDEX_2 i2(seg.p1, seg.p2);
+	    i2.Sort ();
+	    if (osedgesht.Used (i2) &&
+		osedgesht.Get (i2) == 2 &&
+		osedges.Elem(seg.edgenr) == -1)
+	      {
+		Point<3> newp = Center (mesh[PointIndex(seg.p1)],
+					mesh[PointIndex(seg.p2)]);
+
+		ProjectToEdge (geometry.GetSurface(seg.surfnr1), 
+			       geometry.GetSurface(seg.surfnr2), 
+			       newp);
+
+		osedges.Elem(seg.edgenr) = 
+		  mesh.AddPoint (newp, mesh[PointIndex(seg.p1)].GetLayer());
+	      }
+	  }
+      }
+
+
+    for (i = 1; i <= nseg; i++)
+      {
+	Segment & seg = mesh.LineSegment (i);
+	if (seg.edgenr >= 1 && seg.edgenr <= cntedge)
+	  {
+	    if (osedges.Get(seg.edgenr) != -1)
+	      {
+		Segment newseg = seg;
+		newseg.p1 = osedges.Get(seg.edgenr);
+		seg.p2 = osedges.Get(seg.edgenr);
+		mesh.AddSegment (newseg);
+	      }
+	  }
+      }
+
+  }
+
+
+
+  void EdgeCalculation :: 
+  FollowEdge (int pi1, int & ep, int & pos,
+	      const ARRAY<SpecialPoint> & hsp,
+	      double h, const Mesh & mesh,
+	      ARRAY<Point<3> > & edgepoints,
+	      ARRAY<double> & curvelength)
+  {
+    int i, j, s1, s2;
+    double len, steplen, cursteplen, loch;
+    Point<3> p, np, pnp;
+    Vec<3> a1, a2, t;
+
+
+    double size = geometry.MaxSize();  // globflags.GetNumFlag ("maxsize", 500);
+    double epspointdist2 = size * 1e-6; // globflags.GetNumFlag ("epspointdist", size * 1e-6);
+    epspointdist2 = sqr (epspointdist2);
+    int uselocalh = mparam.uselocalh;
+
+
+
+    s1 = hsp.Get(pi1).s1;
+    s2 = hsp.Get(pi1).s2;
+  
+    p = hsp.Get(pi1).p;
+    geometry.GetSurface(s1) -> CalcGradient (p, a1);
+    geometry.GetSurface(s2) -> CalcGradient (p, a2);
+
+    t = Cross (a1, a2);
+    t.Normalize();
+
+    pos = (hsp.Get(pi1).v * t) > 0;
+    if (!pos) t *= -1;
+
+  
+    edgepoints.Append (p);
+    curvelength.Append (0);
+    len = 0;
+
+    loch = min2 (geometry.GetSurface(s1) -> LocH (p, 3, 1, h), 
+		 geometry.GetSurface(s2) -> LocH (p, 3, 1, h));
+  
+  
+  
+    if (uselocalh)
+      {
+	double lh = mesh.GetH(p);
+	if (lh < loch)
+	  loch = lh;
+      }
+
+    steplen = 0.1 * loch;
+  
+    do
+      {
+	if (multithread.terminate)
+	  return;
+      
+	if (fabs (p(0)) + fabs (p(1)) + fabs (p(2)) > 10000)
+	  {
+	    ep = 0;
+	    PrintWarning ("Give up line");
+	    break;
+	  }
+
+	if (steplen > 0.1 * loch) steplen = 0.1 * loch;
+      
+	steplen *= 2;
+	do
+	  {
+	    steplen *= 0.5;
+	    np = p + steplen * t;
+	    pnp = np;
+	    ProjectToEdge (geometry.GetSurface(s1), 
+			   geometry.GetSurface(s2), pnp);
+	  }
+	while (Dist (np, pnp) > 0.1 * steplen);
+      
+	cursteplen = steplen;
+	if (Dist (np, pnp) < 0.01 * steplen) steplen *= 2;
+      
+ 
+	np = pnp;
+      
+#ifdef MYGRAPH
+	if (silentflag <= 2)
+	  {
+	    MyLine3D (p, np, rot);
+	    MyDraw ();
+	  }
+#endif      
+
+	ep = 0;
+      
+	double hvtmin = 1.5 * cursteplen;
+      
+	Box<3> boxp (p - (2 * cursteplen) * Vec<3> (1, 1, 1),
+		     p + (2 * cursteplen) * Vec<3> (1, 1, 1));
+
+	for (i = 1; i <= hsp.Size(); i++)
+	  //        if ( i != pi1 && hsp[i].HasSurfaces (s1, s2) )
+	  {
+	    if (!boxp.IsIn (hsp.Get(i).p))
+	      continue;
+	  
+	    Vec<3> hv = hsp.Get(i).p - p;
+	    if (hv.Length2() > 9 * cursteplen * cursteplen)
+	      continue;
+	    /*
+	      if (!hsp.Get(i).HasSurfaces (s1, s2))
+	      continue;                  // test for dalibor-problem
+	    */
+	    double hvt = hv * t;
+	    hv -= hvt * t;
+	  
+	    if (hv.Length() < 0.2 * cursteplen &&
+		hvt > 0 && 
+		//		  hvt < 1.5 * cursteplen &&
+		hvt < hvtmin && 
+		hsp.Get(i).unconditional == 1 &&
+		(hsp.Get(i).v + t).Length() < 0.4  ) 
+	      {
+		Point<3> hep = hsp.Get(i).p;
+		ProjectToEdge (geometry.GetSurface(s1), 
+			       geometry.GetSurface(s2), hep);            
+	      
+	      
+		if (Dist2 (hep, hsp.Get(i).p) < epspointdist2 )
+		  {
+		    geometry.GetSurface(s1) -> CalcGradient (hep, a1);
+		    geometry.GetSurface(s2) -> CalcGradient (hep, a2);
+		    Vec<3> ept = Cross (a1, a2);
+		    ept /= ept.Length();
+		    if (!pos) ept *= -1;
+		  
+		    if ( (hsp.Get(i).v + ept).Length() < 1e-4 )
+		      {
+			np = hsp.Get(i).p;
+			ep = i;
+			hvtmin = hvt;
+			//			  break;
+		      }
+		  }
+	      }
+	  }
+
+	loch = min2 (geometry.GetSurface(s1) -> LocH (np, 3, 1, h), 
+		     geometry.GetSurface(s2) -> LocH (np, 3, 1, h));
+
+	if (uselocalh)
+	  {
+	    double lh = mesh.GetH(np);
+	    if (lh < loch)
+	      loch = lh;
+	  }
+      
+      
+	len += Dist (p, np) / loch;
+	edgepoints.Append (np);
+	curvelength.Append (len);
+      
+	p = np;
+      
+	geometry.GetSurface(s1) -> CalcGradient (p, a1);
+	geometry.GetSurface(s2) -> CalcGradient (p, a2);
+	t = Cross (a1, a2);
+	t.Normalize();
+	if (!pos) t *= -1;
+      }
+    while (! ep);
+  }
+
+
+
+
+
+
+
+  void EdgeCalculation :: 
+  AnalyzeEdge (int s1, int s2, int pos, int layer,
+	       const ARRAY<Point<3> > & edgepoints,
+	       ARRAY<Segment> & refedges,
+	       ARRAY<int> & refedgesinv)
+  {
+    int i, j, k, l;
+    int hi;
+    Point<3> hp;
+    Vec<3> t, a1, a2, m, n;
+    Segment seg;
+    Solid * locsol;
+    ARRAY<int> locsurfind;
+
+    /*
+      int pi1 = 0, pi2 = 0;
+      extern Mesh * mesh;
+      for (i = 1; i <= mesh->GetNP(); i++)
+      {
+      if (Dist2 (edgepoints.Get(1), mesh->Point(i)) < 1e-12)
+      pi1 = i;
+      if (Dist2 (edgepoints.Last(), mesh->Point(i)) < 1e-12)
+      pi2 = i;
+      }
+      (*testout) << "Analyze edge: " << pi1 << " - " << pi2 << ", pts = " << edgepoints.Size() << endl;
+      (*testout) << "p1 = " << edgepoints.Get(1) << " pl = " << edgepoints.Last() << endl;
+    */
+    int debug = 0;
+    /*
+      Dist2 (Point<3> (2.69642, 1.1866, 2.03), edgepoints.Get(1)) < 1e-6 ||
+      Dist2 (Point<3> (2.69642, 1.1866, 2.03), edgepoints.Last()) < 1e-6;
+    */
+
+    if (debug)
+      {
+	//      (*testout) << "tubious edge !!!" << endl;
+	(*testout) << "s1, s2 = " << s1 << " - " << s2 << endl;
+      }
+
+    refedges.SetSize(0);
+    refedgesinv.SetSize(0);
+    hp = Center (edgepoints.Get(1), edgepoints.Get(2));
+    ProjectToEdge (geometry.GetSurface(s1), geometry.GetSurface(s2), hp);
+
+    geometry.GetSurface(s1) -> CalcGradient (hp, a1);
+    geometry.GetSurface(s2) -> CalcGradient (hp, a2);
+    t = Cross (a1, a2);
+    t.Normalize();
+    if (!pos) t *= -1;    
+  
+    (*testout) << "t = " << t << endl;
+
+    for (i = 0; i < geometry.GetNTopLevelObjects(); i++)
+      {
+	(*testout) << "layer = " << layer 
+		   << ", tlo-layer = " << geometry.GetTopLevelObject(i)->GetLayer() << endl;
+	if (geometry.GetTopLevelObject(i)->GetLayer() != layer) 
+	  continue;
+      
+	const Solid * sol = geometry.GetTopLevelObject(i)->GetSolid();
+	const Surface * surf = geometry.GetTopLevelObject(i)->GetSurface();
+
+	sol -> TangentialSolid (hp, locsol);
+	if (!locsol) continue;
+
+	BoxSphere<3> boxp (hp, hp);
+	boxp.Increase (1e-5);
+	boxp.CalcDiamCenter();
+      
+	ReducePrimitiveIterator rpi(boxp);
+	UnReducePrimitiveIterator urpi;
+      
+	((Solid*)locsol) -> IterateSolid (rpi);
+
+	locsol -> CalcSurfaceInverse ();
+      
+
+	if (!surf)
+	  {
+	    locsol -> GetSurfaceIndices (locsurfind);
+	  }
+	else
+	  {
+	    /*
+	      if (fabs (surf->CalcFunctionValue (hp)) < 1e-6)
+	      continue;
+	    */
+	    locsurfind.SetSize(1);
+	    locsurfind[0] = -1;
+	    for (j = 0; j < geometry.GetNSurf(); j++)
+	      if (geometry.GetSurface(j) == surf)
+		{
+		  locsurfind[0] = j;
+		  //		      geometry.GetSurfaceClassRepresentant(j);
+		  break;
+		}
+	  }
+
+	((Solid*)locsol) -> IterateSolid (urpi);
+
+      
+	if (debug)
+	  (*testout) << "edge of tlo " << i << ", has " << locsurfind.Size() << " faces." << endl;
+      
+
+	for (j = locsurfind.Size()-1; j >= 0; j--)
+	  if (fabs (geometry.GetSurface(locsurfind[j])
+		    ->CalcFunctionValue (hp) ) > 1e-6)
+	    locsurfind.DeleteElement(j+1);
+      
+	if (debug)
+	  (*testout) << locsurfind.Size() << " faces on hp" << endl;
+
+	for (j = 0; j < locsurfind.Size(); j++)
+	  {      
+	    int lsi = locsurfind[j];
+	    int rlsi = geometry.GetSurfaceClassRepresentant(lsi);
+	  
+	    Vec<3> rn;
+
+	    // n is outer normal to solid
+	    geometry.GetSurface(lsi) -> GetNormalVector (hp, n);
+	    if (geometry.GetSurface (lsi)->Inverse())
+	      n *= -1;
+	  
+	    if (fabs (t * n) > 1e-4) continue;
+	    if (debug)
+	      {
+		(*testout) << "face " << locsurfind.Get(j) << ", rep = " << rlsi 
+			   << " has (t*n) = " << (t*n) << endl;
+		(*testout) << "n = " << n << endl;
+	      }
+	  
+	    // rn is normal to class representant
+	    geometry.GetSurface(rlsi) -> GetNormalVector (hp, rn);
+	  
+	    int sameasref = ((n * rn) > 0);
+	  
+	    m = Cross (t, rn);
+	    m.Normalize();
+	  
+
+	    for (k = 1; k <= 2; k ++)
+	      {
+		bool edgeinv = (k == 2);
+	      
+		if (debug)
+		  {
+		    (*testout) << "onface(" << hp << ", " << m << ")= " 
+			       << locsol->OnFace (hp, m);
+		    (*testout) << " vec2in = "
+			       << locsol -> VectorIn2 (hp, m, n) << " and " 
+			       << locsol -> VectorIn2 (hp, m, -1 * n) << endl;
+		  }
+
+		//	      if (locsol -> OnFace (hp, m))
+		if (locsol -> VectorIn2 (hp, m, n) == 0 &&
+		    locsol -> VectorIn2 (hp, m, -1 * n) == 1)
+		  {
+		    hi = 0;
+		    for (l = 1; l <= refedges.Size(); l++)
+		      {
+			if (refedges.Get(l).si == rlsi &&
+			    refedgesinv.Get(l) == edgeinv)
+			  hi = l;
+		      }
+		  
+		    if (!hi)
+		      {
+			seg.si = rlsi;
+			seg.domin = -1;
+			seg.domout = -1;
+			seg.tlosurf = -1;
+			seg.surfnr1 = s1;
+			seg.surfnr2 = s2;
+			hi = refedges.Append (seg);
+			refedgesinv.Append (edgeinv);
+		      }
+		  
+		    if (!surf)
+		      {
+			if (sameasref)
+			  refedges.Elem(hi).domin = i;
+			else 
+			  refedges.Elem(hi).domout = i;
+		      }
+		    else
+		      refedges.Elem(hi).tlosurf = i;
+
+		    if (debug)
+		      (*testout) << "add ref seg:" 
+				 << "si = " << refedges.Get(hi).si
+				 << ", domin = " << refedges.Get(hi).domin
+				 << ", domout = " << refedges.Get(hi).domout
+				 << ", surfnr1/2 = " << refedges.Get(hi).surfnr1
+				 << ", " << refedges.Get(hi).surfnr2
+				 << ", inv = " << refedgesinv.Get(hi) 
+				 << ", refedgenr = " << hi
+				 << endl;
+		  }
+		m *= -1;
+	      } 
+	  }
+	delete locsol;          
+      }
+  }
+
+
+
+  void EdgeCalculation :: 
+  StoreEdge (const ARRAY<Segment> & refedges,
+	     const ARRAY<int> & refedgesinv,
+	     const ARRAY<Point<3> > & edgepoints,
+	     const ARRAY<double> & curvelength,
+	     int layer,
+	     Mesh & mesh)
+  {
+  
+    // Calculate optimal element-length
+    int i, j, k;
+    PointIndex pi;
+    int ne;
+
+    double len, corr, lam;
+    PointIndex thispi, lastpi;
+    Point<3> p, np;
+    Segment seg;
+
+
+    const Surface * surf1 = geometry.GetSurface (refedges.Get(1).surfnr1);
+    const Surface * surf2 = geometry.GetSurface (refedges.Get(1).surfnr2);
+
+    len = curvelength.Last();
+    ne = int (len + 0.5);
+    if (ne == 0) ne = 1;
+    if (Dist2 (edgepoints.Get(1), edgepoints.Last()) < 1e-8 && 
+	ne <= 6) 
+      ne = 6;
+    corr = len / ne;
+
+    // generate initial point
+    p = edgepoints.Get(1);
+    lastpi = -1;
+    for (pi = PointIndex::BASE; 
+	 pi < mesh.GetNP()+PointIndex::BASE; pi++)
+      if (Dist (mesh[pi], p) < 1e-6)
+	{
+	  lastpi = pi;
+	  break;
+	}
+
+    if (lastpi == -1)
+      lastpi = mesh.AddPoint (p, layer);
+
+  
+    j = 1;
+    for (i = 1; i <= ne; i++)
+      {
+	while (curvelength.Get(j) < i * corr && j < curvelength.Size()) j++;
+      
+	lam = (i * corr - curvelength.Get(j-1)) / 
+	  (curvelength.Get(j) - curvelength.Get(j-1));
+      
+	np(0) = (1-lam) * edgepoints.Get(j-1)(0) + lam * edgepoints.Get(j)(0);
+	np(1) = (1-lam) * edgepoints.Get(j-1)(1) + lam * edgepoints.Get(j)(1);
+	np(2) = (1-lam) * edgepoints.Get(j-1)(2) + lam * edgepoints.Get(j)(2);
+      
+      
+	thispi = -1;
+	if (i == ne)
+	  for (pi = PointIndex::BASE; 
+	       pi < mesh.GetNP()+PointIndex::BASE; pi++)
+	    if (Dist(mesh[pi], np) < 1e-6)
+	      thispi = pi;
+      
+	if (thispi == -1)
+	  {
+	    ProjectToEdge (surf1, surf2, np);
+	    thispi = mesh.AddPoint (np, layer);
+	  }
+
+	for (k = 1; k <= refedges.Size(); k++)
+	  {
+	    if (refedgesinv.Get(k))
+	      {
+		seg.p1 = lastpi;
+		seg.p2 = thispi;
+	      }
+	    else
+	      {
+		seg.p1 = thispi;
+		seg.p2 = lastpi;
+	      }
+	    seg.si = refedges.Get(k).si;
+	    seg.domin = refedges.Get(k).domin;
+	    seg.domout = refedges.Get(k).domout;
+	    seg.tlosurf = refedges.Get(k).tlosurf;
+	    seg.edgenr = refedges.Get(k).edgenr;
+	    seg.surfnr1 = refedges.Get(k).surfnr1;
+	    seg.surfnr2 = refedges.Get(k).surfnr2;
+	    seg.seginfo = 0;
+	    if (k == 1) seg.seginfo = (refedgesinv.Get(k)) ? 2 : 1;
+	    mesh.AddSegment (seg);
+	    //	  (*testout) << "add seg " << seg.p1 << "-" << seg.p2 << endl;
+	  
+	    double maxh = min2 (geometry.GetSurface(seg.surfnr1)->GetMaxH(),
+				geometry.GetSurface(seg.surfnr2)->GetMaxH());
+			      
+	    if (seg.domin != -1)
+	      {
+		const Solid * s1 = 
+		  geometry.GetTopLevelObject(seg.domin) -> GetSolid();
+		maxh = min2 (maxh, s1->GetMaxH());
+		maxh = min2 (maxh, geometry.GetTopLevelObject(seg.domin)->GetMaxH());
+		mesh.RestrictLocalH (p, maxh);
+		mesh.RestrictLocalH (np, maxh);
+	      }
+	    if (seg.domout != -1)
+	      {
+		const Solid * s1 = 
+		  geometry.GetTopLevelObject(seg.domout) -> GetSolid();
+		maxh = min2 (maxh, s1->GetMaxH());
+		maxh = min2 (maxh, geometry.GetTopLevelObject(seg.domout)->GetMaxH());
+		mesh.RestrictLocalH (p, maxh);
+		mesh.RestrictLocalH (np, maxh);
+	      }
+	    if (seg.tlosurf != -1)
+	      {
+		double hi = geometry.GetTopLevelObject(seg.tlosurf) -> GetMaxH();
+		maxh = min2 (maxh, hi);
+		mesh.RestrictLocalH (p, maxh);
+		mesh.RestrictLocalH (np, maxh);
+	      }	  
+	  }
+      
+	p = np;
+	lastpi = thispi;
+      }
+
+#ifdef DEVELOP
+    (*testout) << " eplast = " << lastpi << " = " << p << endl;
+#endif
+  }
+  
+
+
+
+
+
+  void EdgeCalculation :: 
+  StoreShortEdge (const ARRAY<Segment> & refedges,
+		  const ARRAY<int> & refedgesinv,
+		  const ARRAY<Point<3> > & edgepoints,
+		  const ARRAY<double> & curvelength,
+		  int layer,
+		  Mesh & mesh)
+  {
+  
+    // Calculate optimal element-length
+    int i, j, k;
+    PointIndex pi;
+    int ne;
+    Segment seg;
+
+    /*
+      double len, corr, lam;
+      int thispi, lastpi;
+      Point<3> p, np;
+
+
+      const Surface * surf1 = geometry.GetSurface (refedges.Get(1).surfnr1);
+      const Surface * surf2 = geometry.GetSurface (refedges.Get(1).surfnr2);
+
+      len = curvelength.Last();
+      ne = int (len + 0.5);
+      if (ne == 0) ne = 1;
+      if (Dist2 (edgepoints[1], edgepoints.Last()) < 1e-8 && 
+      ne <= 6) 
+      ne = 6;
+      corr = len / ne;
+    */
+
+    // generate initial point
+    Point<3> p = edgepoints[0];
+    PointIndex pi1 = -1;
+    for (pi = PointIndex::BASE; 
+	 pi < mesh.GetNP()+PointIndex::BASE; pi++)
+
+      if (Dist (mesh[pi], p) < 1e-6)
+	{
+	  pi1 = pi;
+	  break;
+	}
+
+    if (pi1 == -1) pi1 = mesh.AddPoint (p, layer);
+
+    p = edgepoints.Last();
+    PointIndex pi2 = -1;
+    for (pi = PointIndex::BASE; 
+	 pi < mesh.GetNP()+PointIndex::BASE; pi++)
+
+      if (Dist (mesh[pi], p) < 1e-6)
+	{
+	  pi2 = pi;
+	  break;
+	}
+    if (pi2==-1) pi2 = mesh.AddPoint (p, layer);
+
+    /*
+  
+    j = 1;
+    for (i = 1; i <= ne; i++)
+    {
+    while (curvelength[j] < i * corr && j < curvelength.Size()) j++;
+      
+    lam = (i * corr - curvelength[j-1]) / 
+    (curvelength[j] - curvelength[j-1]);
+      
+    np(0) = (1-lam) * edgepoints[j-1](0) + lam * edgepoints[j](0);
+    np(1) = (1-lam) * edgepoints[j-1](1) + lam * edgepoints[j](1);
+    np(2) = (1-lam) * edgepoints[j-1](2) + lam * edgepoints[j](2);
+      
+      
+    thispi = 0;
+    if (i == ne)
+    for (j = 1; j <= mesh.GetNP(); j++)
+    if (Dist(mesh.Point(j), np) < 1e-6)
+    thispi = j;
+      
+    if (!thispi)
+    {
+    ProjectToEdge (surf1, surf2, np);
+    thispi = mesh.AddPoint (np);
+    }
+    */
+  
+    for (k = 1; k <= refedges.Size(); k++)
+      {
+	if (refedgesinv.Get(k))
+	  {
+	    seg.p1 = pi1;
+	    seg.p2 = pi2;
+	  }
+	else
+	  {
+	    seg.p1 = pi2;
+	    seg.p2 = pi1;
+	  }
+
+	seg.si = refedges.Get(k).si;
+	seg.domin = refedges.Get(k).domin;
+	seg.domout = refedges.Get(k).domout;
+	seg.tlosurf = refedges.Get(k).tlosurf;
+	seg.edgenr = refedges.Get(k).edgenr;
+	seg.surfnr1 = refedges.Get(k).surfnr1;
+	seg.surfnr2 = refedges.Get(k).surfnr2;
+	seg.seginfo = 0;
+	if (k == 1) seg.seginfo = (refedgesinv.Get(k)) ? 2 : 1;
+	mesh.AddSegment (seg);
+	//	  (*testout) << "add seg " << seg.p1 << "-" << seg.p2 << endl;
+      }
+  }
+  
+
+
+
+
+
+
+  void EdgeCalculation :: 
+  CopyEdge (const ARRAY<Segment> & refedges,
+	    const ARRAY<int> & refedgesinv,
+	    int copyfromedge, 
+	    const Point<3> & fromstart, const Point<3> & fromend,
+	    const Point<3> & tostart, const Point<3> & toend,
+	    int copyedgeidentification, 
+	    int layer,
+	    Mesh & mesh)
+  {
+    int i, j, k;
+    PointIndex pi;
+
+    // copy start and end points
+    for (i = 1; i <= 2; i++)
+      {
+	Point<3> fromp =
+	  (i == 1) ? fromstart : fromend;
+	Point<3> top =
+	  (i == 1) ? tostart : toend;
+      
+	PointIndex frompi = -1;
+	PointIndex topi = -1;
+	for (pi = PointIndex::BASE; 
+	     pi < mesh.GetNP()+PointIndex::BASE; pi++)
+	  {
+	    if (Dist2 (mesh[pi], fromp) <= 1e-16)
+	      frompi = pi;
+	    if (Dist2 (mesh[pi], top) <= 1e-16)
+	      topi = pi;
+	  }
+
+	if (topi == -1)
+	  topi = mesh.AddPoint (top, layer);
+
+	const Identification & csi = 
+	  (*geometry.identifications.Get(copyedgeidentification));
+
+	if (csi.Identifyable (mesh[frompi], mesh[topi]))
+	  mesh.GetIdentifications().Add(frompi, topi, copyedgeidentification);
+	else if (csi.Identifyable (mesh[topi], mesh[frompi]))
+	  mesh.GetIdentifications().Add(topi, frompi, copyedgeidentification);
+	else
+	  {
+	    cerr << "edgeflw.cpp: should identify, but cannot";
+	    exit(1);
+	  }
+	/*
+	  (*testout) << "Add Identification from CopyEdge, p1 = " 
+	  << mesh[PointIndex(frompi)] << ", p2 = " 
+	  << mesh[PointIndex(topi)] << endl;
+
+	  mesh.GetIdentifications().Add(frompi, topi, copyedgeidentification);
+	*/
+      }
+
+    int oldns = mesh.GetNSeg();
+    for (i = 1; i <= oldns; i++)
+      {
+	// real copy, since array might be reallocated !!
+	const Segment oldseg = mesh.LineSegment(i);
+	if (oldseg.edgenr != copyfromedge)
+	  continue;
+	if (oldseg.seginfo == 0)
+	  continue;
+
+	int pi1 = oldseg.p1;
+	int pi2 = oldseg.p2;
+
+	int npi1 = geometry.identifications.Get(copyedgeidentification)
+	  -> GetIdentifiedPoint (mesh, pi1);
+	int npi2 = geometry.identifications.Get(copyedgeidentification)
+	  -> GetIdentifiedPoint (mesh, pi2);
+
+	Segment seg;
+
+	for (k = 1; k <= refedges.Size(); k++)
+	  {
+	    int inv = refedgesinv.Get(k);
+
+	    // other edge is inverse
+	    if (oldseg.seginfo == 1)
+	      inv = !inv;
+
+	    //	  (*testout) << "inv, now = " << inv << endl;
+
+	    if (inv)
+	      {
+		seg.p1 = npi1;
+		seg.p2 = npi2;
+	      }
+	    else
+	      {
+		seg.p1 = npi2;
+		seg.p2 = npi1;
+	      }
+	    seg.si = refedges.Get(k).si;
+	    seg.domin = refedges.Get(k).domin;
+	    seg.domout = refedges.Get(k).domout;
+	    seg.tlosurf = refedges.Get(k).tlosurf;
+	    seg.edgenr = refedges.Get(k).edgenr;
+	    seg.surfnr1 = refedges.Get(k).surfnr1;
+	    seg.surfnr2 = refedges.Get(k).surfnr2;
+	    seg.seginfo = 0;
+	    if (k == 1) seg.seginfo = refedgesinv.Get(k) ? 2 : 1;
+	    mesh.AddSegment (seg);
+	    //	  (*testout) << "copy seg " << seg.p1 << "-" << seg.p2 << endl;
+#ifdef DEVELOP
+
+	    (*testout) << "copy seg, face = " << seg.si << ": " 
+		       << " inv = " << inv << ", refinv = " << refedgesinv.Get(k)
+		       << mesh.Point(seg.p1) << ", " << mesh.Point(seg.p2) << endl;
+#endif
+
+	  }
+      
+      }   
+  }
+  
+
+
+
+
+
+
+  void EdgeCalculation :: 
+  FindClosedSurfaces (double h, Mesh & mesh)
+  {
+    // if there is no special point at a sphere, one has to add a segment pair
+  
+    int i, j; 
+    int nsol; 
+    int nsurf = geometry.GetNSurf();
+    int layer;
+
+    BitArray pointatsurface (nsurf);
+    Point<3> p1, p2;
+    Vec<3> nv, tv;
+    Solid * tansol;
+    ARRAY<int> tansurfind;
+    //  const Solid * sol;
+
+    nsol = geometry.GetNTopLevelObjects();
+
+
+    pointatsurface.Clear();
+  
+    /*
+      for (i = 1; i <= specpoints.Size(); i++)
+      {
+      int classrep;
+
+      classrep = geometry.GetSurfaceClassRepresentant (specpoints[i].s1);
+      pointatsurface.Set (classrep);
+      classrep = geometry.GetSurfaceClassRepresentant (specpoints[i].s2);
+      pointatsurface.Set (classrep);
+      //      pointatsurface.Set (specpoints[i].s1);
+      //      pointatsurface.Set (specpoints[i].s2);
+      }
+    */
+    for (i = 1; i <= mesh.GetNSeg(); i++)
+      {
+	const Segment & seg = mesh.LineSegment(i);
+	int classrep;
+
+#ifdef DEVELOP      
+	(*testout) << seg.surfnr1 << ", " << seg.surfnr2 << ", si = " << seg.si << endl;
+#endif
+	classrep = geometry.GetSurfaceClassRepresentant (seg.si);
+
+	pointatsurface.Set (classrep);
+      }
+
+  
+    for (i = 0; i < nsurf; i++)
+      {
+	int classrep = geometry.GetSurfaceClassRepresentant (i);
+
+	if (!pointatsurface.Test(classrep))
+	  {
+	    const Surface * s = geometry.GetSurface(i);
+	    p1 = s -> GetSurfacePoint();
+	    s -> GetNormalVector (p1, nv);
+		    
+	    double hloc = 
+	      min2 (s->LocH (p1, 3, 1, h), mesh.GetH(p1));
+
+	    tv = nv.GetNormal ();
+	    tv *=  (hloc / tv.Length());
+	    p2 = p1 + tv;
+	    s->Project (p2);
+	  
+		    
+	    Segment seg1;
+	    seg1.si = i;
+	    seg1.domin = -1;
+	    seg1.domout = -1;
+
+	    Segment seg2;
+	    seg2.si = i;
+	    seg2.domin = -1;
+	    seg2.domout = -1;
+
+	    seg1.surfnr1 = i;
+	    seg2.surfnr1 = i;
+
+	    for (j = 0; j < nsol; j++)
+	      {
+		if (geometry.GetTopLevelObject(j)->GetSurface())
+		  continue;
+
+		const Solid * sol = geometry.GetTopLevelObject(j)->GetSolid();
+		sol -> TangentialSolid (p1, tansol);
+		layer = geometry.GetTopLevelObject(j)->GetLayer();
+
+		if (tansol)
+		  {
+		    tansol -> GetSurfaceIndices (tansurfind);
+		
+		    if (tansurfind.Size() == 1 && tansurfind.Get(1) == i)
+		      {
+			if (!tansol->VectorIn(p1, nv))
+			  {
+			    seg1.domin = j;
+			    seg2.domin = j;
+			    seg1.tlosurf = j;
+			    seg2.tlosurf = j;
+			  }
+			else
+			  {
+			    seg1.domout = j;
+			    seg2.domout = j;
+			    seg1.tlosurf = j;
+			    seg2.tlosurf = j;
+			  }
+			//        seg.s2 = i;
+			//        seg.invs1 = surfaces[i] -> Inverse();
+			//        seg.invs2 = ! (surfaces[i] -> Inverse());
+		      }
+		    delete tansol;
+		  }
+	      }
+
+
+	    if (seg1.domin != -1 || seg1.domout != -1)
+	      {
+		mesh.AddPoint (p1, layer);
+		mesh.AddPoint (p2, layer);
+		seg1.p1 = mesh.GetNP()-1;
+		seg1.p2 = mesh.GetNP();
+		seg2.p2 = mesh.GetNP()-1;
+		seg2.p1 = mesh.GetNP();
+		seg1.geominfo[0].trignum = 1;
+		seg1.geominfo[1].trignum = 1;
+		seg2.geominfo[0].trignum = 1;
+		seg2.geominfo[1].trignum = 1;
+		mesh.AddSegment (seg1);
+		mesh.AddSegment (seg2);
+
+		PrintMessage (5, "Add line segment to smooth surface");
+
+#ifdef DEVELOP
+		(*testout) << "Add segment at smooth surface " << i;
+		if (i != classrep) (*testout) << ", classrep = " << classrep;
+		(*testout) << ": "
+			   << mesh.Point (mesh.GetNP()-1) << " - "
+			   << mesh.Point (mesh.GetNP()) << endl;
+#endif
+	      }
+	  }
+      }
+  }
+
+}
diff --git a/Netgen/libsrc/csg/edgeflw.hpp b/Netgen/libsrc/csg/edgeflw.hpp
new file mode 100644
index 0000000000..175d2f164d
--- /dev/null
+++ b/Netgen/libsrc/csg/edgeflw.hpp
@@ -0,0 +1,90 @@
+#ifndef FILE_EDGEFLW
+#define FILE_EDGEFLW
+
+/**************************************************************************/
+/* File:   edgeflw.hh                                                     */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Okt. 95                                                    */
+/**************************************************************************/
+
+/*
+  
+   Edge - following function and
+   Projection to edge of implicitly given edge
+
+*/
+ 
+
+/**
+  Calculates edges.
+  The edges of a solid geometry are computed. Special
+  points have to be given.
+ */
+extern void CalcEdges (const CSGeometry & geometry,
+                       const ARRAY<SpecialPoint> & specpoints,
+                       double h, Mesh & mesh);
+
+
+
+
+
+class EdgeCalculation
+{
+  const CSGeometry & geometry;
+  const ARRAY<SpecialPoint> & specpoints;
+  int cntedge;
+public:
+  EdgeCalculation (const CSGeometry & ageometry,
+		   const ARRAY<SpecialPoint> & aspecpoints);
+
+  void Calc(double h, Mesh & mesh);
+
+
+private:
+  void CalcEdges1 (double h, Mesh & mesh);
+
+
+  void FollowEdge (int pi1, int & ep, int & pos,
+		   const ARRAY<SpecialPoint> & hsp,
+		   double h, const Mesh & mesh,
+		   ARRAY<Point<3> > & edgepoints,
+		   ARRAY<double> & curvelength);
+		   
+
+  void AnalyzeEdge (int s1, int s2, int pos, int layer,
+		    const ARRAY<Point<3> > & edgepoints,
+		    ARRAY<Segment> & refedges,
+		    ARRAY<int> & refedgesinv);
+
+  void StoreEdge (const ARRAY<Segment> & refedges,
+		  const ARRAY<int> & refedgesinv,
+		  const ARRAY<Point<3> > & edgepoints,
+		  const ARRAY<double> & curvelength,
+		  int layer,
+		  Mesh & mesh);
+
+  void StoreShortEdge (const ARRAY<Segment> & refedges,
+		       const ARRAY<int> & refedgesinv,
+		       const ARRAY<Point<3> > & edgepoints,
+		       const ARRAY<double> & curvelength,
+		       int layer,
+		       Mesh & mesh);
+
+  void CopyEdge (const ARRAY<Segment> & refedges,
+		 const ARRAY<int> & refedgesinv,
+		 int copyfromedge, 
+		 const Point<3> & fromstart, const Point<3> & fromend,
+		 const Point<3> & tostart, const Point<3> & toend,
+		 int copyedgeidentification,
+		 int layer,
+		 Mesh & mesh);
+
+  
+  void SplitEqualOneSegEdges (Mesh & mesh);
+  void FindClosedSurfaces (double h, Mesh & mesh);
+
+};
+
+
+
+#endif
diff --git a/Netgen/libsrc/csg/explicitcurve2d.cpp b/Netgen/libsrc/csg/explicitcurve2d.cpp
new file mode 100644
index 0000000000..b1eef537c8
--- /dev/null
+++ b/Netgen/libsrc/csg/explicitcurve2d.cpp
@@ -0,0 +1,160 @@
+#include <mystdlib.h>
+#include <csg.hpp>
+
+namespace netgen
+{
+ExplicitCurve2d :: ExplicitCurve2d ()
+  {
+    ;
+  }
+  
+  
+void ExplicitCurve2d :: Project (Point<2> & p) const
+  {
+  double t;
+  t = ProjectParam (p);
+  p = Eval (t);
+  }
+
+double ExplicitCurve2d :: NumericalProjectParam (const Point<2> & p, double lb, double ub) const
+  {
+  double t;
+  Vec<2> tan;
+  Vec<2> curv;
+  Point<2> cp;
+  double f, fl, fu;
+  int cnt;
+  
+  tan = EvalPrime (lb);
+  cp = Eval (lb);
+  fl = tan * (cp - p);
+  if (fl > 0)			// changed by wmf, originally fl >= 0
+    {
+      //      cerr << "tan = " << tan << " cp - p = " << (cp - p) << endl;
+      //      cerr << "ExplicitCurve2d::NumericalProject: lb wrong" << endl;
+      return 0;
+    }
+  
+  tan = EvalPrime (ub);
+  cp = Eval (ub);
+  fu = tan * (cp - p);
+  if (fu < 0)			// changed by wmf, originally fu <= 0
+    {
+      //    cerr << "tan = " << tan << " cp - p = " << (cp - p) << endl;
+      //    cerr << "ExplicitCurve2d::NumericalProject: ub wrong" << endl;
+    return 0;
+    }
+    
+  cnt = 0;
+  while (ub - lb > 1e-12 && fu - fl > 1e-12)
+    {
+    cnt++;
+    if (cnt > 50)
+      {
+      (*testout) << "Num Proj, cnt = " << cnt << endl;
+      }
+     
+    t = (lb * fu - ub * fl) / (fu - fl);
+    if (t > 0.9 * ub + 0.1 * lb) t = 0.9 * ub + 0.1 * lb;
+    if (t < 0.1 * ub + 0.9 * lb) t = 0.1 * ub + 0.9 * lb;
+    
+    tan = EvalPrime (t);
+    cp = Eval (t);
+    f = tan * (cp - p);
+    
+    if (f >= 0)
+      {
+      ub = t;
+      fu = f;
+      }
+    else
+      {
+      lb = t;
+      fl = f;
+      }
+    }
+    
+  return t;
+  }
+
+
+Vec<2> ExplicitCurve2d :: Normal (double t) const
+{
+  Vec<2> tan = EvalPrime (t);
+  tan.Normalize();
+  return Vec<2> (tan(1), -tan(0));
+}
+
+
+void ExplicitCurve2d :: NormalVector (const Point<2> & p, Vec<2> & n) const
+  {
+  double t = ProjectParam (p);
+  n = Normal (t);
+  }
+
+
+Point<2> ExplicitCurve2d :: CurvCircle (double t) const
+  {
+  Point<2> cp;
+  Vec<2> tan, n, curv;
+  double den;
+  
+  cp = Eval (t);
+  tan = EvalPrime (t);
+  n = Normal (t);
+  curv = EvalPrimePrime (t);
+  
+  den = n * curv;
+  if (fabs (den) < 1e-12)
+    return cp + 1e12 * n;  
+    
+  return cp + (tan.Length2() / den) * n;  
+  }
+
+
+double ExplicitCurve2d :: MaxCurvature () const
+  {
+  double t, tmin, tmax, dt;
+  double curv;
+  Vec<2> tan;
+  double maxcurv;
+
+  maxcurv = 0;  
+  
+  tmin = MinParam ();
+  tmax = MaxParam ();
+  dt = (tmax - tmin) / 1000;
+  for (t = tmin; t <= tmax+dt; t += dt)
+    if (SectionUsed (t))
+      {
+      tan = EvalPrime (t);
+      curv = fabs ( (Normal(t) * EvalPrimePrime(t)) / tan.Length2());
+      if (curv > maxcurv) maxcurv = curv; 
+      }
+  return maxcurv;
+  }  
+  
+double ExplicitCurve2d :: MaxCurvatureLoc (const Point<2> & p, double rad) const
+  {
+  double t, tmin, tmax, dt;
+  double curv;
+  Vec<2> tan;
+  double maxcurv;
+
+  maxcurv = 0;  
+  
+  tmin = MinParam ();
+  tmax = MaxParam ();
+  dt = (tmax - tmin) / 1000;
+  for (t = tmin; t <= tmax+dt; t += dt)
+    if (Dist (Eval(t), p) < rad)
+      {
+      tan = EvalPrime (t);
+      curv = fabs ( (Normal(t) * EvalPrimePrime(t)) / tan.Length2());
+      if (curv > maxcurv) maxcurv = curv; 
+      }
+    
+  return maxcurv;
+  }  
+  
+}
diff --git a/Netgen/libsrc/csg/explicitcurve2d.hpp b/Netgen/libsrc/csg/explicitcurve2d.hpp
new file mode 100644
index 0000000000..af405aed3c
--- /dev/null
+++ b/Netgen/libsrc/csg/explicitcurve2d.hpp
@@ -0,0 +1,109 @@
+#ifndef FILE_EXPLICITCURVE2D
+#define FILE_EXPLICITCURVE2D
+
+/**************************************************************************/
+/* File:   explicitcurve2d.hh                                             */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   14. Oct. 96                                                    */
+/**************************************************************************/
+
+/*
+
+  Explicit 2D Curve repesentation
+
+*/
+
+
+
+///
+class ExplicitCurve2d : public Curve2d
+{
+public:
+  ///
+  ExplicitCurve2d ();
+
+  ///
+  virtual void Project (Point<2> & p) const;
+  ///
+  virtual double ProjectParam (const Point<2> & p) const = 0;
+  ///
+  virtual double NumericalProjectParam (const Point<2> & p, double lb, double ub) const;
+  ///
+  virtual double MinParam () const = 0;
+  ///
+  virtual double MaxParam () const = 0;
+  ///
+  virtual Point<2> Eval (double t) const = 0;
+  ///
+  virtual Vec<2> EvalPrime (double t) const = 0;
+  ///
+  virtual Vec<2> Normal (double t) const;
+  ///
+  virtual void NormalVector (const Point<2> & p, Vec<2> & n) const;
+  ///
+  virtual Vec<2> EvalPrimePrime (double t) const = 0;
+
+  ///
+  virtual double MaxCurvature () const;
+  ///
+  virtual double MaxCurvatureLoc (const Point<2> & p, double rad) const;
+
+  ///
+  virtual Point<2> CurvCircle (double t) const;
+  ///
+  virtual void Print (ostream & /* str */) const { };
+  
+  ///
+  virtual int SectionUsed (double /* t */) const { return 1; }
+  ///
+  virtual void Reduce (const Point<2> & /* p */, double /* rad */) { };
+  ///
+  virtual void UnReduce () { };
+}; 
+  
+  
+///
+class BSplineCurve2d : public ExplicitCurve2d
+{
+  ///
+  ARRAY<Point<2> > points;
+  ///
+  ARRAY<int> intervallused;
+  ///
+  int redlevel;
+  
+public:
+  ///
+  BSplineCurve2d ();
+  ///
+  void AddPoint (const Point<2> & apoint);
+
+  bool Inside (const Point<2> & p, double & dist) const;
+  
+  ///
+  virtual double ProjectParam (const Point<2> & p) const;
+  ///
+  virtual double MinParam () const { return 0; }
+  ///
+  virtual double MaxParam () const { return points.Size(); }
+  ///
+  virtual Point<2> Eval (double t) const;
+  ///
+  virtual Vec<2> EvalPrime (double t) const;  
+  ///
+  virtual Vec<2> EvalPrimePrime (double t) const;
+  ///
+  virtual void Print (ostream & str) const;
+
+  ///
+  virtual int SectionUsed (double t) const;
+  ///
+  virtual void Reduce (const Point<2> & p, double rad);
+  ///
+  virtual void UnReduce ();
+};  
+
+
+
+
+#endif
diff --git a/Netgen/libsrc/csg/extrusion.cpp b/Netgen/libsrc/csg/extrusion.cpp
new file mode 100644
index 0000000000..acf9b863bc
--- /dev/null
+++ b/Netgen/libsrc/csg/extrusion.cpp
@@ -0,0 +1,175 @@
+#include <mystdlib.h>
+
+#include <linalg.hpp>
+#include <csg.hpp>
+
+namespace netgen
+{
+
+
+
+  ExtrusionSurface :: ExtrusionSurface (const Point<3> & ap0,
+					const Vec<3> & aex, 
+					const Vec<3> & aey,
+					BSplineCurve2d * acurve,
+					int asegnr)
+    : p0(ap0), ex(aex), ey(aey), curve(acurve), segnr(asegnr)
+  {
+    ;
+  }
+  
+  ExtrusionSurface :: ~ExtrusionSurface ()
+  {
+    ;
+  }
+
+  void ExtrusionSurface :: DefineTangentialPlane (const Point<3> & ap1, 
+						  const Point<3> & ap2)
+  {
+    ;
+  }
+
+  void ExtrusionSurface :: ToPlane (const Point<3> & p3d, Point<2> & pplane, 
+				    double h, int & zone) const
+  {
+    ;
+  }
+  
+  void ExtrusionSurface :: FromPlane (const Point<2> & pplane, 
+				      Point<3> & p3d, double h) const
+  {
+    ;
+  }
+  
+
+  void ExtrusionSurface :: Project (Point<3> & p) const
+  {
+    ;
+  }
+
+
+  double ExtrusionSurface :: CalcFunctionValue (const Point<3> & point) const
+  {
+    return 0;
+  }
+
+  void ExtrusionSurface :: CalcGradient (const Point<3> & point, Vec<3> & grad) const
+  {
+    ;
+  }
+
+  Point<3> ExtrusionSurface :: GetSurfacePoint () const
+  {
+    return Point<3> (0,0,0);
+  }
+
+  double ExtrusionSurface :: HesseNorm () const
+  {
+    return 1;
+  }
+
+  void ExtrusionSurface :: Print (ostream & str) const
+  {
+    ;
+  }
+
+  void ExtrusionSurface :: GetTriangleApproximation (TriangleApproximation & tas, 
+						     const Box<3> & boundingbox, 
+						     double facets) const
+  {
+    Point<2> p2d;
+    Point<3> p;
+    int n = int(facets)+1;
+    Vec<3> ez = Cross (ex, ey);
+    cout << "ex = " << ex << endl;
+    cout << "ey = " << ey << endl;
+    for (double t = 0; t < 1.0001; t += 1.0 / n)
+      {
+	cout << "t = " << t << endl;
+	p2d = curve -> Eval (segnr+t);
+	p = p0 + p2d(0) * ex + p2d(1) * ey;
+	cout << "p2d = " << p2d << endl;
+	cout << "add point " << p << endl;
+	tas.AddPoint (p);
+	tas.AddPoint (p + ez);
+      }
+
+    for (int i = 0; i < n; i++)
+      {
+	cout << "add trig " << endl;
+	tas.AddTriangle (TATriangle (0, 2*i, 2*i+2, 2*i+1));
+	tas.AddTriangle (TATriangle (0, 2*i+2, 2*i+3, 2*i+1));
+      }
+  }
+  
+
+
+
+Extrusion :: Extrusion (const Point<3> & ap0,
+			const Vec<3> & aex, 
+			const Vec<3> & aey,
+			const ARRAY< Point<2> > & points)
+  : p0(ap0), ex(aex), ey(aey)
+{
+  int i;
+  
+  ex.Normalize();
+  ey -= (ex*ey) * ex;
+  ey.Normalize();
+
+  for (i = 0; i < points.Size(); i++)
+    curve.AddPoint (points[i]);
+
+  surfs.SetSize (points.Size()/2);
+  for (i = 0; i < surfs.Size(); i++)
+    surfs = new ExtrusionSurface (p0, ex, ey, &curve, i);
+}
+
+Extrusion :: ~Extrusion ()
+{
+  int i;
+  for (i = 0; i < surfs.Size(); i++)
+    delete surfs[i];
+}
+ 
+
+INSOLID_TYPE Extrusion :: BoxInSolid (const BoxSphere<3> & box) const
+{
+  Vec<3> p0c = box.Center() - p0;
+  Point<2> p2d (ex*p0c, ey*p0c);
+  double r = box.Diam() / 2;
+  double dist;
+  bool inside =
+    curve.Inside (p2d, dist);
+
+  if (inside && dist > r) return IS_INSIDE;
+  if (!inside && dist > r) return IS_OUTSIDE;
+  return DOES_INTERSECT;
+}
+
+
+INSOLID_TYPE Extrusion :: PointInSolid (const Point<3> & p,
+					double eps) const
+{
+  Vec<3> p0c = p - p0;
+  Point<2> p2d (ex*p0c, ey*p0c);
+  double dist;
+  bool inside =
+    curve.Inside (p2d, dist);
+  
+  if (dist < eps) return DOES_INTERSECT;
+  if (inside) return IS_INSIDE;
+  return IS_OUTSIDE;
+}
+
+
+INSOLID_TYPE Extrusion :: VecInSolid (const Point<3> & p,
+				      const Vec<3> & v,
+				      double eps) const
+{
+  Point<3> p2 = p + (1e-3/(v.Length()+1e-16)) * v;
+  return PointInSolid (p2, eps);
+}
+
+
+}
diff --git a/Netgen/libsrc/csg/extrusion.hpp b/Netgen/libsrc/csg/extrusion.hpp
new file mode 100644
index 0000000000..ff5a47b4e1
--- /dev/null
+++ b/Netgen/libsrc/csg/extrusion.hpp
@@ -0,0 +1,89 @@
+#ifndef FILE_EXTRUSION
+#define FILE_EXTRUSION
+
+/**************************************************************************/
+/* File:   extrusion.hpp                                                  */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   17. Mar. 2003                                                  */
+/**************************************************************************/
+
+/*
+
+extrusion of 2D curve
+  
+*/
+
+
+class ExtrusionSurface : public Surface
+{
+protected:
+  BSplineCurve2d * curve;
+  int segnr;
+  Point<3> p0;
+  Vec<3> ex, ey;
+public:
+  ExtrusionSurface (const Point<3> & ap0,
+		    const Vec<3> & aex, 
+		    const Vec<3> & aey,
+		    BSplineCurve2d * acurve,
+		    int asegnr);
+  virtual ~ExtrusionSurface ();
+
+  virtual void DefineTangentialPlane (const Point<3> & ap1, 
+				      const Point<3> & ap2);
+
+  virtual void ToPlane (const Point<3> & p3d, Point<2> & pplane, 
+			double h, int & zone) const;
+  
+  virtual void FromPlane (const Point<2> & pplane, 
+			  Point<3> & p3d, double h) const;
+  
+
+  virtual void Project (Point<3> & p) const;
+
+
+  virtual double CalcFunctionValue (const Point<3> & point) const;
+
+  virtual void CalcGradient (const Point<3> & point, Vec<3> & grad) const;
+
+  virtual Point<3> GetSurfacePoint () const;
+
+  virtual double HesseNorm () const;
+
+  virtual void Print (ostream & str) const;  
+  virtual void GetTriangleApproximation (TriangleApproximation & tas, 
+					 const Box<3> & boundingbox, 
+					 double facets) const;
+};
+
+
+class Extrusion : public Primitive
+{
+protected:
+  Point<3> p0;
+  Vec<3> ex, ey;
+  BSplineCurve2d curve;
+  ARRAY<ExtrusionSurface*> surfs;
+
+public:
+  Extrusion (const Point<3> & ap0,
+	     const Vec<3> & aex, 
+	     const Vec<3> & aey,
+	     const ARRAY< Point<2> > & points);
+  virtual ~Extrusion ();
+  
+  
+
+  virtual INSOLID_TYPE BoxInSolid (const BoxSphere<3> & box) const;
+  virtual INSOLID_TYPE PointInSolid (const Point<3> & p,
+				     double eps) const;
+  virtual INSOLID_TYPE VecInSolid (const Point<3> & p,
+				   const Vec<3> & v,
+				   double eps) const;
+
+  virtual int GetNSurfaces() const { return surfs.Size(); }
+  virtual Surface & GetSurface (int i) { return *surfs[i]; }
+  virtual const Surface & GetSurface (int i) const { return *surfs[i]; }
+};
+
+#endif
diff --git a/Netgen/libsrc/csg/gencyl.cpp b/Netgen/libsrc/csg/gencyl.cpp
new file mode 100644
index 0000000000..f079879738
--- /dev/null
+++ b/Netgen/libsrc/csg/gencyl.cpp
@@ -0,0 +1,209 @@
+#include <linalg.hpp>
+#include <csg.hpp>
+
+
+namespace netgen
+{
+
+GeneralizedCylinder :: GeneralizedCylinder (ExplicitCurve2d & acrosssection,
+					    Point<3> ap, Vec<3> ae1, Vec<3> ae2)
+  : crosssection(acrosssection)
+{
+  planep = ap;
+  planee1 = ae1;
+  planee2 = ae2;
+  planee3 = Cross (planee1, planee2);
+  (*testout) << "Vecs = " << planee1 << " " << planee2 << " " << planee3 << endl;
+};
+  
+
+void GeneralizedCylinder :: Project (Point<3> & p) const
+{
+  Point<2> p2d;
+  double z;
+  
+  p2d = Point<2> (planee1 * (p - planep), planee2 * (p - planep));
+  z = planee3 * (p - planep);
+
+  crosssection.Project (p2d);
+  
+  p = planep + p2d(0) * planee1 + p2d(1) * planee2 + z * planee3;
+}
+
+int GeneralizedCylinder ::BoxInSolid (const BoxSphere<3> & box) const
+{
+  Point<3> p3d;
+  Point<2> p2d, projp;
+  double t;
+  Vec<2> tan, n;
+  
+  p3d = box.Center();
+  
+  p2d = Point<2> (planee1 * (p3d - planep), planee2 * (p3d - planep));
+  t = crosssection.ProjectParam (p2d);
+  
+  projp = crosssection.Eval (t);
+  tan = crosssection.EvalPrime (t);
+  n(0) = tan(1);
+  n(1) = -tan(0);
+    
+  if (Dist (p2d, projp) < box.Diam()/2)
+    return 2;
+    
+  if (n * (p2d - projp) > 0) 
+    {
+      return 0;   
+    }
+    
+  return 1;
+}
+
+double GeneralizedCylinder :: CalcFunctionValue (const Point<3> & point) const
+{
+  Point<2> p2d, projp;
+  double t;
+  Vec<2> tan, n;
+  
+  
+  p2d = Point<2> (planee1 * (point - planep), planee2 * (point - planep));
+  t = crosssection.ProjectParam (p2d);
+  
+  projp = crosssection.Eval (t);
+  tan = crosssection.EvalPrime (t);
+  n(0) = tan(1);
+  n(1) = -tan(0);
+    
+  n /= n.Length();
+  return n * (p2d - projp);
+}
+  
+void GeneralizedCylinder :: CalcGradient (const Point<3> & point, Vec<3> & grad) const
+{
+  Point<2> p2d, projp;
+  double t;
+  Vec<2> tan, n;
+  
+  
+  p2d = Point<2> (planee1 * (point - planep), planee2 * (point - planep));
+  t = crosssection.ProjectParam (p2d);
+  
+  projp = crosssection.Eval (t);
+  tan = crosssection.EvalPrime (t);
+  n(0) = tan(1);
+  n(1) = -tan(0);
+    
+  n /= n.Length();
+  grad = n(0) * planee1 + n(1) * planee2;
+}
+  
+  
+void GeneralizedCylinder :: CalcHesse (const Point<3> & point, Mat<3> & hesse) const
+{
+  Point<2> p2d, projp;
+  double t, dist, val;
+  Point<2> curvp;
+  Vec<2> curvpp;
+  Mat<2> h2d;
+  Mat<3,2> vmat;
+  int i, j, k, l;
+  
+  p2d = Point<2> (planee1 * (point - planep), planee2 * (point - planep));
+  t = crosssection.ProjectParam (p2d);
+
+  curvp = crosssection.CurvCircle (t);
+  curvpp = p2d-curvp;
+  dist = curvpp.Length();
+  curvpp /= dist;
+    
+  h2d(1, 1) = (1 - curvpp(0) * curvpp(0) ) / dist;  
+  h2d(1, 2) = h2d(2, 1) = (- curvpp(0) * curvpp(1) ) / dist;  
+  h2d(2, 2) = (1 - curvpp(1) * curvpp(1) ) / dist;  
+  
+  vmat(0,0) = planee1(0);
+  vmat(1,0) = planee1(1);
+  vmat(2,0) = planee1(2);
+  vmat(0,1) = planee2(0);
+  vmat(1,1) = planee2(1);
+  vmat(2,1) = planee2(2);
+  
+  for (i = 0; i < 3; i++)
+    for (j = 0; j < 3; j++)
+      {
+	val = 0;
+	for (k = 0; k < 2; k++)
+	  for (l = 0; l < 2; l++)
+	    val += vmat(i,k) * h2d(k,l) * vmat(j,l);
+	hesse(i,j) = val;
+      }
+}
+
+
+double GeneralizedCylinder :: HesseNorm () const
+{
+  return crosssection.MaxCurvature();
+}
+
+double GeneralizedCylinder :: MaxCurvatureLoc (const Point<3> & c, double rad) const
+{
+  Point<2> c2d = Point<2> (planee1 * (c - planep), planee2 * (c - planep));
+  return crosssection.MaxCurvatureLoc(c2d, rad);
+}
+  
+
+  
+Point<3> GeneralizedCylinder :: GetSurfacePoint () const
+{
+  Point<2> p2d; 
+  p2d = crosssection.Eval(0);
+  return planep + p2d(0) * planee1 + p2d(1) * planee2;
+}
+
+void GeneralizedCylinder :: Reduce (const BoxSphere<3> & box)
+{
+  Point<2> c2d = Point<2> (planee1 * (box.Center() - planep), 
+			   planee2 * (box.Center() - planep));
+  crosssection.Reduce (c2d, box.Diam()/2);
+}
+
+void GeneralizedCylinder :: UnReduce ()
+{
+  crosssection.UnReduce ();
+}
+
+void GeneralizedCylinder :: Print (ostream & str) const
+{
+  str << "Generalized Cylinder" << endl;
+  crosssection.Print (str);
+}
+  
+#ifdef MYGRAPH  
+void GeneralizedCylinder :: Plot (const class ROT3D & rot) const
+{
+  Point<2> p2d;
+  Point<3> p, oldp;
+  double t, tmin, tmax, dt;
+  
+  tmin = crosssection.MinParam();
+  tmax = crosssection.MaxParam();
+  dt = (tmax - tmin)/ 500;
+  
+  p2d = crosssection.Eval(tmin);
+  p = planep + p2d(0) * planee1 + p2d(1) * planee2;
+  
+  for (t = tmin; t <= tmax+dt; t += dt)
+    {
+      if (crosssection.SectionUsed (t))
+	MySetColor (RED);
+      else
+	MySetColor (BLUE);
+      
+      oldp = p;
+      p2d = crosssection.Eval(t);
+      p = planep + p2d(0) * planee1 + p2d(1) * planee2;
+      MyLine3D (p, oldp, rot);
+    }
+
+}
+
+#endif  
+}
diff --git a/Netgen/libsrc/csg/gencyl.hpp b/Netgen/libsrc/csg/gencyl.hpp
new file mode 100644
index 0000000000..424c867a92
--- /dev/null
+++ b/Netgen/libsrc/csg/gencyl.hpp
@@ -0,0 +1,64 @@
+#ifndef FILE_GENCYL
+#define FILE_GENCYL
+
+/**************************************************************************/
+/* File:   gencyl.hh                                                      */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   14. Oct. 96                                                    */
+/**************************************************************************/
+
+/*
+  
+  Generalized Cylinder
+  
+*/
+
+
+///
+class GeneralizedCylinder : public Surface
+{
+  ///
+  ExplicitCurve2d & crosssection;
+  ///
+  Point<3> planep;
+  ///
+  Vec<3> planee1, planee2, planee3;
+  
+  ///  Vec<3> ex, ey, ez;
+  Vec2d e2x, e2y;
+    ///
+  Point<3> cp;
+  
+public:
+  ///
+  GeneralizedCylinder (ExplicitCurve2d & acrosssection,
+		       Point<3> ap, Vec<3> ae1, Vec<3> ae2);
+  
+  ///
+  virtual void Project (Point<3> & p) const;
+  
+  ///
+  virtual int BoxInSolid (const BoxSphere<3> & box) const;
+  /// 0 .. no, 1 .. yes, 2 .. maybe
+  
+  virtual double CalcFunctionValue (const Point<3> & point) const;
+  ///
+  virtual void CalcGradient (const Point<3> & point, Vec<3> & grad) const;
+  ///
+  virtual void CalcHesse (const Point<3> & point, Mat<3> & hesse) const;
+  ///
+  virtual double HesseNorm () const;
+  ///
+  virtual double MaxCurvatureLoc (const Point<3> & c, double rad) const;
+  ///
+  virtual Point<3> GetSurfacePoint () const;
+  ///
+  virtual void Print (ostream & str) const;
+  
+  ///
+  virtual void Reduce (const BoxSphere<3> & box);
+  ///
+  virtual void UnReduce ();
+};  
+
+#endif
diff --git a/Netgen/libsrc/csg/genmesh.cpp b/Netgen/libsrc/csg/genmesh.cpp
new file mode 100644
index 0000000000..62a336e260
--- /dev/null
+++ b/Netgen/libsrc/csg/genmesh.cpp
@@ -0,0 +1,709 @@
+#include <mystdlib.h>
+
+
+// #include <FlexLexer.h>
+
+#include <myadt.hpp>
+
+#include <linalg.hpp>
+#include <csg.hpp>
+#include <stlgeom.hpp>
+#include <meshing.hpp>
+
+namespace netgen
+{
+ARRAY<SpecialPoint> specpoints;
+static ARRAY<MeshPoint> spoints;
+
+#define TCL_OK 0
+#define TCL_ERROR 1
+
+
+static void FindPoints (CSGeometry & geom, Mesh & mesh,
+			const char * filename)
+{
+  int i;
+  PrintMessage (1, "Start Findpoints");
+
+  char * savetask = multithread.task;
+  multithread.task = "Find points";
+
+  for (i = 0; i < geom.GetNUserPoints(); i++)
+    {
+      mesh.AddPoint (geom.GetUserPoint (i));
+      mesh.AddLockedPoint (PointIndex (i+1));
+    }
+
+  SpecialPointCalculation spc;
+
+  if (spoints.Size() == 0)
+    spc.CalcSpecialPoints (geom, spoints);
+
+  PrintMessage (2, "Analyze spec points");
+  spc.AnalyzeSpecialPoints (geom, spoints, specpoints);
+  
+  PrintMessage (5, "done");
+
+  (*testout) << specpoints.Size() << " special points:" << endl;
+  for (i = 0; i < specpoints.Size(); i++)
+    specpoints[i].Print (*testout);
+
+  /*
+  for (i = 1; i <= geom.identifications.Size(); i++)
+    geom.identifications.Elem(i)->IdentifySpecialPoints (specpoints);
+  */
+  multithread.task = savetask;
+}
+
+
+
+static void FindEdges (CSGeometry & geom, Mesh & mesh,
+		       const char * filename)
+{
+  int i, k;
+  
+  EdgeCalculation ec (geom, specpoints);
+  ec.Calc (mparam.maxh, mesh);
+
+  for (i = 1; i <= geom.singedges.Size(); i++)
+    geom.singedges.Elem(i)->FindPointsOnEdge (mesh);
+  for (i = 1; i <= geom.singpoints.Size(); i++)
+    geom.singpoints.Elem(i)->FindPoints (mesh);
+
+  //  SaveEdges (mesh, filename, h, "edges.out");
+
+  for (i = 1; i <= mesh.GetNSeg(); i++)
+    {
+      int ok = 0;
+      for (k = 1; k <= mesh.GetNFD(); k++)
+	if (mesh.GetFaceDescriptor(k).SegmentFits (mesh.LineSegment(i)))
+	  ok = k;
+
+      if (!ok)
+	ok = mesh.AddFaceDescriptor (FaceDescriptor (mesh.LineSegment(i)));
+
+      mesh.LineSegment(i).si = ok;
+    }
+
+  (*testout) << "identify points after line meshing" << endl;
+  for (i = 0; i < geom.identifications.Size(); i++)
+    geom.identifications[i]->IdentifyPoints (mesh);
+  for (i = 0; i < geom.identifications.Size(); i++)
+    geom.identifications[i]->IdentifyFaces (mesh);
+
+  //  mesh.Save ("lines.vol");
+}  
+
+
+static void MeshSurface (CSGeometry & geom, Mesh & mesh)
+{
+  int i, j, k;
+  int changed;
+
+  char * savetask = multithread.task;
+  multithread.task = "Surface meshing";
+
+  
+  ARRAY<Segment> segments;
+  int noldp = mesh.GetNP();
+
+  double starttime = GetTime();
+
+
+  // find master faces from identified
+  ARRAY<int> masterface(mesh.GetNFD());
+  for (i = 1; i <= mesh.GetNFD(); i++)
+    masterface.Elem(i) = i;
+  
+  ARRAY<INDEX_2> fpairs;
+  do
+    {
+      changed = 0;
+      for (i = 0; i < geom.identifications.Size(); i++)
+	{
+	  geom.identifications[i]->GetIdentifiedFaces (fpairs);
+
+	  for (j = 0; j < fpairs.Size(); j++)
+	    {
+	      if (masterface.Get(fpairs[j].I1()) <
+		  masterface.Get(fpairs[j].I2()))
+		{
+		  changed = 1;
+		  masterface.Elem(fpairs[j].I2()) =
+		    masterface.Elem(fpairs[j].I1());
+		}
+	      if (masterface.Get(fpairs[j].I2()) <
+		  masterface.Get(fpairs[j].I1()))
+		{
+		  changed = 1;
+		  masterface.Elem(fpairs[j].I1()) =
+		    masterface.Elem(fpairs[j].I2());
+		}
+	    }
+	}
+    }
+  while (changed);
+
+
+  int bccnt=0;
+  for (k = 0; k < geom.GetNSurf(); k++)
+    bccnt = max2 (bccnt, geom.GetSurface(k)->GetBCProperty());
+
+  for (k = 1; k <= mesh.GetNFD(); k++)
+    {
+      FaceDescriptor & fd = mesh.GetFaceDescriptor(k);
+      const Surface * surf = geom.GetSurface(fd.SurfNr());
+
+      if (fd.TLOSurface() && 
+	  geom.GetTopLevelObject(fd.TLOSurface()-1) -> GetBCProp() > 0)
+	fd.SetBCProperty (geom.GetTopLevelObject(fd.TLOSurface()-1) -> GetBCProp());
+      else if (surf -> GetBCProperty() != -1)
+	fd.SetBCProperty (surf->GetBCProperty());
+      else
+	{
+	  bccnt++;
+	  fd.SetBCProperty (bccnt);
+	}      
+
+      for (int l = 0; l < geom.bcmodifications.Size(); l++)
+	{
+	  if (geom.GetSurfaceClassRepresentant (fd.SurfNr()) == 
+	      geom.GetSurfaceClassRepresentant (geom.bcmodifications[l].si) &&
+	      (fd.DomainIn() == geom.bcmodifications[l].tlonr+1 ||
+	       fd.DomainOut() == geom.bcmodifications[l].tlonr+1))
+	    {
+	      cout << "modify, surfnr = " << fd.SurfNr() << ", dom = " 
+		   << geom.bcmodifications[l].tlonr+1 << endl;
+	      fd.SetBCProperty (geom.bcmodifications[l].bcnr);
+	    }
+	}
+    }
+
+  /*
+  (*testout) << "Face descriptors:" << endl;
+  for (k = 1; k <= mesh.GetNFD(); k++)
+    (*testout) << "fd(" << k << ") = " << mesh.GetFaceDescriptor(k) << endl;
+  */
+
+  // assemble edge hash-table
+  (*testout) << "calc surf before surface" << endl;
+  mesh.CalcSurfacesOfNode();
+
+  for (k = 1; k <= mesh.GetNFD(); k++)
+    {
+      (*testout) << "mesh face " << k << endl;
+      multithread.percent = 100 * k / (mesh.GetNFD()+1e-10);
+
+      if (masterface.Get(k) != k)
+	continue;
+
+      FaceDescriptor & fd = mesh.GetFaceDescriptor(k);
+
+      (*testout) << "Surface " << k << endl;
+      (*testout) << "Face Descriptor: " << fd << endl;
+      PrintMessage (1, "Surface ", k, " / ", mesh.GetNFD());
+
+      int oldnf = mesh.GetNSE();
+      
+      const Surface * surf =
+	geom.GetSurface((mesh.GetFaceDescriptor(k).SurfNr()));
+
+      /*
+      if (surf -> GetBCProperty() != -1)
+	fd.SetBCProperty (surf->GetBCProperty());
+      else
+	{
+	  bccnt++;
+	  fd.SetBCProperty (bccnt);
+	}
+      */
+
+
+      Meshing2Surfaces meshing(*surf, geom.BoundingBox());
+      meshing.SetStartTime (starttime);
+
+      for (PointIndex pi = PointIndex::BASE; 
+	   pi < noldp+PointIndex::BASE; pi++)
+	{
+	  meshing.AddPoint (mesh[pi], pi);
+	}
+  
+      segments.SetSize (0);
+
+      for (i = 1; i <= mesh.GetNSeg(); i++)
+	{
+	  Segment * seg = &mesh.LineSegment(i);
+	  if (seg->si == k)
+	    {
+	      segments.Append (*seg);
+	      (*testout) << "add segment " << seg->p1 << "-" << seg->p2 << endl;
+	    }
+	}
+
+      for (i = 1; i <= geom.identifications.Size(); i++)
+	geom.identifications.Get(i)->
+	  BuildSurfaceElements(segments, mesh, surf);
+
+      // (*testout) << "Mesh surface, elements:" << endl;
+      for (SegmentIndex si = 0; si < segments.Size(); si++)
+	{
+	  PointGeomInfo gi;
+	  gi.trignum = k;
+	  /*
+	  (*testout) << segments[si].p1 << " - " << segments[si].p2 << endl;
+	  (*testout) << mesh[segments[si].p1] << " - " 
+		     << mesh[segments[si].p2] << endl;
+	  */
+	  meshing.AddBoundaryElement (segments[si].p1 + 1 - PointIndex::BASE, 
+				      segments[si].p2 + 1 - PointIndex::BASE, 
+				      gi, gi);
+	}
+
+      double maxh = mparam.maxh;
+      if (fd.DomainIn() != 0)
+	{
+	  const Solid * s1 = 
+	    geom.GetTopLevelObject(fd.DomainIn()-1) -> GetSolid();
+	  if (s1->GetMaxH() < maxh)
+	    maxh = s1->GetMaxH();
+	  maxh = min2(maxh, geom.GetTopLevelObject(fd.DomainIn()-1)->GetMaxH());
+	}
+      if (fd.DomainOut() != 0)
+	{
+	  const Solid * s1 = 
+	    geom.GetTopLevelObject(fd.DomainOut()-1) -> GetSolid();
+	  if (s1->GetMaxH() < maxh)
+	    maxh = s1->GetMaxH();
+	  maxh = min2(maxh, geom.GetTopLevelObject(fd.DomainOut()-1)->GetMaxH());
+	}
+      if (fd.TLOSurface() != 0)
+	{
+	  double hi = geom.GetTopLevelObject(fd.TLOSurface()-1) -> GetMaxH();
+	  if (hi < maxh) maxh = hi;
+	}
+
+      (*testout) << "domin = " << fd.DomainIn() << ", domout = " << fd.DomainOut()
+		 << ", tlo-surf = " << fd.TLOSurface()
+		 << " mpram.maxh = " << mparam.maxh << ", maxh = " << maxh << endl;
+
+
+      MESHING2_RESULT res =
+	meshing.GenerateMesh (mesh, maxh, k);
+
+      if (res != MESHING2_OK)
+	{
+	  PrintError ("Problem in Surface mesh generation");
+	  throw NgException ("Problem in Surface mesh generation");
+	}
+      if (multithread.terminate) return;
+
+      
+      for (i = oldnf+1; i <= mesh.GetNSE(); i++)
+	mesh.SurfaceElement(i).SetIndex (k);
+
+
+      //      mesh.CalcSurfacesOfNode();
+      if (segments.Size())   
+	{ 
+	  // surface was meshed, not copied
+	  PrintMessage (2, "Optimize Surface");
+	  for (i = 1; i <= mparam.optsteps2d; i++)
+	    {
+	      if (multithread.terminate) return;
+
+	      {
+		MeshOptimize2dSurfaces meshopt(geom);
+		meshopt.SetFaceIndex (k);
+		meshopt.SetImproveEdges (0);
+		meshopt.SetMetricWeight (0.2);
+		meshopt.SetWriteStatus (0);
+
+		meshopt.EdgeSwapping (mesh, (i > mparam.optsteps2d/2));
+	      }
+
+	      if (multithread.terminate) return;
+	      {
+		//		mesh.CalcSurfacesOfNode();
+		
+		MeshOptimize2dSurfaces meshopt(geom);
+		meshopt.SetFaceIndex (k);
+		meshopt.SetImproveEdges (0);
+		meshopt.SetMetricWeight (0.2);
+		meshopt.SetWriteStatus (0);
+
+		meshopt.ImproveMesh (mesh);
+	      }
+
+	      {
+		MeshOptimize2dSurfaces meshopt(geom);
+		meshopt.SetFaceIndex (k);
+		meshopt.SetImproveEdges (0);
+		meshopt.SetMetricWeight (0.2);
+		meshopt.SetWriteStatus (0);
+
+		meshopt.CombineImprove (mesh);
+		//		mesh.CalcSurfacesOfNode();
+	      }
+
+	      if (multithread.terminate) return;
+	      {
+		MeshOptimize2dSurfaces meshopt(geom);
+		meshopt.SetFaceIndex (k);
+		meshopt.SetImproveEdges (0);
+		meshopt.SetMetricWeight (0.2);
+		meshopt.SetWriteStatus (0);
+
+		meshopt.ImproveMesh (mesh);
+	      }
+	    }
+	}
+
+
+
+      PrintMessage (3, (mesh.GetNSE() - oldnf), " elements, ", mesh.GetNP(), " points");
+
+#ifdef OPENGL
+      extern void Render();
+      Render();
+#endif
+    }
+
+  mesh.Compress();
+
+
+
+
+
+
+
+  do
+    {
+      changed = 0;
+      for (k = 1; k <= mesh.GetNFD(); k++)
+	{
+	  multithread.percent = 100 * k / (mesh.GetNFD()+1e-10);
+	  
+	  if (masterface.Get(k) == k)
+	    continue;
+
+	  FaceDescriptor & fd = mesh.GetFaceDescriptor(k);
+
+	  (*testout) << "Surface " << k << endl;
+	  (*testout) << "Face Descriptor: " << fd << endl;
+	  PrintMessage (2, "Surface ", k);
+
+	  int oldnf = mesh.GetNSE();
+      
+	  const Surface * surf =
+	    geom.GetSurface((mesh.GetFaceDescriptor(k).SurfNr()));
+
+	  /*
+	  if (surf -> GetBCProperty() != -1)
+	    fd.SetBCProperty (surf->GetBCProperty());
+	  else
+	    {
+	      bccnt++;
+	      fd.SetBCProperty (bccnt);
+	    }
+	  */
+  
+	  segments.SetSize (0);
+	  for (i = 1; i <= mesh.GetNSeg(); i++)
+	    {
+	      Segment * seg = &mesh.LineSegment(i);
+	      if (seg->si == k)
+		segments.Append (*seg);
+	    }
+
+	  for (i = 1; i <= geom.identifications.Size(); i++)
+	    {
+	      geom.identifications.Elem(i)->GetIdentifiedFaces (fpairs);
+	      int found = 0;
+	      for (j = 1; j <= fpairs.Size(); j++)
+		if (fpairs.Get(j).I1() == k || fpairs.Get(j).I2() == k)
+		  found = 1;
+
+	      if (!found)
+		continue;
+
+	      geom.identifications.Get(i)->
+		BuildSurfaceElements(segments, mesh, surf);
+	      if (!segments.Size())
+		break;
+	    }
+
+	  
+	  if (multithread.terminate) return;
+
+	  for (i = oldnf+1; i <= mesh.GetNSE(); i++)
+	    mesh.SurfaceElement(i).SetIndex (k);
+
+
+	  if (!segments.Size())
+	    {
+	      masterface.Elem(k) = k;
+	      changed = 1; 
+	    }
+
+	  PrintMessage (3, (mesh.GetNSE() - oldnf), " elements, ", mesh.GetNP(), " points");
+	}
+      
+#ifdef OPENGL
+      extern void Render();
+      Render();
+#endif
+    }
+  while (changed);
+
+  mesh.SplitSeparatedFaces();
+
+  mesh.CalcSurfacesOfNode();
+
+  multithread.task = savetask;
+}
+
+
+int GenerateMesh (CSGeometry & geom,
+		  Mesh *& mesh,
+		  int perfstepsstart, int perfstepsend,
+		  const char * optstr)
+{
+  extern char geomfilename[];
+  const char * filename = geomfilename;
+
+  int i;
+  char filenametrunc[255];
+  char filenameext[255];
+
+  if (mesh && mesh->GetNSE() &&
+      !geom.GetNSolids())
+    {
+      if (perfstepsstart < MESHCONST_MESHVOLUME)
+	perfstepsstart = MESHCONST_MESHVOLUME;
+    }
+
+
+  
+  strcpy (filenametrunc, filename);
+  char * pos = strstr (filenametrunc, ".geo");
+  if (pos) strcpy (pos, "");
+
+  if (perfstepsstart <= MESHCONST_ANALYSE)
+    {
+      delete mesh;
+      mesh = new Mesh();
+
+      mesh->SetGlobalH (mparam.maxh);
+
+      ARRAY<double> maxhdom(geom.GetNTopLevelObjects());
+      for (i = 0; i < maxhdom.Size(); i++)
+	maxhdom[i] = geom.GetTopLevelObject(i)->GetMaxH();
+
+      mesh->SetMaxHDomain (maxhdom);
+
+      if (mparam.uselocalh)
+	{
+	  //	  double maxsize = globflags.GetNumFlag ("maxsize", 500);
+	  double maxsize = geom.MaxSize(); 
+	  mesh->SetLocalH (Point<3>(-maxsize, -maxsize, -maxsize),
+			   Point<3>(maxsize, maxsize, maxsize),
+			   mparam.grading);
+
+	  if (mparam.meshsizefilename)
+	    {
+	      ifstream msf(mparam.meshsizefilename);
+	      if (msf)
+		mesh->LoadLocalMeshSize (msf);
+	    }
+	}
+
+      spoints.SetSize(0);
+      FindPoints (geom, *mesh, filename);
+      
+      PrintMessage (5, "find points done");
+
+#ifdef LOG_STREAM
+      (*logout) << "Special points found" << endl
+		<< "time = " << GetTime() << " sec" << endl
+		<< "points: " << mesh->GetNP() << endl << endl;
+#endif
+    }
+
+
+  if (multithread.terminate || perfstepsend <= MESHCONST_ANALYSE) 
+    return TCL_OK;
+
+  if (perfstepsstart <= MESHCONST_MESHEDGES)
+    {
+      FindEdges (geom, *mesh, filename);
+      if (multithread.terminate) return TCL_OK;
+#ifdef LOG_STREAM      
+      (*logout) << "Edges meshed" << endl
+		<< "time = " << GetTime() << " sec" << endl
+		<< "points: " << mesh->GetNP() << endl;
+#endif
+      
+      
+      if (multithread.terminate)
+	return TCL_OK;
+  
+
+      if (mparam.uselocalh)
+	{
+	  mesh->CalcLocalH();
+	  mesh->DeleteMesh();
+	  
+	  FindPoints (geom, *mesh, filename);
+	  if (multithread.terminate) return TCL_OK;
+	  FindEdges (geom, *mesh, filename);
+	  if (multithread.terminate) return TCL_OK;
+
+	  mesh->DeleteMesh();
+	  
+	  FindPoints (geom, *mesh, filename);
+	  if (multithread.terminate) return TCL_OK;
+	  FindEdges (geom, *mesh, filename);
+	  if (multithread.terminate) return TCL_OK;
+	}
+    }
+  
+  if (multithread.terminate || perfstepsend <= MESHCONST_MESHEDGES)
+    return TCL_OK;
+
+
+  if (perfstepsstart <= MESHCONST_MESHSURFACE)
+    {
+      MeshSurface (geom, *mesh);  
+      if (multithread.terminate) return TCL_OK;
+      
+#ifdef LOG_STREAM
+      (*logout) << "Surfaces meshed" << endl
+		<< "time = " << GetTime() << " sec" << endl
+		<< "points: " << mesh->GetNP() << endl;
+#endif      
+      
+      if (mparam.uselocalh && 0)
+	{
+	  mesh->CalcLocalH();      
+	  mesh->DeleteMesh();
+
+	  FindPoints (geom, *mesh, filename);
+	  if (multithread.terminate) return TCL_OK;
+	  FindEdges (geom, *mesh, filename);
+	  if (multithread.terminate) return TCL_OK;
+
+	  MeshSurface (geom, *mesh);  
+	  if (multithread.terminate) return TCL_OK;
+	}
+
+#ifdef LOG_STREAM      
+      (*logout) << "Surfaces remeshed" << endl
+		<< "time = " << GetTime() << " sec" << endl
+		<< "points: " << mesh->GetNP() << endl;
+#endif      
+      
+#ifdef STAT_STREAM
+      (*statout) << mesh->GetNSeg() << " & "
+		 << mesh->GetNSE() << " & - &" 
+		 << GetTime() << " & " << endl;
+#endif  
+
+      MeshQuality2d (*mesh);
+      mesh->CalcSurfacesOfNode();
+
+      /*
+	strcpy (filenameext, filenametrunc);
+	strcat (filenameext, ".surf.mesh");
+	WriteFile (WRITE_SURFACE, mesh, geom, filenameext, filename, h);
+      */
+    }
+  
+  if (multithread.terminate || perfstepsend <= MESHCONST_OPTSURFACE)
+    return TCL_OK;
+
+
+  if (perfstepsstart <= MESHCONST_MESHVOLUME)
+    {
+      multithread.task = "Volume meshing";
+      
+      MESHING3_RESULT res =
+	MeshVolume (mparam, *mesh);
+
+      if (res != MESHING3_OK) return TCL_ERROR;
+      
+      if (multithread.terminate) return TCL_OK;
+      
+      RemoveIllegalElements (*mesh);
+      if (multithread.terminate) return TCL_OK;
+
+      MeshQuality3d (*mesh);
+      
+      for (int i = 0; i < geom.GetNTopLevelObjects(); i++)
+	mesh->SetMaterial (i+1, geom.GetTopLevelObject(i)->GetMaterial().c_str());
+      
+
+#ifdef STAT_STREAM
+      (*statout) << GetTime() << " & ";
+#endif      
+      
+#ifdef LOG_STREAM
+      (*logout) << "Volume meshed" << endl
+		<< "time = " << GetTime() << " sec" << endl
+	    << "points: " << mesh->GetNP() << endl;
+#endif
+    }
+
+  if (multithread.terminate || perfstepsend <= MESHCONST_MESHVOLUME)
+    return TCL_OK;
+
+
+  if (perfstepsstart <= MESHCONST_OPTVOLUME)
+    {
+      multithread.task = "Volume optimization";
+      
+      OptimizeVolume (mparam, *mesh, &geom);
+      if (multithread.terminate) return TCL_OK;
+      
+#ifdef STAT_STREAM
+      (*statout) << GetTime() << " & "
+		 << mesh->GetNE() << " & "
+		 << mesh->GetNP() << " " << '\\' << '\\' << " \\" << "hline" << endl;
+#endif      
+
+#ifdef LOG_STREAM      
+      (*logout) << "Volume optimized" << endl
+		<< "time = " << GetTime() << " sec" << endl
+	    << "points: " << mesh->GetNP() << endl;
+#endif
+
+      
+#ifndef TRAFO
+      /*
+      if (&geom)
+	{
+	  ZRefinementOptions opt;
+	  opt.minref = 0;
+	  ZRefinement (*mesh, &geom, opt);
+	}
+      */
+#endif
+    }
+
+  /*
+  cout << (char)7 << (char)7 << endl;
+  cout << "Meshing finished" << endl << endl;
+  cout << setw (4) << mesh->GetNP() << " Points" << endl;
+  cout << setw (4) << mesh->GetNSE() << " Surface Elements" << endl;
+  cout << setw (4) << mesh->GetNE() << " Volume Elements" << endl;
+  cout << setw (4) << int (GetTime()) << " Seconds" << endl;
+  */
+
+  /*
+    strcpy (filenameext, filenametrunc);
+    strcat (filenameext, ".vol");
+    mesh->Save (filenameext);	
+  */
+
+  return TCL_OK;
+}
+}
diff --git a/Netgen/libsrc/csg/geometry.cpp b/Netgen/libsrc/csg/geometry.cpp
new file mode 100644
index 0000000000..14806ee9cb
--- /dev/null
+++ b/Netgen/libsrc/csg/geometry.cpp
@@ -0,0 +1,1792 @@
+/* A Bison parser, made from geometry.yy
+   by GNU bison 1.35.  */
+
+#define YYBISON 1  /* Identify Bison output.  */
+
+# define	NUM	257
+# define	TOK_SOLID	258
+# define	TOK_RECO	259
+# define	TOK_TLO	260
+# define	TOK_BOUNDINGBOX	261
+# define	IDENT	262
+# define	IDENTSOLID	263
+# define	TOK_SPHERE	264
+# define	TOK_CYLINDER	265
+# define	TOK_CONE	266
+# define	TOK_PLAIN	267
+# define	TOK_TUBE	268
+# define	TOK_GENCYL	269
+# define	TOK_ORTHOBRICK	270
+# define	TOK_POLYHEDRON	271
+# define	TOK_REVOLUTION	272
+# define	TOK_OR	273
+# define	TOK_AND	274
+# define	TOK_NOT	275
+# define	TOK_TRANSLATE	276
+# define	TOK_MULTITRANSLATE	277
+# define	TOK_ROTATE	278
+# define	TOK_MULTIROTATE	279
+# define	TOK_SINGULAR	280
+# define	TOK_EDGE	281
+# define	TOK_POINT	282
+# define	TOK_IDENTIFY	283
+# define	TOK_CLOSESURFACES	284
+# define	TOK_CLOSEEDGES	285
+# define	TOK_PERIODIC	286
+# define	TOK_BOUNDARYCONDITION	287
+
+#line 1 "geometry.yy"
+
+//define YYDEBUG 1
+
+extern int yylex ();
+
+#include <mystdlib.h>
+
+#include <myadt.hpp>
+
+#include <linalg.hpp>
+#include <csg.hpp>
+
+namespace netgen
+{
+netgen::CSGeometry * parsegeom;
+}
+
+using namespace netgen;
+
+// extern ARRAY<Surface*> surfaces;
+// extern SYMBOLTABLE<Solid*> solids;
+
+
+int yyerror (char * s);
+splinetube * tube;
+spline3d * middlecurve;
+Point<3> splinep1;
+BSplineCurve2d *bspline;
+Flags parseflags;
+extern int linenum;
+ARRAY<double> doublearray;
+ARRAY<char*> stringarray;
+
+Polyhedra * polyhedron;
+// Revolution * revolution;
+
+#line 38 "geometry.yy"
+#ifndef YYSTYPE
+typedef union {
+double val;
+char * chptr;
+Solid * solidtype;
+} yystype;
+# define YYSTYPE yystype
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+
+
+#define	YYFINAL		260
+#define	YYFLAG		-32768
+#define	YYNTBASE	42
+
+/* YYTRANSLATE(YYLEX) -- Bison token number corresponding to YYLEX. */
+#define YYTRANSLATE(x) ((unsigned)(x) <= 287 ? yytranslate[x] : 67)
+
+/* YYTRANSLATE[YYLEX] -- Bison token number corresponding to YYLEX. */
+static const char yytranslate[] =
+{
+       0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+      36,    37,     2,     2,    38,    39,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,    34,
+       2,    35,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,    40,     2,    41,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     1,     3,     4,     5,
+       6,     7,     8,     9,    10,    11,    12,    13,    14,    15,
+      16,    17,    18,    19,    20,    21,    22,    23,    24,    25,
+      26,    27,    28,    29,    30,    31,    32,    33
+};
+
+#if YYDEBUG
+static const short yyprhs[] =
+{
+       0,     0,     1,     6,     7,    11,    12,    19,    21,    23,
+      27,    31,    34,    38,    49,    66,    85,   100,   115,   116,
+     125,   136,   149,   166,   185,   189,   191,   195,   197,   203,
+     209,   217,   221,   223,   227,   229,   233,   245,   246,   252,
+     253,   254,   261,   262,   266,   272,   279,   285,   291,   296,
+     300,   305,   320,   329,   334,   335,   338,   339,   342,   345,
+     350,   355,   360,   365,   366,   371,   373,   377,   378,   383,
+     385,   389,   391
+};
+static const short yyrhs[] =
+{
+      -1,    43,     5,    44,    54,     0,     0,    44,    45,    34,
+       0,     0,     4,     8,    35,    47,    46,    56,     0,    48,
+       0,     9,     0,    47,    19,    47,     0,    47,    20,    47,
+       0,    21,    47,     0,    36,    47,    37,     0,    10,    36,
+       3,    38,     3,    38,     3,    34,     3,    37,     0,    11,
+      36,     3,    38,     3,    38,     3,    34,     3,    38,     3,
+      38,     3,    34,     3,    37,     0,    12,    36,     3,    38,
+       3,    38,     3,    34,     3,    34,     3,    38,     3,    38,
+       3,    34,     3,    37,     0,    13,    36,     3,    38,     3,
+      38,     3,    34,     3,    38,     3,    38,     3,    37,     0,
+      16,    36,     3,    38,     3,    38,     3,    34,     3,    38,
+       3,    38,     3,    37,     0,     0,    17,    36,    49,    50,
+      34,    34,    51,    37,     0,    22,    36,     3,    38,     3,
+      38,     3,    34,    47,    37,     0,    23,    36,     3,    38,
+       3,    38,     3,    34,     3,    34,    47,    37,     0,    24,
+      36,     3,    38,     3,    38,     3,    34,     3,    38,     3,
+      38,     3,    34,    47,    37,     0,    25,    36,     3,    38,
+       3,    38,     3,    34,     3,    38,     3,    38,     3,    34,
+       3,    34,    47,    37,     0,    50,    34,    52,     0,    52,
+       0,    51,    34,    53,     0,    53,     0,     3,    38,     3,
+      38,     3,     0,     3,    38,     3,    38,     3,     0,     3,
+      38,     3,    38,     3,    38,     3,     0,    67,    34,    68,
+       0,    68,     0,     3,    38,     3,     0,    70,     0,    70,
+      38,    69,     0,     3,    38,     3,    38,     3,    38,     3,
+      38,     3,    38,     3,     0,     0,     3,    38,     3,    72,
+      73,     0,     0,     0,    38,     3,    38,     3,    74,    73,
+       0,     0,    54,    55,    34,     0,    26,    27,     3,     9,
+       9,     0,    26,    28,     3,     9,     9,     9,     0,    29,
+      30,     9,     9,    56,     0,    29,    31,     9,     9,     9,
+       0,    29,    32,     9,     9,     0,     6,     9,    56,     0,
+       6,     9,     9,    56,     0,     7,    36,     3,    38,     3,
+      38,     3,    34,     3,    38,     3,    38,     3,    37,     0,
+      28,    36,     3,    38,     3,    38,     3,    37,     0,    33,
+       9,     9,     3,     0,     0,    57,    58,     0,     0,    59,
+      58,     0,    39,    66,     0,    39,    66,    35,    66,     0,
+      39,    66,    35,     3,     0,    39,    66,    35,    60,     0,
+      39,    66,    35,    63,     0,     0,    40,    61,    62,    41,
+       0,     3,     0,    62,    38,     3,     0,     0,    40,    64,
+      65,    41,     0,    66,     0,    65,    38,    66,     0,     8,
+       0,     9,     0
+};
+
+#endif
+
+#if YYDEBUG
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+static const short yyrline[] =
+{
+       0,    61,    61,    79,    81,    84,    84,    94,    96,    97,
+      98,    99,   100,   103,   112,   123,   135,   144,   158,   158,
+     197,   206,   222,   231,   285,   287,   289,   291,   293,   300,
+     306,   315,   317,   319,   331,   333,   335,   345,   345,   354,
+     356,   356,   372,   374,   377,   385,   394,   409,   425,   439,
+     453,   470,   477,   482,   511,   511,   516,   518,   521,   524,
+     526,   528,   530,   535,   535,   540,   542,   545,   545,   556,
+     563,   574,   576
+};
+#endif
+
+
+#if (YYDEBUG) || defined YYERROR_VERBOSE
+
+/* YYTNAME[TOKEN_NUM] -- String name of the token TOKEN_NUM. */
+static const char *const yytname[] =
+{
+  "$", "error", "$undefined.", "NUM", "TOK_SOLID", "TOK_RECO", "TOK_TLO", 
+  "TOK_BOUNDINGBOX", "IDENT", "IDENTSOLID", "TOK_SPHERE", "TOK_CYLINDER", 
+  "TOK_CONE", "TOK_PLAIN", "TOK_TUBE", "TOK_GENCYL", "TOK_ORTHOBRICK", 
+  "TOK_POLYHEDRON", "TOK_REVOLUTION", "TOK_OR", "TOK_AND", "TOK_NOT", 
+  "TOK_TRANSLATE", "TOK_MULTITRANSLATE", "TOK_ROTATE", "TOK_MULTIROTATE", 
+  "TOK_SINGULAR", "TOK_EDGE", "TOK_POINT", "TOK_IDENTIFY", 
+  "TOK_CLOSESURFACES", "TOK_CLOSEEDGES", "TOK_PERIODIC", 
+  "TOK_BOUNDARYCONDITION", "';'", "'='", "'('", "')'", "','", "'-'", 
+  "'['", "']'", "input", "@1", "recsoliddef", "soliddef", "@2", "solid", 
+  "solidprimitive", "@3", "polyhedronpoints", "polyhedronfaces", 
+  "polyhedronpoint", "polyhedronface", "recadddef", "adddef", "flaglist", 
+  "@6", "recflaglist", "flag", "numlistbrack", "@7", "numlist", 
+  "stringlistbrack", "@8", "stringlist", "anyident", 0
+};
+#endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const short yyr1[] =
+{
+       0,    43,    42,    44,    44,    46,    45,    47,    47,    47,
+      47,    47,    47,    48,    48,    48,    48,    48,    49,    48,
+      48,    48,    48,    48,    50,    50,    51,    51,    52,    53,
+      53,    67,    67,    68,    69,    69,    70,    72,    71,    73,
+      74,    73,    54,    54,    55,    55,    55,    55,    55,    55,
+      55,    55,    55,    55,    57,    56,    58,    58,    59,    59,
+      59,    59,    59,    61,    60,    62,    62,    64,    63,    65,
+      65,    66,    66
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+static const short yyr2[] =
+{
+       0,     0,     4,     0,     3,     0,     6,     1,     1,     3,
+       3,     2,     3,    10,    16,    18,    14,    14,     0,     8,
+      10,    12,    16,    18,     3,     1,     3,     1,     5,     5,
+       7,     3,     1,     3,     1,     3,    11,     0,     5,     0,
+       0,     6,     0,     3,     5,     6,     5,     5,     4,     3,
+       4,    14,     8,     4,     0,     2,     0,     2,     2,     4,
+       4,     4,     4,     0,     4,     1,     3,     0,     4,     1,
+       3,     1,     1
+};
+
+/* YYDEFACT[S] -- default rule to reduce with in state S when YYTABLE
+   doesn't specify something else to do.  Zero means the default is an
+   error. */
+static const short yydefact[] =
+{
+       1,     0,     3,    42,     0,     0,     2,     0,     4,     0,
+       0,     0,     0,     0,     0,     0,     0,    54,     0,     0,
+       0,     0,     0,     0,     0,     0,    43,     8,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       5,     7,    54,    49,    56,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,    18,    11,
+       0,     0,     0,     0,     0,     0,     0,    54,    50,     0,
+      55,    56,     0,     0,     0,     0,    54,     0,    48,    53,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+      12,     9,    10,     6,    71,    72,    58,    57,     0,    44,
+       0,     0,    46,    47,     0,     0,     0,     0,     0,     0,
+       0,    25,     0,     0,     0,     0,     0,     0,    45,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,    60,    67,    61,    62,    59,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,    24,     0,     0,     0,     0,
+       0,     0,     0,    52,     0,     0,     0,     0,     0,     0,
+       0,     0,    27,     0,     0,     0,     0,    65,     0,     0,
+      69,     0,     0,     0,     0,     0,     0,    28,     0,     0,
+      19,     0,     0,     0,     0,     0,    64,     0,    68,     0,
+       0,     0,     0,     0,     0,     0,    26,     0,     0,     0,
+       0,    66,    70,     0,    13,     0,     0,     0,     0,     0,
+      20,     0,     0,     0,     0,     0,     0,     0,     0,    29,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,    21,
+       0,     0,    51,     0,     0,     0,     0,    30,     0,     0,
+       0,     0,    16,    17,     0,     0,     0,     0,     0,     0,
+      14,     0,    22,     0,     0,     0,    15,    23,     0,     0,
+       0
+};
+
+static const short yydefgoto[] =
+{
+     258,     1,     3,     5,    67,    40,    41,    85,   110,   161,
+     111,   162,     6,    15,    43,    44,    70,    71,   133,   150,
+     168,   134,   151,   169,    96
+};
+
+static const short yypact[] =
+{
+  -32768,     5,-32768,    18,    21,     7,    14,    11,-32768,    52,
+      35,    36,    39,    28,    56,    42,     2,    58,    66,    74,
+      75,    76,    71,    72,    73,    77,-32768,-32768,    48,    49,
+      51,    53,    55,    57,     2,    59,    60,    61,    62,     2,
+      54,-32768,-32768,-32768,    44,    50,    81,    83,    63,    85,
+      90,    91,    99,   100,   101,   102,   103,   104,-32768,-32768,
+     105,   106,   107,   108,    -3,     2,     2,-32768,-32768,    47,
+  -32768,    44,   109,   110,   111,   112,-32768,   113,-32768,-32768,
+      78,    79,    80,    86,    87,   118,    88,    89,    92,    93,
+  -32768,-32768,-32768,-32768,-32768,-32768,    94,-32768,    95,-32768,
+     114,    96,-32768,-32768,   125,   129,   132,   133,   134,   115,
+     116,-32768,   135,   136,   137,   138,    -1,   139,-32768,   140,
+     117,   119,   120,   121,   122,   141,     1,   123,   124,   126,
+     127,-32768,   142,-32768,-32768,-32768,   144,   130,   143,   145,
+     146,   148,   149,   128,   151,-32768,   153,   160,   165,   166,
+     167,    47,   168,-32768,   147,   150,   152,   154,   155,   169,
+     156,   -28,-32768,   157,   158,   159,   161,-32768,    -8,    16,
+  -32768,   162,   170,   171,   172,   173,   176,-32768,   177,   151,
+  -32768,     2,   179,   180,   182,   184,-32768,    47,-32768,   187,
+     164,   174,   163,   175,   178,   183,-32768,    25,   181,   185,
+     186,-32768,-32768,   188,-32768,   193,   195,   196,   199,   200,
+  -32768,     2,   201,   202,   203,   189,   190,   191,   192,   194,
+      29,   197,   198,   204,   205,   206,   208,   211,   214,-32768,
+     215,   217,-32768,   209,   207,   210,   212,-32768,   216,   218,
+     219,   222,-32768,-32768,     2,   228,   220,   221,    31,   224,
+  -32768,   230,-32768,     2,   223,    33,-32768,-32768,   234,   237,
+  -32768
+};
+
+static const short yypgoto[] =
+{
+  -32768,-32768,-32768,-32768,-32768,   -34,-32768,-32768,-32768,-32768,
+     -13,   -65,-32768,-32768,   -39,-32768,   213,-32768,-32768,-32768,
+  -32768,-32768,-32768,-32768,  -115
+};
+
+
+#define	YYLAST		284
+
+
+static const short yytable[] =
+{
+      59,   135,   131,    68,   109,    64,   179,    94,    95,   180,
+       2,    27,    28,    29,    30,    31,    65,    66,    32,    33,
+       9,    10,     4,    34,    35,    36,    37,    38,    93,     7,
+     185,    91,    92,   186,    90,   144,   170,   102,    39,   132,
+      11,     8,    12,    13,    65,    66,    16,    14,    65,    66,
+      65,    66,    65,    66,   187,    94,    95,   188,    22,    23,
+      24,    17,   210,    19,    20,    25,   229,    42,   252,    45,
+     257,    18,   202,    65,    66,    21,    26,    46,    47,    48,
+      49,    50,    51,    69,    53,    54,    52,    55,    72,    56,
+      73,    57,    74,    58,    76,    60,    61,    62,    63,    77,
+      78,    75,    79,    80,    81,    82,    83,    84,    86,    87,
+      88,    89,    98,   145,   196,   101,   104,   105,   106,    99,
+     100,   109,   103,   118,   107,   108,   112,   113,   120,   116,
+     114,   115,   121,   117,   119,   122,   123,   124,   127,   128,
+     129,   130,   136,   137,   143,   -63,   154,   197,   155,   156,
+     126,   157,   158,   125,   160,   138,   163,   139,   140,   141,
+     142,   146,   147,   164,   148,   149,   159,   153,   165,   166,
+     167,   171,   177,   190,   191,   192,   193,   220,   152,   194,
+     195,   172,   198,   199,   173,   200,   174,   201,   175,   176,
+     203,   181,   182,   183,   178,   184,   215,   206,   216,   217,
+     189,   204,   218,   219,   221,   222,   223,     0,   233,   234,
+     248,   235,   205,   207,   236,   211,   208,   237,   238,   255,
+     239,   209,   246,   212,   213,   247,   214,   224,   225,   226,
+     227,   249,   228,   254,   259,   230,   231,   260,     0,     0,
+       0,   232,     0,   240,     0,   241,     0,   242,     0,   243,
+     244,     0,   245,     0,     0,   251,     0,   250,   253,     0,
+     256,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,    97
+};
+
+static const short yycheck[] =
+{
+      34,   116,     3,    42,     3,    39,    34,     8,     9,    37,
+       5,     9,    10,    11,    12,    13,    19,    20,    16,    17,
+       6,     7,     4,    21,    22,    23,    24,    25,    67,     8,
+      38,    65,    66,    41,    37,    34,   151,    76,    36,    40,
+      26,    34,    28,    29,    19,    20,    35,    33,    19,    20,
+      19,    20,    19,    20,    38,     8,     9,    41,    30,    31,
+      32,     9,    37,    27,    28,     9,    37,     9,    37,     3,
+      37,    36,   187,    19,    20,    36,    34,     3,     3,     3,
+       9,     9,     9,    39,    36,    36,     9,    36,    38,    36,
+       9,    36,     9,    36,     9,    36,    36,    36,    36,     9,
+       9,    38,     3,     3,     3,     3,     3,     3,     3,     3,
+       3,     3,     3,   126,   179,     3,    38,    38,    38,     9,
+       9,     3,     9,     9,    38,    38,    38,    38,     3,    35,
+      38,    38,     3,    38,    38,     3,     3,     3,     3,     3,
+       3,     3,     3,     3,     3,     3,     3,   181,     3,     3,
+      34,     3,     3,    38,     3,    38,     3,    38,    38,    38,
+      38,    38,    38,     3,    38,    38,    38,    37,     3,     3,
+       3,     3,     3,     3,     3,     3,     3,   211,    34,     3,
+       3,    34,     3,     3,    34,     3,    34,     3,    34,    34,
+       3,    34,    34,    34,    38,    34,     3,    34,     3,     3,
+      38,    37,     3,     3,     3,     3,     3,    -1,     3,     3,
+     244,     3,    38,    38,     3,    34,    38,     3,     3,   253,
+       3,    38,     3,    38,    38,     3,    38,    38,    38,    38,
+      38,     3,    38,     3,     0,    38,    38,     0,    -1,    -1,
+      -1,    37,    -1,    34,    -1,    38,    -1,    37,    -1,    37,
+      34,    -1,    34,    -1,    -1,    34,    -1,    37,    34,    -1,
+      37,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    71
+};
+/* -*-C-*-  Note some compilers choke on comments on `#line' lines.  */
+#line 3 "/usr/share/bison/bison.simple"
+
+/* Skeleton output parser for bison,
+
+   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002 Free Software
+   Foundation, Inc.
+
+   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, 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.  */
+
+/* As a special exception, when this file is copied by Bison into a
+   Bison output file, you may use that output file without restriction.
+   This special exception was added by the Free Software Foundation
+   in version 1.24 of Bison.  */
+
+/* This is the parser code that is written into each bison parser when
+   the %semantic_parser declaration is not specified in the grammar.
+   It was written by Richard Stallman by simplifying the hairy parser
+   used when %semantic_parser is specified.  */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+   infringing on user name space.  This should be done even for local
+   variables, as they might otherwise be expanded by user macros.
+   There are some unavoidable exceptions within include files to
+   define necessary library symbols; they are noted "INFRINGES ON
+   USER NAME SPACE" below.  */
+
+#ifndef YYPARSE_RETURN_TYPE
+#define YYPARSE_RETURN_TYPE int
+#endif
+
+#if ! defined (yyoverflow) || defined (YYERROR_VERBOSE)
+
+/* The parser invokes alloca or malloc; define the necessary symbols.  */
+
+# if YYSTACK_USE_ALLOCA
+#  define YYSTACK_ALLOC alloca
+# else
+#  ifndef YYSTACK_USE_ALLOCA
+#   if defined (alloca) || defined (_ALLOCA_H)
+#    define YYSTACK_ALLOC alloca
+#   else
+#    ifdef __GNUC__
+#     define YYSTACK_ALLOC __builtin_alloca
+#    endif
+#   endif
+#  endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+   /* Pacify GCC's `empty if-body' warning. */
+#  define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
+# else
+#  if defined (__STDC__) || defined (__cplusplus)
+#   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+#   define YYSIZE_T size_t
+#  endif
+#  define YYSTACK_ALLOC malloc
+#  define YYSTACK_FREE free
+# endif
+#endif /* ! defined (yyoverflow) || defined (YYERROR_VERBOSE) */
+
+
+#if (! defined (yyoverflow) \
+     && (! defined (__cplusplus) \
+	 || ((YYLTYPE_IS_TRIVIAL || ! YYLSP_NEEDED) && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member.  */
+union yyalloc
+{
+  short yyss;
+  YYSTYPE yyvs;
+# if YYLSP_NEEDED
+  YYLTYPE yyls;
+# endif
+};
+
+/* The size of the maximum gap between one aligned stack and the next.  */
+# define YYSTACK_GAP_MAX (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+   N elements.  */
+# if YYLSP_NEEDED
+#  define YYSTACK_BYTES(N) \
+     ((N) * (sizeof (short) + sizeof (YYSTYPE) + sizeof (YYLTYPE))	\
+      + 2 * YYSTACK_GAP_MAX)
+# else
+#  define YYSTACK_BYTES(N) \
+     ((N) * (sizeof (short) + sizeof (YYSTYPE))				\
+      + YYSTACK_GAP_MAX)
+# endif
+
+/* Copy COUNT objects from FROM to TO.  The source and destination do
+   not overlap.  */
+# ifndef YYCOPY
+#  if 1 < __GNUC__
+#   define YYCOPY(To, From, Count) \
+      __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+#  else
+#   define YYCOPY(To, From, Count)		\
+      do					\
+	{					\
+	  register YYSIZE_T yyi;		\
+	  for (yyi = 0; yyi < (Count); yyi++)	\
+	    (To)[yyi] = (From)[yyi];		\
+	}					\
+      while (0)
+#  endif
+# endif
+
+/* Relocate STACK from its old location to the new one.  The
+   local variables YYSIZE and YYSTACKSIZE give the old and new number of
+   elements in the stack, and YYPTR gives the new location of the
+   stack.  Advance YYPTR to a properly aligned location for the next
+   stack.  */
+# define YYSTACK_RELOCATE(Stack)					\
+    do									\
+      {									\
+	YYSIZE_T yynewbytes;						\
+	YYCOPY (&yyptr->Stack, Stack, yysize);				\
+	Stack = &yyptr->Stack;						\
+	yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAX;	\
+	yyptr += yynewbytes / sizeof (*yyptr);				\
+      }									\
+    while (0)
+
+#endif
+
+
+#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__)
+# define YYSIZE_T __SIZE_TYPE__
+#endif
+#if ! defined (YYSIZE_T) && defined (size_t)
+# define YYSIZE_T size_t
+#endif
+#if ! defined (YYSIZE_T)
+# if defined (__STDC__) || defined (__cplusplus)
+#  include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYSIZE_T size_t
+# endif
+#endif
+#if ! defined (YYSIZE_T)
+# define YYSIZE_T unsigned int
+#endif
+
+#define yyerrok		(yyerrstatus = 0)
+#define yyclearin	(yychar = YYEMPTY)
+#define YYEMPTY		-2
+#define YYEOF		0
+#define YYACCEPT	goto yyacceptlab
+#define YYABORT 	goto yyabortlab
+#define YYERROR		goto yyerrlab1
+/* Like YYERROR except do call yyerror.  This remains here temporarily
+   to ease the transition to the new meaning of YYERROR, for GCC.
+   Once GCC version 2 has supplanted version 1, this can go.  */
+#define YYFAIL		goto yyerrlab
+#define YYRECOVERING()  (!!yyerrstatus)
+#define YYBACKUP(Token, Value)					\
+do								\
+  if (yychar == YYEMPTY && yylen == 1)				\
+    {								\
+      yychar = (Token);						\
+      yylval = (Value);						\
+      yychar1 = YYTRANSLATE (yychar);				\
+      YYPOPSTACK;						\
+      goto yybackup;						\
+    }								\
+  else								\
+    { 								\
+      yyerror ("syntax error: cannot back up");			\
+      YYERROR;							\
+    }								\
+while (0)
+
+#define YYTERROR	1
+#define YYERRCODE	256
+
+
+/* YYLLOC_DEFAULT -- Compute the default location (before the actions
+   are run).
+
+   When YYLLOC_DEFAULT is run, CURRENT is set the location of the
+   first token.  By default, to implement support for ranges, extend
+   its range to the last symbol.  */
+
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N)       	\
+   Current.last_line   = Rhs[N].last_line;	\
+   Current.last_column = Rhs[N].last_column;
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments.  */
+
+#if YYPURE
+# if YYLSP_NEEDED
+#  ifdef YYLEX_PARAM
+#   define YYLEX		yylex (&yylval, &yylloc, YYLEX_PARAM)
+#  else
+#   define YYLEX		yylex (&yylval, &yylloc)
+#  endif
+# else /* !YYLSP_NEEDED */
+#  ifdef YYLEX_PARAM
+#   define YYLEX		yylex (&yylval, YYLEX_PARAM)
+#  else
+#   define YYLEX		yylex (&yylval)
+#  endif
+# endif /* !YYLSP_NEEDED */
+#else /* !YYPURE */
+# define YYLEX			yylex ()
+#endif /* !YYPURE */
+
+
+/* Enable debugging if requested.  */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+#  include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args)			\
+do {						\
+  if (yydebug)					\
+    YYFPRINTF Args;				\
+} while (0)
+/* Nonzero means print parse trace.  It is left uninitialized so that
+   multiple parsers can coexist.  */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+#endif /* !YYDEBUG */
+
+/* YYINITDEPTH -- initial size of the parser's stacks.  */
+#ifndef	YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+   if the built-in stack extension method is used).
+
+   Do not make this value too large; the results are undefined if
+   SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH)
+   evaluated with infinite-precision integer arithmetic.  */
+
+#if YYMAXDEPTH == 0
+# undef YYMAXDEPTH
+#endif
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+#ifdef YYERROR_VERBOSE
+
+# ifndef yystrlen
+#  if defined (__GLIBC__) && defined (_STRING_H)
+#   define yystrlen strlen
+#  else
+/* Return the length of YYSTR.  */
+static YYSIZE_T
+#   if defined (__STDC__) || defined (__cplusplus)
+yystrlen (const char *yystr)
+#   else
+yystrlen (yystr)
+     const char *yystr;
+#   endif
+{
+  register const char *yys = yystr;
+
+  while (*yys++ != '\0')
+    continue;
+
+  return yys - yystr - 1;
+}
+#  endif
+# endif
+
+# ifndef yystpcpy
+#  if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE)
+#   define yystpcpy stpcpy
+#  else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+   YYDEST.  */
+static char *
+#   if defined (__STDC__) || defined (__cplusplus)
+yystpcpy (char *yydest, const char *yysrc)
+#   else
+yystpcpy (yydest, yysrc)
+     char *yydest;
+     const char *yysrc;
+#   endif
+{
+  register char *yyd = yydest;
+  register const char *yys = yysrc;
+
+  while ((*yyd++ = *yys++) != '\0')
+    continue;
+
+  return yyd - 1;
+}
+#  endif
+# endif
+#endif
+
+#line 319 "/usr/share/bison/bison.simple"
+
+
+/* The user can define YYPARSE_PARAM as the name of an argument to be passed
+   into yyparse.  The argument should have type void *.
+   It should actually point to an object.
+   Grammar actions can access the variable by casting it
+   to the proper pointer type.  */
+
+#ifdef YYPARSE_PARAM
+# if defined (__STDC__) || defined (__cplusplus)
+#  define YYPARSE_PARAM_ARG void *YYPARSE_PARAM
+#  define YYPARSE_PARAM_DECL
+# else
+#  define YYPARSE_PARAM_ARG YYPARSE_PARAM
+#  define YYPARSE_PARAM_DECL void *YYPARSE_PARAM;
+# endif
+#else /* !YYPARSE_PARAM */
+# define YYPARSE_PARAM_ARG
+# define YYPARSE_PARAM_DECL
+#endif /* !YYPARSE_PARAM */
+
+/* Prevent warning if -Wstrict-prototypes.  */
+#ifdef __GNUC__
+# ifdef YYPARSE_PARAM
+YYPARSE_RETURN_TYPE yyparse (void *);
+# else
+YYPARSE_RETURN_TYPE yyparse (void);
+# endif
+#endif
+
+/* YY_DECL_VARIABLES -- depending whether we use a pure parser,
+   variables are global, or local to YYPARSE.  */
+
+#define YY_DECL_NON_LSP_VARIABLES			\
+/* The lookahead symbol.  */				\
+int yychar;						\
+							\
+/* The semantic value of the lookahead symbol. */	\
+YYSTYPE yylval;						\
+							\
+/* Number of parse errors so far.  */			\
+int yynerrs;
+
+#if YYLSP_NEEDED
+# define YY_DECL_VARIABLES			\
+YY_DECL_NON_LSP_VARIABLES			\
+						\
+/* Location data for the lookahead symbol.  */	\
+YYLTYPE yylloc;
+#else
+# define YY_DECL_VARIABLES			\
+YY_DECL_NON_LSP_VARIABLES
+#endif
+
+
+/* If nonreentrant, generate the variables here. */
+
+#if !YYPURE
+YY_DECL_VARIABLES
+#endif  /* !YYPURE */
+
+YYPARSE_RETURN_TYPE
+yyparse (YYPARSE_PARAM_ARG)
+     YYPARSE_PARAM_DECL
+{
+  /* If reentrant, generate the variables here. */
+#if YYPURE
+  YY_DECL_VARIABLES
+#endif  /* !YYPURE */
+
+  register int yystate;
+  register int yyn;
+  int yyresult;
+  /* Number of tokens to shift before error messages enabled.  */
+  int yyerrstatus;
+  /* Lookahead token as an internal (translated) token number.  */
+  int yychar1 = 0;
+
+  /* Three stacks and their tools:
+     `yyss': related to states,
+     `yyvs': related to semantic values,
+     `yyls': related to locations.
+
+     Refer to the stacks thru separate pointers, to allow yyoverflow
+     to reallocate them elsewhere.  */
+
+  /* The state stack. */
+  short	yyssa[YYINITDEPTH];
+  short *yyss = yyssa;
+  register short *yyssp;
+
+  /* The semantic value stack.  */
+  YYSTYPE yyvsa[YYINITDEPTH];
+  YYSTYPE *yyvs = yyvsa;
+  register YYSTYPE *yyvsp;
+
+#if YYLSP_NEEDED
+  /* The location stack.  */
+  YYLTYPE yylsa[YYINITDEPTH];
+  YYLTYPE *yyls = yylsa;
+  YYLTYPE *yylsp;
+#endif
+
+#if YYLSP_NEEDED
+# define YYPOPSTACK   (yyvsp--, yyssp--, yylsp--)
+#else
+# define YYPOPSTACK   (yyvsp--, yyssp--)
+#endif
+
+  YYSIZE_T yystacksize = YYINITDEPTH;
+
+
+  /* The variables used to return semantic value and location from the
+     action routines.  */
+  YYSTYPE yyval;
+#if YYLSP_NEEDED
+  YYLTYPE yyloc;
+#endif
+
+  /* When reducing, the number of symbols on the RHS of the reduced
+     rule. */
+  int yylen;
+
+  YYDPRINTF ((stderr, "Starting parse\n"));
+
+  yystate = 0;
+  yyerrstatus = 0;
+  yynerrs = 0;
+  yychar = YYEMPTY;		/* Cause a token to be read.  */
+
+  /* Initialize stack pointers.
+     Waste one element of value and location stack
+     so that they stay on the same level as the state stack.
+     The wasted elements are never initialized.  */
+
+  yyssp = yyss;
+  yyvsp = yyvs;
+#if YYLSP_NEEDED
+  yylsp = yyls;
+#endif
+  goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate.  |
+`------------------------------------------------------------*/
+ yynewstate:
+  /* In all cases, when you get here, the value and location stacks
+     have just been pushed. so pushing a state here evens the stacks.
+     */
+  yyssp++;
+
+ yysetstate:
+  *yyssp = yystate;
+
+  if (yyssp >= yyss + yystacksize - 1)
+    {
+      /* Get the current used size of the three stacks, in elements.  */
+      YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+      {
+	/* Give user a chance to reallocate the stack. Use copies of
+	   these so that the &'s don't force the real ones into
+	   memory.  */
+	YYSTYPE *yyvs1 = yyvs;
+	short *yyss1 = yyss;
+
+	/* Each stack pointer address is followed by the size of the
+	   data in use in that stack, in bytes.  */
+# if YYLSP_NEEDED
+	YYLTYPE *yyls1 = yyls;
+	/* This used to be a conditional around just the two extra args,
+	   but that might be undefined if yyoverflow is a macro.  */
+	yyoverflow ("parser stack overflow",
+		    &yyss1, yysize * sizeof (*yyssp),
+		    &yyvs1, yysize * sizeof (*yyvsp),
+		    &yyls1, yysize * sizeof (*yylsp),
+		    &yystacksize);
+	yyls = yyls1;
+# else
+	yyoverflow ("parser stack overflow",
+		    &yyss1, yysize * sizeof (*yyssp),
+		    &yyvs1, yysize * sizeof (*yyvsp),
+		    &yystacksize);
+# endif
+	yyss = yyss1;
+	yyvs = yyvs1;
+      }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+      goto yyoverflowlab;
+# else
+      /* Extend the stack our own way.  */
+      if (yystacksize >= YYMAXDEPTH)
+	goto yyoverflowlab;
+      yystacksize *= 2;
+      if (yystacksize > YYMAXDEPTH)
+	yystacksize = YYMAXDEPTH;
+
+      {
+	short *yyss1 = yyss;
+	union yyalloc *yyptr =
+	  (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+	if (! yyptr)
+	  goto yyoverflowlab;
+	YYSTACK_RELOCATE (yyss);
+	YYSTACK_RELOCATE (yyvs);
+# if YYLSP_NEEDED
+	YYSTACK_RELOCATE (yyls);
+# endif
+# undef YYSTACK_RELOCATE
+	if (yyss1 != yyssa)
+	  YYSTACK_FREE (yyss1);
+      }
+# endif
+#endif /* no yyoverflow */
+
+      yyssp = yyss + yysize - 1;
+      yyvsp = yyvs + yysize - 1;
+#if YYLSP_NEEDED
+      yylsp = yyls + yysize - 1;
+#endif
+
+      YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+		  (unsigned long int) yystacksize));
+
+      if (yyssp >= yyss + yystacksize - 1)
+	YYABORT;
+    }
+
+  YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+  goto yybackup;
+
+
+/*-----------.
+| yybackup.  |
+`-----------*/
+yybackup:
+
+/* Do appropriate processing given the current state.  */
+/* Read a lookahead token if we need one and don't already have one.  */
+/* yyresume: */
+
+  /* First try to decide what to do without reference to lookahead token.  */
+
+  yyn = yypact[yystate];
+  if (yyn == YYFLAG)
+    goto yydefault;
+
+  /* Not known => get a lookahead token if don't already have one.  */
+
+  /* yychar is either YYEMPTY or YYEOF
+     or a valid token in external form.  */
+
+  if (yychar == YYEMPTY)
+    {
+      YYDPRINTF ((stderr, "Reading a token: "));
+      yychar = YYLEX;
+    }
+
+  /* Convert token to internal form (in yychar1) for indexing tables with */
+
+  if (yychar <= 0)		/* This means end of input. */
+    {
+      yychar1 = 0;
+      yychar = YYEOF;		/* Don't call YYLEX any more */
+
+      YYDPRINTF ((stderr, "Now at end of input.\n"));
+    }
+  else
+    {
+      yychar1 = YYTRANSLATE (yychar);
+
+#if YYDEBUG
+     /* We have to keep this `#if YYDEBUG', since we use variables
+	which are defined only if `YYDEBUG' is set.  */
+      if (yydebug)
+	{
+	  YYFPRINTF (stderr, "Next token is %d (%s",
+		     yychar, yytname[yychar1]);
+	  /* Give the individual parser a way to print the precise
+	     meaning of a token, for further debugging info.  */
+# ifdef YYPRINT
+	  YYPRINT (stderr, yychar, yylval);
+# endif
+	  YYFPRINTF (stderr, ")\n");
+	}
+#endif
+    }
+
+  yyn += yychar1;
+  if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1)
+    goto yydefault;
+
+  yyn = yytable[yyn];
+
+  /* yyn is what to do for this token type in this state.
+     Negative => reduce, -yyn is rule number.
+     Positive => shift, yyn is new state.
+       New state is final state => don't bother to shift,
+       just return success.
+     0, or most negative number => error.  */
+
+  if (yyn < 0)
+    {
+      if (yyn == YYFLAG)
+	goto yyerrlab;
+      yyn = -yyn;
+      goto yyreduce;
+    }
+  else if (yyn == 0)
+    goto yyerrlab;
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+  /* Shift the lookahead token.  */
+  YYDPRINTF ((stderr, "Shifting token %d (%s), ",
+	      yychar, yytname[yychar1]));
+
+  /* Discard the token being shifted unless it is eof.  */
+  if (yychar != YYEOF)
+    yychar = YYEMPTY;
+
+  *++yyvsp = yylval;
+#if YYLSP_NEEDED
+  *++yylsp = yylloc;
+#endif
+
+  /* Count tokens shifted since error; after three, turn off error
+     status.  */
+  if (yyerrstatus)
+    yyerrstatus--;
+
+  yystate = yyn;
+  goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state.  |
+`-----------------------------------------------------------*/
+yydefault:
+  yyn = yydefact[yystate];
+  if (yyn == 0)
+    goto yyerrlab;
+  goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction.  |
+`-----------------------------*/
+yyreduce:
+  /* yyn is the number of a rule to reduce with.  */
+  yylen = yyr2[yyn];
+
+  /* If YYLEN is nonzero, implement the default value of the action:
+     `$$ = $1'.
+
+     Otherwise, the following line sets YYVAL to the semantic value of
+     the lookahead token.  This behavior is undocumented and Bison
+     users should not rely upon it.  Assigning to YYVAL
+     unconditionally makes the parser a bit smaller, and it avoids a
+     GCC warning that YYVAL may be used uninitialized.  */
+  yyval = yyvsp[1-yylen];
+
+#if YYLSP_NEEDED
+  /* Similarly for the default location.  Let the user run additional
+     commands if for instance locations are ranges.  */
+  yyloc = yylsp[1-yylen];
+  YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen);
+#endif
+
+#if YYDEBUG
+  /* We have to keep this `#if YYDEBUG', since we use variables which
+     are defined only if `YYDEBUG' is set.  */
+  if (yydebug)
+    {
+      int yyi;
+
+      YYFPRINTF (stderr, "Reducing via rule %d (line %d), ",
+		 yyn, yyrline[yyn]);
+
+      /* Print the symbols being reduced, and their result.  */
+      for (yyi = yyprhs[yyn]; yyrhs[yyi] > 0; yyi++)
+	YYFPRINTF (stderr, "%s ", yytname[yyrhs[yyi]]);
+      YYFPRINTF (stderr, " -> %s\n", yytname[yyr1[yyn]]);
+    }
+#endif
+
+  switch (yyn) {
+
+case 1:
+#line 62 "geometry.yy"
+{
+		  linenum = 1;
+		;
+    break;}
+case 2:
+#line 69 "geometry.yy"
+{
+		int i;
+		extern ARRAY<char*> parsestrings;
+		for (i = 0; i < parsestrings.Size(); i++)
+ 		  delete [] parsestrings[i];
+		parsestrings.SetSize(0);
+		;
+    break;}
+case 5:
+#line 86 "geometry.yy"
+{ parsegeom->SetSolid(yyvsp[-2].chptr, new Solid (Solid::ROOT, yyvsp[0].solidtype)); 
+		  ;
+    break;}
+case 6:
+#line 89 "geometry.yy"
+{ 
+		  parsegeom->SetFlags(yyvsp[-4].chptr, parseflags); 
+		  ;
+    break;}
+case 8:
+#line 96 "geometry.yy"
+{ yyval.solidtype = (Solid*)parsegeom->GetSolid(yyvsp[0].chptr);  ;
+    break;}
+case 9:
+#line 97 "geometry.yy"
+{ yyval.solidtype = new Solid (Solid::UNION, yyvsp[-2].solidtype, yyvsp[0].solidtype); ;
+    break;}
+case 10:
+#line 98 "geometry.yy"
+{ yyval.solidtype = new Solid (Solid::SECTION, yyvsp[-2].solidtype, yyvsp[0].solidtype); ;
+    break;}
+case 11:
+#line 99 "geometry.yy"
+{ yyval.solidtype = new Solid (Solid::SUB, yyvsp[0].solidtype); ;
+    break;}
+case 12:
+#line 100 "geometry.yy"
+{ yyval.solidtype = yyvsp[-1].solidtype; ;
+    break;}
+case 13:
+#line 106 "geometry.yy"
+{ 
+		   OneSurfacePrimitive * surf = new Sphere (Point<3> (yyvsp[-7].val, yyvsp[-5].val, yyvsp[-3].val), yyvsp[-1].val); 
+		   parsegeom -> AddSurface (surf);
+		   surf->SetSurfaceId (0, parsegeom->GetNSurf()-1);
+                   yyval.solidtype = new Solid (surf);
+                 ;
+    break;}
+case 14:
+#line 116 "geometry.yy"
+{
+		   OneSurfacePrimitive * surf = new Cylinder (Point<3> (yyvsp[-13].val, yyvsp[-11].val, yyvsp[-9].val),
+	                                       Point<3> (yyvsp[-7].val, yyvsp[-5].val, yyvsp[-3].val), yyvsp[-1].val);
+		   parsegeom->AddSurface (surf);
+		   surf->SetSurfaceId (0, parsegeom->GetNSurf()-1);
+                   yyval.solidtype = new Solid (surf);
+                 ;
+    break;}
+case 15:
+#line 128 "geometry.yy"
+{
+		   OneSurfacePrimitive * surf = new Cone (Point<3> (yyvsp[-15].val, yyvsp[-13].val, yyvsp[-11].val),
+	                                     	 Point<3> (yyvsp[-7].val, yyvsp[-5].val, yyvsp[-3].val), yyvsp[-9].val, yyvsp[-1].val);
+		   parsegeom->AddSurface (surf);
+		   surf->SetSurfaceId (0, parsegeom->GetNSurf()-1);
+                   yyval.solidtype = new Solid (surf);
+                 ;
+    break;}
+case 16:
+#line 137 "geometry.yy"
+{
+		   OneSurfacePrimitive * surf = new Plane ( Point<3> (yyvsp[-11].val, yyvsp[-9].val, yyvsp[-7].val),
+	                                        Vec<3> (yyvsp[-5].val, yyvsp[-3].val, yyvsp[-1].val) );
+		   parsegeom->AddSurface (surf);
+		   surf->SetSurfaceId (0, parsegeom->GetNSurf()-1);
+                   yyval.solidtype = new Solid (surf);
+                 ;
+    break;}
+case 17:
+#line 146 "geometry.yy"
+{
+		  Primitive * nprim = new OrthoBrick (Point<3> (yyvsp[-11].val, yyvsp[-9].val, yyvsp[-7].val),
+		                                      Point<3> (yyvsp[-5].val, yyvsp[-3].val, yyvsp[-1].val));
+                  for (int j = 0; j < nprim->GetNSurfaces(); j++)
+		    {
+		      parsegeom->AddSurface (&nprim->GetSurface(j));
+		      nprim->SetSurfaceId (j, parsegeom->GetNSurf()-1);
+		      yyval.solidtype = new Solid (nprim);
+		    }
+		;
+    break;}
+case 18:
+#line 159 "geometry.yy"
+{
+		  polyhedron = new Polyhedra ();
+		;
+    break;}
+case 19:
+#line 164 "geometry.yy"
+{
+		  int j;
+                  for (j = 0; j < polyhedron->GetNSurfaces(); j++)
+		    {
+		      parsegeom->AddSurface (&polyhedron->GetSurface(j));
+		      polyhedron->SetSurfaceId (j, parsegeom->GetNSurf()-1);
+		      yyval.solidtype = new Solid (polyhedron);
+		    }	
+		;
+    break;}
+case 20:
+#line 198 "geometry.yy"
+{
+                  Solid * nsol = yyvsp[-1].solidtype -> Copy(*parsegeom);
+                  Vec<3> v(yyvsp[-7].val, yyvsp[-5].val, yyvsp[-3].val);
+                  Transformation<3> trans(v);
+		  nsol -> Transform (trans);
+                  yyval.solidtype = nsol;
+		;
+    break;}
+case 21:
+#line 207 "geometry.yy"
+{
+		  int i;
+                  Solid * hsol = yyvsp[-1].solidtype;
+	          for (i = 1; i <= yyvsp[-3].val; i++)
+                    {
+                      Solid * nsol = yyvsp[-1].solidtype -> Copy(*parsegeom);
+                      Vec<3> v(yyvsp[-9].val, yyvsp[-7].val, yyvsp[-5].val);
+		      v *= i;
+                      Transformation<3> trans(v);
+		      nsol -> Transform (trans);
+                      hsol = new Solid (Solid::UNION, hsol, nsol); 
+                    }
+		  yyval.solidtype = hsol;
+		;
+    break;}
+case 22:
+#line 223 "geometry.yy"
+{
+                  Solid * nsol = yyvsp[-1].solidtype -> Copy(*parsegeom);
+                  Point<3> c(yyvsp[-13].val, yyvsp[-11].val, yyvsp[-9].val);
+                  Transformation<3> rot(c, yyvsp[-7].val, yyvsp[-5].val, yyvsp[-3].val);
+		  nsol -> Transform (rot);
+                  yyval.solidtype = nsol;
+		;
+    break;}
+case 23:
+#line 234 "geometry.yy"
+{
+		  int i;
+                  Solid * hsol = yyvsp[-1].solidtype;                      
+
+		  Point<3> c(yyvsp[-15].val, yyvsp[-13].val, yyvsp[-11].val);
+                  Transformation<3> trans(c, yyvsp[-9].val, yyvsp[-7].val, yyvsp[-5].val);
+		  Transformation<3> multi(Vec<3>(0,0,0));
+		  Transformation<3> ht;
+
+	          for (i = 1; i <= yyvsp[-3].val; i++)
+                    {
+                      Solid * nsol = yyvsp[-1].solidtype -> Copy(*parsegeom);
+		      nsol -> Transform (multi);
+                      hsol = new Solid (Solid::UNION, hsol, nsol); 
+
+		      ht=multi;
+                      multi.Combine (trans, ht);
+                    }
+		  yyval.solidtype = hsol;
+		;
+    break;}
+case 28:
+#line 295 "geometry.yy"
+{
+		polyhedron->AddPoint (Point<3> (yyvsp[-4].val, yyvsp[-2].val, yyvsp[0].val));
+ 		cout << " " << yyvsp[-4].val << " " << yyvsp[-2].val << " " << yyvsp[0].val << endl;
+	;
+    break;}
+case 29:
+#line 302 "geometry.yy"
+{ 
+		polyhedron->AddFace (int(yyvsp[-4].val)-1, int(yyvsp[-2].val)-1, int(yyvsp[0].val)-1);
+		cout << yyvsp[-4].val << " " << yyvsp[-2].val << " " << yyvsp[0].val << endl; 
+	;
+    break;}
+case 30:
+#line 307 "geometry.yy"
+{ 	
+		cout << "face, 1 = " << yyvsp[-6].val << " " << yyvsp[-4].val << " "  << yyvsp[-2].val << " " << yyvsp[0].val << endl; 
+		polyhedron->AddFace (int(yyvsp[-6].val)-1, int(yyvsp[-4].val)-1, int(yyvsp[-2].val)-1);
+		polyhedron->AddFace (int(yyvsp[-6].val)-1, int(yyvsp[-2].val)-1, int(yyvsp[0].val)-1);
+		cout << yyvsp[-6].val << yyvsp[-4].val << yyvsp[-2].val << yyvsp[0].val << endl; 
+	;
+    break;}
+case 33:
+#line 321 "geometry.yy"
+{
+//		revolution->AddPoint (Point<2> ($1, $3));
+ 		cout << " " << yyvsp[-2].val << " " << yyvsp[0].val << endl;
+	;
+    break;}
+case 36:
+#line 338 "geometry.yy"
+{
+	        middlecurve->AddSegment (splinep1, Point<3> (yyvsp[-10].val, yyvsp[-8].val, yyvsp[-6].val), Point<3> (yyvsp[-4].val, yyvsp[-2].val, yyvsp[0].val));
+		splinep1(0) = yyvsp[-4].val; splinep1(1) = yyvsp[-2].val; splinep1(2) = yyvsp[0].val;
+		;
+    break;}
+case 37:
+#line 347 "geometry.yy"
+{
+                bspline = new BSplineCurve2d;
+                bspline -> AddPoint (Point<2> (yyvsp[-2].val, yyvsp[0].val));
+		cout << "first point" << endl;
+                ;
+    break;}
+case 39:
+#line 355 "geometry.yy"
+{ ;
+    break;}
+case 40:
+#line 357 "geometry.yy"
+{
+               bspline -> AddPoint (Point<2> (yyvsp[-2].val, yyvsp[0].val));
+		cout << "Add Point: " << yyvsp[-2].val << "-" << yyvsp[0].val << endl;
+               ;
+    break;}
+case 44:
+#line 379 "geometry.yy"
+{ cout << "singular edge:" << yyvsp[-2].val << " between "
+		 << yyvsp[-1].chptr << " and " << yyvsp[0].chptr << endl; 
+	  parsegeom->singedges.Append 
+	    (new SingularEdge (yyvsp[-2].val, parsegeom->GetSolid(yyvsp[-1].chptr), 
+				parsegeom->GetSolid(yyvsp[0].chptr)));
+	;
+    break;}
+case 45:
+#line 387 "geometry.yy"
+{ cout << "singular point:" << yyvsp[-3].val << " between "
+		 << yyvsp[-2].chptr << ", " << yyvsp[-1].chptr << " and " << yyvsp[0].chptr << endl; 
+	  parsegeom->singpoints.Append 
+	    (new SingularPoint (yyvsp[-3].val, parsegeom->GetSolid(yyvsp[-2].chptr), 
+				parsegeom->GetSolid(yyvsp[-1].chptr),
+				parsegeom->GetSolid(yyvsp[0].chptr)));
+	;
+    break;}
+case 46:
+#line 396 "geometry.yy"
+{ 	
+	  ARRAY<int> si1, si2;
+	  parsegeom->GetSolid(yyvsp[-2].chptr)->GetSurfaceIndices(si1);
+	  parsegeom->GetSolid(yyvsp[-1].chptr)->GetSurfaceIndices(si2);
+
+	  parsegeom->AddIdentification (
+		new CloseSurfaceIdentification (
+			parsegeom->GetNIdentifications()+1,
+			*parsegeom, 
+			parsegeom->GetSurface (si1[0]),
+			parsegeom->GetSurface (si2[0]),
+			parseflags));
+	;
+    break;}
+case 47:
+#line 411 "geometry.yy"
+{ 	
+	  ARRAY<int> si1, si2, si3;
+	  parsegeom->GetSolid(yyvsp[-2].chptr)->GetSurfaceIndices(si1);
+	  parsegeom->GetSolid(yyvsp[-1].chptr)->GetSurfaceIndices(si2);
+	  parsegeom->GetSolid(yyvsp[0].chptr)->GetSurfaceIndices(si3);
+
+	  parsegeom->AddIdentification (
+		new CloseEdgesIdentification (
+			parsegeom->GetNIdentifications()+1,
+			*parsegeom, 
+			parsegeom->GetSurface (si1.Get(1)),
+			parsegeom->GetSurface (si2.Get(1)),
+			parsegeom->GetSurface (si3.Get(1))));
+	;
+    break;}
+case 48:
+#line 427 "geometry.yy"
+{ 
+	  ARRAY<int> si1, si2;
+	  parsegeom->GetSolid(yyvsp[-1].chptr)->GetSurfaceIndices(si1);
+	  parsegeom->GetSolid(yyvsp[0].chptr)->GetSurfaceIndices(si2);
+
+	  parsegeom->AddIdentification (
+		new PeriodicIdentification (
+			parsegeom->GetNIdentifications()+1,
+			*parsegeom,
+			parsegeom->GetSurface (si1.Get(1)),
+			parsegeom->GetSurface (si2.Get(1))));
+	;
+    break;}
+case 49:
+#line 441 "geometry.yy"
+{
+	  int tlonr = 
+            parsegeom->SetTopLevelObject ((Solid*)parsegeom->GetSolid(yyvsp[-1].chptr));
+	  TopLevelObject * tlo = parsegeom->GetTopLevelObject (tlonr);
+	  if (parseflags.NumListFlagDefined ("col"))
+	    {
+	      const ARRAY<double> & col = parseflags.GetNumListFlag ("col");
+	      tlo->SetRGB (col[0], col[1], col[2]);
+	    }
+	  if (parseflags.GetDefineFlag ("transparent"))
+	    tlo->SetTransparent (1);
+	;
+    break;}
+case 50:
+#line 455 "geometry.yy"
+{
+	  ARRAY<int> si;
+	  parsegeom->GetSolid(yyvsp[-1].chptr)->GetSurfaceIndices(si);
+	  int tlonr = 
+	    parsegeom->SetTopLevelObject ((Solid*)parsegeom->GetSolid(yyvsp[-2].chptr),
+					  (Surface*)parsegeom->GetSurface(si.Get(1)));
+	  TopLevelObject * tlo = parsegeom->GetTopLevelObject (tlonr);
+	  if (parseflags.NumListFlagDefined ("col"))
+	    {
+	      const ARRAY<double> & col = parseflags.GetNumListFlag ("col");
+	      tlo->SetRGB (col.Get(1), col.Get(2), col.Get(3));
+	    }
+	  if (parseflags.GetDefineFlag ("transparent"))
+	    tlo->SetTransparent (1);
+	;
+    break;}
+case 51:
+#line 473 "geometry.yy"
+{
+	  parsegeom->SetBoundingBox (Box<3> (Point<3> (yyvsp[-11].val, yyvsp[-9].val, yyvsp[-7].val), 
+                                             Point<3> (yyvsp[-5].val, yyvsp[-3].val, yyvsp[-1].val)));
+	;
+    break;}
+case 52:
+#line 479 "geometry.yy"
+{
+	  parsegeom->AddUserPoint (Point<3> (yyvsp[-5].val, yyvsp[-3].val, yyvsp[-1].val));
+	;
+    break;}
+case 53:
+#line 484 "geometry.yy"
+{
+  	  CSGeometry::BCModification bcm;
+	  ARRAY<int> si;
+
+	  parsegeom->GetSolid(yyvsp[-2].chptr)->GetSurfaceIndices(si);
+	
+          bcm.tlonr = -1;
+	  int i;	
+	  for (i = 0; i < parsegeom->GetNTopLevelObjects(); i++)
+	    if (strcmp (parsegeom->GetTopLevelObject(i)->GetSolid()->Name(), yyvsp[-1].chptr) == 0)
+	      {
+	        bcm.tlonr = i;
+	        break;
+              }
+
+	  bcm.bcnr = int(yyvsp[0].val);
+	  for (i = 0; i < si.Size(); i++)
+            {
+	      bcm.si = si[i];
+              parsegeom->bcmodifications.Append (bcm);
+            }
+	;
+    break;}
+case 54:
+#line 512 "geometry.yy"
+{ parseflags.DeleteFlags (); ;
+    break;}
+case 58:
+#line 523 "geometry.yy"
+{ parseflags.SetFlag (yyvsp[0].chptr); ;
+    break;}
+case 59:
+#line 525 "geometry.yy"
+{ parseflags.SetFlag (yyvsp[-2].chptr, yyvsp[0].chptr); ;
+    break;}
+case 60:
+#line 527 "geometry.yy"
+{ parseflags.SetFlag (yyvsp[-2].chptr, yyvsp[0].val); ;
+    break;}
+case 61:
+#line 529 "geometry.yy"
+{ parseflags.SetFlag (yyvsp[-2].chptr, doublearray); ;
+    break;}
+case 62:
+#line 531 "geometry.yy"
+{ parseflags.SetFlag (yyvsp[-2].chptr, stringarray); ;
+    break;}
+case 63:
+#line 536 "geometry.yy"
+{ doublearray.SetSize (0); ;
+    break;}
+case 65:
+#line 541 "geometry.yy"
+{ doublearray.Append (yyvsp[0].val); ;
+    break;}
+case 66:
+#line 542 "geometry.yy"
+{ doublearray.Append (yyvsp[0].val); ;
+    break;}
+case 67:
+#line 547 "geometry.yy"
+{
+	  int i;
+	  for (i = 0; i < stringarray.Size(); i++)
+	     delete stringarray[i];
+	  stringarray.SetSize (0);
+	;
+    break;}
+case 69:
+#line 558 "geometry.yy"
+{
+			stringarray.Append (new char[strlen(yyvsp[0].chptr)+1]);
+			strcpy (stringarray.Last(), yyvsp[0].chptr);
+		;
+    break;}
+case 70:
+#line 564 "geometry.yy"
+{
+			stringarray.Append (new char[strlen(yyvsp[0].chptr)+1]);
+			strcpy (stringarray.Last(), yyvsp[0].chptr);
+		;
+    break;}
+case 71:
+#line 575 "geometry.yy"
+{ yyval.chptr = yyvsp[0].chptr; ;
+    break;}
+case 72:
+#line 576 "geometry.yy"
+{ yyval.chptr = yyvsp[0].chptr; ;
+    break;}
+}
+
+#line 709 "/usr/share/bison/bison.simple"
+
+
+  yyvsp -= yylen;
+  yyssp -= yylen;
+#if YYLSP_NEEDED
+  yylsp -= yylen;
+#endif
+
+#if YYDEBUG
+  if (yydebug)
+    {
+      short *yyssp1 = yyss - 1;
+      YYFPRINTF (stderr, "state stack now");
+      while (yyssp1 != yyssp)
+	YYFPRINTF (stderr, " %d", *++yyssp1);
+      YYFPRINTF (stderr, "\n");
+    }
+#endif
+
+  *++yyvsp = yyval;
+#if YYLSP_NEEDED
+  *++yylsp = yyloc;
+#endif
+
+  /* Now `shift' the result of the reduction.  Determine what state
+     that goes to, based on the state we popped back to and the rule
+     number reduced by.  */
+
+  yyn = yyr1[yyn];
+
+  yystate = yypgoto[yyn - YYNTBASE] + *yyssp;
+  if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+    yystate = yytable[yystate];
+  else
+    yystate = yydefgoto[yyn - YYNTBASE];
+
+  goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+  /* If not already recovering from an error, report this error.  */
+  if (!yyerrstatus)
+    {
+      ++yynerrs;
+
+#ifdef YYERROR_VERBOSE
+      yyn = yypact[yystate];
+
+      if (yyn > YYFLAG && yyn < YYLAST)
+	{
+	  YYSIZE_T yysize = 0;
+	  char *yymsg;
+	  int yyx, yycount;
+
+	  yycount = 0;
+	  /* Start YYX at -YYN if negative to avoid negative indexes in
+	     YYCHECK.  */
+	  for (yyx = yyn < 0 ? -yyn : 0;
+	       yyx < (int) (sizeof (yytname) / sizeof (char *)); yyx++)
+	    if (yycheck[yyx + yyn] == yyx)
+	      yysize += yystrlen (yytname[yyx]) + 15, yycount++;
+	  yysize += yystrlen ("parse error, unexpected ") + 1;
+	  yysize += yystrlen (yytname[YYTRANSLATE (yychar)]);
+	  yymsg = (char *) YYSTACK_ALLOC (yysize);
+	  if (yymsg != 0)
+	    {
+	      char *yyp = yystpcpy (yymsg, "parse error, unexpected ");
+	      yyp = yystpcpy (yyp, yytname[YYTRANSLATE (yychar)]);
+
+	      if (yycount < 5)
+		{
+		  yycount = 0;
+		  for (yyx = yyn < 0 ? -yyn : 0;
+		       yyx < (int) (sizeof (yytname) / sizeof (char *));
+		       yyx++)
+		    if (yycheck[yyx + yyn] == yyx)
+		      {
+			const char *yyq = ! yycount ? ", expecting " : " or ";
+			yyp = yystpcpy (yyp, yyq);
+			yyp = yystpcpy (yyp, yytname[yyx]);
+			yycount++;
+		      }
+		}
+	      yyerror (yymsg);
+	      YYSTACK_FREE (yymsg);
+	    }
+	  else
+	    yyerror ("parse error; also virtual memory exhausted");
+	}
+      else
+#endif /* defined (YYERROR_VERBOSE) */
+	yyerror ("parse error");
+    }
+  goto yyerrlab1;
+
+
+/*--------------------------------------------------.
+| yyerrlab1 -- error raised explicitly by an action |
+`--------------------------------------------------*/
+yyerrlab1:
+  if (yyerrstatus == 3)
+    {
+      /* If just tried and failed to reuse lookahead token after an
+	 error, discard it.  */
+
+      /* return failure if at end of input */
+      if (yychar == YYEOF)
+	YYABORT;
+      YYDPRINTF ((stderr, "Discarding token %d (%s).\n",
+		  yychar, yytname[yychar1]));
+      yychar = YYEMPTY;
+    }
+
+  /* Else will try to reuse lookahead token after shifting the error
+     token.  */
+
+  yyerrstatus = 3;		/* Each real token shifted decrements this */
+
+  goto yyerrhandle;
+
+
+/*-------------------------------------------------------------------.
+| yyerrdefault -- current state does not do anything special for the |
+| error token.                                                       |
+`-------------------------------------------------------------------*/
+yyerrdefault:
+#if 0
+  /* This is wrong; only states that explicitly want error tokens
+     should shift them.  */
+
+  /* If its default is to accept any token, ok.  Otherwise pop it.  */
+  yyn = yydefact[yystate];
+  if (yyn)
+    goto yydefault;
+#endif
+
+
+/*---------------------------------------------------------------.
+| yyerrpop -- pop the current state because it cannot handle the |
+| error token                                                    |
+`---------------------------------------------------------------*/
+yyerrpop:
+  if (yyssp == yyss)
+    YYABORT;
+  yyvsp--;
+  yystate = *--yyssp;
+#if YYLSP_NEEDED
+  yylsp--;
+#endif
+
+#if YYDEBUG
+  if (yydebug)
+    {
+      short *yyssp1 = yyss - 1;
+      YYFPRINTF (stderr, "Error: state stack now");
+      while (yyssp1 != yyssp)
+	YYFPRINTF (stderr, " %d", *++yyssp1);
+      YYFPRINTF (stderr, "\n");
+    }
+#endif
+
+/*--------------.
+| yyerrhandle.  |
+`--------------*/
+yyerrhandle:
+  yyn = yypact[yystate];
+  if (yyn == YYFLAG)
+    goto yyerrdefault;
+
+  yyn += YYTERROR;
+  if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR)
+    goto yyerrdefault;
+
+  yyn = yytable[yyn];
+  if (yyn < 0)
+    {
+      if (yyn == YYFLAG)
+	goto yyerrpop;
+      yyn = -yyn;
+      goto yyreduce;
+    }
+  else if (yyn == 0)
+    goto yyerrpop;
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+  YYDPRINTF ((stderr, "Shifting error token, "));
+
+  *++yyvsp = yylval;
+#if YYLSP_NEEDED
+  *++yylsp = yylloc;
+#endif
+
+  yystate = yyn;
+  goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here.  |
+`-------------------------------------*/
+yyacceptlab:
+  yyresult = 0;
+  goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here.  |
+`-----------------------------------*/
+yyabortlab:
+  yyresult = 1;
+  goto yyreturn;
+
+/*---------------------------------------------.
+| yyoverflowab -- parser overflow comes here.  |
+`---------------------------------------------*/
+yyoverflowlab:
+  yyerror ("parser stack overflow");
+  yyresult = 2;
+  /* Fall through.  */
+
+yyreturn:
+#ifndef yyoverflow
+  if (yyss != yyssa)
+    YYSTACK_FREE (yyss);
+#endif
+  return yyresult;
+}
+#line 577 "geometry.yy"
+
+
+
+int yyerror (char * s)
+{	
+  cerr << s << " in line " << linenum << endl;
+  return 0;
+}
+
diff --git a/Netgen/libsrc/csg/geoml.hpp b/Netgen/libsrc/csg/geoml.hpp
new file mode 100644
index 0000000000..e7974ad206
--- /dev/null
+++ b/Netgen/libsrc/csg/geoml.hpp
@@ -0,0 +1,16 @@
+#ifndef FILE_GEOML
+#define FILE_GEOML
+
+/* *************************************************************************/
+/* File:   geoml.hh                                                        */
+/* Author: Joachim Schoeberl                                               */
+/* Date:   21. Jun. 98                                                     */
+/* *************************************************************************/
+
+#include <geom/geom.hh>
+
+#include <geom/solid.hh>
+#include <geom/algprim.hh>
+#include <geom/adtree.hh>
+#include <geom/csgeom.hh>
+#endif
diff --git a/Netgen/libsrc/csg/identify.cpp b/Netgen/libsrc/csg/identify.cpp
new file mode 100644
index 0000000000..337bc26a4a
--- /dev/null
+++ b/Netgen/libsrc/csg/identify.cpp
@@ -0,0 +1,1483 @@
+#include <mystdlib.h>
+#include <myadt.hpp>
+
+#include <linalg.hpp>
+#include <csg.hpp>
+#include <meshing.hpp>
+
+
+namespace netgen
+{
+Identification :: Identification (int anr, const CSGeometry & ageom)
+  : geom(ageom), identfaces(10)
+{
+  nr = anr;
+}
+
+Identification :: ~Identification ()
+{
+  ;
+}
+
+
+ostream & operator<< (ostream & ost, Identification & ident)
+{
+  ident.Print (ost);
+  return ost;
+}
+
+
+/*
+void Identification :: IdentifySpecialPoints (ARRAY<class SpecialPoint> & points)
+{
+  ;
+}
+*/
+
+
+int Identification :: 
+Identifyable (const SpecialPoint & sp1, const SpecialPoint & sp2) const
+{
+  cout << "Identification::Identifyable called for base-class" << endl;
+  return 0;
+}
+
+int Identification :: 
+Identifyable (const Point<3> & p1, const Point<3> & sp2) const
+{
+  cout << "Identification::Identifyable called for base-class" << endl;
+  return 0;
+}
+
+
+int Identification :: 
+IdentifyableCandidate (const SpecialPoint & sp1) const
+{
+  return 1;
+}
+
+
+int Identification :: 
+ShortEdge (const SpecialPoint & sp1, const SpecialPoint & sp2) const
+{
+  return 0;
+}
+
+int Identification :: GetIdentifiedPoint (class Mesh & mesh, int pi)
+{
+  cout << "Identification::GetIdentifiedPoint called for base-class" << endl;
+  return -1;
+}
+
+void Identification :: IdentifyPoints (Mesh & mesh)
+{
+  cout << "Identification::IdentifyPoints called for base-class" << endl;
+  ;
+}
+
+void Identification :: IdentifyFaces (class Mesh & mesh)
+{
+  cout << "Identification::IdentifyFaces called for base-class" << endl;
+  ;
+}
+
+void Identification :: 
+BuildSurfaceElements (ARRAY<Segment> & segs,
+		      Mesh & mesh, const Surface * surf)
+{
+  cout << "Identification::BuildSurfaceElements called for base-class" << endl;
+  ;
+}
+
+
+void Identification :: 
+BuildVolumeElements (ARRAY<class Element2d> & surfels,
+			  class Mesh & mesh)
+{
+  ;
+}
+
+void Identification :: 
+GetIdentifiedFaces (ARRAY<INDEX_2> & idfaces) const
+{
+  idfaces.SetSize(0);
+  for (int i = 1; i <= identfaces.GetNBags(); i++)
+    for (int j = 1; j <= identfaces.GetBagSize(i); j++)
+      {
+	INDEX_2 i2;
+	int val;
+	identfaces.GetData (i, j, i2, val);
+	idfaces.Append (i2);
+      }
+}
+
+
+
+
+PeriodicIdentification ::
+PeriodicIdentification (int anr,
+			const CSGeometry & ageom,
+			const Surface * as1,
+			const Surface * as2)
+  : Identification(anr, ageom)
+{
+  s1 = as1;
+  s2 = as2;
+}
+
+PeriodicIdentification :: ~PeriodicIdentification ()
+{
+  ;
+}
+
+/*
+void PeriodicIdentification :: IdentifySpecialPoints 
+(ARRAY<class SpecialPoint> & points)
+{
+  int i, j;
+  int bestj;
+  double bestval, val;
+
+  for (i = 1; i <= points.Size(); i++)
+    {
+      Point<3> p1 = points.Get(i).p;
+      Point<3> hp1 = p1;
+      s1->Project (hp1);
+      if (Dist (p1, hp1) > 1e-6) continue;
+
+      Vec<3> n1;
+      s1->GetNormalVector (p1, n1);
+      n1 /= n1.Length();
+      if ( fabs(n1 * points.Get(i).v) > 1e-3)
+	continue;
+
+      bestval = 1e8;
+      bestj = 1;
+      for (j = 1; j <= points.Size(); j++)
+	{
+	  Point<3> p2= points.Get(j).p;
+	  Point<3> hp2 = p2;
+	  s2->Project (hp2);
+	  if (Dist (p2, hp2) > 1e-6) continue;
+	  
+	  Vec<3> n2;
+	  s2->GetNormalVector (p2, n2);
+	  n2 /= n2.Length();
+	  if ( fabs(n2 * points.Get(j).v) > 1e-3)
+	    continue;
+
+
+	  Vec<3> v(p1, p2);
+	  double vl = v.Length();
+	  double cl = fabs (v*n1);
+
+	  val = 1 - cl*cl/(vl*vl);
+
+	  val += (points.Get(i).v - points.Get(j).v).Length();
+
+	  if (val < bestval)
+	    {
+	      bestj = j;
+	      bestval = val;
+	    }
+	}
+
+      (*testout) << "Identify Periodic special points: pi = " 
+		 << points.Get(i).p << ", vi = " << points.Get(i).v 
+		 << " pj = " << points.Get(bestj).p 
+		 << ", vj = " << points.Get(bestj).v 
+		 << " bestval = " << bestval << endl;
+    }
+}
+*/
+
+int PeriodicIdentification :: 
+Identifyable (const SpecialPoint & sp1, const SpecialPoint & sp2) const
+{
+  int i;
+  double val;
+  
+  SpecialPoint hsp1 = sp1;
+  SpecialPoint hsp2 = sp2;
+
+  for (i = 1; i <= 1; i++)
+    {
+      //      Swap (hsp1, hsp2);
+
+      if (!s1->PointOnSurface (hsp1.p))
+	continue;
+
+      Vec<3> n1;
+      s1->GetNormalVector (hsp1.p, n1);
+      n1 /= n1.Length();
+      if ( fabs(n1 * hsp1.v) > 1e-3)
+	continue;
+
+
+      if (!s2->PointOnSurface(hsp2.p))
+	continue;
+
+      Vec<3> n2;
+      s2->GetNormalVector (hsp2.p, n2);
+      n2 /= n2.Length();
+      if ( fabs(n2 * hsp2.v) > 1e-3)
+	continue;
+
+
+      Vec<3> v = hsp2.p - hsp1.p;
+      double vl = v.Length();
+      double cl = fabs (v*n1);
+      
+
+      val = 1 - cl*cl/(vl*vl);
+      val += (hsp1.v - hsp2.v).Length();
+    
+      if (val < 1e-3)
+	{
+	  return 1;
+	}
+    }
+
+  return 0;
+}
+
+int PeriodicIdentification :: 
+Identifyable (const Point<3> & p1, const Point<3> & p2) const
+{
+  return (s1->PointOnSurface (p1) &&
+	  s2->PointOnSurface (p2));
+}
+  
+
+
+
+int PeriodicIdentification :: 
+GetIdentifiedPoint (class Mesh & mesh,  int pi)
+{
+  const Surface * sold, *snew;
+  const Point<3> & p = mesh.Point (pi);
+
+  if (s1->PointOnSurface (p))
+    {
+      snew = s2;
+    }
+  else
+    {
+      if (s2->PointOnSurface (p))
+	{
+	  snew = s1;
+	}
+      else
+	{
+	  cerr << "GetIdenfifiedPoint: Not possible" << endl;
+	  exit (1);
+	}    
+    }
+  
+  // project to other surface
+  Point<3> hp = p;
+  snew->Project (hp);
+
+  int i;
+  int newpi = 0;
+  for (i = 1; i <= mesh.GetNP(); i++)
+    if (Dist2 (mesh.Point(i), hp) < 1e-12)
+      {
+	newpi = i;
+	break;
+      }
+  if (!newpi)
+    newpi = mesh.AddPoint (hp);
+
+  if (snew == s2)
+    mesh.GetIdentifications().Add (pi, newpi, nr);
+  else
+    mesh.GetIdentifications().Add (newpi, pi, nr);
+	   
+  /* 
+  (*testout) << "Identify points(periodic), nr = " << nr << ": " << mesh.Point(pi)
+	     << " and " << mesh.Point(newpi) 
+	     << ((snew == s2) ? "" : " inverse")
+	     << endl;
+  */
+  return newpi;
+}
+
+
+void PeriodicIdentification :: IdentifyPoints (class Mesh & mesh)
+{
+  int i, j;
+  for (i = 1; i <= mesh.GetNP(); i++)
+    {
+      Point<3> p = mesh.Point(i);
+      if (s1->PointOnSurface (p))
+	{
+	  Point<3> pp = p;
+	  s2->Project (pp);
+	  for (j = 1; j <= mesh.GetNP(); j++)
+	    if (Dist2(mesh.Point(j), pp) < 1e-6)
+	      {
+		mesh.GetIdentifications().Add (i, j, nr);
+		/*
+		(*testout) << "Identify points(periodic:), nr = " << nr << ": "
+			   << mesh.Point(i) << " - " << mesh.Point(j) << endl;
+		*/
+	      }
+	}
+    }
+}
+
+
+void PeriodicIdentification :: IdentifyFaces (class Mesh & mesh)
+{
+  int i, j, k, l;
+  int fi1, fi2, side;
+  for (i = 1; i <= mesh.GetNFD(); i++)
+    for (j = 1; j <= mesh.GetNFD(); j++)
+      {
+	int surfi = mesh.GetFaceDescriptor(i).SurfNr();
+	int surfj = mesh.GetFaceDescriptor(j).SurfNr();
+	if (surfi == surfj)
+	  continue;
+	
+	if (geom.GetSurface (surfi) != s1 ||
+	    geom.GetSurface (surfj) != s2)
+	  continue;
+	    
+	int idok = 1;
+
+
+	//	(*testout) << "check faces " << i << " and " << j << endl;
+	for (side = 1; side <= 2 && idok; side++)
+	  {
+	    if (side == 1)
+	      {
+		fi1 = i; 
+		fi2 = j;
+	      }
+	    else
+	      {
+		fi1 = j;
+		fi2 = i;
+	      }
+
+	    for (k = 1; k <= mesh.GetNSeg(); k++)
+	      {
+		const Segment & seg1 = mesh.LineSegment(k);
+		if (seg1.si != fi1)
+		  continue;
+
+		int foundother = 0;
+		for (l = 1; l <= mesh.GetNSeg(); l++)
+		  {
+		    const Segment & seg2 = mesh.LineSegment(l);
+		    if (seg2.si != fi2)
+		      continue;
+		    
+		    //		    (*testout) << "seg1 = " << seg1.p1 << "-" << seg1.p2 << ", seg2 = " << seg2.p1 << "-" << seg2.p2;
+
+		    if (side == 1)
+		      {
+			if (mesh.GetIdentifications().Get (seg1.p1, seg2.p1) &&
+			    mesh.GetIdentifications().Get (seg1.p2, seg2.p2))
+			  {
+			    foundother = 1;
+			    break;
+			  }
+			
+			if (mesh.GetIdentifications().Get (seg1.p1, seg2.p2) &&
+			    mesh.GetIdentifications().Get (seg1.p2, seg2.p1))
+			  {
+			    foundother = 1;
+			    break;
+			  }
+		      }
+		    else
+		      {
+			if (mesh.GetIdentifications().Get (seg2.p1, seg1.p1) &&
+			    mesh.GetIdentifications().Get (seg2.p2, seg1.p2))
+			  {
+			    foundother = 1;
+			    break;
+			  }
+			
+			if (mesh.GetIdentifications().Get (seg2.p1, seg1.p2) &&
+			    mesh.GetIdentifications().Get (seg2.p2, seg1.p1))
+			  {
+			    foundother = 1;
+			    break;
+			  }
+		      }
+		  }
+
+		if (!foundother)
+		  {
+		    idok = 0;
+		    break;
+		  }
+	      }
+	  }
+
+
+	if (idok)
+	  {
+	    // (*testout) << "Identify faces " << i << " and " << j << endl;
+	    INDEX_2 fpair(i,j);
+	    fpair.Sort();
+	    identfaces.Set (fpair, 1);
+	  }
+      }
+}
+
+
+
+void PeriodicIdentification :: 
+BuildSurfaceElements (ARRAY<Segment> & segs,
+		      Mesh & mesh, const Surface * surf)
+{
+  int i1, i2;
+  int found = 0;
+  int i, j, k;
+  int fother;
+
+
+  int facei = segs.Get(1).si;
+  int surfnr = mesh.GetFaceDescriptor(facei).SurfNr();
+
+
+  if (geom.GetSurface(surfnr) == s1 ||
+      geom.GetSurface(surfnr) == s2)
+    {
+      //      (*testout) << "surfs found !" << endl;
+
+      for (i = 1; i <= mesh.GetNSE(); i++)
+	{
+	  const Element2d & sel = mesh.SurfaceElement(i);
+	  INDEX_2 fpair (facei, sel.GetIndex());
+	  fpair.Sort();
+	  if (identfaces.Used (fpair))
+	    {
+	      found = 1;
+	      fother = sel.GetIndex();
+
+	      // copy element
+	      Element2d newel(3);
+	      newel.SetIndex (facei);
+	      for (k = 1; k <= 3; k++)
+		{
+		  newel.PNum(k) = 
+		    GetIdentifiedPoint (mesh, sel.PNum(k));
+		}	  
+
+	      Vec<3> nt = Cross (Point<3> (mesh.Point (newel.PNum(2)))-
+				 Point<3> (mesh.Point (newel.PNum(1))),
+				 Point<3> (mesh.Point (newel.PNum(3)))-
+				 Point<3> (mesh.Point (newel.PNum(1))));
+	      
+	      Vec<3> nsurf;
+	      geom.GetSurface (surfnr)->GetNormalVector (mesh.Point(newel.PNum(1)), nsurf);
+	      if (nsurf * nt < 0)
+		Swap (newel.PNum(2), newel.PNum(3));
+				
+	      mesh.AddSurfaceElement (newel);
+	    }
+	}
+    }
+  
+  if (found)
+    {
+      (*mycout) << " copy face " << facei << " from face " << fother;
+      segs.SetSize(0);
+    }
+}
+
+
+
+
+
+
+
+
+void PeriodicIdentification :: Print (ostream & ost) const
+{
+  ost << "Periodic Identifiaction, surfaces: " 
+      << s1->Name() << " - " << s2->Name() << endl;
+  s1->Print (ost);
+  ost << " - ";
+  s2->Print (ost);
+  ost << endl;
+}
+
+
+void PeriodicIdentification :: GetData (ostream & ost) const
+{
+  ost << "periodic " << s1->Name() << " " << s2->Name();
+}
+
+
+
+
+
+
+
+CloseSurfaceIdentification ::
+CloseSurfaceIdentification (int anr,
+			    const CSGeometry & ageom,
+			    const Surface * as1,
+			    const Surface * as2,
+			    const Flags & flags)
+  : Identification(anr, ageom)
+{
+  s1 = as1;
+  s2 = as2;
+  ref_levels = int (flags.GetNumFlag ("reflevels", 2));
+  ref_levels_s1 = int (flags.GetNumFlag ("reflevels1", 0));
+  ref_levels_s2 = int (flags.GetNumFlag ("reflevels2", 0));
+  slices = flags.GetNumListFlag ("slices");
+  // eps_n = 1e-3;
+  eps_n = 1e-6;
+}
+
+CloseSurfaceIdentification :: ~CloseSurfaceIdentification ()
+{
+  ;
+}
+
+void CloseSurfaceIdentification :: Print (ostream & ost) const
+{
+  ost << "CloseSurface Identifiaction, surfaces: " 
+      << s1->Name() << " - " << s2->Name() << endl;
+  s1->Print (ost);
+  s2->Print (ost);
+  ost << endl;
+}
+
+
+void CloseSurfaceIdentification :: GetData (ostream & ost) const
+{
+  ost << "close surface " << s1->Name() << " " << s2->Name();
+}
+
+
+/*
+void CloseSurfaceIdentification :: IdentifySpecialPoints 
+(ARRAY<class SpecialPoint> & points)
+{
+  int i, j;
+  int bestj;
+  double bestval, val;
+
+  for (i = 1; i <= points.Size(); i++)
+    {
+      Point<3> p1 = points.Get(i).p;
+      Vec<3> n1;
+
+      if (!s1->PointOnSurface (p1))
+	continue;
+
+      s1->GetNormalVector (p1, n1);
+      n1 /= n1.Length();
+      if ( fabs(n1 * points.Get(i).v) > 1e-3)
+	continue;
+
+      bestval = 1e8;
+      bestj = 1;
+      for (j = 1; j <= points.Size(); j++)
+	{
+	  Point<3> p2= points.Get(j).p;
+	  if (!s2->PointOnSurface (p2))
+	    continue;
+	  
+	  Vec<3> n2;
+	  s2->GetNormalVector (p2, n2);
+	  n2 /= n2.Length();
+	  if ( fabs(n2 * points.Get(j).v) > 1e-3)
+	    continue;
+
+
+	  Vec<3> v(p1, p2);
+	  double vl = v.Length();
+	  double cl = fabs (v*n1);
+
+	  val = 1 - cl*cl/(vl*vl);
+
+	  val += (points.Get(i).v - points.Get(j).v).Length();
+
+	  if (val < bestval)
+	    {
+	      bestj = j;
+	      bestval = val;
+	    }
+	}
+
+      (*testout) << "Identify close surfaces special points: pi = " 
+		 << points.Get(i).p << ", vi = " << points.Get(i).v 
+		 << " pj = " << points.Get(bestj).p 
+		 << ", vj = " << points.Get(bestj).v 
+		 << " bestval = " << bestval << endl;
+    }
+}
+*/
+
+int CloseSurfaceIdentification :: 
+Identifyable (const SpecialPoint & sp1, const SpecialPoint & sp2) const
+{
+  int i;
+  double val;
+
+  for (i = 1; i <= 1; i++)
+    {
+      if (!s1->PointOnSurface (sp1.p))
+	continue;
+
+      Vec<3> n1;
+      s1->GetNormalVector (sp1.p, n1);
+      n1.Normalize();
+      if ( fabs(n1 * sp1.v) > eps_n)
+	continue;
+
+      if (!s2->PointOnSurface(sp2.p))
+	continue;
+
+      Vec<3> n2;
+      s2->GetNormalVector (sp2.p, n2);
+      n2.Normalize();
+      if ( fabs(n2 * sp2.v) > eps_n)
+	continue;
+
+      // must have joint surface 
+      bool joint = 0;
+      for (int j = 0; j < geom.GetNSurf(); j++)
+	{
+	  if (geom.GetSurface(j) -> PointOnSurface(sp1.p) &&
+	      geom.GetSurface(j) -> PointOnSurface(sp2.p) )
+	    {
+	      Vec<3> hn1, hn2;
+	      geom.GetSurface(j)->GetNormalVector (sp1.p, hn1);
+	      geom.GetSurface(j)->GetNormalVector (sp2.p, hn2);
+
+	      if (hn1 * hn2 > 0)
+		{
+		  joint = 1;
+		  break;
+		}
+	    }
+	}
+      if (!joint) continue;
+
+      Vec<3> v = sp2.p - sp1.p;
+      double vl = v.Length();
+      double cl = fabs (v*n1);
+      
+      /*
+      val = 1 - cl*cl/(vl*vl);
+      val += (sp1.v - sp2.v).Length();
+    
+      if (val < 1e-3)
+	{
+	  return 1;
+	}
+      */
+      if (cl > (1-eps_n*eps_n) * vl && (sp1.v - sp2.v).Length() < 0.1)
+	return 1;
+    }
+
+  return 0;
+}
+
+int CloseSurfaceIdentification :: 
+Identifyable (const Point<3> & p1, const Point<3> & p2) const
+{
+  return (s1->PointOnSurface (p1) &&
+	  s2->PointOnSurface (p2));
+}
+  
+
+
+
+int CloseSurfaceIdentification :: 
+IdentifyableCandidate (const SpecialPoint & sp1) const
+{
+  if (s1->PointOnSurface (sp1.p))
+    {
+      Vec<3> n1;
+      s1->GetNormalVector (sp1.p, n1);
+      n1.Normalize();
+      if ( fabs(n1 * sp1.v) > eps_n)
+	return 0;
+      return 1;
+    }
+
+  if (s2->PointOnSurface (sp1.p))
+    {
+      Vec<3> n1;
+      s2->GetNormalVector (sp1.p, n1);
+      n1.Normalize();
+      if ( fabs(n1 * sp1.v) > eps_n)
+	return 0;
+      return 1;
+    }
+  return 0;
+}
+
+
+
+int CloseSurfaceIdentification :: 
+ShortEdge (const SpecialPoint & sp1, const SpecialPoint & sp2) const
+{
+  int i;
+  double val;
+  
+  SpecialPoint hsp1 = sp1;
+  SpecialPoint hsp2 = sp2;
+
+  if ( (s1->PointOnSurface (hsp1.p) && s2->PointOnSurface (hsp2.p)) ||
+       (s1->PointOnSurface (hsp2.p) && s2->PointOnSurface (hsp1.p)) )
+    {
+      return 1;
+    }
+  return 0;
+}
+
+
+
+int CloseSurfaceIdentification :: 
+GetIdentifiedPoint (class Mesh & mesh,  int pi)
+{
+  const Surface * sold, *snew;
+  const Point<3> & p = mesh.Point (pi);
+
+  ARRAY<int,PointIndex::BASE> identmap(mesh.GetNP());
+  mesh.GetIdentifications().GetMap (nr, identmap);
+  if (identmap.Get(pi))
+    return identmap.Get(pi);
+
+  if (s1->PointOnSurface (p))
+    {
+      snew = s2;
+    }
+  else
+    {
+      if (s2->PointOnSurface (p))
+	{
+	  snew = s1;
+	}
+      else
+	{
+	  (*testout)  << "GetIdenfifiedPoint: Not possible" << endl;
+	  (*testout) << "p = " << p << endl;
+	  (*testout) << "surf1: ";
+	  s1->Print (*testout); 
+	  (*testout) << endl;
+	  (*testout) << "surf2: ";
+	  s2->Print (*testout);
+	  (*testout) << endl;
+
+	  cerr << "GetIdenfifiedPoint: Not possible" << endl;
+	  exit (1);
+	}    
+    }
+  
+  // project to other surface
+  Point<3> hp = p;
+  snew->Project (hp);
+
+  int i;
+  int newpi = 0;
+  for (i = 1; i <= mesh.GetNP(); i++)
+    if (Dist2 (mesh.Point(i), hp) < 1e-12)
+      //    if (Dist2 (mesh.Point(i), hp) < 1 * Dist2 (hp, p))
+      {
+	newpi = i;
+	break;
+      }
+  if (!newpi)
+    newpi = mesh.AddPoint (hp);
+
+  if (snew == s2)
+    mesh.GetIdentifications().Add (pi, newpi, nr);
+  else
+    mesh.GetIdentifications().Add (newpi, pi, nr);
+	   
+  /* 
+  (*testout) << "Identify points(closesurface), nr = " << nr << ": " << mesh.Point(pi)
+	     << " and " << mesh.Point(newpi) 
+	     << ((snew == s2) ? "" : " inverse")
+	     << endl;
+  */
+  return newpi;
+}
+
+
+
+
+
+void CloseSurfaceIdentification :: IdentifyPoints (Mesh & mesh)
+{
+  int i, j;
+  int i1, i2;
+
+  int np = mesh.GetNP();
+  BitArray ons2(np);
+  ons2.Clear();
+  for (i2 = 1; i2 <= np; i2++)
+    if (s2->PointOnSurface (mesh.Point(i2)))
+      ons2.Set (i2);
+    
+  for (i1 = 1; i1 <= np; i1++)
+    {
+      const Point<3> p1 = mesh.Point(i1);
+      if (s1->PointOnSurface (p1))
+	{
+	  int candi2 = 0;
+	  double mindist = 1e10;
+
+	  Vec<3> n1;
+	  s1->GetNormalVector (p1, n1);
+	  n1.Normalize();
+
+	  for (i2 = 1; i2 <= np; i2++)
+	    {
+	      if (i2 == i1)
+		continue;
+	
+	      const Point<3> p2 = mesh.Point(i2);
+	      
+	      if (!ons2.Test(i2))
+		continue;
+		  /*
+	      if (!s2->PointOnSurface (p2))
+		continue;
+		  */
+	      Vec<3> n = p2 - p1;
+	      n.Normalize();
+	      
+
+	      if (fabs (n * n1) > 0.9 &&
+		  Dist (p1, p2) < mindist)
+		{
+		  candi2 = i2;
+		  mindist = Dist (p1, p2);
+		}
+	    }
+
+	  if (candi2)
+	    {
+	      // (*testout) << "identify points " << p1 << " - " << mesh.Point(candi2) << endl;
+	      (*testout) << "Add Identification from CSI2, p1 = " 
+			 << mesh[PointIndex(i1)] << ", p2 = " 
+			 << mesh[PointIndex(candi2)] << endl;
+
+	      mesh.GetIdentifications().Add (i1, candi2, nr);
+	    }
+	}
+    }
+}
+
+
+
+void CloseSurfaceIdentification :: IdentifyFaces (class Mesh & mesh)
+{
+  int i, j, k, l;
+  int fi1, fi2, side;
+
+  int s1rep, s2rep;
+  for (i = 0; i < geom.GetNSurf(); i++)
+    {
+      if (geom.GetSurface (i) == s1) 
+	s1rep = geom.GetSurfaceClassRepresentant(i);
+      if (geom.GetSurface (i) == s2) 
+	s2rep = geom.GetSurfaceClassRepresentant(i);
+    }
+
+  for (i = 1; i <= mesh.GetNFD(); i++)
+    for (j = 1; j <= mesh.GetNFD(); j++)
+      {
+	int surfi = mesh.GetFaceDescriptor(i).SurfNr();
+	int surfj = mesh.GetFaceDescriptor(j).SurfNr();
+	if (surfi == surfj)
+	  continue;
+
+	if (s1rep != surfi || s2rep != surfj) 
+	  continue;
+
+	/*
+	if (geom.GetSurface (surfi) != s1 ||
+	    geom.GetSurface (surfj) != s2)
+	  continue;
+	*/
+  
+	int idok = 1;
+
+
+	// (*testout) << "check faces " << i << " and " << j << endl;
+	for (side = 1; side <= 2 && idok; side++)
+	  {
+	    if (side == 1)
+	      {
+		fi1 = i; 
+		fi2 = j;
+	      }
+	    else
+	      {
+		fi1 = j;
+		fi2 = i;
+	      }
+
+	    for (k = 1; k <= mesh.GetNSeg(); k++)
+	      {
+		const Segment & seg1 = mesh.LineSegment(k);
+		if (seg1.si != fi1)
+		  continue;
+
+		int foundother = 0;
+		for (l = 1; l <= mesh.GetNSeg(); l++)
+		  {
+		    const Segment & seg2 = mesh.LineSegment(l);
+		    if (seg2.si != fi2)
+		      continue;
+		    
+		    //		    (*testout) << "seg1 = " << seg1.p1 << "-" << seg1.p2 << ", seg2 = " << seg2.p1 << "-" << seg2.p2;
+
+		    if (side == 1)
+		      {
+			if (mesh.GetIdentifications().Get (seg1.p1, seg2.p1) &&
+			    mesh.GetIdentifications().Get (seg1.p2, seg2.p2))
+			  {
+			    foundother = 1;
+			    break;
+			  }
+			
+			if (mesh.GetIdentifications().Get (seg1.p1, seg2.p2) &&
+			    mesh.GetIdentifications().Get (seg1.p2, seg2.p1))
+			  {
+			    foundother = 1;
+			    break;
+			  }
+		      }
+		    else
+		      {
+			if (mesh.GetIdentifications().Get (seg2.p1, seg1.p1) &&
+			    mesh.GetIdentifications().Get (seg2.p2, seg1.p2))
+			  {
+			    foundother = 1;
+			    break;
+			  }
+			
+			if (mesh.GetIdentifications().Get (seg2.p1, seg1.p2) &&
+			    mesh.GetIdentifications().Get (seg2.p2, seg1.p1))
+			  {
+			    foundother = 1;
+			    break;
+			  }
+		      }
+		  }
+
+		if (!foundother)
+		  {
+		    idok = 0;
+		    break;
+		  }
+	      }
+	  }
+
+
+	if (idok)
+	  {
+	    // (*testout) << "Identify faces " << i << " and " << j << endl;
+	    INDEX_2 fpair(i,j);
+	    fpair.Sort();
+	    identfaces.Set (fpair, 1);
+	  }
+      }
+}
+
+
+
+void CloseSurfaceIdentification :: 
+BuildSurfaceElements (ARRAY<Segment> & segs,
+		      Mesh & mesh, const Surface * surf)
+{
+  int i1, i2;
+  int found = 0, cntquads = 0;
+  int i, j, k;
+
+  // insert quad layer:
+  for (i1 = 1; i1 <= segs.Size(); i1++)
+    for (i2 = 1; i2 < i1; i2++)
+      {
+	const Segment & s1 = segs.Get(i1);
+	const Segment & s2 = segs.Get(i2);
+	if ( (mesh.GetIdentifications().Get (s1.p1, s2.p2) == nr &&
+	      mesh.GetIdentifications().Get (s1.p2, s2.p1) == nr)    || 
+	     (mesh.GetIdentifications().Get (s2.p1, s1.p2) == nr &&
+	      mesh.GetIdentifications().Get (s2.p2, s1.p1) == nr)
+	     )
+	  {
+	    Element2d el(4);
+	    el.PNum(1) = s1.p1;
+	    el.PNum(2) = s1.p2;
+	    el.PNum(3) = s2.p1;
+	    el.PNum(4) = s2.p2;
+
+	    Vec<3> n = Cross (Point<3> (mesh.Point(el.PNum(2)))-
+			      Point<3> (mesh.Point(el.PNum(1))),
+			      Point<3> (mesh.Point(el.PNum(4)))-
+			      Point<3> (mesh.Point(el.PNum(1))));
+
+	    Vec<3> ns;
+	    surf->GetNormalVector (mesh.Point(el.PNum(1)), ns);
+	    // (*testout) << "n = " << n << " ns = " << ns << endl;
+	    if (n * ns < 0)
+	      {
+		// (*testout) << "Swap the quad" << endl;
+		Swap (el.PNum(1), el.PNum(2));
+		Swap (el.PNum(3), el.PNum(4));
+	      }
+			     
+	    mesh.AddSurfaceElement (el);
+	    (*testout) << "add rect element: "
+		       << mesh.Point (el.PNum(1)) << " - "
+		       << mesh.Point (el.PNum(2)) << " - "
+		       << mesh.Point (el.PNum(3)) << " - "
+		       << mesh.Point (el.PNum(4)) << endl;
+	    found = 1;
+	    cntquads++;
+	  }
+      }
+
+  if (found)
+    {
+      (*mycout) << " insert quad layer of " << cntquads
+		<< " elements at face " << segs.Get(1).si << endl;
+      segs.SetSize(0);
+    }
+  else
+    {
+      BuildSurfaceElements2 (segs, mesh, surf);
+    }
+     
+  /* 
+      int fother;
+      int facei = segs.Get(1).si;
+      int surfnr = mesh.GetFaceDescriptor(facei).SurfNr();
+
+      int foundid = 0;
+      for (i = 1; i <= identfaces.GetNBags(); i++)
+	for (j = 1; j <= identfaces.GetBagSize(i); j++)
+	  {
+	    INDEX_2 i2;
+	    int data;
+	    identfaces.GetData (i, j, i2, data);
+	    if (i2.I1() == facei || i2.I2() == facei)
+	      foundid = 1;
+	  }
+
+      //      (*testout) << "facei = " << facei << ", surfnr = " << surfnr << endl;
+
+      if (foundid)
+	{
+	  //	  (*testout) << "surfaces found" << endl;
+	  // copy surface
+	  for (i = 1; i <= mesh.GetNSE(); i++)
+	    {
+	      const Element2d & sel = mesh.SurfaceElement(i);
+	      INDEX_2 fpair (facei, sel.GetIndex());
+	      fpair.Sort();
+	      if (identfaces.Used (fpair))
+		{
+		  found = 1;
+		  fother = sel.GetIndex();
+		  
+		  // copy element
+		  Element2d newel(3);
+		  newel.SetIndex (facei);
+		  for (k = 1; k <= 3; k++)
+		    {
+		      newel.PNum(k) = 
+			GetIdentifiedPoint (mesh, sel.PNum(k));
+		      //		      cout << "id-point = " << sel.PNum(k) << ", np = " << newel.PNum(k) << endl;
+		    }	  
+		  
+		  Vec<3> nt = Cross (Vec<3> (mesh.Point (newel.PNum(1)), mesh.Point (newel.PNum(2))),
+				    Vec<3> (mesh.Point (newel.PNum(1)), mesh.Point (newel.PNum(3))));
+		  Vec<3> nsurf;
+		  geom.GetSurface (surfnr)->GetNormalVector (mesh.Point(newel.PNum(1)), nsurf);
+		  if (nsurf * nt < 0)
+		    Swap (newel.PNum(2), newel.PNum(3));
+		  
+		  mesh.AddSurfaceElement (newel);
+		}
+	    }
+	}
+      
+      if (found)
+	(*mycout) << " copy face " << facei << " from face " << fother;
+    }
+      
+  if (found)
+    segs.SetSize(0);
+  */
+}
+
+
+
+
+
+
+void CloseSurfaceIdentification :: 
+BuildSurfaceElements2 (ARRAY<Segment> & segs,
+		       Mesh & mesh, const Surface * surf)
+{
+  int i1, i2;
+  int found = 0, cntquads = 0;
+  int i, j, k;
+
+  int fother;
+  int facei = segs.Get(1).si;
+  int surfnr = mesh.GetFaceDescriptor(facei).SurfNr();
+  
+  int foundid = 0;
+  for (i = 1; i <= identfaces.GetNBags(); i++)
+    for (j = 1; j <= identfaces.GetBagSize(i); j++)
+      {
+	INDEX_2 i2;
+	int data;
+	identfaces.GetData (i, j, i2, data);
+	if (i2.I1() == facei || i2.I2() == facei)
+	  foundid = 1;
+      }
+  
+      //      (*testout) << "facei = " << facei << ", surfnr = " << surfnr << endl;
+  
+  /*
+    if (geom.GetSurface(surfnr) == s1 ||
+    geom.GetSurface(surfnr) == s2)
+  */
+  if (foundid)
+    {
+      //	  (*testout) << "surfaces found" << endl;
+      // copy surface
+      for (i = 1; i <= mesh.GetNSE(); i++)
+	{
+	  const Element2d & sel = mesh.SurfaceElement(i);
+	  INDEX_2 fpair (facei, sel.GetIndex());
+	  fpair.Sort();
+	  if (identfaces.Used (fpair))
+	    {
+	      found = 1;
+	      fother = sel.GetIndex();
+	      
+	      // copy element
+	      Element2d newel(3);
+	      newel.SetIndex (facei);
+	      for (k = 1; k <= 3; k++)
+		{
+		  newel.PNum(k) = 
+		    GetIdentifiedPoint (mesh, sel.PNum(k));
+		  //		      cout << "id-point = " << sel.PNum(k) << ", np = " << newel.PNum(k) << endl;
+		}	  
+	      
+	      Vec<3> nt = Cross (Point<3> (mesh.Point (newel.PNum(2)))- 
+				 Point<3> (mesh.Point (newel.PNum(1))),
+				 Point<3> (mesh.Point (newel.PNum(3)))- 
+				 Point<3> (mesh.Point (newel.PNum(1))));
+	      Vec<3> nsurf;
+	      geom.GetSurface (surfnr)->GetNormalVector (mesh.Point(newel.PNum(1)), nsurf);
+	      if (nsurf * nt < 0)
+		Swap (newel.PNum(2), newel.PNum(3));
+	      
+	      mesh.AddSurfaceElement (newel);
+	    }
+	}
+    }
+  
+  if (found)
+    {
+      (*mycout) << " copy face " << facei << " from face " << fother;
+      segs.SetSize(0);
+    }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+void CloseSurfaceIdentification :: 
+BuildVolumeElements (ARRAY<class Element2d> & surfels,
+		     class Mesh & mesh)
+{
+  ;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+/*   ***************** Close Edges Identification ********** */
+
+
+
+CloseEdgesIdentification ::
+CloseEdgesIdentification (int anr,
+			  const CSGeometry & ageom,
+			  const Surface * afacet,
+			  const Surface * as1,
+			  const Surface * as2)
+  : Identification(anr, ageom)
+{
+  facet = afacet;
+  s1 = as1;
+  s2 = as2;
+}
+
+CloseEdgesIdentification :: ~CloseEdgesIdentification ()
+{
+  ;
+}
+
+void CloseEdgesIdentification :: Print (ostream & ost) const
+{
+  ost << "CloseEdges Identifiaction, facet = " 
+      << facet->Name() << ", surfaces: " 
+      << s1->Name() << " - " << s2->Name() << endl;
+  facet->Print (ost);
+  s1->Print (ost);
+  s2->Print (ost);
+  ost << endl;
+}
+
+
+void CloseEdgesIdentification :: GetData (ostream & ost) const
+{
+  ost << "closeedges " << facet->Name() << " " 
+      << s1->Name() << " " << s2->Name();
+}
+
+
+/*
+void CloseEdgesIdentification :: IdentifySpecialPoints 
+(ARRAY<class SpecialPoint> & points)
+{
+  int i, j;
+  int bestj;
+  double bestval, val;
+
+  for (i = 1; i <= points.Size(); i++)
+    {
+      Point<3> p1 = points.Get(i).p;
+      Vec<3> n1;
+
+      if (!s1->PointOnSurface (p1))
+	continue;
+
+      s1->GetNormalVector (p1, n1);
+      n1 /= n1.Length();
+      if ( fabs(n1 * points.Get(i).v) > 1e-3)
+	continue;
+
+      bestval = 1e8;
+      bestj = 1;
+      for (j = 1; j <= points.Size(); j++)
+	{
+	  Point<3> p2= points.Get(j).p;
+	  if (!s2->PointOnSurface (p2))
+	    continue;
+	  
+	  Vec<3> n2;
+	  s2->GetNormalVector (p2, n2);
+	  n2 /= n2.Length();
+	  if ( fabs(n2 * points.Get(j).v) > 1e-3)
+	    continue;
+
+
+	  Vec<3> v(p1, p2);
+	  double vl = v.Length();
+	  double cl = fabs (v*n1);
+
+	  val = 1 - cl*cl/(vl*vl);
+
+	  val += (points.Get(i).v - points.Get(j).v).Length();
+
+	  if (val < bestval)
+	    {
+	      bestj = j;
+	      bestval = val;
+	    }
+	}
+
+      (*testout) << "Identify close surfaces special points: pi = " 
+		 << points.Get(i).p << ", vi = " << points.Get(i).v 
+		 << " pj = " << points.Get(bestj).p 
+		 << ", vj = " << points.Get(bestj).v 
+		 << " bestval = " << bestval << endl;
+    }
+}
+*/
+
+int CloseEdgesIdentification :: 
+Identifyable (const SpecialPoint & sp1, const SpecialPoint & sp2) const
+{
+  int i;
+  double val;
+  
+  SpecialPoint hsp1 = sp1;
+  SpecialPoint hsp2 = sp2;
+
+  for (i = 1; i <= 1; i++)
+    {
+      if (!s1->PointOnSurface (hsp1.p))
+	continue;
+
+      Vec<3> n1;
+      s1->GetNormalVector (hsp1.p, n1);
+      n1 /= n1.Length();
+      if ( fabs(n1 * hsp1.v) > 1e-3)
+	continue;
+
+
+      if (!s2->PointOnSurface(hsp2.p))
+	continue;
+
+      Vec<3> n2;
+      s2->GetNormalVector (hsp2.p, n2);
+      n2 /= n2.Length();
+      if ( fabs(n2 * hsp2.v) > 1e-3)
+	continue;
+
+
+      Vec<3> v = hsp2.p - hsp1.p;
+      double vl = v.Length();
+      double cl = fabs (v*n1);
+      
+
+      val = 1 - cl*cl/(vl*vl);
+      val += (hsp1.v - hsp2.v).Length();
+    
+      if (val < 1e-3)
+	{
+	  return 1;
+	}
+    }
+
+  return 0;
+}
+
+
+
+
+void CloseEdgesIdentification :: IdentifyPoints (Mesh & mesh)
+{
+  int i, j;
+  int i1, i2;
+
+  int np = mesh.GetNP();
+  for (i1 = 1; i1 <= np; i1++)
+    for (i2 = 1; i2 <= np; i2++)
+      {
+	if (i2 == i1)
+	  continue;
+	
+	const Point<3> p1 = mesh.Point(i1);
+	const Point<3> p2 = mesh.Point(i2);
+	Point<3> pp1 = p1;
+	Point<3> pp2 = p2;
+	
+	s1->Project (pp1);
+	facet->Project (pp1);
+	s2->Project (pp2);
+	facet->Project (pp2);
+
+	if (Dist (p1, pp1) > 1e-6 || Dist (p2, pp2) > 1e-6)
+	  continue;
+
+	Vec<3> n1, nf, t;
+	Vec<3> n = p2 - p1;
+	n.Normalize();
+
+	s1->GetNormalVector (p1, n1);
+	facet->GetNormalVector (p1, nf);
+	t = Cross (n1, nf);
+	t /= t.Length();
+
+	if (fabs (n * t) < 0.5)
+	  {
+	    (*testout) << "close edges identify points " << p1 << " - " << p2 << endl;
+	    mesh.GetIdentifications().Add (i1, i2, nr);
+	  }
+      }
+}
+
+void CloseEdgesIdentification :: 
+BuildSurfaceElements (ARRAY<Segment> & segs,
+		      Mesh & mesh, const Surface * surf)
+{
+  int i1, i2;
+  int found = 0;
+  int i, j, k;
+
+  if (surf != facet)
+    return;
+
+  for (i1 = 1; i1 <= segs.Size(); i1++)
+    for (i2 = 1; i2 < i1; i2++)
+      {
+	const Segment & s1 = segs.Get(i1);
+	const Segment & s2 = segs.Get(i2);
+	if (mesh.GetIdentifications().Get (s1.p1, s2.p2) &&
+	    mesh.GetIdentifications().Get (s1.p2, s2.p1))
+	  {
+	    Element2d el(4);
+	    el.PNum(1) = s1.p1;
+	    el.PNum(2) = s1.p2;
+	    el.PNum(3) = s2.p2;
+	    el.PNum(4) = s2.p1;
+
+	    Vec<3> n = Cross (Point<3> (mesh.Point(el.PNum(2)))-
+			      Point<3> (mesh.Point(el.PNum(1))),
+			      Point<3> (mesh.Point(el.PNum(3)))-
+			      Point<3> (mesh.Point(el.PNum(1))));
+	    Vec<3> ns;
+	    surf->GetNormalVector (mesh.Point(el.PNum(1)), ns);
+	    (*testout) << "n = " << n << " ns = " << ns << endl;
+	    if (n * ns < 0)
+	      {
+		(*testout) << "Swap the quad" << endl;
+		Swap (el.PNum(1), el.PNum(2));
+		Swap (el.PNum(3), el.PNum(4));
+	      }
+			     
+	    
+	    Swap (el.PNum(3), el.PNum(4));
+	    mesh.AddSurfaceElement (el);
+	    (*testout) << "add rect element: "
+		       << mesh.Point (el.PNum(1)) << " - "
+		       << mesh.Point (el.PNum(2)) << " - "
+		       << mesh.Point (el.PNum(3)) << " - "
+		       << mesh.Point (el.PNum(4)) << endl;
+	    found = 1;
+	  }
+      }
+
+  if (found)
+    segs.SetSize(0);
+}
+
+}
diff --git a/Netgen/libsrc/csg/identify.hpp b/Netgen/libsrc/csg/identify.hpp
new file mode 100644
index 0000000000..b358a424c4
--- /dev/null
+++ b/Netgen/libsrc/csg/identify.hpp
@@ -0,0 +1,173 @@
+
+#ifndef FILE_IDENTIFY
+#define FILE_IDENTIFY
+
+/**************************************************************************/
+/* File:   identify.hh                                                    */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   1. Aug. 99                                                    */
+/**************************************************************************/
+
+/**
+   Identify surfaces for periodic b.c. or
+   thin domains
+*/
+
+
+class SpecialPoint;
+class Identification
+{
+protected:
+  const CSGeometry & geom;
+  // identified faces, index sorted
+  INDEX_2_HASHTABLE<int> identfaces;
+  int nr;
+
+public:
+  Identification (int anr, const CSGeometry & ageom);
+  virtual ~Identification ();
+  virtual void Print (ostream & ost) const = 0;
+  virtual void GetData (ostream & ost) const = 0;
+
+  /// obsolete
+  //  virtual void IdentifySpecialPoints (ARRAY<class SpecialPoint> & points);
+
+  /// can identify both special points (fixed direction)
+  /// (identified points, same tangent)
+  virtual int Identifyable (const SpecialPoint & sp1, const SpecialPoint & sp2) const;
+  ///
+  virtual int Identifyable (const Point<3> & p1, const Point<3> & sp2) const;
+  /// is it possible to identify sp1 with some other ?
+  virtual int IdentifyableCandidate (const SpecialPoint & sp1) const;
+  
+  /// are points (if connected) by a short edge (direction anyhow) ?
+  virtual int ShortEdge (const SpecialPoint & sp1, const SpecialPoint & sp2) const;
+
+  /// add entries in mesh identification tables
+  virtual void IdentifyPoints (class Mesh & mesh);
+
+  /// add entries to identified faces (based on segment infos)
+  virtual void IdentifyFaces (class Mesh & mesh);
+
+  /// get point on other surface, add entry in mesh identifications
+  virtual int GetIdentifiedPoint (class Mesh & mesh, int pi1);
+
+  /// copy surfaces, or fill rectangles
+  virtual void BuildSurfaceElements (ARRAY<class Segment> & segs,
+				     class Mesh & mesh,
+				     const Surface * surf);
+
+  /// insert volume elements in thin layers
+  virtual void BuildVolumeElements (ARRAY<class Element2d> & surfels,
+				    class Mesh & mesh);
+
+  /// get list of identified faces
+  virtual void GetIdentifiedFaces (ARRAY<INDEX_2> & idfaces) const;
+
+  friend ostream & operator<< (ostream & ost, Identification & ident);
+};
+
+
+class PeriodicIdentification : public Identification
+{
+  const Surface * s1;
+  const Surface * s2;
+public:
+  PeriodicIdentification (int anr,
+			  const CSGeometry & ageom,
+			  const Surface * as1,
+			  const Surface * as2);
+  virtual ~PeriodicIdentification ();
+  virtual void Print (ostream & ost) const;
+  virtual void GetData (ostream & ost) const;
+
+
+  //  virtual void IdentifySpecialPoints (ARRAY<class SpecialPoint> & points);
+  virtual int Identifyable (const SpecialPoint & sp1, const SpecialPoint & sp2) const;
+  virtual int Identifyable (const Point<3> & p1, const Point<3> & sp2) const;
+  virtual int GetIdentifiedPoint (class Mesh & mesh, int pi1);
+  virtual void IdentifyPoints (class Mesh & mesh);
+  virtual void IdentifyFaces (class Mesh & mesh);
+  virtual void BuildSurfaceElements (ARRAY<class Segment> & segs,
+				     class Mesh & mesh,
+				     const Surface * surf);
+};
+
+
+///
+class CloseSurfaceIdentification : public Identification
+{
+  const Surface * s1;
+  const Surface * s2;
+  /// number of refinement levels (in Z-refinement)
+  int ref_levels;
+  /// number of refinement levels for layer next to s1 (in Z-refinement)
+  int ref_levels_s1;
+  /// number of refinement levels for layer next to s2 (in Z-refinement)
+  int ref_levels_s2;
+  ///
+  double eps_n;
+  ARRAY<double> slices;
+public:
+  CloseSurfaceIdentification (int anr, 
+			      const CSGeometry & ageom,
+			      const Surface * as1,
+			      const Surface * as2,
+			      const Flags & flags);
+  virtual ~CloseSurfaceIdentification ();
+
+  virtual void Print (ostream & ost) const;
+  virtual void GetData (ostream & ost) const;
+
+
+  //  virtual void IdentifySpecialPoints (ARRAY<class SpecialPoint> & points);
+  virtual int Identifyable (const SpecialPoint & sp1, const SpecialPoint & sp2) const;
+  virtual int Identifyable (const Point<3> & p1, const Point<3> & sp2) const;
+  virtual int IdentifyableCandidate (const SpecialPoint & sp1) const;
+  virtual int ShortEdge (const SpecialPoint & sp1, const SpecialPoint & sp2) const;
+  virtual int GetIdentifiedPoint (class Mesh & mesh, int pi1);
+  const ARRAY<double> & GetSlices () const { return slices; }
+  virtual void IdentifyPoints (class Mesh & mesh);
+  virtual void IdentifyFaces (class Mesh & mesh);
+  virtual void BuildSurfaceElements (ARRAY<class Segment> & segs,
+				     class Mesh & mesh,
+				     const Surface * surf);
+  void BuildSurfaceElements2 (ARRAY<class Segment> & segs,
+			      class Mesh & mesh,
+			      const Surface * surf);
+
+  virtual void BuildVolumeElements (ARRAY<class Element2d> & surfels,
+				    class Mesh & mesh);
+
+  int RefLevels () const { return ref_levels; }
+  int RefLevels1 () const { return ref_levels_s1; }
+  int RefLevels2 () const { return ref_levels_s2; }
+};
+
+
+class CloseEdgesIdentification : public Identification
+{
+  const Surface * facet;
+  const Surface * s1;
+  const Surface * s2;
+public:
+  CloseEdgesIdentification (int anr,
+			    const CSGeometry & ageom,
+			    const Surface * afacet,
+			    const Surface * as1,
+			    const Surface * as2);
+  virtual ~CloseEdgesIdentification ();
+  virtual void Print (ostream & ost) const;
+  virtual void GetData (ostream & ost) const;
+
+  //  virtual void IdentifySpecialPoints (ARRAY<class SpecialPoint> & points);
+  virtual int Identifyable (const SpecialPoint & sp1, const SpecialPoint & sp2) const;
+
+
+  virtual void IdentifyPoints (class Mesh & mesh);
+  virtual void BuildSurfaceElements (ARRAY<class Segment> & segs,
+				     class Mesh & mesh,
+				     const Surface * surf);
+};
+
+#endif
diff --git a/Netgen/libsrc/csg/lex.yy.cpp b/Netgen/libsrc/csg/lex.yy.cpp
new file mode 100644
index 0000000000..31c180c05d
--- /dev/null
+++ b/Netgen/libsrc/csg/lex.yy.cpp
@@ -0,0 +1,1834 @@
+/* A lexical scanner generated by flex */
+
+/* Scanner skeleton version:
+ * $Header: /cvsroot/gmsh/Netgen/libsrc/csg/lex.yy.cpp,v 1.1 2004-06-26 17:58:14 geuzaine Exp $
+ */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+
+
+
+/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */
+#ifdef c_plusplus
+#ifndef __cplusplus
+#define __cplusplus
+#endif
+#endif
+
+
+#ifdef __cplusplus
+
+#include <stdlib.h>
+#include <iostream.h>
+#include <unistd.h>
+
+/* Use prototypes in function declarations. */
+#define YY_USE_PROTOS
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else	/* ! __cplusplus */
+
+#if __STDC__
+
+#define YY_USE_PROTOS
+#define YY_USE_CONST
+
+#endif	/* __STDC__ */
+#endif	/* ! __cplusplus */
+
+#ifdef __TURBOC__
+ #pragma warn -rch
+ #pragma warn -use
+#include <io.h>
+#include <stdlib.h>
+#define YY_USE_CONST
+#define YY_USE_PROTOS
+#endif
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+
+#ifdef YY_USE_PROTOS
+#define YY_PROTO(proto) proto
+#else
+#define YY_PROTO(proto) ()
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index.  If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition.  This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN yy_start = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state.  The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START ((yy_start - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE yyrestart( yyin )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#define YY_BUF_SIZE 16384
+
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+
+extern int yyleng;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+/* The funky do-while in the following #define is used to turn the definition
+ * int a single C statement (which needs a semi-colon terminator).  This
+ * avoids problems with code like:
+ *
+ * 	if ( condition_holds )
+ *		yyless( 5 );
+ *	else
+ *		do_something_else();
+ *
+ * Prior to using the do-while the compiler would get upset at the
+ * "else" because it interpreted the "if" statement as being all
+ * done when it reached the ';' after the yyless() call.
+ */
+
+/* Return all but the first 'n' matched characters back to the input stream. */
+
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up yytext. */ \
+		*yy_cp = yy_hold_char; \
+		YY_RESTORE_YY_MORE_OFFSET \
+		yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \
+		YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+		} \
+	while ( 0 )
+
+#define unput(c) yyunput( c, yytext_ptr )
+
+/* The following is because we cannot portably get our hands on size_t
+ * (without autoconf's help, which isn't available because we want
+ * flex-generated scanners to compile on their own).
+ */
+typedef unsigned int yy_size_t;
+
+
+struct yy_buffer_state
+	{
+	istream* yy_input_file;
+
+	char *yy_ch_buf;		/* input buffer */
+	char *yy_buf_pos;		/* current position in input buffer */
+
+	/* Size of input buffer in bytes, not including room for EOB
+	 * characters.
+	 */
+	yy_size_t yy_buf_size;
+
+	/* Number of characters read into yy_ch_buf, not including EOB
+	 * characters.
+	 */
+	int yy_n_chars;
+
+	/* Whether we "own" the buffer - i.e., we know we created it,
+	 * and can realloc() it to grow it, and should free() it to
+	 * delete it.
+	 */
+	int yy_is_our_buffer;
+
+	/* Whether this is an "interactive" input source; if so, and
+	 * if we're using stdio for input, then we want to use getc()
+	 * instead of fread(), to make sure we stop fetching input after
+	 * each newline.
+	 */
+	int yy_is_interactive;
+
+	/* Whether we're considered to be at the beginning of a line.
+	 * If so, '^' rules will be active on the next match, otherwise
+	 * not.
+	 */
+	int yy_at_bol;
+
+	/* Whether to try to fill the input buffer when we reach the
+	 * end of it.
+	 */
+	int yy_fill_buffer;
+
+	int yy_buffer_status;
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+	/* When an EOF's been seen but there's still some text to process
+	 * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+	 * shouldn't try reading from the input source any more.  We might
+	 * still have a bunch of tokens to match, though, because of
+	 * possible backing-up.
+	 *
+	 * When we actually see the EOF, we change the status to "new"
+	 * (via yyrestart()), so that the user can continue scanning by
+	 * just pointing yyin at a new input file.
+	 */
+#define YY_BUFFER_EOF_PENDING 2
+	};
+
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ */
+#define YY_CURRENT_BUFFER yy_current_buffer
+
+
+
+static void *yy_flex_alloc YY_PROTO(( yy_size_t ));
+static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t ));
+static void yy_flex_free YY_PROTO(( void * ));
+
+#define yy_new_buffer yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+	{ \
+	if ( ! yy_current_buffer ) \
+		yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+	yy_current_buffer->yy_is_interactive = is_interactive; \
+	}
+
+#define yy_set_bol(at_bol) \
+	{ \
+	if ( ! yy_current_buffer ) \
+		yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+	yy_current_buffer->yy_at_bol = at_bol; \
+	}
+
+#define YY_AT_BOL() (yy_current_buffer->yy_at_bol)
+
+
+#define FLEX_DEBUG
+typedef unsigned char YY_CHAR;
+#define yytext_ptr yytext
+#define YY_INTERACTIVE
+
+#define FLEX_DEBUG
+
+#include <FlexLexer.h>
+
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+	yytext_ptr = yy_bp; \
+	yyleng = (int) (yy_cp - yy_bp); \
+	yy_hold_char = *yy_cp; \
+	*yy_cp = '\0'; \
+	yy_c_buf_p = yy_cp;
+
+#define YY_NUM_RULES 37
+#define YY_END_OF_BUFFER 38
+static yyconst short int yy_accept[222] =
+    {   0,
+        0,    0,    0,    0,    0,    0,   38,   33,   32,   34,
+       33,   33,   33,   30,   31,   31,   31,   31,   31,   31,
+       31,   31,   31,   31,   31,   31,   31,   31,   37,    0,
+       36,    0,    0,   30,   30,   30,    0,   31,   31,   31,
+       31,   31,   31,   31,   31,   31,   31,   31,   31,   31,
+        5,   31,   31,   31,   31,   31,   31,   31,   31,   31,
+       31,   31,    0,   35,    0,    0,   30,   31,    4,   31,
+       31,   31,   31,   31,   31,   31,   31,    6,   31,   31,
+       31,   31,   31,   31,   31,   31,   31,   31,    3,   31,
+       31,    0,   30,   31,   31,   31,   13,   31,   22,   31,
+
+       31,   31,   31,   31,   31,   31,   31,   31,   31,   31,
+       31,   31,   31,   31,   16,   31,   31,   31,   31,   31,
+       31,   31,   31,   31,   14,   15,   23,   31,   31,   31,
+       31,    2,   31,   31,   31,   31,   31,   31,   31,   31,
+       17,   31,   31,   31,   31,   31,   31,   31,    9,   31,
+       11,   31,   31,   31,   31,   31,   31,   31,   31,   31,
+       31,   31,   31,   31,   31,   31,   31,   31,   31,   31,
+       31,   31,   12,   24,   31,   31,   31,   27,   31,   31,
+       21,   31,   31,   31,   31,   31,   31,   31,   31,   31,
+       31,   31,    7,   31,   31,   31,   26,   31,   31,   31,
+
+       18,   19,   20,    1,   31,   29,   31,   10,   31,   31,
+       31,   31,   31,   25,   31,   31,    8,   31,   31,   28,
+        0
+    } ;
+
+static yyconst int yy_ec[256] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    2,    1,    1,    4,    1,    1,    1,    1,    1,
+        1,    1,    5,    1,    5,    6,    1,    7,    7,    7,
+        8,    7,    7,    7,    7,    7,    7,    1,    1,    1,
+        1,    1,    1,    1,    9,    9,    9,    9,   10,    9,
+        9,    9,    9,    9,    9,    9,    9,    9,    9,    9,
+        9,    9,    9,    9,    9,    9,    9,    9,    9,    9,
+        1,    1,    1,    1,    1,    1,   11,   12,   13,   14,
+
+       15,   16,   17,   18,   19,    9,   20,   21,   22,   23,
+       24,   25,    9,   26,   27,   28,   29,   30,    9,   31,
+       32,    9,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1
+    } ;
+
+static yyconst int yy_meta[33] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    2,    2,    2,    2,
+        2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
+        2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
+        2,    2
+    } ;
+
+static yyconst short int yy_base[226] =
+    {   0,
+        0,    0,    0,    0,    0,    0,   77,  706,  706,  706,
+       30,   29,   31,   34,   38,   40,   43,   61,   45,   47,
+       50,   58,   64,   66,   87,   76,  105,  124,  706,   67,
+      706,   57,   68,    0,   71,   89,   98,   82,  102,  108,
+      112,  110,  114,  120,  126,  129,  133,  144,  141,  147,
+      150,  153,  156,  161,  158,  163,  166,  169,  176,  178,
+      185,  191,   53,  706,  199,  193,  201,  203,  205,  207,
+      209,  212,  214,  216,  221,  218,  230,  232,  235,  237,
+      240,  242,  244,  247,  253,  260,  262,  265,  267,  271,
+      275,  277,  279,  281,  284,  288,  292,  294,  297,  299,
+
+      301,  303,  306,  308,  311,  313,  316,  318,  330,  332,
+      334,  338,  340,  342,  346,  348,  351,  357,  368,  360,
+      370,  372,  378,  380,  384,  388,  394,  396,  398,  400,
+      402,  405,  409,  411,  414,  421,  423,  426,  428,  430,
+      434,  436,  441,  443,  446,  448,  452,  454,  456,  463,
+      468,  470,  472,  476,  478,  480,  485,  491,  482,  493,
+      495,  497,  502,  505,  511,  515,  517,  519,  521,  528,
+      531,  535,  540,  542,  545,  547,  550,  552,  554,  557,
+      559,  561,  564,  566,  572,  575,  577,  579,  584,  586,
+      590,  592,  596,  602,  610,  612,  614,  616,  619,  623,
+
+      628,  630,  632,  634,  638,  640,  642,  646,  648,  653,
+      655,  657,  659,  661,  663,  667,  669,  672,  676,  681,
+      706,  699,  701,   41,  703
+    } ;
+
+static yyconst short int yy_def[226] =
+    {   0,
+      221,    1,  222,  222,  222,  222,  221,  221,  221,  221,
+      223,  221,  221,  221,  224,  224,  224,  224,  224,  224,
+      224,  224,  224,  224,  224,  224,  224,  224,  221,  223,
+      221,  225,  221,   14,  221,  221,  221,  224,  224,  224,
+      224,  224,  224,  224,  224,  224,  224,  224,  224,  224,
+      224,  224,  224,  224,  224,  224,  224,  224,  224,  224,
+      224,  224,  225,  221,  221,  221,  221,  224,  224,  224,
+      224,  224,  224,  224,  224,  224,  224,  224,  224,  224,
+      224,  224,  224,  224,  224,  224,  224,  224,  224,  224,
+      224,  221,  221,  224,  224,  224,  224,  224,  224,  224,
+
+      224,  224,  224,  224,  224,  224,  224,  224,  224,  224,
+      224,  224,  224,  224,  224,  224,  224,  224,  224,  224,
+      224,  224,  224,  224,  224,  224,  224,  224,  224,  224,
+      224,  224,  224,  224,  224,  224,  224,  224,  224,  224,
+      224,  224,  224,  224,  224,  224,  224,  224,  224,  224,
+      224,  224,  224,  224,  224,  224,  224,  224,  224,  224,
+      224,  224,  224,  224,  224,  224,  224,  224,  224,  224,
+      224,  224,  224,  224,  224,  224,  224,  224,  224,  224,
+      224,  224,  224,  224,  224,  224,  224,  224,  224,  224,
+      224,  224,  224,  224,  224,  224,  224,  224,  224,  224,
+
+      224,  224,  224,  224,  224,  224,  224,  224,  224,  224,
+      224,  224,  224,  224,  224,  224,  224,  224,  224,  224,
+        0,  221,  221,  221,  221
+    } ;
+
+static yyconst short int yy_nxt[739] =
+    {   0,
+        8,    9,   10,   11,   12,   13,   14,   14,   15,   15,
+       16,   17,   18,   15,   19,   15,   20,   15,   21,   15,
+       15,   22,   23,   24,   25,   26,   27,   28,   15,   15,
+       15,   15,   31,   32,   33,   34,   34,   35,   35,   36,
+       34,   34,   39,   37,   38,   38,   38,   38,   37,   38,
+       38,   38,   38,   38,   38,   64,   38,   38,   46,   64,
+       40,   47,   41,   48,   38,   38,   42,   38,   38,   31,
+       38,   38,   38,   38,   35,   35,  221,   35,   35,  221,
+       65,   43,   38,   38,   44,   65,   49,   50,   38,   38,
+       55,   51,   45,   38,   38,   35,   35,  221,   37,   56,
+
+      221,   52,   66,   37,   67,   67,  221,   53,   38,   38,
+       54,   38,   38,  221,   38,   38,   38,   38,   38,   38,
+       38,   38,  221,   57,   68,   69,   38,   38,   58,   59,
+       38,   38,   38,   38,  221,   38,   38,   71,   70,   38,
+       38,  221,   72,  221,   60,   74,   73,   38,   38,   61,
+       38,   38,   62,   38,   38,   75,   38,   38,   76,   38,
+       38,   77,   38,   38,   38,   38,   81,   38,   38,   38,
+       38,  221,   38,   38,   78,   38,   38,   79,   80,   82,
+      221,   83,   38,   38,   38,   38,  221,   84,   86,   87,
+       85,   38,   38,   88,  221,   90,  221,   38,   38,   67,
+
+       67,   89,   91,   92,  221,   93,   93,   67,   67,   38,
+       38,   38,   38,   38,   38,   38,   38,   94,   38,   38,
+       38,   38,   38,   38,   38,   38,   97,   38,   38,   95,
+       99,  221,   98,  100,  221,   96,   38,   38,   38,   38,
+      101,   38,   38,   38,   38,  221,   38,   38,   38,   38,
+       38,   38,  103,   38,   38,  104,  221,  102,  105,   38,
+       38,  221,  106,  110,  107,  221,   38,   38,   38,   38,
+      109,   38,   38,   38,   38,  108,  111,   38,   38,  113,
+      112,   38,   38,   93,   93,   93,   93,   38,   38,  115,
+       38,   38,  116,  114,   38,   38,  221,  117,   38,   38,
+
+       38,   38,  118,   38,   38,   38,   38,   38,   38,   38,
+       38,  221,   38,   38,   38,   38,  119,   38,   38,   38,
+       38,  122,   38,   38,   38,   38,  221,  126,  121,  123,
+      120,  124,  221,  125,  221,  128,   38,   38,   38,   38,
+       38,   38,  221,  127,   38,   38,   38,   38,   38,   38,
+      129,  132,   38,   38,   38,   38,  221,   38,   38,  130,
+      221,  136,  131,   38,   38,  133,   38,   38,  134,  137,
+      221,  138,  221,  135,   38,   38,   38,   38,   38,   38,
+      141,  140,  221,  139,   38,   38,   38,   38,  142,  145,
+       38,   38,  221,  146,   38,   38,  221,  143,  221,  144,
+
+       38,   38,   38,   38,   38,   38,   38,   38,   38,   38,
+      147,   38,   38,  221,  149,   38,   38,   38,   38,  221,
+       38,   38,  150,  151,  153,  221,  148,   38,   38,   38,
+       38,  152,   38,   38,   38,   38,   38,   38,  221,  156,
+       38,   38,   38,   38,  158,  155,  154,   38,   38,   38,
+       38,  159,   38,   38,   38,   38,  157,  221,   38,   38,
+       38,   38,   38,   38,  160,  164,  163,  221,  161,   38,
+       38,  162,  221,  166,   38,   38,   38,   38,   38,   38,
+      167,  165,   38,   38,   38,   38,   38,   38,   38,   38,
+      168,   38,   38,  221,  170,  221,  171,   38,   38,   38,
+
+       38,   38,   38,   38,   38,  176,  221,  169,   38,   38,
+      172,   38,   38,  174,  178,  177,  173,   38,   38,  221,
+      175,   38,   38,   38,   38,   38,   38,   38,   38,  180,
+      179,  183,  221,  184,   38,   38,  221,   38,   38,  185,
+      181,   38,   38,  221,  182,  186,   38,   38,   38,   38,
+      187,   38,   38,   38,   38,  188,   38,   38,   38,   38,
+       38,   38,  190,   38,   38,   38,   38,   38,   38,  189,
+       38,  194,   38,   38,  221,  193,  221,  191,   38,   38,
+      192,   38,   38,   38,   38,   38,   38,  198,  221,  195,
+       38,   38,   38,   38,  221,  196,   38,   38,   38,   38,
+
+      221,  197,   38,   38,  221,  201,  199,  221,   38,   38,
+      200,  221,  202,  221,  203,  204,   38,   38,   38,   38,
+       38,   38,   38,   38,  221,   38,   38,  221,  207,   38,
+       38,  221,  205,  208,   38,   38,   38,   38,   38,   38,
+       38,   38,  206,  209,   38,   38,   38,   38,   38,   38,
+      221,  210,   38,   38,   38,   38,  211,  221,  212,   38,
+       38,   38,   38,   38,   38,   38,   38,   38,   38,   38,
+       38,  213,  221,   38,   38,   38,   38,  217,   38,   38,
+      221,  214,   38,   38,  215,  218,  216,   38,   38,  221,
+      221,  221,  221,  221,  221,  219,  221,  221,  220,   29,
+
+       29,   30,   30,   63,   63,    7,  221,  221,  221,  221,
+      221,  221,  221,  221,  221,  221,  221,  221,  221,  221,
+      221,  221,  221,  221,  221,  221,  221,  221,  221,  221,
+      221,  221,  221,  221,  221,  221,  221,  221
+    } ;
+
+static yyconst short int yy_chk[739] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,   11,   11,   12,   12,   12,   13,   13,   14,
+       14,   14,  224,   14,   15,   15,   16,   16,   14,   17,
+       17,   19,   19,   20,   20,   63,   21,   21,   19,   32,
+       16,   20,   16,   21,   22,   22,   17,   18,   18,   30,
+       23,   23,   24,   24,   33,   33,    7,   35,   35,    0,
+       35,   18,   26,   26,   18,   35,   22,   23,   38,   38,
+       26,   24,   18,   25,   25,   36,   36,    0,   36,   26,
+
+        0,   25,   37,   36,   37,   37,    0,   25,   39,   39,
+       25,   27,   27,    0,   40,   40,   42,   42,   41,   41,
+       43,   43,    0,   27,   40,   41,   44,   44,   27,   27,
+       28,   28,   45,   45,    0,   46,   46,   43,   42,   47,
+       47,    0,   44,    0,   28,   46,   45,   49,   49,   28,
+       48,   48,   28,   50,   50,   47,   51,   51,   48,   52,
+       52,   49,   53,   53,   55,   55,   53,   54,   54,   56,
+       56,    0,   57,   57,   50,   58,   58,   51,   52,   54,
+        0,   54,   59,   59,   60,   60,    0,   55,   57,   58,
+       56,   61,   61,   59,    0,   61,    0,   62,   62,   66,
+
+       66,   60,   62,   65,    0,   65,   65,   67,   67,   68,
+       68,   69,   69,   70,   70,   71,   71,   68,   72,   72,
+       73,   73,   74,   74,   76,   76,   72,   75,   75,   70,
+       74,    0,   73,   75,    0,   71,   77,   77,   78,   78,
+       76,   79,   79,   80,   80,    0,   81,   81,   82,   82,
+       83,   83,   79,   84,   84,   80,    0,   77,   81,   85,
+       85,    0,   81,   85,   82,    0,   86,   86,   87,   87,
+       84,   88,   88,   89,   89,   83,   86,   90,   90,   88,
+       87,   91,   91,   92,   92,   93,   93,   94,   94,   91,
+       95,   95,   94,   90,   96,   96,    0,   95,   97,   97,
+
+       98,   98,   96,   99,   99,  100,  100,  101,  101,  102,
+      102,    0,  103,  103,  104,  104,   98,  105,  105,  106,
+      106,  102,  107,  107,  108,  108,    0,  106,  101,  103,
+      100,  104,    0,  105,    0,  108,  109,  109,  110,  110,
+      111,  111,    0,  107,  112,  112,  113,  113,  114,  114,
+      109,  112,  115,  115,  116,  116,    0,  117,  117,  110,
+        0,  117,  111,  118,  118,  113,  120,  120,  114,  117,
+        0,  118,    0,  116,  119,  119,  121,  121,  122,  122,
+      120,  119,    0,  118,  123,  123,  124,  124,  121,  123,
+      125,  125,    0,  124,  126,  126,    0,  122,    0,  122,
+
+      127,  127,  128,  128,  129,  129,  130,  130,  131,  131,
+      128,  132,  132,    0,  130,  133,  133,  134,  134,    0,
+      135,  135,  131,  133,  135,    0,  129,  136,  136,  137,
+      137,  134,  138,  138,  139,  139,  140,  140,    0,  138,
+      141,  141,  142,  142,  140,  137,  136,  143,  143,  144,
+      144,  142,  145,  145,  146,  146,  139,    0,  147,  147,
+      148,  148,  149,  149,  143,  147,  146,    0,  144,  150,
+      150,  145,    0,  150,  151,  151,  152,  152,  153,  153,
+      152,  148,  154,  154,  155,  155,  156,  156,  159,  159,
+      153,  157,  157,    0,  155,    0,  156,  158,  158,  160,
+
+      160,  161,  161,  162,  162,  161,    0,  154,  163,  163,
+      157,  164,  164,  159,  163,  162,  158,  165,  165,    0,
+      160,  166,  166,  167,  167,  168,  168,  169,  169,  165,
+      164,  168,    0,  169,  170,  170,    0,  171,  171,  170,
+      166,  172,  172,    0,  167,  171,  173,  173,  174,  174,
+      172,  175,  175,  176,  176,  175,  177,  177,  178,  178,
+      179,  179,  177,  180,  180,  181,  181,  182,  182,  176,
+      183,  183,  184,  184,    0,  182,    0,  179,  185,  185,
+      180,  186,  186,  187,  187,  188,  188,  187,    0,  184,
+      189,  189,  190,  190,    0,  185,  191,  191,  192,  192,
+
+        0,  186,  193,  193,    0,  190,  188,    0,  194,  194,
+      189,    0,  191,    0,  192,  194,  195,  195,  196,  196,
+      197,  197,  198,  198,    0,  199,  199,    0,  198,  200,
+      200,    0,  195,  199,  201,  201,  202,  202,  203,  203,
+      204,  204,  196,  200,  205,  205,  206,  206,  207,  207,
+        0,  205,  208,  208,  209,  209,  207,    0,  209,  210,
+      210,  211,  211,  212,  212,  213,  213,  214,  214,  215,
+      215,  210,    0,  216,  216,  217,  217,  215,  218,  218,
+        0,  211,  219,  219,  212,  216,  213,  220,  220,    0,
+        0,    0,    0,    0,    0,  218,    0,    0,  219,  222,
+
+      222,  223,  223,  225,  225,  221,  221,  221,  221,  221,
+      221,  221,  221,  221,  221,  221,  221,  221,  221,  221,
+      221,  221,  221,  221,  221,  221,  221,  221,  221,  221,
+      221,  221,  221,  221,  221,  221,  221,  221
+    } ;
+
+static yyconst short int yy_rule_linenum[37] =
+    {   0,
+       33,   34,   35,   36,   37,   38,   39,   40,   41,   42,
+       43,   44,   45,   46,   47,   48,   49,   50,   51,   52,
+       54,   55,   56,   58,   59,   60,   61,   62,   63,   65,
+       66,   75,   76,   77,   78,   79
+    } ;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+#line 1 "geometry.ll"
+#define INITIAL 0
+#line 2 "geometry.ll"
+#include <mystdlib.h>
+#include <myadt.hpp> 
+
+#include <linalg.hpp> 
+#include <csg.hpp>
+
+
+
+
+// extern SYMBOLTABLE<Solid*> solids;
+namespace netgen {
+extern CSGeometry * parsegeom;
+}
+using namespace netgen;
+
+#include "geometry.h"
+
+
+ARRAY<char*> parsestrings;
+int linenum;
+#define incl 1
+
+#define comment 2
+
+#line 594 "lex.yy.cc"
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap YY_PROTO(( void ));
+#else
+extern int yywrap YY_PROTO(( void ));
+#endif
+#endif
+
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int ));
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen YY_PROTO(( yyconst char * ));
+#endif
+
+#ifndef YY_NO_INPUT
+#endif
+
+#if YY_STACK_USED
+static int yy_start_stack_ptr = 0;
+static int yy_start_stack_depth = 0;
+static int *yy_start_stack = 0;
+#ifndef YY_NO_PUSH_STATE
+static void yy_push_state YY_PROTO(( int new_state ));
+#endif
+#ifndef YY_NO_POP_STATE
+static void yy_pop_state YY_PROTO(( void ));
+#endif
+#ifndef YY_NO_TOP_STATE
+static int yy_top_state YY_PROTO(( void ));
+#endif
+
+#else
+#define YY_NO_PUSH_STATE 1
+#define YY_NO_POP_STATE 1
+#define YY_NO_TOP_STATE 1
+#endif
+
+#ifdef YY_MALLOC_DECL
+YY_MALLOC_DECL
+#else
+#if __STDC__
+#ifndef __cplusplus
+#include <stdlib.h>
+#endif
+#else
+/* Just try to get by without declaring the routines.  This will fail
+ * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int)
+ * or sizeof(void*) != sizeof(int).
+ */
+#endif
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+
+#ifndef ECHO
+#define ECHO LexerOutput( yytext, yyleng )
+#endif
+
+/* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+	if ( (result = LexerInput( (char *) buf, max_size )) < 0 ) \
+		YY_FATAL_ERROR( "input in flex scanner failed" );
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) LexerError( msg )
+#endif
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL int yyFlexLexer::yylex()
+#endif
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+	YY_USER_ACTION
+
+YY_DECL
+	{
+	register yy_state_type yy_current_state;
+	register char *yy_cp, *yy_bp;
+	register int yy_act;
+
+#line 32 "geometry.ll"
+
+#line 723 "lex.yy.cc"
+
+	if ( yy_init )
+		{
+		yy_init = 0;
+
+#ifdef YY_USER_INIT
+		YY_USER_INIT;
+#endif
+
+		if ( ! yy_start )
+			yy_start = 1;	/* first start state */
+
+		if ( ! yyin )
+			yyin = &cin;
+
+		if ( ! yyout )
+			yyout = &cout;
+
+		if ( ! yy_current_buffer )
+			yy_current_buffer =
+				yy_create_buffer( yyin, YY_BUF_SIZE );
+
+		yy_load_buffer_state();
+		}
+
+	while ( 1 )		/* loops until end-of-file is reached */
+		{
+		yy_cp = yy_c_buf_p;
+
+		/* Support of yytext. */
+		*yy_cp = yy_hold_char;
+
+		/* yy_bp points to the position in yy_ch_buf of the start of
+		 * the current run.
+		 */
+		yy_bp = yy_cp;
+
+		yy_current_state = yy_start;
+yy_match:
+		do
+			{
+			register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+			if ( yy_accept[yy_current_state] )
+				{
+				yy_last_accepting_state = yy_current_state;
+				yy_last_accepting_cpos = yy_cp;
+				}
+			while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+				{
+				yy_current_state = (int) yy_def[yy_current_state];
+				if ( yy_current_state >= 222 )
+					yy_c = yy_meta[(unsigned int) yy_c];
+				}
+			yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+			++yy_cp;
+			}
+		while ( yy_base[yy_current_state] != 706 );
+
+yy_find_action:
+		yy_act = yy_accept[yy_current_state];
+		if ( yy_act == 0 )
+			{ /* have to back up */
+			yy_cp = yy_last_accepting_cpos;
+			yy_current_state = yy_last_accepting_state;
+			yy_act = yy_accept[yy_current_state];
+			}
+
+		YY_DO_BEFORE_ACTION;
+
+
+do_action:	/* This label is used only to access EOF actions. */
+
+		if ( yy_flex_debug )
+			{
+			if ( yy_act == 0 )
+				cerr << "--scanner backing up\n";
+			else if ( yy_act < 37 )
+				cerr << "--accepting rule at line " << yy_rule_linenum[yy_act] <<
+				         "(\"" << yytext << "\")\n";
+			else if ( yy_act == 37 )
+				cerr << "--accepting default rule (\"" << yytext << "\")\n";
+			else if ( yy_act == 38 )
+				cerr << "--(end of buffer or a NUL)\n";
+			else
+				cerr << "--EOF (start condition " << YY_START << ")\n";
+			}
+
+		switch ( yy_act )
+	{ /* beginning of action switch */
+			case 0: /* must back up */
+			/* undo the effects of YY_DO_BEFORE_ACTION */
+			*yy_cp = yy_hold_char;
+			yy_cp = yy_last_accepting_cpos;
+			yy_current_state = yy_last_accepting_state;
+			goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+#line 33 "geometry.ll"
+{ return TOK_RECO; }
+	YY_BREAK
+case 2:
+YY_RULE_SETUP
+#line 34 "geometry.ll"
+{ return TOK_SOLID; }
+	YY_BREAK
+case 3:
+YY_RULE_SETUP
+#line 35 "geometry.ll"
+{ return TOK_TLO; }
+	YY_BREAK
+case 4:
+YY_RULE_SETUP
+#line 36 "geometry.ll"
+{ return TOK_AND; }
+	YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 37 "geometry.ll"
+{ return TOK_OR; }
+	YY_BREAK
+case 6:
+YY_RULE_SETUP
+#line 38 "geometry.ll"
+{ return TOK_NOT; }
+	YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 39 "geometry.ll"
+{ return TOK_TRANSLATE; }
+	YY_BREAK
+case 8:
+YY_RULE_SETUP
+#line 40 "geometry.ll"
+{ return TOK_MULTITRANSLATE; }
+	YY_BREAK
+case 9:
+YY_RULE_SETUP
+#line 41 "geometry.ll"
+{ return TOK_ROTATE; }
+	YY_BREAK
+case 10:
+YY_RULE_SETUP
+#line 42 "geometry.ll"
+{ return TOK_MULTIROTATE; }
+	YY_BREAK
+case 11:
+YY_RULE_SETUP
+#line 43 "geometry.ll"
+{ return TOK_SPHERE; }
+	YY_BREAK
+case 12:
+YY_RULE_SETUP
+#line 44 "geometry.ll"
+{ return TOK_CYLINDER; }
+	YY_BREAK
+case 13:
+YY_RULE_SETUP
+#line 45 "geometry.ll"
+{ return TOK_CONE; }
+	YY_BREAK
+case 14:
+YY_RULE_SETUP
+#line 46 "geometry.ll"
+{ return TOK_PLAIN; }
+	YY_BREAK
+case 15:
+YY_RULE_SETUP
+#line 47 "geometry.ll"
+{ return TOK_PLAIN; }
+	YY_BREAK
+case 16:
+YY_RULE_SETUP
+#line 48 "geometry.ll"
+{ return TOK_TUBE; }
+	YY_BREAK
+case 17:
+YY_RULE_SETUP
+#line 49 "geometry.ll"
+{ return TOK_GENCYL; }
+	YY_BREAK
+case 18:
+YY_RULE_SETUP
+#line 50 "geometry.ll"
+{ return TOK_ORTHOBRICK; }
+	YY_BREAK
+case 19:
+YY_RULE_SETUP
+#line 51 "geometry.ll"
+{ return TOK_POLYHEDRON; }
+	YY_BREAK
+case 20:
+YY_RULE_SETUP
+#line 52 "geometry.ll"
+{ return TOK_REVOLUTION; }
+	YY_BREAK
+case 21:
+YY_RULE_SETUP
+#line 54 "geometry.ll"
+{ return TOK_SINGULAR; }
+	YY_BREAK
+case 22:
+YY_RULE_SETUP
+#line 55 "geometry.ll"
+{ return TOK_EDGE; }
+	YY_BREAK
+case 23:
+YY_RULE_SETUP
+#line 56 "geometry.ll"
+{ return TOK_POINT; }
+	YY_BREAK
+case 24:
+YY_RULE_SETUP
+#line 58 "geometry.ll"
+{ return TOK_IDENTIFY; }
+	YY_BREAK
+case 25:
+YY_RULE_SETUP
+#line 59 "geometry.ll"
+{ return TOK_CLOSESURFACES; }
+	YY_BREAK
+case 26:
+YY_RULE_SETUP
+#line 60 "geometry.ll"
+{ return TOK_CLOSEEDGES; }
+	YY_BREAK
+case 27:
+YY_RULE_SETUP
+#line 61 "geometry.ll"
+{ return TOK_PERIODIC; }
+	YY_BREAK
+case 28:
+YY_RULE_SETUP
+#line 62 "geometry.ll"
+{ return TOK_BOUNDARYCONDITION; }
+	YY_BREAK
+case 29:
+YY_RULE_SETUP
+#line 63 "geometry.ll"
+{ return TOK_BOUNDINGBOX; }
+	YY_BREAK
+case 30:
+YY_RULE_SETUP
+#line 65 "geometry.ll"
+{ yylval.val = atof (YYText()); return NUM; }
+	YY_BREAK
+case 31:
+YY_RULE_SETUP
+#line 66 "geometry.ll"
+{
+                  yylval.chptr = new char [YYLeng()+1];
+		  parsestrings.Append (yylval.chptr);
+                  strcpy (yylval.chptr, YYText());
+                  if (parsegeom->GetSolid (yylval.chptr))
+                    return IDENTSOLID;
+                  else
+                    return IDENT;
+                }
+	YY_BREAK
+case 32:
+YY_RULE_SETUP
+#line 75 "geometry.ll"
+/* eat up ws */
+	YY_BREAK
+case 33:
+YY_RULE_SETUP
+#line 76 "geometry.ll"
+{ return int(*YYText()); }
+	YY_BREAK
+case 34:
+YY_RULE_SETUP
+#line 77 "geometry.ll"
+{ linenum++; }
+	YY_BREAK
+case 35:
+YY_RULE_SETUP
+#line 78 "geometry.ll"
+{ linenum++; cout << (YYText()+2) ; }  /* line comment */
+	YY_BREAK
+case 36:
+YY_RULE_SETUP
+#line 79 "geometry.ll"
+{ linenum++; }  /* line comment */
+	YY_BREAK
+case 37:
+YY_RULE_SETUP
+#line 82 "geometry.ll"
+ECHO;
+	YY_BREAK
+#line 1013 "lex.yy.cc"
+case YY_STATE_EOF(INITIAL):
+case YY_STATE_EOF(incl):
+case YY_STATE_EOF(comment):
+	yyterminate();
+
+	case YY_END_OF_BUFFER:
+		{
+		/* Amount of text matched not including the EOB char. */
+		int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1;
+
+		/* Undo the effects of YY_DO_BEFORE_ACTION. */
+		*yy_cp = yy_hold_char;
+		YY_RESTORE_YY_MORE_OFFSET
+
+		if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW )
+			{
+			/* We're scanning a new file or input source.  It's
+			 * possible that this happened because the user
+			 * just pointed yyin at a new source and called
+			 * yylex().  If so, then we have to assure
+			 * consistency between yy_current_buffer and our
+			 * globals.  Here is the right place to do so, because
+			 * this is the first action (other than possibly a
+			 * back-up) that will match for the new input source.
+			 */
+			yy_n_chars = yy_current_buffer->yy_n_chars;
+			yy_current_buffer->yy_input_file = yyin;
+			yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL;
+			}
+
+		/* Note that here we test for yy_c_buf_p "<=" to the position
+		 * of the first EOB in the buffer, since yy_c_buf_p will
+		 * already have been incremented past the NUL character
+		 * (since all states make transitions on EOB to the
+		 * end-of-buffer state).  Contrast this with the test
+		 * in input().
+		 */
+		if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+			{ /* This was really a NUL. */
+			yy_state_type yy_next_state;
+
+			yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text;
+
+			yy_current_state = yy_get_previous_state();
+
+			/* Okay, we're now positioned to make the NUL
+			 * transition.  We couldn't have
+			 * yy_get_previous_state() go ahead and do it
+			 * for us because it doesn't know how to deal
+			 * with the possibility of jamming (and we don't
+			 * want to build jamming into it because then it
+			 * will run more slowly).
+			 */
+
+			yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+			yy_bp = yytext_ptr + YY_MORE_ADJ;
+
+			if ( yy_next_state )
+				{
+				/* Consume the NUL. */
+				yy_cp = ++yy_c_buf_p;
+				yy_current_state = yy_next_state;
+				goto yy_match;
+				}
+
+			else
+				{
+				yy_cp = yy_c_buf_p;
+				goto yy_find_action;
+				}
+			}
+
+		else switch ( yy_get_next_buffer() )
+			{
+			case EOB_ACT_END_OF_FILE:
+				{
+				yy_did_buffer_switch_on_eof = 0;
+
+				if ( yywrap() )
+					{
+					/* Note: because we've taken care in
+					 * yy_get_next_buffer() to have set up
+					 * yytext, we can now set up
+					 * yy_c_buf_p so that if some total
+					 * hoser (like flex itself) wants to
+					 * call the scanner after we return the
+					 * YY_NULL, it'll still work - another
+					 * YY_NULL will get returned.
+					 */
+					yy_c_buf_p = yytext_ptr + YY_MORE_ADJ;
+
+					yy_act = YY_STATE_EOF(YY_START);
+					goto do_action;
+					}
+
+				else
+					{
+					if ( ! yy_did_buffer_switch_on_eof )
+						YY_NEW_FILE;
+					}
+				break;
+				}
+
+			case EOB_ACT_CONTINUE_SCAN:
+				yy_c_buf_p =
+					yytext_ptr + yy_amount_of_matched_text;
+
+				yy_current_state = yy_get_previous_state();
+
+				yy_cp = yy_c_buf_p;
+				yy_bp = yytext_ptr + YY_MORE_ADJ;
+				goto yy_match;
+
+			case EOB_ACT_LAST_MATCH:
+				yy_c_buf_p =
+				&yy_current_buffer->yy_ch_buf[yy_n_chars];
+
+				yy_current_state = yy_get_previous_state();
+
+				yy_cp = yy_c_buf_p;
+				yy_bp = yytext_ptr + YY_MORE_ADJ;
+				goto yy_find_action;
+			}
+		break;
+		}
+
+	default:
+		YY_FATAL_ERROR(
+			"fatal flex scanner internal error--no action found" );
+	} /* end of action switch */
+		} /* end of scanning one token */
+	} /* end of yylex */
+
+yyFlexLexer::yyFlexLexer( istream* arg_yyin, ostream* arg_yyout )
+	{
+	yyin = arg_yyin;
+	yyout = arg_yyout;
+	yy_c_buf_p = 0;
+	yy_init = 1;
+	yy_start = 0;
+	yy_flex_debug = 0;
+	yylineno = 1;	// this will only get updated if %option yylineno
+
+	yy_did_buffer_switch_on_eof = 0;
+
+	yy_looking_for_trail_begin = 0;
+	yy_more_flag = 0;
+	yy_more_len = 0;
+	yy_more_offset = yy_prev_more_offset = 0;
+
+	yy_start_stack_ptr = yy_start_stack_depth = 0;
+	yy_start_stack = 0;
+
+	yy_current_buffer = 0;
+
+#ifdef YY_USES_REJECT
+	yy_state_buf = new yy_state_type[YY_BUF_SIZE + 2];
+#else
+	yy_state_buf = 0;
+#endif
+	}
+
+yyFlexLexer::~yyFlexLexer()
+	{
+	delete yy_state_buf;
+	yy_delete_buffer( yy_current_buffer );
+	}
+
+void yyFlexLexer::switch_streams( istream* new_in, ostream* new_out )
+	{
+	if ( new_in )
+		{
+		yy_delete_buffer( yy_current_buffer );
+		yy_switch_to_buffer( yy_create_buffer( new_in, YY_BUF_SIZE ) );
+		}
+
+	if ( new_out )
+		yyout = new_out;
+	}
+
+#ifdef YY_INTERACTIVE
+int yyFlexLexer::LexerInput( char* buf, int /* max_size */ )
+#else
+int yyFlexLexer::LexerInput( char* buf, int max_size )
+#endif
+	{
+	if ( yyin->eof() || yyin->fail() )
+		return 0;
+
+#ifdef YY_INTERACTIVE
+	yyin->get( buf[0] );
+
+	if ( yyin->eof() )
+		return 0;
+
+	if ( yyin->bad() )
+		return -1;
+
+	return 1;
+
+#else
+	(void) yyin->read( buf, max_size );
+
+	if ( yyin->bad() )
+		return -1;
+	else
+		return yyin->gcount();
+#endif
+	}
+
+void yyFlexLexer::LexerOutput( const char* buf, int size )
+	{
+	(void) yyout->write( buf, size );
+	}
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ *	EOB_ACT_LAST_MATCH -
+ *	EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ *	EOB_ACT_END_OF_FILE - end of file
+ */
+
+int yyFlexLexer::yy_get_next_buffer()
+	{
+	register char *dest = yy_current_buffer->yy_ch_buf;
+	register char *source = yytext_ptr;
+	register int number_to_move, i;
+	int ret_val;
+
+	if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] )
+		YY_FATAL_ERROR(
+		"fatal flex scanner internal error--end of buffer missed" );
+
+	if ( yy_current_buffer->yy_fill_buffer == 0 )
+		{ /* Don't try to fill the buffer, so this is an EOF. */
+		if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 )
+			{
+			/* We matched a single character, the EOB, so
+			 * treat this as a final EOF.
+			 */
+			return EOB_ACT_END_OF_FILE;
+			}
+
+		else
+			{
+			/* We matched some text prior to the EOB, first
+			 * process it.
+			 */
+			return EOB_ACT_LAST_MATCH;
+			}
+		}
+
+	/* Try to read more data. */
+
+	/* First move last chars to start of buffer. */
+	number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1;
+
+	for ( i = 0; i < number_to_move; ++i )
+		*(dest++) = *(source++);
+
+	if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+		/* don't do the read, it's not guaranteed to return an EOF,
+		 * just force an EOF
+		 */
+		yy_current_buffer->yy_n_chars = yy_n_chars = 0;
+
+	else
+		{
+		int num_to_read =
+			yy_current_buffer->yy_buf_size - number_to_move - 1;
+
+		while ( num_to_read <= 0 )
+			{ /* Not enough room in the buffer - grow it. */
+#ifdef YY_USES_REJECT
+			YY_FATAL_ERROR(
+"input buffer overflow, can't enlarge buffer because scanner uses REJECT" );
+#else
+
+			/* just a shorter name for the current buffer */
+			YY_BUFFER_STATE b = yy_current_buffer;
+
+			int yy_c_buf_p_offset =
+				(int) (yy_c_buf_p - b->yy_ch_buf);
+
+			if ( b->yy_is_our_buffer )
+				{
+				int new_size = b->yy_buf_size * 2;
+
+				if ( new_size <= 0 )
+					b->yy_buf_size += b->yy_buf_size / 8;
+				else
+					b->yy_buf_size *= 2;
+
+				b->yy_ch_buf = (char *)
+					/* Include room in for 2 EOB chars. */
+					yy_flex_realloc( (void *) b->yy_ch_buf,
+							 b->yy_buf_size + 2 );
+				}
+			else
+				/* Can't grow it, we don't own it. */
+				b->yy_ch_buf = 0;
+
+			if ( ! b->yy_ch_buf )
+				YY_FATAL_ERROR(
+				"fatal error - scanner input buffer overflow" );
+
+			yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+			num_to_read = yy_current_buffer->yy_buf_size -
+						number_to_move - 1;
+#endif
+			}
+
+		if ( num_to_read > YY_READ_BUF_SIZE )
+			num_to_read = YY_READ_BUF_SIZE;
+
+		/* Read in more data. */
+		YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]),
+			yy_n_chars, num_to_read );
+
+		yy_current_buffer->yy_n_chars = yy_n_chars;
+		}
+
+	if ( yy_n_chars == 0 )
+		{
+		if ( number_to_move == YY_MORE_ADJ )
+			{
+			ret_val = EOB_ACT_END_OF_FILE;
+			yyrestart( yyin );
+			}
+
+		else
+			{
+			ret_val = EOB_ACT_LAST_MATCH;
+			yy_current_buffer->yy_buffer_status =
+				YY_BUFFER_EOF_PENDING;
+			}
+		}
+
+	else
+		ret_val = EOB_ACT_CONTINUE_SCAN;
+
+	yy_n_chars += number_to_move;
+	yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+	yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+	yytext_ptr = &yy_current_buffer->yy_ch_buf[0];
+
+	return ret_val;
+	}
+
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+yy_state_type yyFlexLexer::yy_get_previous_state()
+	{
+	register yy_state_type yy_current_state;
+	register char *yy_cp;
+
+	yy_current_state = yy_start;
+
+	for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp )
+		{
+		register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+		if ( yy_accept[yy_current_state] )
+			{
+			yy_last_accepting_state = yy_current_state;
+			yy_last_accepting_cpos = yy_cp;
+			}
+		while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+			{
+			yy_current_state = (int) yy_def[yy_current_state];
+			if ( yy_current_state >= 222 )
+				yy_c = yy_meta[(unsigned int) yy_c];
+			}
+		yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+		}
+
+	return yy_current_state;
+	}
+
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ *	next_state = yy_try_NUL_trans( current_state );
+ */
+
+yy_state_type yyFlexLexer::yy_try_NUL_trans( yy_state_type yy_current_state )
+	{
+	register int yy_is_jam;
+	register char *yy_cp = yy_c_buf_p;
+
+	register YY_CHAR yy_c = 1;
+	if ( yy_accept[yy_current_state] )
+		{
+		yy_last_accepting_state = yy_current_state;
+		yy_last_accepting_cpos = yy_cp;
+		}
+	while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+		{
+		yy_current_state = (int) yy_def[yy_current_state];
+		if ( yy_current_state >= 222 )
+			yy_c = yy_meta[(unsigned int) yy_c];
+		}
+	yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+	yy_is_jam = (yy_current_state == 221);
+
+	return yy_is_jam ? 0 : yy_current_state;
+	}
+
+
+void yyFlexLexer::yyunput( int c, register char* yy_bp )
+	{
+	register char *yy_cp = yy_c_buf_p;
+
+	/* undo effects of setting up yytext */
+	*yy_cp = yy_hold_char;
+
+	if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
+		{ /* need to shift things up to make room */
+		/* +2 for EOB chars. */
+		register int number_to_move = yy_n_chars + 2;
+		register char *dest = &yy_current_buffer->yy_ch_buf[
+					yy_current_buffer->yy_buf_size + 2];
+		register char *source =
+				&yy_current_buffer->yy_ch_buf[number_to_move];
+
+		while ( source > yy_current_buffer->yy_ch_buf )
+			*--dest = *--source;
+
+		yy_cp += (int) (dest - source);
+		yy_bp += (int) (dest - source);
+		yy_current_buffer->yy_n_chars =
+			yy_n_chars = yy_current_buffer->yy_buf_size;
+
+		if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
+			YY_FATAL_ERROR( "flex scanner push-back overflow" );
+		}
+
+	*--yy_cp = (char) c;
+
+
+	yytext_ptr = yy_bp;
+	yy_hold_char = *yy_cp;
+	yy_c_buf_p = yy_cp;
+	}
+
+
+int yyFlexLexer::yyinput()
+	{
+	int c;
+
+	*yy_c_buf_p = yy_hold_char;
+
+	if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+		{
+		/* yy_c_buf_p now points to the character we want to return.
+		 * If this occurs *before* the EOB characters, then it's a
+		 * valid NUL; if not, then we've hit the end of the buffer.
+		 */
+		if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+			/* This was really a NUL. */
+			*yy_c_buf_p = '\0';
+
+		else
+			{ /* need more input */
+			int offset = yy_c_buf_p - yytext_ptr;
+			++yy_c_buf_p;
+
+			switch ( yy_get_next_buffer() )
+				{
+				case EOB_ACT_LAST_MATCH:
+					/* This happens because yy_g_n_b()
+					 * sees that we've accumulated a
+					 * token and flags that we need to
+					 * try matching the token before
+					 * proceeding.  But for input(),
+					 * there's no matching to consider.
+					 * So convert the EOB_ACT_LAST_MATCH
+					 * to EOB_ACT_END_OF_FILE.
+					 */
+
+					/* Reset buffer status. */
+					yyrestart( yyin );
+
+					/* fall through */
+
+				case EOB_ACT_END_OF_FILE:
+					{
+					if ( yywrap() )
+						return EOF;
+
+					if ( ! yy_did_buffer_switch_on_eof )
+						YY_NEW_FILE;
+#ifdef __cplusplus
+					return yyinput();
+#else
+					return input();
+#endif
+					}
+
+				case EOB_ACT_CONTINUE_SCAN:
+					yy_c_buf_p = yytext_ptr + offset;
+					break;
+				}
+			}
+		}
+
+	c = *(unsigned char *) yy_c_buf_p;	/* cast for 8-bit char's */
+	*yy_c_buf_p = '\0';	/* preserve yytext */
+	yy_hold_char = *++yy_c_buf_p;
+
+
+	return c;
+	}
+
+
+void yyFlexLexer::yyrestart( istream* input_file )
+	{
+	if ( ! yy_current_buffer )
+		yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE );
+
+	yy_init_buffer( yy_current_buffer, input_file );
+	yy_load_buffer_state();
+	}
+
+
+void yyFlexLexer::yy_switch_to_buffer( YY_BUFFER_STATE new_buffer )
+	{
+	if ( yy_current_buffer == new_buffer )
+		return;
+
+	if ( yy_current_buffer )
+		{
+		/* Flush out information for old buffer. */
+		*yy_c_buf_p = yy_hold_char;
+		yy_current_buffer->yy_buf_pos = yy_c_buf_p;
+		yy_current_buffer->yy_n_chars = yy_n_chars;
+		}
+
+	yy_current_buffer = new_buffer;
+	yy_load_buffer_state();
+
+	/* We don't actually know whether we did this switch during
+	 * EOF (yywrap()) processing, but the only time this flag
+	 * is looked at is after yywrap() is called, so it's safe
+	 * to go ahead and always set it.
+	 */
+	yy_did_buffer_switch_on_eof = 1;
+	}
+
+
+void yyFlexLexer::yy_load_buffer_state()
+	{
+	yy_n_chars = yy_current_buffer->yy_n_chars;
+	yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos;
+	yyin = yy_current_buffer->yy_input_file;
+	yy_hold_char = *yy_c_buf_p;
+	}
+
+
+YY_BUFFER_STATE yyFlexLexer::yy_create_buffer( istream* file, int size )
+	{
+	YY_BUFFER_STATE b;
+
+	b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+	b->yy_buf_size = size;
+
+	/* yy_ch_buf has to be 2 characters longer than the size given because
+	 * we need to put in 2 end-of-buffer characters.
+	 */
+	b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 );
+	if ( ! b->yy_ch_buf )
+		YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+	b->yy_is_our_buffer = 1;
+
+	yy_init_buffer( b, file );
+
+	return b;
+	}
+
+
+void yyFlexLexer::yy_delete_buffer( YY_BUFFER_STATE b )
+	{
+	if ( ! b )
+		return;
+
+	if ( b == yy_current_buffer )
+		yy_current_buffer = (YY_BUFFER_STATE) 0;
+
+	if ( b->yy_is_our_buffer )
+		yy_flex_free( (void *) b->yy_ch_buf );
+
+	yy_flex_free( (void *) b );
+	}
+
+
+#include<unistd.h>
+void yyFlexLexer::yy_init_buffer( YY_BUFFER_STATE b, istream* file )
+
+	{
+	yy_flush_buffer( b );
+
+	b->yy_input_file = file;
+	b->yy_fill_buffer = 1;
+
+	b->yy_is_interactive = 0;
+	}
+
+
+void yyFlexLexer::yy_flush_buffer( YY_BUFFER_STATE b )
+	{
+	if ( ! b )
+		return;
+
+	b->yy_n_chars = 0;
+
+	/* We always need two end-of-buffer characters.  The first causes
+	 * a transition to the end-of-buffer state.  The second causes
+	 * a jam in that state.
+	 */
+	b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+	b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+	b->yy_buf_pos = &b->yy_ch_buf[0];
+
+	b->yy_at_bol = 1;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	if ( b == yy_current_buffer )
+		yy_load_buffer_state();
+	}
+
+
+#ifndef YY_NO_SCAN_BUFFER
+#endif
+
+
+#ifndef YY_NO_SCAN_STRING
+#endif
+
+
+#ifndef YY_NO_SCAN_BYTES
+#endif
+
+
+#ifndef YY_NO_PUSH_STATE
+void yyFlexLexer::yy_push_state( int new_state )
+	{
+	if ( yy_start_stack_ptr >= yy_start_stack_depth )
+		{
+		yy_size_t new_size;
+
+		yy_start_stack_depth += YY_START_STACK_INCR;
+		new_size = yy_start_stack_depth * sizeof( int );
+
+		if ( ! yy_start_stack )
+			yy_start_stack = (int *) yy_flex_alloc( new_size );
+
+		else
+			yy_start_stack = (int *) yy_flex_realloc(
+					(void *) yy_start_stack, new_size );
+
+		if ( ! yy_start_stack )
+			YY_FATAL_ERROR(
+			"out of memory expanding start-condition stack" );
+		}
+
+	yy_start_stack[yy_start_stack_ptr++] = YY_START;
+
+	BEGIN(new_state);
+	}
+#endif
+
+
+#ifndef YY_NO_POP_STATE
+void yyFlexLexer::yy_pop_state()
+	{
+	if ( --yy_start_stack_ptr < 0 )
+		YY_FATAL_ERROR( "start-condition stack underflow" );
+
+	BEGIN(yy_start_stack[yy_start_stack_ptr]);
+	}
+#endif
+
+
+#ifndef YY_NO_TOP_STATE
+int yyFlexLexer::yy_top_state()
+	{
+	return yy_start_stack[yy_start_stack_ptr - 1];
+	}
+#endif
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+
+void yyFlexLexer::LexerError( yyconst char msg[] )
+	{
+	cerr << msg << '\n';
+	exit( YY_EXIT_FAILURE );
+	}
+
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up yytext. */ \
+		yytext[yyleng] = yy_hold_char; \
+		yy_c_buf_p = yytext + n; \
+		yy_hold_char = *yy_c_buf_p; \
+		*yy_c_buf_p = '\0'; \
+		yyleng = n; \
+		} \
+	while ( 0 )
+
+
+/* Internal utility routines. */
+
+#ifndef yytext_ptr
+#ifdef YY_USE_PROTOS
+static void yy_flex_strncpy( char *s1, yyconst char *s2, int n )
+#else
+static void yy_flex_strncpy( s1, s2, n )
+char *s1;
+yyconst char *s2;
+int n;
+#endif
+	{
+	register int i;
+	for ( i = 0; i < n; ++i )
+		s1[i] = s2[i];
+	}
+#endif
+
+#ifdef YY_NEED_STRLEN
+#ifdef YY_USE_PROTOS
+static int yy_flex_strlen( yyconst char *s )
+#else
+static int yy_flex_strlen( s )
+yyconst char *s;
+#endif
+	{
+	register int n;
+	for ( n = 0; s[n]; ++n )
+		;
+
+	return n;
+	}
+#endif
+
+
+#ifdef YY_USE_PROTOS
+static void *yy_flex_alloc( yy_size_t size )
+#else
+static void *yy_flex_alloc( size )
+yy_size_t size;
+#endif
+	{
+	return (void *) malloc( size );
+	}
+
+#ifdef YY_USE_PROTOS
+static void *yy_flex_realloc( void *ptr, yy_size_t size )
+#else
+static void *yy_flex_realloc( ptr, size )
+void *ptr;
+yy_size_t size;
+#endif
+	{
+	/* The cast to (char *) in the following accommodates both
+	 * implementations that use char* generic pointers, and those
+	 * that use void* generic pointers.  It works with the latter
+	 * because both ANSI C and C++ allow castless assignment from
+	 * any pointer type to void*, and deal with argument conversions
+	 * as though doing an assignment.
+	 */
+	return (void *) realloc( (char *) ptr, size );
+	}
+
+#ifdef YY_USE_PROTOS
+static void yy_flex_free( void *ptr )
+#else
+static void yy_flex_free( ptr )
+void *ptr;
+#endif
+	{
+	free( ptr );
+	}
+
+#if YY_MAIN
+int main()
+	{
+	yylex();
+	return 0;
+	}
+#endif
+#line 82 "geometry.ll"
+
+
+extern FlexLexer * lexer;
+
+int yylex ()
+  {
+  return lexer -> yylex();
+  }
+
+extern "C" int yywrap ()
+  {
+  return 1;
+  }
diff --git a/Netgen/libsrc/csg/manifold.cpp b/Netgen/libsrc/csg/manifold.cpp
new file mode 100644
index 0000000000..9733389d67
--- /dev/null
+++ b/Netgen/libsrc/csg/manifold.cpp
@@ -0,0 +1,14 @@
+#include <csg.hpp>
+
+namespace netgen
+{
+Manifold :: Manifold () 
+{
+  ;
+}
+
+Manifold :: ~Manifold () 
+{
+  ;
+}
+}
diff --git a/Netgen/libsrc/csg/manifold.hpp b/Netgen/libsrc/csg/manifold.hpp
new file mode 100644
index 0000000000..5deb7236a7
--- /dev/null
+++ b/Netgen/libsrc/csg/manifold.hpp
@@ -0,0 +1,22 @@
+#ifndef FILE_MANIFOLD
+#define FILE_MANIFOLD
+
+/**************************************************************************/
+/* File:   manifold.hh                                                    */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   7. Aug. 96                                                     */
+/**************************************************************************/
+
+/**
+  Basis class for manifolds in 2d and 3d
+*/
+class Manifold
+{
+public:
+  ///
+  Manifold ();
+  ///
+  virtual ~Manifold ();
+};
+
+#endif
diff --git a/Netgen/libsrc/csg/meshsurf.cpp b/Netgen/libsrc/csg/meshsurf.cpp
new file mode 100644
index 0000000000..178133007c
--- /dev/null
+++ b/Netgen/libsrc/csg/meshsurf.cpp
@@ -0,0 +1,178 @@
+#include <mystdlib.h>
+
+#include <csg.hpp>
+#include <meshing.hpp>
+
+
+
+namespace netgen
+{
+  /*
+Meshing2Surfaces :: Meshing2Surfaces (const Surface & asurface)
+  : surface(asurface)
+{
+  ;
+}
+  */
+Meshing2Surfaces :: Meshing2Surfaces (const Surface & asurf,
+				      const Box<3> & abb)
+  : Meshing2(Box3d(abb.PMin(), abb.PMax())), surface(asurf)
+{
+  ;
+}
+
+
+void Meshing2Surfaces :: DefineTransformation (Point3d & p1, Point3d & p2,
+					       const PointGeomInfo * geominfo1,
+					       const PointGeomInfo * geominfo2)
+{
+  ((Surface&)surface).DefineTangentialPlane (p1, p2);
+}
+
+void Meshing2Surfaces :: TransformToPlain (const Point3d & locpoint, 
+					   const MultiPointGeomInfo & geominfo,
+					   Point2d & planepoint, 
+					   double h, int & zone)
+{
+  Point<2> hp;
+  surface.ToPlane (locpoint, hp, h, zone);
+  planepoint.X() = hp(0);
+  planepoint.Y() = hp(1);
+}
+
+int Meshing2Surfaces :: TransformFromPlain (Point2d & planepoint,
+					    Point3d & locpoint, 
+					    PointGeomInfo & gi,
+					    double h)
+{
+  Point<3> hp;
+  Point<2> hp2 (planepoint.X(), planepoint.Y());
+  surface.FromPlane (hp2, hp, h);
+  locpoint = hp;
+  gi.trignum = 1;
+  return 0;
+}
+
+
+
+double Meshing2Surfaces :: CalcLocalH (const Point3d & p, double gh) const
+{
+  return surface.LocH (p, 3, 1, gh);
+  /*
+    double loch = mesh.lochfunc->GetH(p);
+    if (gh < loch) loch = gh;
+    return loch;
+    */
+}
+
+
+
+
+
+
+MeshOptimize2dSurfaces :: MeshOptimize2dSurfaces (const CSGeometry & ageometry)
+  : MeshOptimize2d(), geometry(ageometry)
+{
+  ;
+}
+
+
+void MeshOptimize2dSurfaces :: ProjectPoint (INDEX surfind, Point3d & p) const
+{
+  Point<3> hp = p;
+  geometry.GetSurface(surfind)->Project (hp);
+  p = hp;
+}
+
+void MeshOptimize2dSurfaces :: ProjectPoint2 (INDEX surfind, INDEX surfind2, 
+					      Point3d & p) const
+{
+  Point<3> hp = p;
+  ProjectToEdge ( geometry.GetSurface(surfind), 
+		  geometry.GetSurface(surfind2), hp);
+  p = hp;
+}
+
+
+void MeshOptimize2dSurfaces :: 
+GetNormalVector(INDEX surfind, const Point3d & p, Vec3d & n) const
+{
+  Vec<3> hn = n;
+  geometry.GetSurface(surfind)->CalcGradient (p, hn);
+  hn.Normalize();
+  n = hn;
+
+  /*
+  if (geometry.GetSurface(surfind)->Inverse())
+    n *= -1;
+  */
+}
+  
+
+
+
+
+
+
+RefinementSurfaces :: RefinementSurfaces (const CSGeometry & ageometry)
+  : Refinement(), geometry(ageometry)
+{
+  ;
+}
+
+RefinementSurfaces :: ~RefinementSurfaces ()
+{
+  ;
+}
+  
+void RefinementSurfaces :: 
+PointBetween (const Point3d & p1, const Point3d & p2, double secpoint,
+	      int surfi, 
+	      const PointGeomInfo & gi1, 
+	      const PointGeomInfo & gi2,
+	      Point3d & newp, PointGeomInfo & newgi)
+{
+  Point<3> hnewp;
+  hnewp = p1+secpoint*(p2-p1);
+
+  if (surfi != -1)
+    {
+      geometry.GetSurface (surfi) -> Project (hnewp);
+      newgi.trignum = 1;
+    }
+
+  newp = hnewp;
+}
+
+void RefinementSurfaces :: 
+PointBetween (const Point3d & p1, const Point3d & p2, double secpoint,
+	      int surfi1, int surfi2, 
+	      const EdgePointGeomInfo & ap1, 
+	      const EdgePointGeomInfo & ap2,
+	      Point3d & newp, EdgePointGeomInfo & newgi)
+{
+  Point<3> hnewp = p1+secpoint*(p2-p1);
+  if (surfi1 != -1 && surfi2 != -1 && surfi1 != surfi2)
+    {
+      ProjectToEdge (geometry.GetSurface(surfi1), 
+		     geometry.GetSurface(surfi2), 
+		     hnewp);
+      // (*testout) << "Pointbetween, newp = " << hnewp << endl
+      // << ", err = " << sqrt (sqr (hnewp(0))+ sqr(hnewp(1)) + sqr (hnewp(2))) - 1 << endl;
+      newgi.edgenr = 1;
+    }
+  else if (surfi1 != -1)
+    {
+      geometry.GetSurface (surfi1) -> Project (hnewp);
+    }
+
+  newp = hnewp;
+};
+
+
+void RefinementSurfaces :: ProjectToSurface (Point<3> & p, int surfi)
+{
+  if (surfi != -1)
+    geometry.GetSurface (surfi) -> Project (p);
+};
+}
diff --git a/Netgen/libsrc/csg/meshsurf.hpp b/Netgen/libsrc/csg/meshsurf.hpp
new file mode 100644
index 0000000000..023c2eef70
--- /dev/null
+++ b/Netgen/libsrc/csg/meshsurf.hpp
@@ -0,0 +1,85 @@
+#ifndef FILE_MESHSURF
+#define FILE_MESHSURF
+
+///
+class Meshing2Surfaces : public Meshing2
+{
+  ///
+  const Surface & surface;
+  
+public:
+  ///
+  //  Meshing2Surfaces (const Surface & asurf);
+  ///
+  Meshing2Surfaces (const Surface & asurf, const Box<3> & aboundingbox);
+
+protected:
+  ///
+  virtual void DefineTransformation (Point3d & p1, Point3d & p2,
+				     const PointGeomInfo * geominfo1,
+				     const PointGeomInfo * geominfo2);
+  ///
+  virtual void TransformToPlain (const Point3d & locpoint, 
+				 const MultiPointGeomInfo & geominfo,
+				 Point2d & plainpoint, 
+				 double h, int & zone);
+  ///
+  virtual int TransformFromPlain (Point2d & plainpoint,
+				  Point3d & locpoint, 
+				  PointGeomInfo & gi,
+				  double h);
+  ///
+  virtual double CalcLocalH (const Point3d & p, double gh) const;
+};
+
+
+
+///
+class MeshOptimize2dSurfaces : public MeshOptimize2d
+  {
+  ///
+  const CSGeometry & geometry;
+
+public:
+    ///
+    MeshOptimize2dSurfaces (const CSGeometry & ageometry); 
+   
+    ///
+    virtual void ProjectPoint (INDEX surfind, Point3d & p) const;
+    ///
+    virtual void ProjectPoint2 (INDEX surfind, INDEX surfind2, Point3d & p) const;
+    ///
+    virtual void GetNormalVector(INDEX surfind, const Point3d & p, Vec3d & n) const;
+};
+
+
+
+
+
+class RefinementSurfaces : public Refinement
+{
+  const CSGeometry & geometry;
+
+public:
+  RefinementSurfaces (const CSGeometry & ageometry);
+  virtual ~RefinementSurfaces ();
+  
+  virtual void PointBetween (const Point3d & p1, const Point3d & p2, double secpoint,
+			     int surfi, 
+			     const PointGeomInfo & gi1, 
+			     const PointGeomInfo & gi2,
+			     Point3d & newp, PointGeomInfo & newgi);
+
+  virtual void PointBetween (const Point3d & p1, const Point3d & p2, double secpoint,
+			     int surfi1, int surfi2, 
+			     const EdgePointGeomInfo & ap1, 
+			     const EdgePointGeomInfo & ap2,
+			     Point3d & newp, EdgePointGeomInfo & newgi);
+
+  virtual void ProjectToSurface (Point<3> & p, int surfi);
+};
+
+
+
+#endif
+
diff --git a/Netgen/libsrc/csg/polyhedra.cpp b/Netgen/libsrc/csg/polyhedra.cpp
new file mode 100644
index 0000000000..9a6855227f
--- /dev/null
+++ b/Netgen/libsrc/csg/polyhedra.cpp
@@ -0,0 +1,288 @@
+#include <mystdlib.h>
+
+#include <linalg.hpp>
+#include <csg.hpp>
+
+namespace netgen
+{
+
+Polyhedra::Face::Face (int pi1, int pi2, int pi3, const ARRAY<Point<3> > & points)
+{
+  pnums[0] = pi1;
+  pnums[1] = pi2;
+  pnums[2] = pi3;
+
+  bbox.Set (points[pi1]);
+  bbox.Add (points[pi2]);
+  bbox.Add (points[pi3]);
+
+  v1 = points[pi2] - points[pi1];
+  v2 = points[pi3] - points[pi1];
+
+  n = Cross (v1, v2);
+  nn = n;
+  nn.Normalize();
+  //  PseudoInverse (v1, v2, w1, w2);
+
+  
+  Mat<2,3> mat;
+  Mat<3,2> inv;
+  int i, j;
+  for (i = 0; i < 3; i++)
+    {
+      mat(0,i) = v1(i);
+      mat(1,i) = v2(i);
+    }
+  CalcInverse (mat, inv);
+  for (i = 0; i < 3; i++)
+    {
+      w1(i) = inv(i,0);
+      w2(i) = inv(i,1);
+    }
+}
+
+
+Polyhedra :: Polyhedra ()
+{
+  surfaceactive.SetSize(0);
+  surfaceids.SetSize(0);
+}
+
+Polyhedra :: ~Polyhedra ()
+{
+  ;
+}
+
+Primitive * Polyhedra :: CreateDefault ()
+{
+  return new Polyhedra();
+}
+
+INSOLID_TYPE Polyhedra :: BoxInSolid (const BoxSphere<3> & box) const
+{
+  /*
+  for (i = 1; i <= faces.Size(); i++)
+    if (FaceBoxIntersection (i, box))
+      return DOES_INTERSECT;
+  */
+  for (int i = 0; i < faces.Size(); i++)
+    {
+      if (!faces[i].bbox.Intersect (box))
+	continue;
+
+      const Point<3> & p1 = points[faces[i].pnums[0]];
+      const Point<3> & p2 = points[faces[i].pnums[1]];
+      const Point<3> & p3 = points[faces[i].pnums[2]];
+
+      if (fabs (faces[i].nn * (p1 - box.Center())) > box.Diam()/2)
+	continue;
+
+      double dist2 = MinDistTP2 (p1, p2, p3, box.Center());
+      if (dist2 < sqr (box.Diam()/2))
+	{
+	  //	  (*testout) << "intersect" << endl;
+	  return DOES_INTERSECT;
+	}
+    };
+
+  return PointInSolid (box.Center(), 1e-3 * box.Diam());
+}
+
+
+INSOLID_TYPE Polyhedra :: PointInSolid (const Point<3> & p,
+					double eps) const
+{
+  //  (*testout) << "Point in Sol, p = " << p << " " << flush;
+  Vec<3> n, v1, v2;
+
+  // "random numbers":
+  n(0) = 0.123871;
+  n(1) = 0.15432;
+  n(2) = 0.43989;
+
+  int cnt = 0;
+  Point<3> pmeps (p(0) - eps, p(1) - eps, p(2) - eps);
+
+  for (int i = 0; i < faces.Size(); i++)
+    {
+      const Point<3> & fpmax = faces[i].bbox.PMax();
+      if (fpmax(0) < pmeps(0) ||
+	  fpmax(1) < pmeps(1) ||
+	  fpmax(2) < pmeps(2)) continue;
+
+      const Point<3> & p1 = points[faces[i].pnums[0]];
+      
+      Vec<3> v0 = p - p1;
+      double lam3 = -(faces[i].n * v0) / (faces[i].n * n);
+
+      if (lam3 < -eps) continue;
+      Vec<3> rs = v0 + lam3 * n;
+
+      double lam1 = (faces[i].w1 * rs);
+      double lam2 = (faces[i].w2 * rs);
+
+      if (lam3 < eps)
+	{
+	  if (lam1 >= -eps && lam2 >= -eps && lam1+lam2 <= 1+eps)
+	    {
+	      return DOES_INTERSECT;
+	    }
+	}
+      else if (lam1 >= 0 && lam2 >= 0 && lam1+lam2 <= 1)
+	//	  lam3 > 0)
+	{
+	  cnt++;
+	}
+
+    }
+
+  //  (*testout) << " inside = " << (cnt % 2) << endl;
+  return (cnt % 2) ? IS_INSIDE : IS_OUTSIDE;
+}
+
+
+
+INSOLID_TYPE Polyhedra :: VecInSolid (const Point<3> & p,
+				      const Vec<3> & v,
+				      double eps) const
+{
+  Point<3> p2 = p + (1e-3/(v.Length()+1e-16)) * v;
+  return PointInSolid (p2, eps);
+}
+
+void Polyhedra :: GetPrimitiveData (char *& classname, 
+				    ARRAY<double> & coeffs) const
+{
+  classname = "Polyhedra";
+  coeffs.SetSize(0);
+  coeffs.Append (points.Size());
+  coeffs.Append (faces.Size());
+  coeffs.Append (planes.Size());
+
+  /*
+  int i, j;
+  for (i = 1; i <= planes.Size(); i++)
+    {
+      planes.Elem(i)->Print (*testout);
+    }
+  for (i = 1; i <= faces.Size(); i++)
+    {
+      (*testout) << "face " << i << " has plane " << faces.Get(i).planenr << endl;
+      for (j = 1; j <= 3; j++)
+	(*testout) << points.Get(faces.Get(i).pnums[j-1]);
+      (*testout) << endl;
+    }
+  */
+}
+
+void Polyhedra :: SetPrimitiveData (ARRAY<double> & coeffs)
+{
+  ;
+}
+
+void Polyhedra :: Reduce (const BoxSphere<3> & box)
+{
+  int i;
+
+  for (i = 0; i < planes.Size(); i++)
+    surfaceactive[i] = 0;
+
+  /*
+  for (i = 1; i <= faces.Size(); i++)
+    if (FaceBoxIntersection (i, box))
+      surfaceactive.Elem (faces.Get(i).planenr) = 1;
+  */
+
+  for (i = 0; i < faces.Size(); i++)
+    //    if (faces.Get(i).bbox.Intersect (box))
+    if (FaceBoxIntersection (i, box))
+      surfaceactive[faces[i].planenr] = 1;
+}
+
+void Polyhedra :: UnReduce ()
+{
+  for (int i = 0; i < planes.Size(); i++)
+    surfaceactive[i] = 1;
+}
+
+int Polyhedra :: AddPoint (const Point<3> & p)
+{
+  return points.Append (p);
+}
+
+int Polyhedra :: AddFace (int pi1, int pi2, int pi3)
+{
+  int i;
+
+  faces.Append (Face (pi1, pi2, pi3, points));
+  
+  Point<3> p1 = points[pi1];
+  Point<3> p2 = points[pi2];
+  Point<3> p3 = points[pi3];
+
+  Vec<3> v1 = p2 - p1;
+  Vec<3> v2 = p3 - p1;
+
+  Vec<3> n = Cross (v1, v2); 
+  n.Normalize();
+
+  Plane pl (p1, n);
+  int inverse;
+  int identicto = -1;
+  for (i = 0; i < planes.Size(); i++)
+    if (pl.IsIdentic (*planes[i], inverse, 1e-6))
+      {
+	if (!inverse)
+	  identicto = i;
+      }
+  //  cout << "is identic = " << identicto << endl;
+
+  if (identicto != -1)
+    faces.Last().planenr = identicto;
+  else
+    {
+      planes.Append (new Plane (p1, n));
+      surfaceactive.Append (1);
+      surfaceids.Append (0);
+      faces.Last().planenr = planes.Size()-1;
+    }
+
+  return faces.Size();
+}
+
+
+
+int Polyhedra :: FaceBoxIntersection (int fnr, const BoxSphere<3> & box) const
+{
+  /*
+  (*testout) << "check face box intersection, fnr = " << fnr << endl;
+  (*testout) << "box = " << box << endl;
+  (*testout) << "face-box = " << faces[fnr].bbox << endl;
+  */
+
+  if (!faces[fnr].bbox.Intersect (box))
+    return 0;
+
+  const Point<3> & p1 = points[faces[fnr].pnums[0]];
+  const Point<3> & p2 = points[faces[fnr].pnums[1]];
+  const Point<3> & p3 = points[faces[fnr].pnums[2]];
+
+  double dist2 = MinDistTP2 (p1, p2, p3, box.Center());
+  /*
+  (*testout) << "p1 = " << p1 << endl;
+  (*testout) << "p2 = " << p2 << endl;
+  (*testout) << "p3 = " << p3 << endl;
+
+  (*testout) << "box.Center() = " << box.Center() << endl;
+  (*testout) << "center = " << box.Center() << endl;
+  (*testout) << "dist2 = " << dist2 << endl;
+  (*testout) << "diam = " << box.Diam() << endl;
+  */
+  if (dist2 < sqr (box.Diam()/2))
+    {
+      //      (*testout) << "intersect" << endl;
+      return 1;
+    }
+  return 0;
+}
+}
diff --git a/Netgen/libsrc/csg/polyhedra.hpp b/Netgen/libsrc/csg/polyhedra.hpp
new file mode 100644
index 0000000000..d422c8ca15
--- /dev/null
+++ b/Netgen/libsrc/csg/polyhedra.hpp
@@ -0,0 +1,72 @@
+#ifndef FILE_POLYHEDRA
+#define FILE_POLYHEDRA
+
+
+/**************************************************************************/
+/* File:   polyhedra.hh                                                   */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   19. Mar. 2000                                                  */
+/**************************************************************************/
+
+/*
+
+  Polyhedral primitive
+  
+*/
+
+class Polyhedra : public Primitive
+{
+  class Face {
+  public:
+    int pnums[3];
+    int planenr;
+
+    Box<3> bbox;
+    //    Point<3> center;
+    Vec<3> v1, v2;   // edges
+    Vec<3> w1, w2;   // pseudo-inverse
+    Vec<3> n;        // normal to face
+    Vec<3> nn;       // normed normal
+
+    Face () { ; }
+    Face (int pi1, int pi2, int pi3, const ARRAY<Point<3> > & points);
+  };
+
+  ARRAY<Point<3> > points;
+  ARRAY<Face> faces;
+  ARRAY<Plane*> planes;
+
+public:
+  Polyhedra ();
+  virtual ~Polyhedra ();
+  static Primitive * CreateDefault ();
+
+  virtual INSOLID_TYPE BoxInSolid (const BoxSphere<3> & box) const;
+  virtual INSOLID_TYPE PointInSolid (const Point<3> & p,
+				     double eps) const;
+  virtual INSOLID_TYPE VecInSolid (const Point<3> & p,
+				   const Vec<3> & v,
+				   double eps) const;
+
+  virtual int GetNSurfaces() const 
+    { return planes.Size(); }
+  virtual Surface & GetSurface (int i) 
+    { return *planes[i]; }
+  virtual const Surface & GetSurface (int i) const
+    { return *planes[i]; }
+
+  virtual void GetPrimitiveData (char *& classname, ARRAY<double> & coeffs) const;
+  virtual void SetPrimitiveData (ARRAY<double> & coeffs);
+
+  virtual void Reduce (const BoxSphere<3> & box);
+  virtual void UnReduce ();
+
+  int AddPoint (const Point<3> & p);
+  int AddFace (int pi1, int pi2, int pi3);
+  
+protected:
+  int FaceBoxIntersection (int fnr, const BoxSphere<3> & box) const;
+  //  void CalcData();
+};
+
+#endif
diff --git a/Netgen/libsrc/csg/revolution.cpp b/Netgen/libsrc/csg/revolution.cpp
new file mode 100644
index 0000000000..e235012e43
--- /dev/null
+++ b/Netgen/libsrc/csg/revolution.cpp
@@ -0,0 +1,151 @@
+#include <mystdlib.h>
+
+#include <linalg.hpp>
+#include <csg.hpp>
+
+namespace netgen
+{
+
+#ifdef NONE
+
+Revolution :: Revolution (const Point<3> & ap1, const Point<3> & ap2)
+{
+  p1 = ap1;
+  p2 = ap2;
+  v12 = p2 - p1;
+  v12.Normalize();
+}
+
+Revolution :: ~Revolution ()
+{
+  ;
+}
+
+Primitive * Revolution :: CreateDefault ()
+{
+  return new Revolution( Point<3> (0, 0, 0),
+			 Point<3> (1, 0, 0));
+}
+
+INSOLID_TYPE Revolution :: BoxInSolid (const BoxSphere<3> & box) const
+{
+  int i;
+
+  Vec<3> v = box.Center() - p1;
+  double x = v * v12;
+  double y = sqrt (v.Length2() - x*x);
+  
+  Point<2> lp1, lp2;
+  for (i = 1; i <= polygon.GetNP(); i++)
+    {
+      polygon.GetLine (i, lp1, lp2);
+
+      double dist2 = MinDistLP2 (lp1, lp2, Point<2>(x,y));
+      if (dist2 < sqr (box.Diam()))
+	return DOES_INTERSECT;
+    };
+
+  return PointInSolid (box.Center(), 1e-3 * box.Diam());
+}
+
+
+INSOLID_TYPE Revolution :: PointInSolid (const Point<3> & p,
+					 double eps) const
+{
+  int i, cnt;
+
+  Vec<3> v(p1, p);
+  double x = v * v12;
+  double y = sqrt (v.Length2() - x*x);
+  
+  if (polygon.IsOn (Point<2> (x, y)))
+    return DOES_INTERSECT;
+  if (polygon.IsIn (Point<2> (x, y)))
+    return IS_INSIDE;
+  else
+    return IS_OUTSIDE;
+}
+
+
+
+INSOLID_TYPE Revolution :: VecInSolid (const Point<3> & p,
+				      const Vec<3> & v,
+				      double eps) const
+{
+  Point<3> p2 = p + (1e-3/(v.Length()+1e-16)) * v;
+  return PointInSolid (p2, eps);
+}
+
+
+void Revolution :: GetPrimitiveData (char *& classname, 
+				    ARRAY<double> & coeffs) const
+{
+  classname = "Revolution";
+  coeffs.SetSize(0);
+  coeffs.Append (polygon.GetNP());
+}
+
+void Revolution :: SetPrimitiveData (ARRAY<double> & coeffs)
+{
+  ;
+}
+
+void Revolution :: Reduce (const BoxSphere<3> & box)
+{
+  int i;
+
+  for (i = 1; i <= polygon.GetNP(); i++)
+    surfaceactive.Elem (i) = 0;
+
+
+  Vec<3> v = box.Center() - p1;
+  double x = v * v12;
+  double y = sqrt (v.Length2() - x*x);
+
+  Point<2> lp1, lp2;
+  for (i = 1; i <= polygon.GetNP(); i++)
+    {
+      polygon.GetLine (i, lp1, lp2);
+
+      double dist2 = MinDistLP2 (lp1, lp2, Point<2>(x,y));
+      if (dist2 < sqr (box.Diam()/2))
+	surfaceactive.Elem(i) = 1;
+    };
+}
+
+void Revolution :: UnReduce ()
+{
+  for (int i = 0; i < polygon.GetNP(); i++)
+    surfaceactive[i] = 1;
+}
+
+
+int Revolution :: AddPoint (const Point<2> & p)
+{
+  polygon.AddPoint (p);
+  return polygon.GetNP();
+}
+
+void Revolution :: Finish ()
+{
+  int i;
+  Point<2> lp1, lp2;
+  Point<3> cp1, cp2;
+
+  for (i = 1; i <= polygon.GetNP(); i++)
+    {
+      polygon.GetLine (i, lp1, lp2);
+      cp1 = p1 + lp1.X() * v12;
+      cp2 = p1 + lp2.X() * v12;
+      
+      faces.Append (new Cone (cp1, cp2,
+			      fabs (lp1.Y()), 
+			      fabs (lp2.Y())));
+
+      invsurf.Append (lp1.X() < lp2.X());
+    }
+}
+
+
+#endif
+}
diff --git a/Netgen/libsrc/csg/revolution.hpp b/Netgen/libsrc/csg/revolution.hpp
new file mode 100644
index 0000000000..d57102d306
--- /dev/null
+++ b/Netgen/libsrc/csg/revolution.hpp
@@ -0,0 +1,65 @@
+#ifndef FILE_REVOLUTION
+#define FILE_REVOLUTION
+
+
+/**************************************************************************/
+/* File:   revolution.hh                                                  */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   12. Oct. 2000                                                  */
+/**************************************************************************/
+
+/*
+
+  Primitive of revolution
+  
+*/
+
+
+#ifdef NONE
+
+class Revolution : public Primitive
+{
+  Point<3> p1, p2;
+  Vec<3> v12;
+  Polygon2d polygon;
+  ARRAY<Cone*> faces;
+  ARRAY<int> invsurf;
+public:
+  Revolution (const Point<3> & ap1, const Point<3> & ap2);
+  ~Revolution ();
+  static Primitive * CreateDefault ();
+
+  virtual INSOLID_TYPE BoxInSolid (const BoxSphere<3> & box) const;
+  virtual INSOLID_TYPE PointInSolid (const Point<3> & p,
+				     double eps) const;
+  virtual INSOLID_TYPE VecInSolid (const Point<3> & p,
+				   const Vec<3> & v,
+				   double eps) const;
+
+  virtual int GetNSurfaces() const 
+    { return faces.Size(); }
+  virtual Surface & GetSurface (int i) 
+    { return *faces.Elem(i); }
+  virtual const Surface & GetSurface (int i = 1) const
+    { return *faces.Get(i); }
+
+  virtual int SurfaceInverted (int i = 1) const
+  { return invsurf.Get(i); }
+
+  virtual void GetPrimitiveData (char *& classname, ARRAY<double> & coeffs) const;
+  virtual void SetPrimitiveData (ARRAY<double> & coeffs);
+
+  virtual void Reduce (const BoxSphere<3> & box);
+  virtual void UnReduce ();
+
+  int AddPoint (const Point<2> & p);
+  void Finish ();
+protected:
+  //  int FaceBoxIntersection (int fnr, const BoxSphere<3> & box) const;
+  //  void CalcData();
+};
+
+
+#endif
+
+#endif
diff --git a/Netgen/libsrc/csg/singularref.cpp b/Netgen/libsrc/csg/singularref.cpp
new file mode 100644
index 0000000000..b445d0085b
--- /dev/null
+++ b/Netgen/libsrc/csg/singularref.cpp
@@ -0,0 +1,134 @@
+#include <mystdlib.h>
+#include <myadt.hpp>
+
+#include <linalg.hpp>
+#include <csg.hpp>
+#include <meshing.hpp>
+
+namespace netgen
+{
+
+SingularEdge :: SingularEdge (double abeta, 
+			      const Solid * asol1, 
+			      const Solid * asol2)
+{
+  beta = abeta;
+
+  if (beta > 1) 
+    {
+      beta = 1;
+      cout << "Warning: beta set to 1" << endl;
+    }
+  if (beta <= 1e-3)
+    {
+      beta = 1e-3;
+      cout << "Warning: beta set to minimal value 0.001" << endl;
+    }
+
+  sol1 = asol1;
+  sol2 = asol2;
+}
+
+void SingularEdge :: FindPointsOnEdge (class Mesh & mesh)
+{
+  (*testout) << "find points on edge" << endl;
+  int i, j;
+  points.SetSize(0);
+  segms.SetSize(0);
+  for (i = 1; i <= mesh.GetNSeg(); i++)
+    {
+      INDEX_2 i2 (mesh.LineSegment(i).p1,
+		  mesh.LineSegment(i).p2);
+      
+      int onedge = 1;
+      for (j = 1; j <= 2; j++)
+	{
+	  const Point<3> p = mesh.Point(i2.I(j));
+	  if (sol1->IsIn (p, 1e-3) && sol2->IsIn(p, 1e-3) &&
+	      !sol1->IsStrictIn (p, 1e-3) && !sol2->IsStrictIn(p, 1e-3))
+	    {
+	      ;
+
+	    }
+	  else
+	    onedge = 0;
+	}
+      if (onedge)
+	{
+	  segms.Append (i2);
+	  cout << "sing segment << " << i2 << endl;
+	  points.Append (mesh.Point(i2.I1()));
+	  points.Append (mesh.Point(i2.I2()));
+	}	    
+    }
+
+  
+  (*testout) << "Singular points:" << endl;
+  for (i = 1; i <= points.Size(); i++)
+    (*testout) << points.Get(i) << endl;
+  /*
+  for (i = 1; i <= mesh.GetNP(); i++)
+    {
+      const Point<3> p = mesh.Point(i);
+      if (sol1->IsIn (p) && sol2->IsIn(p) &&
+	  !sol1->IsStrictIn (p) && !sol2->IsStrictIn(p))
+	{
+	  points.Append (p);
+	  cout << "Point " << p << " is on singular edge" << endl;
+	}
+    }
+  */
+}
+
+void SingularEdge :: SetMeshSize (class Mesh & mesh, double globalh)
+{
+  int i;
+
+  double hloc = pow (globalh, 1/beta);
+  for (i = 1; i <= points.Size(); i++)
+    mesh.RestrictLocalH (points.Get(i), hloc);
+}
+
+
+
+
+
+
+SingularPoint :: SingularPoint (double abeta, 
+				const Solid * asol1, 
+				const Solid * asol2,
+				const Solid * asol3)
+{
+  beta = abeta;
+  sol1 = asol1;
+  sol2 = asol2;
+  sol3 = asol3;
+}
+
+
+void SingularPoint :: FindPoints (class Mesh & mesh)
+{
+  int i;
+  points.SetSize(0);
+  for (i = 1; i <= mesh.GetNP(); i++)
+    {
+      const Point<3> p = mesh.Point(i);
+      if (sol1->IsIn (p) && sol2->IsIn(p) && sol3->IsIn(p) &&
+	  !sol1->IsStrictIn (p) && !sol2->IsStrictIn(p) && !sol3->IsStrictIn(p))
+	{
+	  points.Append (p);
+	  cout << "Point " << p << " is a singular point" << endl;
+	}
+    }  
+}
+
+
+void SingularPoint :: SetMeshSize (class Mesh & mesh, double globalh)
+{
+  int i;
+
+  double hloc = pow (globalh, 1/beta);
+  for (i = 1; i <= points.Size(); i++)
+    mesh.RestrictLocalH (points.Get(i), hloc);  
+}
+}
diff --git a/Netgen/libsrc/csg/singularref.hpp b/Netgen/libsrc/csg/singularref.hpp
new file mode 100644
index 0000000000..b2d2f2d839
--- /dev/null
+++ b/Netgen/libsrc/csg/singularref.hpp
@@ -0,0 +1,45 @@
+#ifndef FILE_SINGULARREF
+#define FILE_SINGULARREF
+
+/**************************************************************************/
+/* File:   singularref.hh                                                 */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   25. Sep. 99                                                    */
+/**************************************************************************/
+
+/**
+   Control for local refinement
+*/
+
+
+
+class SingularEdge 
+{
+public:
+  double beta;
+  const Solid *sol1, *sol2;
+  ARRAY<Point<3> > points;
+  ARRAY<INDEX_2> segms;
+public:
+  SingularEdge (double abeta, const Solid * asol1, const Solid * asol2);
+  void FindPointsOnEdge (class Mesh & mesh);
+  void SetMeshSize (class Mesh & mesh, double globalh);
+};
+
+
+class SingularPoint
+{
+public:
+  double beta;
+  const Solid *sol1, *sol2, *sol3;
+  ARRAY<Point<3> > points;
+ 
+public:
+  SingularPoint (double abeta, const Solid * asol1, const Solid * asol2,
+		 const Solid * asol3);
+  void FindPoints (class Mesh & mesh);
+  void SetMeshSize (class Mesh & mesh, double globalh);
+};
+
+
+#endif
diff --git a/Netgen/libsrc/csg/solid.cpp b/Netgen/libsrc/csg/solid.cpp
new file mode 100644
index 0000000000..5ea936c1d1
--- /dev/null
+++ b/Netgen/libsrc/csg/solid.cpp
@@ -0,0 +1,1285 @@
+#include <mystdlib.h>
+
+#include <linalg.hpp>
+#include <csg.hpp>
+
+
+namespace netgen
+{
+  using namespace netgen;
+
+
+SolidIterator :: SolidIterator ()
+{
+  ;
+}
+
+SolidIterator :: ~SolidIterator ()
+{
+  ;
+}
+
+
+
+
+int Solid :: cntnames = 0;
+  
+Solid :: Solid (Primitive * aprim)
+{
+  op = TERM;
+  prim = aprim;
+  s1 = s2 = NULL;
+  maxh = 1e10;
+
+  /*
+  cntnames ++;
+  name = new char[16];
+  sprintf (name, "noname%d", cntnames);
+  */
+  name = NULL;   // name by number ?
+}
+
+Solid :: Solid (optyp aop, Solid * as1, Solid * as2)
+{
+  op = aop;
+  s1 = as1;
+  s2 = as2;
+  prim = NULL;
+  name = NULL;
+  maxh = 1e10;
+}
+
+Solid :: ~Solid ()
+{
+  delete [] name;
+
+  switch (op)
+    {
+    case UNION:
+    case SECTION:
+      {
+	delete s1;
+	delete s2;
+	break;
+      }
+    case SUB:
+      //    case ROOT:
+      {
+	delete s1;
+	break;
+      }
+    default:
+      break;
+    }
+}
+
+void Solid :: SetName (const char * aname)
+{
+  delete [] name;
+  name = new char[strlen (aname)+1];
+  strcpy (name, aname);
+}
+
+
+
+
+Solid * Solid :: Copy (CSGeometry & geom) const
+{
+  Solid * nsol;
+  switch (op)
+    {
+    case TERM:
+      {
+	Primitive * nprim = prim->Copy();
+
+	for (int j = 0; j < nprim->GetNSurfaces(); j++)
+	  {
+	    geom.AddSurface (&nprim->GetSurface(j));
+	    nprim->SetSurfaceId (j, geom.GetNSurf()-1);
+	  }
+	nsol = new Solid (nprim);
+	break;
+      }
+    case SECTION:
+    case UNION:
+      {
+	Solid *nsol1, *nsol2;
+
+	nsol1 = s1 -> Copy (geom);
+	nsol2 = s2 -> Copy (geom);
+
+	nsol = new Solid (op, nsol1, nsol2);
+	break;
+      }
+
+    case SUB:
+      {
+	Solid * nsol1 = s1 -> Copy (geom);
+	nsol = new Solid (SUB, nsol1);
+	break;
+      }
+      
+    case ROOT:
+      {
+	nsol = s1->Copy(geom);
+	break;
+      }
+    }
+  return nsol;
+}
+
+ 
+void Solid :: Transform (Transformation<3> & trans)
+{
+  switch (op)
+    {
+    case TERM:
+      {
+	prim -> Transform (trans);
+	break;
+      }
+    case SECTION:
+    case UNION:
+      {
+	s1 -> Transform (trans);
+	s2 -> Transform (trans);
+	break;
+      }
+
+    case SUB:
+    case ROOT:
+      {
+	s1 -> Transform (trans);
+	break;
+      }
+    }  
+}
+
+
+
+void Solid :: IterateSolid (SolidIterator & it,
+			    int only_once)
+{
+  if (only_once)
+    {
+      if (visited)
+	return;
+
+      visited = 1; 
+    }
+
+  it.Do (this);
+
+  switch (op)
+    {
+    case SECTION:
+      {
+	s1->IterateSolid (it, only_once);
+	s2->IterateSolid (it, only_once);
+	break;
+      }
+    case UNION:
+      {
+	s1->IterateSolid (it, only_once);
+	s2->IterateSolid (it, only_once);
+	break;
+      }
+    case SUB:
+    case ROOT:
+      {
+	s1->IterateSolid (it, only_once);
+	break;
+      }
+    } 
+}
+
+
+
+
+int Solid :: IsIn (const Point<3> & p, double eps) const
+{
+  int hv1, hv2;
+  switch (op)
+    {
+    case TERM:
+      {
+	INSOLID_TYPE ist = prim->PointInSolid (p, eps);
+	return ( (ist == IS_INSIDE) || (ist == DOES_INTERSECT) ) ? 1 : 0;
+      }
+    case SECTION:
+      return s1->IsIn (p, eps) && s2->IsIn (p, eps);
+    case UNION:
+      return s1->IsIn (p, eps) || s2->IsIn (p, eps);
+    case SUB:
+      return !s1->IsStrictIn (p, eps);
+    case ROOT:
+      return s1->IsIn (p, eps);
+    }
+  return 0;
+}
+
+int Solid :: IsStrictIn (const Point<3> & p, double eps) const
+{
+  switch (op)
+    {
+    case TERM:
+      {
+	INSOLID_TYPE ist = prim->PointInSolid (p, eps);
+	return (ist == IS_INSIDE) ? 1 : 0;
+      }
+    case SECTION:
+      return s1->IsStrictIn(p, eps) && s2->IsStrictIn(p, eps);
+    case UNION:
+      return s1->IsStrictIn(p, eps) || s2->IsStrictIn(p, eps);
+    case SUB:
+      return !s1->IsIn (p, eps);
+    case ROOT:
+      return s1->IsStrictIn (p, eps);
+    }
+  return 0;
+}
+
+int Solid :: VectorIn (const Point<3> & p, const Vec<3> & v, 
+		       double eps) const
+{
+  Vec<3> hv;
+  switch (op)
+    {
+    case TERM:
+      {
+	INSOLID_TYPE ist = prim->VecInSolid (p, v, eps);
+	return (ist == IS_INSIDE || ist == DOES_INTERSECT) ? 1 : 0;
+      }
+    case SECTION:
+      return s1 -> VectorIn (p, v, eps) && s2 -> VectorIn (p, v, eps);
+    case UNION:
+      return s1 -> VectorIn (p, v, eps) || s2 -> VectorIn (p, v, eps);
+    case SUB:
+      return !s1->VectorStrictIn(p, v, eps);
+    case ROOT:
+      return s1->VectorIn(p, v, eps);
+    }
+  return 0;
+}
+
+int Solid :: VectorStrictIn (const Point<3> & p, const Vec<3> & v,
+			     double eps) const
+{
+  Vec<3> hv;
+  switch (op)
+    {
+    case TERM:
+      {
+	INSOLID_TYPE ist = prim->VecInSolid (p, v, eps);
+	return (ist == IS_INSIDE) ? 1 : 0;
+      }
+    case SECTION:
+      return s1 -> VectorStrictIn (p, v, eps) && 
+	s2 -> VectorStrictIn (p, v, eps);
+    case UNION:
+      return s1 -> VectorStrictIn (p, v, eps) || 
+	s2 -> VectorStrictIn (p, v, eps);
+    case SUB:
+      return !s1->VectorIn(p, v, eps);
+    case ROOT:
+      return s1->VectorStrictIn(p, v, eps);
+    }
+  return 0;
+}
+
+
+int Solid::VectorIn2 (const Point<3> & p, const Vec<3> & v1, 
+		      const Vec<3> & v2, double eps) const
+{
+  if (VectorStrictIn (p, v1, eps))
+    return 1;
+  if (!VectorIn (p, v1, eps))
+    return 0;
+  
+  return VectorIn2Rec (p, v1, v2, eps);
+}
+
+int Solid::VectorIn2Rec (const Point<3> & p, const Vec<3> & v1, 
+			 const Vec<3> & v2, double eps) const
+{
+  int hv1, hv2;
+  switch (op)
+    {
+    case TERM:
+      return prim->VecInSolid2 (p, v1, v2, eps);
+    case SECTION:
+      return s1->VectorIn2Rec (p, v1, v2, eps) && 
+	s2->VectorIn2Rec (p, v1, v2, eps);
+    case UNION:
+      return s1->VectorIn2Rec (p, v1, v2, eps) ||
+	s2->VectorIn2Rec (p, v1, v2, eps);
+    case SUB:
+      return !s1->VectorIn2Rec (p, v1, v2, eps);
+    case ROOT:
+      return s1->VectorIn2Rec (p, v1, v2, eps);
+    }
+  return 0;  
+}
+
+
+
+
+
+
+void Solid :: Print (ostream & str) const
+{
+  switch (op)
+    {
+    case TERM:
+      {
+	str << prim->GetSurfaceId(0);
+	for (int i = 1; i < prim->GetNSurfaces(); i++)
+	  str << "," << prim->GetSurfaceId(i);
+	break;
+      }
+    case SECTION:
+      {
+	str << "(";
+	s1 -> Print (str);
+	str << " AND ";
+	s2 -> Print (str);
+	str << ")";
+	break;
+      }
+    case UNION:
+      {
+	str << "(";
+	s1 -> Print (str);
+	str << " OR ";
+	s2 -> Print (str);
+	str << ")";
+	break;
+      }
+    case SUB:
+      {
+	str << " NOT ";
+	s1 -> Print (str);
+	break;
+      }
+    case ROOT:
+      {
+	str << " [" << name << "=";
+	s1 -> Print (str);
+	str << "] ";
+	break;
+      }
+    }
+}
+
+
+
+void Solid :: GetSolidData (ostream & ost, int first) const
+{
+  switch (op)
+    {
+    case SECTION:
+      {
+	ost << "(";
+	s1 -> GetSolidData (ost, 0);
+	ost << " AND ";
+	s2 -> GetSolidData (ost, 0);
+	ost << ")";
+	break;
+      }
+    case UNION:
+      {
+	ost << "(";
+	s1 -> GetSolidData (ost, 0);
+	ost << " OR ";
+	s2 -> GetSolidData (ost, 0);
+	ost << ")";
+	break;
+      }
+    case SUB:
+      {
+	ost << "NOT ";
+	s1 -> GetSolidData (ost, 0);
+	break;
+      }
+    case TERM:
+      {
+	if (name)
+	  ost << name;
+	else
+	  ost << "(noname)";
+	break;
+      }
+    case ROOT:
+      {
+	if (first)
+	  s1 -> GetSolidData (ost, 0);
+	else
+	  ost << name;
+	break;
+      }
+    }
+}
+
+
+
+static Solid * CreateSolidExpr (istream & ist, const SYMBOLTABLE<Solid*> & solids);
+static Solid * CreateSolidTerm (istream & ist, const SYMBOLTABLE<Solid*> & solids);
+static Solid * CreateSolidPrim (istream & ist, const SYMBOLTABLE<Solid*> & solids);
+
+static void ReadString (istream & ist, char * str)
+{
+  char * hstr = str;
+  char ch;
+
+  while (1)
+    {
+      ist.get(ch);
+      if (!ist.good()) break;
+
+      if (!isspace (ch))
+	{
+	  ist.putback (ch);
+	  break;
+	}
+    }
+
+  while (1)
+    {
+      ist.get(ch);
+      if (!ist.good()) break;
+      if (isalpha(ch) || isdigit(ch))
+	{
+	  *str = ch;
+	  str++;
+	}
+      else
+	{
+	  ist.putback (ch);
+	  break;
+	}
+    }
+  *str = 0;
+  //  cout << "Read string (" << hstr << ")" 
+  //       << "put back: " << ch << endl;
+}
+
+
+Solid * CreateSolidExpr (istream & ist, const SYMBOLTABLE<Solid*> & solids)
+{
+  //  cout << "create expr" << endl;
+
+  Solid *s1, *s2;
+  char str[100];
+
+  s1 = CreateSolidTerm (ist, solids);
+  ReadString (ist, str);
+  if (strcmp (str, "OR") == 0)
+    {
+      //      cout << " OR ";
+      s2 = CreateSolidExpr (ist, solids);
+      return new Solid (Solid::UNION, s1, s2);
+    }
+
+  //  cout << "no OR found, put back string: " << str << endl;
+  int i;
+  for (i = strlen(str)-1; i >= 0; i--)
+    ist.putback (str[i]);
+
+  return s1;
+}
+
+Solid * CreateSolidTerm (istream & ist, const SYMBOLTABLE<Solid*> & solids)
+{
+  //  cout << "create term" << endl;
+
+  Solid *s1, *s2;
+  char str[100];
+
+  s1 = CreateSolidPrim (ist, solids);
+  ReadString (ist, str);
+  if (strcmp (str, "AND") == 0)
+    {
+      //      cout << " AND ";
+      s2 = CreateSolidTerm (ist, solids);
+      return new Solid (Solid::SECTION, s1, s2);
+    }
+
+
+  //  cout << "no AND found, put back string: " << str << endl;
+  int i;
+  for (i = strlen(str)-1; i >= 0; i--)
+    ist.putback (str[i]);
+
+  return s1;
+}
+
+Solid * CreateSolidPrim (istream & ist, const SYMBOLTABLE<Solid*> & solids)
+{
+  Solid * s1;
+  char ch;
+  char str[100];
+
+  ist >> ch;
+  if (ch == '(')
+    {
+      s1 = CreateSolidExpr (ist, solids);
+      ist >> ch;  // ')'
+      //      cout << "close back " << ch << endl;
+      return s1;
+    }
+  ist.putback (ch);
+  
+  ReadString (ist, str);
+  if (strcmp (str, "NOT") == 0)
+    {
+      //      cout << " NOT ";
+      s1 = CreateSolidPrim (ist, solids);
+      return new Solid (Solid::SUB, s1);
+    }
+
+  (*testout) << "get terminal " << str << endl;
+  s1 = solids.Get(str);
+  if (s1)
+    {
+      //      cout << "primitive: " << str << endl;
+      return s1;
+    }
+  cerr << "syntax error" << endl;
+
+  return NULL;
+}
+
+
+Solid * Solid :: CreateSolid (istream & ist, const SYMBOLTABLE<Solid*> & solids)
+{
+  Solid * nsol =  CreateSolidExpr (ist, solids);
+  nsol = new Solid (ROOT, nsol);
+  (*testout) << "Print new sol: ";
+  nsol -> Print (*testout);
+  (*testout) << endl;
+  return nsol;
+}
+
+
+
+void Solid :: Boundaries (const Point<3> & p, ARRAY<int> & bounds) const
+{
+  int in, strin;
+  bounds.SetSize (0);
+  RecBoundaries (p, bounds, in, strin);
+}
+
+void Solid :: RecBoundaries (const Point<3> & p, ARRAY<int> & bounds,
+			     int & in, int & strin) const
+{
+  switch (op)
+    {
+    case TERM:
+      {
+	/*
+	double val;
+	val = surf->CalcFunctionValue (p);
+	in = (val < 1e-6);
+	strin = (val < -1e-6);
+	if (in && !strin) bounds.Append (id);
+	*/
+	if (prim->PointInSolid (p, 1e-6) == DOES_INTERSECT)
+	  bounds.Append (prim->GetSurfaceId (1));
+	break;
+      }
+    case SECTION:
+      {
+	int i, in1, in2, strin1, strin2;
+	ARRAY<int> bounds1, bounds2;
+
+	s1 -> RecBoundaries (p, bounds1, in1, strin1);
+	s2 -> RecBoundaries (p, bounds2, in2, strin2);
+
+	if (in1 && in2)
+	  {
+	    for (i = 1; i <= bounds1.Size(); i++)
+	      bounds.Append (bounds1.Get(i));
+	    for (i = 1; i <= bounds2.Size(); i++)
+	      bounds.Append (bounds2.Get(i));
+	  }
+	in = (in1 && in2);
+	strin = (strin1 && strin2);
+	break;
+      }
+    case UNION:
+      {
+	int i, in1, in2, strin1, strin2;
+	ARRAY<int> bounds1, bounds2;
+
+	s1 -> RecBoundaries (p, bounds1, in1, strin1);
+	s2 -> RecBoundaries (p, bounds2, in2, strin2);
+
+	if (!strin1 && !strin2)
+	  {
+	    for (i = 1; i <= bounds1.Size(); i++)
+	      bounds.Append (bounds1.Get(i));
+	    for (i = 1; i <= bounds2.Size(); i++)
+	      bounds.Append (bounds2.Get(i));
+	  }
+	in = (in1 || in2);
+	strin = (strin1 || strin2);
+	break;
+      }
+    case SUB:
+      {
+	int hin, hstrin;
+	s1 -> RecBoundaries (p, bounds, hin, hstrin);
+	in = !hstrin;
+	strin = !hin;
+	break;
+      }
+
+    case ROOT:
+      {
+	s1 -> RecBoundaries (p, bounds, in, strin);
+	break;
+      }
+    }
+}
+
+
+
+void Solid :: TangentialSolid (const Point<3> & p, Solid *& tansol) const
+{
+  int in, strin;
+  RecTangentialSolid (p, tansol, in, strin);
+}
+
+void Solid :: RecTangentialSolid (const Point<3> & p, Solid *& tansol,
+				  int & in, int & strin) const
+{
+  tansol = NULL;
+
+  switch (op)
+    {
+    case TERM:
+      {
+	/*
+	double val;
+	val = surf->CalcFunctionValue (p);
+	in = (val < 1e-6);
+	strin = (val < -1e-6);
+	if (in && !strin)
+	  tansol = new Solid (surf, id);
+	*/
+
+	INSOLID_TYPE ist = prim->PointInSolid(p, 1e-6);
+
+	in = (ist == IS_INSIDE || ist == DOES_INTERSECT);
+	strin = (ist == IS_INSIDE);
+
+	if (ist == DOES_INTERSECT)
+	  tansol = new Solid (prim);
+	break;
+      }
+    case SECTION:
+      {
+	int in1, in2, strin1, strin2;
+	Solid * tansol1, * tansol2;
+
+	s1 -> RecTangentialSolid (p, tansol1, in1, strin1);
+	s2 -> RecTangentialSolid (p, tansol2, in2, strin2);
+
+	if (in1 && in2)
+	  {
+	    if (tansol1 && tansol2)
+	      tansol = new Solid (SECTION, tansol1, tansol2);
+	    else if (tansol1)
+	      tansol = tansol1;
+	    else if (tansol2)
+	      tansol = tansol2;
+	  }
+	in = (in1 && in2);
+	strin = (strin1 && strin2);
+	break;
+      }
+    case UNION:
+      {
+	int in1, in2, strin1, strin2;
+	Solid * tansol1, * tansol2;
+
+	s1 -> RecTangentialSolid (p, tansol1, in1, strin1);
+	s2 -> RecTangentialSolid (p, tansol2, in2, strin2);
+
+	if (!strin1 && !strin2)
+	  {
+	    if (tansol1 && tansol2)
+	      tansol = new Solid (UNION, tansol1, tansol2);
+	    else if (tansol1)
+	      tansol = tansol1;
+	    else if (tansol2)
+	      tansol = tansol2;
+	  }
+	in = (in1 || in2);
+	strin = (strin1 || strin2);
+	break;
+      }
+    case SUB:
+      {
+	int hin, hstrin;
+	Solid * tansol1;
+
+	s1 -> RecTangentialSolid (p, tansol1, hin, hstrin);
+
+	if (tansol1)
+	  tansol = new Solid (SUB, tansol1);
+	in = !hstrin;
+	strin = !hin;
+	break;
+      }
+    case ROOT:
+      {
+	s1 -> RecTangentialSolid (p, tansol, in, strin);
+	break;
+      }
+    }
+}
+
+
+
+
+void Solid :: TangentialSolid2 (const Point<3> & p, 
+				const Vec<3> & t,
+				Solid *& tansol) const
+{
+  int in, strin;
+  RecTangentialSolid2 (p, t, tansol, in, strin);
+}
+
+void Solid :: RecTangentialSolid2 (const Point<3> & p, const Vec<3> & t,
+				   Solid *& tansol,
+				   int & in, int & strin) const
+{
+  tansol = NULL;
+
+  switch (op)
+    {
+    case TERM:
+      {
+	/*
+	double val;
+	val = surf->CalcFunctionValue (p);
+	in = (val < 1e-6);
+	strin = (val < -1e-6);
+	if (in && !strin)
+	  tansol = new Solid (surf, id);
+	*/
+
+	INSOLID_TYPE ist = prim->PointInSolid(p, 1e-6);
+	if (ist == DOES_INTERSECT)
+	  ist = prim->VecInSolid (p, t, 1e-6);
+
+	in = (ist == IS_INSIDE || ist == DOES_INTERSECT);
+	strin = (ist == IS_INSIDE);
+
+	if (ist == DOES_INTERSECT)
+	  tansol = new Solid (prim);
+	break;
+      }
+    case SECTION:
+      {
+	int in1, in2, strin1, strin2;
+	Solid * tansol1, * tansol2;
+
+	s1 -> RecTangentialSolid2 (p, t, tansol1, in1, strin1);
+	s2 -> RecTangentialSolid2 (p, t, tansol2, in2, strin2);
+
+	if (in1 && in2)
+	  {
+	    if (tansol1 && tansol2)
+	      tansol = new Solid (SECTION, tansol1, tansol2);
+	    else if (tansol1)
+	      tansol = tansol1;
+	    else if (tansol2)
+	      tansol = tansol2;
+	  }
+	in = (in1 && in2);
+	strin = (strin1 && strin2);
+	break;
+      }
+    case UNION:
+      {
+	int in1, in2, strin1, strin2;
+	Solid * tansol1, * tansol2;
+
+	s1 -> RecTangentialSolid2 (p, t, tansol1, in1, strin1);
+	s2 -> RecTangentialSolid2 (p, t, tansol2, in2, strin2);
+
+	if (!strin1 && !strin2)
+	  {
+	    if (tansol1 && tansol2)
+	      tansol = new Solid (UNION, tansol1, tansol2);
+	    else if (tansol1)
+	      tansol = tansol1;
+	    else if (tansol2)
+	      tansol = tansol2;
+	  }
+	in = (in1 || in2);
+	strin = (strin1 || strin2);
+	break;
+      }
+    case SUB:
+      {
+	int hin, hstrin;
+	Solid * tansol1;
+
+	s1 -> RecTangentialSolid2 (p, t, tansol1, hin, hstrin);
+
+	if (tansol1)
+	  tansol = new Solid (SUB, tansol1);
+	in = !hstrin;
+	strin = !hin;
+	break;
+      }
+    case ROOT:
+      {
+	s1 -> RecTangentialSolid2 (p, t, tansol, in, strin);
+	break;
+      }
+    }
+}
+
+
+
+
+int Solid :: Edge (const Point<3> & p, const Vec<3> & v) const
+{
+  int in, strin, faces;
+  RecEdge (p, v, in, strin, faces);
+  return faces >= 2;
+}
+
+int Solid :: OnFace (const Point<3> & p, const Vec<3> & v) const
+{
+  int in, strin, faces;
+  RecEdge (p, v, in, strin, faces);
+  return faces >= 1;
+}
+
+
+void Solid :: RecEdge (const Point<3> & p, const Vec<3> & v,
+                       int & in, int & strin, int & faces) const
+{
+  switch (op)
+    {
+    case TERM:
+      {
+	INSOLID_TYPE ist = prim->VecInSolid (p, v, 1e-6);
+	in = (ist == IS_INSIDE || ist == DOES_INTERSECT);
+	strin = (ist == IS_INSIDE);
+	/*
+	in = VectorIn (p, v);
+	strin = VectorStrictIn (p, v);
+	*/
+	faces = 0;
+
+	if (in && ! strin)
+	  {
+	    //	    faces = 1;
+	    int i; 
+	    Vec<3> grad;
+	    for (i = 1; i <= prim->GetNSurfaces(); i++)
+	      {
+		double val = prim->GetSurface(i).CalcFunctionValue(p);
+		prim->GetSurface(i).CalcGradient (p, grad);
+		if (fabs (val) < 1e-6 && fabs (v * grad) < 1e-6)
+		  faces++;
+	      }
+	  }
+	    //	else
+	    //	  faces = 0;
+	break;
+      }
+    case SECTION:
+      {
+	int in1, in2, strin1, strin2, faces1, faces2;
+
+	s1 -> RecEdge (p, v, in1, strin1, faces1);
+	s2 -> RecEdge (p, v, in2, strin2, faces2);
+
+	faces = 0;
+	if (in1 && in2)
+	  faces = faces1 + faces2;
+	in = in1 && in2;
+	strin = strin1 && strin2;
+	break;
+      }
+    case UNION:
+      {
+	int in1, in2, strin1, strin2, faces1, faces2;
+
+	s1 -> RecEdge (p, v, in1, strin1, faces1);
+	s2 -> RecEdge (p, v, in2, strin2, faces2);
+
+	faces = 0;
+	if (!strin1 && !strin2)
+	  faces = faces1 + faces2;
+	in = in1 || in2;
+	strin = strin1 || strin2;
+	break;
+      }
+    case SUB:
+      {
+	int in1, strin1;
+	s1 -> RecEdge (p, v, in1, strin1, faces);
+	in = !strin1;
+	strin = !in1;
+	break;
+      }
+    case ROOT:
+      {
+	s1 -> RecEdge (p, v, in, strin, faces);
+	break;
+      }
+    }
+}
+
+
+void Solid :: CalcSurfaceInverse ()
+{
+  CalcSurfaceInverseRec (0);
+}
+
+void Solid :: CalcSurfaceInverseRec (int inv)
+{
+  switch (op)
+    {
+    case TERM:
+      {
+	int priminv;
+	for (int i = 0; i < prim->GetNSurfaces(); i++)
+	  {
+	    priminv = prim->SurfaceInverted(i);
+	    if (inv) priminv = 1 - priminv;
+	    prim->GetSurface(i).SetInverse (priminv);
+	  }
+	break;
+      }
+    case UNION:
+    case SECTION:
+      {
+	s1 -> CalcSurfaceInverseRec (inv);
+	s2 -> CalcSurfaceInverseRec (inv);
+	break;
+      }
+    case SUB:
+      {
+	s1 -> CalcSurfaceInverseRec (1 - inv);
+	break;
+      }
+    case ROOT:
+      {
+	s1 -> CalcSurfaceInverseRec (inv);
+	break;
+      }
+    }
+}
+
+
+Solid * Solid :: GetReducedSolid (const BoxSphere<3> & box) const
+{
+  int in;
+  Solid * res =  RecGetReducedSolid (box, in);
+  return res;
+}
+
+Solid * Solid :: RecGetReducedSolid (const BoxSphere<3> & box, int & in) const
+{
+  Solid * redsol = NULL;
+
+  switch (op)
+    {
+    case TERM:
+      {
+	/* really old
+	in = surf -> BoxInSolid (box);
+	if (in == 2) // maybe
+	  redsol = new Solid (surf, id);
+	*/
+	in = int(prim -> BoxInSolid (box));
+	if (in == 2) // maybe
+	  redsol = new Solid (prim);
+
+	//	prim->GetSurface(1).Print (*testout);
+
+	break;
+      }
+    case SECTION:
+      {
+	int in1, in2;
+	Solid * redsol1, * redsol2;
+
+	redsol1 = s1 -> RecGetReducedSolid (box, in1);
+	redsol2 = s2 -> RecGetReducedSolid (box, in2);
+
+	if (in1 == 0 || in2 == 0)
+	  {
+	    if (in1 == 2) delete redsol1;
+	    if (in2 == 2) delete redsol2;
+	    in = 0;
+	  }
+	else
+	  {
+	    if (in1 == 2 || in2 == 2) in = 2;
+	    else in = 1;
+
+	    if (in1 == 2 && in2 == 2)
+	      redsol = new Solid (SECTION, redsol1, redsol2);
+	    else if (in1 == 2)
+	      redsol = redsol1;
+	    else if (in2 == 2)
+	      redsol = redsol2;
+	  }
+	break;
+      }
+
+    case UNION:
+      {
+	int in1, in2;
+	Solid * redsol1, * redsol2;
+
+	redsol1 = s1 -> RecGetReducedSolid (box, in1);
+	redsol2 = s2 -> RecGetReducedSolid (box, in2);
+
+	if (in1 == 1 || in2 == 1)
+	  {
+	    if (in1 == 2) delete redsol1;
+	    if (in2 == 2) delete redsol2;
+	    in = 1;
+	  }
+	else
+	  {
+	    if (in1 == 2 || in2 == 2) in = 2;
+	    else in = 0;
+
+	    if (in1 == 2 && in2 == 2)
+	      redsol = new Solid (UNION, redsol1, redsol2);
+	    else if (in1 == 2)
+	      redsol = redsol1;
+	    else if (in2 == 2)
+	      redsol = redsol2;
+	  }
+	break;
+      }
+
+    case SUB:
+      {
+	int in1;
+	Solid * redsol1;
+	redsol1 = s1 -> RecGetReducedSolid (box, in1);
+	switch (in1)
+	  {
+	  case 0: in = 1; break;
+	  case 1: in = 0; break;
+	  case 2: in = 2; break;
+	  }
+	if (redsol1)
+	  redsol = new Solid (SUB, redsol1);
+	break;
+      }
+      
+    case ROOT:
+      {
+	int in1;
+	redsol = s1 -> RecGetReducedSolid (box, in1);
+	in = in1;
+	break;
+      }
+    }
+  return redsol;
+}
+
+
+int Solid :: NumPrimitives () const
+{
+  switch (op)
+    {
+    case TERM:
+      {
+	return 1;
+      }
+    case UNION:
+    case SECTION:
+      {
+	return s1->NumPrimitives () + s2 -> NumPrimitives();
+      }
+    case SUB:
+    case ROOT:
+      {
+	return s1->NumPrimitives ();
+      }
+    }
+  return 0;
+}
+
+void Solid :: GetSurfaceIndices (ARRAY<int> & surfind) const
+{
+  surfind.SetSize (0);
+  RecGetSurfaceIndices (surfind);
+}
+
+void Solid :: RecGetSurfaceIndices (ARRAY<int> & surfind) const
+{
+  switch (op)
+    {
+    case TERM:
+      {
+	/*
+	int i;
+	for (i = 1; i <= surfind.Size(); i++)
+	  if (surfind.Get(i) == prim->GetSurfaceId())
+	    return;
+	surfind.Append (prim->GetSurfaceId());
+	break;
+	*/
+	int i, j;
+	for (j = 0; j < prim->GetNSurfaces(); j++)
+	  if (prim->SurfaceActive (j))
+	    {
+	      bool found = 0;
+	      int siprim = prim->GetSurfaceId(j);
+
+	      for (i = 0; i < surfind.Size(); i++)
+		if (surfind[i] == siprim)
+		  {
+		    found = 1;
+		    break;
+		  }
+	      if (!found) surfind.Append (siprim);
+	    }
+	break;
+      }
+    case UNION:
+    case SECTION:
+      {
+	s1 -> RecGetSurfaceIndices (surfind);
+	s2 -> RecGetSurfaceIndices (surfind);
+	break;
+      }
+    case SUB:
+    case ROOT:
+      {
+	s1 -> RecGetSurfaceIndices (surfind);
+	break;
+      }
+    }
+}
+
+
+
+void Solid :: GetSurfaceIndices (IndexSet & iset) const
+{
+  iset.Clear();
+  RecGetSurfaceIndices (iset);
+}
+
+void Solid :: RecGetSurfaceIndices (IndexSet & iset) const
+{
+  switch (op)
+    {
+    case TERM:
+      {
+	/*
+	int i;
+	for (i = 1; i <= surfind.Size(); i++)
+	  if (surfind.Get(i) == prim->GetSurfaceId())
+	    return;
+	surfind.Append (prim->GetSurfaceId());
+	break;
+	*/
+	int i, j;
+	for (j = 0; j < prim->GetNSurfaces(); j++)
+	  if (prim->SurfaceActive (j))
+	    {
+	      int siprim = prim->GetSurfaceId(j);
+	      iset.Add (siprim);
+	    }
+	break;
+      }
+    case UNION:
+    case SECTION:
+      {
+	s1 -> RecGetSurfaceIndices (iset);
+	s2 -> RecGetSurfaceIndices (iset);
+	break;
+      }
+    case SUB:
+    case ROOT:
+      {
+	s1 -> RecGetSurfaceIndices (iset);
+	break;
+      }
+    }
+}
+
+
+
+
+
+
+BlockAllocator Solid :: ball(sizeof (Solid));
+
+
+void * Solid :: operator new(size_t s)
+{
+  return ball.Alloc();
+}
+
+void Solid :: operator delete (void * p)
+{
+  ball.Free (p);
+}
+
+
+
+
+
+
+ReducePrimitiveIterator :: 
+ReducePrimitiveIterator (const BoxSphere<3> & abox)
+  : SolidIterator(), box(abox)
+{
+  ;
+}
+
+ReducePrimitiveIterator :: 
+~ReducePrimitiveIterator ()
+{
+  ;
+}
+
+void 
+ReducePrimitiveIterator :: Do (Solid * sol)
+{
+  if (sol -> GetPrimitive())
+    sol -> GetPrimitive() -> Reduce (box);
+}
+
+
+
+
+UnReducePrimitiveIterator :: 
+UnReducePrimitiveIterator ()
+  : SolidIterator()
+{
+  ;
+}
+
+UnReducePrimitiveIterator :: 
+~UnReducePrimitiveIterator ()
+{
+  ;
+}
+
+void 
+UnReducePrimitiveIterator :: Do (Solid * sol)
+{
+  if (sol -> GetPrimitive())
+    sol -> GetPrimitive() -> UnReduce ();
+}
+}
diff --git a/Netgen/libsrc/csg/solid.hpp b/Netgen/libsrc/csg/solid.hpp
new file mode 100644
index 0000000000..b09d8fd682
--- /dev/null
+++ b/Netgen/libsrc/csg/solid.hpp
@@ -0,0 +1,163 @@
+#ifndef FILE_SOLID
+#define FILE_SOLID
+
+/**************************************************************************/
+/* File:   solid.hh                                                       */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   1. Dez. 95                                                     */
+/**************************************************************************/
+
+/*
+
+  Constructive Solid Model (csg)
+  
+*/
+
+
+
+
+class Solid;
+
+class SolidIterator
+{
+public:
+  SolidIterator ();
+  virtual ~SolidIterator ();
+  virtual void Do (Solid * sol) = 0;
+};
+
+
+
+class Solid
+{
+public:
+  
+  typedef enum optyp1 { TERM, SECTION, UNION, SUB, ROOT, DUMMY } optyp;
+  
+private:
+  char * name;
+  Primitive * prim;
+  Solid * s1, * s2;
+  
+  optyp op;
+  int visited;
+  double maxh;
+
+  static int cntnames;
+
+public:
+  Solid (Primitive * aprim);
+  Solid (optyp aop, Solid * as1, Solid * as2 = NULL);
+  virtual ~Solid ();
+
+  const char * Name () const { return name; }
+  void SetName (const char * aname);
+
+  Solid * Copy (class CSGeometry & geom) const;
+  void Transform (Transformation<3> & trans);
+
+  
+  void IterateSolid (SolidIterator & it, int only_once = 0);
+
+  
+  void Boundaries (const Point<3> & p, ARRAY<int> & bounds) const;
+  int NumPrimitives () const;
+  void GetSurfaceIndices (ARRAY<int> & surfind) const;
+  void GetSurfaceIndices (IndexSet & iset) const;
+
+  Primitive * GetPrimitive ()
+    { return (op == TERM) ? prim : NULL; }
+  const Primitive * GetPrimitive () const
+    { return (op == TERM) ? prim : NULL; }
+
+  // geometric tests
+
+  int IsIn (const Point<3> & p, double eps = 1e-6) const;
+  int IsStrictIn (const Point<3> & p, double eps = 1e-6) const;
+  int VectorIn (const Point<3> & p, const Vec<3> & v, double eps = 1e-6) const;
+  int VectorStrictIn (const Point<3> & p, const Vec<3> & v, double eps = 1e-6) const;
+  
+  int VectorIn2 (const Point<3> & p, const Vec<3> & v1, const Vec<3> & v2,
+		 double eps = 1e-6) const;
+  int VectorIn2Rec (const Point<3> & p, const Vec<3> & v1, const Vec<3> & v2,
+		    double eps = 1e-6) const;
+
+
+  ///
+  void TangentialSolid (const Point<3> & p, Solid *& tansol) const;
+  ///
+  void TangentialSolid2 (const Point<3> & p, const Vec<3> & t,
+			 Solid *& tansol) const;
+  ///
+  int Edge (const Point<3> & p, const Vec<3> & v) const;
+  ///
+  int OnFace (const Point<3> & p, const Vec<3> & v) const;
+  ///
+  virtual void Print (ostream & str) const;
+  ///
+  void CalcSurfaceInverse ();
+  ///
+  Solid * GetReducedSolid (const BoxSphere<3> & box) const;
+  
+
+  void SetMaxH (double amaxh)
+    { maxh = amaxh; }
+  double GetMaxH () const
+    { return maxh; }
+
+  void GetSolidData (ostream & ost, int first = 1) const;
+  static Solid * CreateSolid (istream & ist, const SYMBOLTABLE<Solid*> & solids);
+
+
+  static BlockAllocator ball;
+  void * operator new(size_t);
+  void operator delete (void *);
+
+protected:
+  ///
+
+  void RecBoundaries (const Point<3> & p, ARRAY<int> & bounds, 
+		      int & in, int & strin) const;
+  ///
+  void RecTangentialSolid (const Point<3> & p, Solid *& tansol, 
+			   int & in, int & strin) const;
+  ///
+  void RecTangentialSolid2 (const Point<3> & p, const Vec<3> & vec, 
+			    Solid *& tansol, int & in, int & strin) const;
+  ///
+  void RecEdge (const Point<3> & p, const Vec<3> & v,
+                int & in, int & strin, int & faces) const;
+  ///
+  void CalcSurfaceInverseRec (int inv);
+  ///
+  Solid * RecGetReducedSolid (const BoxSphere<3> & box, int & in) const;
+  ///
+  void RecGetSurfaceIndices (ARRAY<int> & surfind) const;
+  void RecGetSurfaceIndices (IndexSet & iset) const;
+
+  friend class SolidIterator;
+  friend class ClearVisitedIt;
+  friend class RemoveDummyIterator;
+  friend class CSGeometry;
+};
+
+
+class ReducePrimitiveIterator : public SolidIterator
+{
+  const BoxSphere<3> & box;
+public:
+  ReducePrimitiveIterator (const BoxSphere<3> & abox);
+  virtual ~ReducePrimitiveIterator ();
+  virtual void Do (Solid * sol);  
+};
+
+
+class UnReducePrimitiveIterator : public SolidIterator
+{
+public:
+  UnReducePrimitiveIterator ();
+  virtual ~UnReducePrimitiveIterator ();
+  virtual void Do (Solid * sol);  
+};
+
+#endif
diff --git a/Netgen/libsrc/csg/specpoin.cpp b/Netgen/libsrc/csg/specpoin.cpp
new file mode 100644
index 0000000000..12fe79966a
--- /dev/null
+++ b/Netgen/libsrc/csg/specpoin.cpp
@@ -0,0 +1,1369 @@
+#include <mystdlib.h>
+#include <meshing.hpp>
+#include <csg.hpp>
+
+
+/*
+
+   Special Point calculation uses the global Flags:
+
+
+   size .. 500       cube = [-size, size]^3
+   relydegtest       when to rely on degeneration ?
+   calccp            calculate points of intersection ?
+   cpeps1            eps for degenerated poi
+   calcep            calculate points of extreme coordinates ?
+   epeps1            eps for degenerated edge
+   epeps2            eps for axis parallel pec
+   epspointdist      eps for distance of special points 
+*/
+
+
+namespace netgen
+{
+void ProjectToEdge (const Surface * f1, const Surface * f2, Point<3> & hp);
+
+
+
+  /*
+SpecialPoint :: SpecialPoint ()
+  : p(), v(), layer(0)
+{
+  ;
+}
+  */
+
+
+SpecialPoint :: SpecialPoint (const SpecialPoint & sp)
+{
+  p = sp.p;
+  v = sp.v;
+  s1 = sp.s1;
+  s2 = sp.s2;
+  layer = sp.layer;
+  unconditional = sp.unconditional;
+}
+  
+SpecialPoint & SpecialPoint :: operator= (const SpecialPoint & sp)
+{
+  p = sp.p;
+  v = sp.v;
+  s1 = sp.s1;
+  s2 = sp.s2;
+  layer = sp.layer;
+  unconditional = sp.unconditional;
+  return *this;
+}
+
+bool SpecialPoint :: HasSurfaces (int as1, int as2) const
+{
+  return (s1 == as1 && s2 == as2 || s1 == as2 && s2 == as1);
+}
+
+void SpecialPoint :: Print (ostream & str)
+{
+  str << "p = " << p << "   v = " << v 
+      << " s1/s2 = " << s1 << "/" << s2
+      << " layer = " << layer
+      << endl;
+}
+
+
+
+
+SpecialPointCalculation :: SpecialPointCalculation ()
+{
+  ;  
+}
+
+void SpecialPointCalculation :: 
+CalcSpecialPoints (const CSGeometry & ageometry, 
+		   ARRAY<MeshPoint> & apoints)
+{
+  int i;
+
+  geometry = &ageometry;
+  points = &apoints;
+
+  size = geometry->MaxSize();  // globflags.GetNumFlag ("maxsize", 500);
+  (*testout) << "Find Special Points" << endl;
+  (*testout) << "maxsize = " << size << endl;
+
+  cpeps1 = 1e-6; 
+  epeps1 = 1e-3; 
+  epeps2 = 1e-6; 
+
+  epspointdist2 = sqr (size * 1e-8); 
+  relydegtest = size * 1e-4; 
+
+
+  BoxSphere<3> box (Point<3> (-size, -size, -size),
+		    Point<3> ( size,  size,  size));
+  box.CalcDiamCenter();
+  PrintMessage (3, "main-solids: ", geometry->GetNTopLevelObjects());
+
+  for (i = 0; i < geometry->GetNTopLevelObjects(); i++)
+    {
+      (*testout) << "tlo " << i << ":" << endl;
+      const TopLevelObject * tlo = geometry->GetTopLevelObject(i);
+      tlo->GetSolid()->Print (*testout); 
+      (*testout) << endl;
+      CalcSpecialPointsRec (tlo->GetSolid(), tlo->GetLayer(),
+			    box, 1, 1, 1);
+    }
+  
+  PrintDot ('\n');
+
+
+  // add user point:
+  int found = 0;
+  for (i = 0; i < geometry->GetNUserPoints(); i++)
+    AddPoint (geometry->GetUserPoint(i), 1);
+  
+  PrintMessage (3, apoints.Size(), " special points");
+
+  for (i = 0; i < boxesinlevel.Size(); i++)
+    (*testout) << "level " << i << " has " 
+	       << boxesinlevel[i] << " boxes" << endl;
+}
+
+
+
+int debug;
+void SpecialPointCalculation :: 
+CalcSpecialPointsRec (const Solid * sol, int layer,
+		      const BoxSphere<3> & box, 
+		      int level, bool calccp, bool calcep)
+{
+  if (multithread.terminate)
+    return;
+
+  int i;
+  BoxSphere<3> sbox;
+  Solid * redsol;
+
+  int numprim;
+
+  bool decision;
+  bool possiblecrossp, possibleexp;  // possible cross or extremalpoint
+  bool surecrossp, sureexp;          // sure ...
+  
+  static ARRAY<int> locsurf;  // attention: array is static
+
+
+  Point<3> p;
+  int k1, k2, k3;
+  int extremdir;
+  double hd;
+
+  if (!sol) return;
+
+
+  if (level >= 100)
+    {
+      cerr << "Problems in CalcSpecialPoints" << endl;
+      cerr << "Point: " << box.Center() << endl;
+      exit (1);
+    }
+
+  static int cntbox = 0;
+  cntbox++;
+  if (cntbox % 10000 == 0) 
+    PrintDot ();
+
+  if (level <= boxesinlevel.Size())
+    boxesinlevel.Elem(level)++;
+  else
+    boxesinlevel.Append (1);
+
+  /*
+  numprim = sol -> NumPrimitives();
+  sol -> GetSurfaceIndices (locsurf);
+  */
+
+  debug = 0;
+  // box.IsIn (Point<3> (4.9, 1.279, 2.8));
+
+
+  geometry -> GetIndependentSurfaceIndices (sol, box, locsurf);
+  numprim = locsurf.Size();
+  
+  if (debug)
+    {
+      (*testout) << "box = " << box.PMin() << "-" << box.PMax()
+		 << " np = " << numprim << " : ";
+      for (i = 1; i <= locsurf.Size(); i++)
+	(*testout) << " " << locsurf.Get(i);
+      (*testout) << " diam = " << box.Diam();
+      (*testout) << " numprim = " << numprim;
+      (*testout) << endl;
+    }
+
+  p = box.Center();
+  
+  /*
+  (*testout) << "box = " << box.PMin() << " - " << box.PMax()
+	     << ", lev = " << level 
+	     << ", nprim = " << sol->NumPrimitives() 
+	     << ", lsurf = " << locsurf.Size() << endl;
+
+  for (i = 1; i <= locsurf.Size(); i++)
+    geometry->GetSurface (locsurf.Get(i)) -> Print (*testout);
+  sol -> Print (*testout);
+  */
+
+  /*
+    for (i = 1; i <= locsurf.Size(); i++)
+    (*testout) << locsurf.Get(i) << " ";
+    (*testout) << "C = " << box.Center() << " diam = " << box.Diam() << endl;
+    */
+
+  possiblecrossp = (numprim >= 3) && calccp;
+  surecrossp = 0;
+
+  if (possiblecrossp && (locsurf.Size() <= 10))
+    {
+      decision = 1;
+      surecrossp = 0;
+
+      for (k1 = 1; k1 <= locsurf.Size() - 2; k1++)
+	for (k2 = k1 + 1; k2 <= locsurf.Size() - 1; k2++)
+	  for (k3 = k2 + 1; k3 <= locsurf.Size(); k3++)
+	    {
+	      int nc, deg;
+	      nc = CrossPointNewtonConvergence 
+		(geometry->GetSurface(locsurf.Get(k1)), 
+		 geometry->GetSurface(locsurf.Get(k2)), 
+		 geometry->GetSurface(locsurf.Get(k3)), p );
+	      
+	      deg = CrossPointDegenerated 
+		(geometry->GetSurface(locsurf.Get(k1)), 
+		 geometry->GetSurface(locsurf.Get(k2)), 
+		 geometry->GetSurface(locsurf.Get(k3)), box );
+	      
+	      if (!nc && !deg) decision = 0;
+	      if (nc) surecrossp = 1;
+	    }
+
+      if (decision && surecrossp)
+	{
+	  for (k1 = 1; k1 <= locsurf.Size() - 2; k1++)
+	    for (k2 = k1 + 1; k2 <= locsurf.Size() - 1; k2++)
+	      for (k3 = k2 + 1; k3 <= locsurf.Size(); k3++)
+		{
+		  if (CrossPointNewtonConvergence 
+		      (geometry->GetSurface(locsurf.Get(k1)), 
+		       geometry->GetSurface(locsurf.Get(k2)), 
+		       geometry->GetSurface(locsurf.Get(k3)), p ) )
+		    {
+		      Point<3> pp = p;
+		      CrossPointNewton 
+			(geometry->GetSurface(locsurf.Get(k1)), 
+			 geometry->GetSurface(locsurf.Get(k2)), 
+			 geometry->GetSurface(locsurf.Get(k3)), pp);
+              
+		      BoxSphere<3> hbox (pp, pp);
+		      hbox.Increase (1e-8);
+
+		      if (pp(0) > box.PMin()(0) - 1e-5 && 
+			  pp(0) < box.PMax()(0) + 1e-5 &&
+			  pp(1) > box.PMin()(1) - 1e-5 && 
+			  pp(1) < box.PMax()(1) + 1e-5 &&
+			  pp(2) > box.PMin()(2) - 1e-5 && 
+			  pp(2) < box.PMax()(2) + 1e-5 &&
+			  sol -> IsIn (pp) && !sol->IsStrictIn (pp) &&
+			  !CrossPointDegenerated
+			  (geometry->GetSurface(locsurf.Get(k1)), 
+			   geometry->GetSurface(locsurf.Get(k2)), 
+			   geometry->GetSurface(locsurf.Get(k3)), hbox ))
+
+			{ 
+			  //                AddCrossPoint (locsurf, sol, p);
+			  BoxSphere<3> boxp (pp, pp);
+			  boxp.Increase (1e-3);
+			  boxp.CalcDiamCenter();
+			  ARRAY<int> locsurf2;
+
+			  geometry -> GetIndependentSurfaceIndices (sol, boxp, locsurf2);
+			  
+			  /*
+			  ReducePrimitiveIterator rpi(boxp);
+			  UnReducePrimitiveIterator urpi;
+			  
+			  ((Solid*)sol) -> IterateSolid (rpi);
+			  sol -> GetIndependentSurfaceIndices (locsurf2);
+			  ((Solid*)sol) -> IterateSolid (urpi);
+			  */
+			  bool found1 = 0, found2 = 0, found3 = 0;
+			  for (i = 1; i <= locsurf2.Size(); i++)
+			    {
+			      if (locsurf2.Get(i) == locsurf.Get(k1))
+				found1 = 1;
+			      if (locsurf2.Get(i) == locsurf.Get(k2))
+				found2 = 1;
+			      if (locsurf2.Get(i) == locsurf.Get(k3))
+				found3 = 1;
+			    }
+			  
+			  if (found1 && found2 && found3)
+			    if (AddPoint (pp, layer))
+			      {
+				(*testout) << "Crosspoint found: " << pp 
+					   << " diam = " << box.Diam() << endl;
+				(*testout) << "surfs: " 
+					   << locsurf.Get(k1) << "," 
+					   << locsurf.Get(k2) << "," 
+					   << locsurf.Get(k3) << endl;
+			      }
+			}
+		    }
+		}
+	}
+      
+      if (decision)
+	possiblecrossp = 0;
+    }
+
+
+
+
+  possibleexp = (numprim >= 2) && calcep;
+    
+  if (possibleexp && (locsurf.Size() <= 10))
+    {
+      decision = 1;
+      sureexp = 0;
+
+      for (k1 = 1; k1 <= locsurf.Size() - 1; k1++)
+	for (k2 = k1+1; k2 <= locsurf.Size(); k2++)
+	  {
+	    bool nc, deg;
+	    
+	    nc = EdgeNewtonConvergence 
+	      (geometry->GetSurface(locsurf.Get(k1)),
+	       geometry->GetSurface(locsurf.Get(k2)),
+	       p);
+	    
+	    deg = EdgeDegenerated 
+	      (geometry->GetSurface(locsurf.Get(k1)),
+	       geometry->GetSurface(locsurf.Get(k2)),
+	       box);
+	    
+	    if (!nc && !deg) decision = 0;
+	    if (nc) sureexp = 1;
+
+	    if (debug)
+	      {
+		(*testout) << "p = " << p << " s1,2 = " << locsurf.Get(k1) << ", " << locsurf.Get(k2) 
+			   << " nc = " << nc << " deg = " << deg << endl;
+	      }
+	  }
+
+      if (decision && sureexp)
+	{
+	  for (k1 = 1; k1 <= locsurf.Size() - 1; k1++)
+	    for (k2 = k1+1; k2 <= locsurf.Size(); k2++)
+	      {
+		if (
+		    EdgeNewtonConvergence 
+		    (geometry->GetSurface(locsurf.Get(k1)),
+		     geometry->GetSurface(locsurf.Get(k2)),
+		     p) )
+		  {
+		    EdgeNewton 
+		      (geometry->GetSurface(locsurf.Get(k1)),
+		       geometry->GetSurface(locsurf.Get(k2)),
+		       p);
+		    
+		    Point<3> pp;
+		    if (IsEdgeExtremalPoint 
+		      (geometry->GetSurface(locsurf.Get(k1)),
+		       geometry->GetSurface(locsurf.Get(k2)),
+		       p, pp, box.Diam()/2))
+			{
+			  (*testout) << "extremalpoint (nearly) found:" 
+				     << pp
+				     << endl;
+			  if (Dist (pp, box.Center()) < box.Diam()/2 &&
+			      sol -> IsIn (pp) && !sol->IsStrictIn (pp) )
+			    {
+			      //                AddExtremalPoint (locsurf.Get(k1), locsurf.Get(k2), p);
+			      if (AddPoint (pp, layer))
+				(*testout) << "Extremal point found: " << pp << endl;
+			    }  
+			}            
+		  }
+	      }
+	}
+      if (decision)
+	possibleexp = 0;
+    }
+ 
+
+
+  if (possiblecrossp || possibleexp)
+    {
+      for (i = 0; i < 8; i++)
+	{
+	  box.GetSubBox (i, sbox);
+	  sbox.Increase (1e-4 * sbox.Diam());
+
+	  redsol = sol -> GetReducedSolid (sbox);
+
+	  if (redsol)
+	    {
+	      CalcSpecialPointsRec (redsol, layer, sbox, level+1, calccp, calcep);
+	      delete redsol;
+	    }
+	}
+    }
+}
+
+
+
+
+
+/******* Tests for Point of intersection **********************/
+
+
+
+bool SpecialPointCalculation :: 
+CrossPointNewtonConvergence (const Surface * f1, 
+			     const Surface * f2, 
+			     const Surface * f3,
+			     const Point<3> & p)
+{
+  int i;
+  Vec<3> grad;
+  Vec<3> rs, x;
+  Mat<3> jacobi, inv;
+  double alpha, beta, gamma, eta;
+  double sum;
+  int j;
+
+
+  rs(0) = f1->CalcFunctionValue (p);
+  rs(1) = f2->CalcFunctionValue (p);
+  rs(2) = f3->CalcFunctionValue (p);
+
+  f1->CalcGradient (p, grad);
+  jacobi(0,0) = grad(0);
+  jacobi(0,1) = grad(1);
+  jacobi(0,2) = grad(2);
+
+  f2->CalcGradient (p, grad);
+  jacobi(1,0) = grad(0);
+  jacobi(1,1) = grad(1);
+  jacobi(1,2) = grad(2);
+
+  f3->CalcGradient (p, grad);
+  jacobi(2,0) = grad(0);
+  jacobi(2,1) = grad(1);
+  jacobi(2,2) = grad(2);
+
+  alpha = 1;
+  if (fabs (Det (jacobi)) > 1e-8)
+    {
+      CalcInverse (jacobi, inv);
+      x = inv * rs;
+
+      gamma = f1 -> HesseNorm() + f2 -> HesseNorm() + f3 -> HesseNorm();
+      beta = 0;
+      for (i = 0; i < 3; i++)
+	{
+	  sum = 0;
+	  for (j = 0; j < 3; j++)
+	    sum += fabs (inv(i,j));
+	  beta = max2 (beta, sum);
+	}
+      eta = Abs (x);
+
+      alpha = beta * gamma * eta;
+    }
+
+  return (alpha < 0.1);
+}
+
+
+
+
+bool SpecialPointCalculation :: 
+CrossPointDegenerated (const Surface * f1,
+		       const Surface * f2, 
+		       const Surface * f3, 
+		       const BoxSphere<3> & box) const
+{
+  Mat<3> mat;
+  Vec<3> grad, g1, g2, g3;
+  double normprod;
+
+  if (box.Diam() > relydegtest) return 0;
+
+  f1->CalcGradient (box.Center(), g1);
+  normprod = Abs (g1);
+
+  f2->CalcGradient (box.Center(), g2);
+  normprod *= Abs (g2);
+ 
+  f3->CalcGradient (box.Center(), g3);
+  normprod *= Abs (g3);
+
+  for (int i = 0; i < 3; i++)
+    {
+      mat(i,0) = g1(i);
+      mat(i,1) = g2(i);
+      mat(i,2) = g3(i);
+    }
+
+  if (fabs (Det (mat)) < cpeps1 * normprod)
+    return 1;
+  else 
+    return 0;
+}
+ 
+
+
+
+
+void SpecialPointCalculation :: CrossPointNewton (const Surface * f1, 
+						  const Surface * f2, 
+						  const Surface * f3, Point<3> & p)
+{
+  int i;
+  Vec<3> g1, g2, g3;
+  Vec<3> rs, sol;
+  Mat<3> mat;
+
+  i = 10;
+  while (i > 0)
+    {
+      i--;
+      rs(0) = f1->CalcFunctionValue (p);
+      rs(1) = f2->CalcFunctionValue (p);
+      rs(2) = f3->CalcFunctionValue (p);
+
+      f1->CalcGradient (p, g1);
+      f2->CalcGradient (p, g2);
+      f3->CalcGradient (p, g3);
+
+      for (int j = 0; j < 3; j++)
+	{
+	  mat(0, j) = g1(j);
+	  mat(1, j) = g2(j);
+	  mat(2, j) = g3(j);
+	}
+      mat.Solve (rs, sol);
+	  /*
+      Transpose (g1, g2, g3);
+      SolveLinearSystem (g1, g2, g3, rs, sol);
+	  */
+      if (sol.Length() < 1e-12 && i > 1) i = 1;
+
+      p -= sol;
+    }
+}
+
+
+
+
+/******* Tests for Point on edges **********************/
+
+
+
+
+bool SpecialPointCalculation :: 
+EdgeNewtonConvergence (const Surface * f1, const Surface * f2, 
+		       const Point<3> & p)
+{
+  int i;
+  Vec<3> g1, g2, sol;
+  Vec<2> vrs;
+  double alpha, beta, gamma, eta;
+  double sum;
+  Mat<2,3> mat;
+  Mat<3,2> inv;
+  int j;
+
+  vrs(0) = f1->CalcFunctionValue (p);
+  vrs(1) = f2->CalcFunctionValue (p);
+
+  f1->CalcGradient (p, g1);
+  f2->CalcGradient (p, g2);
+
+  for (i = 0; i < 3; i++)
+    {
+      mat(0,i) = g1(i);
+      mat(1,i) = g2(i);
+    }
+
+  alpha = 1;
+
+  if ( fabs(g1 * g2) < (1 - 1e-8) * Abs (g1) * Abs (g2))
+    {
+      CalcInverse (mat, inv);
+      sol = inv * vrs;
+
+      // SolveLinearSystemLS (g1, g2, vrs, sol);
+
+      gamma = f1 -> HesseNorm() + f2 -> HesseNorm();
+
+      /*
+      Vec<3> inv1, inv2;
+      PseudoInverse (g1, g2, inv1, inv2);
+      */
+      
+      beta = 0;
+      for (i = 0; i < 3; i++)
+	for (j = 0; j < 2; j++)
+	  beta += inv(i,j) * inv(i,j);
+      beta = sqrt (beta);
+
+      //      beta = inv1.Length() + inv2.Length();
+      eta = Abs (sol);
+      alpha = beta * gamma * eta;
+    }
+  return (alpha < 0.1);
+}
+
+
+
+
+bool SpecialPointCalculation :: 
+EdgeDegenerated (const Surface * f1,
+		 const Surface * f2, 
+		 const BoxSphere<3> & box) const
+{
+  // perform newton steps. normals parallel ?
+  // if not decideable: return 0 
+  
+  
+  Point<3> p = box.Center();
+  int i;
+  Vec<3> grad, g1, g2, sol;
+  Vec<2> vrs;
+  Mat<2,3> mat;
+
+  i = 20;
+  while (i > 0)
+    {
+      if (Dist (p, box.Center()) > box.Diam())
+	return 0;
+
+      i--;
+      vrs(0) = f1->CalcFunctionValue (p);
+      vrs(1) = f2->CalcFunctionValue (p);
+
+      f1->CalcGradient (p, g1);
+      f2->CalcGradient (p, g2);
+
+      if ( fabs (g1 * g2) > (1 - 1e-10) * Abs (g1) * Abs (g2))
+	return 1;
+
+      for (int j = 0; j < 3; j++)
+	{
+	  mat(0,j) = g1(j);
+	  mat(1,j) = g2(j);
+	}
+      mat.Solve (vrs, sol);
+      //      SolveLinearSystemLS (g1, g2, vrs, sol);
+
+      if (Abs (sol) < 1e-12 && i > 1) i = 1;
+      p -= sol;
+    }
+
+  return 0;
+  /*
+  return 0;
+
+  static DenseMatrix jacobi(3);
+  Vec<3> grad, g1, g2, g3;
+  double normprod;
+  
+  if (box.Diam() > relydegtest) return 0;
+  
+  f1->CalcGradient (box.Center(), g1);
+  normprod = g1.Length();
+  
+  f2->CalcGradient (box.Center(), g2);
+  normprod *= g2.Length();
+  
+  if (fabs (g1 * g2) < 1e-8 * normprod)
+    return 1;
+  else 
+    return 0;
+  */
+}
+
+
+
+
+
+
+void SpecialPointCalculation :: EdgeNewton (const Surface * f1, 
+					    const Surface * f2, Point<3> & p)
+{
+  int i;
+  Vec<3> grad, g1, g2, sol;
+  Vec<2> vrs;
+  Mat<2,3> mat;
+
+  i = 10;
+  while (i > 0)
+    {
+      i--;
+      vrs(0) = f1->CalcFunctionValue (p);
+      vrs(1) = f2->CalcFunctionValue (p);
+
+      f1->CalcGradient (p, g1);
+      f2->CalcGradient (p, g2);
+
+      for (int j = 0; j < 3; j++)
+	{
+	  mat(0,j) = g1(j);
+	  mat(1,j) = g2(j);
+	}
+      mat.Solve (vrs, sol);
+      //      SolveLinearSystemLS (g1, g2, vrs, sol);
+
+      if (Abs (sol) < 1e-12 && i > 1) i = 1;
+      p -= sol;
+    }
+}
+
+
+
+bool SpecialPointCalculation :: 
+IsEdgeExtremalPoint (const Surface * f1, const Surface * f2, 
+		     const Point<3> & p, Point<3> & pp, double rad)
+{
+  Vec<3> g1, g2, t, t1, t2;
+  int j;
+
+  f1->CalcGradient (p, g1);
+  f2->CalcGradient (p, g2);
+  
+  t = Cross (g1, g2);
+  t.Normalize();
+
+  Point<3> p1 = p + rad * t;
+  Point<3> p2 = p - rad * t;
+
+  EdgeNewton (f1, f2, p1);
+  EdgeNewton (f1, f2, p2);
+
+  
+  f1->CalcGradient (p1, g1);
+  f2->CalcGradient (p1, g2);
+  t1 = Cross (g1, g2);
+  t1.Normalize();
+
+  f1->CalcGradient (p2, g1);
+  f2->CalcGradient (p2, g2);
+  t2 = Cross (g1, g2);
+  t2.Normalize();
+
+  double val = 1e-8 * rad * rad;
+  for (j = 0; j < 3; j++)
+    if ( (t1(j) * t2(j) < -val) )
+      {
+	pp = p;
+	ExtremalPointNewton (f1, f2, j+1, pp);
+	return 1;
+      }
+
+  return 0;
+}
+
+
+
+
+
+
+
+
+
+/********** Tests of Points of extremal coordinates  ****************/
+
+
+void SpecialPointCalculation :: ExtremalPointNewton (const Surface * f1, 
+						     const Surface * f2, 
+						     int dir, Point<3> & p)
+{
+  int i;
+
+  Vec<3> g1, g2, v, curv;
+  Vec<3> rs, x, y1, y2, y;
+  Mat<3> h1, h2;
+  Mat<3> jacobi;
+
+
+  if (dir < 1 || dir > 3)
+    {
+      cerr << "Error: Illegal extremdir" << endl;
+      return;
+    }
+
+  i = 50;
+  while (i > 0)
+    {
+      i--;
+      rs(0) = f1->CalcFunctionValue (p);
+      rs(1) = f2->CalcFunctionValue (p);
+
+      f1 -> CalcGradient (p, g1);
+      f2 -> CalcGradient (p, g2);
+
+      f1 -> CalcHesse (p, h1);
+      f2 -> CalcHesse (p, h2);
+
+
+      v = Cross (g1, g2);
+
+      rs(2) = v(dir-1);
+
+      jacobi(0,0) = g1(0);
+      jacobi(0,1) = g1(1);
+      jacobi(0,2) = g1(2);
+
+      jacobi(1,0) = g2(0);
+      jacobi(1,1) = g2(1);
+      jacobi(1,2) = g2(2);
+
+
+      switch (dir)
+	{
+	case 1:
+	  {
+	    y1(0) = 0;
+	    y1(1) = g2(2);
+	    y1(2) = -g2(1);
+	    y2(0) = 0;
+	    y2(1) = -g1(2);
+	    y2(2) = g1(1);
+	    break;
+	  }
+	case 2:
+	  {
+	    y1(0) = -g2(2);
+	    y1(1) = 0;
+	    y1(2) = g2(0);
+	    y2(0) = g1(2);
+	    y2(1) = 0;
+	    y2(2) = -g1(0);
+	    break;
+	  }
+	case 3:
+	  {
+	    y1(0) = g2(1);
+	    y1(1) = -g2(0);
+	    y1(2) = 0;
+	    y2(0) = -g1(1);
+	    y2(1) = g1(0);
+	    y2(2) = 0;
+	    break;
+	  }
+	}
+
+      y = h1 * y1 + h2 * y2;
+
+      jacobi(2,0) = y(0);
+      jacobi(2,1) = y(1);
+      jacobi(2,2) = y(2);
+
+      jacobi.Solve (rs, x);
+      /*
+      CalcInverse (jacobi, inv);
+      inv.Mult (rs, x);
+      */
+      //    (*testout) << "err = " << x.L2Norm() << endl;
+
+      if (Abs (x) < 1e-12 && i > 1)
+	{
+	  //      (*testout) << "convergent in " << (10 - i) << " steps " << endl;
+
+	  i = 1;
+	}
+      
+      p -= x;
+    }
+
+  if (Abs (x) > 1e-10)
+    {
+      (*testout) << "Error: extremum Newton not convergent" << endl;
+      (*testout) << "dir = " << dir << endl;
+      (*testout) << "p = " << p << endl;
+      (*testout) << "x = " << x << endl;
+    }
+}
+
+
+
+
+bool SpecialPointCalculation :: ExtremalPointPossible (const Surface * f1, 
+						       const Surface * f2, 
+						       int dir, 
+						       const BoxSphere<3> & box)
+{
+  double hn1, hn2, gn1, gn2;
+  Point<3> p;
+  Vec<3> g1, g2, v;
+  double f3;
+  double r = box.Diam()/2;
+
+  p = box.Center();
+
+  f1 -> CalcGradient (p, g1);
+  f2 -> CalcGradient (p, g2);
+
+  gn1 = g1.Length();
+  gn2 = g2.Length();
+
+  hn1 = f1 -> HesseNorm ();
+  hn2 = f2 -> HesseNorm ();
+
+  v = Cross (g1, g2);
+  f3 = fabs (v(dir-1));
+
+  //  (*testout) << "f3 = " << f3 << "  r = " << r 
+  //             << "normbound = " 
+  //             << (hn1 * (gn2 + r * hn2) + hn2 * (gn1 + r * hn1)) << endl;
+ 
+  return (f3 <= 3 * r * (hn1 * (gn2 + r * hn2) + hn2 * (gn1 + r * hn1)));
+}
+
+
+
+bool SpecialPointCalculation :: 
+ExtremalPointNewtonConvergence (const Surface * f1, const Surface * f2, 
+				int dir, 
+				const BoxSphere<3> & box)
+{
+  return box.Diam() < 1e-8;
+}
+
+
+bool SpecialPointCalculation :: 
+ExtremalPointDegenerated (const Surface * f1, const Surface * f2, 
+			  int dir, const BoxSphere<3> & box)
+{
+  double gn1, gn2;
+  Point<3> p;
+  Vec<3> g1, g2, v;
+  double maxderiv;
+  double minv;
+  Vec<3> curv, t;
+  Vec<2> rs, x;
+  Mat<3> h1, h2;
+  Mat<2> a, inv;
+  double leftside;
+
+  if (box.Diam() > relydegtest) return 0;
+
+  p = box.Center();
+
+  f1 -> CalcGradient (p, g1);
+  f2 -> CalcGradient (p, g2);
+  gn1 = g1.Length();
+  gn2 = g2.Length();
+
+  v = Cross (g1, g2);
+  if (Abs (v) < epeps1 * gn1 * gn2) return 1;       // irregular edge
+
+  f1 -> CalcHesse (p, h1);
+  f2 -> CalcHesse (p, h2);
+
+  //  hn1 = f1 -> HesseNorm ();
+  //  hn2 = f2 -> HesseNorm ();
+
+  t = v;
+  a(0, 0) = g1 * g1;
+  a(0, 1) = 
+    a(1, 0) = g1 * g2;
+  a(1, 1) = g2 * g2;
+  
+  rs(0) = g1(dir-1);
+  rs(1) = g2(dir-1);
+
+  a.Solve (rs, x);
+
+  /*
+  CalcInverse (a, inv);
+  inv.Mult (rs, x);          // x .. Lagrangeparameter
+  */
+  //  (*testout) << "g1 = " << g1 << " g2 = " << g2 << endl;
+  //  (*testout) << "lam = " << x << endl;
+  //  (*testout) << "h2 = " << h2 << endl;
+
+  leftside = fabs (x(0) * ( t * (h1 * t)) + 
+                   x(1) * ( t * (h2 * t)));
+
+  //  (*testout) << "leftside = " << leftside << endl;
+
+  if (leftside < epeps2 * Abs2 (v)) return 1;  
+
+  return 0;
+}
+
+ 
+
+bool SpecialPointCalculation :: AddPoint (const Point<3> & p, int layer)
+{
+  for (int i = 0; i < points->Size(); i++)
+    if (Dist2 ( (*points)[i], p) < epspointdist2 &&
+	(*points)[i].GetLayer() == layer)
+      return 0;
+
+  points->Append (MeshPoint(p, layer));
+  return 1;
+}
+
+
+
+
+
+
+
+/*
+void SpecialPointCalculation :: 
+AnalyzeSpecialPoints (const CSGeometry & ageometry,
+		      ARRAY<Point<3> > & apoints, 
+		      ARRAY<SpecialPoint> & specpoints)
+{
+  int si, i, j, k, l, m, spi;
+  Solid * locsol;
+  ARRAY<int> surfind;
+  ARRAY<Vec<3>> normalvecs;
+  const Solid * sol;
+  Vec<3> t;
+  Point<3> p;
+
+  ARRAY<int> specpoint2point;
+  specpoints.SetSize (0);
+ 
+  (*testout) << "AnalyzeSpecialPoints" << endl;
+
+  for (si = 1; si <= ageometry.GetNTopLevelObjects(); si++)
+    {
+      (*testout) << "main solid " << si << endl;
+
+      sol = ageometry.GetTopLevelObject(si)->GetSolid();
+      for (i = 1; i <= apoints.Size(); i++)
+	{
+	  p = apoints.Get(i);
+
+	  sol -> TangentialSolid (p, locsol);
+	  if (!locsol) continue;
+	  
+	  (*testout) << "Point " << apoints.Get(i) << endl;
+
+	  locsol -> GetSurfaceIndices (surfind);
+	  for (j = surfind.Size(); j >= 1; j--)
+	    if (fabs (ageometry.GetSurface(surfind.Get(j))->
+		      CalcFunctionValue (p)) > 1e-6)
+	      surfind.DeleteElement (j);
+
+
+
+	  (*testout) << "Surfaces: ";
+	  for (j = 1; j <= surfind.Size(); j++)
+	    (*testout) << surfind.Get(j) << " ";
+	  (*testout) << endl;
+
+	  normalvecs.SetSize(surfind.Size());
+	  for (j = 1; j <= surfind.Size(); j++)
+	    ageometry.GetSurface(surfind.Get(j)) -> 
+	      GetNormalVector(apoints.Get(i), normalvecs.Elem(j));
+
+	  for (j = 1; j <= normalvecs.Size() - 1; j ++)
+	    for (k = j+1; k <= normalvecs.Size(); k++)
+	      for (l = 1; l <= 2; l++)
+		{
+		  t = Cross (normalvecs.Get(j), normalvecs.Get(k));
+		  if (t.Length2() < 1e-8)
+		    {
+		      cerr << "AnalyzePoint: Surfaces degenerated" << endl;
+		      break;
+		    }
+		  t /= t.Length();
+		  if (l == 2) t *= -1;
+
+		  if (locsol -> Edge (apoints.Get(i), t))
+		    {
+		      spi = 0;
+		      for (m = 1; m <= specpoints.Size(); m++)
+			if (Dist2 (specpoints.Get(m).p, apoints.Get(i)) < 1e-8
+			    && (specpoints.Get(m).v - t).Length2() < 1e-8)
+			  {
+			    spi = m;
+			    break;
+			  }
+		      if (!spi)
+			{
+			  spi = specpoints.Append (SpecialPoint());
+			  specpoint2point.Append (i);
+			  specpoints.Last().unconditional = 0;
+			}
+		      specpoints.Elem(spi).p = apoints.Get(i);
+		      specpoints.Elem(spi).v = t;
+		      if (surfind.Size() >= 3)
+			specpoints.Elem(spi).unconditional = 1;
+		      specpoints.Elem(spi).s1 = surfind.Get(j);
+		      specpoints.Elem(spi).s2 = surfind.Get(k);
+		      (*testout) << "spi = " << spi 
+				 << " uncond = " << specpoints.Get(spi).unconditional
+				 << " t = " << t << endl;
+		    }
+          
+		}
+	  delete locsol;
+	}
+    }
+
+  // if special point is unconditional on some solid,
+  // it must be unconditional everywhere:
+
+  BitArray uncond (apoints.Size());
+  uncond.Clear();
+
+  for (i = 1; i <= specpoints.Size(); i++)
+    if (specpoints.Get(i).unconditional)
+      uncond.Set (specpoint2point.Get(i));
+
+  for (i = 1; i <= specpoints.Size(); i++)
+    specpoints.Elem(i).unconditional = 
+      uncond.Test (specpoint2point.Get(i)) ? 1 : 0;
+}
+*/
+
+
+
+void SpecialPointCalculation :: 
+AnalyzeSpecialPoints (const CSGeometry & ageometry,
+		      ARRAY<MeshPoint> & apoints, 
+		      ARRAY<SpecialPoint> & specpoints)
+{
+  int si, i, j, k, l, m, spi;
+
+  Solid * locsol;
+  ARRAY<int> surfind;
+  ARRAY<int> surfind2;
+
+  ARRAY<Vec<3> > normalvecs;
+  const Solid * sol;
+  const Surface * surf;
+
+  Vec<3> t, nsurf;
+  Point<3> p;
+
+  ARRAY<int> specpoint2point;
+  specpoints.SetSize (0);
+
+  geometry = &ageometry;
+ 
+  (*testout) << "AnalyzeSpecialPoints\n";
+
+  for (si = 0; si < ageometry.GetNTopLevelObjects(); si++)
+    {
+      (*testout) << "main solid " << si << "\n";
+
+      sol = ageometry.GetTopLevelObject(si)->GetSolid();
+      surf = ageometry.GetTopLevelObject(si)->GetSurface();
+
+      for (i = 0; i < apoints.Size(); i++)
+	{
+	  p = apoints[i];
+	  if (ageometry.GetTopLevelObject(si)->GetLayer() !=
+	      apoints[i].GetLayer())
+	    continue;
+
+	  // (*testout) << "Point " << apoints[i] << "\n";
+
+	  sol -> TangentialSolid (p, locsol);
+	  if (!locsol) continue;
+	  
+	  // get all surface indices, 
+	  if (surf)
+	    {
+	      locsol -> GetSurfaceIndices (surfind);
+	      bool hassurf = 0;
+	      for (m = 0; m < surfind.Size(); m++)
+		if (ageometry.GetSurface(surfind[m]) == surf)
+		  hassurf = 1;
+
+	      if (!hassurf)
+		continue;
+
+	      surf->GetNormalVector (p, nsurf);
+	    }
+
+	  // get independent surfaces of tangential solid
+
+	  BoxSphere<3> box(p,p);
+	  box.Increase (1e-6);
+	  box.CalcDiamCenter();
+	  ageometry.GetIndependentSurfaceIndices (locsol, box, surfind);
+
+
+	  /*
+	  locsol -> GetSurfaceIndices (surfind);
+	  for (j = surfind.Size(); j >= 1; j--)
+	    if (fabs (ageometry.GetSurface(surfind.Get(j))->
+		      CalcFunctionValue (p)) > 1e-6)
+	      surfind.DeleteElement (j);
+	  */
+
+	  /*
+	  (*testout) << "Surfaces: ";
+	  for (j = 0; j < surfind.Size(); j++)
+	    (*testout) << surfind[j] << " ";
+	  (*testout) << "\n";
+	  */
+
+
+	  normalvecs.SetSize(surfind.Size());
+	  for (j = 0; j < surfind.Size(); j++)
+	    ageometry.GetSurface(surfind[j]) ->
+	      GetNormalVector(apoints[i], normalvecs[j]);
+
+	  for (j = 0; j < normalvecs.Size(); j++)
+	    for (k = j+1; k < normalvecs.Size(); k++)
+	      for (l = 1; l <= 2; l++)
+		{
+		  t = Cross (normalvecs[j], normalvecs[k]);
+		  if (Abs2 (t) < 1e-8)
+		    {
+		      cerr << "AnalyzePoint: Surfaces degenerated" << "\n";
+		      break;
+		    }
+		  t.Normalize();
+		  if (l == 2) t *= -1;
+
+		  // try tangential direction t
+
+		  // (*testout) << "check tangential " << t << "\n";
+
+		  if (surf && fabs (nsurf * t) > 1e-6)
+		    continue;
+
+		  if (!surf)
+		    {
+		      ageometry.GetIndependentSurfaceIndices 
+			(locsol, p, t, surfind2);
+		  
+		      bool found1 = 0, found2 = 0;
+		      for (int ii = 0; ii < surfind2.Size(); ii++)
+			{
+			  if (surfind2[ii] == surfind[j])
+			    found1 = 1;
+			  if (surfind2[ii] == surfind[k])
+			    found2 = 1;
+			}
+		      if (!found1 || !found2)
+			continue;
+		    }
+
+
+		  bool isedge;
+
+		  // isedge = locsol -> Edge (apoints.Get(i), t);
+		  
+		  // edge must be on tangential surface
+		  isedge = 
+		    locsol->VectorIn (p, t) &&
+		    !locsol->VectorStrictIn (p, t);
+		  
+		  // (*testout) << "isedge,1 = " << isedge << "\n";
+
+		  // there must exist at least two different faces on edge
+		  if (isedge)
+		    {
+		      int cnts = 0;
+		      for (m = 0; m < surfind.Size(); m++)
+			{
+			  if (fabs (normalvecs[m] * t) > 1e-6)
+			    continue;
+
+			  Vec<3> s = Cross (normalvecs[m], t);
+			  Vec<3> t2a = t + 0.01 *s;
+			  Vec<3> t2b = t - 0.01 *s;
+
+			  /*
+			  (*testout) << "nv = " << normalvecs[m] << ", s = " << s << "\n";
+			  (*testout) << "t2a = " << t2a << ", t2b = " << t2b << "\n";
+			  (*testout) << "via = "
+				     << locsol->VectorIn (p, t2a) << "/"
+				     << locsol->VectorStrictIn (p, t2a);
+			  (*testout) << "vib = "
+				     << locsol->VectorIn (p, t2b) << "/"
+				     << locsol->VectorStrictIn (p, t2b) << "\n";
+			  */
+
+			  bool isface =
+			    (locsol->VectorIn (p, t2a) &&
+			     !locsol->VectorStrictIn (p, t2a))
+			    ||
+			    (locsol->VectorIn (p, t2b) &&
+			     !locsol->VectorStrictIn (p, t2b));
+			  
+			  if (isface)
+			    {
+			      cnts++;
+			    }
+			}
+		      if (cnts < 2) isedge = 0;
+		    }
+
+		  if (isedge)
+		    {
+		      spi = -1;
+		      for (m = 0; m < specpoints.Size(); m++)
+			if (Dist2 (specpoints[m].p, apoints[i]) < 1e-8
+			    && Abs2(specpoints[m].v - t) < 1e-8)
+			  {
+			    spi = m;
+			    break;
+			  }
+		      if (spi == -1)
+			{
+			  spi = specpoints.Append (SpecialPoint()) - 1;
+			  specpoint2point.Append (i);
+			  specpoints.Last().unconditional = 0;
+			}
+		      specpoints[spi].p = apoints[i];
+		      specpoints[spi].v = t;
+		      if (surfind.Size() >= 3)
+			specpoints[spi].unconditional = 1;
+		      specpoints[spi].s1 = surfind[j];
+		      specpoints[spi].s2 = surfind[k];
+		      specpoints[spi].layer = apoints[i].GetLayer();
+		      for (int up = 0; up < geometry->GetNUserPoints(); up++)
+			if (Dist (geometry->GetUserPoint(up), apoints[i]) < 1e-10)
+			  specpoints[spi].unconditional = 1;
+			
+		      /*
+		      (*testout) << "spi = " << spi 
+				 << " uncond = " << specpoints[spi].unconditional
+				 << " t = " << t << "\n";
+		      */
+		    }
+          
+		}
+	  delete locsol;
+	}
+    }
+
+  // if special point is unconditional on some solid,
+  // it must be unconditional everywhere:
+
+  BitArray uncond (apoints.Size());
+  uncond.Clear();
+
+  for (i = 0; i < specpoints.Size(); i++)
+    if (specpoints[i].unconditional)
+      uncond.Set (specpoint2point[i]);
+  
+  for (i = 0; i < specpoints.Size(); i++)
+    specpoints[i].unconditional = 
+      uncond.Test (specpoint2point[i]) ? 1 : 0;
+}
+}
diff --git a/Netgen/libsrc/csg/specpoin.hpp b/Netgen/libsrc/csg/specpoin.hpp
new file mode 100644
index 0000000000..244361e652
--- /dev/null
+++ b/Netgen/libsrc/csg/specpoin.hpp
@@ -0,0 +1,143 @@
+#ifndef FILE_SPECPOIN
+#define FILE_SPECPOIN
+
+
+/**************************************************************************/
+/* File:   specpoin.hh                                                    */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Okt. 95                                                    */
+/**************************************************************************/
+
+/*
+
+Special Point Calculation
+  
+*/
+
+class Surface;
+class Solid;
+
+/// Special point.
+class SpecialPoint
+{
+public:
+  
+  /// coordinates
+  Point<3> p;
+  /// tangential to edge
+  Vec<3> v;
+  ///
+  int layer;
+  /// point must be used in mesh 
+  bool unconditional; 
+
+  /// surfaces defining edge 
+  int s1, s2;        
+
+  ///
+  SpecialPoint () : p(), v(), layer(0)
+  { ; }
+
+  ///
+  SpecialPoint (const SpecialPoint & sp2);
+
+  ///
+  SpecialPoint & operator= (const SpecialPoint & sp2);
+  
+  ///
+  void Print (ostream & str);
+
+
+  int GetLayer() const { return layer; }
+
+  ///
+  bool HasSurfaces (int as1, int as2) const;
+};
+
+
+
+///
+class SpecialPointCalculation
+{
+private:
+  ///
+  const CSGeometry * geometry;
+  ///
+  ARRAY<MeshPoint> * points;
+  ///
+  ARRAY<long int> boxesinlevel;
+
+  ///
+  double size;
+  ///
+  double relydegtest;   // maximal dimension of bisection intervall for
+                        /// test of degeneration parameters
+  double cpeps1, epeps1, epeps2, epspointdist2;
+
+public: 
+
+  ///
+  SpecialPointCalculation (); 
+  
+  ///
+  void CalcSpecialPoints (const CSGeometry & ageometry, 
+			  ARRAY<MeshPoint> & points);
+  ///
+  void AnalyzeSpecialPoints (const CSGeometry & geometry, 
+			     ARRAY<MeshPoint> & points, 
+			     ARRAY<SpecialPoint> & specpoints);
+
+protected:
+  ///
+  void CalcSpecialPointsRec (const Solid * sol, int layer,
+			     const BoxSphere<3> & box, 
+			     int level, 
+			     bool calccp, bool calcep);
+
+
+  ///
+  bool CrossPointNewtonConvergence (const Surface * f1, const Surface * f2, 
+				    const Surface * f3, const Point<3> & p);  
+  ///
+  bool CrossPointDegenerated (const Surface * f1, const Surface * f2,
+			      const Surface * f3, const BoxSphere<3> & box) const;
+  ///
+  void CrossPointNewton (const Surface * f1, const Surface * f2, 
+			 const Surface * f3, Point<3> & p);
+  
+  bool EdgeNewtonConvergence (const Surface * f1, const Surface * f2, 
+			      const Point<3> & p);  
+  ///
+  bool EdgeDegenerated (const Surface * f1, const Surface * f2,
+			const BoxSphere<3> & box) const;
+  ///
+  void EdgeNewton (const Surface * f1, const Surface * f2, 
+		   Point<3> & p);
+  ///
+  bool IsEdgeExtremalPoint (const Surface * f1, const Surface * f2, 
+			    const Point<3> & p, Point<3> & pp, double rad);
+
+
+
+
+  ///
+  bool ExtremalPointPossible (const Surface * f1, const Surface * f2, 
+			      int dir, const BoxSphere<3> & box);
+  ///
+  bool ExtremalPointDegenerated (const Surface * f1, const Surface * f2, 
+				 int dir, const BoxSphere<3> & box);
+  ///
+  bool ExtremalPointNewtonConvergence (const Surface * f1, const Surface * f2, 
+				       int dir, const BoxSphere<3> & box);
+  ///
+  void ExtremalPointNewton (const Surface * f1, const Surface * f2, 
+			    int dir, Point<3> & p);
+
+
+  ///
+  bool AddPoint (const Point<3> & p, int layer);
+};
+
+#endif
+
+
diff --git a/Netgen/libsrc/csg/spline3d.cpp b/Netgen/libsrc/csg/spline3d.cpp
new file mode 100644
index 0000000000..455493ad6f
--- /dev/null
+++ b/Netgen/libsrc/csg/spline3d.cpp
@@ -0,0 +1,355 @@
+#include <mystdlib.h>
+
+#include <myadt.hpp>
+
+#include <linalg.hpp>
+#include <csg.hpp>
+
+
+namespace netgen
+{
+splinesegment3d :: splinesegment3d (const Point<3> & ap1, const Point<3> & ap2, 
+				    const Point<3> & ap3)
+{
+  p1 = ap1;
+  p2 = ap2;
+  p3 = ap3;
+}
+
+
+/*
+  todo
+  Tip von Joerg Stiller:
+  setzt Du in 
+  void splinesegment3d :: Evaluate
+  Zeilen 54 und 56
+  b2 = 2 * t * (1-t);
+  b2 /= sqrt(2);
+  Das heisst, Du wichtest das zweite Bersteinpolynom mit 
+  w2 = 1 / sqrt(2);
+  Das ist aber nur fuer 45-Grad-Segmente korrekt. Fuer den
+  allgemeinen Fall funktioniert
+  w2 = ( e(p3 - p1), e(p2 - p1) );  // also cos(winkel(p3-p1, p2-p1))
+  bzw. schoen symmetrisch
+  w2 = ( e(p3 - p1), e(p2 - p1) )/2 + ( e(p1 - p3), e(p2 - p3) )/2;
+  Das ist natuerlich kein C++ Code sondern symbolisch, wobei
+  e(p3 - p1)    ist der von p1 zu p3 zeigende Einheitsvektor und
+  (a, b)        steht fuer das Skalarprodukt zweier Vektoren etc.
+
+  Eine vergleichbare Information steht auch irgendwo im Hoscheck & Lasser.
+  Ich habe das Buch aber eben nicht zur Hand.
+*/
+
+void splinesegment3d :: Evaluate (double t, Point<3> & p) const
+{
+  double x, y, z, w;
+  double b1, b2, b3;
+
+  b1 = (1-t)*(1-t);
+  b2 = 2 * t * (1-t);
+  b3 = t * t;
+
+  b2 /= sqrt(double(2));
+
+  x = p1(0) * b1 + p2(0) * b2 + p3(0) * b3;
+  y = p1(1) * b1 + p2(1) * b2 + p3(1) * b3;
+  z = p1(2) * b1 + p2(2) * b2 + p3(2) * b3;
+  w = b1 + b2 + b3;
+
+  p(0) = x / w;
+  p(1) = y / w;
+  p(2) = z / w;
+}
+
+void splinesegment3d :: EvaluateTangent (double t, Vec<3> & tang) const
+{
+  double x, y, z, w, xprime, yprime, zprime, wprime;
+  double b1, b2, b3, b1prime, b2prime, b3prime;
+
+  b1 = (1-t)*(1-t);
+  b2 = 2 * t * (1-t);
+  b3 = t * t;
+  b2 /= sqrt(double(2));
+
+  b1prime = 2 * t - 2;
+  b2prime = - 4 * t + 2;
+  b3prime = 2 * t;
+  b2prime /= sqrt(double(2));
+
+ 
+  x = p1(0) * b1 + p2(0) * b2 + p3(0) * b3;
+  y = p1(1) * b1 + p2(1) * b2 + p3(1) * b3;
+  z = p1(2) * b1 + p2(2) * b2 + p3(2) * b3;
+  w = b1 + b2 + b3;
+
+  xprime = p1(0) * b1prime + p2(0) * b2prime + p3(0) * b3prime;
+  yprime = p1(1) * b1prime + p2(1) * b2prime + p3(1) * b3prime;
+  zprime = p1(2) * b1prime + p2(2) * b2prime + p3(2) * b3prime;
+  wprime = b1prime + b2prime + b3prime;
+
+  tang(0) = (w * xprime - x * wprime) / (w * w);
+  tang(1) = (w * yprime - y * wprime) / (w * w);
+  tang(2) = (w * zprime - z * wprime) / (w * w);
+}
+ 
+
+void spline3d :: AddSegment (const Point<3> & ap1, const Point<3> & ap2, 
+			     const Point<3> & ap3)
+{
+  segments.Append (new splinesegment3d (ap1, ap2, ap3));
+}
+
+void spline3d :: Evaluate (double t, Point<3> & p) const
+{
+  int nr;
+  double loct;
+  static int cnt = 0;
+  
+  cnt++;
+  if (cnt % 10000 == 0) (*mycout) << "Evaluate calls: " << cnt << endl;
+
+  while (t < 0) t += GetNumSegments();
+  while (t >= GetNumSegments()) t -= GetNumSegments();
+  nr = 1 + int (t);
+  loct = t - nr + 1;
+  segments.Get(nr)->Evaluate (loct, p);
+}
+  
+void spline3d :: EvaluateTangent (double t, Vec<3> & tang) const
+{
+  int nr;
+  double loct;
+
+  while (t < 0) t += GetNumSegments();
+  while (t >= GetNumSegments()) t -= GetNumSegments();
+  nr = 1 + int (t);
+  loct = t - nr + 1;
+  segments.Get(nr)->EvaluateTangent (loct, tang);
+}
+
+
+double spline3d :: ProjectToSpline (Point<3> & p) const
+{
+  double t, tl, tu, dt, dist, mindist, optt;
+  Point<3> hp;
+  Vec<3> tanx, px;
+  
+  dt = 0.01;
+  mindist = 0;
+  for (t = 0; t <= GetNumSegments() + dt/2; t += dt)
+    {
+      Evaluate (t, hp);
+      dist = Dist (hp, p);
+      if (t == 0 || dist < mindist)
+	{
+	  optt = t;
+	  mindist = dist;
+	} 
+    }
+
+  
+  tu = optt + dt;
+  tl = optt - dt;
+  while (tu - tl > 1e-2)
+    {
+      optt = 0.5 * (tu + tl);
+      Evaluate (optt, hp);
+      EvaluateTangent (optt, tanx);
+      if (tanx * (hp - p) > 0)
+	tu = optt;
+      else
+	tl = optt;
+    } 
+
+  optt = 0.5 * (tu + tl);
+
+  optt = ProjectToSpline (p, optt);
+  return optt;
+}
+ 
+ 
+double spline3d :: ProjectToSpline (Point<3> & p, double optt) const
+{ 
+  double tl, tu, dt, val, dval, valu, vall;
+  Point<3> hp;
+  Vec<3> tanx, px;
+  int its = 0;
+  int cnt = 1000;
+  do
+    {
+      dt = 1e-8;
+      tl = optt - dt;
+      tu = optt + dt;
+    
+      EvaluateTangent (optt, tanx); 
+      Evaluate (optt, hp);
+      px = hp - p;
+      val =  px * tanx;
+    
+      EvaluateTangent (tl, tanx); 
+      Evaluate (tl, hp);
+      px = hp - p;
+      vall =  px * tanx;
+    
+      EvaluateTangent (tu, tanx); 
+      Evaluate (tu, hp);
+      px = hp - p;
+      valu =  px * tanx;
+    
+      dval = (valu - vall) / (2 * dt);
+
+      if (its % 100 == 99)    
+	(*testout) << "optt = " << optt 
+		   << " val = " << val 
+		   << " dval = " << dval << endl;
+      optt -= val / dval;
+      its++;
+      if (fabs(val) < 1e-8 && cnt > 5) cnt = 5;
+      cnt--;
+    }
+  while (cnt > 0);
+        
+  Evaluate (optt, p);
+  return optt;
+}
+  
+  
+splinetube :: splinetube (const spline3d & amiddlecurve, double ar)
+  : Surface(), middlecurve (amiddlecurve), r(ar)
+{
+  (*mycout) << "Splinetube Allocated, r = " << r << endl;
+
+}
+  
+void splinetube :: DefineTangentialPlane (const Point<3> & ap1, 
+					  const Point<3> & ap2)
+{
+  double t;
+  double phi, z;
+  
+  p1 = ap1;
+  p2 = ap2;
+  cp = p1;
+  t = middlecurve.ProjectToSpline (cp);
+  ex = p1 - cp;
+  middlecurve.EvaluateTangent (t, ez); 
+  ex.Normalize();
+  ez.Normalize();
+  ey = Cross (ez, ex);
+  
+  phi = r * atan2 (ey * (p2-cp), ex * (p2-cp));
+  z = ez * (p2 - cp); 
+  e2x(0) = phi;
+  e2x(1) = z;
+  e2x.Normalize();
+  e2y(1) = e2x(0);
+  e2y(0) = -e2x(1);
+  
+  //  (*testout) << "Defineplane: " << endl
+  //  	<< "p1 = " << p1 << "   p2 = " << p2 << endl
+  //  	<< "pc = " << cp << endl
+  //  	<< "ex = " << ex << " ey = " << ey << " ez = " << ez << endl
+  //  	<< "phi = " << phi << "  z = " << z << endl
+  //  	<< "e2x = " << e2x << " e2y = " << e2y << endl;
+}
+  
+void splinetube :: ToPlane (const Point<3> & p3d, Point<2> & pplain, double h, 
+			    int & zone) const
+{
+  Vec<2> v;
+  v(0) = r * atan2 (ey * (p3d-cp), ex * (p3d-cp));
+  v(1) = ez * (p3d - cp); 
+  zone = 0;
+  if (v(0) > r * 2) zone = 1;
+  if (v(0) < r * 2) zone = 2;
+  
+  pplain(0) = (v * e2x) / h;
+  pplain(1) = (v * e2y) / h;
+}
+  
+void splinetube :: FromPlane (const Point<2> & pplain, Point<3> & p3d, double h) const
+{
+  Vec<2> v;
+  
+  v(0) = pplain(0) * h * e2x(0) + pplain(1) * h * e2y(0);
+  v(1) = pplain(0) * h * e2x(1) + pplain(1) * h * e2y(1);
+  
+  p3d = p1 + v(0) * ey + v(1) * ez;
+
+  Project (p3d);
+}
+  
+void splinetube :: Project (Point<3> & p3d) const
+{
+  Point<3> hp;
+  
+  hp = p3d;
+  middlecurve.ProjectToSpline (hp);
+  
+  p3d = hp + (r / Dist(p3d, hp)) * (p3d - hp); 
+}
+
+
+
+double splinetube :: CalcFunctionValue (const Point<3> & point) const
+{
+  Point<3> hcp;
+  double rad;
+
+  hcp = point;
+  middlecurve.ProjectToSpline (hcp);
+  rad = Dist (hcp, point);
+  return 0.5 * (rad * rad / r - r);
+}
+  
+void splinetube :: CalcGradient (const Point<3> & point, Vec<3> & grad) const
+{
+  Point<3> hcp;
+
+  hcp = point;
+  middlecurve.ProjectToSpline (hcp);
+
+  grad = point - hcp;
+  grad /= r;
+}
+  
+  
+
+
+Point<3> splinetube :: GetSurfacePoint () const
+{
+  Point<3> p;
+  Vec<3> t, n;
+  
+  middlecurve.Evaluate (0, p);
+  middlecurve.EvaluateTangent (0, t);
+  n = t.GetNormal ();
+  n *= r;
+  (*mycout) << "p = " << p << " t = " << t << "  n = " << n << endl;
+  return p + n;
+}
+
+void splinetube :: Print (ostream & str) const
+{
+  int i;
+  str << "SplineTube, " 
+      << middlecurve.GetNumSegments () << " segments, r = " << r << endl;
+  for (i = 1; i <= middlecurve.GetNumSegments(); i++)
+    str << middlecurve.P1(i) << " - " 
+	<< middlecurve.P2(i) << " - " 
+	<< middlecurve.P3(i) << endl;
+}
+
+
+int splinetube :: BoxInSolid (const BoxSphere<3> & box) const
+  // 0 .. no, 1 .. yes, 2 .. maybe
+{
+  Point<3> pc = box.Center();
+  middlecurve.ProjectToSpline (pc);
+  double d = Dist (pc, box.Center());
+  
+  if (d < r - box.Diam()/2) return 1;
+  if (d > r + box.Diam()/2) return 0;
+  return 2;
+}
+}
diff --git a/Netgen/libsrc/csg/spline3d.hpp b/Netgen/libsrc/csg/spline3d.hpp
new file mode 100644
index 0000000000..753788459f
--- /dev/null
+++ b/Netgen/libsrc/csg/spline3d.hpp
@@ -0,0 +1,92 @@
+///
+class splinesegment3d
+  {
+  ///
+  Point<3> p1, p2, p3;
+  
+  public:
+  ///
+  splinesegment3d (const Point<3> & ap1, const Point<3> & ap2, 
+  	const Point<3> & ap3);
+  ///
+  void Evaluate (double t, Point<3> & p) const;
+  ///
+  void EvaluateTangent (double t, Vec<3> & tang) const;
+  ///
+  const Point<3> & P1() const { return p1; }
+  ///
+  const Point<3> & P2() const { return p2; }
+  ///
+  const Point<3> & P3() const { return p3; }
+  };
+
+///
+class spline3d
+  {
+  ///
+  ARRAY<splinesegment3d *> segments;
+  
+  public:
+  ///
+  spline3d () { };
+  ///
+  void AddSegment (const Point<3> & ap1, const Point<3> & ap2, const Point<3> & ap3);
+  ///
+  int GetNumSegments () const { return segments.Size(); }
+  ///
+  double ProjectToSpline (Point<3> & p) const;
+  ///
+  double ProjectToSpline (Point<3> & p, double t) const;
+  ///
+  void Evaluate (double t, Point<3> & p) const;
+  ///
+  void EvaluateTangent (double t, Vec<3> & tang) const;
+  ///
+  const Point<3> & P1(int i) const { return segments.Get(i)->P1(); }
+  ///
+  const Point<3> & P2(int i) const { return segments.Get(i)->P2(); }
+  ///
+  const Point<3> & P3(int i) const { return segments.Get(i)->P3(); }
+  };
+  
+///
+class splinetube : public Surface
+  {
+  ///
+  const spline3d & middlecurve;
+  ///
+  double r;
+///  Vec<3> ex, ey, ez;
+  Vec<2> e2x, e2y;
+  ///
+  Point<3> cp;
+  
+  public:
+  ///
+  splinetube (const spline3d & amiddlecurve, double ar);
+  
+  ///
+  virtual void DefineTangentialPlane (const Point<3> & ap1, const Point<3> & ap2);
+  ///
+  virtual void ToPlane (const Point<3> & p, Point<2> & pplain, double h, int & zone) const;
+  ///
+  virtual void FromPlane (const Point<2> & pplain, Point<3> & p, double h) const;
+  ///
+  virtual void Project (Point<3> & p) const;
+
+//  virtual int RootInBox (const box3d & box) const { return 0; }
+    /// 0 .. no, 1 .. yes, 2 .. maybe
+
+  virtual int BoxInSolid (const BoxSphere<3> & box) const;
+    /// 0 .. no, 1 .. yes, 2 .. maybe
+
+  virtual double CalcFunctionValue (const Point<3> & point) const;
+  ///
+  virtual void CalcGradient (const Point<3> & point, Vec<3> & grad) const;
+  ///
+  virtual double HesseNorm () const { return 0.5 / r; }
+  ///
+  virtual Point<3> GetSurfacePoint () const;
+  ///
+  virtual void Print (ostream & str) const;
+  };  
diff --git a/Netgen/libsrc/csg/surface.cpp b/Netgen/libsrc/csg/surface.cpp
new file mode 100644
index 0000000000..2fd4064562
--- /dev/null
+++ b/Netgen/libsrc/csg/surface.cpp
@@ -0,0 +1,380 @@
+#include <mystdlib.h>
+
+#include <myadt.hpp>
+#include <csg.hpp>
+
+#include <linalg.hpp>
+#include <meshing.hpp>
+
+
+namespace netgen
+{
+Surface :: Surface ()
+{
+  maxh = 1e10;
+  name = new char[7];
+  strcpy (name, "noname");
+  bcprop = -1;
+}
+
+Surface :: ~Surface()
+{
+  delete [] name;
+}
+
+
+void Surface :: SetName (const char * aname)
+{
+  delete [] name;
+  name = new char[strlen (aname)+1];
+  strcpy (name, aname);
+}
+
+
+int Surface :: PointOnSurface (const Point<3> & p,
+			       double eps) const
+{
+  double val = CalcFunctionValue (p);
+  return fabs (val) < eps;
+}
+
+
+void Surface :: CalcHesse (const Point<3> & point, Mat<3> & hesse) const
+{
+  double dx = 1e-5;
+  Point<3> hp1, hp2;
+  Vec<3> g1, g2;
+
+  for (int i = 0; i < 3; i++)
+    {
+      hp1 = point;
+      hp2 = point;
+
+      hp1(i) += dx;
+      hp2(i) -= dx;
+
+      CalcGradient (hp1, g1);
+      CalcGradient (hp2, g2);
+      	
+      for (int j = 0; j < 3; j++)
+	hesse(i, j) = (g1(j) - g2(j)) / (2 * dx);
+    }
+}
+  
+void Surface :: GetNormalVector (const Point<3> & p, Vec<3> & n) const
+{
+  CalcGradient (p, n);
+  n.Normalize();
+  //  if (Inverse()) n *= -1;
+}
+
+void Surface :: DefineTangentialPlane (const Point<3> & ap1, 
+				       const Point<3> & ap2)
+{
+  p1 = ap1;
+  p2 = ap2;
+  
+  GetNormalVector (p1, ez);
+  ex = p2 - p1;
+  ex -= (ex * ez) * ez;
+  ex.Normalize();
+  ey = Cross (ez, ex);  
+}
+
+void Surface :: ToPlane (const Point<3> & p3d, Point<2> & pplane, 
+			 double h, int & zone) const
+{
+  Vec<3> p1p, n;
+
+  GetNormalVector (p3d, n);
+  if (n * ez < 0)
+    {
+      zone = -1;
+      pplane(0) = 1e8;
+      pplane(1) = 1e9;
+      return;
+    }
+  
+  p1p = p3d - p1;
+  pplane(0) = (p1p * ex) / h;
+  pplane(1) = (p1p * ey) / h;
+  zone = 0;
+}	
+
+void Surface :: FromPlane (const Point<2> & pplane, 
+			   Point<3> & p3d, double h) const 
+{ 
+  p3d = p1 
+    + (h * pplane(0)) * ex 
+    + (h * pplane(1)) * ey;
+  
+  Project (p3d);
+}
+
+void Surface :: Project (Point<3> & p) const
+{
+  Vec<3> n;
+  double val;
+
+  for (int i = 1; i <= 10; i++)
+    {
+      val = CalcFunctionValue (p);
+      if (fabs (val) < 1e-12) return;
+	
+      CalcGradient (p, n);
+      p -= (val / Abs2 (n)) * n;
+    }
+}
+
+double Surface :: MaxCurvature () const
+{ 
+  return 0.5 * HesseNorm (); 
+}
+
+double Surface :: 
+MaxCurvatureLoc (const Point<3> & /* c */ , double /* rad */) const
+{ 
+  return MaxCurvature (); 
+}
+              
+
+
+double Surface :: LocH (const Point<3> & p, double x, 
+			double c, double hmax) const
+  // finds h <= hmax, s.t.  h * \kappa_x*h < c
+{
+  /*
+    double h, hmin, kappa;
+    hmin = 0;
+  
+    while (hmin < 0.9 * hmax)
+    {
+    h = 0.5 * (hmin + hmax);
+    kappa = 2 * MaxCurvatureLoc (p, x * h);
+      
+    if (kappa * h >= c)
+    hmax = h;
+    else
+    hmin = h;
+    }
+    return h;
+  */
+
+  double hret;
+  double kappa = MaxCurvatureLoc (p, x*hmax);
+
+  kappa *= c *  mparam.curvaturesafety;
+  
+  if (hmax * kappa < 1)
+    hret = hmax;
+  else
+    hret = 1 / kappa;
+
+  if (maxh < hret)
+    hret = maxh;
+
+  return hret;
+}
+
+
+
+
+Primitive :: Primitive ()
+{
+  surfaceids.SetSize (1);
+  surfaceactive.SetSize (1);
+  surfaceactive[0] = 1;
+}
+
+Primitive :: ~Primitive()
+{
+  ;
+}
+
+int Primitive :: GetSurfaceId (int i) const
+{
+  return surfaceids[i];
+}
+
+void Primitive :: SetSurfaceId (int i, int id) 
+{
+  surfaceids[i] = id;
+}
+
+
+
+
+void Primitive :: GetPrimitiveData (char *& classname, 
+				    ARRAY<double> & coeffs) const
+{
+  classname = "undef";
+  coeffs.SetSize (0);
+}
+
+void Primitive :: SetPrimitiveData (ARRAY<double> & coeffs)
+{
+  ;
+}
+
+Primitive * Primitive :: CreatePrimitive (const char * classname)
+{
+  if (strcmp (classname, "sphere") == 0)
+    return Sphere::CreateDefault();
+  if (strcmp (classname, "plane") == 0)
+    return Plane::CreateDefault();
+  if (strcmp (classname, "cylinder") == 0)
+    return Cylinder::CreateDefault();
+  if (strcmp (classname, "cone") == 0)
+    return Cone::CreateDefault();
+  if (strcmp (classname, "brick") == 0)
+    return Brick::CreateDefault();
+
+  cout << "cannot create primitive " << classname << endl;
+  return NULL;
+}
+
+
+Primitive * Primitive :: Copy () const
+{
+  cout << "Primitive called for baseclass" << endl;
+  return NULL;
+}
+
+
+void Primitive :: Transform (Transformation<3> & trans)
+{
+  cout << "transform called for baseclass" << endl;
+}
+
+
+INSOLID_TYPE Primitive :: 
+VecInSolid2 (const Point<3> & p,
+	     const Vec<3> & v1,
+	     const Vec<3> & v2,
+	     double eps) const
+{
+  Point<3> hp = p + 1e-3 * v1 + 1e-5 * v2;
+  return PointInSolid (hp, eps);
+}
+
+
+
+
+
+
+OneSurfacePrimitive :: OneSurfacePrimitive()
+{
+  ;
+}
+
+OneSurfacePrimitive :: ~OneSurfacePrimitive()
+{
+  ;
+}
+
+
+INSOLID_TYPE OneSurfacePrimitive :: 
+PointInSolid (const Point<3> & p,
+	      double eps) const
+{
+  double hv1 = (GetSurface(0).CalcFunctionValue(p));
+  if (hv1 <= -eps)
+    return IS_INSIDE;
+  if (hv1 >= eps)
+    return IS_OUTSIDE;
+  return DOES_INTERSECT;
+}
+ 
+INSOLID_TYPE OneSurfacePrimitive :: 
+VecInSolid (const Point<3> & p, const Vec<3> & v,
+	    double eps) const
+{
+  Vec<3> hv;
+  double hv1;
+  GetSurface(0).CalcGradient (p, hv);
+
+  hv1 = v * hv;
+
+  if (hv1 <= -eps)
+    return IS_INSIDE;
+  if (hv1 >= eps)
+    return IS_OUTSIDE;
+
+  return DOES_INTERSECT;
+}
+
+
+INSOLID_TYPE OneSurfacePrimitive :: 
+VecInSolid2 (const Point<3> & p,
+	     const Vec<3> & v1,
+	     const Vec<3> & v2,
+	     double eps) const
+{
+  Vec<3> hv;
+  double hv1, hv2;
+
+  GetSurface(0).CalcGradient (p, hv);
+
+  hv1 = v1 * hv;
+  if (hv1 <= -eps)
+    return IS_INSIDE;
+  if (hv1 >= eps)
+    return IS_OUTSIDE;
+
+  hv2 = v2 * hv;
+  if (hv2 <= 0)
+    return IS_INSIDE;
+  else
+    return IS_OUTSIDE;
+}
+  
+
+
+
+int OneSurfacePrimitive :: GetNSurfaces() const
+{
+  return 1;
+}
+
+Surface & OneSurfacePrimitive :: GetSurface (int i)
+{
+  return *this;
+}
+
+const Surface & OneSurfacePrimitive :: GetSurface (int i) const
+{
+  return *this;
+}
+
+
+
+
+
+
+void ProjectToEdge (const Surface * f1, const Surface * f2, Point<3> & hp)
+{
+  Vec<2> rs, lam;
+  Vec<3> a1, a2;
+  Mat<2> a;
+
+  int i = 10;
+  while (i > 0)
+    {
+      i--;
+      rs(0) = f1 -> CalcFunctionValue (hp);
+      rs(1) = f2 -> CalcFunctionValue (hp);
+      f1->CalcGradient (hp, a1);
+      f2->CalcGradient (hp, a2);
+
+      a(0,0) = a1 * a1;
+      a(0,1) = a(1,0) = a1 * a2;
+      a(1,1) = a2 * a2;
+
+      a.Solve (rs, lam);
+
+      hp -= lam(0) * a1 + lam(1) * a2;
+
+      if (Abs2 (rs) < 1e-24 && i > 1) i = 1;
+    }
+}
+}
diff --git a/Netgen/libsrc/csg/surface.hpp b/Netgen/libsrc/csg/surface.hpp
new file mode 100644
index 0000000000..2738d5222d
--- /dev/null
+++ b/Netgen/libsrc/csg/surface.hpp
@@ -0,0 +1,300 @@
+#ifndef FILE_SURFACE
+#define FILE_SURFACE
+
+/**************************************************************************/
+/* File:   surface.hh                                                     */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   1. Dez. 95                                                     */
+/**************************************************************************/
+
+
+
+
+// class DenseMatrix;
+// class Box3dSphere;
+class TriangleApproximation;
+
+/**
+  Basis class for implicit surface geometry.
+  This class is used for generation of surface meshes
+  in NETGEN as well as for mesh refinement in FEPP.
+  */
+
+
+
+
+class Surface
+{
+protected:
+  /// invert normal vector
+  bool inverse;
+  /// maximal h in surface
+  double maxh;
+  /// name of surface
+  char * name;
+  /// boundary condition nr
+  int bcprop;
+  ///
+  
+public:
+  Surface ();
+  /** @name Tangential plane.
+    The tangential plane is used for surface mesh generation.
+   */
+  
+  virtual ~Surface();
+
+protected:
+  /** @name Points in the surface defining tangential plane.
+    Tangential plane is taken in p1, the local x-axis
+    is directed to p2.
+    */
+  //@{
+  ///
+  Point<3> p1;
+  ///
+  Point<3> p2;
+  //@}
+  /** @name Base-vectos for local coordinate system. */
+  //@{
+  /// in plane, directed p1->p2
+  Vec<3> ex;
+  /// in plane
+  Vec<3> ey;
+  /// outer normal direction
+  Vec<3> ez;
+  //@}
+public:
+
+  void SetName (const char * aname);
+  const char * Name () const { return name; }
+
+  //@{
+  /**
+    Defines tangential plane in ap1.
+    The local x-coordinate axis point to the direction of ap2 */
+  virtual void DefineTangentialPlane (const Point<3> & ap1, 
+				      const Point<3> & ap2);
+
+  /// Transforms 3d point p3d to local coordinates pplane
+  virtual void ToPlane (const Point<3> & p3d, Point<2> & pplane, 
+			double h, int & zone) const;
+  
+  /// Transforms point pplane in local coordinates to 3d point
+  virtual void FromPlane (const Point<2> & pplane, 
+			  Point<3> & p3d, double h) const;
+  //@}
+
+
+  /// Move Point p to closes point in surface
+  virtual void Project (Point<3> & p) const;
+
+
+  virtual int IsIdentic (const Surface & s2, int & inv, 
+			 double eps) const
+  { return 0; }
+  
+  ///
+  virtual int PointOnSurface (const Point<3> & p,
+			      double eps = 1e-6) const;
+  
+
+  /** @name Implicit function.
+      Calculate function value and derivatives.
+  */
+  //@{
+  /// Calculate implicit function value in point point
+  virtual double CalcFunctionValue (const Point<3> & point) const = 0;
+
+  /**
+    Calc gradient of implicit function.
+    gradient should be O(1) at surface
+    */
+  virtual void CalcGradient (const Point<3> & point, Vec<3> & grad) const = 0;
+
+  /**
+    Calculate second derivatives of implicit function.
+   */
+  virtual void CalcHesse (const Point<3> & point, Mat<3> & hesse) const;
+
+  /**
+    Returns outer normal vector.
+   */
+  virtual void GetNormalVector (const Point<3> & p, Vec<3> & n) const;
+
+  /**
+    Upper bound for spectral norm of Hesse-matrix
+   */
+  virtual double HesseNorm () const = 0;
+
+  /**
+    Upper bound for spectral norm of Hesse-matrix in the
+    rad - environment of point c.
+   */
+  virtual double HesseNormLoc (const Point<3> & /* c */, 
+			       double /* rad */) const
+  { return HesseNorm (); }
+  //@}
+
+
+  ///
+  virtual double MaxCurvature () const;
+  ///
+  virtual double MaxCurvatureLoc (const Point<3> & /* c */ , 
+				  double /* rad */) const;
+
+  /** Returns any point in the surface.
+    Needed to start surface mesh generation e.g. on sphere */
+  virtual Point<3> GetSurfacePoint () const = 0;
+
+  ///
+  bool Inverse () const { return inverse; }
+  ///
+  void SetInverse (bool ainverse) { inverse = ainverse; }
+  /// 
+  virtual void Print (ostream & str) const = 0;
+  
+  ///
+  virtual void Reduce (const BoxSphere<3> & /* box */) { };
+  ///
+  virtual void UnReduce () { };
+
+  /// set max h in surface
+  void SetMaxH (double amaxh) { maxh = amaxh; }
+  ///
+  double GetMaxH () const { return maxh; }
+  ///
+  int GetBCProperty () const { return bcprop; }
+  ///
+  void SetBCProperty (int abc) { bcprop = abc; }
+
+  /** Determine local mesh-size.
+      Find 
+      \[ h \leq hmax, \]
+      such that
+      \[ h  \times \kappa (x) \leq c \qquad \mbox{in} B(x, h), \]
+      where kappa(x) is the curvature in x. */
+  virtual double LocH (const Point<3> & p, double x, 
+		       double c, double hmax) const;
+
+  /**
+     Gets Approximation by triangles,
+     where qual is about the number of triangles per radius
+  */
+  virtual void GetTriangleApproximation (TriangleApproximation & tas, 
+					 const Box<3> & boundingbox, 
+					 double facets) const { };
+
+#ifdef MYGRAPH  
+  ///
+  virtual void Plot (const class ROT3D & /* rot */) const { };
+#endif
+  };
+
+
+typedef enum { IS_OUTSIDE = 0, IS_INSIDE = 1, DOES_INTERSECT = 2}
+INSOLID_TYPE;
+
+
+
+
+class Primitive
+{
+
+public:
+
+  Primitive ();
+
+  virtual ~Primitive();
+
+  
+  /*
+    Check, whether box intersects solid defined by surface.
+
+    return values:
+    0 .. box outside solid \\
+    1 .. box in solid \\
+    2 .. can't decide (allowed, iff box is close to solid)
+  */
+  virtual INSOLID_TYPE BoxInSolid (const BoxSphere<3> & box) const = 0;
+  virtual INSOLID_TYPE PointInSolid (const Point<3> & p,
+				     double eps) const = 0;
+  virtual INSOLID_TYPE VecInSolid (const Point<3> & p,
+				   const Vec<3> & v,
+				   double eps) const = 0;
+
+  // checks if lim s->0 lim t->0  p + t(v1 + s v2) in solid
+  virtual INSOLID_TYPE VecInSolid2 (const Point<3> & p,
+				    const Vec<3> & v1,
+				    const Vec<3> & v2,
+				    double eps) const;
+
+  
+  virtual int GetNSurfaces() const = 0;
+  virtual Surface & GetSurface (int i = 0) = 0;
+  virtual const Surface & GetSurface (int i = 0) const = 0;
+
+  ARRAY<int> surfaceids;
+  ARRAY<int> surfaceactive;
+
+  int GetSurfaceId (int i = 0) const;
+  void SetSurfaceId (int i, int id);
+  int SurfaceActive (int i) const { return surfaceactive[i]; }
+  virtual int SurfaceInverted (int i = 0) const { return 0; }
+
+  virtual void GetPrimitiveData (char *& classname, 
+				 ARRAY<double> & coeffs) const;
+  virtual void SetPrimitiveData (ARRAY<double> & coeffs);
+  static Primitive * CreatePrimitive (const char * classname);
+
+
+  virtual void Reduce (const BoxSphere<3> & /* box */) { };
+  virtual void UnReduce () { };
+
+  virtual Primitive * Copy () const;
+  virtual void Transform (Transformation<3> & trans);
+};
+
+
+
+
+class OneSurfacePrimitive : public Surface, public Primitive
+{
+public:
+  OneSurfacePrimitive();
+  ~OneSurfacePrimitive();
+
+  virtual INSOLID_TYPE PointInSolid (const Point<3> & p,
+				     double eps) const;
+  virtual INSOLID_TYPE VecInSolid (const Point<3> & p,
+				   const Vec<3> & v,
+				   double eps) const;
+  virtual INSOLID_TYPE VecInSolid2 (const Point<3> & p,
+				    const Vec<3> & v1,
+				    const Vec<3> & v2,
+				    double eps) const;
+
+  
+  virtual int GetNSurfaces() const;
+  virtual Surface & GetSurface (int i = 0);
+  virtual const Surface & GetSurface (int i = 0) const;
+};
+
+
+
+
+
+
+/**
+  Projects point to edge.
+  The point hp is projected to the edge descibed by f1 and f2.
+  It is assumed that the edge is non-degenerated, and the
+  (generalized) Newton method converges.
+ */
+extern void ProjectToEdge (const Surface * f1, 
+			   const Surface * f2,
+			   Point<3> & hp);
+
+
+
+#endif
diff --git a/Netgen/libsrc/csg/triapprox.cpp b/Netgen/libsrc/csg/triapprox.cpp
new file mode 100644
index 0000000000..b314855dae
--- /dev/null
+++ b/Netgen/libsrc/csg/triapprox.cpp
@@ -0,0 +1,62 @@
+#include <mystdlib.h>
+#include <myadt.hpp>
+
+#include <linalg.hpp>
+#include <csg.hpp>
+
+
+namespace netgen
+{
+
+TriangleApproximation :: TriangleApproximation ()
+{
+  ;
+}
+
+int TriangleApproximation :: 
+AddTriangle (const TATriangle & tri, bool invert)
+{ 
+  trias.Append (tri);
+  if (invert)
+    {
+      trias.Last()[1] = tri[2];
+      trias.Last()[2] = tri[1];
+    }
+  return trias.Size()-1;
+}
+
+
+void TriangleApproximation :: RemoveUnusedPoints ()
+{
+  BitArray used(GetNP());
+  ARRAY<int> map (GetNP());
+  int i, j;
+  int cnt = 0;
+
+  used.Clear();
+  for (i = 0; i < GetNT(); i++)
+    for (j = 0; j < 3; j++)
+      used.Set (GetTriangle (i)[j]);
+
+  for (i = 0; i < GetNP(); i++)
+    if (used.Test(i))
+      {
+	map[i] = cnt;
+	cnt++;
+      }
+  
+  for (i = 0; i < GetNT(); i++)
+    for (j = 0; j < 3; j++)
+      trias[i][j] = map[trias[i][j]];
+
+  for (i = 0; i < GetNP(); i++)
+    if (used.Test(i))
+      {
+	points[map[i]] = points[i];
+	normals[map[i]] = normals[i];
+      }
+
+  points.SetSize (cnt);
+  normals.SetSize (cnt);
+}
+}
diff --git a/Netgen/libsrc/csg/triapprox.hpp b/Netgen/libsrc/csg/triapprox.hpp
new file mode 100644
index 0000000000..d7192a9a02
--- /dev/null
+++ b/Netgen/libsrc/csg/triapprox.hpp
@@ -0,0 +1,60 @@
+#ifndef FILE_TRIAPPROX
+#define FILE_TRIAPPROX
+
+/**************************************************************************/
+/* File:   triapprox.hh                                                   */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   2. Mar. 98                                                    */
+/**************************************************************************/
+
+/**
+   Triangulated approxiamtion to true surface
+*/
+ 
+
+class TATriangle
+{
+  int pi[3];
+  int surfind;
+public:
+  TATriangle () { ; }
+
+  TATriangle (int si, int pi1, int pi2, int pi3)
+    { surfind = si; pi[0] = pi1; pi[1] = pi2; pi[2] = pi3; }
+
+  int SurfaceIndex() const { return surfind; }
+  int & SurfaceIndex() { return surfind; }
+
+  //  int PNum (int i) const { return pi[i-1]; }
+  //  int & PNum (int i) { return pi[i-1]; }
+
+  int & operator[] (int i) { return pi[i]; }
+  const int & operator[] (int i) const { return pi[i]; }
+};
+
+
+class TriangleApproximation
+{
+  ARRAY<Point<3> > points;
+  ARRAY<Vec<3> > normals;
+  ARRAY<TATriangle> trias;
+
+public:
+  TriangleApproximation();
+  int GetNP () const { return points.Size(); }
+  int GetNT () const { return trias.Size(); }
+
+  int AddPoint (const Point<3> & p) { points.Append (p); return points.Size()-1; }
+  int AddNormal (const Vec<3> & n) { normals.Append (n); return normals.Size()-1; }
+  int AddTriangle (const TATriangle & tri, bool invert = 0);
+
+  const Point<3> & GetPoint (int i) const { return points[i]; }
+  const TATriangle & GetTriangle (int i) const { return trias[i]; }
+  const Vec<3> & GetNormal (int i) const { return normals[i]; }
+
+  void RemoveUnusedPoints ();
+
+  friend class CSGeometry;
+};
+
+#endif
diff --git a/Netgen/libsrc/general/Makefile b/Netgen/libsrc/general/Makefile
new file mode 100644
index 0000000000..65a387a844
--- /dev/null
+++ b/Netgen/libsrc/general/Makefile
@@ -0,0 +1,12 @@
+#
+# Makefile for general purpose data types
+#
+src = array.cpp bitarray.cpp hashtabl.cpp symbolta.cpp table.cpp flags.cpp \
+	spbita2d.cpp seti.cpp optmem.cpp sort.cpp mystring.cpp parthreads.cpp \
+	moveablemem.cpp dynamicmem.cpp ngexception.cpp
+#	
+lib = gen
+libpath = libsrc/general
+#
+include ../makefile.inc
+
diff --git a/Netgen/libsrc/general/array.cpp b/Netgen/libsrc/general/array.cpp
new file mode 100644
index 0000000000..e3bc3e6fdf
--- /dev/null
+++ b/Netgen/libsrc/general/array.cpp
@@ -0,0 +1,75 @@
+#ifndef FILE_NGSTD_ARRAYCPP
+#define FILE_NGSTD_ARRAYCPP
+// necessary for SGI ????
+
+/**************************************************************************/
+/* File:   array.cpp                                                       */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Jun. 95                                                    */
+/**************************************************************************/
+
+/* 
+   Abstract data type ARRAY
+*/
+
+#include <mystdlib.h>
+#include <myadt.hpp>
+#include <assert.h>
+
+
+namespace netgen
+{
+  using namespace netgen;
+
+#ifdef NONE  
+  void BASE_ARRAY :: ReSize (int minsize, int elementsize)
+  {
+    cout << "resize, minsize = " << minsize << endl;
+
+    if (inc == -1)
+      throw Exception ("Try to resize fixed size array");
+
+    
+    void * p;
+    int nsize = (inc) ? allocsize + inc : 2 * allocsize;
+    if (nsize < minsize) nsize = minsize;
+
+    if (data)
+      {
+	p = new char [nsize * elementsize];
+	
+	int mins = (nsize < actsize) ? nsize : actsize; 
+	memcpy (p, data, mins * elementsize);
+	
+	delete [] static_cast<char*> (data);
+	data = p;
+      }
+    else
+      {
+	data = new char[nsize * elementsize];
+      }
+    
+    allocsize = nsize;
+    cout << "resize done" << endl;
+  }
+  
+  
+  
+  void BASE_ARRAY :: RangeCheck (int i) const
+  {
+    if (i < 0 || i >= actsize)
+      throw ArrayRangeException ();
+  }
+  
+  void BASE_ARRAY :: CheckNonEmpty () const
+  {
+    if (!actsize)
+      {
+	throw Exception ("Array should not be empty");
+	//      cerr << "Array souldn't be empty";
+      }
+  }
+#endif
+}
+#endif
+
diff --git a/Netgen/libsrc/general/array.hpp b/Netgen/libsrc/general/array.hpp
new file mode 100644
index 0000000000..020a15ac34
--- /dev/null
+++ b/Netgen/libsrc/general/array.hpp
@@ -0,0 +1,471 @@
+#ifndef FILE_ARRAY
+#define FILE_ARRAY
+
+/**************************************************************************/
+/* File:   array.hpp                                                      */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Jun. 95                                                    */
+/**************************************************************************/
+
+
+/**
+   A simple array container.
+   Array represented by size and data-pointer.
+   No memory allocation and deallocation, must be provided by user.
+   Helper functions for printing. 
+   Optional range check by macro RANGE_CHECK
+ */
+
+template <class T, int BASE = 0>
+class FlatArray
+{
+protected:
+  /// the size
+  int size;
+  /// the data
+  T * data;
+public:
+
+  /// provide size and memory
+  FlatArray (int asize, T * adata) 
+    : size(asize), data(adata) { ; }
+
+  /// the size
+  int Size() const { return size; }
+
+
+  /// access array. 
+  T & operator[] (int i) 
+  { 
+#ifdef DEBUG
+    if (i-BASE < 0 || i-BASE >= size)
+      cout << "array<" << typeid(T).name() << "> out of range, i = " << i << ", s = " << size << endl;
+#endif
+
+    return data[i-BASE]; 
+  }
+
+
+  /// Access array. 
+  const T & operator[] (int i) const
+  {
+#ifdef DEBUG
+    if (i-BASE < 0 || i-BASE >= size)
+      cout << "array<" << typeid(T).name() << "> out of range, i = " << i << ", s = " << size << endl;
+#endif
+
+    return data[i-BASE]; 
+  }
+
+  ///
+  T & Elem (int i)
+  {
+#ifdef DEBUG
+    if (i < 1 || i > size)
+      cout << "ARRAY<" << typeid(T).name() 
+	   << ">::Elem out of range, i = " << i
+	   << ", s = " << size << endl;
+#endif
+
+    return ((T*)data)[i-1]; 
+  }
+  
+  ///
+  const T & Get (int i) const 
+  {
+#ifdef DEBUG
+    if (i < 1 || i > size)
+      cout << "ARRAY<" << typeid(T).name() << ">::Get out of range, i = " << i
+	   << ", s = " << size << endl;
+#endif
+
+    return ((const T*)data)[i-1]; 
+  }
+
+  ///
+  void Set (int i, const T & el)
+  { 
+#ifdef DEBUG
+    if (i < 1 || i > size)
+      cout << "ARRAY<" << typeid(T).name() << ">::Set out of range, i = " << i
+	   << ", s = " << size << endl;
+#endif
+
+    ((T*)data)[i-1] = el; 
+  }
+
+
+  /// access last element. check by macro CHECK_RANGE
+  T & Last ()
+  {
+    return data[size-1];
+  }
+
+  /// access last element. check by macro CHECK_RANGE
+  const T & Last () const
+  {
+    return data[size-1];
+  }
+
+  /// Fill array with value val
+  FlatArray & operator= (const T & val)
+  {
+    for (int i = 0; i < size; i++)
+      data[i] = val;
+    return *this;
+  }
+};
+
+
+
+
+// print array
+template <class T, int BASE>
+inline ostream & operator<< (ostream & s, const FlatArray<T,BASE> & a)
+{
+  for (int i = BASE; i < a.Size()+BASE; i++)
+    s << i << ": " << a[i] << endl;
+  return s;
+}
+
+
+
+
+/** 
+   Dynamic array container.
+   
+   ARRAY<T> is an automatically increasing array container.
+   The allocated memory doubles on overflow. 
+   Either the container takes care of memory allocation and deallocation,
+   or the user provides one block of data.
+*/
+template <class T, int BASE = 0> 
+class ARRAY : public FlatArray<T, BASE>
+{
+protected:
+  /// physical size of array
+  int allocsize;
+  /// memory is responsibility of container
+  bool ownmem;
+
+public:
+
+  /// Generate array of logical and physical size asize
+  explicit ARRAY(int asize = 0)
+    : FlatArray<T, BASE> (asize, asize ? new T[asize] : 0)
+  {
+    allocsize = asize; 
+    ownmem = 1;
+  }
+
+  /// Generate array in user data
+  ARRAY(int asize, T* adata)
+    : FlatArray<T, BASE> (asize, adata)
+  {
+    allocsize = asize; 
+    ownmem = 0;
+  }
+
+  /// array copy 
+  explicit ARRAY (const ARRAY<T> & a2)
+    : FlatArray<T, BASE> (a2.Size(), a2.Size() ? new T[a2.Size()] : 0)
+  {
+    allocsize = this->size;
+    ownmem = 1;
+    for (int i = BASE; i < this->size+BASE; i++)
+      (*this)[i] = a2[i];
+  }
+
+
+
+  /// if responsible, deletes memory
+  ~ARRAY()
+  {
+    if (ownmem)
+      delete [] this->data;
+  }
+
+  /// Change logical size. If necessary, do reallocation. Keeps contents.
+  void SetSize(int nsize)
+  {
+    if (nsize > allocsize) 
+      ReSize (nsize);
+    this->size = nsize; 
+  }
+
+  /// Change physical size. Keeps logical size. Keeps contents.
+  void SetAllocSize (int nallocsize)
+  {
+    if (nallocsize > allocsize)
+      ReSize (nallocsize);
+  }
+
+
+  /// Add element at end of array. reallocation if necessary.
+  int Append (const T & el)
+  {
+    if (this->size == allocsize) 
+      ReSize (this->size+1);
+    this->data[this->size] = el;
+    this->size++;
+    return this->size;
+  }
+
+
+  /// Delete element i (0-based). Move last element to position i.
+  void Delete (int i)
+  {
+    DeleteElement (i+1);
+  }
+
+
+  /// Delete element i (1-based). Move last element to position i.
+  void DeleteElement (int i)
+  {
+#ifdef CHECK_ARRAY_RANGE
+    RangeCheck (i);
+#endif
+
+    this->data[i-1] = this->data[this->size-1];
+    this->size--;
+  }
+
+  /// Delete last element. 
+  void DeleteLast ()
+  {
+    this->size--;
+  }
+
+  /// Deallocate memory
+  void DeleteAll ()
+  {
+    if (ownmem)
+      delete [] this->data;
+    this->data = 0;
+    this->size = allocsize = 0;
+  }
+
+  /// Fill array with val
+  ARRAY & operator= (const T & val)
+  {
+    FlatArray<T, BASE>::operator= (val);
+    return *this;
+  }
+
+  /// array copy
+  ARRAY & operator= (const ARRAY & a2)
+  {
+    SetSize (a2.Size());
+    for (int i = BASE; i < this->size+BASE; i++)
+      (*this)[i] = a2[i];
+    return *this;
+  }
+
+private:
+
+  /// resize array, at least to size minsize. copy contents
+  void ReSize (int minsize)
+  {
+    int nsize = 2 * allocsize;
+    if (nsize < minsize) nsize = minsize;
+
+    if (this->data)
+      {
+	T * p = new T[nsize];
+	
+	int mins = (nsize < this->size) ? nsize : this->size; 
+	memcpy (p, this->data, mins * sizeof(T));
+
+	if (ownmem)
+	  delete [] this->data;
+	ownmem = 1;
+	this->data = p;
+      }
+    else
+      {
+	this->data = new T[nsize];
+	ownmem = 1;
+      }
+    
+    allocsize = nsize;
+  }
+};
+
+
+
+template <class T, int S> 
+class ArrayMem : public ARRAY<T>
+{
+  // T mem[S];
+  char mem[S*sizeof(T)];
+public:
+  /// Generate array of logical and physical size asize
+  explicit ArrayMem(int asize = 0)
+    : ARRAY<T> (S, static_cast<T*> (static_cast<void*>(&mem[0])))
+  {
+    this->SetSize (asize);
+  }
+
+  ArrayMem & operator= (const T & val)  
+  {
+    ARRAY<T>::operator= (val);
+    return *this;
+  }
+};
+
+
+
+
+
+
+
+
+
+
+
+///
+template <class T> class MoveableArray 
+{
+  int size;
+  int allocsize;
+  MoveableMem<T> data;
+
+public:
+
+  MoveableArray()
+  { 
+    size = allocsize = 0; 
+    data.SetName ("MoveableArray");
+  }
+
+  MoveableArray(int asize)
+    : size(asize), allocsize(asize), data(asize)
+  { ; }
+  
+  ~MoveableArray () { ; }
+
+  int Size() const { return size; }
+
+  void SetSize(int nsize)
+  {
+    if (nsize > allocsize) 
+      {
+	data.ReAlloc (nsize);
+	allocsize = nsize;
+      }
+    size = nsize;
+  }
+
+  void SetAllocSize (int nallocsize)
+  {
+    data.ReAlloc (nallocsize);
+    allocsize = nallocsize;
+  }
+
+  ///
+  T & operator[] (int i)
+  { return ((T*)data)[i]; }
+
+  ///
+  const T & operator[] (int i) const
+  { return ((const T*)data)[i]; }
+
+  ///
+  T & Elem (int i)
+  { return ((T*)data)[i-1]; }
+  
+  ///
+  const T & Get (int i) const 
+  { return ((const T*)data)[i-1]; }
+
+  ///
+  void Set (int i, const T & el)
+  { ((T*)data)[i-1] = el; }
+
+  ///
+  T & Last ()
+  { return ((T*)data)[size-1]; }
+  
+  ///
+  const T & Last () const
+  { return ((const T*)data)[size-1]; }
+  
+  ///
+  int Append (const T & el)
+  {
+    if (size == allocsize) 
+      {
+	SetAllocSize (2*allocsize+1);
+      }
+    ((T*)data)[size] = el;
+    size++;
+    return size;
+  }
+  
+  ///
+  void Delete (int i)
+  {
+    DeleteElement (i+1);
+  }
+
+  ///
+  void DeleteElement (int i)
+  {
+    ((T*)data)[i-1] = ((T*)data)[size-1];
+    size--;
+  }
+  
+  ///
+  void DeleteLast ()
+  { size--; }
+
+  ///
+  void DeleteAll ()
+  {
+    size = allocsize = 0;
+    data.Free();
+  }
+
+  ///
+  void PrintMemInfo (ostream & ost) const
+  {
+    ost << Size() << " elements of size " << sizeof(T) << " = " 
+	<< Size() * sizeof(T) << endl;
+  }
+
+  MoveableArray & operator= (const T & el)
+  {
+    for (int i = 0; i < size; i++)
+      ((T*)data)[i] = el;
+    return *this;
+  }
+
+  void SetName (char * aname)
+  {
+    data.SetName(aname);
+  }
+private:
+  ///
+  MoveableArray & operator= (MoveableArray &);
+  ///
+  MoveableArray (const MoveableArray &);
+};
+
+
+template <class T>
+inline ostream & operator<< (ostream & ost, MoveableArray<T> & a)
+{
+  for (int i = 0; i < a.Size(); i++)
+    ost << i << ": " << a[i] << endl;
+  return ost;
+}
+
+
+
+
+
+
+
+
+#endif
+
diff --git a/Netgen/libsrc/general/autoptr.hpp b/Netgen/libsrc/general/autoptr.hpp
new file mode 100644
index 0000000000..b90841408b
--- /dev/null
+++ b/Netgen/libsrc/general/autoptr.hpp
@@ -0,0 +1,31 @@
+#ifndef FILE_AUTOPTR
+#define FILE_AUTOPTR
+
+/**************************************************************************/
+/* File:   autoptr.hpp                                                    */
+/* Author: STL, Joachim Schoeberl                                         */
+/* Date:   29. Dec. 02                                                    */
+/**************************************************************************/
+
+template <typename T>
+class AutoPtr
+{
+private:
+  T * ptr;
+public:
+  typedef T* pT;
+  explicit AutoPtr (T * p = 0)  { ptr = p; }
+  ~AutoPtr () { delete ptr; }
+  
+  T & operator*() const { return *ptr; }
+  T* operator->() const { return ptr; }
+  T *& Ptr() { return ptr; }
+  T * Ptr() const { return ptr; }
+  void Reset(T * p = 0) { if (p != ptr) { delete ptr; ptr = p; } }
+  operator bool () { return ptr != 0; }
+private:
+  AutoPtr (AutoPtr &) { ; }
+  AutoPtr & operator= (AutoPtr &) { ; }
+};
+
+#endif
diff --git a/Netgen/libsrc/general/bitarray.cpp b/Netgen/libsrc/general/bitarray.cpp
new file mode 100644
index 0000000000..0d03fd5c45
--- /dev/null
+++ b/Netgen/libsrc/general/bitarray.cpp
@@ -0,0 +1,132 @@
+/**************************************************************************/
+/* File:   bitarray.cc                                                    */
+/* Autho: Joachim Schoeberl                                              */
+/* Date:   01. Jun. 95                                                    */
+/**************************************************************************/
+
+/* 
+   data type BitArray
+*/
+
+#include <mystdlib.h>
+#include <myadt.hpp>
+
+
+namespace netgen
+{
+  using namespace netgen;
+
+  BitArray :: BitArray ()
+  {
+    size = 0;
+    data = NULL;
+  }
+
+  BitArray :: BitArray (int asize)
+  {
+    size = 0;
+    data = NULL;
+    SetSize (asize);
+  }
+
+  BitArray :: ~BitArray ()
+  {
+    delete [] data;
+  }
+
+  void BitArray :: SetSize (int asize)
+  {
+    if (size == asize) return;
+    delete [] data;
+
+    size = asize;
+    data = new unsigned char [Addr (size)+1];
+  }
+
+  void BitArray :: Set ()
+  {
+    if (!size) return;
+    for (int i = 0; i <= Addr (size); i++)
+      data[i] = UCHAR_MAX;
+  }
+
+  void BitArray :: Clear ()
+  {
+    if (!size) return;
+    for (int i = 0; i <= Addr (size); i++)
+      data[i] = 0;
+  }
+
+
+
+  void BitArray :: Invert ()
+  {
+    if (!size) return;
+    for (int i = 0; i <= Addr (size); i++)
+      data[i] ^= 255;
+  }
+
+  void BitArray :: And (const BitArray & ba2)
+  {
+    if (!size) return;
+    for (int i = 0; i <= Addr (size); i++)
+      data[i] &= ba2.data[i];
+  }
+
+
+  void BitArray :: Or (const BitArray & ba2)
+  {
+    if (!size) return;
+    for (int i = 0; i <= Addr (size); i++)
+      data[i] |= ba2.data[i];
+  }
+
+
+
+
+
+
+
+
+
+
+
+  template <int BASE>
+  void BitArrayChar<BASE> :: Set ()
+  {
+    data = 1;
+  }
+
+  template <int BASE>
+  void BitArrayChar<BASE> :: Clear ()
+  {
+    data = 0;
+  }
+
+
+  template <int BASE>
+  void BitArrayChar<BASE> :: Invert ()
+  {
+    for (int i = BASE; i < data.Size()+BASE; i++)
+      data[i] = 1 - data[i];
+  }
+
+  template <int BASE>
+  void BitArrayChar<BASE> :: And (const BitArrayChar & ba2)
+  {
+    for (int i = BASE; i < data.Size()+BASE; i++)
+      data[i] &= ba2.data[i];
+  }
+  
+
+  template <int BASE>
+  void BitArrayChar<BASE> :: Or (const BitArrayChar & ba2)
+  {
+    for (int i = BASE; i < data.Size()+BASE; i++)
+      data[i] |= ba2.data[i];
+  }
+  
+
+  template class BitArrayChar<0>;
+  template class BitArrayChar<1>;
+}
diff --git a/Netgen/libsrc/general/bitarray.hpp b/Netgen/libsrc/general/bitarray.hpp
new file mode 100644
index 0000000000..380b78987e
--- /dev/null
+++ b/Netgen/libsrc/general/bitarray.hpp
@@ -0,0 +1,207 @@
+#ifndef FILE_BitArray
+#define FILE_BitArray
+
+/**************************************************************************/
+/* File:   bitarray.hpp                                                   */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Jun. 95                                                    */
+/**************************************************************************/
+
+#include <limits.h>
+
+/**
+   data type BitArray
+   
+   BitArray is a compressed array of Boolean information. By Set and Clear
+   the whole array or one bit can be set or reset, respectively. 
+   Test returns the state of the accoring bit.
+   No range checking is done.
+
+   index ranges from 0 to size-1
+*/
+class BitArray
+{
+  ///
+  INDEX size;
+  ///
+  unsigned char * data;
+
+public:
+  ///
+  BitArray ();
+  ///
+  BitArray (INDEX asize);
+  ///
+  ~BitArray ();
+
+  ///
+  void SetSize (INDEX asize);
+  ///
+  inline INDEX Size () const;
+
+  ///
+  void Set ();
+  ///
+  inline void Set (INDEX i);
+  ///
+  void Clear ();
+  ///
+  inline void Clear (INDEX i);
+  ///
+  inline int Test (INDEX i) const;
+  ///
+  void Invert ();
+  ///
+  void And (const BitArray & ba2);
+  ///
+  void Or (const BitArray & ba2);
+private:
+  ///
+  inline unsigned char Mask (INDEX i) const;
+  ///
+  inline INDEX Addr (INDEX i) const;
+
+  ///
+  BitArray & operator= (BitArray &);
+  ///
+  BitArray (const BitArray &);
+};
+
+
+
+
+
+// print bitarray
+inline ostream & operator<< (ostream & s, const BitArray & a)
+{
+  for (int i = 1; i <= a.Size(); i++)
+    {
+      s << a.Test(i);
+      if (i % 40 == 0) s << "\n";
+    }
+  if (a.Size() % 40 != 0) s << "\n";
+  return s;
+}
+
+
+
+inline
+INDEX BitArray :: Size () const
+  {
+  return size;
+  }
+
+inline
+unsigned char BitArray :: Mask (INDEX i) const
+  {
+  return char(1) << (i % CHAR_BIT);
+  }
+
+inline
+INDEX BitArray :: Addr (INDEX i) const
+  {
+  return (i / CHAR_BIT);
+  }
+
+inline
+void BitArray :: Set (INDEX i)
+  {
+  data[Addr(i)] |= Mask(i);
+  }
+
+inline
+void BitArray :: Clear (INDEX i)
+  {
+  data[Addr(i)] &= ~Mask(i);
+  }
+
+inline
+int BitArray :: Test (INDEX i) const
+  {
+  return (data[i / CHAR_BIT] & (char(1) << (i % CHAR_BIT) ) ) ? 1 : 0;
+  }
+
+
+
+
+
+
+
+
+/**
+   data type BitArrayChar
+   
+   BitArray is an array of Boolean information. By Set and Clear
+   the whole array or one bit can be set or reset, respectively. 
+   Test returns the state of the accoring bit.
+   No range checking is done.
+*/
+template <int BASE = 1>
+class BitArrayChar
+{
+  ///
+  ARRAY<char,BASE> data;
+
+public:
+  ///
+  BitArrayChar ()
+  { ; }
+  ///
+  BitArrayChar (int asize)
+    : data(asize)
+  { ; }
+  ///
+  ~BitArrayChar ()
+  { ; }
+
+  ///
+  void SetSize (int asize)
+  { data.SetSize(asize); }
+
+  ///
+  inline int Size () const
+  { return data.Size(); }
+
+  ///
+  void Set ();
+  ///
+  inline void Set (int i)
+  { data[i] = 1; }
+  ///
+  void Clear ();
+  ///
+  inline void Clear (int i)
+  { data[i] = 0; }
+  ///
+  inline int Test (int i) const
+  { return data[i]; }
+  ///
+  void Invert ();
+  ///
+  void And (const BitArrayChar & ba2);
+  ///
+  void Or (const BitArrayChar & ba2);
+private:
+  ///  copy bitarray is not supported
+  BitArrayChar & operator= (BitArrayChar &) { return *this; }
+  ///  copy bitarray is not supported
+  BitArrayChar (const BitArrayChar &) { ; }
+};
+
+
+
+
+template <int BASE>
+inline ostream & operator<< (ostream & s, const BitArrayChar<BASE> & a)
+{
+  for (int i = 0; i < a.Size(); i++)
+    {
+      s << a.Test(i);
+      if (i % 40 == 0) s << "\n";
+    }
+  if (a.Size() % 40 != 0) s << "\n";
+  return s;
+}
+
+
+#endif
diff --git a/Netgen/libsrc/general/dynamicmem.cpp b/Netgen/libsrc/general/dynamicmem.cpp
new file mode 100644
index 0000000000..9cd1f3ad62
--- /dev/null
+++ b/Netgen/libsrc/general/dynamicmem.cpp
@@ -0,0 +1,117 @@
+#include <iostream>
+#include <iomanip>
+
+#include <myadt.hpp>
+using namespace std;
+
+namespace netgen
+{
+
+BaseDynamicMem * BaseDynamicMem::first = 0;
+BaseDynamicMem * BaseDynamicMem::last = 0;
+
+
+BaseDynamicMem :: BaseDynamicMem ()
+{
+  prev = last;
+  next = 0;
+
+  if (last) last->next = this;
+  last = this;
+  if (!first) first = this;
+
+  size = 0;
+  ptr = 0;
+  name = 0;
+}
+ 
+BaseDynamicMem :: ~BaseDynamicMem ()
+{
+  Free();
+
+  if (next) next->prev = prev;
+  else last = prev;
+  if (prev) prev->next = next;
+  else first = next;
+
+  delete name;
+}
+
+void BaseDynamicMem :: SetName (const char * aname)
+{
+  delete name;
+  if (aname)
+    {
+      name = new char[strlen(aname)+1];
+      strcpy (name, aname);
+    }
+}
+
+
+void BaseDynamicMem :: Alloc (size_t s)
+{
+  size = s;
+  // ptr = new char[s];
+  ptr = (char*)malloc (s);
+}
+
+void BaseDynamicMem :: ReAlloc (size_t s)
+{
+  if (size == s) return;
+
+  char * old = ptr;
+  // ptr = new char[s];
+  ptr = (char*)malloc(s);
+  memmove (ptr, old, (s < size) ? s : size);
+  // delete old;
+  free (old);
+  size = s;
+}
+
+void BaseDynamicMem :: Free ()
+{
+  // delete ptr;
+  free (ptr);
+  ptr = 0;
+}
+
+void BaseDynamicMem :: Swap (BaseDynamicMem & m2)
+{
+  int hi;
+  char * cp;
+  hi = size; size  = m2.size; m2.size = hi;
+  cp = ptr; ptr = m2.ptr; m2.ptr = cp;
+  cp = name; name = m2.name; m2.name = cp;
+}
+
+
+void BaseDynamicMem :: Print ()
+{
+  cout << "****************** Dynamic Mem Report ****************" << endl;
+  BaseDynamicMem * p = first;
+  int mem = 0;
+  int cnt = 0;
+  while (p)
+    {
+      mem += p->size;
+      cnt++;
+
+      cout << setw(10) << p->size << " Bytes";
+      if (p->name)
+	cout << " in block " << p->name;
+      cout << endl;
+
+      p = p->next;
+    }
+
+  if (mem > 100000000)
+    cout << "memory in dynamic memory: " << mem/1048576 << " MB" << endl;
+  else if (mem > 100000)
+    cout << "memory in dynamic memory: " << mem/1024 << " kB" << endl;
+  else
+    cout << "memory in dynamic memory: " << mem << " Bytes" << endl;
+    cout << "number of blocks:         " << cnt << endl;
+  //  cout << "******************************************************" << endl;
+}
+
+}
diff --git a/Netgen/libsrc/general/dynamicmem.hpp b/Netgen/libsrc/general/dynamicmem.hpp
new file mode 100644
index 0000000000..501020988e
--- /dev/null
+++ b/Netgen/libsrc/general/dynamicmem.hpp
@@ -0,0 +1,94 @@
+#ifndef FILE_DYNAMICMEM
+#define FILE_DYNAMICMEM
+
+/**************************************************************************/
+/* File:   dynamicmem.hpp                                                 */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   12. Feb. 2003                                                  */
+/**************************************************************************/
+
+
+
+
+class BaseDynamicMem
+{
+private:
+  static BaseDynamicMem *first, *last;
+
+  BaseDynamicMem *prev, *next;
+  size_t size;
+  char * ptr;
+  char * name;
+
+protected:
+  BaseDynamicMem ();
+  ~BaseDynamicMem ();
+  void Alloc (size_t s);
+  void ReAlloc (size_t s);
+  void Free ();
+  char * Ptr() { return ptr; }
+  const char * Ptr() const { return ptr; }
+  void Swap (BaseDynamicMem & m2);
+public:
+  void SetName (const char * aname);
+  static void Print ();
+};
+
+
+template <typename T>
+class DynamicMem : public BaseDynamicMem
+{
+public:
+  DynamicMem ()
+    : BaseDynamicMem () 
+  {
+    ;
+  }
+  DynamicMem (size_t s)
+    : BaseDynamicMem () 
+  {
+    Alloc (s);
+  }
+  void Alloc (size_t s)
+  {
+    BaseDynamicMem::Alloc (sizeof(T) * s);
+  }
+  void ReAlloc (size_t s)
+  {
+    BaseDynamicMem::ReAlloc (sizeof(T) * s);
+  }
+  void Free ()
+  {
+    BaseDynamicMem::Free ();
+  }
+
+  const T * Ptr() const
+  {
+    return reinterpret_cast<const T*> (BaseDynamicMem::Ptr());
+  }
+
+  T * Ptr()
+  {
+    return reinterpret_cast<T*> (BaseDynamicMem::Ptr());
+  }
+
+  operator const T* () const
+  {
+    return reinterpret_cast<const T*> (BaseDynamicMem::Ptr());
+  }
+
+  operator T* () 
+  {
+    return reinterpret_cast<T*> (BaseDynamicMem::Ptr());
+  }
+
+  void Swap (DynamicMem<T> & m2)
+  {
+    BaseDynamicMem::Swap (m2);
+  }
+protected:
+  DynamicMem (const DynamicMem & m);
+  DynamicMem & operator= (const DynamicMem & m);
+};
+
+#endif
diff --git a/Netgen/libsrc/general/flags.cpp b/Netgen/libsrc/general/flags.cpp
new file mode 100644
index 0000000000..962c8152e8
--- /dev/null
+++ b/Netgen/libsrc/general/flags.cpp
@@ -0,0 +1,330 @@
+/**************************************************************************/
+/* File:   flags.cc                                                       */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   10. Oct. 96                                                    */
+/**************************************************************************/
+
+/* 
+   Datatype Flags
+*/
+
+#include <mystdlib.h>
+#include <myadt.hpp>
+
+namespace netgen
+{
+  using namespace netgen;
+
+  Flags :: Flags ()
+  {
+    ;
+  }
+  
+  Flags :: ~Flags ()
+  {
+    DeleteFlags ();
+  }
+  
+  void Flags :: DeleteFlags ()
+  {
+    int i;
+
+    for (i = 1; i <= strflags.Size(); i++)
+      delete strflags.Elem(i);
+    strflags.DeleteAll();
+    numflags.DeleteAll();
+    defflags.DeleteAll();
+    strlistflags.DeleteAll();
+    numlistflags.DeleteAll();
+  }
+  
+  void Flags :: SetFlag (const char * name, const char * val)
+  {
+    char * hval = new char[strlen (val) + 1];
+    strcpy (hval, val);
+    strflags.Set (name, hval);
+  }
+  
+  void Flags :: SetFlag (const char * name, double val)
+  {
+    numflags.Set (name, val);
+  }
+  
+  void Flags :: SetFlag (const char * name)
+  {
+    defflags.Set (name, 1);
+  }
+
+
+  void Flags :: SetFlag (const char * name, const ARRAY<char*> & val)
+  {
+    ARRAY<char*> * strarray = new ARRAY<char*>;
+    for (int i = 1; i <= val.Size(); i++)
+      {
+	strarray->Append (new char[strlen(val.Get(i))+1]);
+	strcpy (strarray->Last(), val.Get(i));
+      }
+    strlistflags.Set (name, strarray);
+  }
+
+  void Flags :: SetFlag (const char * name, const ARRAY<double> & val)
+  {
+    ARRAY<double> * numarray = new ARRAY<double>;
+    for (int i = 1; i <= val.Size(); i++)
+      numarray->Append (val.Get(i));
+    numlistflags.Set (name, numarray);
+  }
+
+
+
+
+  
+  const char * 
+  Flags :: GetStringFlag (const char * name, const char * def) const
+  {
+    if (strflags.Used (name))
+      return strflags.Get(name);
+    else
+      return def;
+  }
+
+  double Flags :: GetNumFlag (const char * name, double def) const
+  {
+    if (numflags.Used (name))
+      return numflags.Get(name);
+    else
+      return def;
+  }
+  
+  const double * Flags :: GetNumFlagPtr (const char * name) const
+  {
+    if (numflags.Used (name))
+      return & ((SYMBOLTABLE<double>&)numflags).Elem(name);
+    else
+      return NULL;
+  }
+  
+  double * Flags :: GetNumFlagPtr (const char * name) 
+  {
+    if (numflags.Used (name))
+      return & ((SYMBOLTABLE<double>&)numflags).Elem(name);
+    else
+      return NULL;
+  }
+  
+  int Flags :: GetDefineFlag (const char * name) const
+  {
+    return defflags.Used (name);
+  }
+
+
+  const ARRAY<char*> & 
+  Flags :: GetStringListFlag (const char * name) const
+  {
+    if (strlistflags.Used (name))
+      return *strlistflags.Get(name);
+    else
+      {
+	static ARRAY<char*> hstra(0);
+	return hstra;
+      }
+  }
+
+  const ARRAY<double> & 
+  Flags ::GetNumListFlag (const char * name) const
+  {
+    if (numlistflags.Used (name))
+      return *numlistflags.Get(name);
+    else
+      {
+	static ARRAY<double> hnuma(0);
+	return hnuma;
+      }
+  }
+
+
+  int Flags :: StringFlagDefined (const char * name) const
+  {
+    return strflags.Used (name);
+  }
+
+  int Flags :: NumFlagDefined (const char * name) const
+  {
+    return numflags.Used (name);
+  }
+
+  int Flags :: StringListFlagDefined (const char * name) const
+  {
+    return strlistflags.Used (name);
+  }
+
+  int Flags :: NumListFlagDefined (const char * name) const
+  {
+    return numlistflags.Used (name);
+  }
+
+
+  void Flags :: SaveFlags (const char * filename) const 
+  {
+    int i;
+    ofstream outfile (filename);
+  
+    for (i = 1; i <= strflags.Size(); i++)
+      outfile << strflags.GetName(i) << " = " << strflags.Get(i) << endl;
+    for (i = 1; i <= numflags.Size(); i++)
+      outfile << numflags.GetName(i) << " = " << numflags.Get(i) << endl;
+    for (i = 1; i <= defflags.Size(); i++)
+      outfile << defflags.GetName(i) << endl;
+  }
+ 
+
+
+  void Flags :: PrintFlags (ostream & ost) const 
+  {
+    int i;
+  
+    for (i = 1; i <= strflags.Size(); i++)
+      ost << strflags.GetName(i) << " = " << strflags.Get(i) << endl;
+    for (i = 1; i <= numflags.Size(); i++)
+      ost << numflags.GetName(i) << " = " << numflags.Get(i) << endl;
+    for (i = 1; i <= defflags.Size(); i++)
+      ost << defflags.GetName(i) << endl;
+  }
+ 
+
+  void Flags :: LoadFlags (const char * filename) 
+  {
+    char name[100], str[100];
+    char ch;
+    double val;
+    ifstream infile(filename);
+
+    //  (*logout) << "Load flags from " << filename << endl << endl;
+    while (infile.good())
+      {
+	infile >> name;
+	if (strlen (name) == 0) break;
+
+	if (name[0] == '/' && name[1] == '/')
+	  {
+	    //	  (*logout) << "comment: ";
+	    ch = 0;
+	    while (ch != '\n' && infile.good())
+	      {
+		ch = infile.get();
+		//	      (*logout) << ch;
+	      }
+	    continue;
+	  }
+
+	//      (*logout)  << name;
+	ch = 0;
+	infile >> ch;
+	if (ch != '=')
+	  {
+	    //	  (*logout) << endl;
+	    infile.putback (ch);
+	    SetFlag (name);
+	  }
+	else
+	  {
+	    infile >> val;
+	    if (!infile.good())
+	      {
+		infile.clear();
+		infile >> str;
+		SetFlag (name, str);
+		//	      (*logout) << " = " << str << endl;
+	      }
+	    else
+	      {
+		SetFlag (name, val);
+		//	      (*logout) << " = " << val << endl;
+	      }
+	  }
+      }
+    //  (*logout) << endl;
+  }
+
+
+  void Flags :: SetCommandLineFlag (const char * st)
+  {
+    //  cout << "clflag = " << st << endl;
+    istringstream inst( (char *)st);
+    // istrstream defined with char *  (not const char *  ?????)
+
+    char name[100];
+    double val;
+
+
+    if (st[0] != '-')
+      {
+	cerr << "flag must start with '-'" << endl;
+	return;
+      }
+  
+    const char * pos = strchr (st, '=');
+  
+    if (!pos)
+      {
+	//      (cout) << "Add def flag: " << st+1 << endl;
+	SetFlag (st+1);
+      }
+    else
+      {
+	//      cout << "pos = " << pos << endl;
+
+	strncpy (name, st+1, (pos-st)-1);
+	name[pos-st-1] = 0;
+
+	//      cout << "name = " << name << endl;
+
+	pos++;
+	char * endptr = NULL;
+
+	val = strtod (pos, &endptr);
+
+	//      cout << "val = " << val << endl;
+
+	if (endptr == pos)
+	  {
+	    //	  (cout) << "Add String Flag: " << name << " = " << pos << endl;
+	    SetFlag (name, pos);
+	  }
+	else
+	  {
+	    //	  (cout) << "Add Num Flag: " << name << " = " << val << endl;
+	    SetFlag (name, val);
+	  }
+      }
+
+
+    /*
+      inst >> name;
+      (*mycout) << "name = " << name << endl;
+
+      ch = 0;
+      inst >> ch;
+      if (ch != '=')
+      {
+      SetFlag (name);
+      }
+      else
+      {
+      inst >> val;
+      if (!inst.good())
+      {
+      inst.clear();
+      inst >> str;
+      SetFlag (name, str);
+      (*mycout) << "str = " << str << endl;
+      }
+      else
+      {
+      SetFlag (name, val);
+      (*mycout) << "val = " << val << endl;
+      }
+      }
+    */
+  }
+}
diff --git a/Netgen/libsrc/general/flags.hpp b/Netgen/libsrc/general/flags.hpp
new file mode 100644
index 0000000000..7c62f7815b
--- /dev/null
+++ b/Netgen/libsrc/general/flags.hpp
@@ -0,0 +1,83 @@
+#ifndef FILE_FLAGS
+#define FILE_FLAGS
+
+
+/**************************************************************************/
+/* File:   flags.hh                                                       */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   10. Oct. 96                                                   */
+/**************************************************************************/
+
+/** 
+   Flag - Table.
+   A flag table maintains string variables, numerical 
+   variables and boolean flags.
+*/
+class Flags 
+{
+  ///
+  SYMBOLTABLE<char *> strflags;
+  ///
+  SYMBOLTABLE<double> numflags;
+  ///
+  SYMBOLTABLE<int> defflags;
+  ///
+  SYMBOLTABLE<ARRAY<char*>*> strlistflags;
+  ///
+  SYMBOLTABLE<ARRAY<double>*> numlistflags;
+public:
+  ///
+  Flags ();
+  ///
+  ~Flags ();
+  
+  /// Deletes all flags
+  void DeleteFlags ();
+  /// Sets string flag, overwrite if exists
+  void SetFlag (const char * name, const char * val);
+  /// Sets numerical flag, overwrite if exists
+  void SetFlag (const char * name, double val);
+  /// Sets boolean flag
+  void SetFlag (const char * name);
+  /// Sets string arary falg
+  void SetFlag (const char * name, const ARRAY<char*> & val);
+  /// Sets double array flag
+  void SetFlag (const char * name, const ARRAY<double> & val);
+  
+  /// Save flags to file
+  void SaveFlags (const char * filename) const;
+  /// write flags to stream
+  void PrintFlags (ostream & ost) const;
+  /// Load flags from file
+  void LoadFlags (const char * filename);
+  /// set flag of form -name=hello -val=0.5 -defined
+  void SetCommandLineFlag (const char * st);
+
+  /// Returns string flag, default value if not exists
+  const char * GetStringFlag (const char * name, const char * def) const;
+  /// Returns numerical flag, default value if not exists
+  double GetNumFlag (const char * name, double def) const;
+  /// Returns address of numerical flag, null if not exists
+  const double * GetNumFlagPtr (const char * name) const;
+  /// Returns address of numerical flag, null if not exists
+  double * GetNumFlagPtr (const char * name);
+  /// Returns boolean flag
+  int GetDefineFlag (const char * name) const;
+  /// Returns string list flag, empty array if not exist
+  const ARRAY<char*> & GetStringListFlag (const char * name) const;
+  /// Returns num list flag, empty array if not exist
+  const ARRAY<double> & GetNumListFlag (const char * name) const;
+
+
+  /// Test, if string flag is defined
+  int StringFlagDefined (const char * name) const;
+  /// Test, if num flag is defined
+  int NumFlagDefined (const char * name) const;
+  /// Test, if string list flag is defined
+  int StringListFlagDefined (const char * name) const;
+  /// Test, if num list flag is defined
+  int NumListFlagDefined (const char * name) const;
+};
+  
+#endif
+
diff --git a/Netgen/libsrc/general/hashtabl.cpp b/Netgen/libsrc/general/hashtabl.cpp
new file mode 100644
index 0000000000..3081298e24
--- /dev/null
+++ b/Netgen/libsrc/general/hashtabl.cpp
@@ -0,0 +1,293 @@
+/**************************************************************************/
+/* File:   hashtabl.cpp                                                   */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Jun. 95                                                    */
+/**************************************************************************/
+
+/* 
+   Abstract data type HASHTABLE
+*/
+
+#include <mystdlib.h>
+#include <myadt.hpp>
+
+namespace netgen
+{
+  using namespace netgen;
+
+  void INDEX_4 :: Sort ()
+  {
+    if (i[0] > i[1]) Swap (i[0], i[1]);
+    if (i[2] > i[3]) Swap (i[2], i[3]);
+    if (i[0] > i[2]) Swap (i[0], i[2]);
+    if (i[1] > i[3]) Swap (i[1], i[3]);
+    if (i[1] > i[2]) Swap (i[1], i[2]);
+  }
+
+
+
+  void INDEX_4Q :: Sort ()
+  {
+    if (min2 (i[1], i[2]) < min2 (i[0], i[3]))
+      { Swap (i[0], i[1]); Swap (i[2], i[3]);}
+    if (i[3] < i[0])
+      { Swap (i[0], i[3]); Swap (i[1], i[2]);}
+    if (i[3] < i[1])
+      { Swap (i[1], i[3]); }
+  }
+
+
+  ostream & operator<<(ostream  & s, const INDEX_2 & i2)
+  {
+    return s << i2.I1() << ", " << i2.I2();
+  }
+
+  ostream & operator<<(ostream  & s, const INDEX_3 & i3)
+  {
+    return s << i3.I1() << ", " << i3.I2() << ", " << i3.I3();
+  }
+
+  ostream & operator<<(ostream  & s, const INDEX_4 & i4)
+  {
+    return s << i4.I1() << ", " << i4.I2() << ", " << i4.I3() << ", " << i4.I4();
+  }
+
+  ostream & operator<<(ostream  & s, const INDEX_4Q & i4)
+  {
+    return s << i4.I1() << ", " << i4.I2() << ", " << i4.I3() << ", " << i4.I4();
+  }
+
+
+  int BASE_INDEX_HASHTABLE :: Position (int bnr, const INDEX & ind) const
+  {
+    int i;
+    for (i = 1; i <= hash.EntrySize (bnr); i++)
+      if (hash.Get(bnr, i) == ind)
+	return i;
+    return 0;
+  }
+
+
+
+  /*
+  int BASE_INDEX_2_HASHTABLE :: Position (int bnr, const INDEX_2 & ind) const
+  {
+    int i;
+    for (i = 1; i <= hash.EntrySize (bnr); i++)
+      if (hash.Get(bnr, i) == ind)
+	return i;
+    return 0;
+  }
+  */  
+
+  void BASE_INDEX_2_HASHTABLE :: PrintStat (ostream & ost) const
+  {
+    int n = hash.Size();
+    int i;
+    int sumn = 0, sumnn = 0;
+
+    for (i = 1; i <= n; i++)
+      {
+	sumn += hash.EntrySize(i);
+	sumnn += sqr (hash.EntrySize(i));
+      }
+
+    ost << "Hashtable: " << endl
+	<< "size             : " << n << endl
+	<< "elements per row : " << (double(sumn) / double(n)) << endl
+	<< "av. acces time   : " 
+	<< (sumn ? (double (sumnn) / double(sumn)) : 0) << endl;
+  }
+
+
+  /*
+    int BASE_INDEX_3_HASHTABLE :: Position (int bnr, const INDEX_3 & ind) const
+    {
+    int i;
+    const INDEX_3 * pi = &hash.Get(bnr, 1);
+    int n = hash.EntrySize(bnr);
+    for (i = 1; i <= n; ++i, ++pi)
+    {
+    if (*pi == ind)
+    return i;
+    }
+
+    return 0;
+    }
+  */
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  BASE_INDEX_2_CLOSED_HASHTABLE ::
+  BASE_INDEX_2_CLOSED_HASHTABLE (int size)
+    : hash(size)
+  {
+    hash.SetName ("i2-hashtable, hash");
+
+    invalid = -1;
+    int i;
+    for (i = 1; i <= size; i++)
+      hash.Elem(i).I1() = invalid;
+  }
+
+  void BASE_INDEX_2_CLOSED_HASHTABLE ::
+  BaseSetSize (int size)
+  {
+    int i;
+    hash.SetSize(size);
+    for (i = 1; i <= size; i++)
+      hash.Elem(i).I1() = invalid;
+  }
+
+
+  int BASE_INDEX_2_CLOSED_HASHTABLE ::
+  Position2 (const INDEX_2 & ind) const
+  {
+    int i;
+
+    i = HashValue(ind);
+    while (1)
+      {
+	i++;
+	if (i > hash.Size()) i = 1;
+	if (hash.Get(i) == ind) return i;
+	if (hash.Get(i).I1() == invalid) return 0;
+      }
+  }
+
+
+
+  int BASE_INDEX_2_CLOSED_HASHTABLE ::
+  PositionCreate2 (const INDEX_2 & ind, int & apos) 
+  {
+    int i;
+
+    i = HashValue(ind);
+    while (1)
+      {
+	i++;
+	if (i > hash.Size()) i = 1;
+	if (hash.Get(i) == ind) 
+	  {
+	    apos = i;
+	    return 0;
+	  }
+	if (hash.Get(i).I1() == invalid) 
+	  {
+	    hash.Elem(i) = ind;
+	    apos = i;
+	    return 1;
+	  }
+      }
+  }
+
+  int BASE_INDEX_2_CLOSED_HASHTABLE :: UsedElements () const
+  {
+    int i, n = hash.Size();
+    int cnt = 0;
+    for (i = 1; i <= n; i++)
+      if (hash.Get(i).I1() != invalid)
+	cnt++;
+    return cnt;
+  }
+
+
+
+
+
+
+
+
+
+
+
+  BASE_INDEX_3_CLOSED_HASHTABLE ::
+  BASE_INDEX_3_CLOSED_HASHTABLE (int size)
+    : hash(size)
+  {
+    hash.SetName ("i3-hashtable, hash");
+
+    invalid = -1;
+    int i;
+    for (i = 1; i <= size; i++)
+      hash.Elem(i).I1() = invalid;
+  }
+
+  void BASE_INDEX_3_CLOSED_HASHTABLE ::
+  BaseSetSize (int size)
+  {
+    int i;
+    hash.SetSize(size);
+    for (i = 1; i <= size; i++)
+      hash.Elem(i).I1() = invalid;
+  }
+
+
+  int BASE_INDEX_3_CLOSED_HASHTABLE ::
+  Position2 (const INDEX_3 & ind) const
+  {
+    int i;
+
+    i = HashValue(ind);
+    while (1)
+      {
+	i++;
+	if (i > hash.Size()) i = 1;
+	if (hash.Get(i) == ind) return i;
+	if (hash.Get(i).I1() == invalid) return 0;
+      }
+  }
+
+
+
+  int BASE_INDEX_3_CLOSED_HASHTABLE ::
+  PositionCreate2 (const INDEX_3 & ind, int & apos) 
+  {
+    int i;
+
+    i = HashValue(ind);
+    while (1)
+      {
+	i++;
+	if (i > hash.Size()) i = 1;
+	if (hash.Get(i) == ind) 
+	  {
+	    apos = i;
+	    return 0;
+	  }
+	if (hash.Get(i).I1() == invalid) 
+	  {
+	    hash.Elem(i) = ind;
+	    apos = i;
+	    return 1;
+	  }
+      }
+  }
+
+  int BASE_INDEX_3_CLOSED_HASHTABLE :: UsedElements () const
+  {
+    int i, n = hash.Size();
+    int cnt = 0;
+    for (i = 1; i <= n; i++)
+      if (hash.Get(i).I1() != invalid)
+	cnt++;
+    return cnt;
+  }
+
+
+}
+
diff --git a/Netgen/libsrc/general/hashtabl.hpp b/Netgen/libsrc/general/hashtabl.hpp
new file mode 100644
index 0000000000..99d3257b84
--- /dev/null
+++ b/Netgen/libsrc/general/hashtabl.hpp
@@ -0,0 +1,931 @@
+#ifndef FILE_HASHTABL
+#define FILE_HASHTABL
+
+/**************************************************************************/
+/* File:   hashtabl.hh                                                    */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Jun. 95                                                    */
+/**************************************************************************/
+
+/**
+   Abstract data type HASHTABLE.
+   Hash is done by one INDEX
+*/
+class BASE_INDEX_HASHTABLE
+{
+protected:
+  /// keys are stored in this table
+  TABLE<INDEX> hash;
+  
+public:
+  ///
+  BASE_INDEX_HASHTABLE (int size)
+    : hash (size) { };
+  
+protected:
+  ///
+  int HashValue (const INDEX & ind) const
+    {
+      return ind % hash.Size() + 1;
+    }
+
+  ///
+  int Position (int bnr, const INDEX & ind) const;
+};
+
+///
+template <class T>
+class INDEX_HASHTABLE : private BASE_INDEX_HASHTABLE
+{
+  ///
+  TABLE<T> cont;
+  
+public:
+  ///
+  inline INDEX_HASHTABLE (int size);
+  ///
+  inline void Set (const INDEX & hash, const T & acont);
+  ///
+  inline const T & Get (const INDEX & ahash) const;
+  ///
+  inline int Used (const INDEX & ahash) const;
+  ///
+  inline int GetNBags () const;
+  ///
+  inline int GetBagSize (int bnr) const;
+  ///
+  inline void GetData (int bnr, int colnr, INDEX & ahash, T & acont) const;
+
+  ///
+  inline void PrintMemInfo (ostream & ost) const;
+};
+
+
+
+
+
+
+
+
+
+
+
+///
+class BASE_INDEX_2_HASHTABLE
+{
+protected:
+  ///
+  TABLE<INDEX_2> hash;
+  
+public:
+  ///
+  BASE_INDEX_2_HASHTABLE (int size)
+    : hash (size) { };
+
+  ///
+  void PrintStat (ostream & ost) const;
+  void BaseSetSize(int s) {hash.SetSize(s);}
+protected:
+  ///
+  int HashValue (const INDEX_2 & ind) const
+    {
+      return (ind.I1() + ind.I2()) % hash.Size() + 1;
+    }
+  ///
+  int Position (int bnr, const INDEX_2 & ind) const
+  {
+    int i;
+    for (i = 1; i <= hash.EntrySize (bnr); i++)
+      if (hash.Get(bnr, i) == ind)
+	return i;
+    return 0;
+  }
+};
+
+
+///
+template <class T>
+class INDEX_2_HASHTABLE : public BASE_INDEX_2_HASHTABLE
+{
+  ///
+  TABLE<T> cont;
+  
+public:
+  ///
+  inline INDEX_2_HASHTABLE (int size);
+  ///
+  void SetSize(int s) {cont.SetSize(s); BaseSetSize(s);}
+  ///
+  inline void Set (const INDEX_2 & ahash, const T & acont)
+    {
+      int bnr = HashValue (ahash);
+      int pos = Position (bnr, ahash);
+      if (pos)
+	cont.Set (bnr, pos, acont);
+      else
+	{
+	  hash.Add1 (bnr, ahash);
+	  cont.Add1 (bnr, acont);
+	}    
+    }
+  ///
+  inline const T & Get (const INDEX_2 & ahash) const;
+  ///
+  inline int Used (const INDEX_2 & ahash) const;
+  ///
+  inline int GetNBags () const;
+  ///
+  inline int GetBagSize (int bnr) const;
+  ///
+  inline void GetData (int bnr, int colnr, 
+		       INDEX_2 & ahash, T & acont) const;
+  ///
+  inline void PrintMemInfo (ostream & ost) const;
+};
+
+
+
+///
+class BASE_INDEX_3_HASHTABLE
+{
+protected:
+  ///
+  TABLE<INDEX_3> hash;
+
+public:
+  ///
+  BASE_INDEX_3_HASHTABLE (int size)
+    : hash (size) { };
+
+protected:
+  ///
+  int HashValue (const INDEX_3 & ind) const
+    {
+      return (ind.I1() + ind.I2() + ind.I3()) % hash.Size() + 1;
+    }
+
+  ///
+  int Position (int bnr, const INDEX_3 & ind) const
+  {
+    const INDEX_3 * pi = &hash.Get(bnr, 1);
+    int n = hash.EntrySize(bnr);
+    for (int i = 1; i <= n; ++i, ++pi)
+      {
+	if (*pi == ind)
+	return i;
+      }
+    
+    return 0;
+  }
+
+
+};
+
+
+///
+template <class T>
+class INDEX_3_HASHTABLE : private BASE_INDEX_3_HASHTABLE
+{
+  ///
+  TABLE<T> cont;
+
+public:
+  ///
+  inline INDEX_3_HASHTABLE (int size);
+  ///
+  inline void Set (const INDEX_3 & ahash, const T & acont);
+  ///
+  inline const T & Get (const INDEX_3 & ahash) const;
+  ///
+  inline int Used (const INDEX_3 & ahash) const;
+  ///
+  inline int GetNBags () const;
+  ///
+  inline int GetBagSize (int bnr) const;
+  ///
+  inline void SetData (int bnr, int colnr, const INDEX_3 & ahash, const T & acont);
+  ///
+  inline void GetData (int bnr, int colnr, INDEX_3 & ahash, T & acont) const;
+  /// returns position, if not existing, will create (create == return 1)
+  inline int PositionCreate (const INDEX_3 & ahash, int & bnr, int & colnr);
+  ///
+  inline void SetSize (int size);
+
+  ///
+  inline void PrepareSet (const INDEX_3 & ahash);
+  ///
+  inline void AllocateElements ();
+
+  ///
+  inline void PrintMemInfo (ostream & ost) const;
+  ///
+  inline void DeleteData ();
+};
+
+
+
+
+
+
+
+
+/// Closed Hashing HT
+
+class BASE_INDEX_2_CLOSED_HASHTABLE
+{
+protected:
+  ///
+  MoveableArray<INDEX_2> hash;
+  ///
+  int invalid;
+public:
+  ///
+  BASE_INDEX_2_CLOSED_HASHTABLE (int size);
+
+  int Size() const { return hash.Size(); }
+  int UsedPos (int pos) const { return ! (hash.Get(pos).I1() == invalid); }
+  int UsedElements () const;
+
+  ///
+  int HashValue (const INDEX_2 & ind) const
+    {
+      return (ind.I1() + 71 * ind.I2()) % hash.Size() + 1;
+    }
+
+
+  int Position (const INDEX_2 & ind) const
+  {
+    int i = HashValue(ind);
+    while (1)
+      {
+	if (hash.Get(i) == ind) return i;
+	if (hash.Get(i).I1() == invalid) return 0;
+	i++;
+	if (i > hash.Size()) i = 1;
+      }
+    /*
+    int pos = HashValue (ind);
+    if (hash.Get(pos) == ind) return pos;
+    return Position2 (ind);
+    */
+  }
+
+  // returns 1, if new postion is created
+  int PositionCreate (const INDEX_2 & ind, int & apos)
+  {
+    int i = HashValue (ind);
+    if (hash.Get(i) == ind) 
+      {
+	apos = i;
+	return 0;
+      }
+    if (hash.Get(i).I1() == invalid)
+      {
+	hash.Elem(i) = ind; 
+	apos = i;
+	return 1;
+      }
+    return PositionCreate2 (ind, apos);    
+  }
+
+protected:
+  ///
+
+  int Position2 (const INDEX_2 & ind) const;
+  int PositionCreate2 (const INDEX_2 & ind, int & apos);
+  void BaseSetSize (int asize);
+};
+
+
+template <class T>
+class INDEX_2_CLOSED_HASHTABLE : public BASE_INDEX_2_CLOSED_HASHTABLE
+{
+  ///
+  MoveableArray<T> cont;
+
+public:
+  ///
+  inline INDEX_2_CLOSED_HASHTABLE (int size);
+  ///
+  inline void Set (const INDEX_2 & ahash, const T & acont);
+  ///
+  inline const T & Get (const INDEX_2 & ahash) const;
+  ///
+  inline int Used (const INDEX_2 & ahash) const;
+  ///
+  inline void SetData (int pos, const INDEX_2 & ahash, const T & acont);
+  ///
+  inline void GetData (int pos, INDEX_2 & ahash, T & acont) const;
+  ///
+  inline void SetData (int pos, const T & acont);
+  ///
+  inline void GetData (int pos, T & acont) const;
+  ///
+  inline void SetSize (int size);
+  ///
+  inline void PrintMemInfo (ostream & ost) const;
+  ///
+  inline void DeleteData ()
+  { SetSize (cont.Size()); }
+
+  void SetName (const char * aname)
+  {
+    cont.SetName(aname);
+    hash.SetName(aname);
+  }
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+class BASE_INDEX_3_CLOSED_HASHTABLE
+{
+protected:
+  ///
+  MoveableArray<INDEX_3> hash;
+  ///
+  int invalid;
+public:
+  ///
+  BASE_INDEX_3_CLOSED_HASHTABLE (int size);
+
+  int Size() const { return hash.Size(); }
+  int UsedPos (int pos) const { return ! (hash.Get(pos).I1() == invalid); }
+  int UsedElements () const;
+
+  ///
+  int HashValue (const INDEX_3 & ind) const
+    {
+      return (ind.I1() + 15 * ind.I2() + 41 * ind.I3()) % hash.Size() + 1;
+    }
+
+  int Position (const INDEX_3 & ind) const
+  {
+    int pos = HashValue (ind);
+    if (hash.Get(pos) == ind) return pos;
+    return Position2 (ind);
+  }
+
+  // returns 1, if new postion is created
+  int PositionCreate (const INDEX_3 & ind, int & apos)
+  {
+    int i = HashValue (ind);
+    if (hash.Get(i) == ind) 
+      {
+	apos = i;
+	return 0;
+      }
+    if (hash.Get(i).I1() == invalid)
+      {
+	hash.Elem(i) = ind; 
+	apos = i;
+	return 1;
+      }
+    return PositionCreate2 (ind, apos);    
+  }
+
+
+protected:
+  ///
+
+  int Position2 (const INDEX_3 & ind) const;
+  int PositionCreate2 (const INDEX_3 & ind, int & apos);
+  void BaseSetSize (int asize);
+};
+
+
+template <class T>
+class INDEX_3_CLOSED_HASHTABLE : public BASE_INDEX_3_CLOSED_HASHTABLE
+{
+  ///
+  MoveableArray<T> cont;
+
+public:
+  ///
+  inline INDEX_3_CLOSED_HASHTABLE (int size);
+  ///
+  inline void Set (const INDEX_3 & ahash, const T & acont);
+  ///
+  inline const T & Get (const INDEX_3 & ahash) const;
+  ///
+  inline int Used (const INDEX_3 & ahash) const;
+  ///
+  inline void SetData (int pos, const INDEX_3 & ahash, const T & acont);
+  ///
+  inline void GetData (int pos, INDEX_3 & ahash, T & acont) const;
+  ///
+  inline void SetData (int pos, const T & acont);
+  ///
+  inline void GetData (int pos, T & acont) const;
+  ///
+  inline void SetSize (int size);
+  ///
+  inline void PrintMemInfo (ostream & ost) const;
+  ///
+  inline void DeleteData ()
+  { SetSize (cont.Size()); }
+
+  void SetName (const char * aname)
+  {
+    cont.SetName(aname);
+    hash.SetName(aname);
+  }
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+template<class T>
+inline INDEX_3_HASHTABLE<T> :: INDEX_3_HASHTABLE (int size)
+  : BASE_INDEX_3_HASHTABLE (size), cont(size)
+{
+  ;
+}
+
+template<class T>	
+inline int INDEX_3_HASHTABLE<T> :: PositionCreate (const INDEX_3 & ahash, int & bnr, int & colnr)
+{
+  bnr = HashValue (ahash);
+  colnr = Position (bnr, ahash);
+  if (!colnr)
+    {
+      hash.Add (bnr, ahash);
+      cont.AddEmpty (bnr);
+      colnr = cont.EntrySize (bnr);
+      return 1;
+    }
+  return 0;
+}
+
+
+template<class T>
+inline void INDEX_3_HASHTABLE<T> :: Set (const INDEX_3 & ahash, const T & acont)
+{
+  int bnr = HashValue (ahash);
+  int pos = Position (bnr, ahash);
+  if (pos)
+    cont.Set (bnr, pos, acont);
+  else
+    {
+      hash.Add1 (bnr, ahash);
+      cont.Add1 (bnr, acont);
+    }
+}
+
+template<class T>
+inline const T & INDEX_3_HASHTABLE<T> :: Get (const INDEX_3 & ahash) const
+{
+  int bnr = HashValue (ahash);
+  int pos = Position (bnr, ahash);
+  return cont.Get (bnr, pos);
+}
+
+template<class T>
+inline int INDEX_3_HASHTABLE<T> :: Used (const INDEX_3 & ahash) const
+{
+  return (Position (HashValue (ahash), ahash)) ? 1 : 0;
+}
+
+template<class T>
+inline int INDEX_3_HASHTABLE<T> :: GetNBags () const
+{
+  return cont.Size();
+}
+
+template<class T>
+inline int INDEX_3_HASHTABLE<T> :: GetBagSize (int bnr) const
+{
+  return cont.EntrySize (bnr);
+}
+
+template<class T>
+inline void INDEX_3_HASHTABLE<T> :: GetData (int bnr, int colnr, INDEX_3 & ahash, T & acont) const
+{
+  ahash = hash.Get(bnr, colnr);
+  acont = cont.Get(bnr, colnr);
+}    
+
+template<class T>
+inline void INDEX_3_HASHTABLE<T> :: SetData (int bnr, int colnr, const INDEX_3 & ahash, const T & acont)
+{
+  hash.Set(bnr, colnr, ahash);
+  cont.Set(bnr, colnr, acont);
+}    
+
+template<class T>
+inline void INDEX_3_HASHTABLE<T> :: SetSize (int size)
+{
+  hash.SetSize (size);
+  cont.SetSize (size);
+}
+
+template<class T>
+inline void INDEX_3_HASHTABLE<T> :: DeleteData ()
+{
+  int n = hash.Size();
+  hash.SetSize (n);
+  cont.SetSize (n);
+}
+
+template<class T>
+inline void INDEX_3_HASHTABLE<T> :: PrepareSet (const INDEX_3 & ahash)
+{
+  int bnr = HashValue (ahash);
+  hash.IncSizePrepare (bnr-1);
+  cont.IncSizePrepare (bnr-1);
+}
+
+
+template<class T>
+inline void INDEX_3_HASHTABLE<T> :: AllocateElements ()
+{
+  hash.AllocateElementsOneBlock();
+  cont.AllocateElementsOneBlock();
+}
+
+
+
+template<class T>
+inline void INDEX_3_HASHTABLE<T> :: PrintMemInfo (ostream & ost) const
+  {
+    ost << "Hash: " << endl;
+    hash.PrintMemInfo (ost);
+    ost << "Cont: " << endl;
+    cont.PrintMemInfo (ost);
+  }
+
+
+
+
+
+template<class T>
+inline INDEX_HASHTABLE<T> :: INDEX_HASHTABLE (int size)
+  : BASE_INDEX_HASHTABLE (size), cont(size)
+  {
+    ;
+  }
+	
+template<class T>
+inline void INDEX_HASHTABLE<T> :: Set (const INDEX & ahash, const T & acont)
+    {
+    int bnr = HashValue (ahash);
+    int pos = Position (bnr, ahash);
+    if (pos)
+      cont.Set (bnr, pos, acont);
+    else
+      {
+      hash.Add (bnr, ahash);
+      cont.Add (bnr, acont);
+      }
+    }
+
+template<class T>
+inline const T & INDEX_HASHTABLE<T> :: Get (const INDEX & ahash) const
+    {
+    int bnr = HashValue (ahash);
+    int pos = Position (bnr, ahash);
+    return cont.Get (bnr, pos);
+    }
+
+template<class T>
+inline int INDEX_HASHTABLE<T> :: Used (const INDEX & ahash) const
+    {
+    return (Position (HashValue (ahash), ahash)) ? 1 : 0;
+    }
+
+template<class T>
+inline int INDEX_HASHTABLE<T> :: GetNBags () const
+    {
+    return hash.Size();
+    }
+
+template<class T>
+inline int INDEX_HASHTABLE<T> :: GetBagSize (int bnr) const
+    {
+    return hash.EntrySize(bnr);
+    }
+
+template<class T>
+inline void INDEX_HASHTABLE<T> :: GetData (int bnr, int colnr, INDEX & ahash, T & acont) const
+    {
+    ahash = hash.Get(bnr, colnr);   
+    acont = cont.Get(bnr, colnr);
+    }
+    
+template<class T>
+inline void INDEX_HASHTABLE<T> :: PrintMemInfo (ostream & ost) const
+  {
+    ost << "Hash: " << endl;
+    hash.PrintMemInfo (ost);
+    ost << "Cont: " << endl;
+    cont.PrintMemInfo (ost);
+  }
+
+
+    
+    
+    
+    
+    
+    
+    
+/****************** INDEX_2_HASHTABLE ****************************/    
+    
+    
+template<class T>
+inline INDEX_2_HASHTABLE<T> :: INDEX_2_HASHTABLE (int size)
+    : BASE_INDEX_2_HASHTABLE (size), cont(size)
+    {
+      ;
+    }
+
+/*
+template<class T>
+inline void INDEX_2_HASHTABLE<T> :: Set (const INDEX_2 & ahash, const T & acont)
+    {
+    int bnr = HashValue (ahash);
+    int pos = Position (bnr, ahash);
+    if (pos)
+      cont.Set (bnr, pos, acont);
+    else
+      {
+      hash.Add (bnr, ahash);
+      cont.Add (bnr, acont);
+      }
+    }
+*/
+
+template<class T>
+inline const T & INDEX_2_HASHTABLE<T> :: Get (const INDEX_2 & ahash) const
+    {
+    int bnr = HashValue (ahash);
+    int pos = Position (bnr, ahash);
+    return cont.Get (bnr, pos);
+    }
+
+template<class T>
+inline int INDEX_2_HASHTABLE<T> :: Used (const INDEX_2 & ahash) const
+    {
+    return (Position (HashValue (ahash), ahash)) ? 1 : 0;
+    }
+
+template<class T>
+inline int INDEX_2_HASHTABLE<T> :: GetNBags () const
+    {
+    return cont.Size();
+    }
+
+template<class T>
+inline int INDEX_2_HASHTABLE<T> :: GetBagSize (int bnr) const
+    {
+    return cont.EntrySize (bnr);
+    }
+
+template<class T>
+inline void INDEX_2_HASHTABLE<T> :: GetData (int bnr, int colnr, INDEX_2 & ahash, T & acont) const
+    {
+    ahash = hash.Get(bnr, colnr);
+    acont = cont.Get(bnr, colnr);
+    }
+
+
+
+template<class T>
+inline void INDEX_2_HASHTABLE<T> :: PrintMemInfo (ostream & ost) const
+  {
+    ost << "Hash: " << endl;
+    hash.PrintMemInfo (ost);
+    ost << "Cont: " << endl;
+    cont.PrintMemInfo (ost);
+  }
+
+
+
+
+
+
+
+
+
+
+
+
+
+/* *********** Closed Hashing ************************* */
+
+
+
+
+template<class T>
+inline INDEX_2_CLOSED_HASHTABLE<T> :: 
+INDEX_2_CLOSED_HASHTABLE (int size)
+  : BASE_INDEX_2_CLOSED_HASHTABLE(size), cont(size)
+{
+  cont.SetName ("i2-hashtable, contents");
+}
+
+template<class T>
+inline void INDEX_2_CLOSED_HASHTABLE<T> :: 
+Set (const INDEX_2 & ahash, const T & acont)
+{
+  int pos;
+  PositionCreate (ahash, pos);
+  hash.Elem(pos) = ahash;
+  cont.Elem(pos) = acont;
+}
+
+template<class T>
+inline const T & INDEX_2_CLOSED_HASHTABLE<T> :: 
+Get (const INDEX_2 & ahash) const
+{
+  int pos = Position (ahash);
+  return cont.Get(pos);
+}
+
+template<class T>
+inline int INDEX_2_CLOSED_HASHTABLE<T> :: 
+Used (const INDEX_2 & ahash) const
+{
+  int pos = Position (ahash);
+  return (pos != 0);
+}
+
+template<class T>
+inline void INDEX_2_CLOSED_HASHTABLE<T> :: 
+SetData (int pos, const INDEX_2 & ahash, const T & acont)
+{
+  hash.Elem(pos) = ahash;
+  cont.Elem(pos) = acont;
+}
+  
+template<class T>
+inline void INDEX_2_CLOSED_HASHTABLE<T> :: 
+GetData (int pos, INDEX_2 & ahash, T & acont) const
+{
+  ahash = hash.Get(pos);
+  acont = cont.Get(pos);
+}
+
+template<class T>
+inline void INDEX_2_CLOSED_HASHTABLE<T> :: 
+SetData (int pos, const T & acont)
+{
+  cont.Elem(pos) = acont;
+}
+  
+template<class T>
+inline void INDEX_2_CLOSED_HASHTABLE<T> :: 
+GetData (int pos, T & acont) const
+{
+  acont = cont.Get(pos);
+}
+
+
+template<class T>
+inline void INDEX_2_CLOSED_HASHTABLE<T> :: 
+SetSize (int size)
+{
+  BaseSetSize(size);
+  cont.SetSize(size);
+}
+
+
+  
+template<class T>
+inline void INDEX_2_CLOSED_HASHTABLE<T> :: 
+PrintMemInfo (ostream & ost) const
+{
+  cout << "Hashtable: " << Size() 
+       << " entries of size " << sizeof(INDEX_2) << " + " << sizeof(T) 
+       << " = " << Size() * (sizeof(INDEX_2) + sizeof(T)) << " bytes." 
+       << " Used els: " << UsedElements() 
+       << endl;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+template<class T>
+inline INDEX_3_CLOSED_HASHTABLE<T> :: 
+INDEX_3_CLOSED_HASHTABLE (int size)
+  : BASE_INDEX_3_CLOSED_HASHTABLE(size), cont(size)
+{
+  cont.SetName ("i3-hashtable, contents");
+}
+
+template<class T>
+inline void INDEX_3_CLOSED_HASHTABLE<T> :: 
+Set (const INDEX_3 & ahash, const T & acont)
+{
+  int pos;
+  PositionCreate (ahash, pos);
+  hash.Elem(pos) = ahash;
+  cont.Elem(pos) = acont;
+}
+
+template<class T>
+inline const T & INDEX_3_CLOSED_HASHTABLE<T> :: 
+Get (const INDEX_3 & ahash) const
+{
+  int pos = Position (ahash);
+  return cont.Get(pos);
+}
+
+template<class T>
+inline int INDEX_3_CLOSED_HASHTABLE<T> :: 
+Used (const INDEX_3 & ahash) const
+{
+  int pos = Position (ahash);
+  return (pos != 0);
+}
+
+template<class T>
+inline void INDEX_3_CLOSED_HASHTABLE<T> :: 
+SetData (int pos, const INDEX_3 & ahash, const T & acont)
+{
+  hash.Elem(pos) = ahash;
+  cont.Elem(pos) = acont;
+}
+  
+template<class T>
+inline void INDEX_3_CLOSED_HASHTABLE<T> :: 
+GetData (int pos, INDEX_3 & ahash, T & acont) const
+{
+  ahash = hash.Get(pos);
+  acont = cont.Get(pos);
+}
+
+template<class T>
+inline void INDEX_3_CLOSED_HASHTABLE<T> :: 
+SetData (int pos, const T & acont)
+{
+  cont.Elem(pos) = acont;
+}
+  
+template<class T>
+inline void INDEX_3_CLOSED_HASHTABLE<T> :: 
+GetData (int pos, T & acont) const
+{
+  acont = cont.Get(pos);
+}
+
+
+template<class T>
+inline void INDEX_3_CLOSED_HASHTABLE<T> :: 
+SetSize (int size)
+{
+  BaseSetSize(size);
+  cont.SetSize(size);
+}
+
+
+  
+template<class T>
+inline void INDEX_3_CLOSED_HASHTABLE<T> :: 
+PrintMemInfo (ostream & ost) const
+{
+  cout << "Hashtable: " << Size() 
+       << " entries of size " << sizeof(INDEX_3) << " + " << sizeof(T) 
+       << " = " << Size() * (sizeof(INDEX_3) + sizeof(T)) << " bytes" << endl;
+}
+
+
+
+
+
+
+#endif
diff --git a/Netgen/libsrc/general/moveablemem.cpp b/Netgen/libsrc/general/moveablemem.cpp
new file mode 100644
index 0000000000..0e6f894dea
--- /dev/null
+++ b/Netgen/libsrc/general/moveablemem.cpp
@@ -0,0 +1,241 @@
+#include <iostream>
+#include <iomanip>
+
+#include <myadt.hpp>
+using namespace std;
+namespace netgen
+{
+  
+  NgMutex mem_mutex;
+  
+  size_t BaseMoveableMem::totalsize = 0; // 500000000;
+  size_t BaseMoveableMem::used = 0;
+  char * BaseMoveableMem::largeblock = 0;
+  
+  BaseMoveableMem * BaseMoveableMem::first = 0;
+  BaseMoveableMem * BaseMoveableMem::last = 0;
+  
+
+  BaseMoveableMem :: BaseMoveableMem (size_t s)
+  {
+    // cout << "Construct object begin" << endl;
+    //   Print ();
+
+  prev = last;
+  next = 0;
+
+  if (last) last->next = this;
+  last = this;
+  if (!first) first = this;
+
+  size = 0;
+
+  if (prev)
+    pos = prev->pos + prev->size;
+  else
+    pos = 0;
+
+  ptr = 0;
+  name = 0;
+
+  if (s) Alloc(s);
+}
+ 
+BaseMoveableMem :: ~BaseMoveableMem () throw()
+{
+  Free();
+
+  if (next) next->prev = prev;
+  else last = prev;
+  if (prev) prev->next = next;
+  else first = next;
+
+  delete name;
+}
+
+void BaseMoveableMem :: SetName (const char * aname)
+{
+  delete name;
+  if (aname)
+    {
+      name = new char[strlen(aname)+1];
+      strcpy (name, aname);
+    }
+}
+
+
+void BaseMoveableMem :: Alloc (size_t s)
+{
+  if (totalsize == 0)
+    {
+      size = s;
+      ptr = (char*) malloc(s);
+      return;
+    }
+
+
+  used += s - size;
+
+  int r = s % 8;
+  if (r) s += 8-r;
+  if (prev)
+    pos = prev->pos + prev->size;
+  else
+    pos = 0;
+  size = s;
+  
+  if (next)
+    {
+      NgLock lock(mem_mutex);
+      lock.Lock();
+      try
+	{
+	  next->MoveTo (pos+size);
+	}
+      catch (NgException e)
+      {
+	lock.UnLock();
+	throw NgException ("MoveableMem overflow");
+      }
+      lock.UnLock();
+    }
+
+  if (size)
+    {
+      if (!largeblock)
+	{
+	  cout << "moveable memory: allocate large block of "
+	       << totalsize / 1048576  << " MB" << endl; 
+	  // largeblock = new char[totalsize];
+	  largeblock = (char*)malloc (totalsize);
+	}
+      ptr = largeblock+pos;
+
+      if (pos + size > totalsize)
+	throw NgException ("MoveableMem overflow");
+    }
+  else
+    ptr = 0;
+}
+
+void BaseMoveableMem :: ReAlloc (size_t s)
+{
+  if (totalsize == 0)
+    {
+      if (size == s) return;
+      
+      char * old = ptr;
+      ptr = (char*)malloc(s);
+      memmove (ptr, old, (s < size) ? s : size);
+      free (old);
+      size = s;
+      return;
+    }
+
+  Alloc (s);
+}
+
+void BaseMoveableMem :: MoveTo (size_t newpos)
+{
+  //  cout << "move block, oldpos = " << pos << "; newpos = " << newpos
+  // << ", size = " << size << endl;
+  static int move = 0;
+
+  if (newpos + size > totalsize)
+    throw NgException ("MoveableMem overflow");
+  if (newpos > pos)
+    {
+      if (next) next->MoveTo (newpos+size);
+      memmove (largeblock+newpos, largeblock+pos, size);
+      move += size;
+    }
+  else if (newpos < pos)
+    {
+      // cout << "move down: " << size << endl;
+      memmove (largeblock+newpos, largeblock+pos, size);
+      if (next) next->MoveTo (newpos+size);
+      move += size;
+    }
+  pos = newpos;
+  ptr = largeblock+pos;
+  //  cout << "total move: " << move << endl;
+}
+
+void BaseMoveableMem :: Free () throw()
+{
+  if (totalsize == 0)
+    {
+      free (ptr);
+      ptr = 0;
+      return;
+    }
+
+  /*
+    cout << "free block, pos = " << pos << "size = " << size << endl;
+    cout << "before: " << endl;
+    Print();
+  */
+  used -= size;
+  if (next) 
+    {
+      NgLock lock(mem_mutex);
+      lock.Lock();
+      next->MoveTo (pos);
+      lock.UnLock();
+    }
+  
+  size = 0;
+  ptr = 0;
+  // pos = 0;
+}
+
+void BaseMoveableMem :: Swap (BaseMoveableMem & m2) throw()
+{
+  int hi;
+  BaseMoveableMem * hp;
+  char * cp;
+  hi = size; size  = m2.size; m2.size = hi;
+  hi = pos; pos = m2.pos; m2.pos = hi;
+  /*
+  hp = prev; prev = m2.prev; m2.prev = hp;
+  hp = next; next = m2.next; m2.next = hp;
+  */
+  cp = ptr; ptr = m2.ptr; m2.ptr = cp;
+  cp = name; name = m2.name; m2.name = cp;
+}
+
+
+void BaseMoveableMem :: Print ()
+{
+  cout << "****************** Moveable Mem Report ****************" << endl;
+  BaseMoveableMem * p = first;
+  int mem = 0;
+  int cnt = 0;
+  while (p)
+    {
+      mem += p->size;
+      cnt++;
+
+      cout << setw(10) << p->size << " Bytes";
+      cout << ", pos = " << p->pos;
+      //      cout << ", addr = " << p->ptr;
+      if (p->name)
+	cout << " in block " << p->name;
+      cout << endl;
+
+      p = p->next;
+    }
+
+  if (mem > 100000000)
+    cout << "memory in moveable arena: " << mem/1048576 << " MB" << endl;
+  else if (mem > 100000)
+    cout << "memory in moveable arena: " << mem/1024 << " kB" << endl;
+  else
+    cout << "memory in moveable arena: " << mem << " Bytes" << endl;
+  cout << "number of blocks:         " << cnt << endl;
+  
+  cout << " used  = " << used << endl;
+  //  cout << "******************************************************" << endl;
+}
+
+}
diff --git a/Netgen/libsrc/general/moveablemem.hpp b/Netgen/libsrc/general/moveablemem.hpp
new file mode 100644
index 0000000000..d156bb694c
--- /dev/null
+++ b/Netgen/libsrc/general/moveablemem.hpp
@@ -0,0 +1,97 @@
+#ifndef FILE_MOVEABLEMEM
+#define FILE_MOVEABLEMEM
+
+/**************************************************************************/
+/* File:   moveablemem.hpp                                                */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   12. Feb. 2003                                                  */
+/**************************************************************************/
+
+
+extern NgMutex mem_mutex;
+
+class BaseMoveableMem
+{
+public:
+  static size_t totalsize;
+  static size_t used;
+
+private:
+  static char * largeblock;
+  static BaseMoveableMem *first, *last;
+
+  BaseMoveableMem *prev, *next;
+  size_t size, pos;
+  char * ptr;
+  char * name;
+
+protected:
+  BaseMoveableMem (size_t s = 0);
+  ~BaseMoveableMem () throw();
+  void Alloc (size_t s);
+  void ReAlloc (size_t s);
+  void MoveTo (size_t newpos);
+  void Free () throw(); 
+  char * Ptr() { return ptr; }
+  const char * Ptr() const { return ptr; }
+  void Swap (BaseMoveableMem & m2) throw(); 
+public:
+  void SetName (const char * aname);
+  static void Print ();
+};
+
+
+
+
+template <typename T>
+class MoveableMem : public BaseMoveableMem
+{
+public:
+  MoveableMem (size_t s = 0)
+    : BaseMoveableMem (sizeof(T) * s) 
+  {
+    ;
+  }
+  void Alloc (size_t s)
+  {
+    BaseMoveableMem::Alloc (sizeof(T) * s);
+  }
+  void ReAlloc (size_t s)
+  {
+    BaseMoveableMem::ReAlloc (sizeof(T) * s);
+  }
+  void Free ()
+  {
+    BaseMoveableMem::Free ();
+  }
+
+  const T * Ptr() const
+  {
+    return reinterpret_cast<const T*> (BaseMoveableMem::Ptr());
+  }
+
+  T * Ptr()
+  {
+    return reinterpret_cast<T*> (BaseMoveableMem::Ptr());
+  }
+
+  operator const T* () const
+  {
+    return reinterpret_cast<const T*> (BaseMoveableMem::Ptr());
+  }
+
+  operator T* () 
+  {
+    return reinterpret_cast<T*> (BaseMoveableMem::Ptr());
+  }
+
+  void Swap (MoveableMem<T> & m2)
+  {
+    BaseMoveableMem::Swap (m2);
+  }
+protected:
+  MoveableMem (const MoveableMem & m);
+  MoveableMem & operator= (const MoveableMem & m);
+};
+
+#endif
diff --git a/Netgen/libsrc/general/myadt.hpp b/Netgen/libsrc/general/myadt.hpp
new file mode 100644
index 0000000000..f74976d51f
--- /dev/null
+++ b/Netgen/libsrc/general/myadt.hpp
@@ -0,0 +1,43 @@
+#ifndef FILE_MYADT
+#define FILE_MYADT
+
+/**************************************************************************/
+/* File:   myadt.hpp                                                      */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Jun. 95                                                    */
+/**************************************************************************/
+
+/* 
+   include for all abstract data types
+*/
+
+
+
+#include <mystdlib.h>
+#include <mydefs.hpp>
+
+
+namespace netgen
+{
+#include "ngexception.hpp"
+#include "parthreads.hpp"
+#include "moveablemem.hpp"
+#include "dynamicmem.hpp"
+
+#include "template.hpp"
+#include "array.hpp"
+#include "table.hpp"
+#include "hashtabl.hpp"
+#include "symbolta.hpp"
+#include "bitarray.hpp"
+#include "flags.hpp"
+#include "spbita2d.hpp"
+#include "seti.hpp"
+#include "optmem.hpp"
+#include "autoptr.hpp"
+#include "sort.hpp"
+#include "stack.hpp"
+#include "mystring.hpp"
+}
+
+#endif
diff --git a/Netgen/libsrc/general/mystring.cpp b/Netgen/libsrc/general/mystring.cpp
new file mode 100644
index 0000000000..b586202ba8
--- /dev/null
+++ b/Netgen/libsrc/general/mystring.cpp
@@ -0,0 +1,383 @@
+
+//**************************************************************
+//
+// filename:             mystring.cpp
+//
+// project:              doctoral thesis
+//
+// autor:                Dipl.-Ing. Gerstmayr Johannes
+//
+// generated:            20.12.98
+// last change:          20.12.98
+// description:          implementation for strings
+// remarks:
+//
+//**************************************************************
+
+// string class
+#include <mystdlib.h>
+#include <myadt.hpp>
+
+#include <linalg.hpp>
+#include <gprim.hpp>
+
+/*
+#include <iostream.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <fstream.h>
+#include "mystring.hh"
+
+ */
+
+namespace netgen
+{
+
+void DefaultStringErrHandler()
+{
+  cerr << "Fehler : Bereichsüberschreitung bei Stringoperation\n" << flush;
+}
+
+void (*MyStr::ErrHandler)() = DefaultStringErrHandler;
+     
+MyStr::MyStr()
+{
+  length = 0;
+  // str = new char[1];
+  str = shortstr;
+  str[0] = 0;
+}
+
+MyStr::MyStr(const char *s)
+{
+  length = strlen(s);
+
+  if (length > SHORTLEN)
+    str = new char[length + 1];
+  else
+    str = shortstr;
+  strcpy(str, s);
+}
+
+MyStr::MyStr(char s)
+{
+  length = 1;
+  str = shortstr;
+  str[0] = s;
+  str[1] = (char)0;
+}
+
+MyStr::MyStr(const MyStr& s)
+{
+  length = s.length;
+  if (length > SHORTLEN)
+    str = new char[length + 1];
+  else
+    str = shortstr;
+  strcpy(str, s.str);
+}
+
+MyStr::MyStr(int i)
+{
+  char buffer[32];
+  sprintf(buffer, "%d", i);
+  length = strlen(buffer);
+  if (length > SHORTLEN)
+    str = new char[length + 1];
+  else
+    str = shortstr;
+  strcpy(str, buffer);
+}
+
+MyStr::MyStr(long l)
+{
+  char buffer[32];
+  sprintf(buffer, "%ld", l);
+  length = strlen(buffer);
+  if (length > SHORTLEN)
+    str = new char[length + 1];
+  else
+    str = shortstr;
+  strcpy(str, buffer);
+}
+
+MyStr::MyStr(double d)
+{
+  char buffer[32];
+  //if (fabs(d) < 1E-100) {d = 0;}
+  sprintf(buffer, "%g", d);
+  length = strlen(buffer);
+  if (length > SHORTLEN)
+    str = new char[length + 1];
+  else
+    str = shortstr;
+  strcpy(str, buffer);
+}
+
+MyStr::MyStr(const Point3d& p)
+{
+  char buffer[80];
+  //if (fabs(d) < 1E-100) {d = 0;}
+  sprintf(buffer, "[%g, %g, %g]", p.X(), p.Y(), p.Z());
+  length = strlen(buffer);
+  if (length > SHORTLEN)
+    str = new char[length + 1];
+  else
+    str = shortstr;
+  strcpy(str, buffer);
+}
+
+MyStr::MyStr(const Vec3d& p)
+{
+  char buffer[80];
+  //if (fabs(d) < 1E-100) {d = 0;}
+  sprintf(buffer, "[%g, %g, %g]", p.X(), p.Y(), p.Z());
+  length = strlen(buffer);
+  if (length > SHORTLEN)
+    str = new char[length + 1];
+  else
+    str = shortstr;
+  strcpy(str, buffer);
+}
+
+MyStr::MyStr(unsigned n, int)
+{
+  length = n;
+  if (length > SHORTLEN)
+    str = new char[length + 1];
+  else
+    str = shortstr;
+  str[n] = 0;
+}
+
+MyStr::MyStr(const std::string & st)
+{
+  length = st.length();
+  if (length > SHORTLEN)
+    str = new char[length + 1];
+  else
+    str = shortstr;
+  strcpy (str, st.c_str());
+}
+
+
+
+MyStr MyStr::Left(unsigned r)
+{
+  if(r > length)
+    {
+      MyStr::ErrHandler();
+      MyStr s;
+      return s;
+    }
+  else
+    {
+      MyStr tmp(r, 0);
+      strncpy(tmp.str, str, r);
+      return tmp;
+    }
+}
+
+MyStr MyStr::Right(unsigned l)
+{
+  if(l > length)
+    {
+      MyStr::ErrHandler();
+      MyStr s;
+      return s;
+    }
+  else
+    {
+      MyStr tmp(l, 0);
+      strncpy(tmp.str, str + length - l, l);
+      return tmp;
+    }
+}
+
+MyStr& MyStr::InsertAt(unsigned pos, const MyStr& s)
+{
+  if(pos > length)
+    {
+      MyStr::ErrHandler();
+      return *this;
+    }
+  int newLength = length + s.length;
+  char *tmp = new char[newLength + 1];
+  strncpy(tmp, str, pos);
+  strcpy(tmp + pos, s.str);
+  strcpy(tmp + pos + s.length, str + pos);
+
+  if (length > SHORTLEN) delete str;
+  length = newLength;
+  if (length > SHORTLEN)
+    str = tmp;
+  else
+    {
+      strcpy (shortstr, tmp);
+      delete tmp;
+      str = shortstr;
+    }
+  return *this;
+}
+
+MyStr &MyStr::WriteAt(unsigned pos, const MyStr& s)
+{
+  if(pos > length)
+  {
+    MyStr::ErrHandler();
+    return *this;
+  }
+  int n = length - pos;
+  if(s.length < n)
+    n = s.length;
+  strncpy(str + pos, s.str, n);
+  return *this;
+}
+
+void MyStr::ConvertTextToExcel()
+{
+  /*
+  for (int i = 0; i < Length(); i++)
+    {
+      if ((*this)[i]==',') {(*this)[i] = ';';}
+      else if ((*this)[i]=='.') {(*this)[i] = ',';}
+    }
+  */
+}
+
+void MyStr::ConvertExcelToText()
+{
+  /*
+  for (int i = 0; i < Length(); i++)
+    {
+      if ((*this)[i]==',') {(*this)[i] = '.';}
+      else if ((*this)[i]==';') {(*this)[i] = ',';}
+    }
+  */
+}
+
+MyStr& MyStr::operator = (const MyStr& s)
+{
+  if (length > SHORTLEN) delete str;
+  length = s.length;
+  if (length > SHORTLEN)
+    str = new char[length + 1];
+  else
+    str = shortstr;
+  strcpy(str, s.str);
+  return *this;
+}
+
+MyStr operator + (const MyStr& s1, const MyStr& s2)
+{
+  MyStr tmp(s1.length + s2.length, 0);
+  if (s1.length != 0) strcpy(tmp.str, s1.str);
+  if (s2.length != 0) strcpy(tmp.str + s1.length, s2.str);
+  return tmp;
+}
+
+void MyStr::operator += (const MyStr& s)
+{
+  if (length+s.length <= SHORTLEN)
+    {
+      if (s.length != 0) strcpy(shortstr + length, s.str);
+    }
+  else
+    {
+      char *tmp = new char[length + s.length + 1];
+      if (length != 0) strcpy(tmp, str);
+      if (s.length != 0) strcpy(tmp + length, s.str);
+      if (length > SHORTLEN) delete str;
+      length += s.length;
+      str = tmp;
+    }
+}
+
+char& MyStr::operator [] (unsigned n)
+{
+  static char dummy;
+  if(n < length)
+    return str[n];
+  else
+  {
+    MyStr::ErrHandler();
+    return dummy;
+  }
+}
+
+char MyStr::operator [] (unsigned n) const
+{
+  static char dummy;
+  if(n < length)
+    return str[n];
+  else
+  {
+    MyStr::ErrHandler();
+    return dummy;
+  }
+}
+
+MyStr MyStr::operator () (unsigned l, unsigned r)
+{
+  if((l > r) || (r > length))
+  {
+    MyStr::ErrHandler();
+    MyStr s;
+    return s;
+  }
+  else
+  {
+    int n = r - l + 1;
+    MyStr tmp(n, 0);
+    strncpy(tmp.str, str + 1, n);
+    return tmp;
+  }
+}
+
+istream& operator >> (istream& is, MyStr& s)
+{
+  const int buflen = 1000;
+  char buffer[buflen+1];
+
+  int end = 0;
+  s = "";
+  MyStr str;
+
+  while (!end)
+  {
+    is.get(buffer, buflen);
+    str = MyStr(buffer);
+    s += str;
+    if (is.peek() == EOF) {end = 1;}
+  }
+
+  return is;
+}
+
+/*
+#ifdef __borland
+::ifstream& operator >> (::ifstream& is, MyStr& s)       // wb
+{                                                        // wb
+  const int buflen = 1000;                               // wb
+  char buffer[buflen+1];                                 // wb
+                                                         // wb
+  int end = 0;                                           // wb
+  s = "";                                                // wb
+  MyStr str;                                             // wb
+                                                         // wb
+  while (!end)                                           // wb
+  {                                                      // wb
+    is.get(buffer, buflen);                              // wb
+    str = MyStr(buffer);                                 // wb
+    s += str;                                            // wb
+    if (is.peek() == EOF) {end = 1;}                     // wb
+  }                                                      // wb
+                                                         // wb
+  return is;                                             // wb
+}          
+
+#endif
+*/
+}
diff --git a/Netgen/libsrc/general/mystring.hpp b/Netgen/libsrc/general/mystring.hpp
new file mode 100644
index 0000000000..6517aad3fa
--- /dev/null
+++ b/Netgen/libsrc/general/mystring.hpp
@@ -0,0 +1,193 @@
+
+//**************************************************************
+//
+// filename:             mystring.h
+//
+// project:              doctoral thesis, program smart
+//
+// autor:                Dipl.-Ing. Gerstmayr Johannes
+//
+// generated:            20.12.98
+// last change:          20.12.98
+// description:          base class for strings
+// remarks:              string with n characters has
+//                       0..n-1 characters and at pos n a 0
+//
+//**************************************************************
+
+
+#ifndef MYSTRING__H
+#define MYSTRING__H
+
+class Point3d;
+class Vec3d;
+
+class MyStr;
+
+MyStr operator + (const MyStr &, const MyStr &);
+int operator == (const MyStr &, const MyStr &);
+int operator < (const MyStr &, const MyStr &);
+int operator <= (const MyStr &, const MyStr &);
+int operator > (const MyStr &, const MyStr &);
+int operator >= (const MyStr &, const MyStr &);
+int operator != (const MyStr &, const MyStr &);
+ostream& operator << (ostream &, const MyStr &);
+istream& operator >> (istream &, MyStr &);
+
+class MyStr
+{
+public:
+  MyStr();
+  MyStr(const char *);
+  MyStr(char);
+  MyStr(const MyStr &);
+  MyStr(int);
+  MyStr(long);
+  MyStr(double);
+  MyStr(const Point3d& p);
+  MyStr(const Vec3d& p);
+  MyStr(const std::string & st);
+
+  ~MyStr();
+  MyStr Left(unsigned);
+  MyStr Right(unsigned);
+  MyStr& InsertAt(unsigned, const MyStr &);
+  MyStr& WriteAt(unsigned, const MyStr &);
+  unsigned Length() const;
+  int Find(const char);
+  int Find(const char *);
+  int Find(const MyStr &);
+  MyStr& operator = (const MyStr &);
+  friend MyStr operator + (const MyStr &, const MyStr &);
+  void operator += (const MyStr &);
+  char* c_str();
+
+  //change every ',' -> ';', '.' -> ','
+  void ConvertTextToExcel();
+  //change every ','->'.', ';'->','
+  void ConvertExcelToText();
+
+  MyStr operator () (unsigned, unsigned);
+  operator int();
+  operator double();
+  operator long();
+  operator char *();
+  char& operator [] (unsigned int);
+  char operator [] (unsigned int) const;
+
+  friend int operator == (const MyStr &, const MyStr &);
+  friend int operator < (const MyStr &, const MyStr &);
+  friend int operator <= (const MyStr &, const MyStr &);
+  friend int operator > (const MyStr &, const MyStr &);
+  friend int operator >= (const MyStr &, const MyStr &);
+  friend int operator != (const MyStr &, const MyStr &);
+  friend ostream& operator << (ostream &, const MyStr &);
+  friend istream& operator >> (istream &, MyStr &);
+  static void SetToErrHandler(void (*)());
+private:
+  MyStr(unsigned, int);
+  char *str;
+  unsigned length;
+  enum { SHORTLEN = 24 };
+  char shortstr[SHORTLEN+1];
+  static void(*ErrHandler)();
+};
+
+inline MyStr::~MyStr()
+{
+  if (length > SHORTLEN)
+    delete [] str;
+}
+
+inline unsigned MyStr::Length() const
+{
+  return length;
+}
+
+inline int MyStr::Find(const char c)
+{
+  char *pos = strchr(str, int(c));
+  return pos ? int(pos - str) : -1;
+}
+
+inline int MyStr::Find(const MyStr &s)
+{
+  char *pos = strstr(str, s.str);
+  return pos ? int(pos - str) : -1;
+}
+
+inline int MyStr::Find(const char *s)
+{
+  char *pos = strstr(str, s);
+  return pos ? int(pos - str) : -1;
+}
+
+inline MyStr::operator int()
+{
+  return atoi(str);
+}
+
+inline MyStr::operator double()
+{
+  return atof(str);
+}
+
+inline MyStr::operator long()
+{
+  return atol(str);
+}
+
+inline MyStr::operator char *()
+{
+  return str;
+}
+
+inline char* MyStr::c_str()
+{
+  return str;
+}
+
+
+inline int operator == (const MyStr &s1, const MyStr& s2)
+{
+  return strcmp(s1.str, s2.str) == 0;
+}
+
+inline int operator < (const MyStr &s1, const MyStr& s2)
+{
+  return strcmp(s1.str, s2.str) < 0;
+}
+
+inline int operator <= (const MyStr &s1, const MyStr& s2)
+{
+  return strcmp(s1.str, s2.str) <= 0;
+}
+
+inline int operator > (const MyStr &s1, const MyStr& s2)
+{
+  return strcmp(s1.str, s2.str) > 0;
+}
+
+inline int operator >= (const MyStr &s1, const MyStr& s2)
+{
+  return strcmp(s1.str, s2.str) >= 0;
+}
+
+inline int operator != (const MyStr &s1, const MyStr& s2)
+{
+  return !(s1 == s2);
+}
+
+inline ostream& operator << (ostream& os, const MyStr& s)
+{
+  return os << s.str;
+}
+
+inline void MyStr::SetToErrHandler(void (*Handler)())
+{
+  ErrHandler = Handler;
+};
+
+#endif
+
+   
diff --git a/Netgen/libsrc/general/ngexception.cpp b/Netgen/libsrc/general/ngexception.cpp
new file mode 100644
index 0000000000..6746dd2521
--- /dev/null
+++ b/Netgen/libsrc/general/ngexception.cpp
@@ -0,0 +1,33 @@
+/**************************************************************************/
+/* File:   ngexception.cpp                                                */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   16. Jan. 02                                                    */
+/**************************************************************************/
+
+#include <myadt.hpp>
+
+namespace netgen
+{
+  using namespace netgen;
+
+
+
+  NgException :: NgException (const string & s) 
+    : what(s)
+  {
+    ; 
+  }
+
+
+  NgException :: ~NgException () 
+  {
+    ;
+  }
+
+  /// append string to description
+  void NgException :: Append (const string & s)
+  { 
+    what += s; 
+  }
+
+}
diff --git a/Netgen/libsrc/general/ngexception.hpp b/Netgen/libsrc/general/ngexception.hpp
new file mode 100644
index 0000000000..56c561aa8c
--- /dev/null
+++ b/Netgen/libsrc/general/ngexception.hpp
@@ -0,0 +1,30 @@
+#ifndef FILE_NGEXCEPTION
+#define FILE_NGEXCEPTION
+
+/**************************************************************************/
+/* File:   ngexception.hpp                                                */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   16. Jan. 2002                                                  */
+/**************************************************************************/
+
+
+/// Base class for all ng exceptions
+class NgException 
+{
+  /// verbal description of exception
+  string what;
+public:
+  ///
+  NgException (const string & s);
+  ///
+  virtual ~NgException ();
+
+  /// append string to description
+  void Append (const string & s);
+  //  void Append (const char * s);
+  
+  /// verbal description of exception
+  const string & What() const { return what; }
+};
+
+#endif
diff --git a/Netgen/libsrc/general/optmem.cpp b/Netgen/libsrc/general/optmem.cpp
new file mode 100644
index 0000000000..3247e7e38d
--- /dev/null
+++ b/Netgen/libsrc/general/optmem.cpp
@@ -0,0 +1,59 @@
+/**************************************************************************/
+/* File:   optmem.cc                                                      */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   04. Apr. 97                                                    */
+/**************************************************************************/
+
+/* 
+   Abstract data type ARRAY
+*/
+
+
+#include <mystdlib.h>
+#include <myadt.hpp>
+
+namespace netgen
+{
+  using namespace netgen;
+
+  BlockAllocator :: BlockAllocator (unsigned asize, unsigned ablocks)
+    : bablocks (0)
+  {
+    if (asize < sizeof(void*))
+      asize = sizeof(void*);
+    size = asize;
+    blocks = ablocks;
+    freelist = NULL;
+  }
+
+  BlockAllocator :: ~BlockAllocator ()
+  {
+    for (unsigned i = 0; i < bablocks.Size(); i++)
+      delete [] bablocks[i];
+  }
+
+  void * BlockAllocator :: Alloc ()
+  {
+    //  return new char[size];
+    if (!freelist)
+      {
+	// cout << "BlockAlloc: " << size*blocks << endl;
+	char * hcp = new char [size * blocks];
+	bablocks.Append (hcp);
+	bablocks.Last() = hcp;
+	for (unsigned i = 0; i < blocks-1; i++)
+	  *(void**)&(hcp[i * size]) = &(hcp[ (i+1) * size]);
+	*(void**)&(hcp[(blocks-1)*size]) = NULL;
+	freelist = hcp;
+      }
+    void * p = freelist;
+    freelist = *(void**)freelist;
+    return p;
+  }
+
+  void BlockAllocator :: Free (void * p)
+  {
+    *(void**)p = freelist;
+    freelist = p;
+  }
+}
diff --git a/Netgen/libsrc/general/optmem.hpp b/Netgen/libsrc/general/optmem.hpp
new file mode 100644
index 0000000000..a7a136c7c5
--- /dev/null
+++ b/Netgen/libsrc/general/optmem.hpp
@@ -0,0 +1,36 @@
+#ifndef FILE_OPTMEM
+#define FILE_OPTMEM
+
+/**************************************************************************/
+/* File:   optmem.hh                                                      */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   04. Apr. 97                                                    */
+/**************************************************************************/
+
+/** 
+    Optimized Memory allocation classes
+*/
+
+class BlockAllocator
+{
+private:
+  ///
+  unsigned size, blocks;
+  ///
+  void * freelist;
+  ///
+  ARRAY<char*> bablocks;
+public:
+  ///
+  BlockAllocator (unsigned asize, unsigned ablocks = 100);
+  ///
+  ~BlockAllocator ();
+  ///
+  void * Alloc ();
+  ///
+  void Free (void * p);
+};
+
+
+
+#endif
diff --git a/Netgen/libsrc/general/parthreads.cpp b/Netgen/libsrc/general/parthreads.cpp
new file mode 100644
index 0000000000..81e9d0b6cc
--- /dev/null
+++ b/Netgen/libsrc/general/parthreads.cpp
@@ -0,0 +1,40 @@
+/**************************************************************************/
+/* File:   parthreads.cpp                                                 */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Jun. 95                                                    */
+/**************************************************************************/
+
+
+#include <mystdlib.h>
+#include <myadt.hpp>
+
+/*
+
+namespace netgen
+{
+  using namespace netgen;
+
+#ifdef WIN32
+
+  NgLock :: NgLock (NgMutex & mut)
+    : sl(&mut.cs)
+  {
+    ;
+  }
+
+  void NgLock :: Lock ()
+  {
+    sl.Lock();
+  }
+  void NgLock :: UnLock ()
+  {
+    sl.Unlock();
+  }
+
+
+#else
+
+#endif
+}
+
+*/
diff --git a/Netgen/libsrc/general/parthreads.hpp b/Netgen/libsrc/general/parthreads.hpp
new file mode 100644
index 0000000000..99dd017633
--- /dev/null
+++ b/Netgen/libsrc/general/parthreads.hpp
@@ -0,0 +1,126 @@
+#ifndef FILE_PARTHREADS
+#define FILE_PARTHREADS
+
+/**************************************************************************/
+/* File:   parthreads.hh                                                  */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   22. Nov. 2000                                                  */
+/**************************************************************************/
+
+/*
+  Parallel thread, Mutex, 
+*/
+
+#ifdef NO_PARALLEL_THREADS
+
+class NgMutex { };
+
+class NgLock
+{
+public:	
+  NgLock (NgMutex & mut, bool lock = 0) { ; }
+  void Lock () { ; }
+  void UnLock () { ; }
+};
+
+
+#else
+
+#ifdef WIN32
+
+class NgMutex
+{
+  CCriticalSection cs;
+  
+public:
+  NgMutex () 
+  { ; }
+  friend class NgLock;
+};
+
+class NgLock
+{
+  CSingleLock sl;
+  bool locked;
+public:	
+  NgLock (NgMutex & mut, bool lock = 0)
+    : sl(&mut.cs)
+  {
+    if (lock) sl.Lock();
+    locked = lock;
+  }
+
+  ~NgLock ()
+  {
+    if (locked) sl.Unlock();
+  }
+
+  void Lock ()
+  {
+    sl.Lock(); 
+    locked = 1;
+  }
+
+  void UnLock ()
+  { 
+    sl.Unlock(); 
+    locked = 0;
+  }
+};
+
+#else
+
+
+#include <pthread.h>
+
+class NgMutex
+{
+  pthread_mutex_t mut;
+public:
+  NgMutex ()
+  {
+    pthread_mutex_init (&mut, NULL);
+  }
+  friend class NgLock;
+};
+
+class NgLock 
+{
+  pthread_mutex_t & mut;
+  bool locked;
+public:
+  NgLock (NgMutex & ngmut, bool lock = 0)
+    : mut (ngmut.mut)
+  { 
+    if (lock) pthread_mutex_lock (&mut); 
+    locked = lock;
+  };
+
+  ~NgLock()
+  {
+    if (locked) pthread_mutex_unlock (&mut); 
+  }
+  
+  void Lock ()
+  { 
+    pthread_mutex_lock (&mut); 
+    locked = 1;
+  }
+  void UnLock ()
+  { 
+    pthread_mutex_unlock (&mut); 
+    locked = 0;
+  }
+  /*
+  int TryLock ()
+  { 
+    return pthread_mutex_trylock (&mut); 
+  }
+  */
+};
+
+#endif
+
+#endif
+
+#endif
diff --git a/Netgen/libsrc/general/seti.cpp b/Netgen/libsrc/general/seti.cpp
new file mode 100644
index 0000000000..702337f076
--- /dev/null
+++ b/Netgen/libsrc/general/seti.cpp
@@ -0,0 +1,70 @@
+#include <mystdlib.h>
+#include <myadt.hpp>
+
+
+namespace netgen
+{
+  using namespace netgen;
+
+  IndexSet :: IndexSet (int maxind)
+  {
+    SetMaxIndex (maxind);
+  }
+
+  IndexSet :: ~IndexSet ()
+  {
+    Clear();
+  }
+
+
+  void IndexSet :: SetMaxIndex (int maxind)
+  {
+    if (maxind > flags.Size())
+      {
+	flags.SetSize (2 * maxind);
+	flags.Clear();
+      }
+  }
+
+  /*
+    int IndexSet :: IsIn (int ind) const
+    {
+    return flags.Test (ind);
+    }
+  */
+
+  /*
+    void IndexSet :: Add (int ind)
+    {
+    if (ind > flags.Size())
+    {
+    cerr << "out of range" << endl;
+    exit (1);
+    }
+
+    if (!flags.Test(ind))
+    {
+    set.Append (ind);
+    flags.Set (ind);
+    }
+    }
+  */
+
+  void IndexSet :: Del (int ind)
+  {
+    for (int i = 1; i <= set.Size(); i++)
+      if (set.Get(i) == ind)
+	{
+	  set.DeleteElement (ind);
+	  break;
+	}
+    flags.Clear (ind);
+  }
+
+  void IndexSet :: Clear ()
+  {
+    for (int i = 1; i <= set.Size(); i++)
+      flags.Clear (set.Get(i));
+    set.SetSize (0);
+  }
+}
diff --git a/Netgen/libsrc/general/seti.hpp b/Netgen/libsrc/general/seti.hpp
new file mode 100644
index 0000000000..4ca0b8eb4e
--- /dev/null
+++ b/Netgen/libsrc/general/seti.hpp
@@ -0,0 +1,45 @@
+#ifndef FILE_SETI
+#define FILE_SETI
+
+
+/**************************************************************************/
+/* File:   seti.hh                                                        */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   20. Mar. 98                                                    */
+/**************************************************************************/
+
+/**
+  Set of Integers
+  */
+class IndexSet
+{
+  ARRAY<int> set;
+  BitArray flags;
+public:
+  IndexSet (int maxind);
+  
+  ~IndexSet ();
+  /// increase range to maxind
+  void SetMaxIndex (int maxind);
+  int IsIn (int ind) const
+  { 
+    return flags.Test (ind); 
+  }
+
+  void Add (int ind)
+  {
+    if (!flags.Test(ind))
+      {
+	set.Append (ind);
+	flags.Set (ind);
+      }
+  }
+
+  void Del (int ind);
+  void Clear ();
+  
+  const ARRAY<int> & Array() { return set; }
+};
+
+#endif
+
diff --git a/Netgen/libsrc/general/sort.cpp b/Netgen/libsrc/general/sort.cpp
new file mode 100644
index 0000000000..b4f2c8c0b4
--- /dev/null
+++ b/Netgen/libsrc/general/sort.cpp
@@ -0,0 +1,74 @@
+/**************************************************************************/
+/* File:   sort.cc                                                        */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   07. Jan. 00                                                    */
+/**************************************************************************/
+
+/* 
+   Sorting
+*/
+
+
+#include <mystdlib.h>
+#include <myadt.hpp>
+
+namespace netgen
+{
+
+void Sort (const ARRAY<double> & values,
+	   ARRAY<int> & order)
+{
+  int n = values.Size();
+  int i, j;
+
+  order.SetSize (n);
+
+  for (i = 1; i <= n; i++)
+    order.Elem(i) = i;
+  for (i = 1; i <= n-1; i++)
+    for (j = 1; j <= n-1; j++)
+      if (values.Get(order.Elem(j)) > values.Get(order.Elem(j+1)))
+	{
+	  Swap (order.Elem(j), order.Elem(j+1));
+	}
+}
+
+
+void QickSortRec (const ARRAY<double> & values,
+		  ARRAY<int> & order, 
+		  int left, int right)
+{
+  int i, j;
+  double midval;
+
+  i = left;
+  j = right;
+  midval = values.Get(order.Get((i+j)/2));
+  
+  do
+    {
+      while (values.Get(order.Get(i)) < midval) i++;
+      while (midval < values.Get(order.Get(j))) j--;
+      
+      if (i <= j)
+	{
+	  Swap (order.Elem(i), order.Elem(j));
+	  i++; j--;
+	}
+    }
+  while (i <= j);
+  if (left < j) QickSortRec (values, order, left, j);
+  if (i < right) QickSortRec (values, order, i, right);
+}
+
+void QickSort (const ARRAY<double> & values,
+	       ARRAY<int> & order)
+{
+  int i, n = values.Size();
+  order.SetSize (n);
+  for (i = 1; i <= n; i++)
+    order.Elem(i) = i;
+
+  QickSortRec (values, order, 1, order.Size());
+}
+}
diff --git a/Netgen/libsrc/general/sort.hpp b/Netgen/libsrc/general/sort.hpp
new file mode 100644
index 0000000000..63a85dad45
--- /dev/null
+++ b/Netgen/libsrc/general/sort.hpp
@@ -0,0 +1,18 @@
+#ifndef FILE_SORT
+#define FILE_SORT
+
+/**************************************************************************/
+/* File:   sort.hh                                                        */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   07. Jan. 00                                                    */
+/**************************************************************************/
+
+// order(i) is sorted index of element i
+extern void Sort (const ARRAY<double> & values,
+		  ARRAY<int> & order);
+
+extern void QickSort (const ARRAY<double> & values,
+		      ARRAY<int> & order);
+
+		  
+#endif
diff --git a/Netgen/libsrc/general/spbita2d.cpp b/Netgen/libsrc/general/spbita2d.cpp
new file mode 100644
index 0000000000..e1e80e2cad
--- /dev/null
+++ b/Netgen/libsrc/general/spbita2d.cpp
@@ -0,0 +1,172 @@
+/**************************************************************************/
+/* File:   spbita2d.cpp                                                   */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Jun. 95                                                    */
+/**************************************************************************/
+
+/* 
+   Implementation of sparse 2 dimensional bitarray
+*/
+
+
+#include <mystdlib.h>
+#include <myadt.hpp>
+
+namespace netgen
+{
+  using namespace netgen;
+
+  SPARSE_BIT_ARRAY_2D :: SPARSE_BIT_ARRAY_2D (int ah, int aw)
+  {
+    lines = NULL;
+    SetSize (ah, aw);
+  }
+
+  SPARSE_BIT_ARRAY_2D :: ~SPARSE_BIT_ARRAY_2D ()
+  {
+    DeleteElements ();
+    delete lines;
+  }
+
+
+  void SPARSE_BIT_ARRAY_2D :: SetSize (int ah, int aw)
+  {
+    DeleteElements();
+    if (lines)
+      {
+	delete lines;
+	lines = NULL;
+      }
+
+    if (!aw) aw = ah;
+
+    height = ah;
+    width = aw;
+
+    if (!ah) return;
+    lines = new linestruct[ah];
+
+    if (lines)
+      {
+	for (int i = 0; i < ah; i++)
+	  {
+	    lines[i].size = 0;
+	    lines[i].maxsize = 0;
+	    lines[i].col = NULL;
+	  }
+      }
+    else
+      {
+	height = width = 0;
+	MyError ("SPARSE_ARRAY::SetSize: Out of memory");
+      }
+  }
+
+
+
+  void SPARSE_BIT_ARRAY_2D :: DeleteElements ()
+  {
+    if (lines)
+      {
+	for (int i = 0; i < height; i++)
+	  {
+	    if (lines[i].col)
+	      {
+		delete [] lines[i].col;
+		lines[i].col = NULL;
+		lines[i].size = 0;
+		lines[i].maxsize = 0;
+	      }
+	  }
+      }
+  }
+
+
+  int SPARSE_BIT_ARRAY_2D :: Test (int i, int j) const
+  {
+    int k, max, *col;
+
+    if (!lines) return 0;
+    if (i < 1 || i > height) return 0;
+
+    col = lines[i-1].col;
+    max = lines[i-1].size;
+
+    for (k = 0; k < max; k++, col++)
+      if (*col == j) return 1;
+
+    return 0;
+  }
+
+
+
+  void SPARSE_BIT_ARRAY_2D :: Set(int i, int j)
+  {
+    int k, max, *col;
+
+    i--;
+    col = lines[i].col;
+    max = lines[i].size;
+
+    for (k = 0; k < max; k++, col++)
+      if (*col == j)
+	return;
+
+    if (lines[i].size)
+      {
+	if (lines[i].size == lines[i].maxsize)
+	  {
+	    col = new int[lines[i].maxsize+2];
+	    if (col)
+	      {
+		lines[i].maxsize += 2;
+		memcpy (col, lines[i].col, sizeof (int) * lines[i].size);
+		delete [] lines[i].col;
+		lines[i].col = col;
+	      }
+	    else
+	      {
+		MyError ("SPARSE_BIT_ARRAY::Set: Out of mem 1");
+		return;
+	      }
+	  }
+	else
+	  col = lines[i].col;
+
+	if (col)
+	  {
+	    k = lines[i].size-1;
+	    while (k >= 0 && col[k] > j)
+	      {
+		col[k+1] = col[k];
+		k--;
+	      }
+
+	    k++;
+	    lines[i].size++;
+	    col[k] = j;
+	    return;
+	  }
+	else
+	  {
+	    MyError ("SPARSE_ARRAY::Set: Out of memory 2");
+	  }
+      }
+    else
+      {
+	lines[i].col = new int[4];
+	if (lines[i].col)
+	  {
+	    lines[i].maxsize = 4;
+	    lines[i].size = 1;
+	    lines[i].col[0] = j;
+	    return;
+	  }
+	else
+	  {
+	    MyError ("SparseMatrix::Elem: Out of memory 3");
+	  }
+      }
+  }
+
+}
diff --git a/Netgen/libsrc/general/spbita2d.hpp b/Netgen/libsrc/general/spbita2d.hpp
new file mode 100644
index 0000000000..db656653b1
--- /dev/null
+++ b/Netgen/libsrc/general/spbita2d.hpp
@@ -0,0 +1,56 @@
+#ifndef FILE_SPBITA2D
+#define FILE_SPBITA2D
+
+/**************************************************************************/
+/* File:   spbita2d.hh                                                    */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Jun. 95                                                    */
+/**************************************************************************/
+
+/** 
+   Implementation of sparse 2 dimensional bitarray
+*/
+
+
+class SPARSE_BIT_ARRAY_2D
+  {
+  class linestruct { public: INDEX size; INDEX maxsize; INDEX * col; };
+
+  ///
+  linestruct * lines;
+  ///
+  INDEX height, width;
+
+  public:
+
+  ///
+  SPARSE_BIT_ARRAY_2D (INDEX ah = 0, INDEX aw = 0);
+  ///
+  ~SPARSE_BIT_ARRAY_2D ();
+
+  ///
+  void SetSize (INDEX ah, INDEX aw = 0);
+  ///
+  void DeleteElements ();
+
+  ///
+  int Get (INDEX i, INDEX j) const;
+
+  ///
+  INDEX Height () const { return height; }
+  ///
+  INDEX Width () const { return width; }
+
+  ///
+  void Set (INDEX i, INDEX j);
+  ///
+  int Test (INDEX i, INDEX j) const;
+
+  ///
+  INDEX BitsInLine (INDEX i) const { return lines[i-1].size; }
+  ///
+  INDEX GetIndex (INDEX i, INDEX nr) const { return lines[i-1].col[nr-1]; }
+  };
+
+
+#endif
diff --git a/Netgen/libsrc/general/stack.hpp b/Netgen/libsrc/general/stack.hpp
new file mode 100644
index 0000000000..db8dfad266
--- /dev/null
+++ b/Netgen/libsrc/general/stack.hpp
@@ -0,0 +1,112 @@
+#ifndef FILE_STACK
+#define FILE_STACK
+
+/*****************************************************************************/
+/*  File: stack.hh                                                           */
+/*  Author: Wolfram Muehlhuber                                               */
+/*  Date: September 98                                                       */
+/*****************************************************************************/
+
+/*
+  
+  Stack class, based on a resizable array
+
+ */
+
+
+#include "array.hpp"
+
+
+///
+template <class T> class STACK
+{
+public:
+  ///
+  inline STACK (INDEX asize = 0, INDEX ainc = 0);
+  ///
+  inline ~STACK ();
+
+  ///
+  inline void Push (const T & el);
+  ///
+  inline T & Pop ();
+  ///
+  const inline T & Top () const;
+  ///
+  inline int IsEmpty () const;
+  ///
+  inline void MakeEmpty ();
+
+private:
+  ///
+  ARRAY<T> elems;
+  ///
+  INDEX size;
+};
+
+
+
+
+/*
+  
+  Stack class, based on a resizable array
+
+ */
+
+template <class T>
+inline STACK<T> :: STACK (INDEX asize, INDEX ainc)
+  : elems(asize, ainc)
+{
+  size = 0;
+}
+
+
+template <class T>
+inline STACK<T> :: ~STACK ()
+{
+  ;
+}
+
+
+template <class T> 
+inline void STACK<T> :: Push (const T & el)
+{
+  if (size < elems.Size())
+    elems.Elem(++size) = el;
+  else
+    {
+      elems.Append(el);
+      size++;
+    }
+}
+
+
+template <class T> 
+inline T & STACK<T> :: Pop ()
+{
+  return elems.Elem(size--);
+}
+
+
+template <class T>
+const inline T & STACK<T> :: Top () const
+{
+  return elems.Get(size);
+}
+
+template <class T>
+inline int STACK<T> :: IsEmpty () const
+{
+  return (size == 0);
+}
+
+
+template <class T>
+inline void STACK<T> :: MakeEmpty ()
+{
+  size = 0;
+}
+
+
+
+#endif
diff --git a/Netgen/libsrc/general/symbolta.cpp b/Netgen/libsrc/general/symbolta.cpp
new file mode 100644
index 0000000000..b02daa65dc
--- /dev/null
+++ b/Netgen/libsrc/general/symbolta.cpp
@@ -0,0 +1,52 @@
+/**************************************************************************/
+/* File:   symbolta.cc                                                    */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Jun. 95                                                    */
+/**************************************************************************/
+
+/* 
+   Abstract data type Symbol Table
+*/
+
+#include <mystdlib.h>
+#include <myadt.hpp>
+
+
+#ifndef FILE_SYMBOLTABLECC
+#define FILE_SYMBOLTABLECC
+// necessary for SGI ????
+
+
+namespace netgen
+{
+  using namespace netgen;
+
+  BASE_SYMBOLTABLE :: BASE_SYMBOLTABLE ()
+  {
+    ;
+  }
+
+
+  BASE_SYMBOLTABLE :: ~BASE_SYMBOLTABLE()
+  {
+    DelNames();
+  }
+
+
+  void BASE_SYMBOLTABLE :: DelNames()
+  {
+    for (int i = 0; i < names.Size(); i++)
+      delete [] names[i];
+    names.SetSize (0);
+  }
+
+  int BASE_SYMBOLTABLE :: Index (const char * name) const
+  {
+    if (!name) return 0;
+    for (int i = 0; i < names.Size(); i++)
+      if (strcmp (names[i], name) == 0) return i+1;
+    return 0;
+  }
+}
+
+#endif
diff --git a/Netgen/libsrc/general/symbolta.hpp b/Netgen/libsrc/general/symbolta.hpp
new file mode 100644
index 0000000000..e429c7d19b
--- /dev/null
+++ b/Netgen/libsrc/general/symbolta.hpp
@@ -0,0 +1,158 @@
+#ifndef FILE_SYMBOLTA
+#define FILE_SYMBOLTA
+
+
+/**************************************************************************/
+/* File:   symbolta.hh                                                    */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Jun. 95                                                    */
+/**************************************************************************/
+
+/**
+  Base class for the generic SYMBOLTABLE.
+  An array of identifiers is maintained.
+ */
+class BASE_SYMBOLTABLE
+{
+protected:
+  /// identifiers
+  ARRAY <char*> names;
+  
+public:
+  /// Constructor
+  BASE_SYMBOLTABLE ();
+  ///
+  ~BASE_SYMBOLTABLE ();
+  ///
+  void DelNames ();
+  /// Index of symbol name, returns 0 if not used.
+  int Index (const char * name) const;
+};
+
+
+/** 
+   Abstract data type Symbol Table.
+   
+   To a string an value of the generic type T is associated.
+   The string is not copied into the symbol table class!
+*/
+template <class T>
+class SYMBOLTABLE : public BASE_SYMBOLTABLE
+{
+  /// Associated data
+  ARRAY <T> data;
+  
+public:
+  /// Creates a symboltable
+  inline SYMBOLTABLE ();
+  /// Returns size of symboltable
+  inline INDEX Size() const;
+  /// Returns reference to element, error if not used
+  inline T & Elem (const char * name);
+  /// Returns reference to i-th element
+  inline T & Elem (int i) 
+    { return data.Elem(i); }
+  /// Returns element, error if not used
+  inline const T & Get (const char * name) const;
+  /// Returns i-th element
+  inline const T & Get (int i) const;
+  /// Returns name of i-th element
+  inline const char* GetName (int i) const;
+  /// Associates el to the string name, overrides if name is used
+  inline void Set (const char * name, const T & el);
+  /// Checks whether name is used
+  inline int Used (const char * name) const;
+  /// Deletes symboltable
+  inline void DeleteAll ();
+
+  inline T & operator[] (int i) 
+    { return data[i]; }
+  inline const T & operator[] (int i) const
+    { return data[i]; }
+
+private:
+  /// Prevents from copying symboltable by pointer assignment
+  SYMBOLTABLE<T> & operator= (SYMBOLTABLE<T> &);
+};
+
+
+
+
+template <class T>
+inline SYMBOLTABLE<T> :: SYMBOLTABLE () 
+  { 
+    ;
+  }
+
+
+template <class T>
+inline INDEX SYMBOLTABLE<T> :: Size() const
+  {
+  return data.Size();
+  }
+
+template <class T>
+inline T & SYMBOLTABLE<T> :: Elem (const char * name)
+  {
+  int i;
+  i = Index (name);
+  if (i) 
+    return data.Elem (i);
+  else 
+    return data.Elem(1);
+  }
+
+template <class T>
+inline const T & SYMBOLTABLE<T> :: Get (const char * name) const
+  {
+  int i;
+  i = Index (name);
+  if (i) 
+    return data.Get(i);
+  else 
+    return data.Get(1);
+  }
+
+template <class T>
+inline const T & SYMBOLTABLE<T> :: Get (int i) const
+  {
+  return data.Get(i);
+  }
+
+template <class T>
+inline const char* SYMBOLTABLE<T> :: GetName (int i) const
+  {
+  return names.Get(i);
+  }
+
+template <class T>
+inline void SYMBOLTABLE<T> :: Set (const char * name, const T & el)
+  {
+  int i;
+  i = Index (name);
+  if (i) 
+    data.Set(i, el);
+  else
+    {
+    data.Append (el);
+    char * hname = new char [strlen (name) + 1];
+    strcpy (hname, name);
+    names.Append (hname);
+    }
+  }
+
+template <class T>
+inline int SYMBOLTABLE<T> :: Used (const char * name) const
+  {
+  return (Index(name)) ? 1 : 0;
+  }
+
+template <class T>
+inline void SYMBOLTABLE<T> :: DeleteAll () 
+  {	
+  DelNames();
+  data.DeleteAll();
+  }
+
+
+#endif
diff --git a/Netgen/libsrc/general/table.cpp b/Netgen/libsrc/general/table.cpp
new file mode 100644
index 0000000000..7dcd5557d3
--- /dev/null
+++ b/Netgen/libsrc/general/table.cpp
@@ -0,0 +1,192 @@
+/**************************************************************************/
+/* File:   table.cpp                                                      */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Jun. 95                                                    */
+/**************************************************************************/
+
+/* 
+   Abstract data type TABLE
+*/
+
+#include <mystdlib.h>
+#include <myadt.hpp>
+
+namespace netgen
+{
+  using namespace netgen;
+
+  BASE_TABLE :: BASE_TABLE (int size)
+    : data(size)
+  {
+    for (int i = 0; i < size; i++)
+      {
+	data[i].maxsize = 0;
+	data[i].size = 0;
+	data[i].col = NULL;
+      }
+    oneblock = NULL;
+  }
+
+  BASE_TABLE :: BASE_TABLE (const FlatArray<int> & entrysizes, int elemsize)
+    : data(entrysizes.Size())
+  {
+    int i, cnt = 0;
+    int n = entrysizes.Size();
+
+    for (i = 0; i < n; i++)
+      cnt += entrysizes[i];
+    oneblock = new char[elemsize * cnt];
+    // mem_total_alloc_table += elemsize * cnt;
+
+    cnt = 0;
+    for (i = 0; i < n; i++)
+      {
+	data[i].maxsize = entrysizes[i];
+	data[i].size = 0;
+
+	data[i].col = &oneblock[elemsize * cnt];
+	cnt += entrysizes[i];
+      }
+  }
+
+  BASE_TABLE :: ~BASE_TABLE ()
+  {
+    if (oneblock)
+      delete [] oneblock;
+    else
+      {
+	for (int i = 0; i < data.Size(); i++)
+	  delete [] (char*)data[i].col;
+      }
+  }
+  
+  void BASE_TABLE :: SetSize (int size)
+  {
+    int i;
+    for (i = 0; i < data.Size(); i++)
+      delete [] (char*)data[i].col;
+    
+    data.SetSize(size);
+    for (i = 0; i < size; i++)
+      {
+	data[i].maxsize = 0;
+	data[i].size = 0;
+	data[i].col = NULL;
+      }    
+  }
+
+  void BASE_TABLE :: IncSize2 (int i, int elsize)
+  {
+    if (i < 1 || i > data.Size())
+      {
+	MyError ("BASE_TABLE::Inc: Out of range");
+	return;
+      }
+  
+    linestruct & line = data.Elem (i);
+  
+    if (line.size == line.maxsize)
+      {
+	/*
+	  static int totalloc = 0, cnt = 0;
+	  totalloc += (line.maxsize+5) * elsize;
+	  cnt ++;
+
+	  if (cnt % 100000 == 0)
+	  cout << "base_table: total alloc = " << totalloc << endl;
+	*/
+
+	void * p = new char [(line.maxsize+5) * elsize];
+	// mem_total_alloc_table += (line.maxsize+5) * elsize;
+
+
+	if (!p)
+	  {
+	    MyError ("BASE_TABLE::Inc: Out of memory");
+	    return;
+	  }
+      
+	memcpy (p, line.col, line.maxsize * elsize);
+	delete [] (char*)line.col;
+	line.col = p;
+	line.maxsize += 5;
+      }
+  
+    line.size++;
+  }
+
+  void BASE_TABLE :: DecSize (int i)
+  {
+    if (i < 1 || i > data.Size())
+      {
+	MyError ("BASE_TABLE::Dec: Out of range");
+	return;
+      }
+  
+    linestruct & line = data.Elem (i);
+  
+    if (line.size == 0)
+      {
+	MyError ("BASE_TABLE::Dec: EntrySize < 0");
+	return;      
+      }
+  
+    line.size--;
+  }
+
+
+  /*
+  void BASE_TABLE :: IncSizePrepare (int i)
+  {
+    data.Elem(i).maxsize++;
+  }
+  */
+
+
+  void BASE_TABLE :: AllocateElementsOneBlock (int elemsize)
+  {
+    int i, cnt = 0;
+    int n = data.Size();
+
+    for (i = 1; i <= n; i++)
+      cnt += data.Get(i).maxsize;
+    oneblock = new char[elemsize * cnt];
+    // mem_total_alloc_table += elemsize * cnt;
+
+    //  cout << "Allocate oneblock, mem = " << (elemsize * cnt) << endl;
+
+    cnt = 0;
+    for (i = 1; i <= n; i++)
+      {
+	data.Elem(i).size = 0;
+
+	data.Elem(i).col = &oneblock[elemsize * cnt];
+	cnt += data.Elem(i).maxsize;
+      }
+  
+  }
+
+
+
+
+
+
+
+
+  int BASE_TABLE :: AllocatedElements () const
+  {
+    int els = 0;
+    for (int i = 0; i < data.Size(); i++)
+      els += data[i].maxsize;
+    return els;
+  }
+
+  int BASE_TABLE :: UsedElements () const
+  {
+    int els = 0;
+    for (int i = 0; i < data.Size(); i++)
+      els += data[i].size;
+    return els;
+  }
+
+}
diff --git a/Netgen/libsrc/general/table.hpp b/Netgen/libsrc/general/table.hpp
new file mode 100644
index 0000000000..21c6d41a60
--- /dev/null
+++ b/Netgen/libsrc/general/table.hpp
@@ -0,0 +1,202 @@
+#ifndef FILE_TABLE
+#define FILE_TABLE
+
+/**************************************************************************/
+/* File:   table.hpp                                                      */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Jun. 95                                                    */
+/**************************************************************************/
+
+/// Base class to generic class TABLE.
+class BASE_TABLE
+{
+protected:
+  
+  ///
+  class linestruct
+  {
+  public:
+    ///
+    int size;
+    /// 
+    int maxsize;
+    ///
+    void * col;
+  };
+  
+  ///
+  ARRAY<linestruct> data;
+  char * oneblock;
+
+public:
+  ///
+  BASE_TABLE (int size);
+  ///
+  BASE_TABLE (const FlatArray<int> & entrysizes, int elemsize);
+  ///
+  ~BASE_TABLE ();
+  ///
+  void SetSize (int size);
+  ///
+  void IncSize (int i, int elsize)
+  {
+    if (data.Elem(i).size < data.Elem(i).maxsize)
+      data.Elem(i).size++;
+    else
+      IncSize2 (i, elsize);
+  }
+  ///
+  void IncSize2 (int i, int elsize);
+
+  void DecSize (int i);
+
+  ///
+  void AllocateElementsOneBlock (int elemsize);
+
+  int AllocatedElements () const;
+  int UsedElements () const;
+};
+
+
+
+
+
+
+
+/** 
+   Abstract data type TABLE.
+   
+   To an integer i in the range from 1 to size a set of elements of the
+   generic type T is associated. 
+*/
+template <class T, int BASE = 0>
+class TABLE : public BASE_TABLE
+{
+public:
+  /// Creates table.
+  inline TABLE () : BASE_TABLE(0) { ; }
+
+  /// Creates table of size size
+  inline TABLE (int size) : BASE_TABLE (size) { ; }
+
+  /// Creates fixed element size table
+  inline TABLE (const FlatArray<int,BASE> & entrysizes)
+    : BASE_TABLE (FlatArray<int> (entrysizes.Size(), const_cast<int*>(&entrysizes[BASE])), 
+		  sizeof(T))
+  { ; }
+  
+  /// Changes Size of table to size, deletes data
+  inline void SetSize (int size)
+  {
+    BASE_TABLE::SetSize (size);
+  }
+
+
+  /// Inserts element acont into row i, 1-based. Does not test if already used.
+  inline void Add (int i, const T & acont)
+  {
+    IncSize (i-BASE+1, sizeof (T));
+    ((T*)data[i-BASE].col)[data[i-BASE].size-1] = acont;
+  }
+
+  ///
+  void IncSizePrepare (int i)
+  {
+    data[i-BASE].maxsize++;
+  }
+
+
+  /// Inserts element acont into row i, 1-based. Does not test if already used.
+  inline void Add1 (int i, const T & acont)
+  {
+    IncSize (i, sizeof (T));
+    ((T*)data.Elem(i).col)[data.Elem(i).size-1] = acont;
+  }
+  
+  /// Inserts element acont into row i. Does not test if already used, assumes to have mem
+  inline void AddSave (int i, const T & acont)
+    {
+      ((T*)data.Elem(i).col)[data.Elem(i).size] = acont;
+      data.Elem(i).size++;
+    }
+
+  /// Inserts element acont into row i. Does not test if already used.
+  inline void AddEmpty (int i)
+  {
+    IncSize (i, sizeof (T));
+  }
+
+  /** Set the nr-th element in the i-th row to acont.
+    Does not check for overflow. */
+  inline void Set (int i, int nr, const T & acont)
+    { ((T*)data.Get(i).col)[nr-1] = acont; }
+  /** Returns the nr-th element in the i-th row.
+    Does not check for overflow. */
+  inline const T & Get (int i, int nr) const
+    { return ((T*)data.Get(i).col)[nr-1]; }
+
+
+  /** Returns pointer to the first element in row i. */
+  inline const T * GetLine (int i) const
+  {
+    return ((const T*)data.Get(i).col);
+  }
+
+
+  /// Returns size of the table.
+  inline int Size () const
+  {
+    return data.Size();
+  }
+
+  /// Returns size of the i-th row.
+  inline int EntrySize (int i) const
+    { return data.Get(i).size; }
+
+  inline void DecEntrySize (int i)
+    { DecSize(i); }
+
+  void AllocateElementsOneBlock ()
+    { BASE_TABLE::AllocateElementsOneBlock (sizeof(T)); }
+
+
+  inline void PrintMemInfo (ostream & ost) const
+  {
+    int els = AllocatedElements(); 
+    ost << "table: allocaed " << els 
+	<< " a " << sizeof(T) << " Byts = " 
+	<< els * sizeof(T) 
+	<< " bytes in " << Size() << " bags."
+	<< " used: " << UsedElements()
+	<< endl;
+  }
+
+  /// Access entry.
+  FlatArray<T> operator[] (int i) const
+  { 
+#ifdef DEBUG
+    if (i-BASE < 0 || i-BASE >= data.Size())
+      cout << "table out of range, i = " << i << ", s = " << data.Size() << endl;
+#endif
+
+    return FlatArray<T> (data[i-BASE].size, (T*)data[i-BASE].col);
+  }
+};
+
+
+template <class T, int BASE>
+inline ostream & operator<< (ostream & ost, TABLE<T,BASE> & table)
+{
+  for (int i = BASE; i < table.Size()+BASE; i++)
+    {
+      ost << i << ": ";
+      FlatArray<T> row = table[i];
+      for (int j = 0; j < row.Size(); j++)
+	ost << row[j] << " ";
+      ost << endl;
+    }
+  return ost;
+}
+
+#endif
+
diff --git a/Netgen/libsrc/general/template.hpp b/Netgen/libsrc/general/template.hpp
new file mode 100644
index 0000000000..47c7a1ad2e
--- /dev/null
+++ b/Netgen/libsrc/general/template.hpp
@@ -0,0 +1,422 @@
+#ifndef FILE_TEMPLATE
+#define FILE_TEMPLATE
+
+/**************************************************************************/
+/* File:   template.hh                                                    */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Jun. 95                                                    */
+/**************************************************************************/
+
+/*
+   templates, global types, defines and variables
+*/
+
+///	The following value may be adapted to the hardware !
+#ifndef CLOCKS_PER_SEC
+#define CLOCKS_PER_SEC 1000000
+#endif
+
+
+// #include <iostream>
+/** output stream for testing.
+  testout is opened by main */
+extern ostream * testout;
+
+/** use instead of cout */
+extern ostream * mycout;
+
+/** error output stream */
+extern ostream * myerr;
+
+/** Error messages display.
+  Error messages are displayed by this function */
+extern void MyError (const char * ch);
+
+
+/** Rings the bell.
+  Produces nr beeps. */
+extern void MyBeep (int nr = 1);
+
+
+template <class T>
+inline void Swap (T & a, T & b)
+{
+  T temp = a;
+  a = b;
+  b = temp;
+}
+
+/*
+template <class T>
+inline void swap (T & a, T & b)
+{
+  T temp = a;
+  a = b;
+  b = temp;
+}
+*/
+
+
+
+/**
+  INDEX is a typedef for (at least) 4-byte integer
+ */
+typedef int INDEX;
+
+/**
+  BOOL is a typedef for boolean variables
+  */
+// typedef int BOOL;
+
+typedef int ELIND;
+typedef int PIND;
+
+
+class twoint 
+{ 
+public: ///
+  int i1, i2; ///
+  twoint() {};
+  ///
+  twoint(int ii1, int ii2) {i1 = ii1; i2 = ii2;}
+  friend int operator== (const twoint& t1, const twoint& t2);
+  ///
+  void Swap() {int x = i1; i1 = i2; i2 = x;}
+  void Sort() {if (i1 > i2) {Swap();}}
+};
+
+inline int operator== (const twoint& t1, const twoint& t2) 
+{
+  return t1.i1 == t2.i1 && t1.i2 == t2.i2;
+}
+
+class threeint 
+{ 
+public: /// 
+  int i1, i2, i3; ///
+  threeint() {}; 
+  ///
+  threeint(int ii1, int ii2, int ii3) {i1 = ii1; i2 = ii2; i3 = ii3;}
+};
+
+///
+class twodouble
+{
+public:
+  ///
+  double d1, d2;
+  ///
+  twodouble() {d1 = 0; d2 = 0;};
+  ///
+  twodouble(double id1, double id2) {d1 = id1; d2 = id2;}
+  ///
+  void Swap() {double x = d1; d1 = d2; d2 = x;}
+};
+
+class fourint { public: int i1, i2, i3, i4; fourint() {}; };
+
+
+///
+class INDEX_2;
+ostream & operator<<(ostream  & s, const INDEX_2 & i2);
+
+
+class INDEX_2
+{
+  ///
+  INDEX i[2];
+
+public:
+  ///
+  INDEX_2 () { }
+  ///
+  INDEX_2 (INDEX ai1, INDEX ai2)
+    { i[0] = ai1; i[1] = ai2; }
+
+  ///
+  INDEX_2 (const INDEX_2 & in2)
+    { i[0] = in2.i[0]; i[1] = in2.i[1]; }
+
+  ///
+  int operator== (const INDEX_2 & in2) const
+    { return i[0] == in2.i[0] && i[1] == in2.i[1]; }
+
+  ///
+  void Sort ()
+    {
+      if (i[0] > i[1]) 
+	{
+	  INDEX hi = i[0];
+	  i[0] = i[1];
+	  i[1] = hi;
+	}
+    }
+  ///
+  INDEX & I1 () { return i[0]; }
+  ///
+  INDEX & I2 () { return i[1]; }
+  ///
+  INDEX & I (int j) { return i[j-1]; }
+  ///
+  const INDEX & I1 () const { return i[0]; }
+  ///
+  const INDEX & I2 () const { return i[1]; }
+  ///
+  const INDEX & I (int j) const { return i[j-1]; }
+  ///
+  int & operator[] (int j) { return i[j]; }
+  ///
+  const int & operator[] (int j) const { return i[j]; }
+  ///
+  friend ostream & operator<<(ostream  & s, const INDEX_2 & i2);
+};
+
+
+///
+class INDEX_3
+{
+  ///
+  INDEX i[3];
+
+public:
+  ///
+  INDEX_3 () { }
+  ///
+  INDEX_3 (INDEX ai1, INDEX ai2, INDEX ai3)
+    { i[0] = ai1; i[1] = ai2; i[2] = ai3; }
+
+  ///
+  INDEX_3 (const INDEX_3 & in2)
+    { i[0] = in2.i[0]; i[1] = in2.i[1]; i[2] = in2.i[2]; }
+
+  ///
+  void Sort ()
+  {
+    if (i[0] > i[1]) Swap (i[0], i[1]);
+    if (i[1] > i[2]) Swap (i[1], i[2]);
+    if (i[0] > i[1]) Swap (i[0], i[1]);
+  }
+
+  ///
+  int operator== (const INDEX_3 & in2) const
+    { return i[0] == in2.i[0] && i[1] == in2.i[1] && i[2] == in2.i[2];}
+
+  ///
+  INDEX & I1 () { return i[0]; }
+  ///
+  INDEX & I2 () { return i[1]; }
+  ///
+  INDEX & I3 () { return i[2]; }
+  ///
+  INDEX & I (int j) { return i[j-1]; }
+  ///
+  const INDEX & I1 () const { return i[0]; }
+  ///
+  const INDEX & I2 () const { return i[1]; }
+  ///
+  const INDEX & I3 () const { return i[2]; }
+  ///
+  const INDEX & I (int j) const { return i[j-1]; }
+  ///
+  int & operator[] (int j) { return i[j]; }
+  ///
+  const int & operator[] (int j) const { return i[j]; }
+
+  ///
+  friend ostream & operator<<(ostream  & s, const INDEX_3 & i3);
+};
+
+
+
+///
+class INDEX_4
+{
+  ///
+  INDEX i[4];
+
+public:
+  ///
+  INDEX_4 () { }
+  ///
+  INDEX_4 (INDEX ai1, INDEX ai2, INDEX ai3, INDEX ai4)
+    { i[0] = ai1; i[1] = ai2; i[2] = ai3; i[3] = ai4; }
+
+  ///
+  INDEX_4 (const INDEX_4 & in2)
+    { i[0] = in2.i[0]; i[1] = in2.i[1]; i[2] = in2.i[2]; i[3] = in2.i[3]; }
+
+  ///
+  void Sort ();
+
+  ///
+  int operator== (const INDEX_4 & in2) const
+    { return 
+	i[0] == in2.i[0] && i[1] == in2.i[1] && 
+	i[2] == in2.i[2] && i[3] == in2.i[3]; }
+
+  ///
+  INDEX & I1 () { return i[0]; }
+  ///
+  INDEX & I2 () { return i[1]; }
+  ///
+  INDEX & I3 () { return i[2]; }
+  ///
+  INDEX & I4 () { return i[3]; }
+  ///
+  INDEX & I (int j) { return i[j-1]; }
+  ///
+  const INDEX & I1 () const { return i[0]; }
+  ///
+  const INDEX & I2 () const { return i[1]; }
+  ///
+  const INDEX & I3 () const { return i[2]; }
+  ///
+  const INDEX & I4 () const { return i[3]; }
+  ///
+  const INDEX & I (int j) const { return i[j-1]; }
+  ///
+  int & operator[] (int j) { return i[j]; }
+  ///
+  const int & operator[] (int j) const { return i[j]; }
+
+  ///
+  friend ostream & operator<<(ostream  & s, const INDEX_4 & i4);
+};
+
+
+
+
+
+
+
+
+/// The sort preserves quads !!!
+class INDEX_4Q
+{
+  ///
+  INDEX i[4];
+
+public:
+  ///
+  INDEX_4Q () { }
+  ///
+  INDEX_4Q (INDEX ai1, INDEX ai2, INDEX ai3, INDEX ai4)
+    { i[0] = ai1; i[1] = ai2; i[2] = ai3; i[3] = ai4; }
+
+  ///
+  INDEX_4Q (const INDEX_4Q & in2)
+    { i[0] = in2.i[0]; i[1] = in2.i[1]; i[2] = in2.i[2]; i[3] = in2.i[3]; }
+
+  ///
+  void Sort ();
+
+  ///
+  int operator== (const INDEX_4Q & in2) const
+    { return 
+	i[0] == in2.i[0] && i[1] == in2.i[1] && 
+	i[2] == in2.i[2] && i[3] == in2.i[3]; }
+
+  ///
+  INDEX & I1 () { return i[0]; }
+  ///
+  INDEX & I2 () { return i[1]; }
+  ///
+  INDEX & I3 () { return i[2]; }
+  ///
+  INDEX & I4 () { return i[3]; }
+  ///
+  INDEX & I (int j) { return i[j-1]; }
+  ///
+  const INDEX & I1 () const { return i[0]; }
+  ///
+  const INDEX & I2 () const { return i[1]; }
+  ///
+  const INDEX & I3 () const { return i[2]; }
+  ///
+  const INDEX & I4 () const { return i[3]; }
+  ///
+  const INDEX & I (int j) const { return i[j-1]; }
+  ///
+  friend ostream & operator<<(ostream  & s, const INDEX_4Q & i4);
+};
+
+
+
+
+
+
+
+
+
+
+
+
+///
+template <class T>
+inline T min2 (T a, T b)
+{
+  ///
+  return (a < b) ? a : b;
+}
+///
+template <class T>
+inline T max2 (T a, T b)
+{
+  ///
+  return (a > b) ? a : b;
+}
+///
+template <class T>
+inline T min3 (T a, T b, T c)
+{
+  ///
+  return (a < b) ? (a < c) ? a : c
+    : (b < c) ? b : c;
+}
+///
+template <class T>
+inline T max3 (T a, T b, T c)
+{
+  ///
+  return (a > b) ? ((a > c) ? a : c)
+    : ((b > c) ? b : c);
+}
+
+///
+
+///
+template <class T>
+inline int sgn (T a)
+{
+  return (a > 0) ? 1 : (   ( a < 0) ? -1 : 0 );
+}
+
+///
+template <class T>
+inline T sqr (const T a)
+{
+  return a * a; 
+}
+
+///
+template <class T>
+inline T pow3 (const T a)
+{
+  return a * a * a; 
+}
+
+
+
+/*
+template <class T>
+void BubbleSort (int size, T * data);
+
+template <class T>
+void MergeSort (int size, T * data, T * help);
+*/
+
+
+
+
+
+#endif
diff --git a/Netgen/libsrc/geom2d/Makefile b/Netgen/libsrc/geom2d/Makefile
new file mode 100644
index 0000000000..8371fa19e7
--- /dev/null
+++ b/Netgen/libsrc/geom2d/Makefile
@@ -0,0 +1,12 @@
+#
+# Makefile for geometric library
+#
+src =  spline2d.cpp geom2dmesh.cpp splinegeometry2.cpp genmesh2d.cpp
+#
+lib = geom2d
+libpath = libsrc/geom2d
+#
+#
+include ../makefile.inc
+#
+
diff --git a/Netgen/libsrc/geom2d/genmesh2d.cpp b/Netgen/libsrc/geom2d/genmesh2d.cpp
new file mode 100644
index 0000000000..db31208940
--- /dev/null
+++ b/Netgen/libsrc/geom2d/genmesh2d.cpp
@@ -0,0 +1,121 @@
+#include <mystdlib.h>
+#include <csg.hpp>
+#include <geometry2d.hpp>
+#include "meshing.hpp"
+
+namespace netgen
+{
+
+  // static ARRAY<Point<2> > points2;
+  //  static ARRAY<int> lp1, lp2;
+
+
+  extern void Optimize2d (Mesh & mesh, MeshingParameters & mp);
+
+
+
+
+  void MeshFromSpline2D (SplineGeometry2d & geometry,
+			 Mesh *& mesh, 
+			 MeshingParameters & mp)
+  {
+    int i, j, domnr;
+    double elto0, minx, miny, maxx, maxy;
+
+    PointIndex pi;
+    SegmentIndex si;
+    SurfaceElementIndex sei;
+
+    double h = mp.maxh;
+
+    Box<2> bbox;
+    geometry.GetBoundingBox (bbox);
+
+    if (bbox.Diam() < h) 
+      {
+	h = bbox.Diam();
+	mp.maxh = h;
+      }
+
+    mesh = new Mesh;
+    mesh->SetDimension (2);
+    PrintMessage (1, "Generate Mesh from spline geometry");
+
+    geometry.PartitionBoundary (h, *mesh);
+
+    int maxdomnr = 0;
+    for (si = 0; si < mesh->GetNSeg(); si++)
+      {
+	if ( (*mesh)[si].domin > maxdomnr) maxdomnr = (*mesh)[si].domin;
+	if ( (*mesh)[si].domout > maxdomnr) maxdomnr = (*mesh)[si].domout;
+      }
+  
+
+    mesh->ClearFaceDescriptors();
+    for (i = 1; i <= maxdomnr; i++)
+      mesh->AddFaceDescriptor (FaceDescriptor (i, 0, 0, i));
+
+    Point3d pmin(bbox.PMin()(0), bbox.PMin()(1), -bbox.Diam());
+    Point3d pmax(bbox.PMax()(0), bbox.PMax()(1), bbox.Diam());
+
+    mesh->SetLocalH (pmin, pmax, mparam.grading);
+    mesh->SetGlobalH (h);
+  
+    mesh->CalcLocalH();
+
+    int bnp = mesh->GetNP(); // boundary points
+
+    for (domnr = 1; domnr <= maxdomnr; domnr++)
+      {
+	PrintMessage (3, "Meshing domain ", domnr, " / ", maxdomnr);
+
+	int oldnf = mesh->GetNSE();
+
+	Meshing2 meshing (Box3d (pmin, pmax));
+
+	for (pi = PointIndex::BASE; 
+	     pi < bnp+PointIndex::BASE; pi++)
+	  meshing.AddPoint ( (*mesh)[pi], pi);
+      
+
+	PointGeomInfo gi;
+	gi.trignum = 1;
+	for (si = 0; si < mesh->GetNSeg(); si++)
+	  {
+	    if ( (*mesh)[si].domin == domnr)
+	      meshing.AddBoundaryElement ( (*mesh)[si].p1 + 1 - PointIndex::BASE, 
+					   (*mesh)[si].p2 + 1 - PointIndex::BASE, gi, gi);
+	    if ( (*mesh)[si].domout == domnr)
+	      meshing.AddBoundaryElement ( (*mesh)[si].p2 + 1 - PointIndex::BASE, 
+					   (*mesh)[si].p1 + 1 - PointIndex::BASE, gi, gi);
+	  }
+
+
+	mparam.checkoverlap = 0;
+	meshing.GenerateMesh (*mesh, h, domnr);
+
+	for (sei = oldnf; sei < mesh->GetNSE(); sei++)
+	  (*mesh)[sei].SetIndex (domnr);
+      }
+
+
+    int hsteps = mp.optsteps2d;
+
+    mp.optimize2d = "smcm"; 
+    mp.optsteps2d = hsteps/2;
+    Optimize2d (*mesh, mp);
+
+    mp.optimize2d = "Smcm"; 
+    mp.optsteps2d = (hsteps+1)/2;
+    Optimize2d (*mesh, mp);
+
+    mp.optsteps2d = hsteps;
+
+
+
+    mesh->Compress();
+    mesh -> SetNextMajorTimeStamp();
+  }
+
+
+}
diff --git a/Netgen/libsrc/geom2d/geom2dmesh.cpp b/Netgen/libsrc/geom2d/geom2dmesh.cpp
new file mode 100644
index 0000000000..3ca3275d29
--- /dev/null
+++ b/Netgen/libsrc/geom2d/geom2dmesh.cpp
@@ -0,0 +1,96 @@
+#include <mystdlib.h>
+
+#include <csg.hpp>
+#include <geometry2d.hpp>
+#include <meshing.hpp>
+
+namespace netgen
+{
+
+Refinement2d :: Refinement2d (const SplineGeometry2d & ageometry)
+  : Refinement(), geometry(ageometry)
+{
+  ;
+}
+
+Refinement2d :: ~Refinement2d ()
+{
+  ;
+}
+  
+
+
+void Refinement2d :: 
+PointBetween (const Point3d & p1, const Point3d & p2, double secpoint,
+	      int surfi, 
+	      const PointGeomInfo & gi1, 
+	      const PointGeomInfo & gi2,
+	      Point3d & newp, PointGeomInfo & newgi)
+{
+  newp = p1+secpoint*(p2-p1);
+  newgi.trignum = 1;
+  /*
+  if (surfi)
+    {
+      //      (*testout) << "surfi1 = " << surfi << endl;
+      //      (*testout) << "np = " << newp << endl;
+      geometry.GetSurface (surfi) -> Project (newp);
+      newgi.trignum = 1;
+      //      (*testout) << "np2 = " << newp << endl;
+    }
+  */
+}
+
+
+
+void Refinement2d :: 
+PointBetween (const Point3d & p1, const Point3d & p2, double secpoint, 
+	      int surfi1, int surfi2, 
+	      const EdgePointGeomInfo & ap1, 
+	      const EdgePointGeomInfo & ap2,
+	      Point3d & newp, EdgePointGeomInfo & newgi)
+{
+  Point<2> p2d;
+
+  p2d = geometry.GetSplines().Get(ap1.edgenr) -> 
+    GetPoint (((1-secpoint)*ap1.dist+secpoint*ap2.dist));
+
+
+/*
+
+  // test routine: general function on first edge
+
+  double x = secpoint;
+  if (ap1.edgenr == 1)
+      p2d = Point<2>((1-secpoint),fabs(x-0.5) < 0.2 ? (1+cos((x-0.5)*M_PI/0.2))*0.1 : 0);
+
+*/
+
+  //  (*testout) << "refine 2d line, ap1.dist, ap2.dist = " << ap1.dist << ", " << ap2.dist << endl;
+  //  (*testout) << "p1, p2 = " << p1 << p2 << ", newp = " << p2d << endl;
+
+  //  newp = Center (p1, p2);
+  newp = Point3d (p2d(0), p2d(1), 0);
+  newgi.edgenr = ap1.edgenr;
+  newgi.dist = ((1-secpoint)*ap1.dist+secpoint*ap2.dist);
+
+  /*
+  if (surfi1 && surfi2 && surfi1 != surfi2)
+    {
+      //      (*testout) << "surfi1 = " << surfi1 << " surfi2 = " << surfi2 << endl;
+      //      (*testout) << "np = " << newp << endl;
+      //  geometry.GetSurface (surfi1) -> Project (newp);
+      ProjectToEdge (geometry.GetSurface(surfi1), 
+		     geometry.GetSurface(surfi2), 
+		     newp);
+      newgi.edgenr = 1;
+      //      (*testout) << "np2 = " << newp << endl;
+    }
+  else if (surfi1)
+    {
+      geometry.GetSurface (surfi1) -> Project (newp);
+    }
+  */
+};
+
+}
diff --git a/Netgen/libsrc/geom2d/geom2dmesh.hpp b/Netgen/libsrc/geom2d/geom2dmesh.hpp
new file mode 100644
index 0000000000..6912cd7752
--- /dev/null
+++ b/Netgen/libsrc/geom2d/geom2dmesh.hpp
@@ -0,0 +1,38 @@
+#ifndef FILE_GEOM2DMESH
+#define FILE_GEOM2DMESH
+
+/**************************************************************************/
+/* File:   geom2dmesh.hh                                                  */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   22. Jan. 01                                                    */
+/**************************************************************************/
+
+
+class Refinement2d : public Refinement
+{
+  const SplineGeometry2d & geometry;
+
+public:
+  Refinement2d (const SplineGeometry2d & ageometry);
+  virtual ~Refinement2d ();
+  
+  virtual void PointBetween (const Point3d & p1, const Point3d & p2, double secpoint,
+			     int surfi, 
+			     const PointGeomInfo & gi1, 
+			     const PointGeomInfo & gi2,
+			     Point3d & newp, PointGeomInfo & newgi);
+
+  virtual void PointBetween (const Point3d & p1, const Point3d & p2, double secpoint,
+			     int surfi1, int surfi2, 
+			     const EdgePointGeomInfo & ap1, 
+			     const EdgePointGeomInfo & ap2,
+			     Point3d & newp, EdgePointGeomInfo & newgi);
+			     
+};
+
+
+
+
+
+
+#endif
diff --git a/Netgen/libsrc/geom2d/geometry2d.hpp b/Netgen/libsrc/geom2d/geometry2d.hpp
new file mode 100644
index 0000000000..80d276e340
--- /dev/null
+++ b/Netgen/libsrc/geom2d/geometry2d.hpp
@@ -0,0 +1,20 @@
+#ifndef FILE_GEOMETRY2D
+#define FILE_GEOMETRY2D
+
+/* *************************************************************************/
+/* File:   geometry2d.hpp                                                  */
+/* Author: Joachim Schoeberl                                               */
+/* Date:   20. Jul. 02                                                     */
+/* *************************************************************************/
+
+#include <myadt.hpp>
+#include <gprim.hpp>
+
+namespace netgen
+{
+#include "spline2d.hpp"
+#include "splinegeometry2.hpp"
+#include "geom2dmesh.hpp"
+}
+
+#endif
diff --git a/Netgen/libsrc/geom2d/spline2d.cpp b/Netgen/libsrc/geom2d/spline2d.cpp
new file mode 100644
index 0000000000..18c0362f41
--- /dev/null
+++ b/Netgen/libsrc/geom2d/spline2d.cpp
@@ -0,0 +1,350 @@
+/*
+
+2d Spline curve for Mesh generator
+
+*/
+
+#include <mystdlib.h>
+#include <csg.hpp>
+#include <linalg.hpp>
+#include <meshing.hpp>
+
+namespace netgen
+{
+#include "spline2d.hpp"
+
+
+void CalcPartition (double l, double h, double r1, double r2,
+		    double ra, double elto0, ARRAY<double> & points);
+
+
+
+// calculates length of spline-curve
+double SplineSegment :: Length () const
+{
+  Point<2> p, pold;
+
+  int i, n = 100;
+  double dt = 1.0 / n;
+
+  pold = GetPoint (0);
+
+  double l = 0;
+  for (i = 1; i <= n; i++)
+    {
+      p = GetPoint (i * dt);
+      l += Dist (p, pold);
+      pold = p;
+    }
+  return l;
+}
+
+
+
+// partitionizes spline curve
+void SplineSegment :: Partition (double h, double elto0,
+				 Mesh & mesh, int segnr) const
+{
+  int i, j;
+  double l, r1, r2, ra;
+  double lold, dt, frac;
+  int n = 100;
+  Point<2> p, pold, mark, oldmark;
+  ARRAY<double> curvepoints;
+  double edgelength, edgelengthold;
+  l = Length();
+
+  r1 = StartPI().refatpoint;
+  r2 = EndPI().refatpoint;
+  ra = reffak;
+
+  //  cout << "Partition, l = " << l << ", h = " << h << endl;
+  CalcPartition (l, h, r1, r2, ra, elto0, curvepoints);
+  //  cout << "curvepoints = " << curvepoints << endl;
+
+  dt = 1.0 / n;
+
+  l = 0;
+  j = 1;
+
+  pold = GetPoint (0);
+  lold = 0;
+  oldmark = pold;
+  edgelengthold = 0;
+
+  for (i = 1; i <= n; i++)
+    {
+      p = GetPoint (i*dt);
+      l = lold + Dist (p, pold);
+      while (j < curvepoints.Size() && (l >= curvepoints[j] || i == n))
+	{
+	  frac = (curvepoints[j]-lold) / (l-lold);
+	  mark = pold + frac * (p-pold);
+	  edgelength = i*dt + (frac-1)*dt;
+	  {
+	    PointIndex pi1 = -1, pi2 = -1;
+	  
+	    Point3d mark3(mark(0), mark(1), 0);
+	    Point3d oldmark3(oldmark(0), oldmark(1), 0);
+	    
+	    for (PointIndex pk = PointIndex::BASE; 
+		 pk < mesh.GetNP()+PointIndex::BASE; pk++)
+	      {
+		if (Dist (mesh[pk], oldmark3) < 1e-4 * h) pi1 = pk;
+		if (Dist (mesh[pk], mark3) < 1e-4 * h) pi2 = pk;
+	      }
+
+	    //	    cout << "pi1 = " << pi1 << endl;
+	    //	    cout << "pi2 = " << pi2 << endl;
+	    
+	    if (pi1 == -1) pi1 = mesh.AddPoint(oldmark3);
+	    if (pi2 == -1) pi2 = mesh.AddPoint(mark3);
+
+	    // cout << "pi1 = " << pi1 << endl;
+	    // cout << "pi2 = " << pi2 << endl;
+	  
+	    Segment seg;
+	    seg.edgenr = segnr;
+	    seg.si = bc; // segnr;
+	    seg.p1 = pi1;
+	    seg.p2 = pi2;
+	    seg.domin = leftdom;
+	    seg.domout = rightdom;
+	    seg.epgeominfo[0].edgenr = segnr;
+	    seg.epgeominfo[0].dist = edgelengthold;
+	    seg.epgeominfo[1].edgenr = segnr;
+	    seg.epgeominfo[1].dist = edgelength;
+
+	    mesh.AddSegment (seg);
+	  }
+	
+	  oldmark = mark;
+	  edgelengthold = edgelength;
+	  j++;
+	}
+    
+      pold = p;
+      lold = l;
+    }
+}
+
+
+void SplineSegment :: GetPoints (int n, ARRAY<Point<2> > & points)
+{
+  points.SetSize (n);
+  if (n >= 2)
+    for (int i = 0; i < n; i++)
+      points[i] = GetPoint(double(i) / (n-1));
+}
+
+
+
+/* 
+   Implementation of line-segment from p1 to p2
+*/
+
+
+LineSegment :: LineSegment (const GeomPoint2d & ap1, 
+			    const GeomPoint2d & ap2)
+  : p1(ap1), p2(ap2)
+{
+  ;
+}
+
+
+Point<2> LineSegment :: GetPoint (double t) const
+{
+  return p1 + t * (p2 - p1);
+}
+
+double LineSegment :: Length () const
+{
+  return Dist (p1, p2);
+}
+
+
+void LineSegment :: PrintCoeff (ostream & ost) const
+{
+  double dx = p2(0) - p1(0);
+  double dy = p2(1) - p1(1);
+  ost << "0 0 0 " <<  dy << " " << -dx << " " 
+      << dx * p1(1) - dy * p1(0) << endl;
+}
+
+
+
+
+
+SplineSegment3 :: SplineSegment3 (const GeomPoint2d & ap1, 
+				  const GeomPoint2d & ap2,
+				  const GeomPoint2d & ap3)
+  : p1(ap1), p2(ap2), p3(ap3)
+{
+  ;
+}
+
+Point<2> SplineSegment3 :: GetPoint (double t) const
+{
+  double x, y, w;
+  double b1, b2, b3;
+
+  b1 = (1-t)*(1-t);
+  b2 = sqrt(2.0) * t * (1-t);
+  b3 = t * t;
+
+  x = p1(0) * b1 + p2(0) * b2 + p3(0) * b3;
+  y = p1(1) * b1 + p2(1) * b2 + p3(1) * b3;
+  w = b1 + b2 + b3;
+
+  return Point<2> (x/w, y/w);
+}
+
+
+void SplineSegment3 :: PrintCoeff (ostream & ost) const
+{
+  double t;
+  int i;
+  Point<2> p;
+  DenseMatrix a(6, 6);
+  DenseMatrix ata(6, 6);
+  Vector u(6), f(6);
+
+  //  ata.SetSymmetric(1);
+
+  t = 0;
+  for (i = 1; i <= 5; i++, t += 0.25)
+    {
+      p = GetPoint (t);
+      a.Elem(i, 1) = p(0) * p(0);
+      a.Elem(i, 2) = p(1) * p(1);
+      a.Elem(i, 3) = p(0) * p(1);
+      a.Elem(i, 4) = p(0);
+      a.Elem(i, 5) = p(1);
+      a.Elem(i, 6) = 1;
+    }
+  a.Elem(6, 1) = 1;
+
+  CalcAtA (a, ata);
+
+  u = 0;
+  u.Elem(6) = 1;
+  a.MultTrans (u, f);
+  ata.Solve (f, u);
+  
+  for (i = 1; i <= 6; i++)
+    ost << u.Get(i) << "  ";
+  ost << endl;
+}
+
+
+
+
+//########################################################################
+//		circlesegment
+
+CircleSegment :: CircleSegment (const GeomPoint2d & ap1, 
+				const GeomPoint2d & ap2,
+				const GeomPoint2d & ap3)
+  : p1(ap1), p2(ap2), p3(ap3)
+{
+  Vec<2> v1,v2;
+  
+  v1 = p1 - p2;
+  v2 = p3 - p2;
+  
+  Point<2> p1t(p1(0)+v1[1], p1(1)-v1[0]);
+  Point<2> p2t(p3(0)+v2[1], p3(1)-v2[0]);
+  Line2d g1t(p1, p1t), g2t(p3, p2t);
+  
+  pm 	  = CrossPoint (g1t,g2t);
+  radius  = Dist(pm,StartPI());
+  w1      = Angle(Vec2d (p1 - pm));
+  w3      = Angle(Vec2d (p3 - pm));
+  if ( fabs(w3-w1) > M_PI )
+    {  
+      if ( w3>M_PI )   w3 -= 2*M_PI;
+      if ( w1>M_PI )   w1 -= 2*M_PI;
+    }
+}
+ 
+Point<2>  CircleSegment :: GetPoint (double t) const
+{
+  if (t >= 1.0)  { return p3; }
+     
+  double phi = StartAngle() + t*(EndAngle()-StartAngle());
+  Vec2d  tmp(cos(phi),sin(phi));
+     
+  return pm + Radius()*tmp;
+}
+  
+void CircleSegment :: PrintCoeff (ostream & ost) const
+{
+  double a,b,c,d,e,f;
+ 
+  a = b = 1.0;
+  c = 0.0;
+  d = -2.0 * pm[0];
+  e = -2.0 * pm[1];
+  f = sqr(pm[0]) + sqr(pm[1]) - sqr(Radius());
+ 
+  ost << a << "  " << b << "  " << c << "  " << d << "  " << e << "  " << f ;
+  ost << endl;
+}
+
+
+
+
+
+
+//########################################################################
+
+
+
+
+void CalcPartition (double l, double h, double r1, double r2,
+		    double ra, double elto0, ARRAY<double> & points)
+{
+  int i, j, n, nel;
+  double sum, t, dt, fun, fperel, oldf, f;
+
+  n = 1000;
+
+  points.SetSize (0);
+
+  sum = 0;
+  dt = l / n;
+  t = 0.5 * dt;
+  for (i = 1; i <= n; i++)
+    {
+      fun = min3 (h/ra, t/elto0 + h/r1, (l-t)/elto0 + h/r2);
+      sum += dt / fun;
+      t += dt;
+    }
+
+  nel = int (sum+1);
+  fperel = sum / nel;
+
+  points.Append (0);
+
+  i = 1;
+  oldf = 0;
+  t = 0.5 * dt;
+  for (j = 1; j <= n && i < nel; j++)
+    {
+      fun = min3 (h/ra, t/elto0 + h/r1, (l-t)/elto0 + h/r2);
+
+      f = oldf + dt / fun;
+
+      while (f > i * fperel && i < nel)
+	{
+	  points.Append ( (l/n) * (j-1 +  (i * fperel - oldf) / (f - oldf)) );
+	  i++;
+	}
+      oldf = f;
+      t += dt;
+    }
+  points.Append (l);
+}
+
+
+}
diff --git a/Netgen/libsrc/geom2d/spline2d.hpp b/Netgen/libsrc/geom2d/spline2d.hpp
new file mode 100644
index 0000000000..bdd33d736b
--- /dev/null
+++ b/Netgen/libsrc/geom2d/spline2d.hpp
@@ -0,0 +1,167 @@
+#ifndef FILE_SPLINE2D
+#define FILE_SPLINE2D
+
+/**************************************************************************/
+/* File:   spline2d.hh                                                    */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   24. Jul. 96                                                    */
+/**************************************************************************/
+
+
+/*
+  Spline curves for 2D mesh generation
+  */
+
+
+/// Geometry point
+class GeomPoint2d : public Point<2>
+{
+public:
+  /// refinement to point
+  double refatpoint;
+
+  GeomPoint2d ()
+  { ; }
+
+  ///
+  GeomPoint2d (double ax, double ay, double aref = 1)
+    : Point<2> (ax, ay), refatpoint(aref) { ; }
+};
+
+
+
+/// base class for 2d - segment
+class SplineSegment
+{
+public:
+  /// left domain
+  int leftdom;
+  /// right domain
+  int rightdom;
+  /// refinement at line
+  double reffak;
+  /// boundary condition number
+  int bc;
+  /// copy spline mesh from other spline (-1.. do not copy)
+  int copyfrom;
+
+  /// calculates length of curve
+  virtual double Length () const;
+  /// returns point at curve, 0 <= t <= 1
+  virtual Point<2> GetPoint (double t) const = 0;
+  /// partitionizes curve
+  void Partition (double h, double elto0,
+		  Mesh & mesh, int segnr) const;
+  /// returns initial point on curve
+  virtual const GeomPoint2d & StartPI () const = 0;
+  /// returns terminal point on curve
+  virtual const GeomPoint2d & EndPI () const = 0;
+  /** writes curve description for fepp:
+    for implicitly given quadratic curves, the 6 coefficients of
+    the polynomial
+    $$ a x^2 + b y^2 + c x y + d x + e y + f = 0 $$
+    are written to ost */
+  virtual void PrintCoeff (ostream & ost) const = 0;
+
+  virtual void GetPoints (int n, ARRAY<Point<2> > & points);
+};
+
+
+/// Straight line form p1 to p2
+class LineSegment : public SplineSegment
+{
+  ///
+  const GeomPoint2d &p1, &p2;
+public:
+  ///
+  LineSegment (const GeomPoint2d & ap1, const GeomPoint2d & ap2);
+  ///
+  virtual double Length () const;
+  ///
+  virtual Point<2> GetPoint (double t) const;
+  ///
+  virtual const GeomPoint2d & StartPI () const { return p1; };
+  ///
+  virtual const GeomPoint2d & EndPI () const { return p2; }
+  ///
+  virtual void PrintCoeff (ostream & ost) const;
+};
+
+
+/// curve given by a rational, quadratic spline (including ellipses)
+class SplineSegment3 : public SplineSegment
+{
+  ///
+  const GeomPoint2d &p1, &p2, &p3;
+public:
+  ///
+  SplineSegment3 (const GeomPoint2d & ap1, 
+		  const GeomPoint2d & ap2, 
+		  const GeomPoint2d & ap3);
+  ///
+  virtual Point<2> GetPoint (double t) const;
+  ///
+  virtual const GeomPoint2d & StartPI () const { return p1; };
+  ///
+  virtual const GeomPoint2d & EndPI () const { return p3; }
+  ///
+  virtual void PrintCoeff (ostream & ost) const;
+};
+
+
+// Gundolf Haase  8/26/97
+/// A circle
+class CircleSegment : public SplineSegment
+{
+  ///
+private:
+  const GeomPoint2d	&p1, &p2, &p3;
+  Point<2>		pm;
+  double		radius, w1,w3;
+public:
+  ///
+  CircleSegment (const GeomPoint2d & ap1, 
+		 const GeomPoint2d & ap2, 
+		 const GeomPoint2d & ap3);
+  ///
+  virtual Point<2> GetPoint (double t) const;
+  ///
+  virtual const GeomPoint2d & StartPI () const { return p1; };
+  ///
+  virtual const GeomPoint2d & EndPI () const { return p3; }
+  ///
+  virtual void PrintCoeff (ostream & ost) const;
+  ///
+  double Radius() const { return radius; }
+  ///
+  double StartAngle() const { return w1; }
+  ///
+  double EndAngle() const { return w3; }
+};
+
+
+// Gundolf Haase  8/26/97
+/// elliptic curve with one axe parallel to line {P1,P2}
+/*
+class ellipsegment3 : public SplineSegment
+{
+  ///
+  GeomPoint2d *p1, *p2, *p3;
+public:
+  ///
+  SplineSegment3 (GeomPoint2d * ap1, GeomPoint2d * ap2, GeomPoint2d * ap3);
+  ///
+  virtual Point<2> GetPoint (double t) const;
+  ///
+  virtual GeomPoint2d * StartPI () const { return p1; };
+  ///
+  virtual GeomPoint2d * EndPI () const { return p3; }
+  ///
+  virtual void PrintCoeff (ostream & ost) const;
+};
+*/
+
+
+
+
+#endif
diff --git a/Netgen/libsrc/geom2d/splinegeometry2.cpp b/Netgen/libsrc/geom2d/splinegeometry2.cpp
new file mode 100644
index 0000000000..921e22a295
--- /dev/null
+++ b/Netgen/libsrc/geom2d/splinegeometry2.cpp
@@ -0,0 +1,224 @@
+/*
+
+2d Spline curve for Mesh generator
+
+*/
+
+#include <mystdlib.h>
+#include <csg.hpp>
+#include <linalg.hpp>
+#include <meshing.hpp>
+
+
+namespace netgen
+
+{
+
+#include "spline2d.hpp"
+#include "splinegeometry2.hpp"
+
+
+
+
+
+void SplineGeometry2d :: Load (const char * filename)
+{
+  ifstream infile;
+  int nump, numseg, nelp, i, leftdom, rightdom;
+  double x, y;
+  int hi1, hi2, hi3;
+  double hd;
+  char reco[50], ch;
+
+  infile.open (filename);
+
+  infile >> reco;
+  infile >> elto0;
+
+  infile >> nump;
+  for (i = 0; i < nump; i++)
+    {
+      infile >> x >> y >> hd;
+      geompoints.Append (GeomPoint2d(x, y, hd));
+    }
+
+  infile >> numseg;
+
+  SplineSegment * spline = 0;
+  for (i = 0; i < numseg; i++)
+    {
+      infile >> leftdom >> rightdom;
+
+      infile >> nelp;  
+      switch (nelp)
+	{ // type of spline segement
+	case 2:
+	  { // a line
+	    infile >> hi1 >> hi2;
+	    spline = new LineSegment(geompoints[hi1-1],
+				     geompoints[hi2-1]);
+	    break;
+	  }
+	case 3:
+	  { // a rational spline
+	    infile >> hi1 >> hi2 >> hi3;
+	    spline = new SplineSegment3 (geompoints[hi1-1],
+					 geompoints[hi2-1],
+					 geompoints[hi3-1]);
+	    break;
+	  }
+	case 4:
+	  { // an arc
+	    infile >> hi1 >> hi2 >> hi3;
+	    splines.Append (new CircleSegment (geompoints[hi1-1],
+					       geompoints[hi2-1],
+					       geompoints[hi3-1]));
+	    break;
+	  }
+	}
+    
+      infile >> spline->reffak;
+      spline -> leftdom = leftdom;
+      spline -> rightdom = rightdom;
+      splines.Append (spline);
+
+    
+
+      Flags flags;
+      ch = 'a';
+      infile >> ch;
+      while (ch == '-')
+	{
+	  char flag[100];
+	  flag[0]='-';
+	  infile >> (flag+1);
+	  flags.SetCommandLineFlag (flag);
+	  ch = 'a';
+	  infile >> ch;
+	}
+    
+      if (infile.good())
+	infile.putback (ch);
+    
+      splines.Last()->bc = int (flags.GetNumFlag ("bc", i+1));
+      splines.Last()->copyfrom = int (flags.GetNumFlag ("copy", -1));
+    }
+
+
+  Box<2> bbox;
+  GetBoundingBox (bbox);
+  // cout << "bbox = " << bbox << endl;
+}
+
+
+
+void SplineGeometry2d :: 
+PartitionBoundary (double h, Mesh & mesh2d)
+{
+  for (int i = 0; i < splines.Size(); i++)
+    if (splines[i]->copyfrom == -1)
+      splines[i]->Partition(h, elto0, mesh2d, i+1);
+    else
+      CopyEdgeMesh (splines[i]->copyfrom, i+1, mesh2d);
+}
+
+
+void SplineGeometry2d :: CopyEdgeMesh (int from, int to, Mesh & mesh)
+{
+  int i, j, k;
+
+  ARRAY<int> mappoints (mesh.GetNP());
+  ARRAY<double> param (mesh.GetNP());
+  mappoints = -1;
+  param = 0;
+
+  Point3d pmin, pmax;
+  mesh.GetBox (pmin, pmax);
+  double diam2 = Dist2(pmin, pmax);
+
+  cout << "copy edge, from = " << from << " to " << to << endl;
+  
+  for (i = 1; i <= mesh.GetNSeg(); i++)
+    {
+      const Segment & seg = mesh.LineSegment(i);
+      if (seg.edgenr == from)
+	{
+	  mappoints.Elem(seg.p1) = 1;
+	  param.Elem(seg.p1) = seg.epgeominfo[0].dist;
+
+	  mappoints.Elem(seg.p2) = 1;
+	  param.Elem(seg.p2) = seg.epgeominfo[1].dist;
+	}
+    }
+
+  for (i = 1; i <= mappoints.Size(); i++)
+    {
+      if (mappoints.Get(i) != -1)
+	{
+	  Point<2> newp = splines.Get(to)->GetPoint (param.Get(i));
+	  Point<3> newp3 (newp(0), newp(1), 0);
+	  
+	  int npi = -1;
+	  
+	  for (PointIndex pi = PointIndex::BASE; 
+	       pi < mesh.GetNP()+PointIndex::BASE; pi++)
+	    if (Dist2 (mesh.Point(pi), newp3) < 1e-12 * diam2)
+	      npi = pi;
+	  
+	  if (npi == -1)
+	    {
+	      npi = mesh.AddPoint (newp3);
+	    }
+	  
+	  mappoints.Elem(i) = npi;
+
+	  mesh.GetIdentifications().Add (i, npi, to);
+	}
+    }
+
+  // copy segments
+  int oldnseg = mesh.GetNSeg();
+  for (i = 1; i <= oldnseg; i++)
+    {
+      const Segment & seg = mesh.LineSegment(i);
+      if (seg.edgenr == from)
+	{
+	  Segment nseg;
+	  nseg.edgenr = to;
+	  nseg.si = splines.Get(to)->bc;
+	  nseg.p1 = mappoints.Get(seg.p1);
+	  nseg.p2 = mappoints.Get(seg.p2);
+	  nseg.domin = splines.Get(to)->leftdom;
+	  nseg.domout = splines.Get(to)->rightdom;
+	  
+	  nseg.epgeominfo[0].edgenr = to;
+	  nseg.epgeominfo[0].dist = param.Get(seg.p1);
+	  nseg.epgeominfo[1].edgenr = to;
+	  nseg.epgeominfo[1].dist = param.Get(seg.p2);
+	  mesh.AddSegment (nseg);
+	}
+    }
+}
+  
+
+void SplineGeometry2d :: 
+GetBoundingBox (Box<2> & box) const
+{
+  if (!splines.Size())
+    {
+      box.Set (Point<2> (0,0));
+      return;
+    }
+
+  ARRAY<Point<2> > points;
+  for (int i = 0; i < splines.Size(); i++)
+    {
+      splines[i]->GetPoints (20, points);
+
+      if (i == 0) box.Set(points[0]);
+      for (int j = 0; j < points.Size(); j++)
+	box.Add (points[j]);
+    }
+}
+
+}
diff --git a/Netgen/libsrc/geom2d/splinegeometry2.hpp b/Netgen/libsrc/geom2d/splinegeometry2.hpp
new file mode 100644
index 0000000000..38de574b24
--- /dev/null
+++ b/Netgen/libsrc/geom2d/splinegeometry2.hpp
@@ -0,0 +1,43 @@
+#ifndef FILE_SPLINEGEOMETRY2
+#define FILE_SPLINEGEOMETRY2
+
+/**************************************************************************/
+/* File:   splinegeometry2.hpp                                            */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   24. Jul. 96                                                    */
+/**************************************************************************/
+
+
+
+/// 
+extern void LoadBoundarySplines (const char * filename,
+				 ARRAY<GeomPoint2d> & geompoints,
+				 ARRAY<SplineSegment*> & splines, 
+				 double & elto0);
+///
+extern void PartitionBoundary (const ARRAY<SplineSegment*> & splines,
+			       double h, double elto0,
+			       Mesh & mesh2d);
+
+
+class SplineGeometry2d
+{
+  ARRAY<GeomPoint2d> geompoints;
+  ARRAY<SplineSegment*> splines;
+  double elto0;
+
+public:
+  void Load (const char * filename);
+  void PartitionBoundary (double h, Mesh & mesh2d);
+
+  void CopyEdgeMesh (int from, int to, Mesh & mesh2d);
+
+  const ARRAY<SplineSegment*> & GetSplines () const
+  { return splines; }
+
+  void GetBoundingBox (Box<2> & box) const;
+};
+
+
+
+#endif
diff --git a/Netgen/libsrc/gprim/Makefile b/Netgen/libsrc/gprim/Makefile
new file mode 100644
index 0000000000..608e522844
--- /dev/null
+++ b/Netgen/libsrc/gprim/Makefile
@@ -0,0 +1,14 @@
+#
+# Makefile for geometric library
+#
+src =  geom2d.cpp geom3d.cpp  \
+	geomtest3d.cpp adtree.cpp transform3d.cpp geomfuncs.cpp
+
+# reftrans.cpp rot3d.cpp
+#
+lib = gprim
+libpath = libsrc/gprim
+#
+#
+include ../makefile.inc
+#
diff --git a/Netgen/libsrc/gprim/adtree.cpp b/Netgen/libsrc/gprim/adtree.cpp
new file mode 100644
index 0000000000..b3e3f13795
--- /dev/null
+++ b/Netgen/libsrc/gprim/adtree.cpp
@@ -0,0 +1,2292 @@
+#include <mystdlib.h>
+
+
+#include <myadt.hpp>
+// class DenseMatrix;
+#include <gprim.hpp>
+
+namespace netgen
+{
+
+
+/* ******************************* ADTree ******************************* */
+
+
+ADTreeNode :: ADTreeNode(int adim)
+{
+  pi = 0;
+
+  left = NULL;
+  right = NULL;
+  father = NULL;
+  nchilds = 0;
+  dim = adim;
+  data = new float [dim];
+  boxmin = NULL;
+  boxmax = NULL;
+}
+
+
+
+
+ADTreeNode :: ~ADTreeNode()
+{
+  delete data;
+}
+
+
+ADTree :: ADTree (int adim, const float * acmin, 
+			 const float * acmax)
+  : ela(0), stack(1000), stackdir(1000)
+{
+  dim = adim;
+  cmin = new float [dim];
+  cmax = new float [dim];
+  memcpy (cmin, acmin, dim * sizeof(float));
+  memcpy (cmax, acmax, dim * sizeof(float));
+
+  root = new ADTreeNode (dim);
+  root->sep = (cmin[0] + cmax[0]) / 2;
+  root->boxmin = new float [dim];
+  root->boxmax = new float [dim];
+  memcpy (root->boxmin, cmin, dim * sizeof(float));
+  memcpy (root->boxmax, cmax, dim * sizeof(float));
+}
+
+ADTree :: ~ADTree ()
+{
+  ;
+}
+
+void ADTree :: Insert (const float * p, int pi)
+{
+  ADTreeNode *node;
+  ADTreeNode *next;
+  int dir;
+  int lr;
+
+  float * bmin = new float [dim];
+  float * bmax = new float [dim];
+  
+  memcpy (bmin, cmin, dim * sizeof(float));
+  memcpy (bmax, cmax, dim * sizeof(float));
+
+#ifdef MARK
+  MARK (insertloop3)
+#endif
+
+  next = root;
+  dir = 0;
+  while (next)
+    {
+      node = next;
+
+      if (!node->pi)
+	{    
+	  memcpy (node->data, p, dim * sizeof(float));
+	  node->pi = pi;
+
+	  if (ela.Size() < pi)
+	    ela.SetSize (pi);
+	  ela.Elem(pi) = node;
+
+	  return;
+	}
+
+      if (node->sep > p[dir])
+	{
+	  next = node->left;
+	  bmax[dir] = node->sep;
+	  lr = 0;
+	}
+      else
+	{
+	  next = node->right;
+	  bmin[dir] = node->sep;
+	  lr = 1;
+	}
+
+      dir++;
+      if (dir == dim)
+	dir = 0;
+    }
+
+#ifdef MARK
+  MARK (insertend3)
+#endif
+
+
+  next = new ADTreeNode(dim);
+  memcpy (next->data, p, dim * sizeof(float));
+  next->pi = pi;
+  next->sep = (bmin[dir] + bmax[dir]) / 2;
+  next->boxmin = bmin;
+  next->boxmax = bmax;
+
+  if (ela.Size() < pi)
+    ela.SetSize (pi);
+  ela.Elem(pi) = next;
+
+
+  if (lr)
+    node->right = next;
+  else
+    node->left = next;
+  next -> father = node;
+
+  while (node)
+    {
+      node->nchilds++;
+      node = node->father;
+    }
+}
+
+void ADTree :: DeleteElement (int pi)
+{
+  ADTreeNode * node = ela.Get(pi);
+
+  node->pi = 0;
+
+  node = node->father;
+  while (node)
+    {
+      node->nchilds--;
+      node = node->father;
+    }
+}
+
+
+void ADTree :: SetCriterion (ADTreeCriterion & acriterion)
+{
+  criterion = & acriterion;
+}
+
+
+void ADTree :: Reset ()
+{
+  stack.Elem(1) = root;
+  stackdir.Elem(1) = 0;
+  stackindex = 1;
+}
+
+
+int ADTree:: Next ()
+{
+  ADTreeNode *node;
+  int dir;
+
+  if (stackindex == 0)
+    return 0;
+
+  do 
+    {
+      node = stack.Get(stackindex);
+      dir = stackdir.Get(stackindex);
+      stackindex --;
+
+      if (criterion -> Eval(node))
+	{
+	  int ndir = dir + 1;
+	  if (ndir == dim)
+	    ndir = 0;
+
+	  if (node -> left && criterion -> Eval (node->left))
+	    {
+	      stackindex ++;
+	      stack.Elem(stackindex) = node -> left;
+	      stackdir.Elem(stackindex) = ndir;
+	    }
+	  if (node->right && criterion -> Eval (node -> right))
+	    {
+	      stackindex++;
+	      stack.Elem(stackindex) = node->right;
+	      stackdir.Elem(stackindex) = ndir;
+	    }
+	  
+	  if (node -> pi)
+	    return node->pi;
+	}
+    }
+  while (stackindex > 0);
+
+  return 0;
+}
+
+
+void ADTree :: GetMatch (ARRAY <int> & matches)
+{
+  int nodenr;
+
+  Reset();
+
+  while (nodenr = Next())
+    matches.Append (nodenr);
+}
+
+
+void ADTree :: PrintRec (ostream & ost, const ADTreeNode * node) const
+{
+  
+  if (node->data)
+    {
+      ost << node->pi << ": ";
+      ost << node->nchilds << " childs, ";
+      for (int i = 0; i < dim; i++)
+	ost << node->data[i] << " ";
+      ost << endl;
+    }
+  if (node->left)
+    {
+      ost << "l ";
+      PrintRec (ost, node->left);
+    }
+  if (node->right)
+    {
+      ost << "r ";
+      PrintRec (ost, node->right);
+    }
+}
+
+
+/* ******************************* ADTree3 ******************************* */
+
+
+ADTreeNode3 :: ADTreeNode3()
+{
+  pi = 0;
+
+  left = NULL;
+  right = NULL;
+  father = NULL;
+  nchilds = 0;
+}
+
+void ADTreeNode3 :: DeleteChilds ()
+{
+  if (left)
+    {
+      left->DeleteChilds();
+      delete left;
+      left = NULL;
+    }
+  if (right)
+    {
+      right->DeleteChilds();
+      delete right;
+      right = NULL;
+    }
+}
+
+
+BlockAllocator ADTreeNode3 :: ball(sizeof (ADTreeNode3));
+
+
+void * ADTreeNode3 :: operator new(size_t s)
+{
+  ADTreeNode3 * ap;
+  return ball.Alloc();
+}
+
+void ADTreeNode3 :: operator delete (void * p)
+{
+  ball.Free (p);
+  //  ::delete [] p;
+}
+
+
+
+
+
+
+
+ADTree3 :: ADTree3 (const float * acmin, 
+			 const float * acmax)
+  : ela(0)
+{
+  memcpy (cmin, acmin, 3 * sizeof(float));
+  memcpy (cmax, acmax, 3 * sizeof(float));
+
+  root = new ADTreeNode3;
+  root->sep = (cmin[0] + cmax[0]) / 2;
+}
+
+ADTree3 :: ~ADTree3 ()
+{
+  root->DeleteChilds();
+  delete root;
+}
+
+
+void ADTree3 :: Insert (const float * p, int pi)
+{
+  ADTreeNode3 *node;
+  ADTreeNode3 *next;
+  int dir;
+  int lr;
+
+  float bmin[3];
+  float bmax[3];
+  
+  memcpy (bmin, cmin, 3 * sizeof(float));
+  memcpy (bmax, cmax, 3 * sizeof(float));
+
+#ifdef MARK
+  //  MARK (insertloop3)
+#endif
+
+  next = root;
+  dir = 0;
+  while (next)
+    {
+      node = next;
+
+      if (!node->pi)
+	{    
+	  memcpy (node->data, p, 3 * sizeof(float));
+	  node->pi = pi;
+
+	  if (ela.Size() < pi)
+	    ela.SetSize (pi);
+	  ela.Elem(pi) = node;
+
+	  return;
+	}
+
+      if (node->sep > p[dir])
+	{
+	  next = node->left;
+	  bmax[dir] = node->sep;
+	  lr = 0;
+	}
+      else
+	{
+	  next = node->right;
+	  bmin[dir] = node->sep;
+	  lr = 1;
+	}
+
+      dir++;
+      if (dir == 3)
+	dir = 0;
+    }
+
+#ifdef MARK
+  //  MARK (insertend3)
+#endif
+
+
+  next = new ADTreeNode3;
+  memcpy (next->data, p, 3 * sizeof(float));
+  next->pi = pi;
+  next->sep = (bmin[dir] + bmax[dir]) / 2;
+
+
+  if (ela.Size() < pi)
+    ela.SetSize (pi);
+  ela.Elem(pi) = next;		
+
+
+  if (lr)
+    node->right = next;
+  else
+    node->left = next;
+  next -> father = node;
+
+  while (node)
+    {
+      node->nchilds++;
+      node = node->father;
+    }
+}
+
+void ADTree3 :: DeleteElement (int pi)
+{
+  ADTreeNode3 * node = ela.Get(pi);
+
+  node->pi = 0;
+
+  node = node->father;
+  while (node)
+    {
+      node->nchilds--;
+      node = node->father;
+    }
+}
+
+void ADTree3 :: GetIntersecting (const float * bmin, 
+				 const float * bmax,
+				 ARRAY<int> & pis) const
+{
+  static ARRAY<ADTreeNode3*> stack(1000);
+  static ARRAY<int> stackdir(1000);
+  ADTreeNode3 * node;
+  int dir, i, stacks;
+
+  stack.SetSize (1000);
+  stackdir.SetSize(1000);
+  pis.SetSize(0);
+
+  stack.Elem(1) = root;
+  stackdir.Elem(1) = 0;
+  stacks = 1;
+
+  while (stacks)
+    {
+      node = stack.Get(stacks);
+      dir = stackdir.Get(stacks); 
+      stacks--;
+
+      if (node->pi)
+	{
+	  if (node->data[0] >= bmin[0] && node->data[0] <= bmax[0] &&
+	      node->data[1] >= bmin[1] && node->data[1] <= bmax[1] &&
+	      node->data[2] >= bmin[2] && node->data[2] <= bmax[2])
+
+	    pis.Append (node->pi);
+	}
+
+
+      int ndir = dir+1;
+      if (ndir == 3)
+	ndir = 0;
+
+      if (node->left && bmin[dir] <= node->sep)
+	{
+	  stacks++;
+	  stack.Elem(stacks) = node->left;
+	  stackdir.Elem(stacks) = ndir;
+	}
+      if (node->right && bmax[dir] >= node->sep)
+	{
+	  stacks++;
+	  stack.Elem(stacks) = node->right;
+	  stackdir.Elem(stacks) = ndir;
+	}
+    }
+}
+
+void ADTree3 :: PrintRec (ostream & ost, const ADTreeNode3 * node) const
+{
+  
+  if (node->data)
+    {
+      ost << node->pi << ": ";
+      ost << node->nchilds << " childs, ";
+      for (int i = 0; i < 3; i++)
+	ost << node->data[i] << " ";
+      ost << endl;
+    }
+  if (node->left)
+    PrintRec (ost, node->left);
+  if (node->right)
+    PrintRec (ost, node->right);
+}
+
+
+
+
+
+
+
+
+
+/* ******************************* ADTree3Div ******************************* */
+
+
+ADTreeNode3Div :: ADTreeNode3Div()
+{
+  pi = 0;
+  
+  int i;
+  for (i = 0; i < ADTN_DIV; i++)
+    childs[i] = NULL;
+
+  father = NULL;
+  nchilds = 0;
+  minx = 0;
+  dist = 1;
+}
+
+void ADTreeNode3Div :: DeleteChilds ()
+{
+  int i;
+  for (i = 0; i < ADTN_DIV; i++)
+    if (childs[i])
+      {
+	childs[i]->DeleteChilds();
+	delete childs[i];
+	childs[i] = NULL;
+      }
+}
+
+
+BlockAllocator ADTreeNode3Div :: ball(sizeof (ADTreeNode3Div));
+
+void * ADTreeNode3Div :: operator new(size_t)
+{
+  return ball.Alloc();
+}
+
+void ADTreeNode3Div :: operator delete (void * p)
+{
+  ball.Free (p);
+}
+
+
+
+
+
+
+
+ADTree3Div :: ADTree3Div (const float * acmin, 
+			  const float * acmax)
+  : ela(0)
+{
+  memcpy (cmin, acmin, 3 * sizeof(float));
+  memcpy (cmax, acmax, 3 * sizeof(float));
+
+  root = new ADTreeNode3Div;
+
+  root->minx = cmin[0];
+  root->dist = (cmax[0] - cmin[0]) / ADTN_DIV;
+
+  //  root->sep = (cmin[0] + cmax[0]) / 2;
+}
+
+ADTree3Div :: ~ADTree3Div ()
+{
+  root->DeleteChilds();
+  delete root;
+}
+
+
+void ADTree3Div :: Insert (const float * p, int pi)
+{
+  ADTreeNode3Div *node;
+  ADTreeNode3Div *next;
+  int dir;
+  int bag;
+  
+  float bmin[3];
+  float bmax[3];
+  
+  memcpy (bmin, cmin, 3 * sizeof(float));
+  memcpy (bmax, cmax, 3 * sizeof(float));
+
+#ifdef MARK
+  //  MARK (insertloop3)
+#endif
+
+  //  (*testout) << endl << "add point " << Point3d (p[0], p[1], p[2]) << endl;
+
+  next = root;
+  dir = 0;
+  while (next)
+    {
+      node = next;
+
+      if (!node->pi)
+	{    
+	  memcpy (node->data, p, 3 * sizeof(float));
+	  node->pi = pi;
+
+	  if (ela.Size() < pi)
+	    ela.SetSize (pi);
+	  ela.Elem(pi) = node;
+
+	  return;
+	}
+
+      double dx = (bmax[dir] - bmin[dir]) / ADTN_DIV;
+      bag = int ((p[dir]-bmin[dir]) / dx);
+
+      //      (*testout) << "insert, bag = " << bag << endl;
+
+      if (bag < 0) bag = 0;
+      if (bag >= ADTN_DIV) bag = ADTN_DIV-1;
+      
+      double nbmin = bmin[dir] + bag * dx;
+      double nbmax = bmin[dir] + (bag+1) * dx;
+
+      /*      
+      (*testout) << "bmin, max = " << bmin[dir] << "-" << bmax[dir]
+      		 << " p = " << p[dir];
+      */
+      next = node->childs[bag];
+      bmin[dir] = nbmin;
+      bmax[dir] = nbmax;
+
+      //      (*testout) << "new bmin, max = " << bmin[dir] << "-" << bmax[dir] << endl;
+
+      
+      /*      
+      if (node->sep > p[dir])
+	{
+	  next = node->left;
+	  bmax[dir] = node->sep;
+	  lr = 0;
+	}
+      else
+	{
+	  next = node->right;
+	  bmin[dir] = node->sep;
+	  lr = 1;
+	}
+      */
+
+      dir++;
+      if (dir == 3)
+	dir = 0;
+    }
+
+#ifdef MARK
+  //  MARK (insertend3)
+#endif
+
+
+  next = new ADTreeNode3Div;
+  memcpy (next->data, p, 3 * sizeof(float));
+  next->pi = pi;
+
+  next->minx = bmin[dir];
+  next->dist = (bmax[dir] - bmin[dir]) / ADTN_DIV;
+  //  next->sep = (bmin[dir] + bmax[dir]) / 2;
+
+
+  if (ela.Size() < pi)
+    ela.SetSize (pi);
+  ela.Elem(pi) = next;
+
+  node->childs[bag] = next;
+  next -> father = node;
+
+  while (node)
+    {
+      node->nchilds++;
+      node = node->father;
+    }
+}
+
+void ADTree3Div :: DeleteElement (int pi)
+{
+  ADTreeNode3Div * node = ela.Get(pi);
+
+  node->pi = 0;
+
+  node = node->father;
+  while (node)
+    {
+      node->nchilds--;
+      node = node->father;
+    }
+}
+
+void ADTree3Div :: GetIntersecting (const float * bmin, 
+				    const float * bmax,
+				    ARRAY<int> & pis) const
+{
+  static ARRAY<ADTreeNode3Div*> stack(1000);
+  static ARRAY<int> stackdir(1000);
+  ADTreeNode3Div * node;
+  int dir, i, stacks;
+
+  stack.SetSize (1000);
+  stackdir.SetSize(1000);
+  pis.SetSize(0);
+
+  stack.Elem(1) = root;
+  stackdir.Elem(1) = 0;
+  stacks = 1;
+
+  while (stacks)
+    {
+      node = stack.Get(stacks);
+      dir = stackdir.Get(stacks); 
+      stacks--;
+
+      if (node->pi)
+	{
+	  if (node->data[0] >= bmin[0] && node->data[0] <= bmax[0] &&
+	      node->data[1] >= bmin[1] && node->data[1] <= bmax[1] &&
+	      node->data[2] >= bmin[2] && node->data[2] <= bmax[2])
+
+	    pis.Append (node->pi);
+	}
+
+
+      int ndir = dir+1;
+      if (ndir == 3)
+	ndir = 0;
+
+      int mini = int ( (bmin[dir] - node->minx) / node->dist );
+      int maxi = int ( (bmax[dir] - node->minx) / node->dist );
+      
+      //      (*testout) << "get int, mini, maxi = " << mini << ", " << maxi << endl;
+      if (mini < 0) mini = 0;
+      if (maxi >= ADTN_DIV) maxi = ADTN_DIV-1;
+
+      for (i = mini; i <= maxi; i++)
+	if (node->childs[i])
+	  {
+	    stacks++;
+	    stack.Elem(stacks) = node->childs[i];
+	    stackdir.Elem(stacks) = ndir;
+	  }
+
+
+      /*
+      if (node->left && bmin[dir] <= node->sep)
+	{
+	  stacks++;
+	  stack.Elem(stacks) = node->left;
+	  stackdir.Elem(stacks) = ndir;
+	}
+      if (node->right && bmax[dir] >= node->sep)
+	{
+	  stacks++;
+	  stack.Elem(stacks) = node->right;
+	  stackdir.Elem(stacks) = ndir;
+	}
+      */
+    }
+}
+
+void ADTree3Div :: PrintRec (ostream & ost, const ADTreeNode3Div * node) const
+{
+  
+  if (node->data)
+    {
+      ost << node->pi << ": ";
+      ost << node->nchilds << " childs, ";
+      ost << " from " << node->minx << " - " << node->minx + node->dist*ADTN_DIV << "  ";
+      for (int i = 0; i < 3; i++)
+	ost << node->data[i] << " ";
+      ost << endl;
+    }
+  int i;
+  for (i = 0; i < ADTN_DIV; i++)
+    if (node->childs[i])
+      PrintRec (ost, node->childs[i]);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+/* ******************************* ADTree3M ******************************* */
+
+
+ADTreeNode3M :: ADTreeNode3M()
+{
+  int i;
+  for (i = 0; i < ADTN_SIZE; i++)
+    pi[i] = 0;
+
+  left = NULL;
+  right = NULL;
+  father = NULL;
+  nchilds = 0;
+}
+
+void ADTreeNode3M :: DeleteChilds ()
+{
+  if (left)
+    {
+      left->DeleteChilds();
+      delete left;
+      left = NULL;
+    }
+  if (right)
+    {
+      right->DeleteChilds();
+      delete right;
+      right = NULL;
+    }
+}
+
+
+BlockAllocator ADTreeNode3M :: ball(sizeof (ADTreeNode3M));
+
+void * ADTreeNode3M :: operator new(size_t)
+{
+  return ball.Alloc();
+}
+
+void ADTreeNode3M :: operator delete (void * p)
+{
+  ball.Free (p);
+}
+
+
+
+
+
+
+
+ADTree3M :: ADTree3M (const float * acmin, 
+			 const float * acmax)
+  : ela(0)
+{
+  memcpy (cmin, acmin, 3 * sizeof(float));
+  memcpy (cmax, acmax, 3 * sizeof(float));
+
+  root = new ADTreeNode3M;
+  root->sep = (cmin[0] + cmax[0]) / 2;
+}
+
+ADTree3M :: ~ADTree3M ()
+{
+  root->DeleteChilds();
+  delete root;
+}
+
+
+void ADTree3M :: Insert (const float * p, int pi)
+{
+  ADTreeNode3M *node;
+  ADTreeNode3M *next;
+  int dir;
+  int lr;
+  int i;
+  float bmin[3];
+  float bmax[3];
+  
+  memcpy (bmin, cmin, 3 * sizeof(float));
+  memcpy (bmax, cmax, 3 * sizeof(float));
+
+#ifdef MARK
+  //  MARK (insertloop3)
+#endif
+
+  next = root;
+  dir = 0;
+  while (next)
+    {
+      node = next;
+
+      for (i = 0; i < ADTN_SIZE; i++)
+	if (!node->pi[i])
+	  {    
+	    memcpy (node->data[i], p, 3 * sizeof(float));
+	    node->pi[i] = pi;
+	    
+	    if (ela.Size() < pi)
+	      ela.SetSize (pi);
+	    ela.Elem(pi) = node;
+	    
+	    return;
+	  }
+
+      if (node->sep > p[dir])
+	{
+	  next = node->left;
+	  bmax[dir] = node->sep;
+	  lr = 0;
+	}
+      else
+	{
+	  next = node->right;
+	  bmin[dir] = node->sep;
+	  lr = 1;
+	}
+
+      dir++;
+      if (dir == 3)
+	dir = 0;
+    }
+
+#ifdef MARK
+  //  MARK (insertend3)
+#endif
+
+
+  next = new ADTreeNode3M;
+  memcpy (next->data[0], p, 3 * sizeof(float));
+  next->pi[0] = pi;
+  next->sep = (bmin[dir] + bmax[dir]) / 2;
+
+
+  if (ela.Size() < pi)
+    ela.SetSize (pi);
+  ela.Elem(pi) = next;
+
+
+  if (lr)
+    node->right = next;
+  else
+    node->left = next;
+  next -> father = node;
+
+  while (node)
+    {
+      node->nchilds++;
+      node = node->father;
+    }
+}
+
+void ADTree3M :: DeleteElement (int pi)
+{
+  ADTreeNode3M * node = ela.Get(pi);
+
+  int i;
+  for (i = 0; i < ADTN_SIZE; i++)
+    if (node->pi[i] == pi)
+      node->pi[i] = 0;
+
+  node = node->father;
+  while (node)
+    {
+      node->nchilds--;
+      node = node->father;
+    }
+}
+
+void ADTree3M :: GetIntersecting (const float * bmin, 
+				 const float * bmax,
+				 ARRAY<int> & pis) const
+{
+  static ARRAY<ADTreeNode3M*> stack(1000);
+  static ARRAY<int> stackdir(1000);
+  ADTreeNode3M * node;
+  int dir, i, stacks;
+
+  stack.SetSize (1000);
+  stackdir.SetSize(1000);
+  pis.SetSize(0);
+
+  stack.Elem(1) = root;
+  stackdir.Elem(1) = 0;
+  stacks = 1;
+
+  while (stacks)
+    {
+      node = stack.Get(stacks);
+      dir = stackdir.Get(stacks); 
+      stacks--;
+
+      int * hpi = node->pi;
+      for (i = 0; i < ADTN_SIZE; i++)
+	if (hpi[i])
+	  {
+	    float * datai = &node->data[i][0];
+	    if (datai[0] >= bmin[0] && datai[0] <= bmax[0] &&
+		datai[1] >= bmin[1] && datai[1] <= bmax[1] &&
+		datai[2] >= bmin[2] && datai[2] <= bmax[2])
+	      
+	      pis.Append (node->pi[i]);
+	  }
+
+
+      int ndir = dir+1;
+      if (ndir == 3)
+	ndir = 0;
+
+      if (node->left && bmin[dir] <= node->sep)
+	{
+	  stacks++;
+	  stack.Elem(stacks) = node->left;
+	  stackdir.Elem(stacks) = ndir;
+	}
+      if (node->right && bmax[dir] >= node->sep)
+	{
+	  stacks++;
+	  stack.Elem(stacks) = node->right;
+	  stackdir.Elem(stacks) = ndir;
+	}
+    }
+}
+
+void ADTree3M :: PrintRec (ostream & ost, const ADTreeNode3M * node) const
+{
+  
+  if (node->data)
+    {
+      //      ost << node->pi << ": ";
+      ost << node->nchilds << " childs, ";
+      for (int i = 0; i < 3; i++)
+	ost << node->data[i] << " ";
+      ost << endl;
+    }
+  if (node->left)
+    PrintRec (ost, node->left);
+  if (node->right)
+    PrintRec (ost, node->right);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+/* ******************************* ADTree3F ******************************* */
+
+
+ADTreeNode3F :: ADTreeNode3F()
+{
+  pi = 0;
+  father = NULL;
+  nchilds = 0;
+  int i;
+  for (i = 0; i < 8; i++)
+    childs[i] = NULL;
+}
+
+void ADTreeNode3F :: DeleteChilds ()
+{
+  int i;
+
+  for (i = 0; i < 8; i++)
+    {
+      if (childs[i])
+	childs[i]->DeleteChilds();
+      delete childs[i];
+      childs[i] = NULL;
+    }
+}
+
+
+BlockAllocator ADTreeNode3F :: ball(sizeof (ADTreeNode3F));
+
+void * ADTreeNode3F :: operator new(size_t)
+{
+  return ball.Alloc();
+}
+
+void ADTreeNode3F :: operator delete (void * p)
+{
+  ball.Free (p);
+}
+
+
+
+
+
+
+
+ADTree3F :: ADTree3F (const float * acmin, 
+		      const float * acmax)
+  : ela(0)
+{
+  memcpy (cmin, acmin, 3 * sizeof(float));
+  memcpy (cmax, acmax, 3 * sizeof(float));
+
+  root = new ADTreeNode3F;
+  for (int i = 0; i < 3; i++)
+    root->sep[i] = (cmin[i] + cmax[i]) / 2;
+}
+
+ADTree3F :: ~ADTree3F ()
+{
+  root->DeleteChilds();
+  delete root;
+}
+
+
+void ADTree3F :: Insert (const float * p, int pi)
+{
+  ADTreeNode3F *node;
+  ADTreeNode3F *next;
+  int lr;
+
+  float bmin[3];
+  float bmax[3];
+  int i, dir;
+  
+  memcpy (bmin, cmin, 3 * sizeof(float));
+  memcpy (bmax, cmax, 3 * sizeof(float));
+
+#ifdef MARK
+  //  MARK (insertloop3)
+#endif
+
+  next = root;
+  while (next)
+    {
+      node = next;
+      
+      if (!node->pi)
+	{    
+	  memcpy (node->data, p, 3 * sizeof(float));
+	  node->pi = pi;
+
+	  if (ela.Size() < pi)
+	    ela.SetSize (pi);
+	  ela.Elem(pi) = node;
+
+	  return;
+	}
+
+      dir = 0;
+      for (i = 0; i < 3; i++)
+	{
+	  if (node->sep[i] > p[i])
+	    {
+	      bmax[i] = node->sep[i];
+	    }
+	  else
+	    {
+	      bmin[i] = node->sep[i];
+	      dir += (1 << i);
+	    }
+	}
+      next = node->childs[dir];
+
+      /*
+      if (node->sep > p[dir])
+	{
+	  next = node->left;
+	  bmax[dir] = node->sep;
+	  lr = 0;
+	}
+      else
+	{
+	  next = node->right;
+	  bmin[dir] = node->sep;
+	  lr = 1;
+	}
+      */
+    }
+
+
+  next = new ADTreeNode3F;
+  memcpy (next->data, p, 3 * sizeof(float));
+  next->pi = pi;
+
+  for (i = 0; i < 3; i++)
+    next->sep[i] = (bmin[i] + bmax[i]) / 2;
+  
+
+  if (ela.Size() < pi)
+    ela.SetSize (pi);
+  ela.Elem(pi) = next;
+
+  node->childs[dir] = next;
+  next->father = node;
+
+  while (node)
+    {
+      node->nchilds++;
+      node = node->father;
+    }
+}
+
+void ADTree3F :: DeleteElement (int pi)
+{
+  ADTreeNode3F * node = ela.Get(pi);
+
+  node->pi = 0;
+
+  node = node->father;
+  while (node)
+    {
+      node->nchilds--;
+      node = node->father;
+    }
+}
+
+void ADTree3F :: GetIntersecting (const float * bmin, 
+				  const float * bmax,
+				  ARRAY<int> & pis) const
+{
+  static ARRAY<ADTreeNode3F*> stack(1000);
+  ADTreeNode3F * node;
+  int dir, i, stacks;
+
+  stack.SetSize (1000);
+  pis.SetSize(0);
+
+  stack.Elem(1) = root;
+  stacks = 1;
+
+  while (stacks)
+    {
+      node = stack.Get(stacks);
+      stacks--;
+
+      if (node->pi)
+	{
+	  if (node->data[0] >= bmin[0] && node->data[0] <= bmax[0] &&
+	      node->data[1] >= bmin[1] && node->data[1] <= bmax[1] &&
+	      node->data[2] >= bmin[2] && node->data[2] <= bmax[2])
+
+	    pis.Append (node->pi);
+	}
+
+      
+      int i1min = (bmin[0] <= node->sep[0]) ? 0 : 1;
+      int i1max = (bmax[0] < node->sep[0]) ? 0 : 1;
+      int i2min = (bmin[1] <= node->sep[1]) ? 0 : 1;
+      int i2max = (bmax[1] < node->sep[1]) ? 0 : 1;
+      int i3min = (bmin[2] <= node->sep[2]) ? 0 : 1;
+      int i3max = (bmax[2] < node->sep[2]) ? 0 : 1;
+
+      int i1, i2, i3;
+      for (i1 = i1min; i1 <= i1max; i1++)
+	for (i2 = i2min; i2 <= i2max; i2++)
+	  for (i3 = i3min; i3 <= i3max; i3++)
+	    {
+	      i = i1+2*i2+4*i3;
+	      if (node->childs[i])
+		{
+		  stacks++;
+		  stack.Elem(stacks) = node->childs[i];
+		}
+	    }
+      
+      /*
+      if (node->left && bmin[dir] <= node->sep)
+	{
+	  stacks++;
+	  stack.Elem(stacks) = node->left;
+	  stackdir.Elem(stacks) = ndir;
+	}
+      if (node->right && bmax[dir] >= node->sep)
+	{
+	  stacks++;
+	  stack.Elem(stacks) = node->right;
+	  stackdir.Elem(stacks) = ndir;
+	}
+      */
+    }
+}
+
+void ADTree3F :: PrintRec (ostream & ost, const ADTreeNode3F * node) const
+{
+  int i;
+  if (node->data)
+    {
+      ost << node->pi << ": ";
+      ost << node->nchilds << " childs, ";
+      for (i = 0; i < 3; i++)
+	ost << node->data[i] << " ";
+      ost << endl;
+    }
+
+  for (i = 0; i < 8; i++)
+    if (node->childs[i])
+      PrintRec (ost, node->childs[i]);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+/* ******************************* ADTree3FM ******************************* */
+
+
+ADTreeNode3FM :: ADTreeNode3FM()
+{
+  father = NULL;
+  nchilds = 0;
+  int i;
+
+  for (i = 0; i < ADTN_SIZE; i++)
+    pi[i] = 0;
+
+  for (i = 0; i < 8; i++)
+    childs[i] = NULL;
+}
+
+void ADTreeNode3FM :: DeleteChilds ()
+{
+  int i;
+
+  for (i = 0; i < 8; i++)
+    {
+      if (childs[i])
+	childs[i]->DeleteChilds();
+      delete childs[i];
+      childs[i] = NULL;
+    }
+}
+
+
+BlockAllocator ADTreeNode3FM :: ball(sizeof (ADTreeNode3FM));
+
+void * ADTreeNode3FM :: operator new(size_t)
+{
+  return ball.Alloc();
+}
+
+void ADTreeNode3FM :: operator delete (void * p)
+{
+  ball.Free (p);
+}
+
+
+
+
+
+
+
+ADTree3FM :: ADTree3FM (const float * acmin, 
+		      const float * acmax)
+  : ela(0)
+{
+  memcpy (cmin, acmin, 3 * sizeof(float));
+  memcpy (cmax, acmax, 3 * sizeof(float));
+
+  root = new ADTreeNode3FM;
+  for (int i = 0; i < 3; i++)
+    root->sep[i] = (cmin[i] + cmax[i]) / 2;
+}
+
+ADTree3FM :: ~ADTree3FM ()
+{
+  root->DeleteChilds();
+  delete root;
+}
+
+
+void ADTree3FM :: Insert (const float * p, int pi)
+{
+  ADTreeNode3FM *node;
+  ADTreeNode3FM *next;
+  int lr;
+
+  float bmin[3];
+  float bmax[3];
+  int i, dir;
+  
+  memcpy (bmin, cmin, 3 * sizeof(float));
+  memcpy (bmax, cmax, 3 * sizeof(float));
+
+#ifdef MARK
+  //  MARK (insertloop3)
+#endif
+
+  next = root;
+  while (next)
+    {
+      node = next;
+      
+      for (i = 0; i < ADTN_SIZE; i++)
+	if (!node->pi[i])
+	  {    
+	    memcpy (node->data[i], p, 3 * sizeof(float));
+	    node->pi[i] = pi;
+	    
+	    if (ela.Size() < pi)
+	      ela.SetSize (pi);
+	    ela.Elem(pi) = node;
+	    
+	    return;
+	  }
+
+      dir = 0;
+      for (i = 0; i < 3; i++)
+	{
+	  if (node->sep[i] > p[i])
+	    {
+	      bmax[i] = node->sep[i];
+	    }
+	  else
+	    {
+	      bmin[i] = node->sep[i];
+	      dir += (1 << i);
+	    }
+	}
+      next = node->childs[dir];
+
+      /*
+      if (node->sep > p[dir])
+	{
+	  next = node->left;
+	  bmax[dir] = node->sep;
+	  lr = 0;
+	}
+      else
+	{
+	  next = node->right;
+	  bmin[dir] = node->sep;
+	  lr = 1;
+	}
+      */
+    }
+
+
+  next = new ADTreeNode3FM;
+  memcpy (next->data[0], p, 3 * sizeof(float));
+  next->pi[0] = pi;
+
+  for (i = 0; i < 3; i++)
+    next->sep[i] = (bmin[i] + bmax[i]) / 2;
+  
+
+  if (ela.Size() < pi)
+    ela.SetSize (pi);
+  ela.Elem(pi) = next;
+
+  node->childs[dir] = next;
+  next->father = node;
+
+  while (node)
+    {
+      node->nchilds++;
+      node = node->father;
+    }
+}
+
+void ADTree3FM :: DeleteElement (int pi)
+{
+  ADTreeNode3FM * node = ela.Get(pi);
+
+  int i;
+  for (i = 0; i < ADTN_SIZE; i++)
+    if (node->pi[i] == pi)
+      node->pi[i] = 0;
+
+  node = node->father;
+  while (node)
+    {
+      node->nchilds--;
+      node = node->father;
+    }
+}
+
+void ADTree3FM :: GetIntersecting (const float * bmin, 
+				  const float * bmax,
+				  ARRAY<int> & pis) const
+{
+  static ARRAY<ADTreeNode3FM*> stack(1000);
+  ADTreeNode3FM * node;
+  int dir, i, stacks;
+
+  stack.SetSize (1000);
+  pis.SetSize(0);
+
+  stack.Elem(1) = root;
+  stacks = 1;
+
+  while (stacks)
+    {
+      node = stack.Get(stacks);
+      stacks--;
+
+      int * hpi = node->pi;
+      for (i = 0; i < ADTN_SIZE; i++)
+	if (hpi[i])
+	  {
+	    float * datai = &node->data[i][0];
+	    if (datai[0] >= bmin[0] && datai[0] <= bmax[0] &&
+		datai[1] >= bmin[1] && datai[1] <= bmax[1] &&
+		datai[2] >= bmin[2] && datai[2] <= bmax[2])
+	      
+	      pis.Append (node->pi[i]);
+	  }
+
+      /*
+      if (node->pi)
+	{
+	  if (node->data[0] >= bmin[0] && node->data[0] <= bmax[0] &&
+	      node->data[1] >= bmin[1] && node->data[1] <= bmax[1] &&
+	      node->data[2] >= bmin[2] && node->data[2] <= bmax[2])
+
+	    pis.Append (node->pi);
+	}
+      */
+      
+      int i1min = (bmin[0] <= node->sep[0]) ? 0 : 1;
+      int i1max = (bmax[0] < node->sep[0]) ? 0 : 1;
+      int i2min = (bmin[1] <= node->sep[1]) ? 0 : 1;
+      int i2max = (bmax[1] < node->sep[1]) ? 0 : 1;
+      int i3min = (bmin[2] <= node->sep[2]) ? 0 : 1;
+      int i3max = (bmax[2] < node->sep[2]) ? 0 : 1;
+
+      int i1, i2, i3;
+      for (i1 = i1min; i1 <= i1max; i1++)
+	for (i2 = i2min; i2 <= i2max; i2++)
+	  for (i3 = i3min; i3 <= i3max; i3++)
+	    {
+	      i = i1+2*i2+4*i3;
+	      if (node->childs[i])
+		{
+		  stacks++;
+		  stack.Elem(stacks) = node->childs[i];
+		}
+	    }
+      
+      /*
+      if (node->left && bmin[dir] <= node->sep)
+	{
+	  stacks++;
+	  stack.Elem(stacks) = node->left;
+	  stackdir.Elem(stacks) = ndir;
+	}
+      if (node->right && bmax[dir] >= node->sep)
+	{
+	  stacks++;
+	  stack.Elem(stacks) = node->right;
+	  stackdir.Elem(stacks) = ndir;
+	}
+      */
+    }
+}
+
+void ADTree3FM :: PrintRec (ostream & ost, const ADTreeNode3FM * node) const
+{
+  int i;
+  if (node->data)
+    {
+      ost << node->pi << ": ";
+      ost << node->nchilds << " childs, ";
+      for (i = 0; i < 3; i++)
+	ost << node->data[i] << " ";
+      ost << endl;
+    }
+
+  for (i = 0; i < 8; i++)
+    if (node->childs[i])
+      PrintRec (ost, node->childs[i]);
+}
+
+
+
+
+
+
+
+
+
+
+/* ******************************* ADTree6 ******************************* */
+
+
+ADTreeNode6 :: ADTreeNode6()
+{
+  pi = 0;
+
+  left = NULL;
+  right = NULL;
+  father = NULL;
+  nchilds = 0;
+}
+
+void ADTreeNode6 :: DeleteChilds ()
+{
+  if (left)
+    {
+      left->DeleteChilds();
+      delete left;
+      left = NULL;
+    }
+  if (right)
+    {
+      right->DeleteChilds();
+      delete right;
+      right = NULL;
+    }
+}
+
+
+BlockAllocator ADTreeNode6 :: ball (sizeof (ADTreeNode6));
+void * ADTreeNode6 :: operator new(size_t)
+{
+  return ball.Alloc();
+}
+
+void ADTreeNode6 :: operator delete (void * p)
+{
+  ball.Free (p);
+}
+
+
+
+
+
+ADTree6 :: ADTree6 (const float * acmin, 
+			 const float * acmax)
+  : ela(0)
+{
+  memcpy (cmin, acmin, 6 * sizeof(float));
+  memcpy (cmax, acmax, 6 * sizeof(float));
+
+  root = new ADTreeNode6;
+  root->sep = (cmin[0] + cmax[0]) / 2;
+}
+
+ADTree6 :: ~ADTree6 ()
+{
+  root->DeleteChilds();
+  delete root;
+}
+
+void ADTree6 :: Insert (const float * p, int pi)
+{
+  ADTreeNode6 *node;
+  ADTreeNode6 *next;
+  int dir;
+  int lr;
+
+  float bmin[6];
+  float bmax[6];
+
+  
+  memcpy (bmin, cmin, 6 * sizeof(float));
+  memcpy (bmax, cmax, 6 * sizeof(float));
+
+#ifdef MARK
+  MARK (insertloop6)
+#endif
+
+  next = root;
+  dir = 0;
+  while (next)
+    {
+      node = next;
+
+      if (!node->pi)
+	{    
+	  memcpy (node->data, p, 6 * sizeof(float));
+	  node->pi = pi;
+
+	  if (ela.Size() < pi)
+	    ela.SetSize (pi);
+	  ela.Elem(pi) = node;
+
+	  return;
+	}
+
+      if (node->sep > p[dir])
+	{
+	  next = node->left;
+	  bmax[dir] = node->sep;
+	  lr = 0;
+	}
+      else
+	{
+	  next = node->right;
+	  bmin[dir] = node->sep;
+	  lr = 1;
+	}
+
+      dir++;
+      if (dir == 6)
+	dir = 0;
+    }
+
+#ifdef MARK
+  MARK (insertend6)
+#endif
+
+
+  next = new ADTreeNode6;
+  memcpy (next->data, p, 6 * sizeof(float));
+  next->pi = pi;
+  next->sep = (bmin[dir] + bmax[dir]) / 2;
+
+
+  if (ela.Size() < pi)
+    ela.SetSize (pi);
+  ela.Elem(pi) = next;
+
+
+  if (lr)
+    node->right = next;
+  else
+    node->left = next;
+  next -> father = node;
+
+  while (node)
+    {
+      node->nchilds++;
+      node = node->father;
+    }
+}
+
+void ADTree6 :: DeleteElement (int pi)
+{
+  ADTreeNode6 * node = ela.Get(pi);
+
+  node->pi = 0;
+
+  node = node->father;
+  while (node)
+    {
+      node->nchilds--;
+      node = node->father;
+    }
+}
+
+void ADTree6 :: PrintMemInfo (ostream & ost) const
+{
+  ost << Elements() << " elements a " << sizeof(ADTreeNode6) 
+      << " Bytes = "
+      << Elements() * sizeof(ADTreeNode6) << endl;
+  ost << "maxind = " << ela.Size() << " = " << sizeof(ADTreeNode6*) * ela.Size() << " Bytes" << endl;
+}
+
+
+
+class inttn6 {
+public:
+  int dir;
+  ADTreeNode6 * node;
+};
+
+
+
+
+void ADTree6 :: GetIntersecting (const float * bmin, 
+				 const float * bmax,
+				 ARRAY<int> & pis) const
+{
+  static ARRAY<inttn6> stack(10000);
+  ADTreeNode6 * node;
+  int dir, stacks;
+
+  stack.SetSize (10000);
+  pis.SetSize(0);
+
+  stack.Elem(1).node = root;
+  stack.Elem(1).dir = 0;
+  stacks = 1;
+
+  while (stacks)
+    {
+      node = stack.Get(stacks).node;
+      dir = stack.Get(stacks).dir; 
+      stacks--;
+
+      if (node->pi)
+	{
+	  
+// 	  int in = 1;
+// 	  for (i = 0; i < 3; i++)
+// 	    if (/* node->data[i] < bmin[i]  || */ node->data[i] > bmax[i] || 
+// 		node->data[i+3] < bmin[i+3] /* || node->data[i+3] > bmax[i+3] */ )
+// 	      {
+// 		in = 0;
+// 		break;
+// 	      }
+
+// 	  if (in)
+// 	    pis.Append (node->pi);
+
+	  if (node->data[0] > bmax[0] || 
+	      node->data[1] > bmax[1] || 
+	      node->data[2] > bmax[2] || 
+	      node->data[3] < bmin[3] || 
+	      node->data[4] < bmin[4] || 
+	      node->data[5] < bmin[5])
+	    ;
+	  else
+	    pis.Append (node->pi);
+	}
+
+
+      int ndir = dir+1;
+      if (ndir == 6)
+	ndir = 0;
+
+      if (node->left && bmin[dir] <= node->sep)
+	{
+	  stacks++;
+	  stack.Elem(stacks).node = node->left;
+	  stack.Elem(stacks).dir = ndir;
+	}
+      if (node->right && bmax[dir] >= node->sep)
+	{
+	  stacks++;
+	  stack.Elem(stacks).node = node->right;
+	  stack.Elem(stacks).dir = ndir;
+	}
+    }
+}
+
+/*
+void ADTree6 :: GetIntersecting (const float * bmin, 
+				 const float * bmax,
+				 ARRAY<int> & pis) const
+{
+  static ARRAY<ADTreeNode6*> stack(10000);
+  static ARRAY<int> stackdir(10000);
+  ADTreeNode6 * node;
+  int dir, stacks;
+
+  stack.SetSize (10000);
+  stackdir.SetSize(10000);
+  pis.SetSize(0);
+
+  stack.Elem(1) = root;
+  stackdir.Elem(1) = 0;
+  stacks = 1;
+
+  while (stacks)
+    {
+      node = stack.Get(stacks);
+      dir = stackdir.Get(stacks); 
+      stacks--;
+
+      if (node->pi)
+	{
+	  
+	  if (node->data[0] > bmax[0] || 
+	      node->data[1] > bmax[1] || 
+	      node->data[2] > bmax[2] || 
+	      node->data[3] < bmin[3] || 
+	      node->data[4] < bmin[4] || 
+	      node->data[5] < bmin[5])
+	    ;
+	  else
+	    pis.Append (node->pi);
+	}
+
+
+      int ndir = dir+1;
+      if (ndir == 6)
+	ndir = 0;
+
+      if (node->left && bmin[dir] <= node->sep)
+	{
+	  stacks++;
+	  stack.Elem(stacks) = node->left;
+	  stackdir.Elem(stacks) = ndir;
+	}
+      if (node->right && bmax[dir] >= node->sep)
+	{
+	  stacks++;
+	  stack.Elem(stacks) = node->right;
+	  stackdir.Elem(stacks) = ndir;
+	}
+    }
+}
+*/
+
+
+void ADTree6 :: PrintRec (ostream & ost, const ADTreeNode6 * node) const
+{
+  
+  if (node->data)
+    {
+      ost << node->pi << ": ";
+      ost << node->nchilds << " childs, ";
+      for (int i = 0; i < 6; i++)
+	ost << node->data[i] << " ";
+      ost << endl;
+    }
+  if (node->left)
+    PrintRec (ost, node->left);
+  if (node->right)
+    PrintRec (ost, node->right);
+}
+
+
+int ADTree6 :: DepthRec (const ADTreeNode6 * node) const
+{
+  int ldepth = 0;
+  int rdepth = 0;
+
+  if (node->left)
+    ldepth = DepthRec(node->left);
+  if (node->right)
+    rdepth = DepthRec(node->right);
+  return 1 + max2 (ldepth, rdepth);
+}
+
+int ADTree6 :: ElementsRec (const ADTreeNode6 * node) const
+{
+  int els = 1;
+  if (node->left)
+    els += ElementsRec(node->left);
+  if (node->right)
+    els += ElementsRec(node->right);
+  return els;
+}
+
+
+
+
+
+
+
+/* ******************************* ADTree6F ******************************* */
+
+
+ADTreeNode6F :: ADTreeNode6F()
+{
+  pi = 0;
+  father = NULL;
+  nchilds = 0;
+  int i;
+  for (i = 0; i < 64; i++)
+    childs[i] = NULL;
+}
+
+void ADTreeNode6F :: DeleteChilds ()
+{
+  int i;
+
+  for (i = 0; i < 64; i++)
+    {
+      if (childs[i])
+	childs[i]->DeleteChilds();
+      delete childs[i];
+      childs[i] = NULL;
+    }
+}
+
+
+BlockAllocator ADTreeNode6F :: ball(sizeof (ADTreeNode6F));
+
+void * ADTreeNode6F :: operator new(size_t)
+{
+  return ball.Alloc();
+}
+
+void ADTreeNode6F :: operator delete (void * p)
+{
+  ball.Free (p);
+}
+
+
+
+
+
+
+
+ADTree6F :: ADTree6F (const float * acmin, 
+		      const float * acmax)
+  : ela(0)
+{
+  memcpy (cmin, acmin, 6 * sizeof(float));
+  memcpy (cmax, acmax, 6 * sizeof(float));
+
+  root = new ADTreeNode6F;
+  for (int i = 0; i < 6; i++)
+    root->sep[i] = (cmin[i] + cmax[i]) / 2;
+}
+
+ADTree6F :: ~ADTree6F ()
+{
+  root->DeleteChilds();
+  delete root;
+}
+
+
+void ADTree6F :: Insert (const float * p, int pi)
+{
+  ADTreeNode6F *node;
+  ADTreeNode6F *next;
+  int lr;
+
+  float bmin[6];
+  float bmax[6];
+  int i, dir;
+  
+  memcpy (bmin, cmin, 6 * sizeof(float));
+  memcpy (bmax, cmax, 6 * sizeof(float));
+
+#ifdef MARK
+  //  MARK (insertloop3)
+#endif
+
+  next = root;
+  while (next)
+    {
+      node = next;
+      
+      if (!node->pi)
+	{    
+	  memcpy (node->data, p, 6 * sizeof(float));
+	  node->pi = pi;
+
+	  if (ela.Size() < pi)
+	    ela.SetSize (pi);
+	  ela.Elem(pi) = node;
+
+	  return;
+	}
+
+      dir = 0;
+      for (i = 0; i < 6; i++)
+	{
+	  if (node->sep[i] > p[i])
+	    {
+	      bmax[i] = node->sep[i];
+	    }
+	  else
+	    {
+	      bmin[i] = node->sep[i];
+	      dir += (1 << i);
+	    }
+	}
+      next = node->childs[dir];
+
+      /*
+      if (node->sep > p[dir])
+	{
+	  next = node->left;
+	  bmax[dir] = node->sep;
+	  lr = 0;
+	}
+      else
+	{
+	  next = node->right;
+	  bmin[dir] = node->sep;
+	  lr = 1;
+	}
+      */
+    }
+
+
+  next = new ADTreeNode6F;
+  memcpy (next->data, p, 6 * sizeof(float));
+  next->pi = pi;
+
+  for (i = 0; i < 6; i++)
+    next->sep[i] = (bmin[i] + bmax[i]) / 2;
+  
+
+  if (ela.Size() < pi)
+    ela.SetSize (pi);
+  ela.Elem(pi) = next;
+
+  node->childs[dir] = next;
+  next->father = node;
+
+  while (node)
+    {
+      node->nchilds++;
+      node = node->father;
+    }
+}
+
+void ADTree6F :: DeleteElement (int pi)
+{
+  ADTreeNode6F * node = ela.Get(pi);
+
+  node->pi = 0;
+
+  node = node->father;
+  while (node)
+    {
+      node->nchilds--;
+      node = node->father;
+    }
+}
+
+void ADTree6F :: GetIntersecting (const float * bmin, 
+				  const float * bmax,
+				  ARRAY<int> & pis) const
+{
+  static ARRAY<ADTreeNode6F*> stack(1000);
+  ADTreeNode6F * node;
+  int dir, i, stacks;
+
+  stack.SetSize (1000);
+  pis.SetSize(0);
+
+  stack.Elem(1) = root;
+  stacks = 1;
+
+  while (stacks)
+    {
+      node = stack.Get(stacks);
+      stacks--;
+
+      if (node->pi)
+	{
+	  if (
+	      node->data[0] >= bmin[0] && node->data[0] <= bmax[0] &&
+	      node->data[1] >= bmin[1] && node->data[1] <= bmax[1] &&
+	      node->data[2] >= bmin[2] && node->data[2] <= bmax[2] &&
+	      node->data[3] >= bmin[3] && node->data[3] <= bmax[3] &&
+	      node->data[4] >= bmin[4] && node->data[4] <= bmax[4] &&
+	      node->data[5] >= bmin[5] && node->data[5] <= bmax[5]
+	      )
+
+	    pis.Append (node->pi);
+	}
+
+      
+      int i1min = (bmin[0] <= node->sep[0]) ? 0 : 1;
+      int i1max = (bmax[0] < node->sep[0]) ? 0 : 1;
+      int i2min = (bmin[1] <= node->sep[1]) ? 0 : 1;
+      int i2max = (bmax[1] < node->sep[1]) ? 0 : 1;
+      int i3min = (bmin[2] <= node->sep[2]) ? 0 : 1;
+      int i3max = (bmax[2] < node->sep[2]) ? 0 : 1;
+
+      int i4min = (bmin[3] <= node->sep[3]) ? 0 : 1;
+      int i4max = (bmax[3] <  node->sep[3]) ? 0 : 1;
+      int i5min = (bmin[4] <= node->sep[4]) ? 0 : 1;
+      int i5max = (bmax[4] <  node->sep[4]) ? 0 : 1;
+      int i6min = (bmin[5] <= node->sep[5]) ? 0 : 1;
+      int i6max = (bmax[5] <  node->sep[5]) ? 0 : 1;
+
+      int i1, i2, i3, i4, i5, i6;
+      for (i1 = i1min; i1 <= i1max; i1++)
+	for (i2 = i2min; i2 <= i2max; i2++)
+	  for (i3 = i3min; i3 <= i3max; i3++)
+	    for (i4 = i4min; i4 <= i4max; i4++)
+	      for (i5 = i5min; i5 <= i5max; i5++)
+		for (i6 = i6min; i6 <= i6max; i6++)
+		  {
+		    i = i1 + 2*i2 + 4*i3 + 8*i4 + 16*i5 +32*i6;
+		    if (node->childs[i])
+		      {
+			stacks++;
+			stack.Elem(stacks) = node->childs[i];
+		      }
+		  }
+      
+      /*
+      if (node->left && bmin[dir] <= node->sep)
+	{
+	  stacks++;
+	  stack.Elem(stacks) = node->left;
+	  stackdir.Elem(stacks) = ndir;
+	}
+      if (node->right && bmax[dir] >= node->sep)
+	{
+	  stacks++;
+	  stack.Elem(stacks) = node->right;
+	  stackdir.Elem(stacks) = ndir;
+	}
+      */
+    }
+}
+
+void ADTree6F :: PrintRec (ostream & ost, const ADTreeNode6F * node) const
+{
+  int i;
+  if (node->data)
+    {
+      ost << node->pi << ": ";
+      ost << node->nchilds << " childs, ";
+      for (i = 0; i < 6; i++)
+	ost << node->data[i] << " ";
+      ost << endl;
+    }
+
+  for (i = 0; i < 64; i++)
+    if (node->childs[i])
+      PrintRec (ost, node->childs[i]);
+}
+
+
+
+
+/* ************************************* Point3dTree ********************** */
+
+
+
+Point3dTree :: Point3dTree (const Point3d & pmin, const Point3d & pmax)
+{
+  float pmi[3], pma[3];
+  for (int i = 0; i < 3; i++)
+    {
+      pmi[i] = pmin.X(i+1);
+      pma[i] = pmax.X(i+1);
+    }
+  tree = new ADTree3 (pmi, pma);
+}
+
+Point3dTree :: ~Point3dTree ()
+{
+  delete tree;
+}
+
+
+
+void Point3dTree :: Insert (const Point3d & p, int pi)
+{
+  static float pd[3];
+  pd[0] = p.X();
+  pd[1] = p.Y();
+  pd[2] = p.Z();
+  tree->Insert (pd, pi);
+}
+
+void Point3dTree :: GetIntersecting (const Point3d & pmin, const Point3d & pmax, 
+				     ARRAY<int> & pis) const
+{
+  float pmi[3], pma[3];
+  for (int i = 0; i < 3; i++)
+    {
+      pmi[i] = pmin.X(i+1);
+      pma[i] = pmax.X(i+1);
+    }
+  tree->GetIntersecting (pmi, pma, pis);
+}
+
+
+
+
+
+
+
+
+
+
+Box3dTree :: Box3dTree (const Point3d & apmin, const Point3d & apmax)
+{
+  boxpmin = apmin;
+  boxpmax = apmax;
+  float tpmin[6], tpmax[6];
+  for (int i = 0; i < 3; i++)
+    {
+      tpmin[i] = tpmin[i+3] = boxpmin.X(i+1);
+      tpmax[i] = tpmax[i+3] = boxpmax.X(i+1);
+    }
+  tree = new ADTree6 (tpmin, tpmax);
+}
+
+Box3dTree :: ~Box3dTree ()
+{
+  delete tree;
+}
+
+void Box3dTree :: Insert (const Point3d & bmin, const Point3d & bmax, int pi)
+{
+  static float tp[6];
+
+  for (int i = 0; i < 3; i++)
+    {
+      tp[i] = bmin.X(i+1);
+      tp[i+3] = bmax.X(i+1);
+    }
+
+  tree->Insert (tp, pi);
+}
+
+void Box3dTree ::GetIntersecting (const Point3d & pmin, const Point3d & pmax, 
+				  ARRAY<int> & pis) const
+{
+  float tpmin[6];
+  float tpmax[6];
+
+  for (int i = 0; i < 3; i++)
+    {
+      tpmin[i] = boxpmin.X(i+1);
+      tpmax[i] = pmax.X(i+1);
+      
+      tpmin[i+3] = pmin.X(i+1);
+      tpmax[i+3] = boxpmax.X(i+1);
+    }
+
+  tree->GetIntersecting (tpmin, tpmax, pis);
+}
+
+}
diff --git a/Netgen/libsrc/gprim/adtree.hpp b/Netgen/libsrc/gprim/adtree.hpp
new file mode 100644
index 0000000000..d28f873086
--- /dev/null
+++ b/Netgen/libsrc/gprim/adtree.hpp
@@ -0,0 +1,477 @@
+#ifndef FILE_ADTREE
+#define FILE_ADTREE
+
+/* *************************************************************************/
+/* File:   adtree.hh                                                       */
+/* Author: Joachim Schoeberl                                               */
+/* Date:   16. Feb. 98                                                     */
+/* Redesigned by Wolfram Muehlhuber, May 1998                              */
+/* *************************************************************************/
+
+
+
+/**
+  Alternating Digital Tree
+ */
+
+#include <mystdlib.h>
+#include <myadt.hpp>
+
+class ADTreeNode
+{
+public:
+  ADTreeNode *left, *right, *father;
+  int dim;
+  float sep;
+  float *data;
+  float *boxmin;
+  float *boxmax;
+  int pi;
+  int nchilds;
+
+  ADTreeNode (int adim);
+  ~ADTreeNode ();
+
+  friend class ADTree;
+};
+
+
+class ADTreeCriterion
+{
+public:
+  ADTreeCriterion() { }
+  virtual int Eval (const ADTreeNode * node) const = 0;
+};
+
+
+class ADTree
+{
+  int dim;
+  ADTreeNode * root;
+  float *cmin, *cmax;
+  ARRAY<ADTreeNode*> ela;
+  const ADTreeCriterion * criterion; 
+
+  ARRAY<ADTreeNode*> stack;
+  ARRAY<int> stackdir;
+  int stackindex;
+
+public:
+  ADTree (int adim, const float * acmin, 
+	   const float * acmax);
+  ~ADTree ();
+
+  void Insert (const float * p, int pi);
+  // void GetIntersecting (const float * bmin, const float * bmax,
+  //			ARRAY<int> & pis) const;
+  void SetCriterion (ADTreeCriterion & acriterion);
+  void Reset ();
+  int Next ();
+  void GetMatch (ARRAY<int> & matches);
+
+  void DeleteElement (int pi);
+
+
+  void Print (ostream & ost) const
+    { PrintRec (ost, root); }
+
+  void PrintRec (ostream & ost, const ADTreeNode * node) const;
+};
+
+
+
+class ADTreeNode3
+{
+public:
+  ADTreeNode3 *left, *right, *father;
+  float sep;
+  float data[3];
+  int pi;
+  int nchilds;
+
+  ADTreeNode3 ();
+  void DeleteChilds ();
+  friend class ADTree3;
+
+  static BlockAllocator ball;
+  void * operator new(size_t);
+  void operator delete (void *);
+};
+
+
+class ADTree3
+{
+  ADTreeNode3 * root;
+  float cmin[3], cmax[3];
+  ARRAY<ADTreeNode3*> ela;
+
+public:
+  ADTree3 (const float * acmin, 
+	   const float * acmax);
+  ~ADTree3 ();
+
+  void Insert (const float * p, int pi);
+  void GetIntersecting (const float * bmin, const float * bmax,
+			ARRAY<int> & pis) const;
+  
+  void DeleteElement (int pi);
+
+
+  void Print (ostream & ost) const
+    { PrintRec (ost, root); }
+
+  void PrintRec (ostream & ost, const ADTreeNode3 * node) const;
+};
+
+
+
+
+// divide each direction
+#define ADTN_DIV 10
+class ADTreeNode3Div
+{
+public:
+  ADTreeNode3Div *father;
+  ADTreeNode3Div *childs[ADTN_DIV];
+
+  float minx, dist;
+  float data[3];
+  int pi;
+  int nchilds;
+
+  ADTreeNode3Div ();
+  void DeleteChilds ();
+  friend class ADTree3Div;
+
+  static BlockAllocator ball;
+  void * operator new(size_t);
+  void operator delete (void *);
+};
+
+
+class ADTree3Div
+{
+  ADTreeNode3Div * root;
+  float cmin[3], cmax[3];
+  ARRAY<ADTreeNode3Div*> ela;
+
+public:
+  ADTree3Div (const float * acmin, 
+	   const float * acmax);
+  ~ADTree3Div ();
+
+  void Insert (const float * p, int pi);
+  void GetIntersecting (const float * bmin, const float * bmax,
+			ARRAY<int> & pis) const;
+  
+  void DeleteElement (int pi);
+
+
+  void Print (ostream & ost) const
+    { PrintRec (ost, root); }
+
+  void PrintRec (ostream & ost, const ADTreeNode3Div * node) const;
+};
+
+
+
+
+#define ADTN_SIZE 10
+
+// multiple entries
+class ADTreeNode3M
+{
+public:
+  ADTreeNode3M *left, *right, *father;
+  float sep;
+  float data[ADTN_SIZE][3];
+  int pi[ADTN_SIZE];
+  int nchilds;
+
+  ADTreeNode3M ();
+  void DeleteChilds ();
+  friend class ADTree3M;
+
+  static BlockAllocator ball;
+  void * operator new(size_t);
+  void operator delete (void *);
+};
+
+
+class ADTree3M
+{
+  ADTreeNode3M * root;
+  float cmin[3], cmax[3];
+  ARRAY<ADTreeNode3M*> ela;
+
+public:
+  ADTree3M (const float * acmin, 
+	   const float * acmax);
+  ~ADTree3M ();
+
+  void Insert (const float * p, int pi);
+  void GetIntersecting (const float * bmin, const float * bmax,
+			ARRAY<int> & pis) const;
+  
+  void DeleteElement (int pi);
+
+
+  void Print (ostream & ost) const
+    { PrintRec (ost, root); }
+
+  void PrintRec (ostream & ost, const ADTreeNode3M * node) const;
+};
+
+
+
+
+
+
+class ADTreeNode3F
+{
+public:
+  ADTreeNode3F *father;
+  ADTreeNode3F *childs[8];
+  float sep[3];
+  float data[3];
+  int pi;
+  int nchilds;
+
+  ADTreeNode3F ();
+  void DeleteChilds ();
+  friend class ADTree3F;
+
+  static BlockAllocator ball;
+  void * operator new(size_t);
+  void operator delete (void *);
+};
+
+// fat tree
+class ADTree3F
+{
+  ADTreeNode3F * root;
+  float cmin[3], cmax[3];
+  ARRAY<ADTreeNode3F*> ela;
+
+public:
+  ADTree3F (const float * acmin, 
+	   const float * acmax);
+  ~ADTree3F ();
+
+  void Insert (const float * p, int pi);
+  void GetIntersecting (const float * bmin, const float * bmax,
+			ARRAY<int> & pis) const;
+  
+  void DeleteElement (int pi);
+
+
+  void Print (ostream & ost) const
+    { PrintRec (ost, root); }
+
+  void PrintRec (ostream & ost, const ADTreeNode3F * node) const;
+};
+
+
+
+
+class ADTreeNode3FM
+{
+public:
+  ADTreeNode3FM *father;
+  ADTreeNode3FM *childs[8];
+  float sep[3];
+  float data[ADTN_SIZE][3];
+  int pi[ADTN_SIZE];
+  int nchilds;
+
+  ADTreeNode3FM ();
+  void DeleteChilds ();
+  friend class ADTree3FM;
+
+  static BlockAllocator ball;
+  void * operator new(size_t);
+  void operator delete (void *);
+};
+
+// fat tree
+class ADTree3FM
+{
+  ADTreeNode3FM * root;
+  float cmin[3], cmax[3];
+  ARRAY<ADTreeNode3FM*> ela;
+
+public:
+  ADTree3FM (const float * acmin, 
+	   const float * acmax);
+  ~ADTree3FM ();
+
+  void Insert (const float * p, int pi);
+  void GetIntersecting (const float * bmin, const float * bmax,
+			ARRAY<int> & pis) const;
+  
+  void DeleteElement (int pi);
+
+
+  void Print (ostream & ost) const
+    { PrintRec (ost, root); }
+
+  void PrintRec (ostream & ost, const ADTreeNode3FM * node) const;
+};
+
+
+
+
+
+
+
+
+
+class ADTreeNode6
+{
+public:
+  ADTreeNode6 *left, *right, *father;
+  float sep;
+  float data[6];
+  int pi;
+  int nchilds;
+
+  ADTreeNode6 ();
+  void DeleteChilds ();
+  friend class ADTree6;
+
+  static BlockAllocator ball;
+  void * operator new(size_t);
+  void operator delete (void *);
+};
+
+
+class ADTree6
+{
+  ADTreeNode6 * root;
+  float cmin[6], cmax[6];
+  ARRAY<ADTreeNode6*> ela;
+
+public:
+  ADTree6 (const float * acmin, 
+	   const float * acmax);
+  ~ADTree6 ();
+
+  void Insert (const float * p, int pi);
+  void GetIntersecting (const float * bmin, const float * bmax,
+			ARRAY<int> & pis) const;
+  
+  void DeleteElement (int pi);
+
+  
+  void Print (ostream & ost) const
+  { PrintRec (ost, root); }
+  int Depth () const
+  { return DepthRec (root); }
+  int Elements () const
+  { return ElementsRec (root); }
+
+  void PrintRec (ostream & ost, const ADTreeNode6 * node) const;
+  int DepthRec (const ADTreeNode6 * node) const;
+  int ElementsRec (const ADTreeNode6 * node) const;
+
+  void PrintMemInfo (ostream & ost) const;
+};
+
+
+
+
+
+
+class ADTreeNode6F
+{
+public:
+  ADTreeNode6F * father;
+  ADTreeNode6F * childs[64];
+  
+  float sep[6];
+  float data[6];
+  int pi;
+  int nchilds;
+
+  ADTreeNode6F ();
+  void DeleteChilds ();
+  friend class ADTree6F;
+
+  static BlockAllocator ball;
+  void * operator new(size_t);
+  void operator delete (void *);
+};
+
+
+class ADTree6F
+{
+  ADTreeNode6F * root;
+  float cmin[6], cmax[6];
+  ARRAY<ADTreeNode6F*> ela;
+
+public:
+  ADTree6F (const float * acmin, 
+	   const float * acmax);
+  ~ADTree6F ();
+
+  void Insert (const float * p, int pi);
+  void GetIntersecting (const float * bmin, const float * bmax,
+			ARRAY<int> & pis) const;
+  
+  void DeleteElement (int pi);
+
+
+  void Print (ostream & ost) const
+    { PrintRec (ost, root); }
+  int Depth () const
+    { return DepthRec (root); }
+
+  void PrintRec (ostream & ost, const ADTreeNode6F * node) const;
+  int DepthRec (const ADTreeNode6F * node) const;
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+class Point3dTree 
+{
+  ADTree3 * tree;
+
+public:
+  Point3dTree (const Point3d & pmin, const Point3d & pmax);
+  ~Point3dTree ();
+  void Insert (const Point3d & p, int pi);
+  void DeleteElement (int pi) 
+    { tree->DeleteElement(pi); }
+  void GetIntersecting (const Point3d & pmin, const Point3d & pmax, 
+			ARRAY<int> & pis) const;
+  const ADTree3 & Tree() const { return *tree; };
+};
+
+
+
+class Box3dTree
+{
+  ADTree6 * tree;
+  Point3d boxpmin, boxpmax;
+public:
+  Box3dTree (const Point3d & apmin, const Point3d & apmax);
+  ~Box3dTree ();
+  void Insert (const Point3d & bmin, const Point3d & bmax, int pi);
+  void DeleteElement (int pi) 
+    { tree->DeleteElement(pi); }
+  void GetIntersecting (const Point3d & pmin, const Point3d & pmax, 
+			ARRAY<int> & pis) const;
+
+  const ADTree6 & Tree() const { return *tree; };
+};
+#endif
diff --git a/Netgen/libsrc/gprim/geom2d.cpp b/Netgen/libsrc/gprim/geom2d.cpp
new file mode 100644
index 0000000000..01463d0255
--- /dev/null
+++ b/Netgen/libsrc/gprim/geom2d.cpp
@@ -0,0 +1,485 @@
+#include <mystdlib.h>
+
+#include <myadt.hpp>
+#include <gprim.hpp>
+
+#ifndef M_PI
+#define M_PI        3.14159265358979323846
+#endif
+
+namespace netgen
+{
+
+ostream & operator<<(ostream  & s, const Point2d & p)
+{
+  return s << "(" << p.px << ", " << p.py << ")";
+}
+
+ostream & operator<<(ostream  & s, const Vec2d & v)
+{
+  return s << "(" << v.vx << ", " << v.vy << ")";
+}
+
+#ifdef none
+ostream & operator<<(ostream  & s, const Line2d & l)
+  {
+  return s << l.p1 << "-" << l.p2;
+}
+
+ostream & operator<<(ostream  & s, const TRIANGLE2D & t)
+{
+  return s << t.p1 << "-" << t.p2 << "-" << t.p3;
+}
+#endif
+
+
+double Fastatan2 (double x, double y)
+{
+  if (y > 0)
+    {
+      if (x > 0)
+	return y / (x+y);
+      else
+	return 1 - x / (y-x);
+    }
+  else if (y < 0)
+    {
+      if (x < 0)
+	return 2 + y / (x+y);
+      else
+	return 3 - x / (y-x);
+    }
+  else 
+    {
+      if (x >= 0)
+	return 0;
+      else
+	return 2;
+    }
+}
+
+
+double Angle (const Vec2d & v)
+{
+  if (v.X() == 0 && v.Y() == 0) return 0;
+  double ang = atan2 (v.Y(), v.X());
+  if (ang < 0) ang+= 2 * M_PI;
+  return ang;
+}
+
+double FastAngle (const Vec2d & v)
+{
+  return Fastatan2 (v.X(), v.Y());
+}
+
+double Angle (const Vec2d & v1, const Vec2d & v2)
+{
+  double ang = Angle(v2) - Angle(v1);
+  if (ang < 0) ang += 2 * M_PI;
+  return ang;
+}
+
+double FastAngle (const Vec2d & v1, const Vec2d & v2)
+{
+  double ang = FastAngle(v2) - FastAngle(v1);
+  if (ang < 0) ang += 4;
+  return ang;
+}
+
+/*
+int CW (const Point2d & p1,const Point2d & p2,const Point2d & p3)
+{
+  return Cross (p2 - p1, p3 - p2) < 0;
+}
+
+int CCW (const Point2d & p1,const Point2d & p2,const Point2d & p3)
+{
+  return Cross (p2 - p1, p3 - p2) > 0;
+}
+*/
+
+double  Dist2(const Line2d & g, const Line2d & h )
+  {
+  double   dd = 0.0, d1,d2,d3,d4;
+  Point2d  cp = CrossPoint(g,h);
+  
+  if ( Parallel(g,h) || !IsOnLine(g,cp) || !IsOnLine(h,cp) )
+    {
+      d1 = Dist2(g.P1(),h.P1());
+      d2 = Dist2(g.P1(),h.P2());
+      d3 = Dist2(g.P2(),h.P1());
+      d4 = Dist2(g.P2(),h.P2());
+      if (d1<d2)  d2 = d1;
+      if (d3<d4)  d4 = d3;
+      dd = ( d2 < d4 ) ? d2 : d4;
+    }
+  return dd;
+}
+
+
+Point2d CrossPoint (const Line2d & l1, const Line2d & l2)
+  {
+  double den = Cross (l1.Delta(), l2.Delta());
+  double num = Cross ( (l2.P1() - l1.P1()), l2.Delta());
+
+  if (den == 0) return l1.P1();
+  else
+    return l1.P1() + (num/den) * l1.Delta();
+}
+
+
+int CrossPointBarycentric (const Line2d & l1, const Line2d & l2,
+			   double & lam1, double & lam2)
+{
+  // p = l1.1 + lam1 (l1.2-l1.1) = l2.1 + lam2 (l2.2-l2.1)
+  double a11 = l1.p2.X() - l1.p1.X();
+  double a21 = l1.p2.Y() - l1.p1.Y();
+  double a12 = -(l2.p2.X() - l2.p1.X());
+  double a22 = -(l2.p2.Y() - l2.p1.Y());
+
+  double b1 = l2.p1.X() - l1.p1.X();
+  double b2 = l2.p1.Y() - l1.p1.Y();
+  
+  double det = a11*a22 - a12 * a21;
+  if (det == 0) return 1;
+
+  lam1 = (a22 * b1 - a12 * b2) / det;
+  lam2 = (a11 * b2 - a21 * b1) / det;
+  return 0;
+}
+
+
+
+
+int Parallel (const Line2d & l1, const Line2d & l2, double peps)
+  {
+  double p = fabs (Cross (l1.Delta(), l2.Delta()));
+  //  (*mycout) << endl << p << "  " <<  l1.Length() << "  " << l2.Length() << endl;
+  return p <= peps * l1.Length() * l2.Length();
+}
+
+int IsOnLine (const Line2d & l, const Point2d & p, double heps)
+  {
+  double c1 = (p - l.P1()) * l.Delta();
+  double c2 = (p - l.P2()) * l.Delta();
+  double d = fabs (Cross ( (p - l.P1()), l.Delta()));
+  double len2 = l.Length2();
+
+  return c1 >= -heps * len2 && c2 <= heps * len2 && d <= heps * len2;
+}
+
+#ifdef none
+int IsOnLine (const PLine2d & l, const Point2d & p, double heps)
+  {
+  double c1 = (p - l.P1()) * l.Delta();
+  double c2 = (p - l.P2()) * l.Delta();
+  double d = fabs (Cross ( (p - l.P1()), l.Delta()));
+  double len2 = l.Length2();
+
+  return c1 >= -heps * len2 && c2 <= heps * len2 && d <= heps * len2;
+}
+
+int IsOnLongLine (const Line2d & l, const Point2d & p)
+  {
+  double d = fabs (Cross ( (p - l.P1()), l.Delta()));
+  return d <= EPSGEOM * l.Length();
+}
+
+int Hit (const Line2d & l1, const Line2d & l2, double heps)
+  {
+  double den =  Cross ( (l1.P2() - l1.P1()), (l2.P1() - l2.P2()));
+  double num1 = Cross ( (l2.P1() - l1.P1()), (l2.P1() - l2.P2()));
+  double num2 = Cross ( (l1.P2() - l1.P1()), (l2.P1() - l1.P1()));
+  num1 *= sgn (den);
+  num2 *= sgn (den);
+  den = fabs (den);
+
+  int ch = (-den * heps <= num1 && num1 <= den * (1 + heps) &&
+	    -den * heps <= num2 && num2 <= den * (1 + heps));
+  return ch;
+}
+
+
+void Line2d :: GetNormal (Line2d & n) const
+{
+  double 	ax  = P2().X()-P1().X(),
+    ay  = P2().Y()-P1().Y();
+  Point2d 	mid(P1().X()+.5*ax, P1().Y()+.5*ay);
+ 
+ n=Line2d(mid,Point2d(mid.X()+ay,mid.Y()-ax)) ;
+}
+
+Vec2d Line2d :: NormalDelta () const
+{
+ Line2d tmp;
+ GetNormal(tmp);
+ return tmp.Delta();
+}
+
+int TRIANGLE2D :: IsOn (const Point2d & p) const
+  {
+  return IsOnLine (Line2d (p1, p2), p) ||
+         IsOnLine (Line2d (p1, p3), p) ||
+         IsOnLine (Line2d (p2, p3), p);
+  }
+
+
+int TRIANGLE2D :: IsIn (const Point2d & p) const
+{
+  return ::CW(p, p1, p2) == ::CW(p, p2, p3) &&
+         ::CW(p, p1, p2) == ::CW(p, p3, p1);
+}
+
+
+
+int PTRIANGLE2D :: IsOn (const Point2d & p) const
+{
+  return IsOnLine (Line2d (*p1, *p2), p) ||
+         IsOnLine (Line2d (*p1, *p3), p) ||
+         IsOnLine (Line2d (*p2, *p3), p);
+}
+
+
+int PTRIANGLE2D :: IsIn (const Point2d & p) const
+{
+  return ::CW(p, *p1, *p2) == ::CW(p, *p2, *p3) &&
+         ::CW(p, *p1, *p2) == ::CW(p, *p3, *p1);
+}
+
+#endif
+
+
+
+
+
+
+Polygon2d :: Polygon2d ()
+{
+  ;
+}
+
+Polygon2d :: ~Polygon2d ()
+{
+  ;
+}
+
+void Polygon2d :: AddPoint (const Point2d & p)
+{ 
+  points.Append(p); 
+}
+
+
+double Polygon2d :: HArea () const
+{
+  int i;
+  double ar = 0;
+  for (i = 1; i <= points.Size(); i++)
+    {
+      const Point2d & p1 = points.Get(i);
+      const Point2d & p2 = points.Get(i%points.Size()+1);
+      ar += 
+	(p2.X()-p1.X()) * p1.Y() -
+	(p2.Y()-p1.Y()) * p1.X();
+    }
+  return ar/2;
+  /*
+  CURSOR c;
+  double ar = 0;
+  Point2d * p1, * p2, p0 = Point2d(0, 0);
+  Vec2d v1, v2 = Vec2d(1, 0);
+
+  p2 = points[points.Last()];
+  for (c = points.First(); c != points.Head(); c++)
+    {
+    p1 = p2;
+    p2 = points[c];
+    ar += Cross ( (*p2-*p1), (*p1 - p0));
+    }
+  return ar / 2;
+  */
+}
+
+
+int Polygon2d :: IsOn (const Point2d & p) const
+{
+  int i;
+  for (i = 1; i <= points.Size(); i++)
+    {
+      const Point2d & p1 = points.Get(i);
+      const Point2d & p2 = points.Get(i%points.Size()+1);
+      if (IsOnLine (Line2d(p1, p2), p)) return 1;
+    }
+  return 0;
+  /*
+  CURSOR c;
+  Point2d * p1, * p2;
+  
+  p2 = points[points.Last()];
+  for (c = points.First(); c != points.Head(); c++)
+    {
+      p1 = p2;
+      p2 = points[c];
+      if (IsOnLine (Line2d(*p1, *p2), p)) return 1;
+    }
+  return 0;
+  */
+}
+
+
+int Polygon2d :: IsIn (const Point2d & p) const
+{
+  int i;
+  double sum = 0, ang;
+  for (i = 1; i <= points.Size(); i++)
+    {
+      const Point2d & p1 = points.Get(i);
+      const Point2d & p2 = points.Get(i%points.Size()+1);
+      ang = Angle ( (p1 - p), (p2 - p) );
+      if (ang > M_PI) ang -= 2 * M_PI;
+      sum += ang;
+    }
+  return fabs(sum) > M_PI;
+  /*
+  CURSOR c;
+  Point2d * p1, * p2;
+  double sum = 0, ang;
+
+  p2 = points[points.Last()];
+  for (c = points.First(); c != points.Head(); c++)
+    {
+    p1 = p2;
+    p2 = points[c];
+    ang = Angle ( (*p1 - p), (*p2 - p) );
+    if (ang > M_PI) ang -= 2 * M_PI;
+    sum += ang;
+    }
+
+  return fabs(sum) > M_PI;
+  */
+}
+
+int Polygon2d :: IsConvex () const
+  {
+    /*
+  Point2d *p, *pold, *pnew;
+  char cw;
+  CURSOR c;
+
+  if (points.Length() < 3) return 0;
+
+  c = points.Last();
+  p = points[c];
+  c--;
+  pold = points[c];
+  pnew = points[points.First()];
+  cw = ::CW (*pold, *p, *pnew);
+
+  for (c = points.First(); c != points.Head(); c++)
+    {
+    pnew = points[c];
+    if (cw != ::CW (*pold, *p, *pnew))
+      return 0;
+    pold = p;
+    p = pnew;
+    }
+    */
+    return 0;
+  }
+
+
+int Polygon2d :: IsStarPoint (const Point2d & p) const
+  {
+    /*
+  Point2d *pnew, *pold;
+  char cw;
+  CURSOR c;
+
+  if (points.Length() < 3) return 0;
+
+  pold = points[points.Last()];
+  pnew = points[points.First()];
+
+  cw = ::CW (p, *pold, *pnew);
+
+  for (c = points.First(); c != points.Head(); c++)
+    {
+    pnew = points[c];
+    if (cw != ::CW (p, *pold, *pnew))
+      return 0;
+    pold = pnew;
+    }
+  return 1;
+    */
+    return 0;
+  }
+
+
+Point2d Polygon2d :: Center () const
+  {
+    /*
+  double ai, a = 0, x = 0, y = 0;
+  Point2d * p, *p2;
+  Point2d p0 = Point2d(0, 0);
+  CURSOR c;
+
+  p2 = points[points.Last()];
+
+  for (c = points.First(); c != points.Head(); c++)
+    {
+    p = points[c];
+    ai = Cross (*p2 - p0, *p - p0);
+    x += ai / 3 * (p2->X() + p->X());
+    y += ai / 3 * (p2->Y() + p->Y());
+    a+= ai;
+    p2 = p;
+    }
+  if (a != 0)
+    return Point2d (x / a, y / a);
+  else
+    return Point2d (0, 0);
+    */
+    return Point2d (0, 0);
+  }
+
+
+
+Point2d Polygon2d :: EqualAreaPoint () const
+  {
+    /*
+  double a11 = 0, a12 = 0, a21= 0, a22 = 0;
+  double b1 = 0, b2 = 0, dx, dy;
+  double det;
+  Point2d * p, *p2;
+  CURSOR c;
+
+  p = points[points.Last()];
+
+  for (c = points.First(); c != points.Head(); c++)
+    {
+    p2 = p;
+    p = points[c];
+
+    dx = p->X() - p2->X();
+    dy = p->Y() - p2->Y();
+
+    a11 += sqr (dy);
+    a12 -= dx * dy;
+    a21 -= dx * dy;
+    a22 += sqr (dx);
+    b1 -= dy * (p->X() * p2->Y() - p2->X() * p->Y());
+    b2 -= dx * (p->Y() * p2->X() - p2->Y() * p->X());
+    }
+
+  det = a11 * a22 - a21 * a12;
+
+  if (det != 0)
+    return Point2d ( (b1 * a22 - b2 * a12) / det,
+                     (a11 * b2 - a21 * b1) / det);
+  else
+    return Point2d (0, 0);
+*/
+    return Point2d (0, 0);
+  }
+
+
+}
diff --git a/Netgen/libsrc/gprim/geom2d.hpp b/Netgen/libsrc/gprim/geom2d.hpp
new file mode 100644
index 0000000000..48b5eda71d
--- /dev/null
+++ b/Netgen/libsrc/gprim/geom2d.hpp
@@ -0,0 +1,870 @@
+#ifndef FILE_GEOM2D
+#define FILE_GEOM2D
+
+/* *************************************************************************/
+/* File:   geom2d.hh                                                       */
+/* Author: Joachim Schoeberl                                               */
+/* Date:   5. Aug. 95                                                      */
+/* *************************************************************************/
+
+
+
+/* Geometric Algorithms */
+
+#define EPSGEOM 1E-5
+
+
+// extern void MyError (const char * ch);
+
+class Point2d;
+class Vec2d;
+
+class LINE2D;
+class Line2d;
+class PLine2d;
+class TRIANGLE2D;
+class PTRIANGLE2D;
+
+
+inline Vec2d operator- (const Point2d & p1, const Point2d & p2);
+inline Point2d operator- (const Point2d & p1, const Vec2d & v);
+inline Point2d operator+ (const Point2d & p1, const Vec2d & v);
+inline Point2d Center (const Point2d & p1, const Point2d & p2);
+
+inline void PpSmV (const Point2d & p1, double s, const Vec2d & v, Point2d & p2);
+inline void PmP (const Point2d & p1, const Point2d & p2, Vec2d & v);
+ostream & operator<<(ostream  & s, const Point2d & p);
+inline Vec2d operator- (const Point2d & p1, const Point2d & p2);
+inline Point2d operator- (const Point2d & p1, const Vec2d & v);
+inline Point2d operator+ (const Point2d & p1, const Vec2d & v);
+inline Vec2d operator- (const Vec2d & p1, const Vec2d & v);
+inline Vec2d operator+ (const Vec2d & p1, const Vec2d & v);
+inline Vec2d operator* (double scal, const Vec2d & v);
+double Angle (const Vec2d & v);
+double FastAngle (const Vec2d & v);
+double Angle (const Vec2d & v1, const Vec2d & v2);
+double FastAngle (const Vec2d & v1, const Vec2d & v2);
+ostream & operator<<(ostream  & s, const Vec2d & v);
+double Dist2(const Line2d & g, const Line2d & h );		// GH
+int Near (const Point2d & p1, const Point2d & p2, const double eps);
+
+int Parallel (const Line2d & l1, const Line2d & l2, double peps = EPSGEOM);
+int IsOnLine (const Line2d & l, const Point2d & p, double heps = EPSGEOM);
+int IsOnLongLine (const Line2d & l, const Point2d & p);
+int Hit (const Line2d & l1, const Line2d & l2, double heps = EPSGEOM);
+ostream & operator<<(ostream  & s, const Line2d & l);
+Point2d CrossPoint (const PLine2d & l1, const PLine2d & l2);
+int Parallel (const PLine2d & l1, const PLine2d & l2, double peps = EPSGEOM);
+int IsOnLine (const PLine2d & l, const Point2d & p, double heps = EPSGEOM);
+int IsOnLongLine (const PLine2d & l, const Point2d & p);
+int Hit (const PLine2d & l1, const Line2d & l2, double heps = EPSGEOM);
+ostream & operator<<(ostream  & s, const Line2d & l);
+ostream & operator<<(ostream  & s, const TRIANGLE2D & t); 
+ostream & operator<<(ostream & s, const PTRIANGLE2D & t);
+
+///
+class Point2d
+{
+  ///
+  friend class Vec2d;
+
+protected:
+  ///
+  double px, py;
+
+public:
+  ///
+  Point2d() { /* px = py = 0; */ }
+  ///
+  Point2d(double ax, double ay) { px = ax; py = ay; }
+  ///
+  Point2d(const Point2d & p2) { px = p2.px; py = p2.py; }
+
+  Point2d (const Point<2> & p2)
+  {
+    px = p2(0);
+    py = p2(1);
+  }
+  ///
+  Point2d & operator= (const Point2d & p2)
+    { px = p2.px; py = p2.py; return *this; }
+    
+  ///
+  int operator== (const Point2d & p2) const			// GH
+    { return (px == p2.px  &&  py == p2.py) ; }
+
+  ///
+  double & X() { return px; }
+  ///
+  double & Y() { return py; }
+  ///
+  double X() const { return px; }
+  ///
+  double Y() const { return py; }
+
+  operator Point<2> () const
+  {
+    return Point<2> (px, py);
+  }
+
+
+  ///
+  friend inline Vec2d operator- (const Point2d & p1, const Point2d & p2);
+  ///
+  friend inline Point2d operator- (const Point2d & p1, const Vec2d & v);
+  ///
+  friend inline Point2d operator+ (const Point2d & p1, const Vec2d & v);
+
+  ///
+  friend inline Point2d Center (const Point2d & p1, const Point2d & p2);
+
+  const Point2d & SetToMin (const Point2d & p2)
+    {
+      if (p2.px < px) px = p2.px;
+      if (p2.py < py) py = p2.py;
+      return *this;
+    }
+
+
+  ///
+  const Point2d & SetToMax (const Point2d & p2)
+    {
+      if (p2.px > px) px = p2.px;
+      if (p2.py > py) py = p2.py;
+      return *this;
+    }
+
+  ///
+  friend double Dist (const Point2d & p1, const Point2d & p2)
+    { return sqrt ( (p1.px - p2.px) * (p1.px - p2.px) +
+		    (p1.py - p2.py) * (p1.py - p2.py) ); }
+  //    { return sqrt ( sqr (p1.X()-p2.X()) + sqr (p1.Y()-p2.Y()) ); }
+
+  ///
+  friend double Dist2 (const Point2d & p1, const Point2d & p2)
+    { return ( (p1.px - p2.px) * (p1.px - p2.px) +
+	       (p1.py - p2.py) * (p1.py - p2.py) ); }
+  //    { return sqr (p1.X()-p2.X()) + sqr (p1.Y()-p2.Y()) ; }
+
+
+  /**
+    Points clock-wise ?
+    Are the points (p1, p2, p3) clock-wise ?
+    */
+  friend inline int CW (const Point2d & p1, const Point2d & p2, const Point2d & p3)
+    {
+      //      return Cross (p2 - p1, p3 - p2) < 0;      
+      return
+	(p2.px - p1.px) * (p3.py - p2.py) - 
+	(p2.py - p1.py) * (p3.px - p2.px) < 0;
+    }
+  /**
+    Points counter-clock-wise ?
+    Are the points (p1, p2, p3) counter-clock-wise ?
+    */
+  friend inline int CCW (const Point2d & p1, const Point2d & p2, const Point2d & p3)
+    {
+      //      return Cross (p2 - p1, p3 - p2) > 0;
+      return
+	(p2.px - p1.px) * (p3.py - p2.py) - 
+	(p2.py - p1.py) * (p3.px - p2.px) > 0;
+    }
+
+  ///
+  friend inline void PpSmV (const Point2d & p1, double s, const Vec2d & v, Point2d & p2);
+  ///
+  friend inline void PmP (const Point2d & p1, const Point2d & p2, Vec2d & v);
+
+  ///
+  friend ostream & operator<<(ostream  & s, const Point2d & p);
+};
+
+
+inline int Near (const Point2d & p1, const Point2d & p2, 
+	  const double eps = 1e-4 )
+{ 
+  return  Dist2(p1,p2) <= eps*eps; 
+}
+
+
+
+
+
+
+///
+class Vec2d
+  {
+protected:
+  ///
+  double vx, vy;
+
+public:
+  ///
+    Vec2d() { /* vx = vy = 0; */ }
+    ///
+    Vec2d(double ax, double ay)
+    { vx = ax; vy = ay; }
+    ///
+    Vec2d(const Vec2d & v2) { vx = v2.vx; vy = v2.vy; }
+
+    ///
+    explicit Vec2d(const Vec<2> & v2) { vx = v2(0); vy = v2(1); }
+
+    ///
+    Vec2d(const Point2d & p1, const Point2d & p2)
+    { vx = p2.px - p1.px; vy = p2.py - p1.py; }
+    
+  ///
+  Vec2d & operator= (const Vec2d & p2)
+    { vx = p2.vx; vy = p2.vy; return *this; }
+
+  ///
+  double & X() { return vx; }
+  ///
+  double & Y() { return vy; }
+  ///
+  double X() const { return vx; }
+  ///
+  double Y() const { return vy; }
+
+  ///
+  double Length() const { return sqrt (vx * vx + vy * vy); }
+  ///
+  double Length2() const { return vx * vx + vy * vy; }
+
+  void GetNormal (Vec2d & n) const { n.vx=-vy; n.vy=vx; }		// GH
+
+  ///
+  inline Vec2d & operator+= (const Vec2d & v2);
+  ///
+  inline Vec2d & operator-= (const Vec2d & v2);
+  ///
+  inline Vec2d & operator*= (double s);
+  ///
+  inline Vec2d & operator/= (double s);
+
+  ///
+  friend inline Vec2d operator- (const Point2d & p1, const Point2d & p2);
+  ///
+  friend inline Point2d operator- (const Point2d & p1, const Vec2d & v);
+  ///
+  friend inline Point2d operator+ (const Point2d & p1, const Vec2d & v);
+  ///
+  friend inline Vec2d operator- (const Vec2d & p1, const Vec2d & v);
+  ///
+  friend inline Vec2d operator+ (const Vec2d & p1, const Vec2d & v);
+  ///
+  friend inline Vec2d operator* (double scal, const Vec2d & v);
+
+  ///
+  friend double operator* (const Vec2d & v1, const Vec2d & v2)
+    { return v1.X() * v2.X() + v1.Y() * v2.Y(); }
+
+
+  ///
+  friend double Cross (const Vec2d & v1, const Vec2d & v2)
+    { return double(v1.X()) * double(v2.Y()) -
+             double(v1.Y()) * double(v2.X()); }
+
+  ///
+  friend inline void PpSmV (const Point2d & p1, double s, const Vec2d & v, Point2d & p2);
+  ///
+  friend inline void PmP (const Point2d & p1, const Point2d & p2, Vec2d & v);
+
+///						Angle in [0,2*PI)
+
+  ///
+  friend double Angle (const Vec2d & v);
+  ///
+  friend double FastAngle (const Vec2d & v);
+  ///
+  friend double Angle (const Vec2d & v1, const Vec2d & v2);
+  ///
+  friend double FastAngle (const Vec2d & v1, const Vec2d & v2);
+
+  ///
+  friend ostream & operator<<(ostream  & s, const Vec2d & v);
+  };
+
+
+
+///
+class Line2d
+  {
+protected:
+  ///
+  Point2d p1, p2;
+
+public:
+  ///
+  Line2d() : p1(), p2() { };
+  ///
+  Line2d(const Point2d & ap1, const Point2d & ap2)
+    { p1 = ap1; p2 = ap2; }
+
+  ///
+  Line2d & operator= (const Line2d & l2)
+    { p1 = l2.p1; p2 = l2.p2; return *this;}
+
+  ///
+  Point2d & P1() { return p1; }
+  ///
+  Point2d & P2() { return p2; }
+  ///
+  const Point2d & P1() const { return p1; }
+  ///
+  const Point2d & P2() const { return p2; }
+
+  ///
+  double XMax() const { return max2 (p1.X(), p2.X()); }
+  ///
+  double YMax() const { return max2 (p1.Y(), p2.Y()); }
+  ///
+  double XMin() const { return min2 (p1.X(), p2.X()); }
+  ///
+  double YMin() const { return min2 (p1.Y(), p2.Y()); }
+
+  ///
+  Vec2d Delta () const { return Vec2d (p2.X()-p1.X(), p2.Y()-p1.Y()); }
+  ///
+  double Length () const { return Delta().Length(); }
+  ///
+  double Length2 () const
+        { return sqr (p1.X() - p2.X()) +
+                 sqr (p1.Y() - p2.Y()); }
+
+  void GetNormal (Line2d & n) const;					// GH
+  Vec2d NormalDelta () const;						// GH
+
+  /// square of the distance between two 2d-lines.
+  friend double Dist2(const Line2d & g, const Line2d & h );		// GH
+
+  ///
+  friend Point2d CrossPoint (const Line2d & l1, const Line2d & l2);
+    /// returns 1 iff parallel
+    friend int CrossPointBarycentric (const Line2d & l1, const Line2d & l2,
+				      double & lam1, double & lam2);
+
+  ///
+  friend int Parallel (const Line2d & l1, const Line2d & l2, double peps);
+  ///
+  friend int IsOnLine (const Line2d & l, const Point2d & p, double heps);
+  ///
+  friend int IsOnLongLine (const Line2d & l, const Point2d & p);
+  ///
+  friend int Hit (const Line2d & l1, const Line2d & l2, double heps);
+
+  ///
+  friend ostream & operator<<(ostream  & s, const Line2d & l);
+  };
+
+
+#ifdef NONE
+///
+class PLine2d
+  {
+protected:
+  ///
+  Point2d const * p1, *p2;
+
+public:
+  ///
+  PLine2d() { };
+  ///
+  PLine2d(Point2d const * ap1, Point2d const * ap2)
+    { p1 = ap1; p2 = ap2; }
+
+  ///
+  PLine2d & operator= (const PLine2d & l2)
+    { p1 = l2.p1; p2 = l2.p2; return *this;}
+
+  ///
+  const Point2d *& P1() { return p1; }
+  ///
+  const Point2d *& P2() { return p2; }
+  ///
+  const Point2d & P1() const { return *p1; }
+  ///
+  const Point2d & P2() const { return *p2; }
+
+  ///
+  double XMax() const { return max2 (p1->X(), p2->X()); }
+  ///
+  double YMax() const { return max2 (p1->Y(), p2->Y()); }
+  ///
+  double XMin() const { return min2 (p1->X(), p2->X()); }
+  ///
+  double YMin() const { return min2 (p1->Y(), p2->Y()); }
+
+
+  ///
+  Vec2d Delta () const { return Vec2d (p2->X()-p1->X(), p2->Y()-p1->Y()); }
+  ///
+  double Length () const { return Delta().Length(); }
+  ///
+  double Length2 () const
+        { return sqr (p1->X() - p2->X()) +
+                 sqr (p1->Y() - p2->Y()); }
+
+
+    
+  ///
+  friend Point2d CrossPoint (const PLine2d & l1, const PLine2d & l2);
+  ///
+  friend int Parallel (const PLine2d & l1, const PLine2d & l2, double peps);
+  ///
+  friend int IsOnLine (const PLine2d & l, const Point2d & p, double heps);
+  ///
+  friend int IsOnLongLine (const PLine2d & l, const Point2d & p);
+  ///
+  friend int Hit (const PLine2d & l1, const Line2d & l2, double heps);
+
+  ///
+  friend ostream & operator<<(ostream  & s, const Line2d & l);
+  };
+
+
+
+///
+class ILINE
+  {
+  ///
+  INDEX i[2];
+
+  public:
+  ///
+  ILINE() {};
+  ///
+  ILINE(INDEX i1, INDEX i2) { i[0] = i1; i[1] = i2; }
+  ///
+  ILINE(const ILINE & l) { i[0] = l.i[0]; i[1] = l.i[1]; }
+
+  ///
+  ILINE & operator= (const ILINE & l)
+    { i[0] = l.i[0]; i[1] = l.i[1]; return *this; }
+
+  ///
+  const INDEX & I(int ai) const { return i[ai-1]; }
+  ///
+  const INDEX & X() const { return i[0]; }
+  ///
+  const INDEX & Y() const { return i[1]; }
+  ///
+  const INDEX & I1() const { return i[0]; }
+  ///
+  const INDEX & I2() const { return i[1]; }
+
+  ///
+  INDEX & I(int ai) { return i[ai-1]; }
+  ///
+  INDEX & X() { return i[0]; }
+  ///
+  INDEX & Y() { return i[1]; }
+  ///
+  INDEX & I1() { return i[0]; }
+  ///
+  INDEX & I2() { return i[1]; }
+  };
+
+
+
+
+///
+class TRIANGLE2D
+  {
+private:
+  ///
+  Point2d p1, p2, p3;
+
+public:
+  ///
+  TRIANGLE2D() { };
+  ///
+  TRIANGLE2D (const Point2d & ap1, const Point2d & ap2,
+              const Point2d & ap3)
+    { p1 = ap1; p2 = ap2; p3 = ap3;}
+
+  ///
+  TRIANGLE2D & operator= (const TRIANGLE2D & t2)
+    { p1 = t2.p1; p2 = t2.p2; p3 = t2.p3; return *this; }
+
+  ///
+  Point2d & P1() { return p1; }
+  ///
+  Point2d & P2() { return p2; }
+  ///
+  Point2d & P3() { return p3; }
+  ///
+  const Point2d & P1() const { return p1; }
+  ///
+  const Point2d & P2() const { return p2; }
+  ///
+  const Point2d & P3() const { return p3; }
+
+  ///
+  double XMax() const { return max3 (p1.X(), p2.X(), p3.X()); }
+  ///
+  double YMax() const { return max3 (p1.Y(), p2.Y(), p3.Y()); }
+  ///
+  double XMin() const { return min3 (p1.X(), p2.X(), p3.X()); }
+  ///
+  double YMin() const { return min3 (p1.Y(), p2.Y(), p3.Y()); }
+
+  ///
+  inline Point2d Center () const
+   { return Point2d( (p1.X()+p2.X()+p3.X())/3, (p1.Y()+p2.Y()+p3.Y())/3); }
+
+  ///
+  int Regular() const;
+  /// 
+  int CW () const;
+  ///
+  int CCW () const;
+
+  ///
+  int IsOn (const Point2d & p) const;
+  ///
+  int IsIn (const Point2d & p) const;
+  ///
+  friend ostream & operator<<(ostream  & s, const TRIANGLE2D & t);
+  };
+
+
+///
+class PTRIANGLE2D
+  {
+private:
+  ///
+  Point2d const *p1, *p2, *p3;
+
+public:
+  ///
+  PTRIANGLE2D() { };
+  ///
+  PTRIANGLE2D (const Point2d * ap1, const Point2d * ap2,
+              const Point2d * ap3)
+    { p1 = ap1; p2 = ap2; p3 = ap3;}
+
+  ///
+  PTRIANGLE2D & operator= (const PTRIANGLE2D & t2)
+    { p1 = t2.p1; p2 = t2.p2; p3 = t2.p3; return *this; }
+
+  ///
+  const Point2d *& P1() { return p1; }
+  ///
+  const Point2d *& P2() { return p2; }
+  ///
+  const Point2d *& P3() { return p3; }
+  ///
+  const Point2d * P1() const { return p1; }
+  ///
+  const Point2d * P2() const { return p2; }
+  ///
+  const Point2d * P3() const { return p3; }
+
+  ///
+  double XMax() const { return max3 (p1->X(), p2->X(), p3->X()); }
+  ///
+  double YMax() const { return max3 (p1->Y(), p2->Y(), p3->Y()); }
+  ///
+  double XMin() const { return min3 (p1->X(), p2->X(), p3->X()); }
+  ///
+  double YMin() const { return min3 (p1->Y(), p2->Y(), p3->Y()); }
+
+  ///
+  Point2d Center () const
+   { return Point2d( (p1->X()+p2->X()+p3->X())/3, (p1->Y()+p2->Y()+p3->Y())/3); }
+
+
+  ///
+  int Regular() const;
+  ///
+  int CW () const;
+  ///
+  int CCW () const;
+
+  ///
+  int IsOn (const Point2d & p) const;
+  ///
+  int IsIn (const Point2d & p) const;
+  ///
+  friend ostream & operator<<(ostream & s, const PTRIANGLE2D & t);
+  };
+#endif
+
+
+
+class Polygon2d
+{
+protected:
+  ARRAY<Point2d> points;
+  
+public:
+  Polygon2d ();
+  ~Polygon2d ();
+  
+  void AddPoint (const Point2d & p);
+  int GetNP() const { return points.Size(); }
+  void GetPoint (int i, Point2d & p) const
+  { p = points.Get(i); }
+  void GetLine (int i, Point2d & p1, Point2d & p2) const
+  { p1 = points.Get(i); p2 = points.Get(i%points.Size()+1); }
+
+  double Area () const { return fabs (HArea()); }
+  int CW () const { return HArea() > 0; }
+  int CCW () const { return HArea() < 0; }
+  
+  int IsOn (const Point2d & p) const;
+  int IsIn (const Point2d & p) const;
+
+  int IsConvex () const;
+
+  int IsStarPoint (const Point2d & p) const;
+  Point2d Center() const;
+  Point2d EqualAreaPoint () const;
+private:
+  double HArea () const;
+};
+
+
+/** Cheap approximation to atan2.
+  A monotone function of atan2(x,y) is computed.
+ */
+extern double Fastatan2 (double x, double y);
+
+
+inline Vec2d & Vec2d :: operator+= (const Vec2d & v2)
+  {
+  vx += v2.vx;
+  vy += v2.vy;
+  return *this;
+  }
+
+inline Vec2d & Vec2d :: operator-= (const Vec2d & v2)
+  {
+  vx -= v2.vx;
+  vy -= v2.vy;
+  return *this;
+  }
+
+inline Vec2d & Vec2d :: operator*= (double s)
+  {
+  vx *= s;
+  vy *= s;
+  return *this;
+  }
+
+
+inline Vec2d & Vec2d :: operator/= (double s)
+{
+  if (s != 0)
+    {
+      vx /= s;
+      vy /= s;
+    }
+  else
+    {
+      MyError ("Vec2d::operator /=: Division by zero");
+    }
+  return *this;
+}
+
+
+
+inline Vec2d operator- (const Point2d & p1, const Point2d & p2)
+  {
+  return Vec2d (p1.X() - p2.X(), p1.Y() - p2.Y());
+  }
+
+
+inline Point2d operator- (const Point2d & p1, const Vec2d & v)
+  {
+  return Point2d (p1.X() - v.X(), p1.Y() - v.Y());
+  }
+
+
+inline Point2d operator+ (const Point2d & p1, const Vec2d & v)
+  {
+  return Point2d (p1.X() + v.X(), p1.Y() + v.Y());
+  }
+
+
+inline Point2d Center (const Point2d & p1, const Point2d & p2)
+  {
+  return Point2d ((p1.X() + p2.X()) / 2, (p1.Y() + p2.Y()) / 2);
+  }
+
+
+inline Vec2d operator- (const Vec2d & v1, const Vec2d & v2)
+  {
+  return Vec2d (v1.X() - v2.X(), v1.Y() - v2.Y());
+  }
+
+
+inline Vec2d operator+ (const Vec2d & v1, const Vec2d & v2)
+  {
+  return Vec2d (v1.X() + v2.X(), v1.Y() + v2.Y());
+  }
+
+
+inline Vec2d operator* (double scal, const Vec2d & v)
+  {
+  return Vec2d (scal * v.X(), scal * v.Y());
+  }
+
+
+inline void PpSmV (const Point2d & p1, double s,
+                   const Vec2d & v, Point2d & p2)
+  {
+  p2.X() = p1.X() + s * v.X();
+  p2.Y() = p1.Y() + s * v.Y();
+  }
+
+
+inline void PmP (const Point2d & p1, const Point2d & p2, Vec2d & v)
+  {
+  v.X() = p1.X() - p2.X();
+  v.Y() = p1.Y() - p2.Y();
+  }
+
+
+
+
+
+#ifdef none
+inline int TRIANGLE2D :: Regular() const
+    {
+    return fabs(Cross ( p2 - p1, p3 - p2)) > EPSGEOM;
+    }
+
+
+inline int TRIANGLE2D :: CW () const
+    {
+    return Cross ( p2 - p1, p3 - p2) < 0;
+    }
+
+
+inline int TRIANGLE2D :: CCW () const
+    {
+    return Cross ( p2 - p1, p3 - p2) > 0;
+    }
+
+
+
+
+inline int PTRIANGLE2D :: Regular() const
+    {
+    return fabs(Cross ( *p2 - *p1, *p3 - *p2)) > EPSGEOM;
+    }
+
+
+inline int PTRIANGLE2D :: CW () const
+    {
+    return Cross ( *p2 - *p1, *p3 - *p2) < 0;
+    }
+
+
+inline int PTRIANGLE2D :: CCW () const
+    {
+    return Cross ( *p2 - *p1, *p3 - *p2) > 0;
+    }
+
+
+#endif
+
+
+///
+class Mat2d
+{
+protected:
+  ///
+  double coeff[4];
+
+public:
+  ///
+  Mat2d() { coeff[0] = coeff[1] = coeff[2] = coeff[3] = 0; }
+  ///
+  Mat2d(double a11, double a12, double a21, double a22)
+    { coeff[0] = a11; coeff[1] = a12; coeff[2] = a21; coeff[3] = a22; }
+  ///
+  Mat2d(const Mat2d & m2)
+    { for (int i = 0; i < 4; i++) coeff[i] = m2.Get(i); }
+
+  ///
+  double & Elem (INDEX i, INDEX j) { return coeff[2*(i-1)+j-1]; }
+  ///
+  double & Elem (INDEX i) {return coeff[i]; }
+  ///
+  double Get (INDEX i, INDEX j) const { return coeff[2*(i-1)+j-1]; }
+  ///
+  double Get (INDEX i) const {return coeff[i]; }
+
+  ///  
+  double Det () const { return coeff[0] * coeff[3] - coeff[1] * coeff[2]; }
+
+  ///
+  void Mult (const Vec2d & v, Vec2d & prod) const;
+  ///
+  void MultTrans (const Vec2d & v , Vec2d & prod) const;
+  ///
+  void Solve (const Vec2d & rhs, Vec2d & x) const;
+  /// Solves mat * x = rhs, but using a positive definite matrix instead of mat
+  void SolvePositiveDefinite (const Vec2d & rhs, Vec2d & x) const;
+  /// add a term \alpha * v * v^T
+  void AddDiadicProduct (double alpha, Vec2d & v);
+};
+
+
+
+inline void Mat2d :: Mult (const Vec2d & v, Vec2d & prod) const
+{
+  prod.X() = coeff[0] * v.X() + coeff[1] * v.Y();
+  prod.Y() = coeff[2] * v.X() + coeff[3] * v.Y();
+}
+
+
+inline  void Mat2d :: MultTrans (const Vec2d & v, Vec2d & prod) const
+{
+  prod.X() = coeff[0] * v.X() + coeff[2] * v.Y();
+  prod.Y() = coeff[1] * v.X() + coeff[3] * v.Y();
+}
+
+
+
+inline void Mat2d :: Solve (const Vec2d & rhs, Vec2d & x) const
+{
+  double det = Det();
+  
+  if (det == 0)
+    MyError ("Mat2d::Solve: zero determinant");
+  else
+    {
+      x.X() = (coeff[3] * rhs.X() - coeff[1] * rhs.Y()) / det;
+      x.Y() = (-coeff[2] * rhs.X() + coeff[0] * rhs.Y()) / det;
+    }
+}
+
+
+inline void Mat2d :: SolvePositiveDefinite (const Vec2d & rhs, Vec2d & x) const
+{
+  double a = max2(coeff[0], 1e-8);
+  double b = coeff[1] / a;
+  double c = coeff[2] / a;
+  double d = max2(coeff[3] - a *b * c, 1e-8);
+
+  x.X() = (rhs.X() - b * rhs.Y()) / a;
+  x.Y() = rhs.Y() / d - c * x.X();
+}
+
+
+inline void Mat2d :: AddDiadicProduct (double alpha, Vec2d & v)
+{
+  coeff[0] += alpha * v.X() * v.X();
+  coeff[1] += alpha * v.X() * v.Y();
+  coeff[2] += alpha * v.Y() * v.X();
+  coeff[3] += alpha * v.Y() * v.Y();
+}
+
+
+
+#endif
diff --git a/Netgen/libsrc/gprim/geom3d.cpp b/Netgen/libsrc/gprim/geom3d.cpp
new file mode 100644
index 0000000000..b243e62c3a
--- /dev/null
+++ b/Netgen/libsrc/gprim/geom3d.cpp
@@ -0,0 +1,640 @@
+#include <mystdlib.h>
+
+#include <myadt.hpp>
+#include <gprim.hpp>
+
+namespace netgen
+{
+ostream & operator<<(ostream  & s, const Point3d & p)
+  {
+  return s << "(" << p.x[0] << ", " << p.x[1] << ", " << p.x[2] << ")";
+  }
+
+ostream & operator<<(ostream  & s, const Vec3d & v)
+  {
+  return s << "(" << v.x[0] << ", " << v.x[1] << ", " << v.x[2] << ")";
+  }
+
+double Angle (const Vec3d & v1, const Vec3d & v2)
+{
+  double co = (v1 * v2) / (v1.Length() * v2.Length());
+  if (co > 1) co = 1;
+  if (co < -1) co = -1;
+  return acos ( co );
+}
+
+
+void Vec3d :: GetNormal (Vec3d & n) const
+  {
+  if (fabs (X()) > fabs (Z()))
+    {
+    n.X() = -Y();
+    n.Y() = X();
+    n.Z() = 0;
+    }
+  else
+    {
+    n.X() = 0;
+    n.Y() = Z();
+    n.Z() = -Y();
+    }
+  double len = n.Length();
+  if (len == 0)
+    {
+    n.X() = 1;
+    n.Y() = n.Z() = 0;
+    }
+  else
+    n /= len;
+  }
+
+/*
+ostream & operator<<(ostream  & s, const ROTDenseMatrix3D & r)
+  {
+  return s << "{ (" << r.txx << ", " << r.txy << ", " << r.txz << ") , ("
+                    << r.tyx << ", " << r.tyy << ", " << r.tyz << ") , ("
+                    << r.tzx << ", " << r.tzy << ", " << r.tzz << ") }";
+  }
+*/
+
+/*
+Vec3d operator- (const Point3d & p1, const Point3d & p2)
+  {
+  return Vec3d (p1.X() - p2.X(), p1.Y() - p2.Y(),p1.Z() - p2.Z());
+  }
+
+Point3d operator- (const Point3d & p1, const Vec3d & v)
+  {
+  return Point3d (p1.X() - v.X(), p1.Y() - v.Y(),p1.Z() - v.Z());
+  }
+
+Point3d operator+ (const Point3d & p1, const Vec3d & v)
+  {
+  return Point3d (p1.X() + v.X(), p1.Y() + v.Y(),p1.Z() + v.Z());
+  }
+
+Vec3d operator- (const Vec3d & v1, const Vec3d & v2)
+  {
+  return Vec3d (v1.X() - v2.X(), v1.Y() - v2.Y(),v1.Z() - v2.Z());
+  }
+
+Vec3d operator+ (const Vec3d & v1, const Vec3d & v2)
+  {
+  return Vec3d (v1.X() + v2.X(), v1.Y() + v2.Y(),v1.Z() + v2.Z());
+  }
+
+Vec3d operator* (double scal, const Vec3d & v)
+  {
+  return Vec3d (scal * v.X(), scal * v.Y(), scal * v.Z());
+  }
+*/
+/*
+double operator* (const Vec3d & v1, const Vec3d & v2)
+  {
+  return v1.X() * v2.X() + v1.Y() * v2.Y() + v1.Z() * v2.Z();
+  }
+
+double Cross (const Vec3d & v1, const Vec3d & v2)
+  {
+  return v1.X() * v2.Y() - v1.Y() * v2.X();
+  }
+*/
+
+/*
+void ROTDenseMatrix3D :: CalcRotMat(double ag, double bg, double lg, double size2, Vec3d r)
+  {
+  size = size2;
+  txx=size * ( cos(bg) * cos(lg) );
+  txy=size * ( cos(bg) * sin(lg) );
+  txz=size * (-sin(bg)           );
+
+  tyx=size * ( sin(ag) * sin(bg) * cos(lg) - cos(ag) * sin(lg) );
+  tyy=size * ( sin(ag) * sin(bg) * sin(lg) + cos(ag) * cos(lg) );
+  tyz=size * ( sin(ag) * cos(bg)                               );
+
+  tzx=size * ( cos(ag) * sin(bg) * cos(lg) + sin(ag) * sin(lg) );
+  tzy=size * ( cos(ag) * sin(bg) * sin(lg) - sin(ag) * cos(lg) );
+  tzz=size * ( cos(ag) * cos(bg)                               );
+
+  deltaR=r;
+  }
+ROTDenseMatrix3D :: ROTDenseMatrix3D(double ag, double bg, double lg, double size2, Vec3d r)
+  {CalcRotMat(ag, bg, lg, size2, r); }
+
+ROTDenseMatrix3D :: ROTDenseMatrix3D(Vec3d rot2)
+  {
+  Vec3d r2(0,0,0);
+  CalcRotMat(rot2.X(), rot2.Y(), rot2.Z(), 1, r2);
+  }
+
+ROTDenseMatrix3D ROTDenseMatrix3D :: INV()
+  {
+  ROTDenseMatrix3D rinv(txx/sqr(size),tyx/sqr(size),tzx/sqr(size),
+                   txy/sqr(size),tyy/sqr(size),tzy/sqr(size),
+                   txz/sqr(size),tyz/sqr(size),tzz/sqr(size),
+                   1/size,deltaR);
+  return rinv;
+  }
+
+Vec3d operator* (const ROTDenseMatrix3D & r, const Vec3d & v)
+  {
+  return Vec3d (r.XX() * v.X() + r.XY() * v.Y() + r.XZ() * v.Z(),
+                r.YX() * v.X() + r.YY() * v.Y() + r.YZ() * v.Z(),
+                r.ZX() * v.X() + r.ZY() * v.Y() + r.ZZ() * v.Z() );
+  }
+
+Point3d operator* (const ROTDenseMatrix3D & r, const Point3d & p)
+  {
+  return Point3d (r.XX() * p.X() + r.XY() * p.Y() + r.XZ() * p.Z(),
+                  r.YX() * p.X() + r.YY() * p.Y() + r.YZ() * p.Z(),
+                  r.ZX() * p.X() + r.ZY() * p.Y() + r.ZZ() * p.Z() );
+  }
+*/
+
+
+
+
+
+
+
+Box3d :: Box3d ( double aminx, double amaxx,
+                 double aminy, double amaxy,
+                 double aminz, double amaxz )
+{
+  minx[0] = aminx; maxx[0] = amaxx;
+  minx[1] = aminy; maxx[1] = amaxy;
+  minx[2] = aminz; maxx[2] = amaxz;
+}
+
+Box3d :: Box3d ( const Box3d & b2 )
+{
+  for (int i = 0; i < 3; i++)
+    {
+      minx[i] = b2.minx[i];
+      maxx[i] = b2.maxx[i];
+    }
+}
+
+
+/*
+int Box3d :: Intersect (const Box3d & box2) const
+{
+  int i;
+  for (i = 0; i <= 2; i++)
+    if (minx[i] > box2.maxx[i] || maxx[i] < box2.minx[i])
+      return 0;
+  return 1;
+}
+*/
+
+/*
+void Box3d :: SetPoint (const Point3d & p)
+{
+  minx[0] = maxx[0] = p.X();
+  minx[1] = maxx[1] = p.Y();
+  minx[2] = maxx[2] = p.Z();
+}
+
+void Box3d :: AddPoint (const Point3d & p)
+{
+  if (p.X() < minx[0]) minx[0] = p.X();
+  if (p.X() > maxx[0]) maxx[0] = p.X();
+  if (p.Y() < minx[1]) minx[1] = p.Y();
+  if (p.Y() > maxx[1]) maxx[1] = p.Y();
+  if (p.Z() < minx[2]) minx[2] = p.Z();
+  if (p.Z() > maxx[2]) maxx[2] = p.Z();
+}
+*/
+
+void Box3d :: GetPointNr (int i, Point3d & point) const
+{
+  i--;
+  point.X() = (i & 1) ? maxx[0] : minx[0];
+  point.Y() = (i & 2) ? maxx[1] : minx[1];
+  point.Z() = (i & 4) ? maxx[2] : minx[2];
+}
+
+
+void Box3d :: Increase (double d)
+{
+  for (int i = 0; i <= 2; i++)
+    {
+      minx[i] -= d;
+      maxx[i] += d;
+    }
+}
+
+void Box3d :: IncreaseRel (double /* rel */)
+{
+  for (int i = 0; i <= 2; i++)
+    {
+      double d = 0.5 * (maxx[i] - minx[i]);
+      minx[i] -= d;
+      maxx[i] += d;
+    }
+}
+
+
+Box3d :: Box3d (const Point3d& p1, const Point3d& p2)
+{
+  minx[0] = min2 (p1.X(), p2.X());
+  minx[1] = min2 (p1.Y(), p2.Y());
+  minx[2] = min2 (p1.Z(), p2.Z());
+  maxx[0] = max2 (p1.X(), p2.X());
+  maxx[1] = max2 (p1.Y(), p2.Y());
+  maxx[2] = max2 (p1.Z(), p2.Z());
+}
+
+const Box3d& Box3d :: operator+=(const Box3d& b)
+{
+  minx[0] = min2 (minx[0], b.minx[0]);
+  minx[1] = min2 (minx[1], b.minx[1]);
+  minx[2] = min2 (minx[2], b.minx[2]);
+  maxx[0] = max2 (maxx[0], b.maxx[0]);
+  maxx[1] = max2 (maxx[1], b.maxx[1]);
+  maxx[2] = max2 (maxx[2], b.maxx[2]);
+
+  return *this;
+}
+
+Point3d Box3d :: MaxCoords() const
+{
+  return Point3d(maxx[0], maxx[1], maxx[2]);
+}
+
+Point3d Box3d :: MinCoords() const
+{
+  return Point3d(minx[0], minx[1], minx[2]);
+}
+
+/*
+void Box3d :: CreateNegMinMaxBox()
+{
+  minx[0] = MAXDOUBLE;
+  minx[1] = MAXDOUBLE;
+  minx[2] = MAXDOUBLE;
+  maxx[0] = MINDOUBLE;
+  maxx[1] = MINDOUBLE;
+  maxx[2] = MINDOUBLE;
+
+}
+*/
+
+void Box3d :: WriteData(ofstream& fout) const
+{
+  for(int i = 0; i < 3; i++)
+    {
+      fout << minx[i] << " " << maxx[i] << " ";
+    }
+  fout << "\n";
+}
+
+void Box3d :: ReadData(ifstream& fin)
+{
+  for(int i = 0; i < 3; i++)
+    {
+      fin >> minx[i];
+      fin >> maxx[i];
+    }
+}
+
+
+
+
+Box3dSphere :: Box3dSphere ( double aminx, double amaxx,
+			     double aminy, double amaxy,
+			     double aminz, double amaxz )
+  : Box3d (aminx, amaxx, aminy, amaxy, aminz, amaxz)
+{
+  CalcDiamCenter ();
+}
+
+
+void Box3dSphere :: CalcDiamCenter ()
+{
+  diam = sqrt( sqr (maxx[0] - minx[0]) +
+	       sqr (maxx[1] - minx[1]) + 
+	       sqr (maxx[2] - minx[2]));
+  
+  c.X() = 0.5 * (minx[0] + maxx[0]);
+  c.Y() = 0.5 * (minx[1] + maxx[1]);
+  c.Z() = 0.5 * (minx[2] + maxx[2]);
+  
+  inner = min2 ( min2 (maxx[0] - minx[0], maxx[1] - minx[1]), maxx[2] - minx[2]) / 2;
+}
+
+
+void Box3dSphere :: GetSubBox (int i, Box3dSphere & sbox) const
+{
+  i--;
+  if (i & 1)
+    {
+      sbox.minx[0] = c.X();
+      sbox.maxx[0] = maxx[0];
+    }
+  else
+    {
+      sbox.minx[0] = minx[0];
+      sbox.maxx[0] = c.X();
+    }
+  if (i & 2)
+    {
+      sbox.minx[1] = c.Y();
+      sbox.maxx[1] = maxx[1];
+    }
+  else
+    {
+      sbox.minx[1] = minx[1];
+      sbox.maxx[1] = c.Y();
+    }
+  if (i & 4)
+    {
+      sbox.minx[2] = c.Z();
+      sbox.maxx[2] = maxx[2];
+    }
+  else
+    {
+      sbox.minx[2] = minx[2];
+      sbox.maxx[2] = c.Z();
+    }
+  
+  //  sbox.CalcDiamCenter ();
+
+  sbox.c.X() = 0.5 * (sbox.minx[0] + sbox.maxx[0]);
+  sbox.c.Y() = 0.5 * (sbox.minx[1] + sbox.maxx[1]);
+  sbox.c.Z() = 0.5 * (sbox.minx[2] + sbox.maxx[2]);
+  sbox.diam = 0.5 * diam;
+  sbox.inner = 0.5 * inner;
+}
+
+
+
+
+/*
+double Determinant (const Vec3d & col1,
+		    const Vec3d & col2,
+		    const Vec3d & col3)
+{
+  return
+    col1.x[0] * ( col2.x[1] * col3.x[2] - col2.x[2] * col3.x[1]) +
+    col1.x[1] * ( col2.x[2] * col3.x[0] - col2.x[0] * col3.x[2]) +
+    col1.x[2] * ( col2.x[0] * col3.x[1] - col2.x[1] * col3.x[0]);
+}
+*/
+
+void Transpose (Vec3d & v1, Vec3d & v2, Vec3d & v3)
+{
+  Swap (v1.Y(), v2.X());
+  Swap (v1.Z(), v3.X());
+  Swap (v2.Z(), v3.Y());
+}
+
+
+int SolveLinearSystem (const Vec3d & col1, const Vec3d & col2,
+		       const Vec3d & col3, const Vec3d & rhs,
+		       Vec3d & sol)
+{
+  Vec3d cr;
+  Cross (col1, col2, cr);
+  double det = cr * col3;
+
+  if (fabs (det) < 1e-40)
+    return 1;
+
+  if (fabs(cr.Z()) > 1e-12)
+    {
+      // solve for 3. component
+      sol.Z() = (cr * rhs) / det;
+      
+      // 2x2 system for 1. and 2. component
+      double res1 = rhs.X() - sol.Z() * col3.X();
+      double res2 = rhs.Y() - sol.Z() * col3.Y();
+      
+      sol.X() = (col2.Y() * res1 - col2.X() * res2) / cr.Z();
+      sol.Y() = (col1.X() * res2 - col1.Y() * res1) / cr.Z();
+  
+    }
+  else
+    {
+      det = Determinant (col1, col2, col3);
+      if (fabs (det) < 1e-40)
+	return 1;
+      
+      sol.X() = Determinant (rhs, col2, col3) / det;
+      sol.Y() = Determinant (col1, rhs, col3) / det;
+      sol.Z() = Determinant (col1, col2, rhs) / det;
+    }
+
+  return 0;
+}
+
+
+int SolveLinearSystemLS (const Vec3d & col1,
+			 const Vec3d & col2,
+			 const Vec2d & rhs,
+			 Vec3d & sol)
+{
+  double a11 = col1 * col1;
+  double a12 = col1 * col2;
+  double a22 = col2 * col2;
+  
+  double det = a11 * a22 - a12 * a12;
+
+  if (det*det <= 1e-24 * a11 * a22)
+    {
+      sol = Vec3d (0, 0, 0);
+      return 1;
+    }
+  
+  Vec2d invrhs;
+  invrhs.X() = ( a22 * rhs.X() - a12 * rhs.Y()) / det;
+  invrhs.Y() = (-a12 * rhs.X() + a11 * rhs.Y()) / det;
+
+  sol.X() = invrhs.X() * col1.X() + invrhs.Y() * col2.X();
+  sol.Y() = invrhs.X() * col1.Y() + invrhs.Y() * col2.Y();
+  sol.Z() = invrhs.X() * col1.Z() + invrhs.Y() * col2.Z();
+
+  return 0;
+
+  /*
+  Vec3d inv1, inv2;
+  int err = 
+    PseudoInverse (col1, col2, inv1, inv2);
+
+   sol = rhs.X() * inv1 + rhs.Y() * inv2;
+   return err;
+  */
+}
+
+int SolveLinearSystemLS2 (const Vec3d & col1,
+			 const Vec3d & col2,
+			 const Vec2d & rhs,
+			 Vec3d & sol, double & x, double & y)
+{
+  double a11 = col1 * col1;
+  double a12 = col1 * col2;
+  double a22 = col2 * col2;
+  
+  double det = a11 * a22 - a12 * a12;
+
+  if (fabs (det) <= 1e-12 * col1.Length() * col2.Length() || 
+      col1.Length2() == 0 || col2.Length2() == 0)
+    {
+      sol = Vec3d (0, 0, 0);
+      x = 0; y = 0;
+      return 1;
+    }
+  
+  Vec2d invrhs;
+  invrhs.X() = ( a22 * rhs.X() - a12 * rhs.Y()) / det;
+  invrhs.Y() = (-a12 * rhs.X() + a11 * rhs.Y()) / det;
+
+  sol.X() = invrhs.X() * col1.X() + invrhs.Y() * col2.X();
+  sol.Y() = invrhs.X() * col1.Y() + invrhs.Y() * col2.Y();
+  sol.Z() = invrhs.X() * col1.Z() + invrhs.Y() * col2.Z();
+
+  x = invrhs.X();
+  y = invrhs.Y();
+
+  return 0;
+
+  /*
+  Vec3d inv1, inv2;
+  int err = 
+    PseudoInverse (col1, col2, inv1, inv2);
+
+   sol = rhs.X() * inv1 + rhs.Y() * inv2;
+   return err;
+  */
+}
+
+int PseudoInverse (const Vec3d & col1,
+		   const Vec3d & col2,
+		   Vec3d & inv1,
+		   Vec3d & inv2)
+{
+  double a11 = col1 * col1;
+  double a12 = col1 * col2;
+  double a22 = col2 * col2;
+  
+  double det = a11 * a22 - a12 * a12;
+
+  if (fabs (det) < 1e-12 * col1.Length() * col2.Length())
+    {
+      inv1 = Vec3d (0, 0, 0);
+      inv2 = Vec3d (0, 0, 0);
+      return 1;
+    }
+
+  double ia11 = a22 / det;
+  double ia12 = -a12 / det;
+  double ia22 = a11 / det;
+
+  inv1 = ia11 * col1 + ia12 * col2;
+  inv2 = ia12 * col1 + ia22 * col2;
+
+  return 0;
+}
+
+
+
+
+QuadraticFunction3d :: 
+QuadraticFunction3d (const Point3d & p, const Vec3d & v)
+{
+  Vec3d hv(v);
+  hv /= (hv.Length() + 1e-12);
+  Vec3d t1, t2;
+  hv.GetNormal (t1);
+  Cross (hv, t1, t2);
+  
+  double t1p = t1.X() * p.X() + t1.Y() * p.Y() + t1.Z() * p.Z();
+  double t2p = t2.X() * p.X() + t2.Y() * p.Y() + t2.Z() * p.Z();
+  c0 = sqr (t1p) + sqr (t2p);
+  cx = -2 * (t1p * t1.X() + t2p * t2.X());
+  cy = -2 * (t1p * t1.Y() + t2p * t2.Y());
+  cz = -2 * (t1p * t1.Z() + t2p * t2.Z());
+
+  cxx = t1.X() * t1.X() + t2.X() * t2.X();
+  cyy = t1.Y() * t1.Y() + t2.Y() * t2.Y();
+  czz = t1.Z() * t1.Z() + t2.Z() * t2.Z();
+
+  cxy = 2 * t1.X() * t1.Y() + 2 * t2.X() * t2.Y();
+  cxz = 2 * t1.X() * t1.Z() + 2 * t2.X() * t2.Z();
+  cyz = 2 * t1.Y() * t1.Z() + 2 * t2.Y() * t2.Z();
+
+  /*
+  (*testout) << "c0 = " << c0
+	     << " clin = " << cx << " " << cy << " " << cz 
+	     << " cq = " << cxx << " " << cyy << " " << czz
+	     << cxy << " " << cyz << " " << cyz << endl;
+  */
+}
+
+// QuadraticFunction3d gqf (Point3d (0,0,0), Vec3d (1, 0, 0));
+
+
+
+
+
+void referencetransform :: Set (const Point3d & p1, const Point3d & p2,
+                                const Point3d & p3, double ah)
+{
+  ex = p2 - p1;
+  ex /= ex.Length();
+  ey = p3 - p1;
+  ey -= (ex * ey) * ex;
+  ey /= ey.Length();
+  ez = Cross (ex, ey);
+  rp = p1;
+  h = ah;
+
+  exh = ah * ex;
+  eyh = ah * ey;
+  ezh = ah * ez;
+  ah = 1 / ah;
+  ex_h = ah * ex;
+  ey_h = ah * ey;
+  ez_h = ah * ez;
+}
+
+void referencetransform :: ToPlain (const Point3d & p, Point3d & pp) const
+{
+  Vec3d v;
+  v = p - rp;
+  pp.X() = (ex_h * v);
+  pp.Y() = (ey_h * v);
+  pp.Z() = (ez_h * v);
+}
+
+void referencetransform :: ToPlain (const ARRAY<Point3d> & p,
+                                    ARRAY<Point3d> & pp) const
+{
+  Vec3d v;
+  int i;
+
+  pp.SetSize (p.Size());
+  for (i = 1; i <= p.Size(); i++)
+    {
+      v = p.Get(i) - rp;
+      pp.Elem(i).X() = (ex_h * v);
+      pp.Elem(i).Y() = (ey_h * v);
+      pp.Elem(i).Z() = (ez_h * v);
+    }
+}
+
+void referencetransform :: FromPlain (const Point3d & pp, Point3d & p) const
+{
+  Vec3d v;
+  //  v = (h * pp.X()) * ex + (h * pp.Y()) * ey + (h * pp.Z()) * ez;
+  //  p = rp + v;
+  v.X() = pp.X() * exh.X() + pp.Y() * eyh.X() + pp.Z() * ezh.X();
+  v.Y() = pp.X() * exh.Y() + pp.Y() * eyh.Y() + pp.Z() * ezh.Y();
+  v.Z() = pp.X() * exh.Z() + pp.Y() * eyh.Z() + pp.Z() * ezh.Z();
+  p.X() = rp.X() + v.X();
+  p.Y() = rp.Y() + v.Y();
+  p.Z() = rp.Z() + v.Z();
+}
+
+
+}
diff --git a/Netgen/libsrc/gprim/geom3d.hpp b/Netgen/libsrc/gprim/geom3d.hpp
new file mode 100644
index 0000000000..fd60e6b26f
--- /dev/null
+++ b/Netgen/libsrc/gprim/geom3d.hpp
@@ -0,0 +1,728 @@
+#ifndef FILE_GEOM3D
+#define FILE_GEOM3D
+
+/* *************************************************************************/
+/* File:   geom3d.hh                                                       */
+/* Author: Joachim Schoeberl                                               */
+/* Date:   5. Aug. 95                                                      */
+/* *************************************************************************/
+
+
+
+
+extern void MyError (const char * ch);
+
+class Point3d;
+class Vec3d;
+
+inline Vec3d operator- (const Point3d & p1, const Point3d & p2);
+inline Point3d operator- (const Point3d & p1, const Vec3d & v);
+inline Point3d operator+ (const Point3d & p1, const Vec3d & v);
+Point3d & Add (double d, const Vec3d & v);
+Point3d & Add2 (double d, const Vec3d & v,
+			 double d2, const Vec3d & v2);
+inline Point3d Center (const Point3d & p1, const Point3d & p2);
+inline Point3d Center (const Point3d & p1, const Point3d & p2, const Point3d & p3);
+inline Point3d Center (const Point3d & p1, const Point3d & p2, 
+				const Point3d & p3, const Point3d & p4);
+ostream & operator<<(ostream  & s, const Point3d & p);
+inline Vec3d operator- (const Vec3d & p1, const Vec3d & v);
+inline Vec3d operator+ (const Vec3d & p1, const Vec3d & v);
+inline Vec3d operator* (double scal, const Vec3d & v);
+inline double operator* (const Vec3d & v1, const Vec3d & v2);
+inline Vec3d Cross (const Vec3d & v1, const Vec3d & v2);
+inline void Cross (const Vec3d & v1, const Vec3d & v2, Vec3d & prod);
+double Angle (const Vec3d & v);
+double FastAngle (const Vec3d & v);
+double Angle (const Vec3d & v1, const Vec3d & v2);
+double FastAngle (const Vec3d & v1, const Vec3d & v2);
+ostream & operator<<(ostream  & s, const Vec3d & v);
+void Transpose (Vec3d & v1, Vec3d & v2, Vec3d & v3);
+int SolveLinearSystem (const Vec3d & col1,
+		       const Vec3d & col2,
+		       const Vec3d & col3,
+		       const Vec3d & rhs,
+		       Vec3d & sol);
+int SolveLinearSystemLS (const Vec3d & col1,
+			 const Vec3d & col2,
+			 const Vec2d & rhs,
+			 Vec3d & sol);
+int SolveLinearSystemLS2 (const Vec3d & col1,
+			  const Vec3d & col2,
+			  const Vec2d & rhs, 
+			  Vec3d & sol,
+			  double & x, double & y);
+int PseudoInverse (const Vec3d & col1,
+		   const Vec3d & col2,
+		   Vec3d & inv1,
+		   Vec3d & inv2);
+double Determinant (const Vec3d & col1,
+		    const Vec3d & col2,
+		    const Vec3d & col3);
+
+/// Point in R3
+class Point3d
+{
+protected:
+  ///
+  double x[3];
+  
+public:
+  ///
+  Point3d () { x[0] = x[1] = x[2] = 0; }
+  ///
+  Point3d(double ax, double ay, double az) 
+    { x[0] = ax; x[1] = ay; x[2] = az; }
+  ///
+  Point3d(double ax[3])
+    { x[0] = ax[0]; x[1] = ax[1]; x[2] = ax[2]; }
+
+  ///
+  Point3d(const Point3d & p2) 
+    { x[0] = p2.x[0]; x[1] = p2.x[1]; x[2] = p2.x[2]; }
+
+  Point3d (const Point<3> & p2)
+  {
+    for (int i = 0; i < 3; i++)
+      x[i] = p2(i);
+  }
+  
+  ///
+  Point3d & operator= (const Point3d & p2)
+    { x[0] = p2.x[0]; x[1] = p2.x[1]; x[2] = p2.x[2]; return *this; }
+  
+  ///
+  int operator== (const Point3d& p) const
+    { return (x[0] == p.x[0] && x[1] == p.x[1] && x[2] == p.x[2]); }
+  
+  ///
+  double & X() { return x[0]; }
+  ///
+  double & Y() { return x[1]; }
+  ///
+  double & Z() { return x[2]; }
+  ///
+  double X() const { return x[0]; }
+  ///
+  double Y() const { return x[1]; }
+  ///
+  double Z() const { return x[2]; }
+  ///
+  double & X(int i) { return x[i-1]; }
+  ///
+  double X(int i) const { return x[i-1]; }
+  ///
+  const Point3d & SetToMin (const Point3d & p2)
+    {
+      if (p2.x[0] < x[0]) x[0] = p2.x[0];
+      if (p2.x[1] < x[1]) x[1] = p2.x[1];
+      if (p2.x[2] < x[2]) x[2] = p2.x[2];
+      return *this;
+    }
+
+  ///
+  const Point3d & SetToMax (const Point3d & p2)
+    {
+      if (p2.x[0] > x[0]) x[0] = p2.x[0];
+      if (p2.x[1] > x[1]) x[1] = p2.x[1];
+      if (p2.x[2] > x[2]) x[2] = p2.x[2];
+      return *this;
+    }
+
+  ///
+  friend inline Vec3d operator- (const Point3d & p1, const Point3d & p2);
+  ///
+  friend inline Point3d operator- (const Point3d & p1, const Vec3d & v);
+  ///
+  friend inline Point3d operator+ (const Point3d & p1, const Vec3d & v);
+  ///
+  inline Point3d & operator+= (const Vec3d & v);
+  inline Point3d & operator-= (const Vec3d & v);
+  ///
+  inline Point3d & Add (double d, const Vec3d & v);
+  ///
+  inline Point3d & Add2 (double d, const Vec3d & v,
+			 double d2, const Vec3d & v2);
+  ///
+  friend inline double Dist (const Point3d & p1, const Point3d & p2)
+    { return sqrt (  (p1.x[0]-p2.x[0]) * (p1.x[0]-p2.x[0]) + 
+		     (p1.x[1]-p2.x[1]) * (p1.x[1]-p2.x[1]) +
+                     (p1.x[2]-p2.x[2]) * (p1.x[2]-p2.x[2])); }
+  ///
+  inline friend double Dist2 (const Point3d & p1, const Point3d & p2)
+    { return  (  (p1.x[0]-p2.x[0]) * (p1.x[0]-p2.x[0]) + 
+		 (p1.x[1]-p2.x[1]) * (p1.x[1]-p2.x[1]) +
+		 (p1.x[2]-p2.x[2]) * (p1.x[2]-p2.x[2])); }
+
+  ///
+  friend inline Point3d Center (const Point3d & p1, const Point3d & p2);
+  ///
+  friend inline Point3d Center (const Point3d & p1, const Point3d & p2, const Point3d & p3);
+  ///
+  friend inline Point3d Center (const Point3d & p1, const Point3d & p2, 
+				const Point3d & p3, const Point3d & p4);
+  ///
+  friend ostream & operator<<(ostream  & s, const Point3d & p);
+  
+  ///
+  friend class Vec3d;
+  ///
+  friend class Box3d;
+
+
+  operator Point<3> () const
+  {
+    return Point<3> (x[0], x[1], x[2]);
+  }
+};
+
+
+///
+class Vec3d
+{
+protected:
+  ///
+  double x[3];
+
+public:
+  ///
+  inline Vec3d() { x[0] = x[1] = x[2] = 0; }
+  ///
+  inline Vec3d(double ax, double ay, double az)
+    { x[0] = ax; x[1] = ay; x[2] = az; }
+  ///
+  Vec3d(double ax[3])
+    { x[0] = ax[0]; x[1] = ax[1]; x[2] = ax[2]; }
+  ///
+  inline Vec3d(const Vec3d & v2) 
+    { x[0] = v2.x[0]; x[1] = v2.x[1]; x[2] = v2.x[2]; }
+  ///
+  inline Vec3d(const Point3d & p1, const Point3d & p2)
+    { 
+      x[0] = p2.x[0] - p1.x[0];
+      x[1] = p2.x[1] - p1.x[1];
+      x[2] = p2.x[2] - p1.x[2]; 
+    }
+  ///
+  inline Vec3d(const Point3d & p1)
+    { 
+      x[0] = p1.x[0];
+      x[1] = p1.x[1];
+      x[2] = p1.x[2];
+    }
+  
+  Vec3d (const Vec<3> & v2)
+  {
+    for (int i = 0; i < 3; i++)
+      x[i] = v2(i);
+  }
+
+  operator Vec<3> () const
+  {
+    return Vec<3> (x[0], x[1], x[2]);
+  }
+
+
+  Vec3d & operator= (const Vec3d & v2)
+    { x[0] = v2.x[0]; x[1] = v2.x[1]; x[2] = v2.x[2]; return *this; }
+  ///
+  Vec3d & operator= (double val)
+    { x[0] = x[1] = x[2] = val; return *this; }
+  ///
+  double & X() { return x[0]; }
+  ///
+  double & Y() { return x[1]; }
+  ///
+  double & Z() { return x[2]; }
+  ///
+  double & X(int i) { return x[i-1]; }
+
+  ///
+  double X() const { return x[0]; }
+  ///
+  double Y() const { return x[1]; }
+  ///
+  double Z() const { return x[2]; }
+  ///
+  double X(int i) const { return x[i-1]; }
+
+  ///
+  double Length() const 
+    { return sqrt (x[0] * x[0] + x[1] * x[1] + x[2] * x[2]); }
+  ///
+  double Length2() const 
+    { return x[0] * x[0] + x[1] * x[1] + x[2] * x[2]; }
+
+  ///
+  Vec3d & operator+= (const Vec3d & v2);
+  ///
+  Vec3d & operator-= (const Vec3d & v2);
+  ///
+  Vec3d & operator*= (double s);
+  ///
+  Vec3d & operator/= (double s);
+  ///
+  inline Vec3d & Add (double d, const Vec3d & v);
+  ///
+  inline Vec3d & Add2 (double d, const Vec3d & v,
+			 double d2, const Vec3d & v2);
+
+  ///
+  friend inline Vec3d operator- (const Point3d & p1, const Point3d & p2);
+  ///
+  friend inline Point3d operator- (const Point3d & p1, const Vec3d & v);
+  ///
+  friend inline Point3d operator+ (const Point3d & p1, const Vec3d & v);
+  ///
+  friend inline Vec3d operator- (const Vec3d & p1, const Vec3d & v);
+  ///
+  friend inline Vec3d operator+ (const Vec3d & p1, const Vec3d & v);
+  ///
+  friend inline Vec3d operator* (double scal, const Vec3d & v);
+
+  ///
+  friend inline double operator* (const Vec3d & v1, const Vec3d & v2);
+  ///
+  friend inline Vec3d Cross (const Vec3d & v1, const Vec3d & v2);
+  ///
+  friend inline void Cross (const Vec3d & v1, const Vec3d & v2, Vec3d & prod);
+
+  /// Returns one normal-vector to n
+  void GetNormal (Vec3d & n) const;
+  ///
+  friend double Angle (const Vec3d & v);
+  ///
+  friend double FastAngle (const Vec3d & v);
+  ///
+  friend double Angle (const Vec3d & v1, const Vec3d & v2);
+  ///
+  friend double FastAngle (const Vec3d & v1, const Vec3d & v2);
+
+  void Normalize() 
+  {
+    double len = (x[0] * x[0] + x[1] * x[1] + x[2] * x[2]);
+    if (len == 0) return;
+    len = sqrt (len);
+    x[0] /= len; x[1] /= len; x[2] /= len;
+  }
+
+  ///
+  friend ostream & operator<<(ostream  & s, const Vec3d & v);
+
+  ///
+  friend class Point3d;
+  friend void Transpose (Vec3d & v1, Vec3d & v2, Vec3d & v3);
+  friend int SolveLinearSystem (const Vec3d & col1,
+				const Vec3d & col2,
+				const Vec3d & col3,
+				const Vec3d & rhs,
+				Vec3d & sol);
+  friend int SolveLinearSystemLS (const Vec3d & col1,
+				  const Vec3d & col2,
+				  const Vec2d & rhs,
+				  Vec3d & sol);
+  friend int SolveLinearSystemLS2 (const Vec3d & col1,
+				   const Vec3d & col2,
+				   const Vec2d & rhs, 
+				   Vec3d & sol,
+				   double & x, double & y);
+  friend int PseudoInverse (const Vec3d & col1,
+			    const Vec3d & col2,
+			    Vec3d & inv1,
+			    Vec3d & inv2);
+  friend double Determinant (const Vec3d & col1,
+			     const Vec3d & col2,
+			     const Vec3d & col3);
+};
+
+
+
+
+class QuadraticFunction3d
+{
+  double c0, cx, cy, cz;
+  double cxx, cyy, czz, cxy, cxz, cyz;
+
+public:
+  QuadraticFunction3d (const Point3d & p, const Vec3d & v);
+  double Eval (const Point3d & p)
+    {
+      return 
+	c0 
+	+ p.X() * (cx + cxx * p.X() + cxy * p.Y() + cxz * p.Z())
+	+ p.Y() * (cy + cyy * p.Y() + cyz * p.Z())
+	+ p.Z() * (cz + czz * p.Z());
+    }
+};
+
+
+
+inline Point3d Center (const Point3d & p1, const Point3d & p2)
+{
+  return Point3d (0.5 * (p1.x[0] + p2.x[0]),
+		  0.5 * (p1.x[1] + p2.x[1]),
+		  0.5 * (p1.x[2] + p2.x[2]));
+}
+
+
+inline Point3d Center (const Point3d & p1, const Point3d & p2,
+                       const Point3d & p3)
+{
+  return Point3d (1.0/3.0 * (p1.x[0] + p2.x[0] + p3.x[0]),
+		  1.0/3.0 * (p1.x[1] + p2.x[1] + p3.x[1]),
+		  1.0/3.0 * (p1.x[2] + p2.x[2] + p3.x[2]));
+}
+
+inline Point3d Center (const Point3d & p1, const Point3d & p2,
+                       const Point3d & p3, const Point3d & p4)
+{
+  return Point3d (0.25 * (p1.x[0] + p2.x[0] + p3.x[0] + p4.x[0]),
+		  0.25 * (p1.x[1] + p2.x[1] + p3.x[1] + p4.x[1]),
+		  0.25 * (p1.x[2] + p2.x[2] + p3.x[2] + p4.x[2]));
+}
+
+
+
+inline Vec3d & Vec3d :: operator+= (const Vec3d & v2)
+{
+  x[0] += v2.x[0];
+  x[1] += v2.x[1];
+  x[2] += v2.x[2];
+  return *this;
+}
+
+inline Vec3d & Vec3d :: operator-= (const Vec3d & v2)
+{
+  x[0] -= v2.x[0];
+  x[1] -= v2.x[1];
+  x[2] -= v2.x[2];
+  return *this;
+}
+
+
+inline Vec3d & Vec3d :: operator*= (double s)
+{
+  x[0] *= s;
+  x[1] *= s;
+  x[2] *= s;
+  return *this;
+}
+
+
+inline Vec3d & Vec3d :: operator/= (double s)
+{
+  if (s != 0)
+    {
+      x[0] /= s;
+      x[1] /= s;
+      x[2] /= s;
+    }
+  else
+    {
+      cerr << "Vec div by 0, v = " << (*this) << endl;
+      //      MyError ("Vec3d::operator /=: Divisioin by zero");
+    }
+  return *this;
+}
+
+inline Vec3d & Vec3d::Add (double d, const Vec3d & v)
+{
+  x[0] += d * v.x[0]; 
+  x[1] += d * v.x[1]; 
+  x[2] += d * v.x[2];
+  return *this;
+}
+
+inline Vec3d & Vec3d::Add2 (double d, const Vec3d & v,
+			    double d2, const Vec3d & v2)
+{
+  x[0] += d * v.x[0] + d2 * v2.x[0]; 
+  x[1] += d * v.x[1] + d2 * v2.x[1]; 
+  x[2] += d * v.x[2] + d2 * v2.x[2]; 
+  return *this;
+}
+
+
+
+
+
+
+
+
+inline Vec3d operator- (const Point3d & p1, const Point3d & p2)
+{
+  return Vec3d (p1.x[0] - p2.x[0], p1.x[1] - p2.x[1],p1.x[2] - p2.x[2]);
+}
+
+
+inline Point3d operator- (const Point3d & p1, const Vec3d & v)
+{
+  return Point3d (p1.x[0] - v.x[0], p1.x[1] - v.x[1],p1.x[2] - v.x[2]);
+}
+
+
+inline Point3d operator+ (const Point3d & p1, const Vec3d & v)
+{
+  return Point3d (p1.x[0] + v.x[0], p1.x[1] + v.x[1],p1.x[2] + v.x[2]);
+}
+
+inline Point3d & Point3d::operator+= (const Vec3d & v) 
+{
+  x[0] += v.x[0]; 
+  x[1] += v.x[1]; 
+  x[2] += v.x[2];
+  return *this;
+}
+
+inline Point3d & Point3d::operator-= (const Vec3d & v) 
+{
+  x[0] -= v.x[0]; 
+  x[1] -= v.x[1]; 
+  x[2] -= v.x[2];
+  return *this;
+}
+
+inline Point3d & Point3d::Add (double d, const Vec3d & v)
+{
+  x[0] += d * v.x[0]; 
+  x[1] += d * v.x[1]; 
+  x[2] += d * v.x[2];
+  return *this;
+}
+
+inline Point3d & Point3d::Add2 (double d, const Vec3d & v,
+				double d2, const Vec3d & v2)
+{
+  x[0] += d * v.x[0] + d2 * v2.x[0]; 
+  x[1] += d * v.x[1] + d2 * v2.x[1]; 
+  x[2] += d * v.x[2] + d2 * v2.x[2]; 
+  return *this;
+}
+
+
+inline Vec3d operator- (const Vec3d & v1, const Vec3d & v2)
+{
+  return Vec3d (v1.x[0] - v2.x[0], v1.x[1] - v2.x[1],v1.x[2] - v2.x[2]);
+}
+
+
+inline Vec3d operator+ (const Vec3d & v1, const Vec3d & v2)
+{
+  return Vec3d (v1.x[0] + v2.x[0], v1.x[1] + v2.x[1],v1.x[2] + v2.x[2]);
+}
+
+
+inline Vec3d operator* (double scal, const Vec3d & v)
+{
+  return Vec3d (scal * v.x[0], scal * v.x[1], scal * v.x[2]);
+}
+
+
+
+inline double operator* (const Vec3d & v1, const Vec3d & v2)
+{
+  return v1.x[0] * v2.x[0] + v1.x[1] * v2.x[1] + v1.x[2] * v2.x[2];
+}
+
+
+
+inline Vec3d Cross (const Vec3d & v1, const Vec3d & v2)
+{
+  return Vec3d
+    ( v1.x[1] * v2.x[2] - v1.x[2] * v2.x[1],
+      v1.x[2] * v2.x[0] - v1.x[0] * v2.x[2],
+      v1.x[0] * v2.x[1] - v1.x[1] * v2.x[0]);
+}
+
+inline void Cross (const Vec3d & v1, const Vec3d & v2, Vec3d & prod)
+{
+  prod.x[0] = v1.x[1] * v2.x[2] - v1.x[2] * v2.x[1];
+  prod.x[1] = v1.x[2] * v2.x[0] - v1.x[0] * v2.x[2];
+  prod.x[2] = v1.x[0] * v2.x[1] - v1.x[1] * v2.x[0];
+}
+
+inline double Determinant (const Vec3d & col1,
+			   const Vec3d & col2,
+			   const Vec3d & col3)
+{
+  return
+    col1.x[0] * ( col2.x[1] * col3.x[2] - col2.x[2] * col3.x[1]) +
+    col1.x[1] * ( col2.x[2] * col3.x[0] - col2.x[0] * col3.x[2]) +
+    col1.x[2] * ( col2.x[0] * col3.x[1] - col2.x[1] * col3.x[0]);
+}
+
+
+///
+class Box3d
+{
+protected:
+  ///
+  double minx[3], maxx[3];
+
+public:
+  ///
+  Box3d () { };
+  ///
+  Box3d ( double aminx, double amaxx,
+          double aminy, double amaxy,
+          double aminz, double amaxz );
+  ///
+  Box3d ( const Box3d & b2 );
+  ///
+  Box3d (const Point3d& p1, const Point3d& p2);
+  ///
+  double MinX () const { return minx[0]; }
+  ///
+  double MaxX () const { return maxx[0]; }
+  ///
+  double MinY () const { return minx[1]; }
+  ///
+  double MaxY () const { return maxx[1]; }
+  ///
+  double MinZ () const { return minx[2]; }
+  ///
+  double MaxZ () const { return maxx[2]; }
+
+  ///
+  double Mini (int i) const { return minx[i-1]; }
+  ///
+  double Maxi (int i) const { return maxx[i-1]; }
+
+  ///
+  Point3d PMin () const { return Point3d(minx[0], minx[1], minx[2]); }
+  ///
+  Point3d PMax () const { return Point3d(maxx[0], maxx[1], maxx[2]); }
+
+  ///
+  void GetPointNr (int i, Point3d & point) const;
+  /// increase Box at each side with dist 
+  void Increase (double dist);
+  /// increase Box by factor rel
+  void IncreaseRel (double rel);
+  /// return 1 if closures are intersecting
+  int Intersect (const Box3d & box2) const
+  {
+    if (minx[0] > box2.maxx[0] || maxx[0] < box2.minx[0] ||
+	minx[1] > box2.maxx[1] || maxx[1] < box2.minx[1] ||
+	minx[2] > box2.maxx[2] || maxx[2] < box2.minx[2])
+      return 0;
+    return 1;
+  }
+  /// return 1 if point p in closure
+  int IsIn (const Point3d & p) const
+    {
+      if (minx[0] <= p.x[0] && maxx[0] >= p.x[0] &&
+	  minx[1] <= p.x[1] && maxx[1] >= p.x[1] &&
+	  minx[2] <= p.x[2] && maxx[2] >= p.x[2])
+	return 1;
+      return 0;
+    }
+  ///
+  inline void SetPoint (const Point3d & p)
+    {
+      minx[0] = maxx[0] = p.X();
+      minx[1] = maxx[1] = p.Y();
+      minx[2] = maxx[2] = p.Z();    
+    }
+
+  ///
+  inline void AddPoint (const Point3d & p)
+    {
+      if (p.x[0] < minx[0]) minx[0] = p.x[0];
+      if (p.x[0] > maxx[0]) maxx[0] = p.x[0];
+      if (p.x[1] < minx[1]) minx[1] = p.x[1];
+      if (p.x[1] > maxx[1]) maxx[1] = p.x[1];
+      if (p.x[2] < minx[2]) minx[2] = p.x[2];
+      if (p.x[2] > maxx[2]) maxx[2] = p.x[2];
+    }
+
+  ///
+  const Box3d& operator+=(const Box3d& b);
+
+  ///
+  Point3d MaxCoords() const;
+  ///
+  Point3d MinCoords() const;
+
+  /// Make a negative sized box;
+  //  void CreateNegMinMaxBox();
+  
+  ///
+  Point3d CalcCenter () const { return Point3d(0.5*(minx[0] + maxx[0]),
+					       0.5*(minx[1] + maxx[1]),
+					       0.5*(minx[2] + maxx[2])); }
+  ///
+  double CalcDiam () const { return sqrt(sqr(maxx[0]-minx[0])+
+					 sqr(maxx[1]-minx[1])+
+					 sqr(maxx[2]-minx[2])); }
+
+  ///
+  void WriteData(ofstream& fout) const;
+  ///
+  void ReadData(ifstream& fin);
+};
+
+
+class Box3dSphere : public Box3d
+{
+protected:
+  ///
+  double diam, inner;
+  ///
+  Point3d c;
+public:
+  ///
+  Box3dSphere () { };
+  ///
+  Box3dSphere ( double aminx, double amaxx,
+		double aminy, double amaxy,
+		double aminz, double amaxz);
+  ///
+  const Point3d & Center () const { return c; }
+
+  ///
+  double Diam () const { return diam; }
+  ///
+  double Inner () const { return inner; }
+  ///
+  void GetSubBox (int i, Box3dSphere & sbox) const;
+
+  // private:
+  ///
+  void CalcDiamCenter ();
+};
+
+
+
+
+///
+class referencetransform
+{
+  ///
+  Vec3d ex, ey, ez;
+  ///
+  Vec3d exh, eyh, ezh;
+  ///
+  Vec3d ex_h, ey_h, ez_h;
+  ///
+  Point3d rp;
+  ///
+  double h;
+
+public:
+
+  ///
+  void Set (const Point3d & p1, const Point3d & p2,
+            const Point3d & p3, double ah);
+
+  ///
+  void ToPlain (const Point3d & p, Point3d & pp) const;
+  ///
+  void ToPlain (const ARRAY<Point3d> & p, ARRAY<Point3d> & pp) const;
+  ///
+  void FromPlain (const Point3d & pp, Point3d & p) const;
+};
+
+
+
+#endif
diff --git a/Netgen/libsrc/gprim/geomfuncs.cpp b/Netgen/libsrc/gprim/geomfuncs.cpp
new file mode 100644
index 0000000000..b2ac83824a
--- /dev/null
+++ b/Netgen/libsrc/gprim/geomfuncs.cpp
@@ -0,0 +1,111 @@
+#include <mystdlib.h>
+
+#include <myadt.hpp>
+#include <gprim.hpp>
+
+namespace netgen
+{
+
+  /*
+  // template <>
+inline void CalcInverse (const Mat<2,2> & m, Mat<2,2> & inv)
+{
+  double det = m(0,0) * m(1,1) - m(0,1) * m(1,0);
+  if (det == 0) 
+    {
+      inv = 0;
+      return;
+    }
+
+  double idet = 1.0 / det;
+  inv(0,0) =  idet * m(1,1);
+  inv(0,1) = -idet * m(0,1);
+  inv(1,0) = -idet * m(1,0);
+  inv(1,1) =  idet * m(0,0);
+}
+  */
+
+
+
+  // template <>
+void CalcInverse (const Mat<3,3> & m, Mat<3,3> & inv)
+{
+  double det = Det (m);
+  if (det == 0) 
+    {
+      inv = 0;
+      return;
+    }
+
+  double idet = 1.0 / det;
+  inv(0,0) =  idet * (m(1,1) * m(2,2) - m(1,2) * m(2,1));
+  inv(1,0) = -idet * (m(1,0) * m(2,2) - m(1,2) * m(2,0));
+  inv(2,0) =  idet * (m(1,0) * m(2,1) - m(1,1) * m(2,0));
+
+  inv(0,1) = -idet * (m(0,1) * m(2,2) - m(0,2) * m(2,1));
+  inv(1,1) =  idet * (m(0,0) * m(2,2) - m(0,2) * m(2,0));
+  inv(2,1) = -idet * (m(0,0) * m(2,1) - m(0,1) * m(2,0));
+
+  inv(0,2) =  idet * (m(0,1) * m(1,2) - m(0,2) * m(1,1));
+  inv(1,2) = -idet * (m(0,0) * m(1,2) - m(0,2) * m(1,0));
+  inv(2,2) =  idet * (m(0,0) * m(1,1) - m(0,1) * m(1,0));
+}
+
+/*
+// template <>
+void CalcInverse (const Mat<2,3> & m, Mat<3,2> & inv)
+{
+  Mat<2,2> a = m * Trans (m);
+  Mat<2,2> ainv;
+  CalcInverse (a, ainv);
+  inv = Trans (m) * ainv;
+}
+*/
+
+
+
+double Det (const Mat<2,2> & m) 
+{
+  return  m(0,0) * m(1,1) - m(0,1) * m(1,0);
+}
+
+double Det (const Mat<3,3> & m) 
+{
+  return 
+    m(0,0) * m(1,1) * m(2,2)
+    + m(1,0) * m(2,1) * m(0,2)
+    + m(2,0) * m(0,1) * m(1,2)
+    - m(0,0) * m(2,1) * m(1,2)
+    - m(1,0) * m(0,1) * m(2,2)
+    - m(2,0) * m(1,1) * m(0,2);
+}
+
+
+void EigenValues (const Mat<3,3> & m, Vec<3> & ev)
+{
+  const double pi = 3.141592;
+  double a, b, c, d;
+  double p, q;
+  double arg;
+
+  a = -1.;
+  b = m(0,0) + m(1,1) + m(2,2);
+  c = -( m(0,0)*m(2,2) + m(1,1)*m(2,2) + m(0,0)*m(1,1) - sqr(m(0,1)) - sqr(m(0,2)) - sqr(m(1,2)) );
+  d = Det (m);
+  p = 3.*a*c - sqr(b);
+  q = 27.*sqr(a)*d - 9.*a*b*c + 2.*sqr(b)*b;
+
+
+  arg = acos((-q/2)/sqrt(-(p*p*p)));
+
+
+  ev(0) = (2. * sqrt(-p) * cos(arg/3.) - b) / 3.*a;
+  ev(1) = (-2. * sqrt(-p) * cos(arg/3.+pi/3) - b) / 3.*a;
+  ev(2) = (-2. * sqrt(-p) * cos(arg/3.-pi/3)- b) / 3.*a;
+
+
+
+}
+
+
+}
diff --git a/Netgen/libsrc/gprim/geomfuncs.hpp b/Netgen/libsrc/gprim/geomfuncs.hpp
new file mode 100644
index 0000000000..b013261df8
--- /dev/null
+++ b/Netgen/libsrc/gprim/geomfuncs.hpp
@@ -0,0 +1,129 @@
+#ifndef FILE_GEOMFUNCS
+#define FILE_GEOMFUNCS
+
+/* *************************************************************************/
+/* File:   geomfuncs.hpp                                                   */
+/* Author: Joachim Schoeberl                                               */
+/* Date:   20. Jul. 02                                                     */
+/* *************************************************************************/
+
+
+template <int D>
+inline double Abs (const Vec<D> & v)
+{
+  double sum = 0;
+  for (int i = 0; i < D; i++)
+    sum += v(i) * v(i);
+  return sqrt (sum);
+}
+
+
+template <int D>
+inline double Abs2 (const Vec<D> & v)
+{
+  double sum = 0;
+  for (int i = 0; i < D; i++)
+    sum += v(i) * v(i);
+  return sum;
+}
+
+
+
+template <int D>
+inline double Dist (const Point<D> & a, const Point<D> & b)
+{
+  return Abs (a-b);
+}
+
+template <int D>
+inline double Dist2 (const Point<D> & a, const Point<D> & b)
+{
+  return Abs2 (a-b);
+}
+
+
+template <int D>
+inline Point<D> Center (const Point<D> & a, const Point<D> & b)
+{
+  Point<D> res;
+  for (int i = 0; i < D; i++)
+    res(i) = 0.5 * (a(i) + b(i));
+  return res;
+}
+
+template <int D>
+inline Point<D> Center (const Point<D> & a, const Point<D> & b, const Point<D> & c)
+{
+  Point<D> res;
+  for (int i = 0; i < D; i++)
+    res(i) = (1.0/3.0) * (a(i) + b(i) + c(i));
+  return res;
+}
+
+
+
+inline Vec<3> Cross (const Vec<3> & v1, const Vec<3> & v2)
+{
+  return Vec<3> 
+    ( v1(1) * v2(2) - v1(2) * v2(1),
+      v1(2) * v2(0) - v1(0) * v2(2),
+      v1(0) * v2(1) - v1(1) * v2(0) );
+}
+
+
+template <>
+inline  Vec<2> Vec<2> :: GetNormal () const
+{
+  return Vec<2> (-x[1], x[0]);
+}
+
+template <>
+inline  Vec<3> Vec<3> :: GetNormal () const
+{
+  if (fabs (x[0]) > fabs (x[2]))
+    return Vec<3> (-x[1], x[0], 0);
+  else
+    return Vec<3> (0, x[2], -x[1]);
+}
+
+
+
+// template <int H, int W>
+inline void CalcInverse (const Mat<2,2> & m, Mat<2,2> & inv)
+{
+  double det = m(0,0) * m(1,1) - m(0,1) * m(1,0);
+  if (det == 0) 
+    {
+      inv = 0;
+      return;
+    }
+
+  double idet = 1.0 / det;
+  inv(0,0) =  idet * m(1,1);
+  inv(0,1) = -idet * m(0,1);
+  inv(1,0) = -idet * m(1,0);
+  inv(1,1) =  idet * m(0,0);
+}
+
+void CalcInverse (const Mat<3,3> & m, Mat<3,3> & inv);
+
+inline void CalcInverse (const Mat<2,3> & m, Mat<3,2> & inv)
+{
+  Mat<2,2> a = m * Trans (m);
+  Mat<2,2> ainv;
+  CalcInverse (a, ainv);
+  inv = Trans (m) * ainv;
+}
+
+// void CalcInverse (const Mat<3,2> & m, Mat<2,3> & inv);
+
+
+
+double Det (const Mat<2,2> & m);
+double Det (const Mat<3,3> & m);
+
+// eigenvalues of a symmetric matrix
+void EigenValues (const Mat<3,3> & m, Vec<3> & ev);
+void EigenValues (const Mat<2,2> & m, Vec<3> & ev);
+
+#endif
diff --git a/Netgen/libsrc/gprim/geomobjects.hpp b/Netgen/libsrc/gprim/geomobjects.hpp
new file mode 100644
index 0000000000..9f6a8f025b
--- /dev/null
+++ b/Netgen/libsrc/gprim/geomobjects.hpp
@@ -0,0 +1,333 @@
+#ifndef FILE_OBJECTS
+#define FILE_OBJECTS
+
+/* *************************************************************************/
+/* File:   geomobjects.hpp                                                 */
+/* Author: Joachim Schoeberl                                               */
+/* Date:   20. Jul. 02                                                     */
+/* *************************************************************************/
+
+
+
+template <int D> class Vec;
+template <int D> class Point;
+
+
+template <int D>
+class Point
+{
+
+protected:
+  double x[D];
+
+public:
+  Point () { ; }
+  Point (double ax) { x[0] = ax; }
+  Point (double ax, double ay) { x[0] = ax; x[1] = ay; }
+  Point (double ax, double ay, double az)
+  { x[0] = ax; x[1] = ay; x[2] = az; }
+  Point (double ax, double ay, double az, double au)
+  { x[0] = ax; x[1] = ay; x[2] = az; x[3] = au;}
+
+  Point (const Point<D> & p2)
+  { for (int i = 0; i < D; i++) x[i] = p2.x[i]; }
+
+  explicit Point (const Vec<D> & v)
+  { for (int i = 0; i < D; i++) x[i] = v(i); }
+
+
+  Point & operator= (const Point<D> & p2)
+  {
+    for (int i = 0; i < D; i++) x[i] = p2.x[i]; 
+    return *this;
+  }
+
+  double & operator() (int i) { return x[i]; }
+  const double & operator() (int i) const { return x[i]; }
+
+  operator const double* () const { return x; }
+};
+
+
+
+
+
+template <int D>
+class Vec
+{
+
+protected:
+  double x[D];
+
+public:
+  Vec () { ; }
+  Vec (double ax) { for (int i = 0; i < D; i++) x[i] = ax; }
+  Vec (double ax, double ay) { x[0] = ax; x[1] = ay; }
+  Vec (double ax, double ay, double az)
+  { x[0] = ax; x[1] = ay; x[2] = az; }
+  Vec (double ax, double ay, double az, double au)
+  { x[0] = ax; x[1] = ay; x[2] = az; x[3] = au; }
+
+  Vec (const Vec<D> & p2)
+  { for (int i = 0; i < D; i++) x[i] = p2.x[i]; }
+
+  explicit Vec (const Point<D> & p)
+  { for (int i = 0; i < D; i++) x[i] = p(i); }
+
+
+  Vec & operator= (const Vec<D> & p2)
+  {
+    for (int i = 0; i < D; i++) x[i] = p2.x[i]; 
+    return *this;
+  }
+
+  Vec & operator= (double s)
+  {
+    for (int i = 0; i < D; i++) x[i] = s;
+    return *this;
+  }
+
+  double & operator() (int i) { return x[i]; }
+  const double & operator() (int i) const { return x[i]; }
+
+  operator const double* () const { return x; }
+
+  double Length () const
+  {
+    double l = 0;
+    for (int i = 0; i < D; i++)
+      l += x[i] * x[i];
+    return sqrt (l);
+  }
+
+  double Length2 () const
+  {
+    double l = 0;
+    for (int i = 0; i < D; i++)
+      l += x[i] * x[i];
+    return l;
+  }
+
+  const Vec<D> & Normalize ()
+  {
+    double l = Length();
+    if (l != 0)
+      for (int i = 0; i < D; i++)
+	x[i] /= l;
+    return *this;
+  }
+
+  Vec<D> GetNormal () const;
+};
+
+
+
+
+
+template <int H, int W=H>
+class Mat
+{
+
+protected:
+  double x[H*W];
+
+public:
+  Mat () { ; }
+  Mat (const Mat & b)
+  { for (int i = 0; i < H*W; i++) x[i] = b.x[i]; }
+  
+  Mat & operator= (double s)
+  {
+    for (int i = 0; i < H*W; i++) x[i] = s;
+    return *this;
+  }
+
+  Mat & operator= (const Mat & b)
+  {
+    for (int i = 0; i < H*W; i++) x[i] = b.x[i]; 
+    return *this;
+  }
+
+  double & operator() (int i, int j) { return x[i*W+j]; }
+  const double & operator() (int i, int j) const { return x[i*W+j]; }
+
+  Vec<H> Col (int i) const
+  {
+    Vec<H> hv; 
+    for (int j = 0; j < H; j++)
+      hv(j) = x[j*W+i];
+    return hv; 
+  }
+
+  Vec<W> Row (int i) const
+  {
+    Vec<W> hv; 
+    for (int j = 0; j < W; j++)
+      hv(j) = x[i*W+j];
+    return hv; 
+  }
+
+  void Solve (const Vec<H> & rhs, Vec<W> & sol) const
+  {
+    Mat<W,H> inv;
+    CalcInverse (*this, inv);
+    sol = inv * rhs;
+  }
+};
+
+
+
+
+template <int D>
+class Box
+{
+protected:
+  Point<D> pmin, pmax;
+public:
+  Box () { ; }
+  Box ( const Point<D> & p1, const Point<D> & p2)
+  {
+    for (int i = 0; i < D; i++)
+      {
+	pmin(i) = min2(p1(i), p2(i));
+	pmax(i) = max2(p1(i), p2(i));
+      }
+  }
+
+  const Point<D> & PMin () const { return pmin; }
+  const Point<D> & PMax () const { return pmax; }
+  
+  void Set (const Point<D> & p)
+  { pmin = pmax = p; }
+
+  void Add (const Point<D> & p)
+  { 
+    for (int i = 0; i < D; i++)
+      {
+	if (p(i) < pmin(i)) pmin(i) = p(i);
+	else if (p(i) > pmax(i)) pmax(i) = p(i);
+      }
+  }
+
+  Point<D> Center () const 
+  { 
+    Point<D> c;
+    for (int i = 0; i < D; i++)
+      c(i) = 0.5 * (pmin(i)+pmax(i)); 
+    return c;
+  }
+  double Diam () const { return Abs (pmax-pmin); }
+
+  Point<D> GetPointNr (int nr) const
+  {
+    Point<D> p;
+    for (int i = 0; i < D; i++)
+      {
+	p(i) = (nr & 1) ? pmax(i) : pmin(i);
+	nr >>= 1;
+      }
+    return p;
+  }
+
+
+  bool Intersect (const Box<D> & box2) const
+  {
+    for (int i = 0; i < D; i++)
+      if (pmin(i) > box2.pmax(i) ||
+	  pmax(i) < box2.pmin(i)) return 0;
+    return 1;
+  }
+
+
+  bool IsIn (const Point<D> & p) const
+  {
+    for (int i = 0; i < D; i++)
+      if (p(i) < pmin(i) || p(i) > pmax(i)) return 0;
+    return 1;
+  }
+
+
+  void Increase (double dist)
+  {
+    for (int i = 0; i < D; i++)
+      {
+	pmin(i) -= dist;
+	pmax(i) += dist;
+      }
+  }
+};
+
+
+
+
+template <int D>
+class BoxSphere : public Box<D>
+{
+protected:
+  ///
+  Point<D> c;
+  ///
+  double diam;
+  ///
+  double inner;
+public:
+  ///
+  BoxSphere () { };
+  ///
+  BoxSphere ( Point<D> pmin, Point<D> pmax )
+    : Box<D> (pmin, pmax)
+  {
+    CalcDiamCenter();
+  }
+
+  ///
+  const Point<D> & Center () const { return c; }
+  ///
+  double Diam () const { return diam; }
+  ///
+  double Inner () const { return inner; }
+
+
+  ///
+  void GetSubBox (int nr, BoxSphere & sbox) const
+  {
+    for (int i = 0; i < D; i++)
+      {
+	if (nr & 1)
+	  {
+	    sbox.pmin(i) = c(i);
+	    sbox.pmax(i) = this->pmax(i);
+	  }
+	else
+	  {
+	    sbox.pmin(i) = this->pmin(i);
+	    sbox.pmax(i) = c(i);
+	  }
+	sbox.c(i) = 0.5 * (sbox.pmin(i) + sbox.pmax(i));
+	nr >>= 1;
+      }
+    sbox.diam = 0.5 * diam;
+    sbox.inner = 0.5 * inner;
+  }
+
+
+  ///
+  void CalcDiamCenter ()
+  {
+    c = Box<D>::Center ();
+    diam = Dist (this->pmin, this->pmax);
+
+    inner = this->pmax(0) - this->pmin(0);
+    for (int i = 1; i < D; i++)
+      if (this->pmax(i) - this->pmin(i) < inner)
+	inner = this->pmax(i) - this->pmin(i);
+  }
+
+};
+
+
+
+
+
+
+#endif
diff --git a/Netgen/libsrc/gprim/geomobjects2.hpp b/Netgen/libsrc/gprim/geomobjects2.hpp
new file mode 100644
index 0000000000..014a38525a
--- /dev/null
+++ b/Netgen/libsrc/gprim/geomobjects2.hpp
@@ -0,0 +1,366 @@
+#ifndef FILE_OBJECTS
+#define FILE_OBJECTS
+
+/* *************************************************************************/
+/* File:   geomobjects.hpp                                                 */
+/* Author: Joachim Schoeberl                                               */
+/* Date:   20. Jul. 02                                                     */
+/* *************************************************************************/
+
+template <typename T>
+class VecExpr
+{
+public:
+  VecExpr () { ; }
+  double operator() (int i) const { return static_cast<const T&> (*this) (i); }
+};
+
+
+template <int D> class Vec;
+template <int D> class Point;
+
+
+template <int D>
+class Point : public VecExpr<Point<D> >
+{
+
+protected:
+  double x[D];
+
+public:
+  Point () { ; }
+  Point (double ax) { x[0] = ax; }
+  Point (double ax, double ay) { x[0] = ax; x[1] = ay; }
+  Point (double ax, double ay, double az)
+  { x[0] = ax; x[1] = ay; x[2] = az; }
+  Point (double ax, double ay, double az, double au)
+  { x[0] = ax; x[1] = ay; x[2] = az; x[3] = au;}
+
+  Point (const Point<D> & p2)
+  { for (int i = 0; i < D; i++) x[i] = p2.x[i]; }
+
+  explicit Point (const Vec<D> & v)
+  { for (int i = 0; i < D; i++) x[i] = v(i); }
+
+
+  template <typename T>
+  explicit Point (const VecExpr<T> & expr)
+  {
+    for (int i = 0; i < D; i++) x[i] = expr(i); 
+  }
+
+  Point & operator= (const Point<D> & p2)
+  {
+    for (int i = 0; i < D; i++) x[i] = p2.x[i]; 
+    return *this;
+  }
+
+  template <typename T>
+  Point & operator= (const VecExpr<T> & expr)
+  {
+    for (int i = 0; i < D; i++) x[i] = expr(i);
+    return *this;
+  }
+
+  double & operator() (int i) { return x[i]; }
+  const double & operator() (int i) const { return x[i]; }
+
+  operator const double* () const { return x; }
+};
+
+
+
+
+
+template <int D>
+class Vec : public VecExpr<Vec<D> >
+{
+
+protected:
+  double x[D];
+
+public:
+  Vec () { ; }
+  Vec (double ax) { for (int i = 0; i < D; i++) x[i] = ax; }
+  Vec (double ax, double ay) { x[0] = ax; x[1] = ay; }
+  Vec (double ax, double ay, double az)
+  { x[0] = ax; x[1] = ay; x[2] = az; }
+  Vec (double ax, double ay, double az, double au)
+  { x[0] = ax; x[1] = ay; x[2] = az; x[3] = au; }
+
+  Vec (const Vec<D> & p2)
+  { for (int i = 0; i < D; i++) x[i] = p2.x[i]; }
+
+  explicit Vec (const Point<D> & p)
+  { for (int i = 0; i < D; i++) x[i] = p(i); }
+
+  template <typename T>
+  explicit Vec (const VecExpr<T> & expr)
+  {
+    for (int i = 0; i < D; i++) x[i] = expr(i); 
+  }
+
+
+  Vec & operator= (const Vec<D> & p2)
+  {
+    for (int i = 0; i < D; i++) x[i] = p2.x[i]; 
+    return *this;
+  }
+
+  template <typename T>
+  Vec & operator= (const VecExpr<T> & expr)
+  {
+    for (int i = 0; i < D; i++) x[i] = expr(i);
+    return *this;
+  }
+
+  Vec & operator= (double s)
+  {
+    for (int i = 0; i < D; i++) x[i] = s;
+    return *this;
+  }
+
+  double & operator() (int i) { return x[i]; }
+  const double & operator() (int i) const { return x[i]; }
+
+  operator const double* () const { return x; }
+
+  double Length () const
+  {
+    double l = 0;
+    for (int i = 0; i < D; i++)
+      l += x[i] * x[i];
+    return sqrt (l);
+  }
+
+  double Length2 () const
+  {
+    double l = 0;
+    for (int i = 0; i < D; i++)
+      l += x[i] * x[i];
+    return l;
+  }
+
+  const Vec<D> & Normalize ()
+  {
+    double l = Length();
+    if (l != 0)
+      for (int i = 0; i < D; i++)
+	x[i] /= l;
+    return *this;
+  }
+
+  Vec<D> GetNormal () const;
+};
+
+
+
+
+
+template <int H, int W=H>
+class Mat
+{
+
+protected:
+  double x[H*W];
+
+public:
+  Mat () { ; }
+  Mat (const Mat & b)
+  { for (int i = 0; i < H*W; i++) x[i] = b.x[i]; }
+  
+  Mat & operator= (double s)
+  {
+    for (int i = 0; i < H*W; i++) x[i] = s;
+    return *this;
+  }
+
+  Mat & operator= (const Mat & b)
+  {
+    for (int i = 0; i < H*W; i++) x[i] = b.x[i]; 
+    return *this;
+  }
+
+  double & operator() (int i, int j) { return x[i*W+j]; }
+  const double & operator() (int i, int j) const { return x[i*W+j]; }
+
+  Vec<H> Col (int i) const
+  {
+    Vec<H> hv; 
+    for (int j = 0; j < H; j++)
+      hv(j) = x[j*W+i];
+    return hv; 
+  }
+
+  Vec<W> Row (int i) const
+  {
+    Vec<W> hv; 
+    for (int j = 0; j < W; j++)
+      hv(j) = x[i*W+j];
+    return hv; 
+  }
+
+  void Solve (const Vec<H> & rhs, Vec<W> & sol) const
+  {
+    Mat<W,H> inv;
+    CalcInverse (*this, inv);
+    sol = inv * rhs;
+  }
+};
+
+
+
+
+template <int D>
+class Box
+{
+protected:
+  Point<D> pmin, pmax;
+public:
+  Box () { ; }
+  Box ( const Point<D> & p1, const Point<D> & p2)
+  {
+    for (int i = 0; i < D; i++)
+      {
+	pmin(i) = min2(p1(i), p2(i));
+	pmax(i) = max2(p1(i), p2(i));
+      }
+  }
+
+  const Point<D> & PMin () const { return pmin; }
+  const Point<D> & PMax () const { return pmax; }
+  
+  void Set (const Point<D> & p)
+  { pmin = pmax = p; }
+
+  void Add (const Point<D> & p)
+  { 
+    for (int i = 0; i < D; i++)
+      {
+	if (p(i) < pmin(i)) pmin(i) = p(i);
+	else if (p(i) > pmax(i)) pmax(i) = p(i);
+      }
+  }
+
+  Point<D> Center () const 
+  { 
+    Point<D> c;
+    for (int i = 0; i < D; i++)
+      c(i) = 0.5 * (pmin(i)+pmax(i)); 
+    return c;
+  }
+  double Diam () const { return Abs (pmax-pmin); }
+
+  Point<D> GetPointNr (int nr) const
+  {
+    Point<D> p;
+    for (int i = 0; i < D; i++)
+      {
+	p(i) = (nr & 1) ? pmax(i) : pmin(i);
+	nr >>= 1;
+      }
+    return p;
+  }
+
+
+  bool Intersect (const Box<D> & box2) const
+  {
+    for (int i = 0; i < D; i++)
+      if (pmin(i) > box2.pmax(i) ||
+	  pmax(i) < box2.pmin(i)) return 0;
+    return 1;
+  }
+
+
+  bool IsIn (const Point<D> & p) const
+  {
+    for (int i = 0; i < D; i++)
+      if (p(i) < pmin(i) || p(i) > pmax(i)) return 0;
+    return 1;
+  }
+
+
+  void Increase (double dist)
+  {
+    for (int i = 0; i < D; i++)
+      {
+	pmin(i) -= dist;
+	pmax(i) += dist;
+      }
+  }
+};
+
+
+
+
+template <int D>
+class BoxSphere : public Box<D>
+{
+protected:
+  ///
+  Point<D> c;
+  ///
+  double diam;
+  ///
+  double inner;
+public:
+  ///
+  BoxSphere () { };
+  ///
+  BoxSphere ( Point<D> pmin, Point<D> pmax )
+    : Box<D> (pmin, pmax)
+  {
+    CalcDiamCenter();
+  }
+
+  ///
+  const Point<D> & Center () const { return c; }
+  ///
+  double Diam () const { return diam; }
+  ///
+  double Inner () const { return inner; }
+
+
+  ///
+  void GetSubBox (int nr, BoxSphere & sbox) const
+  {
+    for (int i = 0; i < D; i++)
+      {
+	if (nr & 1)
+	  {
+	    sbox.pmin(i) = c(i);
+	    sbox.pmax(i) = this->pmax(i);
+	  }
+	else
+	  {
+	    sbox.pmin(i) = this->pmin(i);
+	    sbox.pmax(i) = c(i);
+	  }
+	sbox.c(i) = 0.5 * (sbox.pmin(i) + sbox.pmax(i));
+	nr >>= 1;
+      }
+    sbox.diam = 0.5 * diam;
+    sbox.inner = 0.5 * inner;
+  }
+
+
+  ///
+  void CalcDiamCenter ()
+  {
+    c = Box<D>::Center ();
+    diam = Dist (this->pmin, this->pmax);
+
+    inner = this->pmax(0) - this->pmin(0);
+    for (int i = 1; i < D; i++)
+      if (this->pmax(i) - this->pmin(i) < inner)
+	inner = this->pmax(i) - this->pmin(i);
+  }
+
+};
+
+
+
+
+
+
+#endif
diff --git a/Netgen/libsrc/gprim/geomops.hpp b/Netgen/libsrc/gprim/geomops.hpp
new file mode 100644
index 0000000000..0b783c076b
--- /dev/null
+++ b/Netgen/libsrc/gprim/geomops.hpp
@@ -0,0 +1,374 @@
+#ifndef FILE_GEOMOPS
+#define FILE_GEOMOPS
+
+/* *************************************************************************/
+/* File:   geomops.hpp                                                     */
+/* Author: Joachim Schoeberl                                               */
+/* Date:   20. Jul. 02                                                     */
+/* *************************************************************************/
+
+
+/*
+
+Point - Vector operations
+
+ */
+
+
+template <int D>
+inline Vec<D> operator+ (const Vec<D> & a, const Vec<D> & b)
+{
+  Vec<D> res;
+  for (int i = 0; i < D; i++)
+    res(i) = a(i) + b(i);
+  return res;
+}
+
+
+
+template <int D>
+inline Point<D> operator+ (const Point<D> & a, const Vec<D> & b)
+{
+  Point<D> res;
+  for (int i = 0; i < D; i++)
+    res(i) = a(i) + b(i);
+  return res;
+}
+
+
+
+template <int D>
+inline Vec<D> operator- (const Point<D> & a, const Point<D> & b)
+{
+  Vec<D> res;
+  for (int i = 0; i < D; i++)
+    res(i) = a(i) - b(i);
+  return res;
+}
+
+template <int D>
+inline Point<D> operator- (const Point<D> & a, const Vec<D> & b)
+{
+  Point<D> res;
+  for (int i = 0; i < D; i++)
+    res(i) = a(i) - b(i);
+  return res;
+}
+
+template <int D>
+inline Vec<D> operator- (const Vec<D> & a, const Vec<D> & b)
+{
+  Vec<D> res;
+  for (int i = 0; i < D; i++)
+    res(i) = a(i) - b(i);
+  return res;
+}
+
+
+
+template <int D>
+inline Vec<D> operator* (double s, const Vec<D> & b)
+{
+  Vec<D> res;
+  for (int i = 0; i < D; i++)
+    res(i) = s * b(i);
+  return res;
+}
+
+
+template <int D>
+inline double operator* (const Vec<D> & a, const Vec<D> & b)
+{
+  double sum = 0;
+  for (int i = 0; i < D; i++)
+    sum += a(i) * b(i);
+  return sum;
+}
+
+
+
+template <int D>
+inline Vec<D> operator- (const Vec<D> & b)
+{
+  Vec<D> res;
+  for (int i = 0; i < D; i++)
+    res(i) = -b(i);
+  return res;
+}
+
+
+template <int D>
+inline Point<D> & operator+= (Point<D> & a, const Vec<D> & b)
+{
+  for (int i = 0; i < D; i++)
+    a(i) += b(i);
+  return a;
+}
+
+template <int D>
+inline Vec<D> & operator+= (Vec<D> & a, const Vec<D> & b)
+{
+  for (int i = 0; i < D; i++)
+    a(i) += b(i);
+  return a;
+}
+
+
+template <int D>
+inline Point<D> & operator-= (Point<D> & a, const Vec<D> & b)
+{
+  for (int i = 0; i < D; i++)
+    a(i) -= b(i);
+  return a;
+}
+
+template <int D>
+inline Vec<D> & operator-= (Vec<D> & a, const Vec<D> & b)
+{
+  for (int i = 0; i < D; i++)
+    a(i) -= b(i);
+  return a;
+}
+
+
+
+template <int D>
+inline Vec<D> & operator*= (Vec<D> & a, double s)
+{
+  for (int i = 0; i < D; i++)
+    a(i) *= s;
+  return a;
+}
+
+
+template <int D>
+inline Vec<D> & operator/= (Vec<D> & a, double s)
+{
+  for (int i = 0; i < D; i++)
+    a(i) /= s;
+  return a;
+}
+
+
+
+
+// Matrix - Vector operations
+
+/*
+template <int H, int W>
+inline Vec<H> operator* (const Mat<H,W> & m, const Vec<W> & v)
+{
+  Vec<H> res;
+  for (int i = 0; i < H; i++)
+    {
+      res(i) = 0;
+      for (int j = 0; j < W; j++)
+	res(i) += m(i,j) * v(j);
+    }
+  return res;
+}
+*/
+
+// thanks to VC60 partial template specialization features !!!
+
+inline Vec<2> operator* (const Mat<2,2> & m, const Vec<2> & v)
+{
+  Vec<2> res;
+  for (int i = 0; i < 2; i++)
+    {
+      res(i) = 0;
+      for (int j = 0; j < 2; j++)
+	res(i) += m(i,j) * v(j);
+    }
+  return res;
+}
+
+inline Vec<2> operator* (const Mat<2,3> & m, const Vec<3> & v)
+{
+  Vec<2> res;
+  for (int i = 0; i < 2; i++)
+    {
+      res(i) = 0;
+      for (int j = 0; j < 3; j++)
+	res(i) += m(i,j) * v(j);
+    }
+  return res;
+}
+
+
+inline Vec<3> operator* (const Mat<3,2> & m, const Vec<2> & v)
+{
+  Vec<3> res;
+  for (int i = 0; i < 3; i++)
+    {
+      res(i) = 0;
+      for (int j = 0; j < 2; j++)
+	res(i) += m(i,j) * v(j);
+    }
+  return res;
+}
+
+
+inline Vec<3> operator* (const Mat<3,3> & m, const Vec<3> & v)
+{
+  Vec<3> res;
+  for (int i = 0; i < 3; i++)
+    {
+      res(i) = 0;
+      for (int j = 0; j < 3; j++)
+	res(i) += m(i,j) * v(j);
+    }
+  return res;
+}
+
+
+
+
+
+
+
+/*
+template <int H1, int W1, int H2, int W2>
+inline Mat<H1,W2> operator* (const Mat<H1,W1> & a, const Mat<H2,W2> & b)
+{
+  Mat<H1,W2> m;
+  for (int i = 0; i < H1; i++)
+    for (int j = 0; j < W2; j++)
+      {
+	double sum = 0;
+	for (int k = 0; k < W1; k++)
+	  sum += a(i,k) * b(k, j);
+	m(i,j) = sum; 
+      }
+  return m;
+}
+*/
+
+inline Mat<2,2> operator* (const Mat<2,2> & a, const Mat<2,2> & b)
+{
+  Mat<2,2> m;
+  for (int i = 0; i < 2; i++)
+    for (int j = 0; j < 2; j++)
+      {
+	double sum = 0;
+	for (int k = 0; k < 2; k++)
+	  sum += a(i,k) * b(k, j);
+	m(i,j) = sum; 
+      }
+  return m;
+}
+
+inline Mat<2,2> operator* (const Mat<2,3> & a, const Mat<3,2> & b)
+{
+  Mat<2,2> m;
+  for (int i = 0; i < 2; i++)
+    for (int j = 0; j < 2; j++)
+      {
+	double sum = 0;
+	for (int k = 0; k < 3; k++)
+	  sum += a(i,k) * b(k, j);
+	m(i,j) = sum; 
+      }
+  return m;
+}
+
+
+inline Mat<3,2> operator* (const Mat<3,2> & a, const Mat<2,2> & b)
+{
+  Mat<3,2> m;
+  for (int i = 0; i < 3; i++)
+    for (int j = 0; j < 2; j++)
+      {
+	double sum = 0;
+	for (int k = 0; k < 2; k++)
+	  sum += a(i,k) * b(k, j);
+	m(i,j) = sum; 
+      }
+  return m;
+}
+
+inline Mat<3,3> operator* (const Mat<3,3> & a, const Mat<3,3> & b)
+{
+  Mat<3,3> m;
+  for (int i = 0; i < 3; i++)
+    for (int j = 0; j < 3; j++)
+      {
+	double sum = 0;
+	for (int k = 0; k < 3; k++)
+	  sum += a(i,k) * b(k, j);
+	m(i,j) = sum; 
+      }
+  return m;
+}
+
+
+
+
+
+
+
+
+template <int H, int W>
+inline Mat<W,H> Trans (const Mat<H,W> & m)
+{
+  Mat<W,H> res;
+  for (int i = 0; i < H; i++)
+    for (int j = 0; j < W; j++)
+      res(j,i) = m(i,j);
+  return res;
+}
+
+
+
+
+
+
+
+
+
+
+
+template <int D>
+inline ostream & operator<< (ostream & ost, const Vec<D> & a)
+{
+  ost << "(";
+  for (int i = 0; i < D-1; i++)
+    ost << a(i) << ", ";
+  ost << a(D-1) << ")";
+  return ost;
+}
+
+template <int D>
+inline ostream & operator<< (ostream & ost, const Point<D> & a)
+{
+  ost << "(";
+  for (int i = 0; i < D-1; i++)
+    ost << a(i) << ", ";
+  ost << a(D-1) << ")";
+  return ost;
+}
+
+template <int D>
+inline ostream & operator<< (ostream & ost, const Box<D> & b)
+{
+  ost << b.PMin() << " - " << b.PMax();
+  return ost;
+}
+
+template <int H, int W>
+inline ostream & operator<< (ostream & ost, const Mat<H,W> & m)
+{
+  ost << "(";
+  for (int i = 0; i < H; i++)
+    {
+      for (int j = 0; j < W; j++)
+	ost << m(i,j) << "   ";
+      ost << endl;
+    }
+  return ost;
+}
+
+
+
+
+#endif
diff --git a/Netgen/libsrc/gprim/geomops2.hpp b/Netgen/libsrc/gprim/geomops2.hpp
new file mode 100644
index 0000000000..c615da14ec
--- /dev/null
+++ b/Netgen/libsrc/gprim/geomops2.hpp
@@ -0,0 +1,428 @@
+#ifndef FILE_GEOMOPS
+#define FILE_GEOMOPS
+
+/* *************************************************************************/
+/* File:   geomops.hpp                                                     */
+/* Author: Joachim Schoeberl                                               */
+/* Date:   20. Jul. 02                                                     */
+/* *************************************************************************/
+
+
+/*
+
+Point - Vector operations
+
+ */
+
+
+
+
+template <class TA, class TB>
+class SumExpr : public VecExpr<SumExpr<TA, TB> >
+{
+  const TA a;
+  const TB b;
+public:
+  SumExpr (const TA aa, const TB ab) : a(aa), b(ab) { ; }
+  double operator() (int i) const { return a(i) + b(i); }
+};
+
+template <typename TA, typename TB>
+inline SumExpr<TA,TB>
+operator+ (const VecExpr<TA> & a, const VecExpr<TB> & b)
+{
+  return SumExpr<TA,TB> (static_cast <const TA&> (a), static_cast <const TB&> (b));
+}
+
+/*
+template <int D1, int D2>
+inline SumExpr<const Vec<D1>&, const Vec<D2>&>
+operator+ (const Vec<D1> & a, const Vec<D2> & b)
+{
+  return SumExpr<const Vec<D1>&, const Vec<D2>&> (a, b);
+}
+*/
+
+
+
+
+
+/*
+template <int D>
+inline Vec<D> operator+ (const Vec<D> & a, const Vec<D> & b)
+{
+  Vec<D> res;
+  for (int i = 0; i < D; i++)
+    res(i) = a(i) + b(i);
+  return res;
+}
+*/
+
+template <int D>
+inline Point<D> operator+ (const Point<D> & a, const Vec<D> & b)
+{
+  Point<D> res;
+  for (int i = 0; i < D; i++)
+    res(i) = a(i) + b(i);
+  return res;
+}
+
+
+template <int D>
+inline Vec<D> operator- (const Point<D> & a, const Point<D> & b)
+{
+  Vec<D> res;
+  for (int i = 0; i < D; i++)
+    res(i) = a(i) - b(i);
+  return res;
+}
+
+template <int D>
+inline Point<D> operator- (const Point<D> & a, const Vec<D> & b)
+{
+  Point<D> res;
+  for (int i = 0; i < D; i++)
+    res(i) = a(i) - b(i);
+  return res;
+}
+
+template <int D>
+inline Vec<D> operator- (const Vec<D> & a, const Vec<D> & b)
+{
+  Vec<D> res;
+  for (int i = 0; i < D; i++)
+    res(i) = a(i) - b(i);
+  return res;
+}
+
+
+template <int D>
+inline Vec<D> operator* (double s, const Vec<D> & b)
+{
+  Vec<D> res;
+  for (int i = 0; i < D; i++)
+    res(i) = s * b(i);
+  return res;
+}
+
+
+template <int D>
+inline double operator* (const Vec<D> & a, const Vec<D> & b)
+{
+  double sum = 0;
+  for (int i = 0; i < D; i++)
+    sum += a(i) * b(i);
+  return sum;
+}
+
+
+
+template <int D>
+inline Vec<D> operator- (const Vec<D> & b)
+{
+  Vec<D> res;
+  for (int i = 0; i < D; i++)
+    res(i) = -b(i);
+  return res;
+}
+
+
+template <int D>
+inline Point<D> & operator+= (Point<D> & a, const Vec<D> & b)
+{
+  for (int i = 0; i < D; i++)
+    a(i) += b(i);
+  return a;
+}
+
+
+template <int D, typename T>
+inline Point<D> & operator+= (Point<D> & a, const VecExpr<T> & b)
+{
+  for (int i = 0; i < D; i++)
+    a(i) += b(i);
+  return a;
+}
+
+template <int D>
+inline Vec<D> & operator+= (Vec<D> & a, const Vec<D> & b)
+{
+  for (int i = 0; i < D; i++)
+    a(i) += b(i);
+  return a;
+}
+
+
+
+
+
+template <int D>
+inline Point<D> & operator-= (Point<D> & a, const Vec<D> & b)
+{
+  for (int i = 0; i < D; i++)
+    a(i) -= b(i);
+  return a;
+}
+
+template <int D, typename T>
+inline Point<D> & operator-= (Point<D> & a, const VecExpr<T> & b)
+{
+  for (int i = 0; i < D; i++)
+    a(i) -= b(i);
+  return a;
+}
+
+
+
+
+
+template <int D>
+inline Vec<D> & operator-= (Vec<D> & a, const Vec<D> & b)
+{
+  for (int i = 0; i < D; i++)
+    a(i) -= b(i);
+  return a;
+}
+
+
+
+template <int D>
+inline Vec<D> & operator*= (Vec<D> & a, double s)
+{
+  for (int i = 0; i < D; i++)
+    a(i) *= s;
+  return a;
+}
+
+
+template <int D>
+inline Vec<D> & operator/= (Vec<D> & a, double s)
+{
+  for (int i = 0; i < D; i++)
+    a(i) /= s;
+  return a;
+}
+
+
+
+
+// Matrix - Vector operations
+
+/*
+template <int H, int W>
+inline Vec<H> operator* (const Mat<H,W> & m, const Vec<W> & v)
+{
+  Vec<H> res;
+  for (int i = 0; i < H; i++)
+    {
+      res(i) = 0;
+      for (int j = 0; j < W; j++)
+	res(i) += m(i,j) * v(j);
+    }
+  return res;
+}
+*/
+
+// thanks to VC60 partial template specialization features !!!
+
+inline Vec<2> operator* (const Mat<2,2> & m, const Vec<2> & v)
+{
+  Vec<2> res;
+  for (int i = 0; i < 2; i++)
+    {
+      res(i) = 0;
+      for (int j = 0; j < 2; j++)
+	res(i) += m(i,j) * v(j);
+    }
+  return res;
+}
+
+inline Vec<2> operator* (const Mat<2,3> & m, const Vec<3> & v)
+{
+  Vec<2> res;
+  for (int i = 0; i < 2; i++)
+    {
+      res(i) = 0;
+      for (int j = 0; j < 3; j++)
+	res(i) += m(i,j) * v(j);
+    }
+  return res;
+}
+
+
+inline Vec<3> operator* (const Mat<3,2> & m, const Vec<2> & v)
+{
+  Vec<3> res;
+  for (int i = 0; i < 3; i++)
+    {
+      res(i) = 0;
+      for (int j = 0; j < 2; j++)
+	res(i) += m(i,j) * v(j);
+    }
+  return res;
+}
+
+
+inline Vec<3> operator* (const Mat<3,3> & m, const Vec<3> & v)
+{
+  Vec<3> res;
+  for (int i = 0; i < 3; i++)
+    {
+      res(i) = 0;
+      for (int j = 0; j < 3; j++)
+	res(i) += m(i,j) * v(j);
+    }
+  return res;
+}
+
+
+
+
+
+
+
+/*
+template <int H1, int W1, int H2, int W2>
+inline Mat<H1,W2> operator* (const Mat<H1,W1> & a, const Mat<H2,W2> & b)
+{
+  Mat<H1,W2> m;
+  for (int i = 0; i < H1; i++)
+    for (int j = 0; j < W2; j++)
+      {
+	double sum = 0;
+	for (int k = 0; k < W1; k++)
+	  sum += a(i,k) * b(k, j);
+	m(i,j) = sum; 
+      }
+  return m;
+}
+*/
+
+inline Mat<2,2> operator* (const Mat<2,2> & a, const Mat<2,2> & b)
+{
+  Mat<2,2> m;
+  for (int i = 0; i < 2; i++)
+    for (int j = 0; j < 2; j++)
+      {
+	double sum = 0;
+	for (int k = 0; k < 2; k++)
+	  sum += a(i,k) * b(k, j);
+	m(i,j) = sum; 
+      }
+  return m;
+}
+
+inline Mat<2,2> operator* (const Mat<2,3> & a, const Mat<3,2> & b)
+{
+  Mat<2,2> m;
+  for (int i = 0; i < 2; i++)
+    for (int j = 0; j < 2; j++)
+      {
+	double sum = 0;
+	for (int k = 0; k < 3; k++)
+	  sum += a(i,k) * b(k, j);
+	m(i,j) = sum; 
+      }
+  return m;
+}
+
+
+inline Mat<3,2> operator* (const Mat<3,2> & a, const Mat<2,2> & b)
+{
+  Mat<3,2> m;
+  for (int i = 0; i < 3; i++)
+    for (int j = 0; j < 2; j++)
+      {
+	double sum = 0;
+	for (int k = 0; k < 2; k++)
+	  sum += a(i,k) * b(k, j);
+	m(i,j) = sum; 
+      }
+  return m;
+}
+
+inline Mat<3,3> operator* (const Mat<3,3> & a, const Mat<3,3> & b)
+{
+  Mat<3,3> m;
+  for (int i = 0; i < 3; i++)
+    for (int j = 0; j < 3; j++)
+      {
+	double sum = 0;
+	for (int k = 0; k < 3; k++)
+	  sum += a(i,k) * b(k, j);
+	m(i,j) = sum; 
+      }
+  return m;
+}
+
+
+
+
+
+
+
+
+template <int H, int W>
+inline Mat<W,H> Trans (const Mat<H,W> & m)
+{
+  Mat<W,H> res;
+  for (int i = 0; i < H; i++)
+    for (int j = 0; j < W; j++)
+      res(j,i) = m(i,j);
+  return res;
+}
+
+
+
+
+
+
+
+
+
+
+
+template <int D>
+inline ostream & operator<< (ostream & ost, const Vec<D> & a)
+{
+  ost << "(";
+  for (int i = 0; i < D-1; i++)
+    ost << a(i) << ", ";
+  ost << a(D-1) << ")";
+  return ost;
+}
+
+template <int D>
+inline ostream & operator<< (ostream & ost, const Point<D> & a)
+{
+  ost << "(";
+  for (int i = 0; i < D-1; i++)
+    ost << a(i) << ", ";
+  ost << a(D-1) << ")";
+  return ost;
+}
+
+template <int D>
+inline ostream & operator<< (ostream & ost, const Box<D> & b)
+{
+  ost << b.PMin() << " - " << b.PMax();
+  return ost;
+}
+
+template <int H, int W>
+inline ostream & operator<< (ostream & ost, const Mat<H,W> & m)
+{
+  ost << "(";
+  for (int i = 0; i < H; i++)
+    {
+      for (int j = 0; j < W; j++)
+	ost << m(i,j) << "   ";
+      ost << endl;
+    }
+  return ost;
+}
+
+
+
+
+#endif
diff --git a/Netgen/libsrc/gprim/geomtest3d.cpp b/Netgen/libsrc/gprim/geomtest3d.cpp
new file mode 100644
index 0000000000..14d1d58bd1
--- /dev/null
+++ b/Netgen/libsrc/gprim/geomtest3d.cpp
@@ -0,0 +1,1223 @@
+#include <mystdlib.h>
+#include <myadt.hpp>
+
+#include <linalg.hpp>
+#include <gprim.hpp>
+
+namespace netgen
+{
+int
+IntersectTriangleLine (const Point3d ** tri, const Point3d ** line)
+{
+  Vec3d vl(*line[0], *line[1]);
+  Vec3d vt1(*tri[0], *tri[1]);
+  Vec3d vt2(*tri[0], *tri[2]);
+  Vec3d vrs(*tri[0], *line[0]);
+
+  static DenseMatrix a(3), ainv(3);
+  static Vector rs(3), lami(3);
+  int i;
+
+  /*
+  (*testout) << "Tri-Line inters: " << endl
+	     << "tri = " << *tri[0] << ", " << *tri[1] << ", " << *tri[2] << endl
+	     << "line = " << *line[0] << ", " << *line[1] << endl;
+  */
+  for (i = 1; i <= 3; i++)
+    {
+      a.Elem(i, 1) = -vl.X(i);
+      a.Elem(i, 2) = vt1.X(i);
+      a.Elem(i, 3) = vt2.X(i);
+      rs.Elem(i) = vrs.X(i);
+    }
+
+  double det = a.Det();
+
+  double arel = vl.Length() * vt1.Length() * vt2.Length();
+  /*
+  double amax = 0;
+  for (i = 1; i <= 9; i++)
+    if (fabs (a.Get(i)) > amax)
+      amax = fabs(a.Get(i));
+  */
+  // new !!!!
+  if (fabs (det) <= 1e-10 * arel)
+    {
+#ifdef DEVELOP      
+      // line parallel to triangle !
+      // cout << "ERROR: IntersectTriangleLine degenerated" << endl;
+      //      (*testout) << "WARNING: IntersectTriangleLine degenerated\n";
+      /*
+      (*testout) << "lin-tri intersection: " << endl
+		 << "line = " << *line[0] << " - " << *line[1] << endl
+		 << "tri = " << *tri[0] << " - " << *tri[1] << " - " << *tri[2] << endl
+		 << "lami = " << lami << endl
+		 << "pc = " << ( *line[0] + lami.Get(1) * vl ) << endl
+		 << "   = " << ( *tri[0] + lami.Get(2) * vt1 + lami.Get(3) * vt2) << endl
+		 << " a = " << a << endl
+		 << " ainv = " << ainv << endl
+		 << " det(a) = " << det << endl
+		 << " rs = " << rs << endl;
+      */
+#endif
+      return 0;
+    }
+
+  CalcInverse (a, ainv);
+  ainv.Mult (rs, lami);
+
+  //  (*testout) << "lami = " << lami << endl;
+
+  double eps = 1e-6;
+  if (
+      (lami.Get(1) >= -eps && lami.Get(1) <= 1+eps && 
+       lami.Get(2) >= -eps && lami.Get(3) >= -eps && 
+       lami.Get(2) + lami.Get(3) <= 1+eps)  && !
+      (lami.Get(1) >= eps && lami.Get(1) <= 1-eps && 
+       lami.Get(2) >= eps && lami.Get(3) >= eps && 
+       lami.Get(2) + lami.Get(3) <= 1-eps) )
+
+
+     {
+#ifdef DEVELOP
+       //      cout << "WARNING: IntersectTriangleLine degenerated" << endl;
+      (*testout) << "WARNING: IntersectTriangleLine numerical inexact" << endl;
+
+      (*testout) << "lin-tri intersection: " << endl
+		 << "line = " << *line[0] << " - " << *line[1] << endl
+		 << "tri = " << *tri[0] << " - " << *tri[1] << " - " << *tri[2] << endl
+		 << "lami = " << lami << endl
+		 << "pc = " << ( *line[0] + lami.Get(1) * vl ) << endl
+		 << "   = " << ( *tri[0] + lami.Get(2) * vt1 + lami.Get(3) * vt2) << endl
+		 << " a = " << a << endl
+		 << " ainv = " << ainv << endl
+		 << " det(a) = " << det << endl
+		 << " rs = " << rs << endl;
+#endif
+    }
+      
+
+  if (lami.Get(1) >= 0 && lami.Get(1) <= 1 && 
+      lami.Get(2) >= 0 && lami.Get(3) >= 0 && lami.Get(2) + lami.Get(3) <= 1)
+    {
+
+      return 1;
+    }
+
+  return 0;
+}
+
+
+
+
+
+int IntersectTetTriangle (const Point3d ** tet, const Point3d ** tri,
+			  const int * tetpi, const int * tripi)
+{
+  int i, j;
+  double diam = Dist (*tri[0], *tri[1]);
+  double epsrel = 1e-8;
+  double eps = diam * epsrel;
+
+#ifdef MARK
+  MARK (inttettri1);
+#endif
+
+  double eps2 = eps * eps;
+  int loctripi[3], cnt = 0;
+  int loctetpi[4];
+
+  int tetp1 = -1, tetp2 = -1;
+  int trip1 = -1, trip2 = -1;
+  int tetp3, tetp4, trip3;
+
+  /*
+  for (i = 0; i < 4; i++)
+    loctetpi[i] = -1;
+  */
+
+
+  if (!tetpi)
+    {
+      for (i = 0; i <= 2; i++)
+	{
+	  //	  loctripi[i] = -1;
+	  for (j = 0; j <= 3; j++)
+	    {
+	      if (Dist2 (*tet[j], *tri[i]) < eps2)
+		{
+		  //		  loctripi[i] = j;
+		  //		  loctetpi[j] = i;
+		  cnt++;
+		  tetp2 = tetp1;
+		  tetp1 = j;
+		  trip2 = trip1;
+		  trip1 = i;
+		  break;
+		}
+	    }
+	}
+    }
+  else
+    {
+      for (i = 0; i <= 2; i++)
+	{
+	  //	  loctripi[i] = -1;
+	  for (j = 0; j <= 3; j++)
+	    {
+	      if (tetpi[j] == tripi[i])
+		{
+		  //		  loctripi[i] = j;
+		  //		  loctetpi[j] = i;
+		  cnt++;
+		  tetp2 = tetp1;
+		  tetp1 = j;
+		  trip2 = trip1;
+		  trip1 = i;
+		  break;
+		}
+	    }
+	}
+    }  
+  
+  //  (*testout) << "cnt = " << cnt << endl;
+
+#ifdef MARK
+  MARK (inttettri2);
+#endif
+
+
+  //  (*testout) << "tet-trig inters, cnt = " << cnt << endl;
+  
+  // cnt .. number of common points
+  switch (cnt)
+    {
+    case 0:
+      {
+#ifdef MARK
+  MARK (inttettric0);
+#endif
+
+	Vec3d no, n;
+	int inpi[3];
+
+	// check, if some trigpoint is in tet:
+
+	for (j = 0; j < 3; j++)
+	  inpi[j] = 1;
+
+	for (i = 1; i <= 4; i++)
+	  {
+	    int pi1 = i % 4;
+	    int pi2 = (i+1) % 4;
+	    int pi3 = (i+2) % 4;
+	    int pi4 = (i+3) % 4;
+
+	    Vec3d v1 (*tet[pi1], *tet[pi2]);
+	    Vec3d v2 (*tet[pi1], *tet[pi3]);
+	    Vec3d v3 (*tet[pi1], *tet[pi4]);
+	    Cross (v1, v2, n);
+
+	    // n /= n.Length();
+	    double nl = n.Length();
+
+	    if (v3 * n > 0)
+	      n *= -1;
+
+	    int outeri = 1;
+	    for (j = 0; j < 3; j++)
+	      {
+		Vec3d v(*tet[pi1], *tri[j]);
+		if ( v * n < eps * nl)
+		  outeri = 0;
+		else
+		  inpi[j] = 0;
+	      }
+
+	    if (outeri)
+	      return 0;
+	  }
+
+	if (inpi[0] || inpi[1] || inpi[2])
+	  {
+	    return 1;
+	  }
+
+
+	// check, if some tet edge intersects triangle:
+	const Point3d * line[2], *tetf[3];
+	for (i = 0; i <= 2; i++)
+	  for (j = i+1; j <= 3; j++)
+	    {
+	      line[0] = tet[i];
+	      line[1] = tet[j];
+
+	      if (IntersectTriangleLine (tri, &line[0]))
+		return 1;
+	    }
+
+	// check, if triangle line intersects tet face:
+	for (i = 0; i <= 3; i++)
+	  {
+	    for (j = 0; j <= 2; j++)
+	      tetf[j] = tet[(i+j) % 4];
+	    
+	    for (j = 0; j <= 2; j++)
+	      {
+		line[0] = tri[j];
+		line[1] = tri[(j+1) % 3];
+		
+		if (IntersectTriangleLine (&tetf[0], &line[0]))
+		  return 1;
+	      }
+	  }
+
+
+	return 0;
+//GH	break;
+      }
+    case 1:
+      {
+#ifdef MARK
+  MARK (inttettric1);
+#endif
+
+	trip2 = 0;
+	while (trip2 == trip1)
+	  trip2++;
+	trip3 = 3 - trip1 - trip2;
+
+	tetp2 = 0;
+	while (tetp2 == tetp1)
+	  tetp2++;
+	tetp3 = 0;
+	while (tetp3 == tetp1 || tetp3 == tetp2)
+	  tetp3++;
+	tetp4 = 6 - tetp1 - tetp2 - tetp3;
+
+	Vec3d vtri1 = *tri[trip2] - *tri[trip1];
+	Vec3d vtri2 = *tri[trip3] - *tri[trip1];
+	Vec3d ntri;
+	Cross (vtri1, vtri2, ntri);
+
+	// tri durch tet ?
+	// fehlt noch
+
+
+	// test 3 tet-faces:
+	for (i = 1; i <= 3; i++)
+	  {
+	    Vec3d vtet1, vtet2;
+	    switch (i)
+	      {
+	      case 1:
+		{
+		  vtet1 = *tet[tetp2] - *tet[tetp1];
+		  vtet2 = *tet[tetp3] - *tet[tetp1];
+		  break;
+		}
+	      case 2:
+		{
+		  vtet1 = *tet[tetp3] - *tet[tetp1];
+		  vtet2 = *tet[tetp4] - *tet[tetp1];
+		  break;
+		}
+	      case 3:
+		{
+		  vtet1 = *tet[tetp4] - *tet[tetp1];
+		  vtet2 = *tet[tetp2] - *tet[tetp1];
+		  break;
+		}
+	      }
+	    
+	    Vec3d ntet;
+	    Cross (vtet1, vtet2, ntet);
+	    
+	    Vec3d crline = Cross (ntri, ntet);
+
+	    double lcrline = crline.Length();
+
+	    if (lcrline < eps * eps * eps * eps)  // new change !
+	      continue;
+
+	    if (vtri1 * crline + vtri2 * crline < 0)
+	      crline *= -1;
+
+	    crline /= lcrline;
+
+	    double lam1, lam2, lam3, lam4;
+	    LocalCoordinates (vtri1, vtri2, crline, lam1, lam2);
+	    LocalCoordinates (vtet1, vtet2, crline, lam3, lam4);
+	    
+	    if (lam1 > -epsrel && lam2 > -epsrel &&
+		lam3 > -epsrel && lam4 > -epsrel)
+	      {
+		
+		/*
+		(*testout) << "lcrline = " << lcrline 
+			   << " eps = " << eps << " diam = " << diam << endl;
+		 
+		(*testout) << "hit, cnt == 1 " 
+			   << "lam1,2,3,4 = " << lam1 << ", " 
+			   << lam2 << ", " << lam3 << ", " << lam4
+			   << "\n";
+		*/
+		return 1;
+	      }
+	  }
+	return 0;
+//GH	break;
+      }
+    case 2:
+      {
+#ifdef MARK
+  MARK (inttettric2);
+#endif
+
+	// common edge
+	tetp3 = 0;
+	while (tetp3 == tetp1 || tetp3 == tetp2)
+	  tetp3++;
+	tetp4 = 6 - tetp1 - tetp2 - tetp3;
+	trip3 = 3 - trip1 - trip2;
+
+	//	(*testout) << "trip1,2,3 = " << trip1 << ", " << trip2 << ", " << trip3 << endl;
+	//	(*testout) << "tetp1,2,3,4 = " << tetp1 << ", " << tetp2 
+	//		   << ", " << tetp3 << ", " << tetp4 << endl;
+
+	Vec3d vtri = *tri[trip3] - *tri[trip1];
+	Vec3d vtet1 = *tet[tetp3] - *tri[trip1];
+	Vec3d vtet2 = *tet[tetp4] - *tri[trip1];
+
+	Vec3d n = *tri[trip2] - *tri[trip1];
+	n /= n.Length();
+
+	vtet1 -= (n * vtet1) * n;
+	vtet2 -= (n * vtet2) * n;
+
+
+	double lam1, lam2;
+	LocalCoordinates (vtet1, vtet2, vtri, lam1, lam2);
+	
+	if (lam1 < -epsrel || lam2 < -epsrel)
+	  return 0;
+	else
+	  {
+	    /*
+
+	    (*testout) << "vtet1 = " << vtet1 << endl;
+	    (*testout) << "vtet2 = " << vtet2 << endl;
+	    (*testout) << "vtri = " << vtri << endl;
+	    (*testout) << "lam1 = " << lam1 << " lam2 = " << lam2 << endl;
+	    (*testout) << (lam1 * (vtet1 * vtet1) + lam2 * (vtet1 * vtet2))
+		       << " = " << (vtet1 * vtri) << endl;
+	    (*testout) << (lam1 * (vtet1 * vtet2) + lam2 * (vtet2 * vtet2))
+		       << " = " << (vtet2 * vtri) << endl;
+	    
+	    (*testout) << "tet = ";
+	    for (j = 0; j < 4; j++)
+	      (*testout) << (*tet[j]) << " ";
+	    (*testout) << endl;
+	    (*testout) << "tri = ";
+	    for (j = 0; j < 3; j++)
+	      (*testout) << (*tri[j]) << " ";
+	    (*testout) << endl;
+
+	    (*testout) << "hit, cnt == 2" << endl;
+	    */
+	    
+	    return 1;
+	  }
+	  
+	break;
+      }
+    case 3:
+      {
+#ifdef MARK
+  MARK (inttettric3);
+#endif
+
+	// common face
+	return 0;
+      }
+    }
+
+  (*testout) << "hit, cnt = " << cnt << endl;
+  return 1;
+}
+
+
+
+
+
+int IntersectTetTriangleRef (const Point3d ** tri, const int * tripi)
+{
+  int i, j;
+  double eps = 1e-8;
+  double eps2 = eps * eps;
+
+  static Point3d rtetp1(0, 0, 0);
+  static Point3d rtetp2(1, 0, 0);  
+  static Point3d rtetp3(0, 1, 0); 
+  static Point3d rtetp4(0, 0, 1);
+
+  static const Point3d * tet[] = { &rtetp1, &rtetp2, &rtetp3, &rtetp4 };
+  static int tetpi[] = { 1, 2, 3, 4 };
+
+
+  //  return IntersectTetTriangle (tet, tri, tetpi, tripi);
+
+  
+  int cnt = 0;
+
+  int tetp1 = -1, tetp2 = -1;
+  int trip1 = -1, trip2 = -1;
+  int tetp3, tetp4, trip3;
+
+
+  if (!tetpi)
+    {
+      for (i = 0; i <= 2; i++)
+	{
+	  for (j = 0; j <= 3; j++)
+	    {
+	      if (Dist2 (*tet[j], *tri[i]) < eps2)
+		{
+		  cnt++;
+		  tetp2 = tetp1;
+		  tetp1 = j;
+		  trip2 = trip1;
+		  trip1 = i;
+		  break;
+		}
+	    }
+	}
+    }
+  else
+    {
+      for (i = 0; i <= 2; i++)
+	{
+	  for (j = 0; j <= 3; j++)
+	    {
+	      if (tetpi[j] == tripi[i])
+		{
+		  cnt++;
+		  tetp2 = tetp1;
+		  tetp1 = j;
+		  trip2 = trip1;
+		  trip1 = i;
+		  break;
+		}
+	    }
+	}
+    }  
+  
+  //  (*testout) << "cnt = " << cnt << endl;
+
+#ifdef MARK
+  MARK (inttettriref2);
+#endif
+  
+
+  switch (cnt)
+    {
+    case 0:
+      {
+#ifdef MARK
+  MARK (inttettric0ref);
+#endif
+
+	Vec3d no, n;
+	//	int inpi[3];
+	int pside[3][4];
+
+	for (j = 0; j < 3; j++)
+	  {
+	    pside[j][0] = (*tri[j]).X() > -eps;
+	    pside[j][1] = (*tri[j]).Y() > -eps;
+	    pside[j][2] = (*tri[j]).Z() > -eps;
+	    pside[j][3] = (*tri[j]).X() + (*tri[j]).Y() + (*tri[j]).Z() < 1+eps;
+	  }
+
+	
+	for (j = 0; j < 4; j++)
+	  {
+	    if (!pside[0][j] && !pside[1][j] && !pside[2][j])
+	      return 0;
+	  }
+
+	for (j = 0; j < 3; j++)
+	  {
+	    if (pside[j][0] && pside[j][1] && pside[j][2] && pside[j][3])
+	      return 1;
+	  }
+
+
+	const Point3d * line[2], *tetf[3];
+	for (i = 0; i <= 2; i++)
+	  for (j = i+1; j <= 3; j++)
+	    {
+	      line[0] = tet[i];
+	      line[1] = tet[j];
+
+	      if (IntersectTriangleLine (tri, &line[0]))
+		return 1;
+	    }
+
+	for (i = 0; i <= 3; i++)
+	  {
+	    for (j = 0; j <= 2; j++)
+	      tetf[j] = tet[(i+j) % 4];
+	    
+	    for (j = 0; j <= 2; j++)
+	      {
+		line[0] = tri[j];
+		line[1] = tri[(j+1) % 3];
+
+	      if (IntersectTriangleLine (&tetf[0], &line[0]))
+		return 1;
+	      }
+	  }
+
+
+	return 0;
+	break;
+      }
+    case 1:
+      {
+#ifdef MARK
+  MARK (inttettric1ref);
+#endif
+
+	trip2 = 0;
+	if (trip2 == trip1)
+	  trip2++;
+	trip3 = 3 - trip1 - trip2;
+
+	tetp2 = 0;
+	while (tetp2 == tetp1)
+	  tetp2++;
+	tetp3 = 0;
+	while (tetp3 == tetp1 || tetp3 == tetp2)
+	  tetp3++;
+	tetp4 = 6 - tetp1 - tetp2 - tetp3;
+
+	Vec3d vtri1 = *tri[trip2] - *tri[trip1];
+	Vec3d vtri2 = *tri[trip3] - *tri[trip1];
+	Vec3d ntri;
+	Cross (vtri1, vtri2, ntri);
+
+	// tri durch tet ?
+
+	/*
+	Vec3d vtet1(*tet[tetp1], *tet[tetp2]);
+	Vec3d vtet2(*tet[tetp1], *tet[tetp3]);
+	Vec3d vtet3(*tet[tetp1], *tet[tetp4]);
+	Vec3d sol;
+	
+	SolveLinearSystem (vtet1, vtet2, vtet3, vtri1, sol);
+	if (sol.X() > 0 && sol.Y() > 0 && sol.Z() > 0)
+	  return 1;
+
+	SolveLinearSystem (vtet1, vtet2, vtet3, vtri2, sol);
+	if (sol.X() > 0 && sol.Y() > 0 && sol.Z() > 0)
+	  return 1;
+	*/
+
+	// test 3 tet-faces:
+	for (i = 1; i <= 3; i++)
+	  {
+	    Vec3d vtet1, vtet2;
+	    switch (i)
+	      {
+	      case 1:
+		{
+		  vtet1 = *tet[tetp2] - *tet[tetp1];
+		  vtet2 = *tet[tetp3] - *tet[tetp1];
+		  break;
+		}
+	      case 2:
+		{
+		  vtet1 = *tet[tetp3] - *tet[tetp1];
+		  vtet2 = *tet[tetp4] - *tet[tetp1];
+		  break;
+		}
+	      case 3:
+		{
+		  vtet1 = *tet[tetp4] - *tet[tetp1];
+		  vtet2 = *tet[tetp2] - *tet[tetp1];
+		  break;
+		}
+	      }
+	    
+	    Vec3d ntet;
+	    Cross (vtet1, vtet2, ntet);
+	    
+	    Vec3d crline = Cross (ntri, ntet);
+
+	    double lcrline = crline.Length();
+	    if (lcrline < eps * eps)
+	      continue;
+
+
+	    if (vtri1 * crline + vtri2 * crline < 0)
+	      crline *= -1;
+
+	    double lam1, lam2, lam3, lam4;
+	    LocalCoordinates (vtri1, vtri2, crline, lam1, lam2);
+	    LocalCoordinates (vtet1, vtet2, crline, lam3, lam4);
+	    
+	    if (lam1 > -eps && lam2 > -eps &&
+		lam3 > -eps && lam4 > -eps)
+	      {
+		//		(*testout) << "hit, cnt == 1" << "\n";
+		return 1;
+	      }
+	  }
+
+	return 0;
+	break;
+      }
+    case 2:
+      {
+#ifdef MARK
+  MARK (inttettric2ref);
+#endif
+
+	// common edge
+	tetp3 = 0;
+	while (tetp3 == tetp1 || tetp3 == tetp2)
+	  tetp3++;
+	tetp4 = 6 - tetp1 - tetp2 - tetp3;
+	trip3 = 3 - trip1 - trip2;
+
+	//	(*testout) << "trip1,2,3 = " << trip1 << ", " << trip2 << ", " << trip3 << endl;
+	//	(*testout) << "tetp1,2,3,4 = " << tetp1 << ", " << tetp2 
+	//		   << ", " << tetp3 << ", " << tetp4 << endl;
+
+	Vec3d vtri = *tri[trip3] - *tri[trip1];
+	Vec3d vtet1 = *tet[tetp3] - *tri[trip1];
+	Vec3d vtet2 = *tet[tetp4] - *tri[trip1];
+
+	Vec3d n = *tri[trip2] - *tri[trip1];
+	n /= n.Length();
+
+	vtet1 -= (n * vtet1) * n;
+	vtet2 -= (n * vtet2) * n;
+
+
+	double lam1, lam2;
+	LocalCoordinates (vtet1, vtet2, vtri, lam1, lam2);
+	
+	if (lam1 < -eps || lam2 < -eps)
+	  return 0;
+	else
+	  {
+
+// 	    (*testout) << "vtet1 = " << vtet1 << endl;
+// 	    (*testout) << "vtet2 = " << vtet2 << endl;
+// 	    (*testout) << "vtri = " << vtri << endl;
+// 	    (*testout) << "lam1 = " << lam1 << " lam2 = " << lam2 << endl;
+
+// 	    (*testout) << (lam1 * (vtet1 * vtet1) + lam2 * (vtet1 * vtet2))
+// 		       << " = " << (vtet1 * vtri) << endl;
+// 	    (*testout) << (lam1 * (vtet1 * vtet2) + lam2 * (vtet2 * vtet2))
+// 		       << " = " << (vtet2 * vtri) << endl;
+	    
+// 	    (*testout) << "tet = ";
+// 	    for (j = 0; j < 4; j++)
+// 	      (*testout) << (*tet[j]) << " ";
+// 	    (*testout) << endl;
+// 	    (*testout) << "tri = ";
+// 	    for (j = 0; j < 3; j++)
+// 	      (*testout) << (*tri[j]) << " ";
+// 	    (*testout) << endl;
+
+// 	    (*testout) << "hit, cnt == 2" << endl;
+
+	    return 1;
+	  }
+	  
+	break;
+      }
+    case 3:
+      {
+#ifdef MARK
+  MARK (inttettric3ref);
+#endif
+
+	// common face
+	return 0;
+      }
+    }
+
+  (*testout) << "hit, cnt = " << cnt << endl;
+  return 1;
+}
+
+
+
+
+
+
+
+
+
+
+
+int IntersectTriangleTriangle (const Point3d ** tri1, const Point3d ** tri2)
+{
+  int i, j;
+  double diam = Dist (*tri1[0], *tri1[1]);
+  double epsrel = 1e-8;
+  double eps = diam * epsrel;
+  double eps2 = eps * eps;
+
+
+
+  int cnt = 0;
+  /*
+  int tri1pi[3];
+  int tri2pi[3];
+  */
+
+  //  int tri1p1 = -1; 
+  /// int tri1p2 = -1;
+  //  int tri2p1 = -1;
+  //   int tri2p2 = -1;
+  //  int tri1p3, tri2p3;
+
+  /*
+  for (i = 0; i < 3; i++)
+    tri1pi[i] = -1;
+  */
+  for (i = 0; i <= 2; i++)
+    {
+      //      tri2pi[i] = -1;
+      for (j = 0; j <= 2; j++)
+	{
+	  if (Dist2 (*tri1[j], *tri2[i]) < eps2)
+	    {
+	      //	      tri2pi[i] = j;
+	      //	      tri1pi[j] = i;
+	      cnt++;
+	      //	      tri1p2 = tri1p1;
+	      //	      tri1p1 = j;
+	      //	      tri2p2 = tri2p1;
+	      //	      tri2p1 = i;
+	      break;
+	    }
+	}
+    }
+  
+  switch (cnt)
+    {
+    case 0:
+      {
+	const Point3d * line[2];
+	
+	for (i = 0; i <= 2; i++)
+	  {
+	    line[0] = tri2[i];
+	    line[1] = tri2[(i+1)%3];
+
+	    if (IntersectTriangleLine (tri1, &line[0]))
+	      {
+		(*testout) << "int1, line = " << *line[0] << " - " << *line[1] << endl;
+		return 1;
+	      }
+	  }	
+
+	for (i = 0; i <= 2; i++)
+	  {
+	    line[0] = tri1[i];
+	    line[1] = tri1[(i+1)%3];
+
+	    if (IntersectTriangleLine (tri2, &line[0]))
+	      {
+		(*testout) << "int2, line = " << *line[0] << " - " << *line[1] << endl;
+		return 1;
+	      }
+	  }	
+	break;
+      }
+    default:
+      return 0;
+    }
+
+  return 0;
+}
+
+
+
+void
+LocalCoordinates (const Vec3d & e1, const Vec3d & e2,
+		  const Vec3d & v, double & lam1, double & lam2)
+{
+  double m11 = e1 * e1;
+  double m12 = e1 * e2;
+  double m22 = e2 * e2;
+  double rs1 = v * e1;
+  double rs2 = v * e2;
+  
+  double det = m11 * m22 - m12 * m12;
+  lam1 = (rs1 * m22 - rs2 * m12)/det;
+  lam2 = (m11 * rs2 - m12 * rs1)/det;
+}
+
+
+
+
+
+int CalcSphereCenter (const Point3d ** pts, Point3d & c)
+{
+  /*
+  static DenseMatrix a(3), inva(3);
+  static Vector rs(3), sol(3);
+  int i;
+  double h = Dist(*pts[0], *pts[1]);
+
+  for (i = 1; i <= 3; i++)
+    {
+      const Point3d & p1 = *pts[0];
+      const Point3d & p2 = *pts[i];
+      Vec3d v(p1, p2);
+      a.Elem(i,1) = v.X();
+      a.Elem(i,2) = v.Y();
+      a.Elem(i,3) = v.Z();
+
+      rs.Elem(i) = 0.5 * (v * v);
+    }
+
+  if (fabs (a.Det()) <= 1e-12 * h * h * h)
+    {
+      (*testout) << "CalcSphereCenter: degenerated" << endl;
+      return 1;
+    }
+
+  CalcInverse (a, inva);
+  inva.Mult (rs, sol);
+
+  for (i = 1; i <= 3; i++)
+    c.X(i) = pts[0]->X(i) + sol.Elem(i);
+  */
+
+  Vec3d row1 (*pts[0], *pts[1]);
+  Vec3d row2 (*pts[0], *pts[2]);
+  Vec3d row3 (*pts[0], *pts[3]);
+
+  Vec3d rhs(0.5 * (row1*row1),
+	    0.5 * (row2*row2),
+	    0.5 * (row3*row3));
+  Transpose (row1, row2, row3);
+  
+  Vec3d sol;
+  if (SolveLinearSystem (row1, row2, row3, rhs, sol))
+    {
+      (*testout) << "CalcSphereCenter: degenerated" << endl;
+      return 1;
+    }
+
+  c = *pts[0] + sol;
+  return 0;
+}
+
+
+
+
+
+int CalcTriangleCenter (const Point3d ** pts, Point3d & c)
+{
+  static DenseMatrix a(2), inva(2);
+  static Vector rs(2), sol(2);
+  double h = Dist(*pts[0], *pts[1]);
+
+  Vec3d v1(*pts[0], *pts[1]);
+  Vec3d v2(*pts[0], *pts[2]);
+
+  rs.Elem(1) = v1 * v1;
+  rs.Elem(2) = v2 * v2;
+
+  a.Elem(1,1) = 2 * rs.Get(1);
+  a.Elem(1,2) = a.Elem(2,1) = 2 * (v1 * v2);
+  a.Elem(2,2) = 2 * rs.Get(2);
+
+  if (fabs (a.Det()) <= 1e-12 * h * h)
+    {
+      (*testout) << "CalcTriangleCenter: degenerated" << endl;
+      return 1;
+    }
+
+  CalcInverse (a, inva);
+  inva.Mult (rs, sol);
+
+  c = *pts[0];
+  v1 *= sol.Get(1);
+  v2 *= sol.Get(2);
+
+  c += v1;
+  c += v2;
+
+  return 0;
+}
+
+
+
+double ComputeCylinderRadius (const Point3d & p1, 
+			      const Point3d & p2,
+			      const Point3d & p3, 
+			      const Point3d & p4)
+{
+  Vec3d v12(p1, p2);
+  Vec3d v13(p1, p3);
+  Vec3d v14(p1, p4);
+
+  Vec3d n1 = Cross (v12, v13);
+  Vec3d n2 = Cross (v14, v12);
+		
+  double n1l = n1.Length();
+  double n2l = n2.Length();
+  n1 /= n1l;
+  n2 /= n2l;
+
+  double v12len = v12.Length();
+  double h1 = n1l / v12len;
+  double h2 = n2l / v12len;
+  
+  /*
+  (*testout) << "n1 = " << n1 << " n2 = " << n2 
+	     << "h1 = " << h1 << " h2 = " << h2 << endl;
+  */
+  return ComputeCylinderRadius (n1, n2, h1, h2);
+}
+
+
+
+
+/*
+  Two triangles T1 and T2 have normals n1 and n2.
+  The height over the common edge is h1, and h2.
+ */
+double ComputeCylinderRadius (const Vec3d & n1, const Vec3d & n2,
+				     double h1, double h2)
+{
+  Vec3d t1, t2;
+  double n11 = n1 * n1;
+  double n12 = n1 * n2;
+  double n22 = n2 * n2;
+  double det = n11 * n22 - n12 * n12;
+  
+  if (fabs (det) < 1e-14 * n11 * n22)
+    return 1e20;
+
+  // a biorthogonal bases   (ti * nj) = delta_ij:
+  t1 = (n22/det) * n1 + (-n12/det) * n2;
+  t2 = (-n12/det) * n1 + (n11/det) * n2;
+
+  // normalize:
+  t1 /= t1.Length();
+  t2 /= t2.Length();
+
+  /*
+    vector to center point has form
+    v = lam1 n1 + lam2 n2
+    and fulfills
+    t2 v = h1/2
+    t1 v = h2/2
+  */
+
+  double lam1 = 0.5 * h2 / (n1 * t1);
+  double lam2 = 0.5 * h1 / (n2 * t2);
+  
+  double rad = (lam1 * n1 + lam2 * n2).Length();
+  /*
+  (*testout) << "n1 = " << n1
+	     << " n2 = " << n2
+	     << " t1 = " << t1
+	     << " t2 = " << t2
+	     << " rad = " << rad << endl;
+  */
+  return rad;
+}
+    
+
+
+
+
+
+double MinDistLP2 (const Point2d & lp1, const Point2d & lp2, const Point2d & p)
+{
+  Vec2d v(lp1, lp2);
+  Vec2d vlp(lp1, p);
+
+  // dist(lam) = \| vlp \|^2 - 2 lam (v1p, v) + lam^2 \| v \|^2
+
+  // lam = (v * vlp) / (v * v);
+  // if (lam < 0) lam = 0;
+  // if (lam > 1) lam = 1;
+
+  double num = v*vlp;
+  double den = v*v;
+
+  if (num <= 0) 
+    return Dist2 (lp1, p);
+
+  if (num >= den) 
+    return Dist2 (lp2, p);
+  
+  if (den > 0)
+    {
+      return vlp.Length2() - num * num /den;
+    }
+  else
+    return vlp.Length2();
+}
+
+
+
+
+double MinDistLP2 (const Point3d & lp1, const Point3d & lp2, const Point3d & p)
+{
+  Vec3d v(lp1, lp2);
+  Vec3d vlp(lp1, p);
+
+  // dist(lam) = \| vlp \|^2 - 2 lam (v1p, v) + lam^2 \| v \|^2
+
+  // lam = (v * vlp) / (v * v);
+  // if (lam < 0) lam = 0;
+  // if (lam > 1) lam = 1;
+
+  double num = v*vlp;
+  double den = v*v;
+
+  if (num <= 0) 
+    return Dist2 (lp1, p);
+
+  if (num >= den) 
+    return Dist2 (lp2, p);
+  
+  if (den > 0)
+    {
+      return vlp.Length2() - num * num /den;
+    }
+  else
+    return vlp.Length2();
+}
+
+
+
+double MinDistTP2 (const Point3d & tp1, const Point3d & tp2, 
+		   const Point3d & tp3, const Point3d & p)
+{
+  double lam1, lam2;
+  double res;
+
+  LocalCoordinates (Vec3d (tp1, tp2), Vec3d (tp1, tp3),
+		    Vec3d (tp1, p), lam1, lam2);
+  int in1 = lam1 >= 0;
+  int in2 = lam2 >= 0;
+  int in3 = lam1+lam2 <= 1;
+  
+  if (in1 && in2 && in3)
+    {
+      Point3d pp = tp1 + lam1 * Vec3d(tp1, tp2) + lam2 *  Vec3d (tp1, tp3);
+      res = Dist2 (p, pp);
+    }
+  else
+    {
+      res = Dist2 (tp1, p);
+      if (!in1)
+	{
+	  double hv = MinDistLP2 (tp1, tp3, p);
+	  if (hv < res) res = hv; 
+	}
+      if (!in2)
+	{
+	  double hv = MinDistLP2 (tp1, tp2, p);
+	  if (hv < res) res = hv; 
+	}
+      if (!in3)
+	{
+	  double hv = MinDistLP2 (tp2, tp3, p);
+	  if (hv < res) res = hv; 
+	}
+      /*
+      double d1 = MinDistLP2 (tp1, tp2, p);
+      double d2 = MinDistLP2 (tp1, tp3, p);
+      double d3 = MinDistLP2 (tp2, tp3, p);
+      res = min3 (d1, d2, d3);
+      */
+    }
+
+  return res;
+
+  Vec3d pp1(tp1, p);
+  Vec3d v1(tp1, tp2), v2(tp1, tp3);
+
+  double c = pp1.Length2();
+  double cx = -2 * (pp1 * v1);
+  double cy = -2 * (pp1 * v2);
+  double cxx = v1.Length2();
+  double cxy = 2 * (v1 * v2);
+  double cyy = v2.Length2();
+
+  QuadraticPolynomial2V pol (-c, -cx, -cy, -cxx, -cxy, -cyy);
+  double res2 =  - pol.MaxUnitTriangle ();
+
+  if (fabs (res - res2) > 1e-8)
+    cout << "res and res2 differ: " << res << " != " << res2 << endl;
+  return res2;
+}
+
+
+// 0 checks !!!
+double MinDistLL2 (const Point3d & l1p1, const Point3d & l1p2,
+		  const Point3d & l2p1, const Point3d & l2p2)
+{
+  // dist(lam1,lam2) = \| l2p1+lam2v2 - (l1p1+lam1 v1) \|
+  // min !
+
+  Vec3d l1l2 (l1p1, l2p1);
+  Vec3d v1 (l1p1, l1p2);
+  Vec3d v2 (l2p1, l2p2);
+
+  double a11, a12, a22, rs1, rs2;
+  double lam1, lam2, det;
+
+  a11 = v1*v1;
+  a12 = -(v1*v2);
+  a22 = v2*v2;
+  rs1 = l1l2 * v1;
+  rs2 = - (l1l2 * v2);
+  
+  det = a11 * a22 - a12 * a12;
+  if (det < 1e-14 * a11 * a22) 
+    det = 1e-14 * a11 * a22;  // regularization should be stable
+
+  if (det < 1e-20)
+    det = 1e-20;
+
+
+  lam1 = (a22 * rs1 - a12 * rs2) / det;
+  lam2 = (-a12 * rs1 + a11 * rs2) / det;
+
+  if (lam1 >= 0 && lam2 >= 0 && lam1 <= 1 && lam2 <= 1)
+    {
+      Vec3d v = l1l2 + (-lam1) * v1 + lam2 * v2;
+      return v.Length2();
+    }
+
+  double minv, hv;
+  minv = MinDistLP2 (l1p1, l1p2, l2p1);
+  hv =  MinDistLP2 (l1p1, l1p2, l2p2);
+  if (hv < minv) minv = hv;
+
+  hv =  MinDistLP2 (l2p1, l2p2, l1p1);
+  if (hv < minv) minv = hv;
+  hv =  MinDistLP2 (l2p1, l2p2, l1p2);
+  if (hv < minv) minv = hv;
+
+  return minv;
+}
+			 
+}
diff --git a/Netgen/libsrc/gprim/geomtest3d.hpp b/Netgen/libsrc/gprim/geomtest3d.hpp
new file mode 100644
index 0000000000..f801b8cdef
--- /dev/null
+++ b/Netgen/libsrc/gprim/geomtest3d.hpp
@@ -0,0 +1,80 @@
+#ifndef FILE_GEOMTEST3D
+#define FILE_GEOMTEST3D
+
+/* *************************************************************************/
+/* File:   geomtest3d.hh                                                   */
+/* Author: Joachim Schoeberl                                               */
+/* Date:   13. Feb. 98                                                     */
+/* *************************************************************************/
+
+
+
+extern int
+IntersectTriangleLine (const Point3d ** tri, const Point3d ** line);
+
+
+
+/**
+  Returns 0, iff
+  closure (tet)  cup  closure (tri)  is empty, one corner point of tet,
+  one edge of tet or one face of tet
+ */
+extern int 
+IntersectTetTriangle (const Point3d ** tet, const Point3d ** tri,
+		      const int * tetpi = NULL, const int * tripi = NULL);
+
+/**
+  Same test as above, but tet int reference position (0, ex, ey, ez),
+  tetpi = 1, 2, 4, 5
+ */
+extern int 
+IntersectTetTriangleRef (const Point3d ** tri, const int * tripi = NULL);
+
+
+// 1, iff not regular triangulation
+extern int 
+IntersectTriangleTriangle (const Point3d ** tri1, const Point3d ** tri2);
+
+
+extern void
+LocalCoordinates (const Vec3d & e1, const Vec3d & e2,
+		  const Vec3d & v, double & lam1, double & lam2);
+
+/// return 1 = degenerated sphere
+extern int
+CalcSphereCenter (const Point3d ** pts, Point3d & c);
+
+/// return 1 = degenerated triangle
+extern int
+CalcTriangleCenter (const Point3d ** pts, Point3d & c);
+
+
+
+/*
+  Compute radius of cylinder fitting 4 points.
+  cylinder axis is in the direction of p1-p2
+*/
+extern double ComputeCylinderRadius (const Point3d & p1, const Point3d & p2,
+				     const Point3d & p3, const Point3d & p4);
+
+/*
+  Two triangles T1 and T2 have normals n1 and n2.
+  The height over the common edge is h1, and h2.
+  Radius of cylinder fitting both triangles
+*/
+extern double ComputeCylinderRadius (const Vec3d & n1, const Vec3d & n2,
+				     double h1, double h2);
+
+
+extern double MinDistLP2 (const Point2d & lp1, const Point2d & lp2, const Point2d & p);
+
+extern double MinDistLP2 (const Point3d & lp1, const Point3d & lp2, const Point3d & p);
+
+extern double MinDistTP2 (const Point3d & tp1, const Point3d & tp2, 
+			  const Point3d & tp3, const Point3d & p);
+
+extern double MinDistLL2 (const Point3d & l1p1, const Point3d & l1p2,
+			  const Point3d & l2p1, const Point3d & l2p2);
+
+
+#endif
diff --git a/Netgen/libsrc/gprim/gprim.hpp b/Netgen/libsrc/gprim/gprim.hpp
new file mode 100644
index 0000000000..0f57ebac86
--- /dev/null
+++ b/Netgen/libsrc/gprim/gprim.hpp
@@ -0,0 +1,26 @@
+#ifndef FILE_GPRIM
+#define FILE_GPRIM
+
+/* *************************************************************************/
+/* File:   gprim.hpp                                                        */
+/* Author: Joachim Schoeberl                                               */
+/* Date:   14. Aug. 97                                                     */
+/* *************************************************************************/
+
+
+namespace netgen
+{
+#include "geomobjects.hpp"
+#include "geomops.hpp"
+#include "geomfuncs.hpp"
+
+#include "geom2d.hpp"
+#include "geom3d.hpp"
+#include "geomtest3d.hpp"
+// #include "rot3d.hpp"
+#include "transform3d.hpp"
+// #include "reftrans.hpp"
+#include "adtree.hpp"
+}
+
+#endif
diff --git a/Netgen/libsrc/gprim/testgeom.cpp b/Netgen/libsrc/gprim/testgeom.cpp
new file mode 100644
index 0000000000..8413f0f2b5
--- /dev/null
+++ b/Netgen/libsrc/gprim/testgeom.cpp
@@ -0,0 +1,20 @@
+#include <mystdlib.h>
+
+#include <myadt.hpp>
+#include <gprim.hpp>
+
+
+Vec<2> func1 (const Point<2> & a, const Point<2> & b)
+{
+  return a-b;
+}
+
+void func2 (Point<3> & a, Vec<3> & v)
+{
+  a += 3.4 * v;
+}
+
+void func3 (const Mat<2,2> & m, const Vec<2> & vc, Vec<2> & res)
+{
+  res += Trans (m) * vc;
+}
diff --git a/Netgen/libsrc/gprim/transform3d.cpp b/Netgen/libsrc/gprim/transform3d.cpp
new file mode 100644
index 0000000000..40ef4e3b2a
--- /dev/null
+++ b/Netgen/libsrc/gprim/transform3d.cpp
@@ -0,0 +1,172 @@
+#include <mystdlib.h>
+
+#include <myadt.hpp>
+#include <gprim.hpp>
+#include <linalg.hpp>
+
+namespace netgen
+{
+
+Transformation3d :: Transformation3d ()
+{
+  int i, j;
+  for (i = 0; i < 3; i++)
+    {
+      offset[i] = 0;
+      for (j = 0; j < 3; j++)
+	lin[i][j] = 0;
+    }
+}
+
+Transformation3d :: Transformation3d (const Vec3d & translate)
+{
+  int i, j;
+  for (i = 0; i < 3; i++)
+    for (j = 0; j < 3; j++)
+      lin[i][j] = 0;
+  for (i = 0; i < 3; i++)
+    {
+      offset[i] = translate.X(i+1);
+      lin[i][i] = 1;
+    }
+}
+
+
+Transformation3d :: 
+Transformation3d (const Point3d & c, double alpha, 
+		  double beta, double gamma)
+{
+  // total = T_c x Rot_0 x T_c^{-1}
+  // Use Euler angles, see many books from tech mech, e.g. 
+  // Shabana "multibody systems"
+
+  Transformation3d tc(c);
+  Transformation3d tcinv;
+  tc.CalcInverse (tcinv);
+
+  Transformation3d r1, r2, r3, ht, ht2;
+  r1.SetAxisRotation (3, alpha);
+  r2.SetAxisRotation (1, beta);
+  r3.SetAxisRotation (3, gamma);
+
+  ht.Combine (tc, r3);
+  ht2.Combine (ht, r2);
+  ht.Combine (ht2, r1);
+  Combine (ht, tcinv);
+
+  //  (*testout) << "Rotation - Transformation:" << (*this) << endl;
+}
+
+
+
+
+Transformation3d :: Transformation3d (const Point3d ** pp)
+{
+  int i, j;
+  for (i = 1; i <= 3; i++)
+    {
+      offset[i-1] = (*pp[0]).X(i);
+      for (j = 1; j <= 3; j++)
+	lin[i-1][j-1] = (*pp[j]).X(i) - (*pp[0]).X(i);
+    }
+}
+
+Transformation3d :: Transformation3d (const Point3d pp[])
+{
+  int i, j;
+  for (i = 1; i <= 3; i++)
+    {
+      offset[i-1] = pp[0].X(i);
+      for (j = 1; j <= 3; j++)
+	lin[i-1][j-1] = pp[j].X(i) - pp[0].X(i);
+    }
+}
+
+
+void Transformation3d :: CalcInverse (Transformation3d & inv) const
+{
+  static DenseMatrix a(3), inva(3);
+  static Vector b(3), sol(3);
+  int i, j;
+  
+  for (i = 1; i <= 3; i++)
+    {
+      b.Elem(i) = offset[i-1];
+      for (j = 1; j <= 3; j++)
+	a.Elem(i, j) = lin[i-1][j-1];
+    }
+
+  ::netgen::CalcInverse (a, inva);
+  inva.Mult (b, sol);
+
+  for (i = 1; i <= 3; i++)
+    {
+      inv.offset[i-1] = -sol.Get(i);
+      for (j = 1; j <= 3; j++)
+	inv.lin[i-1][j-1] = inva.Elem(i, j);
+    }
+}
+
+
+void  Transformation3d:: 
+Combine (const Transformation3d & ta, const Transformation3d & tb)
+{
+  int i, j, k;
+
+  // o = o_a+ m_a o_b
+  // m = m_a m_b
+
+  for (i = 0; i <= 2; i++)
+    {
+      offset[i] = ta.offset[i];
+      for (j = 0; j <= 2; j++)
+	offset[i] += ta.lin[i][j] * tb.offset[j];
+    }
+  
+  for (i = 0; i <= 2; i++)
+    for (j = 0; j <= 2; j++)
+      {
+	lin[i][j] = 0;
+	for (k = 0; k <= 2; k++)
+	  lin[i][j] += ta.lin[i][k] * tb.lin[k][j];
+      }
+}
+void Transformation3d :: SetAxisRotation (int dir, double alpha)
+{
+  double co = cos(alpha);
+  double si = sin(alpha);
+  dir--;
+  int pos1 = (dir+1) % 3;
+  int pos2 = (dir+2) % 3;
+
+  int i, j;
+  for (i = 0; i <= 2; i++)
+    {
+      offset[i] = 0;
+      for (j = 0; j <= 2; j++)
+	lin[i][j] = 0;
+    }
+
+  lin[dir][dir] = 1;
+  lin[pos1][pos1] = co;
+  lin[pos2][pos2] = co;
+  lin[pos1][pos2] = si;
+  lin[pos2][pos1] = -si;
+}
+
+ostream & operator<< (ostream & ost, Transformation3d & trans)
+{
+  int i, j;
+  ost << "offset = ";
+  for (i = 0; i <= 2; i++)
+    ost << trans.offset[i] << " ";
+  ost << endl << "linear = " << endl;
+  for (i = 0; i <= 2; i++)
+    {
+      for (j = 0; j <= 2; j++)
+	ost << trans.lin[i][j] << " ";
+      ost << endl;
+    }
+  return ost;
+}
+}
diff --git a/Netgen/libsrc/gprim/transform3d.hpp b/Netgen/libsrc/gprim/transform3d.hpp
new file mode 100644
index 0000000000..9eccc5a7f9
--- /dev/null
+++ b/Netgen/libsrc/gprim/transform3d.hpp
@@ -0,0 +1,131 @@
+#ifndef FILE_TRANSFORM3D
+#define FILE_TRANSFORM3D
+
+/* *************************************************************************/
+/* File:   transform3d.hh                                                  */
+/* Author: Joachim Schoeberl                                               */
+/* Date:   22. Mar. 98                                                     */
+/* *************************************************************************/
+
+/*
+  Affine - Linear mapping in 3D space
+ */
+
+class Transformation3d;
+ostream & operator<< (ostream & ost, Transformation3d & trans);
+
+class Transformation3d
+{
+  double lin[3][3];
+  double offset[3];
+public:
+  ///
+  Transformation3d ();
+  /// Unit tet is mapped to tet descibed by pp
+  Transformation3d (const Point3d ** pp);
+  /// Unit tet is mapped to tet descibed by pp
+  Transformation3d (const Point3d pp[]);
+  /// translation
+  Transformation3d (const Vec3d & translate);
+  /// rotation with ...
+  Transformation3d (const Point3d & c, double alpha, double beta, double gamma);
+  /// 
+  void CalcInverse (Transformation3d & inv) const;
+  /// this = ta x tb
+  void Combine (const Transformation3d & ta, const Transformation3d & tb);
+  /// dir = 1..3 (== x..z)
+  void SetAxisRotation (int dir, double alpha);
+  ///
+  void Transform (const Point3d & from, Point3d & to) const
+    {
+      for (int i = 1; i <= 3; i++)
+	{
+	  to.X(i) = offset[i-1] + lin[i-1][0] * from.X(1) + 
+	    lin[i-1][1] * from.X(2) + lin[i-1][2] * from.X(3);
+	}
+    }
+  /// transform vector, apply only linear part, not offset
+  void Transform (const Vec3d & from, Vec3d & to) const
+    {
+      for (int i = 1; i <= 3; i++)
+	{
+	  to.X(i) = lin[i-1][0] * from.X(1) + 
+	    lin[i-1][1] * from.X(2) + lin[i-1][2] * from.X(3);
+	}
+    }
+  friend ostream & operator<< (ostream & ost, Transformation3d & trans);
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+template <int D>
+class Transformation
+{
+  Mat<D> m;
+  Vec<D> v;
+public:
+  ///
+  Transformation () { m = 0; v = 0; }
+
+  /// Unit tet is mapped to tet descibed by pp
+  Transformation (const Point<D> * pp);
+
+  /// translation
+  Transformation (const Vec<D> & translate)
+  {
+    v = translate;
+    m = 0;
+    for (int i = 0; i < D; i++)
+      m(i,i) = 1;
+  }
+
+  // rotation with ...
+  Transformation (const Point<D> & c, double alpha, double beta, double gamma)
+  {
+    ;
+  }
+
+  /// 
+  void CalcInverse (Transformation & inv) const;
+
+  /// this = ta x tb
+  void Combine (const Transformation & ta, const Transformation & tb)
+  {
+    v = ta.v + ta.m * tb.v;
+    m = ta.m * tb.m;
+  }
+
+  /// dir = 1..3 (== x..z)
+  void SetAxisRotation (int dir, double alpha);
+
+  ///
+  void Transform (const Point<D> & from, Point<D> & to) const
+  {
+    to = Point<D> (v + m * Vec<D>(from));
+  }
+
+  /// transform vector, apply only linear part, not offset
+  void Transform (const Vec<D> & from, Vec<D> & to) const
+  {
+    to = m * from;
+  }
+};
+
+template <int D>
+ostream & operator<< (ostream & ost, Transformation<D> & trans);
+
+
+
+
+#endif
diff --git a/Netgen/libsrc/include/csg.hpp b/Netgen/libsrc/include/csg.hpp
new file mode 100644
index 0000000000..ffd45ef0bf
--- /dev/null
+++ b/Netgen/libsrc/include/csg.hpp
@@ -0,0 +1 @@
+#include "../csg/csg.hpp"
diff --git a/Netgen/libsrc/include/geometry2d.hpp b/Netgen/libsrc/include/geometry2d.hpp
new file mode 100644
index 0000000000..bf0965c228
--- /dev/null
+++ b/Netgen/libsrc/include/geometry2d.hpp
@@ -0,0 +1 @@
+#include "../geom2d/geometry2d.hpp"
diff --git a/Netgen/libsrc/include/gprim.hpp b/Netgen/libsrc/include/gprim.hpp
new file mode 100644
index 0000000000..1e827aaf8c
--- /dev/null
+++ b/Netgen/libsrc/include/gprim.hpp
@@ -0,0 +1 @@
+#include "../gprim/gprim.hpp"
diff --git a/Netgen/libsrc/include/incvis.hpp b/Netgen/libsrc/include/incvis.hpp
new file mode 100644
index 0000000000..a38e918698
--- /dev/null
+++ b/Netgen/libsrc/include/incvis.hpp
@@ -0,0 +1,33 @@
+// libraries for User interface:
+
+/*
+#include <tcl8.3.h>
+#include <tk8.3.h>
+
+#include <GL/gl.h>
+#include <GL/glu.h>
+#include "../togl/togl.h"
+
+#include <tix8.1.h>
+*/
+
+
+#include <tcl.h>
+#include <tk.h>
+
+
+#if TK_MAJOR_VERSION==8 && TK_MINOR_VERSION==4
+#define tcl_const const
+#else
+#define tcl_const
+#endif
+
+
+#include <GL/gl.h>
+#include <GL/glu.h>
+#include "../../togl/togl.h"
+
+
+
+// Just the init-call
+// #include <tix.h>
diff --git a/Netgen/libsrc/include/linalg.hpp b/Netgen/libsrc/include/linalg.hpp
new file mode 100644
index 0000000000..e96bd036c3
--- /dev/null
+++ b/Netgen/libsrc/include/linalg.hpp
@@ -0,0 +1 @@
+#include "../linalg/linalg.hpp"
diff --git a/Netgen/libsrc/include/meshing.hpp b/Netgen/libsrc/include/meshing.hpp
new file mode 100644
index 0000000000..e41a88f9f2
--- /dev/null
+++ b/Netgen/libsrc/include/meshing.hpp
@@ -0,0 +1 @@
+#include <../meshing/meshing.hpp>
diff --git a/Netgen/libsrc/include/myadt.hpp b/Netgen/libsrc/include/myadt.hpp
new file mode 100644
index 0000000000..d36bef05c1
--- /dev/null
+++ b/Netgen/libsrc/include/myadt.hpp
@@ -0,0 +1 @@
+#include <../general/myadt.hpp>
diff --git a/Netgen/libsrc/include/mydefs.hpp b/Netgen/libsrc/include/mydefs.hpp
new file mode 100644
index 0000000000..c34ce56a8e
--- /dev/null
+++ b/Netgen/libsrc/include/mydefs.hpp
@@ -0,0 +1,29 @@
+#ifndef FILE_MYDEFS
+#define FILE_MYDEFS
+
+/**************************************************************************/
+/* File:   mydefs.hh                                                      */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   10. Mar. 98                                                    */
+/**************************************************************************/
+
+/*
+  defines for graphics, testmodes, ...
+*/
+
+
+// #define DEBUG
+
+
+#define noDEMOVERSION
+#define noDEVELOP
+#define noSTEP
+#define noSOLIDGEOM
+
+#define noDEMOAPP
+#define noMODELLER
+
+#define noSTAT_STREAM
+#define noLOG_STREAM
+
+#endif
diff --git a/Netgen/libsrc/include/occgeom.hpp b/Netgen/libsrc/include/occgeom.hpp
new file mode 100644
index 0000000000..af258e0df0
--- /dev/null
+++ b/Netgen/libsrc/include/occgeom.hpp
@@ -0,0 +1 @@
+#include "../occ/occgeom.hpp"
diff --git a/Netgen/libsrc/include/opti.hpp b/Netgen/libsrc/include/opti.hpp
new file mode 100644
index 0000000000..6b8a0b61c8
--- /dev/null
+++ b/Netgen/libsrc/include/opti.hpp
@@ -0,0 +1 @@
+#include "../opti/opti.hpp"
diff --git a/Netgen/libsrc/include/stepgeom.hpp b/Netgen/libsrc/include/stepgeom.hpp
new file mode 100644
index 0000000000..d2c5c5e41e
--- /dev/null
+++ b/Netgen/libsrc/include/stepgeom.hpp
@@ -0,0 +1,10 @@
+#include "../stepgeom/geomanif.hh"
+#include "../stepgeom/geopac2d.hh"
+#include "../stepgeom/geopac3d.hh"
+#include "../stepgeom/geosplinesurf.hh"
+#include "../stepgeom/algprim.hh"
+#include "../stepgeom/scenery.hh"
+#include "../stepgeom/brep.hh"
+#include "../stepgeom/adtcrit.hh"
+#include "../stepgeom/STEPgeom.hh"
+#include "../stepgeom/visapprox.hh"
diff --git a/Netgen/libsrc/include/stepreader.hpp b/Netgen/libsrc/include/stepreader.hpp
new file mode 100644
index 0000000000..0214d58d9d
--- /dev/null
+++ b/Netgen/libsrc/include/stepreader.hpp
@@ -0,0 +1 @@
+#include "../stepgeom/STEPread.hh"
diff --git a/Netgen/libsrc/include/stlgeom.hpp b/Netgen/libsrc/include/stlgeom.hpp
new file mode 100644
index 0000000000..f1eea264e1
--- /dev/null
+++ b/Netgen/libsrc/include/stlgeom.hpp
@@ -0,0 +1 @@
+#include <../stlgeom/stlgeom.hpp>
diff --git a/Netgen/libsrc/include/visual.hpp b/Netgen/libsrc/include/visual.hpp
new file mode 100644
index 0000000000..f026f5a458
--- /dev/null
+++ b/Netgen/libsrc/include/visual.hpp
@@ -0,0 +1 @@
+#include "../visualization/visual.hpp"
diff --git a/Netgen/libsrc/interface/Makefile b/Netgen/libsrc/interface/Makefile
new file mode 100644
index 0000000000..98d943a028
--- /dev/null
+++ b/Netgen/libsrc/interface/Makefile
@@ -0,0 +1,7 @@
+src = nginterface.cpp writeuser.cpp writediffpack.cpp writeabaqus.cpp writefluent.cpp writepermas.cpp writetochnog.cpp writetecplot.cpp wuchemnitz.cpp writetochnog.cpp writefeap.cpp readuser.cpp importsolution.cpp
+#
+lib = nginterface
+libpath = libsrc/interface
+#
+include ../makefile.inc
+#
diff --git a/Netgen/libsrc/interface/importsolution.cpp b/Netgen/libsrc/interface/importsolution.cpp
new file mode 100644
index 0000000000..3973d3927e
--- /dev/null
+++ b/Netgen/libsrc/interface/importsolution.cpp
@@ -0,0 +1,121 @@
+//
+//  Read solution file
+//
+
+
+#include <mystdlib.h>
+
+
+#include <myadt.hpp>
+#include <linalg.hpp>
+#include <csg.hpp>
+#include <meshing.hpp>
+
+#include "nginterface.h"
+
+namespace netgen
+{
+#include "writeuser.hpp"
+
+
+void ImportSolution (const char * filename)
+{
+  ifstream inf (filename);
+  char buf[100], name[1000];
+  int i, j, size, comps, order;
+  bool iscomplex;
+  const char * type;
+  Flags flags;
+
+  while (1)
+    {
+      buf[0] = 0;
+      inf >> buf;
+      if (strcmp (buf, "solution") == 0)
+	{
+	  inf >> name;
+	  
+	  inf >> buf[0];
+	  flags.DeleteFlags ();
+	  while (buf[0] == '-')
+	    {
+	      inf >> buf[1];
+	      inf.putback (buf[1]);
+	      if (!isalpha (buf[1]))
+		{
+		  break;
+		}
+	      inf >> (buf+1);
+	      flags.SetCommandLineFlag (buf);
+	      buf[0] = 0;
+	      inf >> buf[0];
+	    }
+	  inf.putback (buf[0]);
+
+	  (*testout) << "Flags: " << endl;
+	  flags.PrintFlags (*testout);
+	  (*testout) << "done" << endl;
+
+	  size = int(flags.GetNumFlag ("size", Ng_GetNP()));
+	  comps = int(flags.GetNumFlag ("components", 1));
+	  type = flags.GetStringFlag ("type", "nodal");
+	  order = int(flags.GetNumFlag ("order", 1));
+	  iscomplex = flags.GetDefineFlag ("complex");
+
+	  double * sol = new double[size*comps];
+	  
+	  (*testout) << "import solution " << name << " size = " << size << " comps = " << comps << " order = " << order << endl;
+
+	  for (i = 0; i < size*comps; i++)
+	    {
+	      inf >> sol[i];
+	      //	      (*testout) << "sol: " << sol[i] << endl;
+	    }
+	  
+	  Ng_SolutionData soldata;
+	  Ng_InitSolutionData (&soldata);
+	  soldata.name = name;
+	  soldata.data = sol;
+	  soldata.dist = comps;
+	  soldata.components = comps;
+	  soldata.order = order;
+	  soldata.iscomplex = iscomplex;
+	  soldata.soltype = NG_SOLUTION_NODAL;
+	  if (strcmp (type, "element") == 0)
+	    soldata.soltype = NG_SOLUTION_ELEMENT;
+	  if (strcmp (type, "surfaceelement") == 0)
+	    soldata.soltype = NG_SOLUTION_SURFACE_ELEMENT;
+	  if (strcmp (type, "noncontinuous") == 0)
+	    soldata.soltype = NG_SOLUTION_NONCONTINUOUS;
+	  if (strcmp (type, "surfacenoncontinuous") == 0)
+	    soldata.soltype = NG_SOLUTION_SURFACE_NONCONTINUOUS;
+
+	  Ng_SetSolutionData (&soldata);
+	  }
+      else
+	{
+	  //	  cout << "kw = (" << buf << ")" << endl;
+	  (*testout) << "kw = (" << buf << ")" << endl;
+	  break;
+	}
+    }
+  /*
+  struct Ng_SolutionData
+    {
+      char * name;      // name of gridfunction
+      double * data;    // solution values
+      int components;   // used components in solution vector
+      int dist;         // num of doubles per entry (alignment!)
+      Ng_SolutionType soltype;  // type of solution function
+  };
+
+  // initialize solution data with default arguments
+  void Ng_InitSolutionData (Ng_SolutionData * soldata);
+  // set solution data
+  void Ng_SetSolutionData (Ng_SolutionData * soldata);
+  */
+}
+
+
+
+}
diff --git a/Netgen/libsrc/interface/nginterface.cpp b/Netgen/libsrc/interface/nginterface.cpp
new file mode 100644
index 0000000000..5510f28a27
--- /dev/null
+++ b/Netgen/libsrc/interface/nginterface.cpp
@@ -0,0 +1,1301 @@
+#include <mystdlib.h>
+
+
+#include <meshing.hpp>
+#include <csg.hpp>
+#include <geometry2d.hpp>
+#include <stlgeom.hpp>
+
+#include <visual.hpp>
+
+#include "nginterface.h"
+// #include <FlexLexer.h>
+
+
+
+
+namespace netgen
+{
+  extern AutoPtr<Mesh> mesh;
+  extern VisualSceneMesh vsmesh;
+  extern Tcl_Interp * tcl_interp;
+
+  extern SplineGeometry2d * geometry2d;
+  extern CSGeometry * parsegeom;
+  extern CSGeometry * geometry;
+  extern STLGeometry * stlgeometry;
+
+  extern VisualSceneSolution vssolution;
+  extern CSGeometry * ParseCSG (istream & istr);
+}
+
+
+using namespace netgen;
+
+/*
+  extern void * operator new (size_t s);
+  extern void * operator new [] (size_t s);
+  extern void operator delete (void * p);
+  extern void operator delete [] (void * p);
+*/
+
+// extern FlexLexer * lexer;
+
+
+
+void Ng_LoadGeometry (char * filename)
+{
+  ifstream infile (filename);
+
+  if (geometry) 
+    delete geometry;
+
+  if (strcmp (&filename[strlen(filename)-3], "geo") == 0)
+    {
+      /*
+      geometry = new CSGeometry(filename);
+      
+      parsegeom = geometry;
+      
+      lexer = new yyFlexLexer (&infile);
+      
+      extern int yyparse ();
+      yyparse ();
+      delete lexer; 
+      */
+
+      geometry = netgen::ParseCSG (infile);
+
+      if (!geometry)
+	throw NgException ("input file not found");
+
+      geometry -> FindIdenticSurfaces(1e-6);
+      Box<3> box (geometry->BoundingBox());
+
+      geometry->CalcTriangleApproximation (box, 0.01, 10);
+    }
+  else
+    {
+      geometry = new CSGeometry("");
+
+      if (strcmp (&filename[strlen(filename)-4], "in2d") == 0)
+	{
+
+	  if (geometry2d)
+	    delete geometry2d;
+	  geometry2d = new SplineGeometry2d();
+	  geometry2d -> Load (filename);
+	}
+
+      else
+	{
+	  cerr << "Unknown geometry extension!!" << endl;
+	}
+    }
+}                          
+
+
+void Ng_LoadMesh (char * filename)
+{
+  mesh.Reset (new Mesh());
+  mesh->Load (filename);
+}
+
+
+
+int Ng_GetDimension ()
+{
+  return mesh->GetDimension();
+}
+
+int Ng_GetNP ()
+{
+  return mesh->GetNP();
+}
+
+int Ng_GetNV ()
+{
+  return mesh->GetNV();
+}
+
+int Ng_GetNE ()
+{
+  if (mesh->GetDimension() == 3)
+    return mesh->GetNE();
+  else
+    return mesh->GetNSE();
+}
+
+int Ng_GetNSE ()
+{
+  if (mesh->GetDimension() == 3)
+    return mesh->GetNSE();
+  else
+    return mesh->GetNSeg();
+}
+
+void Ng_GetPoint (int pi, double * p)
+{
+  const Point3d & hp = mesh->Point (pi);
+  p[0] = hp.X();
+  p[1] = hp.Y();
+  if (mesh->GetDimension() == 3)
+    p[2] = hp.Z();
+}
+
+
+NG_ELEMENT_TYPE Ng_GetElement (int ei, int * epi, int * np)
+{
+  if (mesh->GetDimension() == 3)
+    {
+      int i;
+      const Element & el = mesh->VolumeElement (ei);
+      for (i = 0; i < el.GetNP(); i++)
+	epi[i] = el.PNum(i+1);
+      
+      if (np)
+	*np = el.GetNP();
+
+      if (el.GetType() == PRISM)
+	{
+	  // degenerated prism, (should be obsolete)
+	  const int map1[] = { 3, 2, 5, 6, 1 };
+	  const int map2[] = { 1, 3, 6, 4, 2 };
+	  const int map3[] = { 2, 1, 4, 5, 3 };
+	  
+	  const int * map = NULL;
+	  int deg1 = 0, deg2 = 0, deg3 = 0;
+	  int deg = 0;
+	  if (el.PNum(1) == el.PNum(4)) { map = map1; deg1 = 1; }
+	  if (el.PNum(2) == el.PNum(5)) { map = map2; deg2 = 1; }
+	  if (el.PNum(3) == el.PNum(6)) { map = map3; deg3 = 1; }
+	  
+	  switch (deg1+deg2+deg3)
+	    {
+	      {
+	      case 1:
+		cout << "degenerated prism found, deg = 1" << endl;
+		for (i = 0; i < 5; i++)
+		  epi[i] = el.PNum (map[i]);
+		
+		if (np) *np = 5;
+		return NG_PYRAMID;
+		break;
+	      }
+	    case 2:
+	      {
+		cout << "degenerated prism found, deg = 2" << endl;
+		if (!deg1) epi[3] = el.PNum(4);
+		if (!deg2) epi[3] = el.PNum(5);
+		if (!deg3) epi[3] = el.PNum(6);
+		
+		if (np) *np = 4;
+		return NG_TET;
+		break;
+	      }
+	    default:
+	      ;
+	    }
+	  
+	}
+
+      return NG_ELEMENT_TYPE (el.GetType());
+    }
+  else
+    {
+      int i;
+      const Element2d & el = mesh->SurfaceElement (ei);
+      for (i = 0; i < el.GetNP(); i++)
+	epi[i] = el.PNum(i+1);      
+
+      if (np) *np = el.GetNP();
+      return NG_ELEMENT_TYPE (el.GetType());
+      /*
+      switch (el.GetNP())
+	{
+	case 3: return NG_TRIG; 
+	case 4: return NG_QUAD; 
+	case 6: return NG_TRIG6; 
+	}
+      */
+    }
+
+  // should not occur
+  return NG_TET;
+}
+
+
+NG_ELEMENT_TYPE Ng_GetElementType (int ei)
+{
+  if (mesh->GetDimension() == 3)
+    {
+      return NG_ELEMENT_TYPE (mesh->VolumeElement (ei).GetType());
+    }
+  else
+    {
+      int i;
+      const Element2d & el = mesh->SurfaceElement (ei);
+      switch (el.GetNP())
+	{
+	case 3: return NG_TRIG; 
+	case 4: return NG_QUAD; 
+	case 6: return NG_TRIG6; 
+	}
+    }
+
+  // should not occur
+  return NG_TET;
+}
+
+
+
+int Ng_GetElementIndex (int ei)
+{
+  if (mesh->GetDimension() == 3)
+    return mesh->VolumeElement(ei).GetIndex();
+  else
+    {
+      int ind = mesh->SurfaceElement(ei).GetIndex(); 
+      ind = mesh->GetFaceDescriptor(ind).BCProperty();
+      return ind;
+    }
+}
+
+char * Ng_GetElementMaterial (int ei)
+{
+  static char empty[] = "";
+  if (mesh->GetDimension() == 3)
+    {
+      int ind = mesh->VolumeElement(ei).GetIndex();
+      // cout << "ind = " << ind << endl;
+      const char * mat = mesh->GetMaterial (ind);
+      if (mat)
+	return const_cast<char*> (mat);
+      else 
+	return empty;
+    }
+  return 0;
+}
+
+NG_ELEMENT_TYPE Ng_GetSurfaceElement (int ei, int * epi, int * np)
+{
+  if (mesh->GetDimension() == 3)
+    {
+      const Element2d & el = mesh->SurfaceElement (ei);
+      for (int i = 0; i < el.GetNP(); i++)
+	epi[i] = el[i];
+      
+      if (np) *np = el.GetNP();
+      
+      return NG_ELEMENT_TYPE (el.GetType());
+    }
+  else
+    {
+      const Segment & seg = mesh->LineSegment (ei);
+
+      if (!seg.pmid)
+	{
+	  epi[0] = seg.p1;
+	  epi[1] = seg.p2;
+	  
+	  if (np) *np = 2;
+	  return NG_SEGM;
+	}
+      else
+	{
+	  epi[0] = seg.p1;
+	  epi[1] = seg.p2;
+	  epi[2] = seg.pmid;
+
+	  if (np) *np = 3;
+	  return NG_SEGM3;
+	}
+    }
+
+  return NG_TRIG;
+}
+
+int Ng_GetSurfaceElementIndex (int ei)
+{
+  if (mesh->GetDimension() == 3)
+    return mesh->GetFaceDescriptor(mesh->SurfaceElement(ei).GetIndex()).BCProperty();
+  else
+    return mesh->LineSegment(ei).si;
+}
+
+
+void Ng_GetNormalVector (int sei, int locpi, double * nv)
+{
+  nv[0] = 0; 
+  nv[1] = 0;
+  nv[2] = 1;
+  
+  if (mesh->GetDimension() == 3)
+    {
+      Vec<3> n;
+      Point<3> p;
+      p = mesh->Point (mesh->SurfaceElement(sei).PNum(locpi));
+
+      int surfi = mesh->GetFaceDescriptor(mesh->SurfaceElement(sei).GetIndex()).SurfNr();
+      if (geometry)
+	{
+	  geometry->GetSurface (surfi) -> GetNormalVector(p, n);
+	  nv[0] = n(0);
+	  nv[1] = n(1);
+	  nv[2] = n(2);
+	}
+    }
+}
+
+
+int Ng_FindElementOfPoint (double * p, double * lami)
+{
+  if (mesh->GetDimension() == 3)
+    {
+      Point3d p3d(p[0], p[1], p[2]);
+      int ind = 
+	mesh->GetElementOfPoint(p3d, lami);
+      return ind;
+    }
+  else
+    {
+      double lam3[3];
+      Point3d p2d(p[0], p[1], 0);
+      int ind = 
+	mesh->GetElementOfPoint(p2d, lam3);
+      lami[0] = lam3[0];
+      lami[1] = lam3[1];
+      return ind;
+    }
+}
+
+
+
+void Ng_GetElementTransformation (int ei, const double * xi, 
+				  double * x, double * dxdxi)
+{
+  if (mesh->GetDimension() == 2)
+    {
+      Point<2> xl(xi[0], xi[1]);
+      Point<3> xg;
+      Mat<3,2> dx;
+
+      mesh->GetCurvedElements().CalcSurfaceTransformation (xl, ei-1, xg, dx);
+
+      // still 1-based arrays
+      if (x)
+	{
+	  for (int i = 0; i < 2; i++)
+	    x[i] = xg(i);
+	}
+	  
+      if (dxdxi)
+	{
+	  for (int i=0; i<2; i++)
+	    {
+	      dxdxi[2*i] = dx(i,0);
+	      dxdxi[2*i+1] = dx(i,1);
+	    }
+	}
+    }
+  else
+    {
+      Point<3> xl(xi[0], xi[1], xi[2]);
+  //    (*testout) << "elnr = " << ei << ", eltrans, xl = " << xl << endl;
+      Point<3> xg;
+      Mat<3,3> dx;
+
+      mesh->GetCurvedElements().CalcElementTransformation (xl, ei-1, xg, dx);
+
+      // still 1-based arrays
+      if (x)
+	{
+	  for (int i = 0; i < 3; i++)
+	    x[i] = xg(i);
+	}
+
+      if (dxdxi)
+	{
+	  for (int i=0; i<3; i++)
+	    {
+	      dxdxi[3*i] = dx(i,0);
+	      dxdxi[3*i+1] = dx(i,1);
+              dxdxi[3*i+2] = dx(i,2);
+	    }
+	}
+    }
+}
+
+
+void Ng_GetSurfaceElementTransformation (int sei, const double * xi, 
+					 double * x, double * dxdxi)
+{
+  if (mesh->GetDimension() == 2)
+    {
+      Point<3> xg;
+      Vec<3> dx;
+
+      // still 1-based arrays
+      mesh->GetCurvedElements().CalcSegmentTransformation (xi[0], sei-1, xg, dx);
+
+      if (x)
+        for (int i = 0; i < 2; i++)
+	  x[i] = xg(i);
+	  
+      if (dxdxi)
+        for (int i=0; i<2; i++)
+	  dxdxi[i] = dx(i);
+
+    }
+  else
+    {
+      Point<2> xl(xi[0], xi[1]);
+      Point<3> xg;
+      Mat<3,2> dx;
+      
+      // still 1-based arrays
+      mesh->GetCurvedElements().CalcSurfaceTransformation (xl, sei-1, xg, dx);
+      
+      for (int i=0; i<3; i++)
+	{
+	  if (x)
+	    x[i] = xg(i);
+	  if (dxdxi)
+	    {
+	      dxdxi[2*i] = dx(i,0);
+	      dxdxi[2*i+1] = dx(i,1);
+	    }
+	}
+    }
+}
+
+
+
+
+void Ng_SetRefinementFlag (int ei, int flag)
+{
+  if (mesh->GetDimension() == 3)
+    mesh->VolumeElement(ei).SetRefinementFlag (flag != 0);
+  else
+    mesh->SurfaceElement(ei).SetRefinementFlag (flag != 0);
+}
+
+void Ng_SetSurfaceRefinementFlag (int ei, int flag)
+{
+  if (mesh->GetDimension() == 3)
+    mesh->SurfaceElement(ei).SetRefinementFlag (flag != 0);
+}
+
+
+void Ng_Refine (NG_REFINEMENT_TYPE reftype)
+{
+  BisectionOptions biopt;
+  biopt.usemarkedelements = 1;
+  biopt.refine_hp = 0;
+  if (reftype == NG_REFINE_P || reftype == NG_REFINE_HP)
+    biopt.refine_hp = 1;
+
+  if (geometry && mesh->GetDimension() == 3)
+    {
+      RefinementSurfaces ref (*geometry);
+      ref.Bisect (*mesh, biopt);
+    }
+  else if (stlgeometry)
+    {
+      RefinementSTLGeometry ref (*stlgeometry);
+      ref.Bisect (*mesh, biopt);
+    }
+  else if (geometry2d)
+    {
+      Refinement2d ref (*geometry2d);
+      ref.Bisect (*mesh, biopt);
+    }
+  else
+    {
+      cout << "No geometry available" << endl;
+      Refinement ref;
+      ref.Bisect (*mesh, biopt);
+    }
+
+  mesh -> UpdateTopology();
+}
+
+void Ng_SecondOrder ()
+{
+  if (stlgeometry)
+    {
+      RefinementSTLGeometry ref (*stlgeometry);
+      ref.MakeSecondOrder (*mesh);
+    }
+
+  else if (geometry2d)
+    {
+      Refinement2d ref (*geometry2d);
+      ref.MakeSecondOrder (*mesh);
+    }
+
+  else if (geometry && mesh->GetDimension() == 3)
+
+    {
+      RefinementSurfaces ref (*geometry);
+      ref.MakeSecondOrder (*mesh);
+    }
+  else
+    {
+      cout << "no geom" << endl;
+      Refinement ref;
+      ref.MakeSecondOrder (*mesh);
+    }
+
+  mesh -> UpdateTopology();
+}
+
+void Ng_HPRefinement (int levels)
+{
+  HPRefinement (*mesh, levels);
+}
+
+
+void Ng_HighOrder (int order)
+{
+  Refinement * ref;
+
+  if (stlgeometry)
+    ref = new RefinementSTLGeometry (*stlgeometry);
+  else if (geometry2d)
+    ref = new Refinement2d (*geometry2d);
+  else
+    ref = new RefinementSurfaces (*geometry);
+
+  // cout << "parameter 1: " << argv[1] << " (conversion to int = " << atoi(argv[1]) << ")" << endl;
+
+  mesh -> GetCurvedElements().BuildCurvedElements (ref, order);
+
+  delete ref;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+int Ng_ME_GetNVertices (NG_ELEMENT_TYPE et)
+{
+  switch (et)
+    {
+    case NG_SEGM:
+    case NG_SEGM3:
+      return 2;
+
+    case NG_TRIG:
+    case NG_TRIG6:
+      return 3;
+
+    case NG_QUAD:
+      return 4;
+
+    case NG_TET:
+    case NG_TET10:
+      return 4;
+
+    case NG_PYRAMID:
+      return 5;
+
+    case NG_PRISM:
+    case NG_PRISM12:
+      return 6;
+
+    case NG_HEX:
+      return 8;
+
+    default:
+      cerr << "Ng_ME_GetNVertices, illegal element type " << et << endl;
+    }
+  return 0;
+}
+
+int Ng_ME_GetNEdges (NG_ELEMENT_TYPE et)
+{
+  switch (et)
+    {
+    case NG_SEGM:
+    case NG_SEGM3:
+      return 1;
+
+    case NG_TRIG:
+    case NG_TRIG6:
+      return 3;
+
+    case NG_QUAD:
+      return 4;
+
+    case NG_TET:
+    case NG_TET10:
+      return 6;
+
+    case NG_PYRAMID:
+      return 8;
+
+    case NG_PRISM:
+    case NG_PRISM12:
+      return 9;
+
+    case NG_HEX:
+      return 12;
+
+    default:
+      cerr << "Ng_ME_GetNEdges, illegal element type " << et << endl;
+    }
+  return 0;
+}
+
+
+int Ng_ME_GetNFaces (NG_ELEMENT_TYPE et)
+{
+  switch (et)
+    {
+    case NG_SEGM:
+    case NG_SEGM3:
+      return 0;
+
+    case NG_TRIG:
+    case NG_TRIG6:
+      return 1;
+
+    case NG_QUAD:
+    case NG_QUAD6:
+      return 1;
+
+    case NG_TET:
+    case NG_TET10:
+      return 4;
+
+    case NG_PYRAMID:
+      return 5;
+
+    case NG_PRISM:
+    case NG_PRISM12:
+      return 5;
+
+    case NG_HEX:
+      return 6;
+
+    default:
+      cerr << "Ng_ME_GetNVertices, illegal element type " << et << endl;
+    }
+  return 0;
+}
+
+
+const NG_POINT * Ng_ME_GetVertices (NG_ELEMENT_TYPE et)
+{
+  static double segm_points [][3] = 
+    { { 1, 0, 0 },
+      { 0, 0, 0 } };
+
+  static double trig_points [][3] = 
+    { { 1, 0, 0 },
+      { 0, 1, 0 },
+      { 0, 0, 0 } };
+
+  static double quad_points [][3] = 
+    { { 0, 0, 0 },
+      { 1, 0, 0 },
+      { 1, 1, 0 },
+      { 0, 1, 0 } };
+
+  static double tet_points [][3] = 
+    { { 1, 0, 0 },
+      { 0, 1, 0 },
+      { 0, 0, 1 },
+      { 0, 0, 0 } };
+
+  static double pyramid_points [][3] =
+    {
+      { 0, 0, 0 },
+      { 1, 0, 0 },
+      { 1, 1, 0 },
+      { 0, 1, 0 },
+      { 0, 0, 1-1e-7 },
+    };    
+  
+  static double prism_points[][3] = 
+    {
+      { 1, 0, 0 },
+      { 0, 1, 0 },
+      { 0, 0, 0 },
+      { 1, 0, 1 },
+      { 0, 1, 1 },
+      { 0, 0, 1 }
+    };
+
+  switch (et)
+    {
+    case NG_SEGM:
+    case NG_SEGM3:
+      return segm_points;
+
+    case NG_TRIG:
+    case NG_TRIG6:
+      return trig_points;
+
+    case NG_QUAD:
+    case NG_QUAD6:
+      return quad_points;
+
+    case NG_TET:
+    case NG_TET10:
+      return tet_points;
+
+    case NG_PYRAMID:
+      return pyramid_points;
+
+    case NG_PRISM:
+    case NG_PRISM12:
+      return prism_points;
+
+    case NG_HEX:
+    default:
+      cerr << "Ng_ME_GetVertices, illegal element type " << et << endl;
+    }
+  return 0;
+}
+
+
+
+const NG_EDGE * Ng_ME_GetEdges (NG_ELEMENT_TYPE et)
+{
+  static int segm_edges[1][2] =
+    { { 1, 2 }};
+
+  static int trig_edges[3][2] =
+    { { 3, 1 },
+      { 3, 2 },
+      { 1, 2 }};
+
+  static int quad_edges[4][2] =
+    { { 1, 2 },
+      { 4, 3 },
+      { 1, 4 },
+      { 2, 3 }};
+
+
+  static int tet_edges[6][2] =
+    { { 4, 1 },
+      { 4, 2 },
+      { 4, 3 }, 
+      { 1, 2 },
+      { 1, 3 },
+      { 2, 3 }};
+
+  static int prism_edges[9][2] =
+    { { 3, 1 },
+      { 1, 2 },
+      { 3, 2 },
+      { 6, 4 },
+      { 4, 5 },
+      { 6, 5 },
+      { 3, 6 },
+      { 1, 4 },
+      { 2, 5 }};
+
+  static int pyramid_edges[8][2] =
+    { { 1, 2 },
+      { 2, 3 },
+      { 1, 4 },
+      { 4, 3 },
+      { 1, 5 },
+      { 2, 5 },
+      { 3, 5 },
+      { 4, 5 }};
+
+
+
+  switch (et)
+    {
+    case NG_SEGM:
+    case NG_SEGM3:
+      return segm_edges;
+
+    case NG_TRIG:
+    case NG_TRIG6:
+      return trig_edges;
+
+    case NG_QUAD:
+    case NG_QUAD6:
+      return quad_edges;
+
+    case NG_TET:
+    case NG_TET10:
+      return tet_edges;
+
+    case NG_PYRAMID:
+      return pyramid_edges;
+
+    case NG_PRISM:
+    case NG_PRISM12:
+      return prism_edges;
+
+    case NG_HEX:
+    default:
+      cerr << "Ng_ME_GetEdges, illegal element type " << et << endl;
+    }
+  return 0;  
+}
+
+
+const NG_FACE * Ng_ME_GetFaces (NG_ELEMENT_TYPE et)
+{
+  static int tet_faces[4][4] =
+    { { 4, 2, 3, 0 },
+      { 4, 1, 3, 0 },
+      { 4, 1, 2, 0 },
+      { 1, 2, 3, 0 } };
+  
+  static int prism_faces[5][4] =
+    {
+      { 1, 2, 3, 0 },
+      { 4, 5, 6, 0 },
+      { 3, 1, 4, 6 },
+      { 1, 2, 5, 4 },
+      { 2, 3, 6, 5 } 
+    };
+  
+  static int pyramid_faces[5][4] =
+    {
+      { 1, 2, 5, 0 },
+      { 2, 3, 5, 0 },
+      { 3, 4, 5, 0 },
+      { 4, 1, 5, 0 },
+      { 1, 2, 3, 4 } 
+    };
+  
+  static int trig_faces[1][4] = 
+    {
+      { 1, 2, 3, 0 },
+    };
+
+  switch (et)
+    {
+    case NG_TET:
+    case NG_TET10:
+      return tet_faces;
+
+    case NG_PRISM:
+    case NG_PRISM12:
+      return prism_faces;
+
+    case NG_PYRAMID:
+      return pyramid_faces;
+
+
+    case NG_SEGM:
+    case NG_SEGM3:
+
+    case NG_TRIG:
+    case NG_TRIG6:
+      return trig_faces;
+    case NG_QUAD:
+
+
+    case NG_HEX:
+
+    default:
+      cerr << "Ng_ME_GetFaces, illegal element type " << et << endl;
+    }
+  return 0;
+}
+
+
+int Ng_GetNEdges()
+{
+  return mesh->GetTopology().GetNEdges();
+}
+int Ng_GetNFaces()
+{
+  return mesh->GetTopology().GetNFaces();
+}
+
+
+
+int Ng_GetElement_Edges (int elnr, int * edges, int * orient)
+{
+  const MeshTopology & topology = mesh->GetTopology();
+  if (mesh->GetDimension() == 3)
+    return topology.GetElementEdges (elnr, edges, orient);
+  else
+    return topology.GetSurfaceElementEdges (elnr, edges, orient);
+}
+
+int Ng_GetElement_Faces (int elnr, int * faces, int * orient)
+{
+  const MeshTopology & topology = mesh->GetTopology();
+  if (mesh->GetDimension() == 3)
+    return topology.GetElementFaces (elnr, faces, orient);
+  else
+    {
+      faces[0] = elnr;
+      if (orient) orient[0] = 0;
+      return 1;
+    }
+}
+
+int Ng_GetSurfaceElement_Edges (int elnr, int * edges, int * orient)
+{
+  const MeshTopology & topology = mesh->GetTopology();
+  if (mesh->GetDimension() == 3)
+    return topology.GetSurfaceElementEdges (elnr, edges, orient);
+  else
+    {
+      if (orient)
+	topology.GetSegmentEdge(elnr, edges[0], orient[0]);
+      else
+	edges[0] = topology.GetSegmentEdge(elnr);
+    }
+  return 1;
+  /*
+    int i, ned;
+    const MeshTopology & topology = mesh->GetTopology();
+    ARRAY<int> ia;
+    topology.GetSurfaceElementEdges (elnr, ia);
+    ned = ia.Size();
+    for (i = 1; i <= ned; i++)
+    edges[i-1] = ia.Get(i);
+
+    if (orient)
+    {
+    topology.GetSurfaceElementEdgeOrientations (elnr, ia);
+    for (i = 1; i <= ned; i++)
+    orient[i-1] = ia.Get(i);
+    }
+    return ned;
+  */
+}
+
+int Ng_GetSurfaceElement_Face (int selnr, int * orient)
+{
+  if (mesh->GetDimension() == 3)
+    {
+      const MeshTopology & topology = mesh->GetTopology();
+      if (orient)
+	*orient = topology.GetSurfaceElementFaceOrientation (selnr);
+      return topology.GetSurfaceElementFace (selnr);
+    }
+  return -1;
+}
+
+int Ng_GetFace_Vertices (int fnr, int * vert)
+{
+  const MeshTopology & topology = mesh->GetTopology();
+  ArrayMem<int,4> ia;
+  topology.GetFaceVertices (fnr, ia);
+  for (int i = 0; i < ia.Size(); i++)
+    vert[i] = ia[i];
+  //  cout << "face verts = " << ia << endl;
+  return ia.Size();
+}
+
+
+int Ng_GetFace_Edges (int fnr, int * edge)
+{
+  const MeshTopology & topology = mesh->GetTopology();
+  ArrayMem<int,4> ia;
+  topology.GetFaceEdges (fnr, ia);
+  for (int i = 0; i < ia.Size(); i++)
+    edge[i] = ia[i];
+  return ia.Size();
+}
+
+void Ng_GetEdge_Vertices (int ednr, int * vert)
+{
+  const MeshTopology & topology = mesh->GetTopology();
+  topology.GetEdgeVertices (ednr, vert[0], vert[1]);
+}
+
+
+int Ng_GetElementOrder (int enr)
+{
+  if (mesh->GetDimension() == 3)
+    return mesh->VolumeElement(enr).GetOrder();
+  else
+    return mesh->SurfaceElement(enr).GetOrder();
+}
+
+
+
+int Ng_GetNLevels ()
+{
+  return mesh->mglevels;
+}
+
+
+void Ng_GetParentNodes (int ni, int * parents)
+{
+  if (ni <= mesh->mlbetweennodes.Size())
+    {
+      parents[0] = mesh->mlbetweennodes.Get(ni).I1();
+      parents[1] = mesh->mlbetweennodes.Get(ni).I2();
+    }
+  else
+    parents[0] = parents[1] = 0;
+}
+
+
+int Ng_GetParentElement (int ei)
+{
+  if (mesh->GetDimension() == 3)
+    {
+      if (ei <= mesh->mlparentelement.Size())
+	return mesh->mlparentelement.Get(ei);
+    }
+  else
+    {
+      if (ei <= mesh->mlparentsurfaceelement.Size())
+	return mesh->mlparentsurfaceelement.Get(ei);
+    }
+  return 0;
+}
+
+
+int Ng_GetParentSElement (int ei)
+{
+  if (mesh->GetDimension() == 3)
+    {
+      if (ei <= mesh->mlparentsurfaceelement.Size())
+	return mesh->mlparentsurfaceelement.Get(ei);
+    }
+  else
+    {
+      return 0;
+    }
+  return 0;
+}
+
+
+
+
+
+int Ng_GetClusterRepVertex (int pi)
+{
+  return mesh->GetClusters().GetVertexRepresentant(pi);
+}
+
+int Ng_GetClusterRepEdge (int pi)
+{
+  return mesh->GetClusters().GetEdgeRepresentant(pi);
+}
+
+int Ng_GetClusterRepFace (int pi)
+{
+  return mesh->GetClusters().GetFaceRepresentant(pi);
+}
+
+int Ng_GetClusterRepElement (int pi)
+{
+  return mesh->GetClusters().GetElementRepresentant(pi);
+}
+
+
+
+
+
+
+void Ng_InitSolutionData (Ng_SolutionData * soldata)
+{
+  soldata -> name = NULL;
+  soldata -> data = NULL;
+  soldata -> components = 1;
+  soldata -> dist = 1;
+  soldata -> order = 1;
+  soldata -> iscomplex = 0;
+  soldata -> draw_surface = 1;
+  soldata -> draw_volume = 1;
+  soldata -> soltype = NG_SOLUTION_NODAL;
+  soldata -> solclass = 0;
+}
+
+void Ng_SetSolutionData (Ng_SolutionData * soldata)
+{
+  //   vssolution.ClearSolutionData ();
+  VisualSceneSolution::SolData * vss = new VisualSceneSolution::SolData;
+
+  //  cout << "Add solution " << soldata->name << ", type = " << soldata->soltype << endl;
+
+  vss->name = new char[strlen (soldata->name)+1];
+  strcpy (vss->name, soldata->name);
+
+  vss->data = soldata->data;
+  vss->components = soldata->components;
+  vss->dist = soldata->dist;
+  vss->order = soldata->order;
+  vss->iscomplex = bool(soldata->iscomplex);
+  vss->draw_surface = soldata->draw_surface;
+  vss->draw_volume = soldata->draw_volume;
+  vss->soltype = VisualSceneSolution::SolType (soldata->soltype);
+  vss->solclass = soldata->solclass;
+  vssolution.AddSolutionData (vss);
+}
+
+
+void Ng_Redraw ()
+{
+  vssolution.UpdateSolutionTimeStamp();
+  Render();
+}
+
+
+void Ng_SetVisualizationParameter (const char * name, const char * value)
+{
+  char buf[100];
+  sprintf (buf, "visoptions.%s", name);
+  cout << "name = " << name << ", value = " << value << endl;
+  cout << "set tcl-variable " << buf << " to " << value << endl;
+  Tcl_SetVar (tcl_interp, buf, const_cast<char*> (value), 0);
+  Tcl_Eval (tcl_interp, "Ng_Vis_Set parameters;");
+}
+
+
+
+
+int firsttime = 1;
+int animcnt = 0;
+void PlayAnimFile(const char* name, int speed, int maxcnt)
+{
+  //extern Mesh * mesh;
+
+  /*
+  if (mesh.Ptr()) mesh->DeleteMesh();
+  if (!mesh.Ptr()) mesh = new Mesh();
+  */
+  mesh.Reset (new Mesh());
+
+  int ne, np, i, ti;
+
+  char str[80];
+  char str2[80];
+
+  //int tend = 5000;
+  //  for (ti = 1; ti <= tend; ti++)
+  //{
+  int rti = (animcnt%(maxcnt-1)) + 1;
+  animcnt+=speed;
+  
+  sprintf(str2,"%05i.sol",rti);
+  strcpy(str,"mbssol/");
+  strcat(str,name);
+  strcat(str,str2);
+
+  cout << "read file '" << str << "'" << endl;
+  
+  ifstream infile(str);
+  infile >> ne;
+  for (i = 1; i <= ne; i++)
+    {
+      int j;
+      Element2d tri(3);
+      tri.SetIndex(1); //faceind
+      
+      for (j = 1; j <= 3; j++)
+	infile >> tri.PNum(j);
+
+      infile >> np;
+      for (i = 1; i <= np; i++)
+	{
+	  Point3d p;
+	  infile >> p.X() >> p.Y() >> p.Z();
+	  if (firsttime)
+	    mesh->AddPoint (p);
+	  else
+	    mesh->Point(i)=p;
+	}
+
+      //firsttime = 0;
+      Ng_Redraw();
+   }
+}
+
+		
+int Ng_GetNPeriodicVertices ()
+{
+  ARRAY<INDEX_2> apairs;
+  mesh->GetIdentifications().GetPairs (0, apairs);
+  return apairs.Size();
+}
+
+
+// pairs should be an integer array of 2*npairs
+void Ng_GetPeriodicVertices (int * pairs)
+{
+  ARRAY<INDEX_2> apairs;
+  mesh->GetIdentifications().GetPairs (0, apairs);
+  for (int i = 0; i < apairs.Size(); i++)
+    {
+      pairs[2*i] = apairs[i].I1();
+      pairs[2*i+1] = apairs[i].I2();
+    }
+      
+	/*<<<<<< nginterface.cpp
+      infile >> np;
+      for (i = 1; i <= np; i++)
+	{
+	  Point3d p;
+	  infile >> p.X() >> p.Y() >> p.Z();
+	  if (firsttime)
+	    mesh->AddPoint (p);
+	  else
+	    mesh->Point(i)=p;
+	}
+
+      //firsttime = 0;
+      Ng_Redraw();
+      //}
+}
+
+		
+int Ng_GetNPeriodicVertices ()
+{
+  ARRAY<INDEX_2> apairs;
+  mesh->GetIdentifications().GetPairs (0, apairs);
+  return apairs.Size();
+}
+
+
+// pairs should be an integer array of 2*npairs
+void Ng_GetPeriodicVertices (int * pairs)
+{
+  ARRAY<INDEX_2> apairs;
+  mesh->GetIdentifications().GetPairs (0, apairs);
+  for (int i = 0; i < apairs.Size(); i++)
+    {
+      pairs[2*i] = apairs[i].I1();
+      pairs[2*i+1] = apairs[i].I2();
+    }
+=======
+      if (firsttime)
+	mesh->AddSurfaceElement (tri);
+    }
+  
+  infile >> np;
+  for (i = 1; i <= np; i++)
+    {
+      Point3d p;
+      infile >> p.X() >> p.Y() >> p.Z();
+      if (firsttime)
+	mesh->AddPoint (p);
+      else
+	mesh->Point(i)=p;
+    }
+  
+  //firsttime = 0;
+  Ng_Redraw();
+>>>>>>> 1.9 
+*/
+}
+
+
diff --git a/Netgen/libsrc/interface/nglib.cpp b/Netgen/libsrc/interface/nglib.cpp
new file mode 100644
index 0000000000..d309cd7189
--- /dev/null
+++ b/Netgen/libsrc/interface/nglib.cpp
@@ -0,0 +1,538 @@
+/**************************************************************************/
+/* File:   nglib.cc                                                       */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   7. May. 2000                                                   */
+/**************************************************************************/
+
+/*
+  
+  Interface to the netgen meshing kernel
+  
+*/
+
+
+#include <mystdlib.h>
+#include <myadt.hpp>
+
+#include <linalg.hpp>
+#include <csg.hpp>
+#include <stlgeom.hpp>
+#include <geometry2d.hpp>
+#include <meshing.hpp>
+
+// #include <FlexLexer.h>
+
+#include "nglib.h"
+
+using namespace netgen;
+
+// constants and types:
+
+// initialize, deconstruct Netgen library:
+void Ng_Init ()
+{
+  mycout = &cout;
+  myerr = &cerr;
+  testout = new ofstream ("test.out");
+}
+
+void Ng_Exit ()
+{
+  ;
+}
+  
+
+
+Ng_Mesh * Ng_NewMesh ()
+{
+  Mesh * mesh = new Mesh;  
+  mesh->AddFaceDescriptor (FaceDescriptor (1, 1, 0, 1));
+  return (Ng_Mesh*)(void*)mesh;
+}
+
+void Ng_DeleteMesh (Ng_Mesh * mesh)
+{
+  delete (Mesh*)mesh;
+}
+
+
+// feeds points, surface elements and volume elements to the mesh
+void Ng_AddPoint (Ng_Mesh * mesh, double * x)
+{
+  Mesh * m = (Mesh*)mesh;
+  m->AddPoint (Point3d (x[0], x[1], x[2]));
+}
+  
+void Ng_AddSurfaceElement (Ng_Mesh * mesh, Ng_Surface_Element_Type et,
+			   int * pi)
+{
+  Mesh * m = (Mesh*)mesh;
+  Element2d el (3);
+  el.SetIndex (1);
+  el.PNum(1) = pi[0];
+  el.PNum(2) = pi[1];
+  el.PNum(3) = pi[2];
+  m->AddSurfaceElement (el);
+}
+
+void Ng_AddVolumeElement (Ng_Mesh * mesh, Ng_Volume_Element_Type et,
+			  int * pi)
+{
+  Mesh * m = (Mesh*)mesh;
+  Element el (4);
+  el.SetIndex (1);
+  el.PNum(1) = pi[0];
+  el.PNum(2) = pi[1];
+  el.PNum(3) = pi[2];
+  el.PNum(4) = pi[3];
+  m->AddVolumeElement (el);
+}
+
+// ask for number of points, surface and volume elements
+int Ng_GetNP (Ng_Mesh * mesh)
+{
+  return ((Mesh*)mesh) -> GetNP();
+}
+
+int Ng_GetNSE (Ng_Mesh * mesh)
+{
+  return ((Mesh*)mesh) -> GetNSE();
+}
+
+int Ng_GetNE (Ng_Mesh * mesh)
+{
+  return ((Mesh*)mesh) -> GetNE();
+}
+
+
+//  return point coordinates
+void Ng_GetPoint (Ng_Mesh * mesh, int num, double * x)
+{
+  const Point3d & p = ((Mesh*)mesh)->Point(num);
+  x[0] = p.X();
+  x[1] = p.Y();
+  x[2] = p.Z();
+}
+
+// return surface and volume element in pi
+Ng_Surface_Element_Type 
+Ng_GetSurfaceElement (Ng_Mesh * mesh, int num, int * pi)
+{
+  const Element2d & el = ((Mesh*)mesh)->SurfaceElement(num);
+  for (int i = 1; i <= el.GetNP(); i++)
+    pi[i-1] = el.PNum(i);
+  Ng_Surface_Element_Type et;
+  switch (el.GetNP())
+    {
+    case 3: et = NG_TRIG; break;
+    case 4: et = NG_QUAD; break;
+    case 6: et = NG_TRIG6; break;
+    }
+  return et;
+}
+
+Ng_Volume_Element_Type
+Ng_GetVolumeElement (Ng_Mesh * mesh, int num, int * pi)
+{
+  const Element & el = ((Mesh*)mesh)->VolumeElement(num);
+  for (int i = 1; i <= el.GetNP(); i++)
+    pi[i-1] = el.PNum(i);
+  Ng_Volume_Element_Type et;
+  switch (el.GetNP())
+    {
+    case 4: et = NG_TET; break;
+    case 5: et = NG_PYRAMID; break;
+    case 6: et = NG_PRISM; break;
+    case 10: et = NG_TET10; break;
+    }
+  return et;
+}
+
+
+
+// generates volume mesh from surface mesh
+Ng_Result Ng_GenerateVolumeMesh (Ng_Mesh * mesh, Ng_Meshing_Parameters * mp)
+{
+  Mesh * m = (Mesh*)mesh;
+  
+  
+  MeshingParameters mparam;
+  mparam.maxh = mp->maxh;
+  mparam.meshsizefilename = mp->meshsize_filename;
+
+  m->CalcLocalH();
+
+  MeshVolume (mparam, *m);
+  RemoveIllegalElements (*m);
+  OptimizeVolume (mparam, *m, NULL);
+
+  return NG_OK;
+}
+
+
+
+// 2D Meshing Functions:
+
+
+
+void Ng_AddPoint_2D (Ng_Mesh * mesh, double * x)
+{
+  Mesh * m = (Mesh*)mesh;
+  
+  m->AddPoint (Point3d (x[0], x[1], 0));
+}
+
+void Ng_AddBoundarySeg_2D (Ng_Mesh * mesh, int pi1, int pi2)
+{
+  Mesh * m = (Mesh*)mesh;
+
+  Segment seg;
+  seg.p1 = pi1;
+  seg.p2 = pi2;
+  m->AddSegment (seg);
+}
+  
+
+int Ng_GetNP_2D (Ng_Mesh * mesh)
+{
+  Mesh * m = (Mesh*)mesh;
+  return m->GetNP();
+}
+
+int Ng_GetNE_2D (Ng_Mesh * mesh)
+{
+  Mesh * m = (Mesh*)mesh;
+  return m->GetNSE();
+}
+
+int Ng_GetNSeg_2D (Ng_Mesh * mesh)
+{
+  Mesh * m = (Mesh*)mesh;
+  return m->GetNSeg();
+}
+  
+void Ng_GetPoint_2D (Ng_Mesh * mesh, int num, double * x)
+{
+  Mesh * m = (Mesh*)mesh;
+
+  Point3d & p = m->Point(num);
+  x[0] = p.X();
+  x[1] = p.Y();
+}
+
+void Ng_GetElement_2D (Ng_Mesh * mesh, int num, int * pi, int * matnum)
+{
+  const Element2d & el = ((Mesh*)mesh)->SurfaceElement(num);
+  for (int i = 1; i <= 3; i++)
+    pi[i-1] = el.PNum(i);
+  if (matnum)
+    *matnum = el.GetIndex();
+}
+
+
+void Ng_GetSegment_2D (Ng_Mesh * mesh, int num, int * pi, int * matnum)
+{
+  const Segment & seg = ((Mesh*)mesh)->LineSegment(num);
+  pi[0] = seg.p1;
+  pi[1] = seg.p2;
+
+  if (matnum)
+    *matnum = seg.edgenr;
+}
+
+
+
+Ng_Geometry_2D * Ng_LoadGeometry_2D (char * filename)
+{
+  SplineGeometry2d * geom = new SplineGeometry2d();
+  geom -> Load (filename);
+  return (Ng_Geometry_2D *)geom;
+}
+
+namespace netgen {
+  extern void MeshFromSpline2D (SplineGeometry2d & geometry,
+				Mesh *& mesh, 
+				MeshingParameters & mp);
+}
+
+
+Ng_Result Ng_GenerateMesh_2D (Ng_Geometry_2D * geom,
+			      Ng_Mesh ** mesh,
+			      Ng_Meshing_Parameters * mp)
+{
+  MeshingParameters mparam;
+  mparam.maxh = mp->maxh;
+  mparam.meshsizefilename = mp->meshsize_filename;
+
+  Mesh * m;
+  MeshFromSpline2D (*(SplineGeometry2d*)geom, m, mparam);
+  
+  cout << m->GetNSE() << " elements, " << m->GetNP() << " points" << endl;
+  
+  *mesh = (Ng_Mesh*)m;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ARRAY<STLReadTriangle> readtrias; //only before initstlgeometry
+ARRAY<Point<3> > readedges; //only before init stlgeometry
+ 
+void Ng_SaveMesh(Ng_Mesh * mesh, char* filename)
+{
+  ((Mesh*)mesh)->Save(filename);
+}
+
+// loads geometry from STL file
+Ng_STL_Geometry * Ng_STL_LoadGeometry (char * filename, int binary)
+{
+  int i;
+  STLGeometry geom;
+  STLGeometry* geo;
+  ifstream ist(filename);
+
+  if (binary)
+    {
+      geo = geom.LoadBinary(ist);
+    }
+  else
+    {
+      geo = geom.Load(ist);
+    }
+
+  readtrias.SetSize(0);
+  readedges.SetSize(0);
+
+  Point3d p;
+  Vec3d normal;
+  double p1[3];
+  double p2[3];
+  double p3[3];
+  double n[3];
+
+  Ng_STL_Geometry * geo2 = Ng_STL_NewGeometry();
+
+  for (i = 1; i <= geo->GetNT(); i++)
+    {
+      const STLTriangle& t = geo->GetTriangle(i);
+      p = geo->GetPoint(t.PNum(1));
+      p1[0] = p.X(); p1[1] = p.Y(); p1[2] = p.Z(); 
+      p = geo->GetPoint(t.PNum(2));
+      p2[0] = p.X(); p2[1] = p.Y(); p2[2] = p.Z(); 
+      p = geo->GetPoint(t.PNum(3));
+      p3[0] = p.X(); p3[1] = p.Y(); p3[2] = p.Z();
+      normal = t.Normal();
+      n[0] = normal.X(); n[1] = normal.Y(); n[2] = normal.Z();
+      
+      Ng_STL_AddTriangle(geo2, p1, p2, p3, n);
+    }
+
+  return geo2;
+}
+
+// generate new STL Geometry
+Ng_STL_Geometry * Ng_STL_NewGeometry ()
+{
+  return (Ng_STL_Geometry*)(void*)new STLGeometry;
+} 
+
+// after adding triangles (and edges) initialize
+Ng_Result Ng_STL_InitSTLGeometry (Ng_STL_Geometry * geom)
+{
+  STLGeometry* geo = (STLGeometry*)geom;
+  geo->InitSTLGeometry(readtrias);
+  readtrias.SetSize(0);
+
+  if (readedges.Size() != 0)
+    {
+      int i;
+      /*
+      for (i = 1; i <= readedges.Size(); i+=2)
+	{
+	  cout << "e(" << readedges.Get(i) << "," << readedges.Get(i+1) << ")" << endl;
+	}
+      */
+      geo->AddEdges(readedges);
+    }
+
+  if (geo->GetStatus() == STLTopology::STL_GOOD || geo->GetStatus() == STLTopology::STL_WARNING) return NG_OK;
+  return NG_SURFACE_INPUT_ERROR;
+}
+
+  // automatically generates edges:
+Ng_Result Ng_STL_MakeEdges (Ng_STL_Geometry * geom,
+		       Ng_Mesh* mesh,
+		       Ng_Meshing_Parameters * mp)
+{
+  STLGeometry* stlgeometry = (STLGeometry*)geom;
+  Mesh* me = (Mesh*)mesh;
+  
+  MeshingParameters mparam;
+
+  mparam.maxh = mp->maxh;
+  mparam.meshsizefilename = mp->meshsize_filename;
+
+  me -> SetGlobalH (mparam.maxh);
+  me -> SetLocalH (stlgeometry->GetBoundingBox().PMin() - Vec3d(10, 10, 10),
+		   stlgeometry->GetBoundingBox().PMax() + Vec3d(10, 10, 10),
+		   0.3);
+
+  if (mp->meshsize_filename)
+    {
+      ifstream infile (mp->meshsize_filename);
+      if (!infile.good()) return NG_FILE_NOT_FOUND;
+      me -> LoadLocalMeshSize (infile);
+    }
+
+  STLMeshing (*stlgeometry, *me);
+  
+  stlgeometry->edgesfound = 1;
+  stlgeometry->surfacemeshed = 0;
+  stlgeometry->surfaceoptimized = 0;
+  stlgeometry->volumemeshed = 0;
+  
+  return NG_OK;
+}
+
+  
+// generates mesh, empty mesh be already created.
+Ng_Result Ng_STL_GenerateSurfaceMesh (Ng_STL_Geometry * geom,
+				      Ng_Mesh* mesh,
+				      Ng_Meshing_Parameters * mp)
+{
+  STLGeometry* stlgeometry = (STLGeometry*)geom;
+  Mesh* me = (Mesh*)mesh;
+
+  MeshingParameters mparam;
+
+  mparam.maxh = mp->maxh;
+  mparam.meshsizefilename = mp->meshsize_filename;
+
+  /*
+  me -> SetGlobalH (mparam.maxh);
+  me -> SetLocalH (stlgeometry->GetBoundingBox().PMin() - Vec3d(10, 10, 10),
+		   stlgeometry->GetBoundingBox().PMax() + Vec3d(10, 10, 10),
+		   0.3);
+  */
+  /*
+  STLMeshing (*stlgeometry, *me);
+  
+  stlgeometry->edgesfound = 1;
+  stlgeometry->surfacemeshed = 0;
+  stlgeometry->surfaceoptimized = 0;
+  stlgeometry->volumemeshed = 0;
+  */  
+  int retval = STLSurfaceMeshing (*stlgeometry, *me);
+  if (retval == MESHING3_OK)
+    {
+      (*mycout) << "Success !!!!" << endl;
+      stlgeometry->surfacemeshed = 1;
+      stlgeometry->surfaceoptimized = 0;
+      stlgeometry->volumemeshed = 0;
+    } 
+  else if (retval == MESHING3_OUTERSTEPSEXCEEDED)
+    {
+      (*mycout) << "ERROR: Give up because of too many trials. Meshing aborted!" << endl;
+    }
+  else if (retval == MESHING3_TERMINATE)
+    {
+      (*mycout) << "Meshing Stopped!" << endl;
+    }
+  else
+    {
+      (*mycout) << "ERROR: Surface meshing not successful. Meshing aborted!" << endl;
+    }
+
+
+  STLSurfaceOptimization (*stlgeometry, *me, mparam);
+
+  return NG_OK;
+}
+
+
+  // fills STL Geometry
+  // positive orientation
+  // normal vector may be null-pointer
+void Ng_STL_AddTriangle (Ng_STL_Geometry * geom, 
+			 double * p1, double * p2, double * p3, double * nv)
+{
+  Point<3> apts[3];
+  apts[0] = Point<3>(p1[0],p1[1],p1[2]);
+  apts[1] = Point<3>(p2[0],p2[1],p2[2]);
+  apts[2] = Point<3>(p3[0],p3[1],p3[2]);
+
+  Vec<3> n;
+  if (!nv)
+    n = Cross (apts[0]-apts[1], apts[0]-apts[2]);
+  else
+    n = Vec<3>(nv[0],nv[1],nv[2]);
+
+  readtrias.Append(STLReadTriangle(apts,n));
+}
+
+  // add (optional) edges:
+void Ng_STL_AddEdge (Ng_STL_Geometry * geom, 
+		     double * p1, double * p2)
+{
+  readedges.Append(Point3d(p1[0],p1[1],p1[2]));
+  readedges.Append(Point3d(p2[0],p2[1],p2[2]));
+}
+
+
+
+Ng_Meshing_Parameters :: Ng_Meshing_Parameters()
+{
+  maxh = 1000;
+  fineness = 0.5;
+  secondorder = 0;
+  meshsize_filename = 0;
+}
+
+
+
+
+
+// compatibility functions:
+
+namespace netgen 
+{
+
+  char geomfilename[255];
+
+void MyError (const char * ch)
+{
+  cerr << ch;
+}
+
+//Destination for messages, errors, ...
+void Ng_PrintDest(const char * s)
+{
+  (*mycout) << s << flush;
+}
+
+double GetTime ()
+{
+  return 0;
+}
+
+void ResetTime ()
+{
+  ;
+}
+
+void MyBeep (int i)
+{
+  ;
+}
+
+}
diff --git a/Netgen/libsrc/interface/printdest.cpp b/Netgen/libsrc/interface/printdest.cpp
new file mode 100644
index 0000000000..0db654d94f
--- /dev/null
+++ b/Netgen/libsrc/interface/printdest.cpp
@@ -0,0 +1,11 @@
+#include <mystdlib.h>
+#include <myadt.hpp>
+
+namespace netgen
+{
+  //Destination for messages, errors, ...
+  void Ng_PrintDest(const char * s)
+  {
+    (*mycout) << s << flush;
+  }
+}
diff --git a/Netgen/libsrc/interface/readuser.cpp b/Netgen/libsrc/interface/readuser.cpp
new file mode 100644
index 0000000000..0a9d2b6802
--- /dev/null
+++ b/Netgen/libsrc/interface/readuser.cpp
@@ -0,0 +1,372 @@
+//
+//  Read user dependent output file
+//
+
+
+#include <mystdlib.h>
+
+
+#include <myadt.hpp>
+#include <linalg.hpp>
+#include <csg.hpp>
+#include <meshing.hpp>
+
+namespace netgen
+{
+#include "writeuser.hpp"
+
+void ReadFile (Mesh & mesh,
+	       const char * filename)
+{
+  cout << "Read User File" << endl;
+
+  int i, j;
+
+  char reco[100];
+  int np, nbe;
+
+
+
+  // ".surf" - mesh
+  
+  if ( (strlen (filename) > 5) &&
+       strcmp (&filename[strlen (filename)-5], ".surf") == 0 )
+    
+    {
+      cout << "Surface file" << endl;
+      
+      ifstream in (filename);
+      
+      in >> reco;
+      in >> np;
+      for (i = 1; i <= np; i++)
+	{
+	  Point3d p;
+	  in >> p.X() >> p.Y() >> p.Z();
+	  mesh.AddPoint (p);
+	}
+      
+      
+      in >> nbe;
+      //      int invert = globflags.GetDefineFlag ("invertsurfacemesh");
+      for (i = 1; i <= nbe; i++)
+	{
+	  Element2d el;
+	  int hi;
+	  
+	  el.SetIndex(1);
+	  
+	  for (j = 1; j <= 3; j++)
+	    {
+	      in >> el.PNum(j);
+	      if (el.PNum(j) < PointIndex(1) || 
+		  el.PNum(j) > PointIndex(np))
+		{
+		  cerr << "Point Number " << el.PNum(j) << " out of range 1..."
+		       << np << endl;
+		  return;
+		}
+	    }
+	  
+	  /*
+	    if (invert)
+	    Swap (el.PNum(2), el.PNum(3));
+	  */
+	  
+	  mesh.AddSurfaceElement (el);
+	}
+      
+      mesh.ClearFaceDescriptors();
+      mesh.AddFaceDescriptor (FaceDescriptor(0,1,0,0));
+      
+      cout << "points: " << np << " faces: " << nbe << endl;
+    }
+  
+  
+  
+
+  
+  // Universal mesh (AVL)
+  if ( (strlen (filename) > 4) &&
+       strcmp (&filename[strlen (filename)-4], ".unv") == 0 )
+    {  
+      int i, j, k;
+      
+      double h;
+      char reco[100];
+      int np, nbe;
+      int invert;
+      
+      
+      ifstream in(filename);
+
+      invert = 0;    // globflags.GetDefineFlag ("invertsurfacemesh");
+      double scale = 1;  // globflags.GetNumFlag ("scale", 1);
+
+
+      while (in.good())
+	{
+	  in >> reco;
+	  if (strcmp (reco, "NODES") == 0)
+	    {
+	      cout << "nodes found" << endl;
+	      for (j = 1; j <= 4; j++)
+		in >> reco;  // read dummy
+
+	      while (1)
+		{
+		  int pi, hi;
+		  double x, y, z;
+		  Point3d p;
+
+		  in >> pi;
+		  if (pi == -1)
+		    break;
+
+		  in >> hi >> hi >> hi;
+		  in >> p.X() >> p.Y() >> p.Z();
+
+		  p.X() *= scale;
+		  p.Y() *= scale;
+		  p.Z() *= scale;
+
+
+		  mesh.AddPoint (p);
+		}
+	    }
+
+	  if (strcmp (reco, "ELEMENTS") == 0)
+	    {
+	      cout << "elements found" << endl;
+	      for (j = 1; j <= 4; j++)
+		in >> reco;  // read dummy
+
+	      while (1)
+		{
+		  int hi;
+		  in >> hi;
+		  if (hi == -1) break;
+		  for (j = 1; j <= 7; j++)
+		    in >> hi;
+	      
+		  Element2d el;
+		  el.SetIndex(1);
+		  in >> el.PNum(1) >> el.PNum(2) >> el.PNum(3);
+	      
+		  if (invert)
+		    Swap (el.PNum(2), el.PNum(3));
+		  mesh.AddSurfaceElement (el);	  
+	      
+		  for (j = 1; j <= 5; j++)
+		    in >> hi;
+		}
+	    }
+	}
+      
+      mesh.ClearFaceDescriptors();
+      mesh.AddFaceDescriptor (FaceDescriptor(0,1,0,0));
+
+      Point3d pmin, pmax;
+      mesh.GetBox (pmin, pmax);
+      cout << "bounding-box = " << pmin << "-" << pmax << endl;
+    }
+
+
+
+  // fepp format2d:
+  
+  if ( (strlen (filename) > 7) &&
+       strcmp (&filename[strlen (filename)-7], ".mesh2d") == 0 )
+    {
+      cout << "Reading FEPP2D Mesh" << endl;
+      
+      char buf[100];
+      int np, ne, nseg, i, j;
+
+      ifstream in (filename);
+
+      in >> buf;
+
+      in >> nseg;
+      for (i = 1; i <= nseg; i++)
+	{
+	  int bound, p1, p2;
+	  in >> bound >> p1 >> p2;
+	  // forget them
+	}
+
+      in >> ne;
+      for (i = 1; i <= ne; i++)
+	{
+	  int mat, nelp;
+	  in >> mat >> nelp;
+	  Element2d el (nelp);
+	  el.SetIndex (mat);
+	  for (j = 1; j <= nelp; j++)
+	    in >> el.PNum(j);
+	  mesh.AddSurfaceElement (el);
+	}
+
+      in >> np;
+      for (i = 1; i <= np; i++)
+	{
+	  Point3d p(0,0,0);
+	  in >> p.X() >> p.Y();
+	  mesh.AddPoint (p);
+	}
+    }
+
+  
+  else if ( (strlen (filename) > 5) &&
+	    strcmp (&filename[strlen (filename)-5], ".mesh") == 0 )
+    {
+      cout << "Reading Neutral Format" << endl;
+      
+      char buf[100];
+      int np, ne, nse, i, j;
+
+      ifstream in (filename);
+
+      in >> np;
+      for (i = 1; i <= np; i++)
+	{
+	  Point3d p(0,0,0);
+	  in >> p.X() >> p.Y() >> p.Z();
+	  mesh.AddPoint (p);
+	}
+
+      in >> ne;
+      for (i = 1; i <= ne; i++)
+	{
+	  int mat;
+	  in >> mat;
+	  Element el (4);
+	  el.SetIndex (mat);
+	  for (j = 1; j <= 4; j++)
+	    in >> el.PNum(j);
+	  mesh.AddVolumeElement (el);
+	}
+
+
+      in >> nse;
+      for (i = 1; i <= nse; i++)
+	{
+	  int mat, nelp;
+	  in >> mat;
+	  Element2d el (3);
+	  el.SetIndex (mat);
+	  for (j = 1; j <= 3; j++)
+	    in >> el.PNum(j);
+	  mesh.AddSurfaceElement (el);
+	}
+    }
+
+
+  if ( (strlen (filename) > 4) &&
+       strcmp (&filename[strlen (filename)-4], ".emt") == 0 )
+    {
+      ifstream inemt (filename);
+      
+      string pktfile = filename;
+      int len = strlen (filename);
+      pktfile[len-3] = 'p';
+      pktfile[len-2] = 'k';
+      pktfile[len-1] = 't';
+      cout << "pktfile = " << pktfile << endl;
+
+      int np, nse, i;
+      int num, bcprop;
+      ifstream inpkt (pktfile.c_str());
+      inpkt >> np;
+      ARRAY<double> values(np);
+      for (i = 1; i <= np; i++)
+	{
+	  Point3d p(0,0,0);
+	  inpkt >> p.X() >> p.Y() >> p.Z()
+		>> bcprop >> values.Elem(i);
+	  mesh.AddPoint (p);
+	}      
+
+      mesh.ClearFaceDescriptors();
+      mesh.AddFaceDescriptor (FaceDescriptor(0,1,0,0));
+      mesh.GetFaceDescriptor(1).SetBCProperty (1);
+      mesh.AddFaceDescriptor (FaceDescriptor(0,1,0,0));
+      mesh.GetFaceDescriptor(2).SetBCProperty (2);
+      mesh.AddFaceDescriptor (FaceDescriptor(0,1,0,0));
+      mesh.GetFaceDescriptor(3).SetBCProperty (3);
+      mesh.AddFaceDescriptor (FaceDescriptor(0,1,0,0));
+      mesh.GetFaceDescriptor(4).SetBCProperty (4);
+      mesh.AddFaceDescriptor (FaceDescriptor(0,1,0,0));
+      mesh.GetFaceDescriptor(5).SetBCProperty (5);
+
+      int p1, p2, p3;
+      double value;
+      inemt >> nse;
+      for (i = 1; i <= nse; i++)
+	{
+	  inemt >> p1 >> p2 >> p3 >> bcprop >> value;
+
+	  if (bcprop < 1 >> bcprop > 4)
+	    cerr << "bcprop out of range, bcprop = " << bcprop << endl;
+	  p1++;
+	  p2++;
+	  p3++;
+	  if (p1 < 1 || p1 > np || p2 < 1 || p2 > np || p3 < 1 || p3 > np)
+	    {
+	      cout << "p1 = " << p1 << " p2 = " << p2 << " p3 = " << p3 << endl;
+	    }
+
+	  if (i > 110354) Swap (p2, p3);
+	  if (mesh.Point(p1).X() < 0.25)
+	    Swap (p2,p3);
+
+	  Element2d el(TRIG);
+
+	  if (bcprop == 1)
+	    {
+	      if (values.Get(p1) < -69999)
+		el.SetIndex(1);
+	      else
+		el.SetIndex(2);
+	    }
+	  else
+	    el.SetIndex(3);
+
+
+	  el.PNum(1) = p1;
+	  el.PNum(2) = p2;
+	  el.PNum(3) = p3;
+	  mesh.AddSurfaceElement (el);
+	}
+
+
+      ifstream incyl ("ngusers/guenter/cylinder.surf");
+      int npcyl, nsecyl; 
+      incyl >> npcyl;
+      cout << "npcyl = " << npcyl << endl;
+      for (i = 1; i <= npcyl; i++)
+	{
+	  Point3d p(0,0,0);
+	  incyl >> p.X() >> p.Y() >> p.Z();
+	  mesh.AddPoint (p);
+	}
+      incyl >> nsecyl;
+      cout << "nsecyl = " << nsecyl << endl;
+      for (i = 1; i <= nsecyl; i++)
+	{
+	  incyl >> p1 >> p2 >> p3;
+	  p1 += np;
+	  p2 += np;
+	  p3 += np;
+	  Element2d el(TRIG);
+	  el.SetIndex(5);
+	  el.PNum(1) = p1;
+	  el.PNum(2) = p2;
+	  el.PNum(3) = p3;
+	  mesh.AddSurfaceElement (el);
+	}
+    }
+
+}
+
+}
diff --git a/Netgen/libsrc/interface/writeabaqus.cpp b/Netgen/libsrc/interface/writeabaqus.cpp
new file mode 100644
index 0000000000..e9308b1472
--- /dev/null
+++ b/Netgen/libsrc/interface/writeabaqus.cpp
@@ -0,0 +1,237 @@
+//
+//  Write Abaqus file
+//
+//
+
+#include <mystdlib.h>
+
+#include <myadt.hpp>
+#include <linalg.hpp>
+#include <csg.hpp>
+#include <meshing.hpp>
+
+namespace netgen
+{
+#include "writeuser.hpp"
+
+
+
+
+void WriteAbaqusFormat (const Mesh & mesh,
+			const string & filename)
+
+{
+      
+  cout << "\nWrite Abaqus Volume Mesh" << endl;
+
+  ofstream outfile (filename.c_str());
+
+  outfile << "*Heading" << endl;
+  outfile << " " << filename << endl;
+
+  outfile.precision(8);
+
+  outfile << "*Node" << endl;
+
+  int np = mesh.GetNP();
+  int ne = mesh.GetNE();
+  int i, j, k;
+
+  for (i = 1; i <= np; i++)
+    {
+      outfile << i << ", ";
+      outfile << mesh.Point(i).X() << ", ";
+      outfile << mesh.Point(i).Y() << ", ";
+      outfile << mesh.Point(i).Z() << "\n";
+    }
+
+  int elemcnt = 0; //element counter
+  int finished = 0;
+  int indcnt = 1; //index counter
+
+  while (!finished)
+    {
+      int actcnt = 0;
+      const Element & el1 = mesh.VolumeElement(1);
+      int non = el1.GetNP();
+      if (non == 4)
+	{
+	  outfile << "*Element, type=C3D4, ELSET=PART" << indcnt << endl;
+	} 
+      else if (non == 10)
+	{
+	  outfile << "*Element, type=C3D10, ELSET=PART" << indcnt << endl;
+	} 
+      else
+	{
+	  cout << "unsupported Element type!!!" << endl;	  
+	}
+
+      for (i = 1; i <= ne; i++)
+	{
+	  const Element & el = mesh.VolumeElement(i);
+	      
+	  if (el.GetIndex() == indcnt)
+	    {
+	      actcnt++;
+	      if (el.GetNP() != non) 
+		{
+		  cout << "different element-types in a subdomain are not possible!!!" << endl;
+		  continue;
+		}
+		  
+	      elemcnt++;
+	      outfile << elemcnt << ", ";
+	      if (non == 4)
+		{
+		  outfile << el.PNum(1) << ", ";
+		  outfile << el.PNum(2) << ", ";
+		  outfile << el.PNum(4) << ", ";
+		  outfile << el.PNum(3) << "\n";
+		}
+	      else if (non == 10)
+		{
+		  outfile << el.PNum(1) << ", ";
+		  outfile << el.PNum(2) << ", ";
+		  outfile << el.PNum(4) << ", ";
+		  outfile << el.PNum(3) << ", ";
+		  outfile << el.PNum(5) << ", ";
+		  outfile << el.PNum(9) << ", ";
+		  outfile << el.PNum(7) << ", " << "\n";
+		  outfile << el.PNum(6) << ", ";
+		  outfile << el.PNum(8) << ", ";
+		  outfile << el.PNum(10) << "\n";
+		}
+	      else
+		{
+		  cout << "unsupported Element type!!!" << endl;
+		  for (j = 1; j <= el.GetNP(); j++)
+		    {
+		      outfile << el.PNum(j);
+		      if (j != el.GetNP()) outfile << ", ";
+		    }
+		  outfile << "\n";
+		}
+	    }
+	}	  
+      indcnt++;
+      if (elemcnt == ne) {finished = 1; cout << "all elements found by Index!" << endl;}
+      if (actcnt == 0) {finished = 1;}
+    }
+
+  if (mesh.GetIdentifications().GetMaxNr())
+    {
+      // periodic identification, implementation for
+      // Helmut J. Boehm, TU Vienna
+	  
+      char cfilename[255];
+      strcpy (cfilename, filename.c_str());
+
+      char mpcfilename[255];
+      strcpy (mpcfilename, cfilename);
+      int len = strlen (cfilename);
+      if (len >= 4 && (strcmp (mpcfilename+len-4, ".inp") == 0))
+	strcpy (mpcfilename+len-4, ".mpc");
+      else
+	strcat (mpcfilename, ".mpc");
+	  
+      ofstream mpc (mpcfilename);
+
+      int masternode;
+
+      ARRAY<INDEX_2> pairs;
+      BitArray master(np), help(np);
+      master.Set();
+      for (i = 1; i <= 3; i++)
+	{
+	  mesh.GetIdentifications().GetPairs (i, pairs);
+	  help.Clear();
+	  for (j = 1; j <= pairs.Size(); j++)
+	    {
+	      help.Set (pairs.Get(j).I1());
+	    }
+	  master.And (help);
+	}
+      for (i = 1; i <= np; i++)
+	if (master.Test(i))
+	  masternode = i;
+
+      cout << "masternode = " << masternode << " = "
+	   << mesh.Point(masternode) << endl;
+      ARRAY<int> slaves(3);
+      for (i = 1; i <= 3; i++)
+	{
+	  mesh.GetIdentifications().GetPairs (i, pairs);
+	  for (j = 1; j <= pairs.Size(); j++)
+	    {
+	      if (pairs.Get(j).I1() == masternode)
+		slaves.Elem(i) = pairs.Get(j).I2();
+	    }
+	  cout << "slave(" << i << ") = " << slaves.Get(i)
+	       << " = " << mesh.Point(slaves.Get(i)) << endl;
+	}
+	  
+	  
+      outfile << "**\n"
+	      << "*NSET,NSET=CTENODS\n"
+	      << slaves.Get(1) << ", " 
+	      << slaves.Get(2) << ", " 
+	      << slaves.Get(3) << endl;
+
+	  
+      outfile << "**\n"
+	      << "**POINT_fixed\n"
+	      << "**\n"
+	      << "*BOUNDARY, OP=NEW\n";
+      for (j = 1; j <= 3; j++)
+	outfile << masternode << ", " << j << ",,    0.\n";
+
+      outfile << "**\n"
+	      << "*BOUNDARY, OP=NEW\n";
+      for (j = 1; j <= 3; j++)
+	{
+	  Vec3d v(mesh.Point(masternode), mesh.Point(slaves.Get(j)));
+	  double vlen = v.Length();
+	  int dir = 0;
+	  if (fabs (v.X()) > 0.9 * vlen) dir = 2;
+	  if (fabs (v.Y()) > 0.9 * vlen) dir = 3;
+	  if (fabs (v.Z()) > 0.9 * vlen) dir = 1;
+	  if (!dir)
+	    cout << "ERROR: Problem with rigid body constraints" << endl;
+	  outfile << slaves.Get(j) << ", " << dir << ",,    0.\n";
+	}
+
+      outfile << "**\n"
+	      << "*EQUATION, INPUT=" << mpcfilename << endl;
+	  
+
+      BitArray eliminated(np);
+      eliminated.Clear();
+      for (i = 1; i <= mesh.GetIdentifications().GetMaxNr(); i++)
+	{
+	  mesh.GetIdentifications().GetPairs (i, pairs);
+	  if (!pairs.Size())
+	    continue;
+	      
+	  for (j = 1; j <= pairs.Size(); j++)
+	    if (pairs.Get(j).I1() != masternode && 
+		!eliminated.Test(pairs.Get(j).I2()))
+	      {
+		eliminated.Set (pairs.Get(j).I2());
+		for (k = 1; k <= 3; k++)
+		  {
+		    mpc << "4" << "\n";
+		    mpc << pairs.Get(j).I2() << "," << k << ", -1.0, ";
+		    mpc << pairs.Get(j).I1() << "," << k << ", 1.0, ";
+		    mpc << slaves.Get(i) << "," << k << ", 1.0, ";
+		    mpc << masternode << "," << k << ", -1.0 \n";
+		  }
+	      }
+	}
+    }
+
+
+  cout << "done" << endl;
+}
+
+}
diff --git a/Netgen/libsrc/interface/writediffpack.cpp b/Netgen/libsrc/interface/writediffpack.cpp
new file mode 100644
index 0000000000..25f9b2986f
--- /dev/null
+++ b/Netgen/libsrc/interface/writediffpack.cpp
@@ -0,0 +1,296 @@
+//
+//  Write diffpack file
+//
+//  by
+//  Bartosz Sawicki <sawickib@ee.pw.edu.pl>
+//  extended by
+//  Jacques Lechelle <jacques.lechelle@wanadoo.fr>
+//
+#include <mystdlib.h>
+
+#include <myadt.hpp>
+#include <linalg.hpp>
+#include <csg.hpp>
+#include <meshing.hpp>
+
+
+namespace netgen
+{
+#include "writeuser.hpp"
+
+
+void WriteDiffPackFormat (const Mesh & mesh,
+			  const CSGeometry & geom,
+			  const string & filename)
+{
+  //   double scale = globflags.GetNumFlag ("scale", 1);
+  double scale = 1;
+
+  ofstream outfile(filename.c_str());
+
+  if (mesh.GetDimension() == 3)
+
+    {
+      // Output compatible to Diffpack grid format
+      // Bartosz Sawicki <sawickib@ee.pw.edu.pl>
+
+      int np = mesh.GetNP();
+      int ne = mesh.GetNE();
+      int nse = mesh.GetNSE();
+      ARRAY <int> BIname;
+      ARRAY <int> BCsinpoint;
+      int i, j, k, l;
+
+
+      outfile.precision(6);
+      outfile.setf (ios::fixed, ios::floatfield);
+      outfile.setf (ios::showpoint);
+
+      const Element & eldummy = mesh.VolumeElement((int)1);
+      outfile << "\n\n"
+	"Finite element mesh (GridFE):\n\n"
+	"  Number of space dim. =   3\n"
+	"  Number of elements   =  " << ne << "\n"
+	"  Number of nodes      =  " << np << "\n\n"
+	"  All elements are of the same type : dpTRUE\n"
+	"  Max number of nodes in an element: "<< eldummy.GetNP() << "\n"
+	"  Only one subdomain               : dpFALSE\n"
+	"  Lattice data                     ? 0\n\n\n\n";
+      
+      for (i = 1; i <= nse; i++) 
+	{
+	  int BI=mesh.GetFaceDescriptor(mesh.SurfaceElement(i).GetIndex()).BCProperty();
+	  int nbi=BIname.Size();
+	  int found=0;
+	  for (j = 1; j <= nbi; j++)
+	    if(BI == BIname.Get(j)) found = 1;
+	  if( ! found ) BIname.Append(BI);	    	     
+	}
+      
+      outfile << "  " << BIname.Size() <<  " Boundary indicators:  ";
+      for (i =1 ; i <= BIname.Size(); i++)
+	outfile << BIname.Get(i) << " ";
+      outfile << "\n\n\n";
+      
+      outfile << "  Nodal coordinates and nodal boundary indicators,\n"
+	"  the columns contain:\n"
+	"   - node number\n"
+	"   - coordinates\n"
+	"   - no of boundary indicators that are set (ON)\n"
+	"   - the boundary indicators that are set (ON) if any.\n"
+	"#\n";
+
+      for (i = 1; i <= np; i++)
+        {
+          const Point3d & p = mesh.Point(i);
+
+          outfile.width(4);
+          outfile << i << "  (";
+          outfile.width(10);
+          outfile << p.X()/scale << ", ";
+          outfile.width(9);
+          outfile << p.Y()/scale << ", ";
+          outfile.width(9);
+          outfile << p.Z()/scale << ") ";
+	 
+	  if(mesh.PointType(i) != INNERPOINT) 
+	    {
+	      BCsinpoint.DeleteAll();
+	      for (j = 1; j <= nse; j++) 
+		{
+		  for (k = 1; k <= mesh.SurfaceElement(j).GetNP(); k++) 
+		    {
+		      if(mesh.SurfaceElement(j).PNum(k)==i) 
+			{
+			  int BC=mesh.GetFaceDescriptor(mesh.SurfaceElement(j).GetIndex()).BCProperty();
+			  int nbcsp=BCsinpoint.Size();
+			  int found = 0;
+			  for (l = 1; l <= nbcsp; l++)
+			    if(BC == BCsinpoint.Get(l)) found = 1;
+			  if( ! found ) BCsinpoint.Append(BC); 	    	     
+			}
+		    }
+		}
+	      int nbcsp = BCsinpoint.Size();
+	      outfile << "[" << nbcsp << "] ";
+	      for (j = 1; j <= nbcsp; j++)
+		outfile << BCsinpoint.Get(j) << " ";
+	      outfile << "\n";
+            }
+          else outfile << "[0]\n";
+
+        }
+
+      outfile << "\n"
+	"  Element types and connectivity\n"
+	"  the columns contain:\n"
+	"   - element number\n"
+	"   - element type\n"
+	"   - subdomain number\n"
+	"   - the global node numbers of the nodes in the element.\n"
+	"#\n";
+
+      for (i = 1; i <= ne; i++)
+        {
+          const Element & el = mesh.VolumeElement(i);
+          outfile.width(5);
+          if(el.GetNP()==4)
+            outfile << i << "  ElmT4n3D ";
+          else
+            outfile << i << "  ElmT10n3D ";
+          outfile.width(4);
+          outfile << el.GetIndex() << "    ";
+          if(el.GetNP()==10)
+            {
+	      outfile.width(8);
+	      outfile << el.PNum(1);
+	      outfile.width(8);
+	      outfile << el.PNum(3);
+	      outfile.width(8);
+	      outfile << el.PNum(2);
+	      outfile.width(8);
+	      outfile << el.PNum(4);
+	      outfile.width(8);
+	      outfile << el.PNum(6);
+	      outfile.width(8);
+	      outfile << el.PNum(8);
+	      outfile.width(8);
+	      outfile << el.PNum(5);
+	      outfile.width(8);
+	      outfile << el.PNum(7);
+	      outfile.width(8);
+	      outfile << el.PNum(10);
+	      outfile.width(8);
+	      outfile << el.PNum(9);
+            }
+          else
+            {
+	      outfile.width(8);
+	      outfile << el.PNum(1);
+	      outfile.width(8);
+	      outfile << el.PNum(3);
+	      outfile.width(8);
+	      outfile << el.PNum(2);
+	      outfile.width(8);
+	      outfile << el.PNum(4);
+            }
+          outfile << "\n";
+        }
+    } /* Diffpack */
+
+  else
+
+    {
+      // Output compatible to Diffpack grid format 2D
+
+      int np = mesh.GetNP();
+      int ne = mesh.GetNE();
+      int nse = mesh.GetNSE();
+      ARRAY <int> BIname;
+      ARRAY <int> BCsinpoint;
+      int i, j, k, l;
+
+
+      outfile.precision(6);
+      outfile.setf (ios::fixed, ios::floatfield);
+      outfile.setf (ios::showpoint);
+
+      outfile << "\n\n"
+	"Finite element mesh (GridFE):\n\n"
+	"  Number of space dim. =  2\n"
+	"  Number of elements   =  " << nse << "\n"
+	"  Number of nodes      =  " << np << "\n\n"
+	"  All elements are of the same type : dpTRUE\n"
+	"  Max number of nodes in an element: 3\n"
+	"  Only one subdomain               : dpFALSE\n"
+	"  Lattice data                     ? 0\n\n\n\n";
+      
+      for (i = 1; i <= nse; i++) 
+	{
+	  int BI=mesh.GetFaceDescriptor(mesh.SurfaceElement(i).GetIndex()).BCProperty();
+	  int nbi=BIname.Size();
+	  int found=0;
+	  for (j = 1; j <= nbi; j++)
+	    if(BI == BIname.Get(j)) found = 1;
+	  if( ! found ) BIname.Append(BI);	    	     
+	}
+      
+      outfile << "  " << BIname.Size() <<  " Boundary indicators:  ";
+      for (i =1 ; i <= BIname.Size(); i++)
+	outfile << BIname.Get(i) << " ";
+      outfile << "\n\n\n";
+      
+      outfile << "  Nodal coordinates and nodal boundary indicators,\n"
+	"  the columns contain:\n"
+	"   - node number\n"
+	"   - coordinates\n"
+	"   - no of boundary indicators that are set (ON)\n"
+	"   - the boundary indicators that are set (ON) if any.\n"
+	"#\n";
+
+      for (i = 1; i <= np; i++)
+        {
+          const Point3d & p = mesh.Point(i);
+
+          outfile.width(4);
+          outfile << i << "  (";
+          outfile.width(10);
+          outfile << p.X()/scale << ", ";
+          outfile.width(9);
+          outfile << p.Y()/scale << ", ";
+	 
+	  if(mesh.PointType(i) != INNERPOINT) 
+	    {
+	      BCsinpoint.DeleteAll();
+	      for (j = 1; j <= nse; j++) 
+		{
+		  for (k = 1; k <= 2; k++) 
+		    {
+		      if(mesh.SurfaceElement(j).PNum(k)==i) 
+			{
+			  int BC=mesh.GetFaceDescriptor(mesh.SurfaceElement(j).GetIndex()).BCProperty();
+			  int nbcsp=BCsinpoint.Size();
+			  int found = 0;
+			  for (l = 1; l <= nbcsp; l++)
+			    if(BC == BCsinpoint.Get(l)) found = 1;
+			  if( ! found ) BCsinpoint.Append(BC); 	    	     
+			}
+		    }
+		}
+	      int nbcsp = BCsinpoint.Size();
+	      outfile << "[" << nbcsp << "] ";
+	      for (j = 1; j <= nbcsp; j++)
+		outfile << BCsinpoint.Get(j) << " ";
+	      outfile << "\n";
+            }
+          else outfile << "[0]\n";
+
+        }
+
+      outfile << "\n"
+	"  Element types and connectivity\n"
+	"  the columns contain:\n"
+	"   - element number\n"
+	"   - element type\n"
+	"   - subdomain number\n"
+	"   - the global node numbers of the nodes in the element.\n"
+	"#\n";
+
+      for (i = 1; i <= nse; i++)
+        {
+          const Element2d & el = mesh.SurfaceElement(i);
+          outfile.width(5);
+          outfile << i << "  ElmT3n2D ";
+          outfile.width(4);
+          outfile << el.GetIndex() << "    ";
+	  outfile.width(8);
+	  outfile << el.PNum(1);
+	  outfile.width(8);
+	  outfile << el.PNum(3);
+	  outfile.width(8);
+	  outfile << el.PNum(2);
+          outfile << "\n";
+        }
+    }
+}
+}
diff --git a/Netgen/libsrc/interface/writefeap.cpp b/Netgen/libsrc/interface/writefeap.cpp
new file mode 100644
index 0000000000..817ee7c538
--- /dev/null
+++ b/Netgen/libsrc/interface/writefeap.cpp
@@ -0,0 +1,220 @@
+//
+// Write FEAP file
+// FEAP by Bob Taylor, Berkely
+//
+// contact Peter Wriggers or Albrecht Rieger, Hannover
+// rieger@ibnm.uni-hannover.de
+//
+
+#include <mystdlib.h>
+
+#include <myadt.hpp>
+#include <linalg.hpp>
+#include <csg.hpp>
+#include <meshing.hpp>
+
+namespace netgen
+{
+
+#include "writeuser.hpp"
+
+
+void WriteFEAPFormat (const Mesh & mesh,
+		      const string & filename)
+  
+{
+  // Feap format by A. Rieger 
+  // rieger@ibnm.uni-hannover.de
+
+  int inverttets = mparam.inverttets;
+  int invertsurf = mparam.inverttrigs;
+
+  int i, j, zz, n;
+
+  double scale = 1;   // globflags.GetNumFlag ("scale", 1);
+  
+  ofstream outfile(filename.c_str());
+ 
+  outfile << "feap" << "\n";
+  outfile << mesh.GetNP();
+  outfile << ",";
+  outfile << mesh.GetNE();
+  outfile << ",";
+  outfile << "1,3,3,4" << "\n" << "\n"; 
+  outfile << "!numnp,numel,nummat,ndm,ndf,nen";
+  outfile << "\n";
+      
+  outfile << "\n" << "\n";
+  outfile << "!node,,         X           Y           Z" << "\n";
+  outfile << "COOR" << "\n";
+  outfile.precision(4);
+  outfile.setf (ios::fixed, ios::floatfield);
+  outfile.setf (ios::showpoint);
+
+  for (i = 1; i <= mesh.GetNP(); i++)
+    {
+      outfile.width(5);
+      outfile << i;
+      outfile << ",,";
+      outfile.width(10);
+      outfile << mesh.Point(i).X()/scale << "  ";
+      outfile.width(10);
+      outfile << mesh.Point(i).Y()/scale << "  ";
+      outfile.width(10);
+      outfile << mesh.Point(i).Z()/scale << "\n";
+    }   
+      
+  outfile << "\n" << "\n";
+  outfile << "!elm,,mat,     n1      n2      n3      n4" << "\n";
+  outfile << "ELEM" << "\n";
+
+  for (i = 1; i <= mesh.GetNE(); i++)
+    {
+      Element el = mesh.VolumeElement(i);
+      if (inverttets)
+	el.Invert();
+
+
+      outfile.width(5);
+      outfile << i;
+      outfile << ",,";
+      outfile << el.GetIndex();
+      outfile << ",";
+
+
+      for (j = 1; j <= el.NP(); j++)
+	{
+	  outfile.width(8);
+	  outfile << el.PNum(j);
+	}
+      outfile << "\n";
+    }
+      
+  outfile << "\n" << "\n";
+      
+      
+  /*
+
+  //outfile << "SLOA" << "\n";
+  //outfile << "2,3,3" << "\n";
+  //outfile << GetNSE() << "\n";
+  outfile << "selm" << "\n" << GetNSE() << "\n";
+  for (i = 1; i <= GetNSE(); i++)
+  {
+  if (SurfaceElement(i).GetIndex())
+  {
+  outfile.width(8);
+  outfile << facedecoding.Get(SurfaceElement(i).GetIndex ()).surfnr;
+  //outfile.width(8);	  
+  //outfile << facedecoding.Get(SurfaceElement(i).GetIndex ()).domin;
+  //outfile.width(8);	  
+  //outfile << facedecoding.Get(SurfaceElement(i).GetIndex ()).domout;
+  }
+  else
+  outfile << "       0       0       0";
+  
+  
+  Element2d sel = SurfaceElement(i);
+  if (invertsurf)
+  sel.Invert();
+  //outfile.width(8);
+  //outfile << sel.GetNP();
+  //if (facedecoding.Get(SurfaceElement(i).GetIndex ()).surfnr == 4)
+  //{
+  for (j = 1; j <= sel.GetNP(); j++)
+  {
+  outfile.width(8);	  
+  outfile << sel.PNum(j);
+  }
+  //outfile.width(8);	
+  //outfile << "0.0";
+  //outfile.width(8);	
+  //outfile << "0.0";
+  //outfile.width(8);	
+  //outfile << "1.0" << "\n";
+  //}
+  outfile << "\n";
+  //outfile << endl;
+  }
+  */
+
+
+
+  // BEGIN CONTACT OUTPUT
+  /*      
+	  int masterindex, slaveindex;
+	  cout << "Master Surface index = ";
+	  cin >> masterindex;
+	  cout << "Slave Surface index  = ";
+	  cin >> slaveindex;
+
+
+	  // CONTACT SURFACE 1
+	  outfile << "\n";
+	  outfile << "\n";
+	  outfile << "surface,1" << "\n";;
+	  outfile.width(6);
+	  outfile << "tria" << "\n";;
+	  outfile.width(13);
+	  outfile << "facet" << "\n";;
+	  zz = 0;
+	  for (i = 1; i <= mesh.GetNSE(); i++)
+	  {
+	  Element2d sel = mesh.SurfaceElement(i);
+	  if (invertsurf)
+	  sel.Invert();
+	  if (mesh.GetFaceDescriptor(sel.GetIndex ()).BCProperty() == masterindex)
+	  {
+	  zz++;
+	  outfile.width(14);
+	  outfile << zz;
+	  outfile << ",,";
+	  for (j = 1; j <= sel.GetNP(); j++)
+	  {
+	  outfile << sel.PNum(j);
+	  outfile << ",";
+	  }
+	  outfile << "\n";
+	  }
+	  }
+
+
+	  // CONTACT SURFACE 2
+	  outfile << "\n";
+	  outfile << "\n";
+	  outfile << "surface,2" << "\n";;
+	  outfile.width(6);
+	  outfile << "tria" << "\n";;
+	  outfile.width(13);
+	  outfile << "facet" << "\n";;
+	  zz = 0;
+	  for (i = 1; i <= mesh.GetNSE(); i++)
+	  {
+	  
+	  Element2d sel = mesh.SurfaceElement(i);
+	  if (invertsurf)
+	  sel.Invert();
+	  if (mesh.GetFaceDescriptor(sel.GetIndex ()).BCProperty() == slaveindex)
+	  {
+	  zz++;
+	  outfile.width(14);
+	  outfile << zz;
+	  outfile << ",,";
+	  for (j = 1; j <= sel.GetNP(); j++)
+	  {
+	  outfile << sel.PNum(j);
+	  outfile << ",";
+	  }
+	  outfile << "\n";
+	  }
+	  }
+      
+	  outfile << "\n";
+	  outfile << "\n";
+  */      
+      
+  // END CONTACT OUTPUT
+
+  cout << "done" << endl;
+}
+}
diff --git a/Netgen/libsrc/interface/writefluent.cpp b/Netgen/libsrc/interface/writefluent.cpp
new file mode 100644
index 0000000000..1a214089e3
--- /dev/null
+++ b/Netgen/libsrc/interface/writefluent.cpp
@@ -0,0 +1,200 @@
+//
+//  Write Fluent file
+//  Johannes Gerstmayr, University Linz
+//
+
+#include <mystdlib.h>
+
+#include <myadt.hpp>
+#include <linalg.hpp>
+#include <csg.hpp>
+#include <meshing.hpp>
+
+namespace netgen
+{
+
+#include "writeuser.hpp"
+
+
+
+static char* CHex(int i)
+{
+  static char str[100];
+  sprintf(str,"%x",i); //hex
+  return str;
+}
+
+
+
+
+void WriteFluentFormat (const Mesh & mesh,
+			const string & filename)
+
+{
+  // Simple output 
+  cout << "start writing fluent export" << endl;
+      
+  int np = mesh.GetNP();
+  int ne = mesh.GetNE();
+  int nse = mesh.GetNSE();
+  int i, j;
+
+  ofstream outfile (filename.c_str());
+  char str[100];
+
+  outfile.precision(6);
+  //outfile.setf (ios::fixed, ios::floatfield);
+  //outfile.setf (ios::showpoint);
+      
+  outfile << "(0 \"Exported file from NETGEN (c) Joachim Schoeberl and Johannes Gerstmayr\")" << endl;
+  outfile << "(0 \"Dimension:\")" << endl;
+  outfile << "(2 3)" << endl << endl;
+
+  outfile << "(0 \"Nodes:\")" << endl;
+
+  //number of nodes:
+  sprintf(str,"(10 (0 1 %x 1))",np); //hexadecimal!!!
+  outfile << str << endl;
+
+  //nodes of zone 1:
+  sprintf(str,"(10 (7 1 %x 1)(",np); //hexadecimal!!!
+  outfile << str << endl;
+  for (i = 1; i <= np; i++)
+    {
+      const Point3d & p = mesh.Point(i);
+
+      //outfile.width(10);
+      outfile << p.X() << " ";
+      outfile << p.Y() << " ";
+      outfile << p.Z() << "\n";
+    }
+  outfile << "))" << endl << endl;
+
+  //write faces with elements
+
+  outfile << "(0 \"Faces:\")" << endl;
+
+  Element2d face, face2;
+  int i2, j2;
+  ARRAY<INDEX_3> surfaceelp;
+  ARRAY<int> surfaceeli;
+  ARRAY<int> locels;
+
+  //no cells=no tets
+  //no faces=2*tets
+
+  int noverbface = 2*ne-nse/2;
+      
+  sprintf(str,"(13 (0 1 %x 0))",(noverbface+nse)); //hexadecimal!!!
+  outfile << str << endl;
+      
+  sprintf(str,"(13 (4 1 %x 2 3)(",noverbface); //hexadecimal!!!
+  outfile << str << endl;
+
+  const_cast<Mesh&> (mesh).BuildElementSearchTree();
+
+  for (i = 1; i <= ne; i++)
+    {
+      if (ne > 2000)
+	{
+	  if (i%2000 == 0)
+	    {
+	      cout << (double)i/(double)ne*100. << "%" << endl;
+	    }
+	}
+
+      Element el = mesh.VolumeElement(i);
+      //if (inverttets)
+      //  el.Invert();
+	  
+      //outfile << el.GetIndex() << "    ";
+      if (el.GetNP() != 4) {cout << "only tet-meshes supported in write fluent!" << endl;}
+	  
+      //faces:
+	  
+      Box3d box;
+      el.GetBox(mesh.Points(), box);
+      box.IncreaseRel(1e-6);
+
+      mesh.GetIntersectingVolEls(box.PMin(),box.PMax(),locels);
+      int nel = locels.Size();
+      int locind;
+
+      //cout << "nel=" << nel << endl;
+
+      for (j = 1; j <= el.GetNFaces(); j++)
+	{
+	  el.GetFace(j, face);
+	  face.Invert();
+	  int eli2 = 0;
+	  int stopsig = 0;
+	      
+
+	  for (i2 = 1; i2 <= nel; i2++)
+	    {
+	      locind = locels.Get(i2);
+	      //cout << "  locind=" << locind << endl;
+
+	      Element el2 = mesh.VolumeElement(locind);
+	      //if (inverttets)
+	      //  el2.Invert();
+
+	      for (j2 = 1; j2 <= el2.GetNFaces(); j2++)
+		{
+		  el2.GetFace(j2, face2);
+
+		  if (face2.HasFace(face)) {eli2 = locind; stopsig = 1; break;}
+		}
+	      if (stopsig) break;
+	    }
+	      
+	  if (eli2==i) cout << "error in WRITE_FLUENT!!!" << endl;
+	      
+	  if (eli2 > i) //dont write faces two times!
+	    {
+	      //i: left cell, eli: right cell
+	      outfile << CHex(face.PNum(2)) << " " << CHex(face.PNum(1)) << " " << CHex(face.PNum(3)) << " ";
+	      outfile << CHex(i) << " " << CHex(eli2) << "\n";
+	    }
+	  if (eli2 == 0) 
+	    {
+	      surfaceelp.Append(INDEX_3(face.PNum(2),face.PNum(1),face.PNum(3)));
+	      surfaceeli.Append(i);
+	    }
+	}
+    }
+  outfile << "))" << endl;
+      
+  sprintf(str,"(13 (2 %x %x 3 3)(",(noverbface+1),noverbface+nse); //hexadecimal!!!
+  outfile << str << endl;
+
+  for (i = 1; i <= surfaceelp.Size(); i++)
+    {
+      outfile << CHex(surfaceelp.Get(i).I1()) << " " << CHex(surfaceelp.Get(i).I2()) << " " << CHex(surfaceelp.Get(i).I3()) << " ";
+      outfile << CHex(surfaceeli.Get(i)) << " " << 0 << "\n";
+    }
+
+  outfile << "))" << endl << endl;
+
+  outfile << "(0 \"Cells:\")" << endl;
+      
+  sprintf(str,"(12 (0 1 %x 0))",ne); //hexadecimal!!!
+  outfile << str << endl;
+
+  sprintf(str,"(12 (1 1 %x 1 2))",ne); //hexadecimal!!!
+  outfile << str << endl << endl;
+
+
+
+
+  outfile << "(0 \"Zones:\")\n"
+	  << "(45 (1 fluid fluid)())\n"
+    //      << "(45 (2 velocity-inlet velocity_inlet.1)())\n"
+    //      << "(45 (3 pressure-outlet pressure_outlet.2)())\n"
+	  << "(45 (2 wall wall)())\n"
+	  << "(45 (4 interior default-interior)())\n" << endl;
+
+  cout << "done" << endl;
+}
+
+}
diff --git a/Netgen/libsrc/interface/writepermas.cpp b/Netgen/libsrc/interface/writepermas.cpp
new file mode 100644
index 0000000000..824a36bc9b
--- /dev/null
+++ b/Netgen/libsrc/interface/writepermas.cpp
@@ -0,0 +1,169 @@
+//
+// Write Permas file
+// for Intes GmbH, Stuttgart
+//
+
+#include <mystdlib.h>
+
+#include <myadt.hpp>
+#include <linalg.hpp>
+#include <csg.hpp>
+#include <meshing.hpp>
+
+namespace netgen
+{
+#include "writeuser.hpp"
+
+
+
+void WritePermasFormat (const Mesh & mesh,
+			const string & filename)
+
+{
+  
+  ofstream outfile (filename.c_str());
+
+  outfile.precision(8);
+      
+  int np = mesh.GetNP();
+  int ne = mesh.GetNE();
+  int nse = mesh.GetNSE();
+  int i, j, k;
+
+
+  if (ne == 0)
+    {
+      // pure surface mesh
+
+      cout << "\nWrite Permas Surface Mesh" << endl;
+
+      int elnr = 0;
+      for (j = 1; j <= 2; j++)
+	{
+	  int nelp;
+	  switch (j)
+	    {
+	    case 1:
+	      nelp = 3;
+	      outfile << "$ELEMENT TYPE = TRIA3  ESET = ALLQUAD" << endl;		  
+	      break;
+	    case 2:
+	      nelp = 4;
+	      outfile << "$ELEMENT TYPE = QUAD4  ESET = ALLQUAD" << endl;		  
+	      break;
+	    }
+	      
+	  for (i = 1; i <= nse; i++)
+	    {
+	      const Element2d & el = mesh.SurfaceElement(i);
+	      if (el.GetNP() != nelp)
+		continue;
+		  
+	      elnr++;
+	      outfile << elnr << "  ";
+	      for (k = 1; k <= nelp; k++)
+		outfile << " " << el.PNum(k);
+	      outfile << endl;
+		  
+	    }
+	}
+    }
+
+  else
+
+    {
+      cout << "\nWrite Permas Volume Mesh" << endl;
+
+
+      int secondorder = (mesh.VolumeElement(1).GetNP() == 10);
+	  	  
+      if (!secondorder)
+	{
+	  outfile << "$ELEMENT TYPE = TET4  ESET = ALLTET" << endl;
+	  for (i = 1; i <= ne; i++)
+	    {
+	      const Element & el = mesh.VolumeElement(i);
+	      outfile << i 
+		      << " " << el.PNum(1) 
+		      << " " << el.PNum(2) 
+		      << " " << el.PNum(3) 
+		      << " " << el.PNum(4) << endl;
+	    }
+	}
+      else
+	{
+	  outfile << "$ELEMENT TYPE = TET10  ESET = ALLTET" << endl;
+	  for (i = 1; i <= ne; i++)
+	    {
+	      const Element & el = mesh.VolumeElement(i);
+	      outfile << i 
+		      << " " << el.PNum(1) 
+		      << " " << el.PNum(5) 
+		      << " " << el.PNum(2) 
+		      << " " << el.PNum(8) 
+		      << " " << el.PNum(3) 
+		      << " " << el.PNum(6) << endl << "& "
+		      << " " << el.PNum(7) 
+		      << " " << el.PNum(9) 
+		      << " " << el.PNum(10) 
+		      << " " << el.PNum(4) << endl;
+	    }
+	}
+	  
+      outfile << endl << endl;
+	  
+	  
+      outfile << "$SURFACE GEO  SURFID = 1  SFSET = ALLSUR" << endl;
+      for (i = 1; i <= nse; i++)
+	{
+	  const Element2d & el = mesh.SurfaceElement(i);
+	  if (el.GetNP() == 3)
+	    outfile << "STRIA3"
+		    << " " << el.PNum(1) 
+		    << " " << el.PNum(2) 
+		    << " " << el.PNum(3) << endl;
+	}    
+	  
+      for (i = 1; i <= nse; i++)
+	{
+	  const Element2d & el = mesh.SurfaceElement(i);
+	  if (el.GetNP() == 4)
+	    outfile << "SQUAD4"
+		    << " " << el.PNum(1) 
+		    << " " << el.PNum(2) 
+		    << " " << el.PNum(3) 
+		    << " " << el.PNum(4) << endl;
+	}      
+	  
+      for (i = 1; i <= nse; i++)
+	{
+	  const Element2d & el = mesh.SurfaceElement(i);
+	  if (el.GetNP() == 6)
+	    outfile << "STRIA6"
+		    << " " << el.PNum(1) 
+		    << " " << el.PNum(4) 
+		    << " " << el.PNum(2) 
+		    << " " << el.PNum(5) 
+		    << " " << el.PNum(3) 
+		    << " " << el.PNum(6) << endl;
+	}      
+    }
+
+
+  outfile << endl << endl;
+      
+
+
+  outfile << "$COOR  NSET = ALLNODES" << endl;
+
+  for (i = 1; i <= np; i++)
+    {
+      outfile << i << " ";
+      outfile << mesh.Point(i).X() << " ";
+      outfile << mesh.Point(i).Y() << " ";
+      outfile << mesh.Point(i).Z() << "\n";
+    }
+}
+
+
+}
diff --git a/Netgen/libsrc/interface/writetecplot.cpp b/Netgen/libsrc/interface/writetecplot.cpp
new file mode 100644
index 0000000000..1f5e01351b
--- /dev/null
+++ b/Netgen/libsrc/interface/writetecplot.cpp
@@ -0,0 +1,127 @@
+//
+//
+// TECPLOT file by Jawor Georgiew
+//
+#include <mystdlib.h>
+
+#include <myadt.hpp>
+#include <linalg.hpp>
+#include <csg.hpp>
+#include <meshing.hpp>
+
+
+
+namespace netgen
+{
+#include "writeuser.hpp"
+
+void WriteTecPlotFormat (const Mesh & mesh,
+			 const CSGeometry & geom,
+			 const string & filename)
+{
+  INDEX i;
+  int j, k, e, z;
+  Vec<3> n;
+  
+  INDEX np = mesh.GetNP();
+  INDEX ne = mesh.GetNE();
+  INDEX nse = mesh.GetNSE();
+  
+  ARRAY<int> sn(np);
+  ofstream outfile(filename.c_str());
+  
+  outfile << "TITLE=\" " << filename << "\"" << endl;
+
+  // fill hashtable
+
+  INDEX_3_HASHTABLE<int> face2volelement(ne);
+
+  for (i = 1; i <= ne; i++)
+    {
+      const Element & el = mesh.VolumeElement(i);
+      INDEX_3 i3;
+      int k, l;
+      for (j = 1; j <= 4; j++)   // loop over faces of tet
+	{
+	  l = 0;
+	  for (k = 1; k <= 4; k++)
+	    if (k != j)
+	      {
+		l++;
+		i3.I(l) = el.PNum(k);
+	      }
+	  i3.Sort();
+	  face2volelement.Set (i3, i);
+	}
+    }
+      
+      
+  for (j = 1; j <= geom.GetNSurf(); j++)       /* Flaeche Nummer j */
+    {
+      for (i = 1; i <= np; i++)
+	sn.Elem(i) = 0;
+
+      e = 0;
+       
+      for (i = 1; i <= nse; i++)
+	{
+	  const Element2d & el = mesh.SurfaceElement(i);
+	  if (j ==  mesh.GetFaceDescriptor (el.GetIndex ()).SurfNr())
+	    {
+	      for (k = 1; k <= 3; k++)
+		sn.Elem(el.PNum(k)) = 1;
+	      e++;                     /* e= Anzahl der neuen Elemente */
+	    }
+	}
+
+      z = 0;
+      for (i = 1; i <= np; i++)
+	if (sn.Elem(i) == 1)
+	  sn.Elem(i) = ++z;
+
+      outfile << "ZONE T=\" Surface " << j << " \", N=" << z
+	      << ", E=" << e << ", ET=TRIANGLE, F=FEPOINT" << endl;
+
+      for (i = 1; i <= np; i++)
+	if (sn.Elem(i) != 0)
+	  {
+	    geom.GetSurface(j) -> GetNormalVector ( mesh.Point(i), n );
+		
+	    outfile << mesh.Point(i).X() << " " /* Knoten Koordinaten */
+		    << mesh.Point(i).Y() << " "
+		    << mesh.Point(i).Z() << " "
+		    << n(0) << " "
+		    << n(1) << " "
+		    << n(2) << " "
+		    << i     << endl;
+	  }
+	  
+
+      for (i = 1; i <= nse; i++)
+	{
+	  const Element2d & el = mesh.SurfaceElement(i);
+	  if (j ==  mesh.GetFaceDescriptor(el.GetIndex ()).SurfNr())
+	    /* FlaechenKnoten (3) */
+	    outfile << sn.Get(el.PNum(1)) << " " 
+		    << sn.Get(el.PNum(2)) << " "
+		    << sn.Get(el.PNum(3)) << endl;
+	      
+	  /// Hier soll noch die Ausgabe der Nummer des angrenzenden
+	      /// Vol.elements erfolgen !
+
+	      for (i = 1; i <= nse; i++)
+		{
+		  const Element2d & el = mesh.SurfaceElement(i);
+		  INDEX_3 i3;
+		  for (j = 1; j <= 3; j++)
+		    i3.I(j) = el.PNum(j);
+		  i3.Sort();
+		  
+		  int elind = face2volelement.Get(i3);
+		}
+	}
+    }
+}
+
+
+}
diff --git a/Netgen/libsrc/interface/writetochnog.cpp b/Netgen/libsrc/interface/writetochnog.cpp
new file mode 100644
index 0000000000..50546dc2d1
--- /dev/null
+++ b/Netgen/libsrc/interface/writetochnog.cpp
@@ -0,0 +1,108 @@
+//
+//  Write Tochnog file
+//
+//  by
+//
+//  Andreas Seltmann
+//  email:  A.Seltmann@lsw.uni-heidelberg.de
+//
+#include <mystdlib.h>
+
+#include <myadt.hpp>
+#include <linalg.hpp>
+#include <csg.hpp>
+#include <meshing.hpp>
+
+
+namespace netgen
+{
+#include "writeuser.hpp"
+
+
+void WriteTochnogFormat (const Mesh & mesh,
+			 const string & filename)
+{
+  cout << "\nWrite Tochnog Volume Mesh" << endl;
+
+  ofstream outfile (filename.c_str());
+
+  outfile << "(Nodes and Elements generated with NETGEN" << endl;
+  outfile << " " << filename << ")" << endl;
+
+  outfile.precision(8);
+
+  outfile << "(Nodes)" << endl;
+
+  int np = mesh.GetNP();
+  int ne = mesh.GetNE();
+  int i, j, k;
+
+  for (i = 1; i <= np; i++)
+    {
+      outfile << "node " << " " << i << " ";
+      outfile << mesh.Point(i).X() << " ";
+      outfile << mesh.Point(i).Y() << " ";
+      outfile << mesh.Point(i).Z() << "\n";
+    }
+
+  int elemcnt = 0; //element counter
+  int finished = 0;
+  int indcnt = 1; //index counter
+
+  while (!finished)
+    {
+      int actcnt = 0;
+      const Element & el1 = mesh.VolumeElement(1);
+      int non = el1.GetNP();
+      if (non == 4)
+	{
+	  outfile << "(Elements, type=-tet4)" << endl;
+	} 
+      else
+	{
+	  cout << "unsupported Element type!!!" << endl;	  
+	}
+
+      for (i = 1; i <= ne; i++)
+	{
+	  const Element & el = mesh.VolumeElement(i);
+	      
+	  if (el.GetIndex() == indcnt)
+	    {
+	      actcnt++;
+	      if (el.GetNP() != non) 
+		{
+		  cout << "different element-types in a subdomain are not possible!!!" << endl;
+		  continue;
+		}
+		  
+	      elemcnt++;
+	      outfile << "element " << elemcnt << " -tet4 ";
+	      if (non == 4)
+		{
+		  outfile << el.PNum(1) << " ";
+		  outfile << el.PNum(2) << " ";
+		  outfile << el.PNum(4) << " ";
+		  outfile << el.PNum(3) << "\n";
+		}
+	      else
+		{
+		  cout << "unsupported Element type!!!" << endl;
+		  for (j = 1; j <= el.GetNP(); j++)
+		    {
+		      outfile << el.PNum(j);
+		      if (j != el.GetNP()) outfile << ", ";
+		    }
+		  outfile << "\n";
+		}
+	    }
+	}	  
+      indcnt++;
+      if (elemcnt == ne) {finished = 1; cout << "all elements found by Index!" << endl;}
+      if (actcnt == 0) {finished = 1;}
+    }
+
+  cout << "done" << endl;
+}
+
+}
diff --git a/Netgen/libsrc/interface/writeuser.cpp b/Netgen/libsrc/interface/writeuser.cpp
new file mode 100644
index 0000000000..1909eb2193
--- /dev/null
+++ b/Netgen/libsrc/interface/writeuser.cpp
@@ -0,0 +1,729 @@
+//
+//  Write user dependent output file
+//
+
+#include <mystdlib.h>
+
+#include <myadt.hpp>
+#include <linalg.hpp>
+#include <csg.hpp>
+#include <geometry2d.hpp>
+#include <meshing.hpp>
+
+namespace netgen
+{
+#include "writeuser.hpp"
+
+
+void RegisterUserFormats (ARRAY<const char*> & names)
+{
+  char *types[] =
+    {
+      "Neutral Format",
+      "Surface Mesh Format" ,
+      "DIFFPACK Format",
+      "TecPlot Format",     
+      "Tochnog Format",
+      "Abaqus Format",
+      "Fluent Format",
+      "Permas Format",
+      "FEAP Format",
+      "STL Format",
+      "VRML Format",
+      "Fepp Format",
+      //      { "Chemnitz Format" },
+      0
+    };
+
+  for (int i = 0; types[i]; i++)
+    names.Append (types[i]);
+}
+
+
+
+bool WriteUserFormat (const string & format, 	
+		      const Mesh & mesh,
+		      const CSGeometry & geom,
+		      const string & filename)
+{
+  cout << "Write user format " << format << endl;
+
+  if (format == "Neutral Format")
+    WriteNeutralFormat (mesh, geom, filename);
+
+  else if (format == "Surface Mesh Format")
+    WriteSurfaceFormat (mesh, filename);
+
+  else if (format == "DIFFPACK Format")
+    WriteDiffPackFormat (mesh, geom, filename);
+
+  else if (format == "Tochnog Format")
+    WriteTochnogFormat (mesh, filename);
+
+  else if (format == "TecPlot Format")
+    cerr << "ERROR: TecPlot format currently out of order" << endl;
+      // WriteTecPlotFormat (mesh, geom, filename);
+
+  else if (format == "Abaqus Format")
+    WriteAbaqusFormat (mesh, filename);
+
+  else if (format == "Fluent Format")
+    WriteFluentFormat (mesh, filename);
+
+  else if (format == "Permas Format")
+    WritePermasFormat (mesh, filename);
+
+  else if (format == "FEAP Format")
+    WriteFEAPFormat (mesh, filename);
+
+  else if (format == "STL Format")
+    WriteSTLFormat (mesh, filename);
+
+  else if (format == "VRML Format")
+    WriteVRMLFormat (mesh, 1, filename);
+
+  else if (format == "Fepp Format")
+    WriteFEPPFormat (mesh, geom, filename);
+
+  else if (format == "Chemnitz Format")
+    WriteUserChemnitz (mesh, filename);
+  
+  else 
+    {
+      return 1;
+    }
+
+  return 0;
+}
+
+
+
+
+/*
+ *  Neutral mesh format
+ *  points, elements, surface elements
+ */
+
+void WriteNeutralFormat (const Mesh & mesh,
+			 const CSGeometry & geom,
+			 const string & filename)
+{
+  cout << "write neutral, new" << endl;
+  int np = mesh.GetNP();
+  int ne = mesh.GetNE();
+  int nse = mesh.GetNSE();
+  int i, j;
+  
+  int inverttets = mparam.inverttets;
+  int invertsurf = mparam.inverttrigs;
+
+  ofstream outfile (filename.c_str());
+
+  outfile.precision(6);
+  outfile.setf (ios::fixed, ios::floatfield);
+  outfile.setf (ios::showpoint);
+  
+  outfile << np << "\n";
+  
+  for (i = 1; i <= np; i++)
+    {
+      const Point3d & p = mesh.Point(i);
+      
+      outfile.width(10);
+      outfile << p.X() << " ";
+      outfile.width(9);
+      outfile << p.Y() << " ";
+      outfile.width(9);
+      outfile << p.Z() << "\n";
+    }
+
+  outfile << ne << "\n";
+  for (i = 1; i <= ne; i++)
+    {
+      Element el = mesh.VolumeElement(i);
+      if (inverttets)
+	el.Invert();
+      outfile.width(4);
+      outfile << el.GetIndex() << "  ";
+      for (j = 1; j <= el.GetNP(); j++)
+	{
+	  outfile << " ";
+	  outfile.width(8);
+	  outfile << el.PNum(j);
+	}
+      outfile << "\n";
+    }
+
+  outfile << nse << "\n";
+  for (i = 1; i <= nse; i++)
+    {
+      Element2d el = mesh.SurfaceElement(i);
+      if (invertsurf)
+	el.Invert();
+      outfile.width(4);
+      outfile << mesh.GetFaceDescriptor (el.GetIndex()).BCProperty() << "    ";
+      for (j = 1; j <= el.GetNP(); j++)
+	{
+	  outfile << " ";
+	  outfile.width(8);
+	  outfile << el.PNum(j);
+	}
+      outfile << "\n";
+    }
+}
+
+
+
+
+
+
+
+
+
+void WriteSurfaceFormat (const Mesh & mesh,
+			 const string & filename)
+{
+  // surface mesh
+  int i, j;
+  
+  cout << "Write Surface Mesh" << endl;
+  
+  ofstream outfile (filename.c_str());
+  
+  outfile << "surfacemesh" << endl;
+  
+  outfile << mesh.GetNP() << endl;
+  for (i = 1; i <= mesh.GetNP(); i++)
+    {
+      for (j = 1; j <= 3; j++)
+	{
+	  outfile.width(10);
+	  outfile << mesh.Point(i).X(j) << " ";
+	}
+      outfile << endl;
+    }
+  outfile << mesh.GetNSE() << endl;
+  for (i = 1; i <= mesh.GetNSE(); i++)
+    {
+      for (j = 1; j <= 3; j++)
+	{
+	  outfile.width(8);
+	  outfile << mesh.SurfaceElement(i).PNum(j);
+	}
+      outfile << endl;
+    }
+}
+
+
+
+
+
+/*
+ *  save surface mesh as STL file
+ */
+
+void WriteSTLFormat (const Mesh & mesh,
+		     const string & filename)
+{
+  cout << "\nWrite STL Surface Mesh" << endl;
+  
+  ofstream outfile (filename.c_str());
+  
+  int i, j, k;
+  
+  outfile.precision(10);
+  
+  outfile << "solid" << endl;
+  
+  for (i = 1; i <= mesh.GetNSE(); i++)
+    {
+      outfile << "facet normal ";
+      const Point3d& p1 = mesh.Point(mesh.SurfaceElement(i).PNum(1));
+      const Point3d& p2 = mesh.Point(mesh.SurfaceElement(i).PNum(2));
+      const Point3d& p3 = mesh.Point(mesh.SurfaceElement(i).PNum(3));
+      
+      Vec3d normal = Cross(p2-p1,p3-p1);
+      if (normal.Length() != 0)
+	{
+	  normal /= (normal.Length());		  
+	}
+      
+      outfile << normal.X() << " " << normal.Y() << " " << normal.Z() << "\n";
+      outfile << "outer loop\n";
+      
+      outfile << "vertex " << p1.X() << " " << p1.Y() << " " << p1.Z() << "\n";
+      outfile << "vertex " << p2.X() << " " << p2.Y() << " " << p2.Z() << "\n";
+      outfile << "vertex " << p3.X() << " " << p3.Y() << " " << p3.Z() << "\n";
+      
+      outfile << "endloop\n";
+      outfile << "endfacet\n"; 
+    }
+  outfile << "endsolid" << endl;
+}
+
+
+
+
+
+/*
+ *
+ *  write surface mesh as VRML file
+ *
+ */
+
+void WriteVRMLFormat (const Mesh & mesh,
+		      bool faces,
+		      const string & filename)
+{
+
+  if (faces)
+
+    {
+      // Output in VRML, IndexedFaceSet is used 
+      // Bartosz Sawicki <sawickib@ee.pw.edu.pl>
+
+      int np = mesh.GetNP();
+      int nse = mesh.GetNSE();
+      int i, j, k, l;
+
+      ofstream outfile (filename.c_str());
+
+      outfile.precision(6);
+      outfile.setf (ios::fixed, ios::floatfield);
+      outfile.setf (ios::showpoint);
+
+      outfile << "#VRML V2.0 utf8 \n"
+	         "Background {\n"
+		 "    skyColor [1 1 1]\n"
+     		 "    groundColor [1 1 1]\n"
+		 "}\n"
+		 "Group{ children [\n"
+		 "Shape{ \n"
+		 "appearance Appearance { material Material { }} \n"
+                 "geometry IndexedFaceSet { \n"
+                 "coord Coordinate { point [ \n";  
+	        
+
+      for (i = 1; i <= np; i++)
+        {
+          const Point3d & p = mesh.Point(i);
+          outfile.width(10);
+          outfile << p.X() << " ";
+          outfile << p.Y() << " ";
+          outfile << p.Z() << " \n";
+	}
+
+      outfile << "  ] } \n"
+                 "coordIndex [ \n";               
+	
+      for (i = 1; i <= nse; i++)
+	{
+	  const Element2d & el = mesh.SurfaceElement(i);
+      
+	  for (j = 1; j <= 3; j++)
+	    {
+	      outfile.width(8);
+	      outfile << el.PNum(j)-1;
+	    }
+	  outfile << " -1 \n";
+	}
+      
+      outfile << "  ] \n";
+
+      //define number and RGB definitions of colors
+      outfile << "color Color { color [1 0 0, 0 1 0, 0 0 1, 1 1 0]} \n"
+                 "colorIndex [\n";
+      
+      for (i = 1; i <= nse; i++)
+	{
+	  outfile << mesh.GetFaceDescriptor(mesh.SurfaceElement(i).GetIndex ()).BCProperty();      
+          outfile << endl;
+	}
+      
+      outfile << " ] \n"
+                 "colorPerVertex FALSE \n"
+                 "creaseAngle 0 \n"
+		 "solid FALSE \n"
+                 "ccw FALSE \n"
+		 "convex TRUE \n"
+                 "} } # end of Shape\n"
+		 "] }\n";
+                         
+    } /* end of VRMLFACES */
+
+
+  else
+
+    {
+        // Output in VRML, IndexedLineSet is used
+	// Bartosz Sawicki <sawickib@ee.pw.edu.pl>
+
+      int np = mesh.GetNP();
+      int nse = mesh.GetNSE();
+      int i, j, k, l;
+
+      ofstream outfile (filename.c_str());
+
+      outfile.precision(6);
+      outfile.setf (ios::fixed, ios::floatfield);
+      outfile.setf (ios::showpoint);
+
+      outfile << "#VRML V2.0 utf8 \n"
+	         "Background {\n"
+		 "    skyColor [1 1 1]\n"
+     		 "    groundColor [1 1 1]\n"
+		 "}\n"
+		 "Group{ children [\n"
+	         "Shape{ \n"
+		 "appearance Appearance { material Material { }} \n"
+                 "geometry IndexedLineSet { \n"
+                 "coord Coordinate { point [ \n";  
+	        
+
+      for (i = 1; i <= np; i++)
+        {
+          const Point3d & p = mesh.Point(i);
+          outfile.width(10);
+          outfile << p.X() << " ";
+          outfile << p.Y() << " ";
+          outfile << p.Z() << " \n";
+	}
+
+      outfile << "  ] } \n"
+                 "coordIndex [ \n";               
+	
+      for (i = 1; i <= nse; i++)
+	{
+	  const Element2d & el = mesh.SurfaceElement(i);
+      
+	  for (j = 1; j <= 3; j++)
+	    {
+	      outfile.width(8);
+	      outfile << el.PNum(j)-1;
+	    }
+	  outfile.width(8);  
+	  outfile << el.PNum(1)-1; 
+	  outfile << " -1 \n";
+	}
+      
+      outfile << "  ] \n";
+
+/* Uncomment if you want color mesh    
+      outfile << "color Color { color [1 1 1, 0 1 0, 0 0 1, 1 1 0]} \n"
+                 "colorIndex [\n";
+      
+      for (i = 1; i <= nse; i++)
+	{
+	  outfile << mesh.GetFaceDescriptor(mesh.SurfaceElement(i).GetIndex ()).BCProperty();      
+          outfile << endl;
+	}
+      
+      outfile << " ] \n"
+*/ 
+      outfile << "colorPerVertex FALSE \n"
+                 "} } #end of Shape\n"
+		 "] } \n";
+                         
+    }
+
+}
+
+
+
+
+
+
+/*
+ * FEPP .. a finite element package developed at University Linz, Austria
+ */
+void WriteFEPPFormat (const Mesh & mesh,
+		      const CSGeometry & geom,
+		      const string & filename)
+{
+  
+  ofstream outfile (filename.c_str());
+
+  if (mesh.GetDimension() == 3)
+
+    {
+
+      // output for FEPP
+      
+      int np = mesh.GetNP();
+      int ne = mesh.GetNE();
+      int nse = mesh.GetNSE();
+      int ns = mesh.GetNFD();
+      int i, j;
+
+      outfile.precision(5);
+      outfile.setf (ios::fixed, ios::floatfield);
+      outfile.setf (ios::showpoint);
+      
+      outfile << "volumemesh4" << endl;
+      outfile << nse << endl;
+      for (i = 1; i <= nse; i++)
+	{
+	  const Element2d & el = mesh.SurfaceElement(i);
+
+	  //	  int facenr = mesh.facedecoding.Get(el.GetIndex()).surfnr;
+	  outfile.width(4);
+	  outfile << el.GetIndex() << " ";
+	  outfile.width(4);
+	  //	  outfile << mesh.GetFaceDescriptor(el.GetIndex()).BCProperty() << " ";
+	  outfile << mesh.GetFaceDescriptor(el.GetIndex()).BCProperty() << " ";
+	  outfile.width(4);
+	  outfile << el.GetNP() << "    ";
+	  for (j = 1; j <= el.GetNP(); j++)
+	    {
+	      outfile.width(8);
+	      outfile << el.PNum(j);
+	    }
+	  outfile << "\n";
+	}
+
+
+      outfile << ne << "\n";
+      for (i = 1; i <= ne; i++)
+	{
+	  const Element & el = mesh.VolumeElement(i);
+	  outfile.width(4);
+	  outfile << el.GetIndex() << " ";
+	  outfile.width(4);
+	  outfile << el.GetNP() << " ";
+	  for (j = 1; j <= el.GetNP(); j++)
+	    {
+	      outfile.width(8);
+	      outfile << el.PNum(j);
+	    }
+	  outfile << "\n";
+	}
+
+      outfile << np << "\n";
+      for (i = 1; i <= np; i++)
+	{
+	  const Point3d & p = mesh.Point(i);
+
+	  outfile.width(10);
+	  outfile << p.X() << " ";
+	  outfile.width(9);
+	  outfile << p.Y() << " ";
+	  outfile.width(9);
+	  outfile << p.Z() << "\n";
+	}
+
+      /*      
+      if (typ == WRITE_FEPPML)
+	{
+	  int nbn =  mesh.mlbetweennodes.Size();
+	  outfile << nbn << "\n";
+	  for (i = 1; i <= nbn; i++)
+	    outfile << mesh.mlbetweennodes.Get(i).I1() << " "
+		    << mesh.mlbetweennodes.Get(i).I2() << "\n";
+	  
+
+	  //	  int ncon = mesh.connectedtonode.Size();
+	  //	  outfile << ncon << "\n";
+	  //	  for (i = 1; i <= ncon; i++)
+	  //	    outfile << i << " " << mesh.connectedtonode.Get(i) << endl;
+	}
+      */
+
+
+      // write CSG surfaces
+      if (&geom && geom.GetNSurf() >= ns)
+	{
+	  outfile << ns << endl;
+	  for (i = 1; i <= ns; i++)
+	    geom.GetSurface(mesh.GetFaceDescriptor(i).SurfNr())->Print(outfile);
+	}
+      else 
+	outfile << "0" << endl;
+    }
+
+  
+  else
+    
+    { // 2D fepp format
+      
+      ;
+      /*
+      extern SplineGeometry2d * geometry2d;
+      if (geometry2d)
+	Save2DMesh (mesh, &geometry2d->GetSplines(), outfile);
+      else
+	Save2DMesh (mesh, 0, outfile);
+      */
+    }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#ifdef OLDSTYLE_WRITE
+
+
+void WriteFile (int typ,
+		const Mesh & mesh,
+		const CSGeometry & geom,
+		const char * filename,
+		const char * geomfile,
+		double h)
+{
+
+  
+  int inverttets = mparam.inverttets;
+  int invertsurf = mparam.inverttrigs;
+
+
+
+
+
+
+
+
+  if (typ == WRITE_EDGEELEMENT)
+    {
+      // write edge element file
+      // Peter Harscher, ETHZ
+
+      cout << "Write Edge-Element Format" << endl;
+
+      ofstream outfile (filename);
+
+      int i, j;
+      int ned;
+
+      // hash table representing edges;
+      INDEX_2_HASHTABLE<int> edgeht(mesh.GetNP());
+
+      // list of edges
+      ARRAY<INDEX_2> edgelist;
+
+      // edge (point) on boundary ?
+      BitArray bedge, bpoint(mesh.GetNP());
+      
+      static int eledges[6][2] = { { 1, 2 } , { 1, 3 } , { 1, 4 },
+				   { 2, 3 } , { 2, 4 } , { 3, 4 } };
+
+      // fill hashtable   (point1, point2)  ---->  edgenr
+      for (i = 1; i <= mesh.GetNE(); i++)
+	{
+	  const Element & el = mesh.VolumeElement (i);
+	  INDEX_2 edge;
+	  for (j = 1; j <= 6; j++)
+	    {
+	      edge.I1() = el.PNum (eledges[j-1][0]);
+	      edge.I2() = el.PNum (eledges[j-1][1]);
+	      edge.Sort();
+
+	      if (!edgeht.Used (edge))
+		{
+		  edgelist.Append (edge);
+		  edgeht.Set (edge, edgelist.Size());
+		}
+	    }
+	}
+
+      
+      // set bedges, bpoints
+      bedge.SetSize (edgelist.Size());
+      bedge.Clear();
+      bpoint.Clear();
+
+      for (i = 1; i <= mesh.GetNSE(); i++)
+	{
+	  const Element2d & sel = mesh.SurfaceElement(i);
+	  for (j = 1; j <= 3; j++)
+	    {
+	      bpoint.Set (sel.PNum(j));
+
+	      INDEX_2 edge;
+	      edge.I1() = sel.PNum(j);
+	      edge.I2() = sel.PNum(j%3+1);
+	      edge.Sort();
+
+	      bedge.Set (edgeht.Get (edge));
+	    }
+	}
+
+
+
+      outfile << mesh.GetNE() << endl;
+      // write element ---> point
+      for (i = 1; i <= mesh.GetNE(); i++)
+	{
+	  const Element & el = mesh.VolumeElement(i);
+	  
+	  outfile.width(8);
+	  outfile << i;
+	  for (j = 1; j <= 4; j++)
+	    {
+	      outfile.width(8);
+	      outfile << el.PNum(j);
+	    }
+	  outfile << endl;
+	}
+
+      // write element ---> edge
+      for (i = 1; i <= mesh.GetNE(); i++)
+	{
+	  const Element & el = mesh.VolumeElement (i);
+	  INDEX_2 edge;
+	  for (j = 1; j <= 6; j++)
+	    {
+	      edge.I1() = el.PNum (eledges[j-1][0]);
+	      edge.I2() = el.PNum (eledges[j-1][1]);
+	      edge.Sort();
+
+	      outfile.width(8);
+	      outfile << edgeht.Get (edge);
+	    }
+	  outfile << endl;
+	}
+
+      // write points
+      outfile << mesh.GetNP() << endl;
+      outfile.precision (6);
+      for (i = 1; i <= mesh.GetNP(); i++)
+	{
+	  const Point3d & p = mesh.Point(i);
+	  
+	  for (j = 1; j <= 3; j++)
+	    {
+	      outfile.width(8);
+	      outfile << p.X(j);
+	    }
+	  outfile << "       "
+		  << (bpoint.Test(i) ? "1" : 0) << endl;
+	}
+
+      // write edges
+      outfile << edgelist.Size() << endl;
+      for (i = 1; i <= edgelist.Size(); i++)
+	{
+	  outfile.width(8);
+	  outfile << edgelist.Get(i).I1();
+	  outfile.width(8);
+	  outfile << edgelist.Get(i).I2();
+	  outfile << "       "
+		  << (bedge.Test(i) ? "1" : "0") << endl;
+	}
+    }
+
+
+
+
+}
+#endif
+}
diff --git a/Netgen/libsrc/interface/writeuser.hpp b/Netgen/libsrc/interface/writeuser.hpp
new file mode 100644
index 0000000000..26e8f8eeb1
--- /dev/null
+++ b/Netgen/libsrc/interface/writeuser.hpp
@@ -0,0 +1,101 @@
+#ifndef WRITEUSER
+#define WRITEUSER
+
+/**************************************************************************/
+/* File:    writeuser.hh                                                  */
+/* Authors: many                                                          */
+/* Date:    10. Dec. 97                                                   */
+/**************************************************************************/
+
+
+extern 
+void WriteFile (int typ,
+		const Mesh & mesh,
+		const CSGeometry & geom,
+		const char * filename,
+		const char * geomfile = NULL,
+		double h = 0);
+
+
+
+extern 
+void ReadFile (Mesh & mesh,
+	       const char * filename);
+
+extern 
+void ImportSolution (const char * filename);
+
+
+
+
+
+
+
+extern
+void WriteNeutralFormat (const Mesh & mesh,
+			 const CSGeometry & geom,
+			 const string & filename);
+
+extern
+void WriteSurfaceFormat (const Mesh & mesh,
+			 const string & filename);
+
+extern
+void WriteSTLFormat (const Mesh & mesh,
+		     const string & filename);
+
+extern
+void WriteVRMLFormat (const Mesh & mesh,
+		      bool faces,
+		      const string & filename);
+
+extern
+void WriteFEPPFormat (const Mesh & mesh,
+		      const CSGeometry & geom,
+		      const string & filename);
+
+extern
+void WriteUserChemnitz (const Mesh & mesh,
+			const string & filename);
+
+
+
+
+
+extern 
+void WriteDiffPackFormat (const Mesh & mesh,
+			  const CSGeometry & geom,
+			  const string & filename);
+
+extern
+void WriteTochnogFormat (const Mesh & mesh,
+			 const string & filename);
+
+extern
+void WriteTecPlotFormat (const Mesh & mesh,
+			 const CSGeometry & geom,
+			 const string & filename);
+
+extern
+void WriteAbaqusFormat (const Mesh & mesh,
+			const string & filename);
+
+extern
+void WriteFluentFormat (const Mesh & mesh,
+			const string & filename);
+
+extern
+void WritePermasFormat (const Mesh & mesh,
+			const string & filename);
+
+extern
+void WriteFEAPFormat (const Mesh & mesh,
+		      const string & filename);
+
+
+extern void RegisterUserFormats (ARRAY<const char*> & names);
+extern bool WriteUserFormat (const string & format, 	
+			     const Mesh & mesh,
+			     const CSGeometry & geom,
+			     const string & filename);
+#endif
diff --git a/Netgen/libsrc/interface/wuchemnitz.cpp b/Netgen/libsrc/interface/wuchemnitz.cpp
new file mode 100644
index 0000000000..306cbe6268
--- /dev/null
+++ b/Netgen/libsrc/interface/wuchemnitz.cpp
@@ -0,0 +1,309 @@
+// Write Chemnitz file format
+
+
+#include <mystdlib.h>
+
+#include <myadt.hpp>
+
+#include <linalg.hpp>
+#include <csg.hpp>
+#include <meshing.hpp>
+
+namespace netgen
+{
+
+class POINT3D
+  {
+  public:
+  POINT3D () { };
+  double x, y, z;
+  };
+
+class VOLELEMENT
+  {
+  public:
+  VOLELEMENT () {};
+  int domnr, p1, p2, p3, p4;
+  int faces[4];
+  };
+  
+class SURFELEMENT
+  {
+  public:
+  SURFELEMENT () { };
+  int snr, p1, p2, p3;
+  };
+  
+
+class FACE
+  {
+  public:
+  FACE () { };
+  int p1, p2, p3;
+  int edges[3];
+  };
+
+class EDGE
+  {
+  public:
+  EDGE () { };
+  int p1, p2;
+  };
+
+static ARRAY<POINT3D> points;
+static ARRAY<VOLELEMENT> volelements;
+static ARRAY<SURFELEMENT> surfelements;
+
+static ARRAY<FACE> faces;
+static ARRAY<EDGE> edges;
+
+
+void ReadFile (char * filename)
+  {
+  int i, n;
+  ifstream infile(filename);
+  char reco[100];
+  
+  
+  infile >> reco;  // file format recognition
+  
+  infile >> n;   // number of surface elements
+  cout << n << " Surface elements" << endl;
+  
+  for (i = 1; i <= n; i++)
+    {
+    SURFELEMENT sel;
+    infile >> sel.snr >> sel.p1 >> sel.p2 >> sel.p3;
+    surfelements.Append (sel);
+    }
+    
+  infile >> n;   // number of volume elements
+  cout << n << " Volume elements" << endl;
+  
+  for (i = 1; i <= n; i++)
+    {
+    VOLELEMENT el;
+    infile >> el.p1 >> el.p2 >> el.p3 >> el.p4;
+    volelements.Append (el);
+    }
+    
+  infile >> n;   // number of points 
+  cout << n << " Points" << endl;
+  
+  for (i = 1; i <= n; i++)
+    {
+    POINT3D p;
+    infile >> p.x >> p.y >> p.z;
+    points.Append (p);
+    }
+  }
+  
+  
+
+void ReadFileMesh (const Mesh & mesh)
+{
+  int i, n;
+  
+  n = mesh.GetNSE();   // number of surface elements
+  cout << n << " Surface elements" << endl;
+  
+  for (i = 1; i <= n; i++)
+    {
+      SURFELEMENT sel;
+      const Element2d & el = mesh.SurfaceElement(i);
+      sel.snr = el.GetIndex();
+      sel.p1 = el.PNum(1);
+      sel.p2 = el.PNum(2);
+      sel.p3 = el.PNum(3);
+      surfelements.Append (sel);
+    }
+    
+  n = mesh.GetNE();   // number of volume elements
+  cout << n << " Volume elements" << endl;
+  
+  for (i = 1; i <= n; i++)
+    {
+      VOLELEMENT el;
+      const Element & nel = mesh.VolumeElement(i);
+      el.p1 = nel.PNum(1);
+      el.p2 = nel.PNum(2);
+      el.p3 = nel.PNum(3);
+      el.p4 = nel.PNum(4);
+      //      infile >> el.p1 >> el.p2 >> el.p3 >> el.p4;
+      volelements.Append (el);
+    }
+    
+  n = mesh.GetNP();   // number of points 
+  cout << n << " Points" << endl;
+  
+  for (i = 1; i <= n; i++)
+    {
+      POINT3D p;
+      Point3d mp = mesh.Point(i);
+      p.x = mp.X();
+      p.y = mp.Y();
+      p.z = mp.Z();
+      //      infile >> p.x >> p.y >> p.z;
+      points.Append (p);
+    }
+  }
+  
+
+
+
+void Convert ()
+  {
+  int i, j, facei, edgei;
+  INDEX_3 i3;
+  INDEX_2 i2;
+
+  INDEX_3_HASHTABLE<int> faceindex(volelements.Size()/5 + 1);
+  INDEX_2_HASHTABLE<int> edgeindex(volelements.Size()/5 + 1);
+  
+  for (i = 1; i <= volelements.Size(); i++)
+    {
+    for (j = 1; j <= 4; j++)
+      {
+      switch (j)
+        {
+        case 1:
+          i3.I1() = volelements.Get(i).p2;
+          i3.I2() = volelements.Get(i).p3;
+          i3.I3() = volelements.Get(i).p4;
+          break;
+        case 2:
+          i3.I1() = volelements.Get(i).p1;
+          i3.I2() = volelements.Get(i).p3;
+          i3.I3() = volelements.Get(i).p4;
+          break;
+         case 3:
+          i3.I1() = volelements.Get(i).p1;
+          i3.I2() = volelements.Get(i).p2;
+          i3.I3() = volelements.Get(i).p4;
+          break;
+         case 4:
+          i3.I1() = volelements.Get(i).p1;
+          i3.I2() = volelements.Get(i).p2;
+          i3.I3() = volelements.Get(i).p3;
+          break;
+        }
+      i3.Sort();
+      if (faceindex.Used (i3)) 
+        facei = faceindex.Get(i3);
+      else
+        {
+        FACE fa;
+        fa.p1 = i3.I1();
+        fa.p2 = i3.I2();
+        fa.p3 = i3.I3();
+        facei = faces.Append (fa);
+        faceindex.Set (i3, facei);
+        } 
+        
+      volelements.Elem(i).faces[j-1] = facei;  
+      }    
+    
+    } 
+ 
+
+  for (i = 1; i <= faces.Size(); i++)
+    {
+    for (j = 1; j <= 3; j++)
+      {
+      switch (j)
+        {
+        case 1:
+          i2.I1() = faces.Get(i).p2;
+          i2.I2() = faces.Get(i).p3;
+          break;
+        case 2:
+          i2.I1() = faces.Get(i).p1;
+          i2.I2() = faces.Get(i).p3;
+          break;
+         case 3:
+          i2.I1() = faces.Get(i).p1;
+          i2.I2() = faces.Get(i).p2;
+          break;
+        }
+      if (i2.I1() > i2.I2()) Swap (i2.I1(), i2.I2());
+      if (edgeindex.Used (i2)) 
+        edgei = edgeindex.Get(i2);
+      else
+        {
+        EDGE ed;
+        ed.p1 = i2.I1();
+        ed.p2 = i2.I2();
+        edgei = edges.Append (ed);
+        edgeindex.Set (i2, edgei);
+        } 
+        
+      faces.Elem(i).edges[j-1] = edgei;  
+      }    
+    
+    }  
+ 
+  }  
+  
+  
+void WriteFile (ostream & outfile)
+  {
+  int i;
+  
+  outfile 
+  	<< "#VERSION: 1.0" << endl
+  	<< "#PROGRAM: NETGEN" << endl
+  	<< "#EQN_TYPE: POISSON" << endl
+  	<< "#DIMENSION: 3D" << endl
+  	<< "#DEG_OF_FREE: 1" << endl
+  	<< "#DESCRIPTION: I don't know" << endl
+  	<< "##RENUM: not done" << endl
+  	<< "#USER: Kleinzen" << endl
+  	<< "DATE: 10.06.1996" << endl;
+  
+  outfile << "#HEADER:   8" << endl
+  	<< points.Size() << "  " << edges.Size() << "  " 
+  	<< faces.Size() << "  " << volelements.Size() << "  0  0  0  0" << endl;
+  
+  outfile << "#VERTEX:   " << points.Size() << endl;
+  for (i = 1; i <= points.Size(); i++)
+    outfile << "  " << i << "  " << points.Get(i).x << "  " << points.Get(i).y 
+    	<< "  " << points.Get(i).z << endl;
+    	
+  outfile << "#EDGE:  " << edges.Size() << endl;
+  for (i = 1; i <= edges.Size(); i++)
+    outfile << "  " << i << "  1  " 
+    	<< edges.Get(i).p1 << "  " 
+    	<< edges.Get(i).p2 
+    	<< "  0" << endl;
+    
+  outfile << "#FACE:  " << faces.Size() << endl;  
+  for (i = 1; i <= faces.Size(); i++)
+    outfile << "  " << i << "  1  3  " 
+    	<< faces.Get(i).edges[0] << "  " 
+    	<< faces.Get(i).edges[1] << "  " 
+    	<< faces.Get(i).edges[2] << endl;
+    	
+  outfile << "#SOLID:  " << volelements.Size() << endl;
+  for (i = 1; i <= volelements.Size(); i++)
+    outfile << "  " << i << "  1  4  " 
+    	<< volelements.Get(i).faces[0] << "  "
+    	<< volelements.Get(i).faces[1] << "  "
+    	<< volelements.Get(i).faces[2] << "  "
+    	<< volelements.Get(i).faces[3] << endl;
+    	
+  outfile << "#END_OF_DATA" << endl;
+  }
+    
+
+void WriteUserChemnitz (const Mesh & mesh,
+			const string & filename)
+{
+  ofstream outfile (filename.c_str());
+
+  ReadFileMesh (mesh);
+  Convert ();
+  
+  WriteFile (outfile);
+  cout << "Wrote Chemnitz standard file" << endl;
+}
+}
diff --git a/Netgen/libsrc/linalg/Makefile b/Netgen/libsrc/linalg/Makefile
new file mode 100644
index 0000000000..a3ca3763d9
--- /dev/null
+++ b/Netgen/libsrc/linalg/Makefile
@@ -0,0 +1,13 @@
+#
+# Makefile for linear algebra library
+#
+src = densemat.cpp vector.cpp polynomial.cpp
+#
+lib = la
+libpath = libsrc/linalg
+#
+#
+include ../makefile.inc
+#
+
+
diff --git a/Netgen/libsrc/linalg/basemat.cpp b/Netgen/libsrc/linalg/basemat.cpp
new file mode 100644
index 0000000000..49fd4c2e41
--- /dev/null
+++ b/Netgen/libsrc/linalg/basemat.cpp
@@ -0,0 +1,465 @@
+#include <mystdlib.h>
+#include <linalg.hpp>
+
+
+// ofstream (*myerr) ("error.out");
+// ofstream (*myerr) ("NUL");
+
+
+namespace netgen
+{
+
+double BaseMatrix :: shit = 0;
+
+
+BaseMatrix :: BaseMatrix ()
+  {
+  height = width = 0;
+  symmetric = 0;
+  }
+
+BaseMatrix :: BaseMatrix (INDEX h, INDEX w)
+  {
+  if (!w) w = h;
+  height = h;
+  width = w;
+  symmetric = 0;
+  }
+
+void BaseMatrix :: SetSize (INDEX h, INDEX w)
+  {
+  if (!w) w = h;
+  height = h;
+  width = w;
+  }
+
+void BaseMatrix :: SetSymmetric (int sym)
+  {
+  symmetric = sym;
+  }
+
+double & BaseMatrix :: operator() (INDEX, INDEX)
+  {
+  (*myerr) << "BaseMatrix: operator() called" << endl;
+  return shit;
+  }
+
+double BaseMatrix :: operator() (INDEX, INDEX) const
+  {
+  (*myerr) << "BaseMatrix: operator() called" << endl;
+  return 0;
+  }
+
+
+
+ostream & operator<<(ostream & s, const BaseMatrix & m)
+  {
+  return m.Print (s);
+  }
+
+ostream & BaseMatrix :: Print (ostream & s) const
+  {
+  if (Symmetric()) s << "Symmetric" << endl;
+  for (INDEX i = 1; i <= Height(); i++)
+    {
+    for (INDEX j = 1; j < Width(); j++)
+      s << (*this)(i, j) << "  ";
+    s << (*this)(i, Width()) << endl;
+    }
+
+  return s;
+  }
+
+
+
+TempVector BaseMatrix :: operator* (const BaseVector & v) const
+  {
+  Vector * prod = new Vector(Height());
+
+  if (Width() != v.Length())
+    {
+    (*myerr) << "\nMatrix and Vector don't fit 1" << endl;
+    }
+  else if (Height() != prod->Length())
+    {
+    (*myerr) << "Base_Matrix::operator*(Vector): prod vector not ok" << endl;
+    }
+  else
+    {
+    Mult (v, *prod);
+    }
+
+  return *prod;
+  }
+
+
+
+DenseMatrix operator* (const BaseMatrix & m1, const BaseMatrix & m2)
+  {
+  DenseMatrix temp (m1.Height(), m2.Width());
+  double sum;
+
+  if (m1.Width() != m2.Height())
+         {
+         (*myerr) << "BaseMatrix :: operator*: Matrix Size does not fit" << endl;
+         }
+  else if (temp.Height() != m1.Height())
+         {
+         (*myerr) << "BaseMatrix :: operator*: temp not allocated" << endl;
+    }
+  else
+    {
+    for (INDEX i = 1; i <= m1.Height(); i++)
+      for (INDEX j = 1; j <= m2.Width(); j++)
+        {
+        sum = 0;
+        for (INDEX k = 1; k <= m1.Width(); k++)
+          sum += m1(i, k) * m2(k, j);
+        temp(i, j) = sum;
+        }
+    }
+  return temp;
+  }
+
+
+DenseMatrix operator+ (const BaseMatrix & m1, const BaseMatrix & m2)
+  {
+  DenseMatrix temp (m1.Height(), m1.Width());
+  INDEX i, j;
+
+  if (m1.Width() != m2.Width() || m1.Height() != m2.Height())
+    {
+    (*myerr) << "BaseMatrix :: operator+: Matrix Size does not fit" << endl;
+    }
+  else if (temp.Height() != m1.Height())
+    {
+    (*myerr) << "BaseMatrix :: operator+: temp not allocated" << endl;
+    }
+  else
+    {
+    for (i = 1; i <= m1.Height(); i++)
+      for (j = 1; j <= m1.Width(); j++)
+        {
+        temp(i, j) = m1(i, j) + m2(i, j);
+        }
+    }
+  return temp;
+  }
+
+
+void BaseMatrix :: Mult (const BaseVector & /* v */,
+      BaseVector & /* prod */) const
+  {
+  (*myerr) << "BaseMatrix :: Mult called" << endl;
+  }
+
+void BaseMatrix :: MultTrans (const BaseVector &  v,
+      BaseVector & prod) const
+  {
+  if (Symmetric())
+    Mult (v, prod);
+  else
+    (*myerr) << "BaseMatrix :: MultTrans called for non symmetric matrix" << endl;
+  }
+
+void BaseMatrix :: Residuum (const BaseVector &  x,
+      const BaseVector & b, BaseVector & res) const
+  {
+  Mult (x, res);
+  res *= -1;
+  res.Add (1, b);
+  }
+
+void BaseMatrix :: ResiduumTrans (const BaseVector & x,
+      const BaseVector & b, BaseVector & res) const
+  {
+  MultTrans (x, res);
+  res *= -1;
+  res.Add (1, b);
+  }
+
+BaseMatrix * BaseMatrix :: Copy () const
+  {
+  (*myerr) << "BaseMatrix :: Copy called" << endl;
+  return NULL;
+  }
+
+
+BaseVector * BaseMatrix :: CreateVector () const
+  {
+  return new Vector (Height());
+  }
+
+
+
+/*
+void BaseMatrix :: Mult (const Vector & v, Vector & prod) const
+  {
+  double sum;
+
+  prod.SetLength (Height());
+
+  if (Width() != v.Length())
+    {
+    (*myerr) << "\nMatrix and Vector don't fit 2" << endl;
+    }
+  else if (Height() != prod.Length())
+    {
+    (*myerr) << "Base_Matrix::operator*(Vector): prod vector not ok" << endl;
+    }
+  else
+    {
+    for (INDEX i = 1; i <= Height(); i++)
+      {
+      sum = 0;
+
+      for (INDEX j = 1; j <= Width(); j++)
+        sum += (*this)(i,j) * v.Get(j);
+
+      prod.Set (i, sum);
+      }
+    }
+  }
+
+
+void BaseMatrix :: MultTrans (const Vector & v, Vector & prod) const
+  {
+  double sum;
+
+  prod.SetLength (Width());
+
+  if (Height() != v.Length())
+    {
+    (*myerr) << "\nMatrix and Vector don't fit 3" << endl;
+    }
+  else if (Width() != prod.Length())
+    {
+    (*myerr) << "Base_Matrix::operator*(Vector): prod vector not ok" << endl;
+    }
+  else
+    {
+    for (INDEX i = 1; i <= Width(); i++)
+      {
+      sum = 0;
+
+      for (INDEX j = 1; j <= Height(); j++)
+        sum += (*this)(j, i) * v.Get(j);
+
+      prod.Set (i, sum);
+      }
+    }
+  }
+
+
+void BaseMatrix :: Residuum (const Vector & x, const Vector & b, Vector & res) const
+  {
+  double sum;
+
+  res.SetLength (Height());
+
+  if (Width() != x.Length() || Height() != b.Length())
+    {
+    (*myerr) << "\nMatrix and Vector don't fit 4" << endl;
+    }
+  else if (Height() != res.Length())
+    {
+    (*myerr) << "Base_Matrix::operator*(Vector): prod vector not ok" << endl;
+    }
+  else
+    {
+    for (INDEX i = 1; i <= Height(); i++)
+      {
+      sum = b.Get(i);
+
+      for (INDEX j = 1; j <= Width(); j++)
+        sum -= (*this)(i,j) * x.Get(j);
+
+      res.Set (i, sum);
+      }
+    }
+  }
+*/
+
+
+
+
+
+
+
+void BaseMatrix :: SolveDestroy (const Vector & v, Vector & sol)
+  {
+  INDEX i, j, k;
+  double q;
+
+  if (Width() != Height())
+    {
+    (*myerr) << "SolveDestroy: Matrix not square";
+    return;
+    }
+  if (Width() != v.Length())
+    {
+    (*myerr) << "SolveDestroy: Matrix and Vector don't fit";
+    return;
+    }
+
+  sol = v;
+  if (Height() != sol.Length())
+    {
+    (*myerr) << "SolveDestroy: Solution Vector not ok";
+    return;
+    }
+
+  for (i = 1; i <= Height(); i++)
+    {
+    for (j = i+1; j <= Height(); j++)
+      {
+      q=(*this)(j,i) / (*this)(i,i);
+      for (k = i+1; k <= Height(); k++)
+        {
+        (*this)(j, k) -= q * (*this)(i,k);
+        }
+      sol.Elem(j) -= q * sol.Get(i);
+      }
+    }
+
+  for (i = Height(); i >= 1; i--)
+    {
+    q = sol(i);
+    for (j = i+1; j <= Height(); j++)
+      {
+      q -= (*this)(i,j) * sol.Get(j);
+      }
+    sol.Set(i, q / (*this)(i,i));
+    }
+  }
+
+void BaseMatrix :: Solve (const Vector & v, Vector & sol) const
+  {
+  BaseMatrix * temp = Copy();
+
+  if (temp->Height() != Height())
+    {
+    (*myerr) << "Solve: Matrix temp not allocated" << endl;
+    return;
+    }
+
+  temp->SolveDestroy (v, sol);
+
+  delete temp;
+  }
+
+
+Vector BaseMatrix :: SolveDestroyFunc (const Vector & /* b */) const
+{
+  return Vector(0);
+}
+
+
+
+Vector BaseMatrix :: Solve (const Vector & v) const
+  {
+  Vector sol (v.Length());
+
+  if (Width() != Height())
+    {
+    (*myerr) << "Solve: Matrix not square";
+    return v;
+    }
+  if (Width() != v.Length())
+    {
+    (*myerr) << "Solve: Matrix and Vector don't fit";
+    return v;
+    }
+  if (Width() != sol.Length())
+    {
+    (*myerr) << "Solve: Vector sol not allocated" << endl;
+    }
+
+  Solve (v, sol);
+
+  return sol;
+  }
+
+
+
+
+
+
+
+void BaseMatrix :: LU_Decomposition (DenseMatrix & l, DenseMatrix & u) const
+  {
+  INDEX i, j ,k;
+  double sum;
+  l.SetSize (Width());
+  u.SetSize (Width());
+
+  for (i = 1; i <= Width(); i++)
+    for (j = 1; j <= Width(); j++)
+      l(i, j) = u(i, j) = 0;
+
+  for (i = 1; i <= Width(); i++)
+    {
+    for (k = 1; k < i; k++)
+      {
+      sum = (*this)(i, k);
+      for (j = 1; j < k; j++)
+        sum -= l(i, j) * u(j, k);
+      l(i, k) = sum / u(k, k);
+      }
+    l(i, i) = 1;
+
+    for (k = i; k <= Width(); k++)
+      {
+      sum = (*this)(i, k);
+      for (j = 1; j < i; j++)
+        sum -= l(i, j) * u(j, k);
+      u(i, k) = sum;
+      }
+    }
+  }
+
+
+
+void Transpose (const BaseMatrix & m1, DenseMatrix & m2)
+  {
+  m2.SetSize (m1.Width(), m1.Height());
+  INDEX i, j;
+
+  for (i = 1; i <= m1.Height(); i++)
+    for (j = 1; j <= m1.Width(); j++)
+      m2(j, i) = m1(i, j);
+  }
+
+
+
+DenseMatrix * BaseMatrix :: MakeDenseMatrix () const
+{
+  DenseMatrix * dmat = new DenseMatrix (Height(), Width());
+  dmat -> SetSymmetric(Symmetric());
+
+  Vector x(Width()), y(Height());
+  INDEX i, j;
+
+  for (i = 1; i <= Width(); i++)
+    {
+      x = 0;
+      x.Elem(i) = 1;
+      Mult (x, y);
+      
+      for (j = 1; j <= Height(); j++)
+	dmat->Elem(j, i) = y.Get(j);
+    }
+
+  return dmat;
+}
+ 
+
+BaseMatrix * BaseMatrix :: InverseMatrix (const BitArray * /* inner */) const
+{
+  (*mycout) << "called basematrix::inversemarix" << endl;
+  return NULL;
+}
+
+
+
+}
diff --git a/Netgen/libsrc/linalg/basemat.hpp b/Netgen/libsrc/linalg/basemat.hpp
new file mode 100644
index 0000000000..89a9e21411
--- /dev/null
+++ b/Netgen/libsrc/linalg/basemat.hpp
@@ -0,0 +1,105 @@
+#ifndef FILE_BASEMAT
+#define FILE_BASEMAT
+
+/**************************************************************************/
+/* File:   basemat.hh                                                     */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Oct. 94                                                    */
+/**************************************************************************/
+
+/* 
+   Base type for linear operator
+*/
+
+class DenseMatrix;
+
+///
+class BaseMatrix
+{
+protected:
+  ///
+  INDEX height, width;
+  ///
+  int symmetric;
+  ///
+  static double shit;
+
+public:
+  ///
+  BaseMatrix ();
+  ///
+  BaseMatrix (INDEX h, INDEX w = 0);
+  ///
+  virtual ~BaseMatrix () { };
+
+  ///
+  INDEX Width () const { return width; }
+  ///
+  INDEX Height () const { return height; }
+  ///
+  int Symmetric () const { return symmetric; }
+
+  ///
+  virtual void SetSize (INDEX h, INDEX w = 0);
+  ///
+  virtual void SetSymmetric (int sym = 1);
+
+  ///
+  virtual double & operator() (INDEX i, INDEX j);
+  ///
+  virtual double operator() (INDEX i, INDEX j) const;
+
+  ///
+  friend ostream & operator<<(ostream & s, const BaseMatrix & m);
+  ///
+  virtual ostream & Print (ostream & s) const;
+
+  ///
+  TempVector operator* (const BaseVector & v) const;
+
+
+  ///
+  virtual void Mult (const BaseVector & v, BaseVector & prod) const;
+  ///
+  virtual void MultTrans (const BaseVector & v, BaseVector & prod) const;
+  ///
+  virtual void Residuum (const BaseVector & x, const BaseVector & b, BaseVector & res) const;
+  ///
+  virtual void ResiduumTrans (const BaseVector & x, const BaseVector & b, BaseVector & res) const;
+  //  virtual double EvaluateBilinearform (const BaseVector & x);
+
+  virtual BaseMatrix * Copy () const;
+  ///
+  virtual BaseVector * CreateVector () const;
+
+  ///
+  virtual void AddElementMatrix (const ARRAY<INDEX> & /* pnum */, 
+				 const BaseMatrix & /* elemmat */) { };
+  ///
+  virtual void MultElementMatrix (const ARRAY<INDEX> & /* pnum */, 
+				  const BaseVector & /* x */, BaseVector & /* y */) { };
+  ///
+  virtual void MultTransElementMatrix (const ARRAY<INDEX> & /* pnum */, 
+				       const BaseVector & /* x */, BaseVector & /* y */) { };
+
+
+  ///
+  virtual DenseMatrix * MakeDenseMatrix () const;
+  ///
+  virtual BaseMatrix * InverseMatrix (const class BitArray * inner = NULL)
+    const;
+
+  ///
+  virtual void SolveDestroy (const Vector & b, Vector & x);
+  ///
+  void Solve (const Vector & b, Vector & x) const;
+  ///
+  virtual Vector SolveDestroyFunc (const Vector & b) const;
+  ///
+  Vector Solve (const Vector & b) const;
+  ///
+  virtual void LU_Decomposition (DenseMatrix & l, DenseMatrix & u) const;
+};
+
+
+#endif
diff --git a/Netgen/libsrc/linalg/densemat.cpp b/Netgen/libsrc/linalg/densemat.cpp
new file mode 100644
index 0000000000..d15c123e0d
--- /dev/null
+++ b/Netgen/libsrc/linalg/densemat.cpp
@@ -0,0 +1,1443 @@
+#include <mystdlib.h>
+
+#include <linalg.hpp>
+
+
+namespace netgen
+{
+  DenseMatrix :: DenseMatrix () 
+  {
+    data = NULL;
+    height = 0;
+    width = 0;
+  }
+
+  DenseMatrix :: DenseMatrix (int h, int w)
+  {
+    if (!w) w = h;
+    width = w;
+    height = h;
+    if (h*w)
+      data = new double[h*w];
+    else 
+      data = 0;
+
+    for (int i = 0 ; i < (h * w); i++)
+      data[i] = 0;
+  }
+
+  /*
+  DenseMatrix :: DenseMatrix (int h, int w, const double * d) 
+    : BaseMatrix (h, w)
+  {
+  int size = h * w;  
+  int i;
+  
+  if (size)
+    {
+      data = new double[size]; 
+      for (i = 0; i < size; i++)
+	data[i] = d[i];
+    }
+  else
+    data = NULL;
+  }    
+  */
+
+  DenseMatrix :: DenseMatrix (const DenseMatrix & m2)
+  {
+    data = NULL;
+    SetSize (m2.Height(), m2.Width());
+    memcpy (data, m2.data, sizeof(double) * Height() * Width());
+  }
+
+  DenseMatrix :: ~DenseMatrix ()
+  {
+    delete [] data;
+  }
+  
+  
+  void DenseMatrix :: SetSize (int h, int w)
+  {
+    if (!w) w = h;
+    if (height == h && width == w) return;
+    
+    height = h;
+    width = w;
+    
+    delete[] data;
+    
+    if (h*w)  
+      data = new double[h*w];
+    else
+      data = NULL;
+  }
+
+
+  /*
+DenseMatrix & DenseMatrix :: operator= (const BaseMatrix & m2)
+  {
+  int i, j;
+
+  SetSize (m2.Height(), m2.Width());
+
+  if (data)
+    for (i = 1; i <= Height(); i++)
+      for (j = 1; j <= Width(); j++)
+        Set (i, j, m2(i, j));
+  else
+    (*myerr) << "DenseMatrix::Operator=: Matrix not allocated" << endl;
+
+  return *this;
+  }
+  */
+
+
+  DenseMatrix & DenseMatrix :: operator= (const DenseMatrix & m2)
+  {
+    SetSize (m2.Height(), m2.Width());
+    
+    if (data) memcpy (data, m2.data, sizeof(double) * m2.Height() * m2.Width());
+    return *this;
+  }
+
+
+  DenseMatrix & DenseMatrix :: operator+= (const DenseMatrix & m2)
+  {
+    int i;
+    double * p, * q;
+    
+    if (Height() != m2.Height() || Width() != m2.Width())
+    {
+      (*myerr) << "DenseMatrix::Operator+=: Sizes don't fit" << endl;
+      return *this;
+    }
+    
+    if (data)
+      {
+	p = data;
+	q = m2.data;
+	for (i = Width() * Height(); i > 0; i--)
+      {
+      *p += *q;
+      p++;
+      q++;
+      }
+    }
+  else
+    (*myerr) << "DenseMatrix::Operator+=: Matrix not allocated" << endl;
+
+  return *this;
+  }
+
+
+DenseMatrix & DenseMatrix :: operator-= (const DenseMatrix & m2)
+  {
+  int i;
+  double * p, * q;
+
+  if (Height() != m2.Height() || Width() != m2.Width())
+    {
+    (*myerr) << "DenseMatrix::Operator-=: Sizes don't fit" << endl;
+    return *this;
+    }
+
+  if (data)
+    {
+    p = data;
+    q = m2.data;
+    for (i = Width() * Height(); i > 0; i--)
+      {
+      *p -= *q;
+      p++;
+      q++;
+      }
+    }
+  else
+    (*myerr) << "DenseMatrix::Operator-=: Matrix not allocated" << endl;
+
+  return *this;
+  }
+
+
+
+
+  /*
+double & DenseMatrix :: operator() (int i, int j)
+{
+  if (i >= 1 && j >= 1 && i <= height && j <= width)
+    return Elem(i,j);
+  else (*myerr) << "DenseMatrix: index (" << i << "," << j << ") out of range (1.."
+		<< height << ",1.." << width << ")\n";
+  static double dummy = 0;
+  return dummy;
+}
+
+  double DenseMatrix :: operator() (int i, int j) const
+  {
+    if (i >= 1 && j >= 1 && i <= height && j <= width)
+      return Get(i,j);
+    else (*myerr) << "DenseMatrix: index (" << i << "," << j << ") out of range (1.."
+            << height << ",1.." << width << ")\n";
+
+    static double dummy = 0;
+    return dummy;
+  }
+  */
+
+DenseMatrix & DenseMatrix :: operator= (double v)
+  {
+  int i;
+  double * p = data;
+
+  if (data)
+    for (i = width*height; i > 0; i--, p++)
+      *p = v;
+
+  return *this;
+  }
+
+
+
+DenseMatrix & DenseMatrix :: operator*= (double v)
+  {
+  int i;
+  double * p = data;
+
+  if (data)
+    for (i = width*height; i > 0; i--, p++)
+      *p *= v;
+
+  return *this;
+  }
+
+
+double DenseMatrix :: Det () const
+  {
+  if (width != height)
+    {
+    (*myerr) << "DenseMatrix :: Det: width != height" << endl;
+    return 0;
+    }
+
+  switch (width)
+    {
+    case 1: return Get(1, 1);
+    case 2: return Get(1) * Get(4) - Get(2) * Get(3);
+
+    case 3: return Get(1) * Get(5) * Get(9)
+                 + Get(2) * Get(6) * Get(7)
+                 + Get(3) * Get(4) * Get(8)
+                 - Get(1) * Get(6) * Get(8)
+                 - Get(2) * Get(4) * Get(9)
+                 - Get(3) * Get(5) * Get(7);
+    default:
+      {
+      (*myerr) << "Matrix :: Det:  general size not implemented (size=" << width << ")" << endl;
+      return 0;
+      }
+    }
+  }
+
+
+void CalcInverse (const DenseMatrix & m1, DenseMatrix & m2)
+  {
+    //  int i, j, k, n;
+  double det;
+  //  DenseMatrix m1 = hm1;
+
+  if (m1.width != m1.height)
+    {
+    (*myerr) << "CalcInverse: matrix not symmetric" << endl;
+    return;
+    }
+  if (m1.width != m2.width || m1.height != m2.height)
+    {
+    (*myerr) << "CalcInverse: dim(m2) != dim(m1)" << endl;
+    return;
+    }
+
+
+  if (m1.Width() <= 3)
+    {
+    det = m1.Det();
+    if (det == 0)
+      {
+      (*myerr) << "CalcInverse: Matrix singular" << endl;
+      return;
+      }
+
+    det = 1e0 / det;
+    switch (m1.width)
+      {
+      case 1:
+        {
+        m2.Set(1, 1, det);
+        return;
+        }
+      case 2:
+        {
+        m2.Set(1, 1, det * m1.Get(4));
+        m2.Set(2, 2, det * m1.Get(1));  
+        m2.Set(1, 2, - det * m1.Get(2));
+        m2.Set(2, 1, - det * m1.Get(3));
+        return;
+        }
+      case 3:
+        {
+        m2.Set(1, 1,  det * (m1.Get(5) * m1.Get(9) - m1.Get(6) * m1.Get(8)));
+        m2.Set(2, 1, -det * (m1.Get(4) * m1.Get(9) - m1.Get(6) * m1.Get(7)));
+        m2.Set(3, 1,  det * (m1.Get(4) * m1.Get(8) - m1.Get(5) * m1.Get(7)));
+
+        m2.Set(1, 2, -det * (m1.Get(2) * m1.Get(9) - m1.Get(3) * m1.Get(8)));
+        m2.Set(2, 2,  det * (m1.Get(1) * m1.Get(9) - m1.Get(3) * m1.Get(7)));
+        m2.Set(3, 2, -det * (m1.Get(1) * m1.Get(8) - m1.Get(2) * m1.Get(7)));
+
+        m2.Set(1, 3,  det * (m1.Get(2) * m1.Get(6) - m1.Get(3) * m1.Get(5)));
+        m2.Set(2, 3, -det * (m1.Get(1) * m1.Get(6) - m1.Get(3) * m1.Get(4)));
+        m2.Set(3, 3,  det * (m1.Get(1) * m1.Get(5) - m1.Get(2) * m1.Get(4)));
+        return;
+        }
+      }
+    }
+    
+  else
+    {
+      int i, j, k, n;
+      n = m1.Height();
+      
+
+#ifdef CHOL
+      int dots = (n > 200);
+
+      // Cholesky
+      
+      double x;
+      Vector p(n);
+
+      m2 = m1;
+      /*
+      m2.SetSymmetric();
+      if (!m2.Symmetric())
+	cerr << "m should be symmetric for Cholesky" << endl;
+      */
+
+      for (i = 1; i <= n; i++)
+	for (j = 1; j < i; j++)
+	  m2.Elem(j, i) = m2.Get(i, j);
+      
+      for (i = 1; i <= n; i++)
+	{
+	  if (dots && i % 10 == 0)
+	    (*mycout) << "." << flush;
+
+	  for (j = i; j <= n; j++)
+	    {
+	      x = m2.Get(i, j);
+
+	      const double * pik = &m2.Get(i, 1);
+	      const double * pjk = &m2.Get(j, 1);
+
+	      for (k = i-2; k >= 0; --k, ++pik, ++pjk)
+		x -= (*pik) * (*pjk);
+		  
+	      // for (k = i-1; k >= 1; --k)
+	      //   x -= m2.Get(j, k) * m2.Get(i, k);
+
+	      if (i == j)
+		{
+		  if (x <= 0)
+		    {
+		      cerr << "Matrix indefinite 1" << endl;
+		      return;
+		    }
+		  
+		  p.Elem(i) = 1 / sqrt(x);
+		}
+	      else
+		{
+		  m2.Elem(j, i) = x * p.Get(i);
+		}
+	    }
+	}
+
+      for (i = 1; i <= n; i++)
+	m2.Elem(i, i) = 1 / p.Get(i);
+
+      // check: A = L L^t
+
+//       for (i = 1; i <= n; i++)
+// 	for (j = 1; j <= n; j++)
+// 	  {
+// 	    x = 0;
+// 	    for (k = 1; k <= i && k <= j; k++)
+// 	      x += m2.Get(i, k) * m2.Get(j, k);
+// 	    (*testout) << "err " << i << "," << j << " = " << (m1.Get(i, j) - x) << endl;
+// 	  }
+
+
+      
+      // calc L^{-1}, store upper triangle
+      
+      //      DenseMatrix hm(n);
+      //      hm = m2;
+
+      for (i = 1; i <= n; i++)
+	{
+	  if (dots && i % 10 == 0)
+	    (*mycout) << "+" << flush;
+
+	  for (j = i; j <= n; j++)
+	    {
+	      x = 0;
+	      if (j == i) x = 1;
+
+	      const double * pjk = &m2.Get(j, i);
+	      const double * pik = &m2.Get(i, i);
+	      for (k = i; k < j; k++, ++pjk, ++pik)
+		x -= *pik * *pjk;
+
+	      //  for (k = i; k < j; k++)
+	      //  x -= m2.Get(j, k) * m2.Get(i, k);
+
+	      m2.Elem(i, j) = x / m2.Get(j, j);
+	    }
+	}
+      
+//      (*testout) << "check L^-1" << endl;
+//      for (i = 1; i <= n; i++)
+// 	for (j = 1; j <= n; j++)
+// 	  {
+// 	    x = 0;
+// 	    for (k = j; k <= i; k++)
+// 	      x += hm.Get(i, k) * m2.Get(j, k);
+// 	    (*testout) << "i, j = " << i << "," << j << " x = " << x << endl;
+// 	  }
+
+
+      // calc A^-1 = L^-T * L^-1
+
+      for (i = 1; i <= n; i++)
+	{
+	  if (dots && i % 10 == 0)
+	    (*mycout) << "-" << flush;
+
+	  for (j = 1; j <= i; j++)
+	    {
+	      x = 0;
+	      k = i;
+	      if (j > i) k = j;
+
+	      const double * pik = &m2.Get(i, k);
+	      const double * pjk = &m2.Get(j, k);
+
+	      for ( ; k <= n; ++k, ++pik, ++pjk)
+		x += *pik * *pjk;
+	      // for (  ; k <= n; k++)
+	      //   x += m2.Get(i, k) * m2.Get(j, k);
+	      
+	      m2.Elem(i, j) = x;
+	    }
+	}
+	  
+      for (i = 1; i <= n; i++)
+	for (j = 1; j < i; j++)
+	  m2.Elem(j, i) = m2.Get(i, j);
+      
+      if (dots) (*mycout) << endl;
+#endif
+
+
+
+      // Gauss - Jordan - algorithm
+      
+      int r, hi;
+      double max, hr;
+      
+
+      ARRAY<int> p(n);   // pivot-permutation
+      Vector hv(n);
+    
+      
+      m2 = m1;
+
+      /*      
+      if (m2.Symmetric())
+	for (i = 1; i <= n; i++)
+	  for (j = 1; j < i; j++)
+	    m2.Elem(j, i) = m2.Get(i, j);
+      */
+      
+    // Algorithm of Stoer, Einf. i. d. Num. Math, S 145
+      
+      for (j = 1; j <= n; j++)
+	p.Set(j, j);
+      
+      for (j = 1; j <= n; j++)
+	{
+	  // pivot search
+	  
+	  max = fabs(m2.Get(j, j));
+	  r = j;
+	  
+	  for (i = j+1; i <= n ;i++)
+	    if (fabs (m2.Get(i, j)) > max)
+	      {
+		r = i;
+		max = fabs (m2.Get(i, j));
+	      }
+	  
+	  if (max < 1e-20)
+	    {
+	      cerr << "Inverse matrix: matrix singular" << endl;
+	      return;
+	    }
+	  
+	  r = j;
+	  
+	  // exchange rows
+	  if (r > j)
+	    {
+	      for (k = 1; k <= n; k++)
+		{
+		  hr = m2.Get(j, k);
+		  m2.Elem(j, k) = m2.Get(r, k);
+		  m2.Elem(r, k) = hr;
+		}
+	      hi = p.Get(j);
+	      p.Elem(j) = p.Get(r);
+	      p.Elem(r) = hi;
+	    }
+	  
+	  
+	  // transformation
+	  
+	  hr = 1 / m2.Get(j, j);
+	  for (i = 1; i <= n; i++)
+	    m2.Elem(i, j) *= hr;
+	  m2.Elem(j, j) = hr;
+	  
+	  for (k = 1; k <= n; k++)
+	    if (k != j)
+	      {
+		for (i = 1; i <= n; i++)
+		  if (i != j)
+		    m2.Elem(i, k) -= m2.Elem(i, j) * m2.Elem(j, k);
+		m2.Elem(j, k) *= -hr;
+	      }
+	}
+      
+      // col exchange
+      
+      for (i = 1; i <= n; i++)
+	{
+	  for (k = 1; k <= n; k++)
+	    hv.Elem(p.Get(k)) = m2.Get(i, k);
+	  for (k = 1; k <= n; k++)
+	    m2.Elem(i, k) = hv.Get(k);
+	}
+
+
+
+    /*
+    if (m1.Symmetric())
+      for (i = 1; i <= n; i++)
+	for (j = 1; j < i; j++)
+	  m1.Elem(j, i) = m1.Get(i, j);
+
+    m2 = 0;
+    
+    for (i = 1; i <= n; i++)
+      m2.Elem(i, i) = 1;
+      
+    for (i = 1; i <= n; i++)
+      {
+	//	(*mycout) << '.' << flush;
+      q = m1.Get(i, i);
+      for (k = 1; k <= n; k++)
+        {
+        m1.Elem(i, k) /= q;
+        m2.Elem(i, k) /= q;
+        }
+        
+      for (j = i+1; j <= n; j++)
+        {
+        q = m1.Elem(j, i);
+
+	double * m1pi = &m1.Elem(i, i);
+	double * m1pj = &m1.Elem(j, i);
+
+	for (k = n; k >= i; --k, ++m1pi, ++m1pj)
+	    *m1pj -= q * (*m1pi);
+
+	double * m2pi = &m2.Elem(i, 1);
+	double * m2pj = &m2.Elem(j, 1);
+
+	for (k = i; k > 0; --k, ++m2pi, ++m2pj)
+	    *m2pj -= q * (*m2pi);
+
+	    //        for (k = 1; k <= n; k++)  
+	    //          {
+	    //          m1.Elem(j, k) -= q * m1.Elem(i, k);
+	    //          m2.Elem(j, k) -= q * m2.Elem(i, k);
+	    //          }
+	  
+        }
+      }  
+            
+    for (i = n; i >= 1; i--)
+      {
+	//	(*mycout) << "+" << flush;
+	for (j = 1; j < i; j++)
+	  {
+	    q = m1.Elem(j, i);
+
+	    double * m2pi = &m2.Elem(i, 1);
+	    double * m2pj = &m2.Elem(j, 1);
+
+	    for (k = n; k > 0; --k, ++m2pi, ++m2pj)
+	      *m2pj -= q * (*m2pi);	    
+
+	    
+	    //	    for (k = 1; k <= n; k++)
+	    //	      {
+	    //		m1.Elem(j, k) -= q * m1.Elem(i, k);
+	    //		m2.Elem(j, k) -= q * m2.Elem(i, k);
+	    //	      }    
+	  }         
+      }
+
+    if (m2.Symmetric())
+      {
+	for (i = 1; i <= n; i++)
+	  for (j = 1; j < i; j++)
+	    m2.Elem(i, j) = m2.Elem(j, i);
+      }
+*/
+    }
+  }
+
+
+void CalcAAt (const DenseMatrix & a, DenseMatrix & m2)
+  {
+  int n1 = a.Height();
+  int n2 = a.Width();
+  int i, j, k;
+  double sum;
+  const double *p, *q, *p0;
+
+  if (m2.Height() != n1 || m2.Width() != n1)
+    {
+    (*myerr) << "CalcAAt: sizes don't fit" << endl;
+    return;
+    }
+
+  for (i = 1; i <= n1; i++)
+    {
+    sum = 0;
+    p = &a.ConstElem(i, 1);
+    for (k = 1; k <= n2; k++)
+      {
+      sum += *p * *p;
+      p++;
+      }
+    m2.Set(i, i, sum);
+
+    p0 = &a.ConstElem(i, 1);
+    q = a.data;
+    for (j = 1; j < i; j++)
+      {
+      sum = 0;
+      p = p0;
+
+      for (k = 1; k <= n2; k++)
+        {
+        sum += *p * *q;
+        p++;
+        q++;
+        }
+      m2.Set(i, j, sum);
+      m2.Set(j, i, sum);
+      }
+    }
+  }
+
+
+
+#ifdef ABC
+BaseMatrix * DenseMatrix :: InverseMatrix (const BitArray * /* inner */) const
+{
+  if (Height() != Width())
+    {
+      (*myerr) << "BaseMatrix::InverseMatrix(): Matrix not symmetric" << endl;
+      return new DenseMatrix(1);
+    }
+  else
+    {
+      if (Symmetric())
+	{	
+	  (*mycout) << "Invmat not available" << endl;
+	  BaseMatrix * invmat = NULL;
+	  return invmat;
+	}
+
+      DenseMatrix * invmat = new DenseMatrix (Height());
+
+      CalcInverse (*this, *invmat);
+      return invmat;
+    }
+}
+#endif
+
+
+
+void CalcAtA (const DenseMatrix & a, DenseMatrix & m2)
+  {
+  int n1 = a.Height();
+  int n2 = a.Width();
+  int i, j, k;
+  double sum;
+
+  if (m2.Height() != n2 || m2.Width() != n2)
+    {
+    (*myerr) << "CalcAtA: sizes don't fit" << endl;
+    return;
+    }
+
+  for (i = 1; i <= n2; i++)
+    for (j = 1; j <= n2; j++)
+      {
+      sum = 0;
+      for (k = 1; k <= n1; k++)
+        sum += a.Get(k, i) * a.Get(k, j);
+      m2.Elem(i, j) = sum;
+      }
+  }
+
+
+
+
+
+
+void CalcABt (const DenseMatrix & a, const DenseMatrix & b, DenseMatrix & m2)
+  {
+  int n1 = a.Height();
+  int n2 = a.Width();
+  int n3 = b.Height();
+  int i, j, k;
+  double sum;
+
+  if (m2.Height() != n1 || m2.Width() != n3 || b.Width() != n2)
+    {
+    (*myerr) << "CalcABt: sizes don't fit" << endl;
+    return;
+    }
+
+  double * pm2 = &m2.Elem(1, 1);
+  const double * pa1 = &a.Get(1, 1);
+
+  for (i = 1; i <= n1; i++)
+    {
+      const double * pb = &b.Get(1, 1);
+      for (j = 1; j <= n3; j++)
+	{
+	  sum = 0;
+	  const double * pa = pa1;
+	  
+	  for (k = 1; k <= n2; k++)
+	    {
+	      sum += *pa * *pb;
+	      pa++; pb++;
+	    }
+	  
+	  *pm2 = sum;
+	  pm2++;
+	}
+      pa1 += n2;
+    }
+  }
+
+
+void CalcAtB (const DenseMatrix & a, const DenseMatrix & b, DenseMatrix & m2)
+  {
+  int n1 = a.Height();
+  int n2 = a.Width();
+  int n3 = b.Width();
+  int i, j, k;
+
+  if (m2.Height() != n2 || m2.Width() != n3 || b.Height() != n1)
+    {
+    (*myerr) << "CalcAtB: sizes don't fit" << endl;
+    return;
+    }
+
+  for (i = 1; i <= n2 * n3; i++)
+    m2.data[i-1] = 0;
+
+  for (i = 1; i <= n1; i++)
+    for (j = 1; j <= n2; j++)
+      {
+	const double va = a.Get(i, j);
+	double * pm2 = &m2.Elem(j, 1);
+	const double * pb = &b.Get(i, 1);
+
+	for (k = 1; k <= n3; ++k, ++pm2, ++pb)
+	  *pm2 += va * *pb;
+	//	for (k = 1; k <= n3; k++)
+	//	  m2.Elem(j, k) += va * b.Get(i, k);
+      }
+  /*
+  for (i = 1; i <= n2; i++)
+    for (j = 1; j <= n3; j++)
+      {
+	sum = 0;
+	for (k = 1; k <= n1; k++)
+	  sum += a.Get(k, i) * b.Get(k, j);
+	m2.Elem(i, j) = sum;
+      }
+      */
+  }
+
+
+
+
+
+
+
+DenseMatrix operator* (const DenseMatrix & m1, const DenseMatrix & m2)
+  {
+  DenseMatrix temp (m1.Height(), m2.Width());
+
+  if (m1.Width() != m2.Height())
+    {
+    (*myerr) << "DenseMatrix :: operator*: Matrix Size does not fit" << endl;
+    }
+  else if (temp.Height() != m1.Height())
+    {
+    (*myerr) << "DenseMatrix :: operator*: temp not allocated" << endl;
+    }
+  else
+    {
+    Mult (m1, m2, temp);
+    }
+  return temp;
+  }
+
+
+void Mult (const DenseMatrix & m1, const DenseMatrix & m2, DenseMatrix & m3)
+  {
+  double sum;
+  double *p1, *p1s, *p1sn, *p1snn, *p2, *p2s, *p2sn, *p3;
+
+  if (m1.Width() != m2.Height() || m1.Height() != m3.Height() ||
+       m2.Width() != m3.Width() )
+    {
+    (*myerr) << "DenseMatrix :: Mult: Matrix Size does not fit" << endl;
+    (*myerr) << "m1: " << m1.Height() << " x " << m1.Width() << endl;
+    (*myerr) << "m2: " << m2.Height() << " x " << m2.Width() << endl;
+    (*myerr) << "m3: " << m3.Height() << " x " << m3.Width() << endl;
+    return;
+    }
+  /*
+  else if (m1.Symmetric() || m2.Symmetric() || m3.Symmetric())
+    {
+    (*myerr) << "DenseMatrix :: Mult: not implemented for symmetric matrices" << endl;
+    return;
+    }
+  */
+  else
+    {
+      //      int i, j, k;
+      int n1 = m1.Height();
+      int n2 = m2.Width();
+      int n3 = m1.Width();
+
+      /*
+      for (i = n1 * n2-1; i >= 0; --i)
+	m3.data[i] = 0;
+
+      const double * pm1 = &m1.Get(1, 1);
+      for (i = 1; i <= n1; i++)
+	{
+	  const double * pm2 = &m2.Get(1, 1);
+	  double * pm3i = &m3.Elem(i, 1);
+
+	  for (j = 1; j <= n3; j++)
+	    {
+	      const double vm1 = *pm1;
+	      ++pm1;
+	      //	      const double vm1 = m1.Get(i, j);
+	      double * pm3 = pm3i;
+	      //	      const double * pm2 = &m2.Get(j, 1);
+
+	      for (k = 0; k < n2; k++)
+		{
+		  *pm3 += vm1 * *pm2;
+		  ++pm2;
+		  ++pm3;
+		}
+
+	    //	    for (k = 1; k <= n2; k++)
+	    //	      m3.Elem(i, k) += m1.Get(i, j) * m2.Get(j, k);
+	    }
+	}
+	*/
+
+      /*
+      for (i = 1; i <= n1; i++)
+	for (j = 1; j <= n2; j++)
+	  {
+	    sum = 0;
+	    for (k = 1; k <= n3; k++)
+	      sum += m1.Get(i, k) * m2.Get(k, j);
+	    m3.Set(i, j, sum);
+	  }
+	  */
+
+
+      /*
+      for (i = 1; i <= n1; i++)
+	{
+	  const double pm1i = &m1.Get(i, 1);
+	  const double pm2j = &m2.Get(1, 1);
+
+	  for (j = 1; j <= n2; j++)
+	    {
+	      double sum = 0;
+	      const double * pm1 = pm1i;
+	      const double * pm2 = pm2j;
+	      pm2j++;
+
+	      for (k = 1; k <= n3; k++)
+		{
+		  sum += *pm1 * *pm2;
+		  ++pm1;
+		  pm2 += n2;
+		}
+	      
+	      m3.Set (i, j, sum);
+	    }
+	}
+	*/
+
+
+      p3 = m3.data;
+      p1s = m1.data;
+      p2sn = m2.data + n2;
+      p1snn = p1s + n1 * n3;
+
+      while (p1s != p1snn)
+	{
+	  p1sn = p1s + n3;
+	  p2s = m2.data;
+	  
+	  while (p2s != p2sn)
+	    {
+	      sum = 0;
+	      p1 = p1s;
+	      p2 = p2s;
+	      p2s++;
+
+	      while (p1 != p1sn)
+		{
+		  sum += *p1 * *p2;
+		  p1++;
+		  p2 += n2;
+		}
+	      *p3++ = sum;
+	    }
+	  p1s = p1sn;
+	}
+    }
+  }  
+
+
+
+DenseMatrix operator+ (const DenseMatrix & m1, const DenseMatrix & m2)
+  {
+  DenseMatrix temp (m1.Height(), m1.Width());
+  int i, j;
+
+  if (m1.Width() != m2.Width() || m1.Height() != m2.Height())
+    {
+    (*myerr) << "BaseMatrix :: operator+: Matrix Size does not fit" << endl;
+    }
+  else if (temp.Height() != m1.Height())
+    {
+    (*myerr) << "BaseMatrix :: operator+: temp not allocated" << endl;
+    }
+  else
+    {
+    for (i = 1; i <= m1.Height(); i++)
+      for (j = 1; j <= m1.Width(); j++)
+        {
+        temp.Set(i, j, m1.Get(i, j) + m2.Get(i, j));
+        }
+    }
+  return temp;
+  }
+
+
+
+
+void Transpose (const DenseMatrix & m1, DenseMatrix & m2)
+{
+  int w = m1.Width();
+  int h = m1.Height();
+  int i, j;
+
+  m2.SetSize (w, h);
+
+  double * pm2 = &m2.Elem(1, 1);
+  for (j = 1; j <= w; j++)
+    {
+      const double * pm1 = &m1.Get(1, j);
+      for (i = 1; i <= h; i++)
+	{
+	  *pm2 = *pm1;
+	  pm2 ++;
+	  pm1 += w;
+	}
+    }
+}
+
+
+/*
+void DenseMatrix :: Mult (const Vector & v, Vector & prod) const
+  {
+  double sum, val;
+  const double * mp, * sp;
+  double * dp;
+  // const Vector & v = bv.CastToVector();
+  // Vector & prod = bprod.CastToVector();
+  
+
+  int n = Height();
+  int m = Width();
+
+  if (prod.Size() != n)
+    prod.SetSize (n);
+
+#ifdef DEVELOP
+  if (!n) 
+    {
+      cout << "DenseMatrix::Mult  mheight = 0" << endl;
+    }
+  if (!m) 
+    {
+      cout << "DenseMatrix::Mult mwidth = 0" << endl;
+    }
+
+  if (m != v.Size())
+    {
+    (*myerr) << "\nMatrix and Vector don't fit" << endl;
+    }
+  else if (Height() != prod.Size())
+    {
+    (*myerr) << "Base_Matrix::operator*(Vector): prod vector not ok" << endl;
+    }
+  else
+#endif
+    {
+      if (Symmetric())
+	{
+	  int i, j;
+
+
+	  for (i = 1; i <= n; i++)
+	    {
+	      sp = &v.Get(1);
+	      dp = &prod.Elem(1);
+	      mp = &Get(i, 1);
+
+	      val = v.Get(i);
+	      sum = Get(i, i) * val;
+
+	      for (j = 1; j < i; ++j, ++mp, ++sp, ++dp)
+		{
+		  sum += *mp * *sp;
+		  *dp += val * *mp;
+		}
+
+	      prod.Elem(i) = sum;
+	    }
+	}
+      else
+	{
+	  mp = data;
+	  dp = &prod.Elem(1);
+	  for (int i = 1; i <= n; i++)
+	    {
+	      sum = 0;
+	      sp = &v.Get(1);
+	      
+	      for (int j = 1; j <= m; j++)
+		{
+		  //        sum += Get(i,j) * v.Get(j);
+		  sum += *mp * *sp;
+		  mp++;
+		  sp++;
+		}
+	      
+	      //      prod.Set (i, sum);
+	      *dp = sum;
+	      dp++;
+	    }
+	}
+    }
+  }
+*/
+
+void DenseMatrix :: MultTrans (const Vector & v, Vector & prod) const
+{
+  // const Vector & v = (const Vector&)bv; // .CastToVector();
+  // Vector & prod = (Vector & )bprod;     // .CastToVector();
+
+  /*
+  if (Height() != v.Size())
+    {
+    (*myerr) << "\nMatrix and Vector don't fit" << endl;
+    }
+  else if (Width() != prod.Size())
+    {
+    (*myerr) << "Base_Matrix::operator*(Vector): prod vector not ok" << endl;
+    }
+  else
+  */
+    {
+      int i, j;
+      int w = Width(), h = Height();
+      if (prod.Size() != w)
+	prod.SetSize (w);
+
+      const double * pmat = &Get(1, 1);
+      const double * pv = &v.Get(1);
+
+      prod = 0;
+
+      for (i = 1; i <= h; i++)
+	{
+	  double val = *pv;
+	  ++pv;
+
+	  double * pprod = &prod.Elem(1);
+
+	  for (j = w-1; j >= 0; --j, ++pmat, ++pprod)
+	    {
+	      *pprod += val * *pmat;
+	    }
+	}
+	
+      /*
+      double sum;
+
+      for (i = 1; i <= Width(); i++)
+	{
+	  sum = 0;
+	  
+	  for (int j = 1; j <= Height(); j++)
+	    sum += Get(j, i) * v.Get(j);
+	  
+	  prod.Set (i, sum);
+	}
+      */
+    }
+  }
+
+
+void DenseMatrix :: Residuum (const Vector & x, const Vector & b,
+      Vector & res) const
+  {
+  double sum;
+  //   const Vector & x = bx.CastToVector();
+  //  const Vector & b = bb.CastToVector();
+  //  Vector & res = bres.CastToVector();
+
+  res.SetSize (Height());
+
+  if (Width() != x.Size() || Height() != b.Size())
+    {
+    (*myerr) << "\nMatrix and Vector don't fit" << endl;
+    }
+  else if (Height() != res.Size())
+    {
+    (*myerr) << "Base_Matrix::operator*(Vector): prod vector not ok" << endl;
+    }
+  else
+    {
+      int i, j;
+      int h = Height(); 
+      int w = Width();
+      const double * mp = &Get(1, 1);
+
+      for (i = 1; i <= h; i++)
+	{
+	  sum = b.Get(i);
+	  const double * xp = &x.Get(1);
+
+	  for (j = 1; j <= w; ++j, ++mp, ++xp)
+	    sum -= *mp * *xp;
+	  
+	  res.Elem(i) = sum;
+	}
+    }
+  }
+
+#ifdef ABC
+double DenseMatrix :: EvaluateBilinearform (const Vector & hx) const
+  {
+  double sum = 0, hsum;
+  // const Vector & hx = x.CastToVector();
+  int i, j;
+
+  if (Width() != hx.Size() || Height() != hx.Size())
+    {
+    (*myerr) << "Matrix::EvaluateBilinearForm: sizes don't fit" << endl;
+    }
+  else
+    {
+    for (i = 1; i <= Height(); i++)
+      {
+      hsum = 0;
+      for (j = 1; j <= Height(); j++)
+        {
+        hsum += Get(i, j) * hx.Get(j);
+        }
+      sum += hsum * hx.Get(i);
+      }
+    }
+
+//  testout << "sum = " << sum << endl;
+  return sum;
+  }
+
+
+void DenseMatrix :: MultElementMatrix (const ARRAY<int> & pnum, 
+      const Vector & hx, Vector & hy)
+  {
+  int i, j;
+  //  const Vector & hx = x.CastToVector();
+  //  Vector & hy = y.CastToVector();
+
+  if (Symmetric())
+    {
+    for (i = 1; i <= Height(); i++)
+      {
+      for (j = 1; j < i; j++)
+        {
+	hy.Elem(pnum.Get(i)) += Get(i, j) * hx.Get(pnum.Get(j));
+	hy.Elem(pnum.Get(j)) += Get(i, j) * hx.Get(pnum.Get(i));
+	}
+      hy.Elem(pnum.Get(j)) += Get(i, i) * hx.Get(pnum.Get(i));	
+      }
+    }
+  else
+    for (i = 1; i <= Height(); i++)
+      for (j = 1; j <= Width(); j++)
+	hy.Elem(pnum.Get(i)) += Get(i, j) * hx.Get(pnum.Get(j));
+    
+  }
+  
+void DenseMatrix :: MultTransElementMatrix (const ARRAY<int> & pnum, 
+      const Vector & hx, Vector & hy)
+  {
+  int i, j;
+  //  const Vector & hx = x.CastToVector();
+  //  Vector & hy = y.CastToVector();
+
+  if (Symmetric())
+    MultElementMatrix (pnum, hx, hy);
+  else
+    for (i = 1; i <= Height(); i++)
+      for (j = 1; j <= Width(); j++)
+	hy.Elem(pnum.Get(i)) += Get(j, i) * hx.Get(pnum.Get(j));
+  }
+#endif
+
+
+void DenseMatrix :: Solve (const Vector & v, Vector & sol) const
+{
+  DenseMatrix temp (*this);
+  temp.SolveDestroy (v, sol);
+}
+
+
+void DenseMatrix :: SolveDestroy (const Vector & v, Vector & sol)
+  {
+  double q;
+
+  if (Width() != Height())
+    {
+    (*myerr) << "SolveDestroy: Matrix not square";
+    return;
+    }
+  if (Width() != v.Size())
+    {
+    (*myerr) << "SolveDestroy: Matrix and Vector don't fit";
+    return;
+    }
+
+  sol = v;
+  if (Height() != sol.Size())
+    {
+    (*myerr) << "SolveDestroy: Solution Vector not ok";
+    return;
+    }
+
+
+  if (0 /* Symmetric() */)
+    {
+      
+      // Cholesky factorization
+
+      int i, j, k, n;
+      n = Height();
+      
+      // Cholesky
+      
+      double x;
+      Vector p(n);
+
+      for (i = 1; i <= n; i++)
+	for (j = 1; j < i; j++)
+	  Elem(j, i) = Get(i, j);
+      
+      for (i = 1; i <= n; i++)
+	{
+	  // (*mycout) << "." << flush;
+	  for (j = i; j <= n; j++)
+	    {
+	      x = Get(i, j);
+
+	      const double * pik = &Get(i, 1);
+	      const double * pjk = &Get(j, 1);
+
+	      for (k = i-2; k >= 0; --k, ++pik, ++pjk)
+		x -= (*pik) * (*pjk);
+		  
+	      // for (k = i-1; k >= 1; --k)
+	      //   x -= Get(j, k) * Get(i, k);
+
+	      if (i == j)
+		{
+		  if (x <= 0)
+		    {
+		      cerr << "Matrix indefinite" << endl;
+		      return;
+		    }
+		  
+		  p.Elem(i) = 1 / sqrt(x);
+		}
+	      else
+		{
+		  Elem(j, i) = x * p.Get(i);
+		}
+	    }
+	}
+
+      for (i = 1; i <= n; i++)
+        Elem(i, i) = 1 / p.Get(i);
+
+      // A = L L^t 
+      // L stored in left-lower triangle
+
+
+      sol = v;
+
+      // Solve L sol = sol
+
+      for (i = 1; i <= n; i++)
+	{
+	  double val = sol.Get(i);
+
+	  const double * pij = &Get(i, 1);
+	  const double * solj = &sol.Get(1);
+
+	  for (j = 1; j < i; j++, ++pij, ++solj)
+	    val -= *pij * *solj;
+	  //	  for (j = 1; j < i; j++)
+	  //	    val -= Get(i, j) * sol.Get(j);
+
+	  sol.Elem(i) = val / Get(i, i);
+	}
+
+      // Solve L^t sol = sol
+
+      for (i = n; i >= 1; i--)
+	{
+	  double val = sol.Get(i) / Get(i, i);
+	  sol.Elem(i) = val;
+
+	  double * solj = &sol.Elem(1);
+	  const double * pij = &Get(i, 1);
+
+	  for (j = 1; j < i; ++j, ++pij, ++solj)
+	    *solj -= val * *pij;
+	  //	  for (j = 1; j < i; j++)
+	  //	    sol.Elem(j) -= Get(i, j) * val;
+	}
+
+
+    }
+  else
+    {
+      //      (*mycout) << "gauss" << endl;
+      int i, j, k, n = Height();
+      for (i = 1; i <= n; i++)
+	{
+	  for (j = i+1; j <= n; j++)
+	    {
+	      q = Get(j,i) / Get(i,i);
+	      if (q)
+		{
+		  const double * pik = &Get(i, i+1);
+		  double * pjk = &Elem(j, i+1);
+
+		  for (k = i+1; k <= n; ++k, ++pik, ++pjk)
+		    *pjk -= q * *pik;
+		  
+		  //  for (k = i+1; k <= Height(); k++)
+		  //	Elem(j, k) -= q * Get(i,k);
+
+
+		  sol.Elem(j) -= q * sol.Get(i);
+		}
+	    }
+	}
+      
+      for (i = n; i >= 1; i--)
+	{
+	  q = sol.Get(i);
+	  for (j = i+1; j <= n; j++)
+	      q -= Get(i,j) * sol.Get(j);
+
+	  sol.Elem(i) = q / Get(i,i);
+	}
+    }
+  }
+
+
+/*
+BaseMatrix * DenseMatrix :: Copy () const
+  {
+  return new DenseMatrix (*this);
+  }
+*/
+
+
+
+
+ostream & operator<< (ostream & ost, const DenseMatrix & m)
+{
+  for (int i = 0; i < m.Height(); i++)
+    {
+      for (int j = 0; j < m.Width(); j++)
+	ost << m.Get(i+1,j+1) << " ";
+      ost << endl;
+    }
+  return ost;
+}
+
+
+
+}
diff --git a/Netgen/libsrc/linalg/densemat.hpp b/Netgen/libsrc/linalg/densemat.hpp
new file mode 100644
index 0000000000..f2dc9bd605
--- /dev/null
+++ b/Netgen/libsrc/linalg/densemat.hpp
@@ -0,0 +1,260 @@
+#ifndef FILE_DENSEMAT
+#define FILE_DENSEMAT
+
+/**************************************************************************/
+/* File:   densemat.hh                                                    */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Oct. 94                                                    */
+/**************************************************************************/
+
+/** 
+    Data type dense matrix
+*/
+
+
+#include <assert.h>
+
+class DenseMatrix
+{
+protected:
+  int height;
+  int width;
+  double * data;
+
+public:
+  ///
+  DenseMatrix ();
+  ///
+  DenseMatrix (int h, int w = 0);
+  ///
+  DenseMatrix (const DenseMatrix & m2);
+  ///
+  ~DenseMatrix ();
+
+  ///
+  void SetSize (int h, int w = 0);
+
+  int Height() const { return height; }
+  int Width() const { return width; }
+
+  double & operator() (int i, int j) { return data[i*width+j]; }
+  double operator() (int i, int j) const { return data[i*width+j]; }
+
+  ///
+  DenseMatrix & operator= (const DenseMatrix & m2);
+  ///
+  DenseMatrix & operator+= (const DenseMatrix & m2);
+  ///
+  DenseMatrix & operator-= (const DenseMatrix & m2);
+
+  ///
+  DenseMatrix & operator= (double v);
+  ///
+  DenseMatrix & operator*= (double v);
+
+  ///
+  void Mult (const FlatVector & v, FlatVector & prod) const
+  {
+    double sum;
+    const double * mp, * sp;
+    double * dp;
+    
+    if (prod.Size() != height)
+      {
+	cerr << "Mult: wrong vector size " << endl;
+	assert (1);
+	// prod.SetSize (height);
+      }
+    
+#ifdef DEBUG
+    if (!height) 
+      {
+	cout << "DenseMatrix::Mult height = 0" << endl;
+      }
+    if (!width) 
+      {
+	cout << "DenseMatrix::Mult width = 0" << endl;
+      }
+    
+    if (width != v.Size())
+      {
+	(*myerr) << "\nMatrix and Vector don't fit" << endl;
+      }
+    else if (Height() != prod.Size())
+      {
+	(*myerr) << "Base_Matrix::operator*(Vector): prod vector not ok" << endl;
+      }
+    else
+#endif
+      {      
+	mp = data;
+	dp = &prod.Elem(1);
+	for (int i = 1; i <= height; i++)
+	  {
+	    sum = 0;
+	    sp = &v.Get(1);
+	    
+	    for (INDEX j = 1; j <= width; j++)
+	      {
+		//        sum += Get(i,j) * v.Get(j);
+		sum += *mp * *sp;
+		mp++;
+		sp++;
+	      }
+	    
+	    *dp = sum;
+	    dp++;
+	  }
+      }
+  }
+
+  ///
+  void MultTrans (const Vector & v, Vector & prod) const;
+  ///
+  void Residuum (const Vector & x, const Vector & b, Vector & res) const;
+  ///
+  double Det () const;
+
+  ///
+  friend DenseMatrix operator* (const DenseMatrix & m1, const DenseMatrix & m2);
+  ///
+  friend DenseMatrix operator+ (const DenseMatrix & m1, const DenseMatrix & m2);
+
+  /// 
+  friend void Transpose (const DenseMatrix & m1, DenseMatrix & m2);
+  ///
+  friend void Mult (const DenseMatrix & m1, const DenseMatrix & m2, DenseMatrix & m3);
+  ///
+  friend void CalcInverse (const DenseMatrix & m1, DenseMatrix & m2);
+  ///
+  friend void CalcAAt (const DenseMatrix & a, DenseMatrix & m2);
+  ///
+  friend void CalcAtA (const DenseMatrix & a, DenseMatrix & m2);
+  ///
+  friend void CalcABt (const DenseMatrix & a, const DenseMatrix & b, DenseMatrix & m2);
+  ///
+  friend void CalcAtB (const DenseMatrix & a, const DenseMatrix & b, DenseMatrix & m2);
+  ///
+  void Solve (const Vector & b, Vector & x) const;
+  ///
+  void SolveDestroy (const Vector & b, Vector & x);
+  ///
+  const double & Get(INDEX i, INDEX j) const { return data[(i-1)*width+j-1]; }
+  ///
+  const double & Get(INDEX i) const { return data[i-1]; }
+  ///
+  void Set(INDEX i, INDEX j, double v) { data[(i-1)*width+j-1] = v; }
+  ///
+  double & Elem(INDEX i, INDEX j) { return data[(i-1)*width+j-1]; }
+  ///
+  const double & ConstElem(INDEX i, INDEX j) const { return data[(i-1)*width+j-1]; }
+};
+
+
+extern ostream & operator<< (ostream & ost, const DenseMatrix & m);
+
+
+
+template <int WIDTH>
+class MatrixFixWidth
+{
+protected:
+  int height;
+  double * data;
+
+public:
+  ///
+  MatrixFixWidth () 
+  { height = 0; data = 0; }
+  ///
+  MatrixFixWidth (int h)
+  { height = h; data = new double[WIDTH*height]; }
+  ///
+  ~MatrixFixWidth ()
+  { delete [] data; }
+
+  void SetSize (int h)
+  {
+    if (h != height)
+      {
+	delete data;
+	height = h;
+	data = new double[WIDTH*height]; 
+      }
+  }
+
+  int Height() const { return height; }
+  int Width() const { return WIDTH; }
+
+  /*
+  ///
+  virtual double & operator() (INDEX i, INDEX j);
+  ///
+  virtual double operator() (INDEX i, INDEX j) const;
+  */
+
+  ///
+  MatrixFixWidth & operator= (double v)
+  {
+    for (int i = 0; i < height*WIDTH; i++)
+      data[i] = 0; 
+  }
+
+  ///
+  void Mult (const FlatVector & v, FlatVector & prod) const
+  {
+    double sum;
+    const double * mp, * sp;
+    double * dp;
+
+    /*    
+    if (prod.Size() != height)
+      {
+	cerr << "MatrixFixWidth::Mult: wrong vector size " << endl;
+	assert (1);
+      }
+    */    
+
+    mp = data;
+    dp = &prod[0];
+    for (int i = 0; i < height; i++)
+      {
+	sum = 0;
+	sp = &v[0];
+	
+	for (int j = 0; j < WIDTH; j++)
+	  {
+	    sum += *mp * *sp;
+	    mp++;
+	    sp++;
+	  }
+	    
+	*dp = sum;
+	dp++;
+      }
+  }
+
+  double & operator() (int i, int j)
+  { return data[i*WIDTH+j]; }
+
+  const double & operator() (int i, int j) const
+  { return data[i*WIDTH+j]; }
+
+
+
+  const double & Get(int i, int j) const { return data[(i-1)*WIDTH+j-1]; }
+  ///
+  const double & Get(int i) const { return data[i-1]; }
+  ///
+  void Set(int i, int j, double v) { data[(i-1)*WIDTH+j-1] = v; }
+  ///
+  double & Elem(int i, int j) { return data[(i-1)*WIDTH+j-1]; }
+  ///
+  const double & ConstElem(int i, int j) const { return data[(i-1)*WIDTH+j-1]; }
+};
+
+
+
+
+
+#endif
diff --git a/Netgen/libsrc/linalg/linalg.hpp b/Netgen/libsrc/linalg/linalg.hpp
new file mode 100644
index 0000000000..3dd73e8ef0
--- /dev/null
+++ b/Netgen/libsrc/linalg/linalg.hpp
@@ -0,0 +1,33 @@
+#ifndef FILE_LINALG
+#define FILE_LINALG
+
+/* *************************************************************************/
+/* File:   linalg.hpp                                                      */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Oct. 94                                                    */
+/* *************************************************************************/
+
+/* 
+
+   Data types for basic linear algebra
+   more data types are found in linalgl.hpp
+   
+   The basic concepts include the data types 
+   
+    Vector
+    SparseMatrix
+    DenseMatrix
+
+*/
+
+
+#include <myadt.hpp>
+namespace netgen
+{
+#include "vector.hpp"
+#include "densemat.hpp"
+#include "polynomial.hpp"
+}
+#endif
+
+
diff --git a/Netgen/libsrc/linalg/polynomial.cpp b/Netgen/libsrc/linalg/polynomial.cpp
new file mode 100644
index 0000000000..f947e0a191
--- /dev/null
+++ b/Netgen/libsrc/linalg/polynomial.cpp
@@ -0,0 +1,216 @@
+#include <mystdlib.h>
+#include <linalg.hpp>
+
+namespace netgen
+{
+
+QuadraticPolynomial1V :: 
+QuadraticPolynomial1V (double ac, double acx, double acxx)
+{
+  c = ac;
+  cx = acx;
+  cxx = acxx;
+}
+
+double QuadraticPolynomial1V :: 
+Value (double x)
+{
+  return c + cx * x + cxx * x * x;
+}
+
+double QuadraticPolynomial1V ::  MaxUnitInterval ()
+{
+  // inner max
+  if (cxx < 0 && cx > 0 && cx < -2 * cxx)
+    {
+      return c - 0.25 * cx * cx / cxx;
+    }
+
+  
+  if (cx + cxx > 0)   // right edge
+    return c + cx + cxx;
+
+  // left end
+  return c;
+}
+
+
+
+
+LinearPolynomial2V :: 
+LinearPolynomial2V (double ac, double acx, double acy)
+{
+  c = ac;
+  cx = acx;
+  cy = acy;
+};
+
+
+QuadraticPolynomial2V ::   
+QuadraticPolynomial2V ()
+{
+  ;
+}
+
+
+QuadraticPolynomial2V :: 
+QuadraticPolynomial2V (double ac, double acx, double acy,
+		       double acxx, double acxy, double acyy)
+{
+  c = ac;
+  cx = acx;
+  cy = acy;
+  cxx = acxx;
+  cxy = acxy;
+  cyy = acyy;
+}
+
+void QuadraticPolynomial2V :: 
+Square (const LinearPolynomial2V & lp)
+{
+  c = lp.c * lp.c;
+  cx = 2 * lp.c * lp.cx;
+  cy = 2 * lp.c * lp.cy;
+
+  cxx = lp.cx * lp.cx;
+  cxy = 2 * lp.cx * lp.cy;
+  cyy = lp.cy * lp.cy;
+}
+
+void QuadraticPolynomial2V :: 
+Add (double lam, const QuadraticPolynomial2V & qp2)
+{
+  c += lam * qp2.c;
+  cx += lam * qp2.cx;
+  cy += lam * qp2.cy;
+  cxx += lam * qp2.cxx;
+  cxy += lam * qp2.cxy;
+  cyy += lam * qp2.cyy;
+}
+
+double QuadraticPolynomial2V :: 
+Value (double x, double y)
+{
+  return c + cx * x + cy * y + cxx * x * x + cxy * x * y + cyy * y * y;
+}
+
+/*
+double QuadraticPolynomial2V :: 
+MinUnitSquare ()
+{
+  double x, y;
+  double minv = 1e8;
+  double val;
+  for (x = 0; x <= 1; x += 0.1)
+    for (y = 0; y <= 1; y += 0.1)
+      {
+	val = Value (x, y);
+	if (val < minv)
+	  minv = val;
+      }
+  return minv;
+};
+*/
+
+double QuadraticPolynomial2V :: 
+MaxUnitSquare ()
+{
+  // find critical point
+
+  double maxv = c;
+  double hv;
+
+  double det, x0, y0;
+  det = 4 * cxx * cyy - cxy * cxy;
+
+  if (det > 0)
+    {
+      // definite surface
+      
+      x0 = (-2 * cyy * cx + cxy * cy) / det;
+      y0 = (cxy * cx -2 * cxx * cy) / det;
+
+      if (x0 >= 0 && x0 <= 1 && y0 >= 0 && y0 <= 1)
+	{
+	  hv = Value (x0, y0);
+	  if (hv > maxv) maxv = hv;
+	}
+    }
+  
+  QuadraticPolynomial1V e1(c, cx, cxx);
+  QuadraticPolynomial1V e2(c, cy, cyy);
+  QuadraticPolynomial1V e3(c+cy+cyy, cx+cxy, cxx);
+  QuadraticPolynomial1V e4(c+cx+cxx, cy+cxy, cyy);
+  
+  hv = e1.MaxUnitInterval();
+  if (hv > maxv) maxv = hv;
+  hv = e2.MaxUnitInterval();
+  if (hv > maxv) maxv = hv;
+  hv = e3.MaxUnitInterval();
+  if (hv > maxv) maxv = hv;
+  hv = e4.MaxUnitInterval();
+  if (hv > maxv) maxv = hv;
+
+  return maxv;
+
+  //  (*testout) << "maxv = " << maxv << " =~= ";
+
+  /*
+  double x, y;
+  maxv = -1e8;
+  double val;
+  for (x = 0; x <= 1.01; x += 0.1)
+    for (y = 0; y <= 1.01; y += 0.1)
+      {
+	val = Value (x, y);
+	if (val > maxv)
+	  maxv = val;
+      }
+
+  //  (*testout) << maxv << endl;
+  return maxv;
+  */
+};
+
+
+
+
+double QuadraticPolynomial2V :: 
+MaxUnitTriangle ()
+{
+  // find critical point
+  
+  double maxv = c;
+  double hv;
+
+  double det, x0, y0;
+  det = 4 * cxx * cyy - cxy * cxy;
+
+  if (cxx < 0 && det > 0)
+    { 
+      // definite surface
+      
+      x0 = (-2 * cyy * cx + cxy * cy) / det;
+      y0 = (cxy * cx -2 * cxx * cy) / det;
+
+      if (x0 >= 0 && y0 >= 0 && x0+y0 <= 1)
+	{
+	  return Value (x0, y0);
+	}
+    }
+  
+  
+  QuadraticPolynomial1V e1(c, cx, cxx);
+  QuadraticPolynomial1V e2(c, cy, cyy);
+  QuadraticPolynomial1V e3(c+cy+cyy, cx-cy+cxy-2*cyy, cxx-cxy+cyy);
+  
+  hv = e1.MaxUnitInterval();
+  if (hv > maxv) maxv = hv;
+  hv = e2.MaxUnitInterval();
+  if (hv > maxv) maxv = hv;
+  hv = e3.MaxUnitInterval();
+  if (hv > maxv) maxv = hv;
+
+  return maxv;
+}
+}
diff --git a/Netgen/libsrc/linalg/polynomial.hpp b/Netgen/libsrc/linalg/polynomial.hpp
new file mode 100644
index 0000000000..3108d4dd72
--- /dev/null
+++ b/Netgen/libsrc/linalg/polynomial.hpp
@@ -0,0 +1,45 @@
+#ifndef FILE_POLYNOMIAL
+#define FILE_POLYNOMIAL
+
+/* *************************************************************************/
+/* File:   polynomial.hh                                                   */
+/* Author: Joachim Schoeberl                                               */
+/* Date:   25. Nov. 99                                                     */
+/* *************************************************************************/
+
+
+class QuadraticPolynomial1V 
+{
+  double c, cx, cxx;
+public:
+  QuadraticPolynomial1V (double ac, double acx, double acxx);
+  double Value (double x);
+  double MaxUnitInterval ();
+};
+
+class LinearPolynomial2V
+{
+  double c, cx, cy;
+public:
+  LinearPolynomial2V (double ac, double acx, double acy);
+  friend class QuadraticPolynomial2V;
+};
+
+
+class QuadraticPolynomial2V
+{
+  double c, cx, cy, cxx, cxy, cyy;
+public:
+  QuadraticPolynomial2V ();
+  QuadraticPolynomial2V (double ac, double acx, double acy,
+			 double acxx, double acxy, double acyy);
+  void Square (const LinearPolynomial2V & lp);
+  void Add (double lam, const QuadraticPolynomial2V & qp);
+
+  double Value (double x, double y);
+  //  double MinUnitSquare ();
+  double MaxUnitSquare ();
+  double MaxUnitTriangle ();
+};
+
+#endif
diff --git a/Netgen/libsrc/linalg/sparsmat.cpp b/Netgen/libsrc/linalg/sparsmat.cpp
new file mode 100644
index 0000000000..cb2f32a233
--- /dev/null
+++ b/Netgen/libsrc/linalg/sparsmat.cpp
@@ -0,0 +1,1703 @@
+#include <mystdlib.h>
+ 
+#include <linalg.hpp>
+
+
+namespace netgen
+{
+MatrixGraph :: MatrixGraph (int size, int aincrement)
+{
+  int i;
+  increment = aincrement;
+  
+  lines.SetSize (size);
+  for (i = 1;i <= size; i++)
+    {
+      lines.Elem(i).allocsize = increment;
+      lines.Elem(i).size = 1;
+      lines.Elem(i).diag = 1;
+      lines.Elem(i).col = new INDEX[increment];
+      lines.Elem(i).col[0] = i;
+    }
+}
+
+MatrixGraph :: MatrixGraph (const ARRAY<int> & linesize)
+{
+  INDEX i;
+  INDEX n = linesize.Size();
+  INDEX sum = 0;
+  INDEX * cola;
+
+  lines.SetSize (n);
+  increment = 0;
+
+  for (i = 1; i <= n; i++)
+    sum += linesize.Get(i);
+  
+  cola = new INDEX[sum];
+
+  sum = 0;
+  for (i = 1; i <= n; i++)
+    {
+      lines.Elem(i).allocsize=linesize.Get(i);
+      lines.Elem(i).size = 1;
+      lines.Elem(i).diag = 1;
+      lines.Elem(i).col = &cola[sum];
+      cola[sum] = i;
+      sum += linesize.Get(i);
+    }
+}
+
+int MatrixGraph :: GetPosition (INDEX i, INDEX j) const
+{
+  int k;
+  
+  INDEX * ip = lines.Get(i).col;
+  INDEX n = lines.Get(i).size;
+  for (k = 1; k <= n; k++, ip++)
+    {
+      if (j == *ip) return k;
+    }
+
+  return 0;
+  
+  /*  
+  //  quick search:
+
+  const INDEX * ip = lines.Get(i).col;
+  int max = lines.Get(i).size;
+
+  int l = 0, k = 1, newind;
+  
+  while (k < max)
+    k <<= 1;
+
+  while (k > 0)
+    {
+      k >>= 1;
+      newind = k+l;
+      if (newind >= max) continue;
+      if (ip[newind] <= j)
+	l += k;
+    }
+
+  if (l < max && ip[l] == j) 
+    return l+1;
+
+  return 0;
+  */
+}
+
+
+
+int MatrixGraph :: CreatePosition (INDEX i, INDEX j)    
+  {
+  int k;
+  MatrixGraph::linestruct * lin = &lines.Elem(i);
+
+ 
+
+  for (k = 1; k <= lin->size; k++)
+    {
+      if (lin->col[k-1] == j) 
+	return 0;
+      if (lin->col[k-1] > j) 
+	break;
+    }
+
+  // k ... position to enter new element
+
+  if (lin->size == lin->allocsize)
+    {
+      INDEX * tmpcol = new INDEX[lin->size + increment];
+      memcpy (tmpcol, lin->col, sizeof(INDEX) * lin->size);
+      delete lin->col;
+      lin->col = tmpcol;
+      lin->allocsize+=increment;
+    }
+
+  if (k <= lin->size)
+    memmove (&lin->col[k], &lin->col[k-1], 
+	     sizeof(INDEX) * (lin->size + 1 - k));
+  
+  lin->col[k-1] = j;
+  lin->size++;
+  if (j < i) lin->diag++;
+
+  return 1;
+  }
+
+
+
+double & SparseMatrix :: operator() (INDEX i, INDEX j)
+{
+  if (i >= 1 && i <= height && j >= 1 && j <= width)
+    return Elem(i, j);
+  else
+    {
+    (*myerr) << "SparseMatirx::operator(): out of range" << endl;
+    return shit;
+    }
+}
+ 
+double SparseMatrix :: operator() (INDEX i, INDEX j) const
+{
+  if (i >= 1 && i <= height && j >= 1 && j <= width)
+    return Get(i, j);
+  else
+    {
+    (*myerr) << "SparseMatirx::operator(): out of range" << endl;
+    return shit;
+    }
+}
+   
+
+
+
+
+
+SparseMatrix :: SparseMatrix (INDEX h, INDEX w)
+  : BaseMatrix (h, w)
+{
+  ;
+}
+
+
+
+
+void SparseMatrix :: Mult (const BaseVector & bv, BaseVector & bprod) const
+  {
+  double sum, vi;
+  INDEX i, j, n;
+
+  const INDEX * col;
+  const double * valp;
+
+  const Vector & v = bv.CastToVector();
+  Vector & prod = bprod.CastToVector();
+
+  prod.SetLength (Height());
+
+  /*
+  if (prod.Length() != Height() || v.Length() != Width())
+    {
+    (*myerr) << "SparseMatrix::Mult: Dimensions don't fit" << endl;
+    return;
+    }
+    */
+
+  if (!Symmetric())
+    {
+      n = Height();
+      INDEX w = Width();
+
+      /*
+      const MatrixGraph::linestruct * linep = &graph->lines.Get(1);   
+
+      for (i = 1; i <= n; i++) 
+	{
+	  sum = 0; 
+	  col = linep->col;
+	  valp = data.Get(i);
+	  
+	  for (j = 0; j < linep->size; j++, valp++, col++)
+	    sum += *valp * v.Get(*col); 
+
+	  linep++;
+	  prod.Set (i, sum);
+	}
+	*/
+
+      const MatrixGraph::linestruct * linep = &graph->lines.Get(1);   
+      const double * vp = &v.Get(1);
+      vp--;
+
+      for (i = 1; i <= n; i++) 
+	{
+	  sum = 0; 
+	  col = linep->col;
+	  valp = data.Get(i);
+	  const int ls = linep->size;
+	  
+	  if (i <= w)
+	    for (j = 0; j < ls; j++)
+	      sum += valp[j] * vp[col[j]];
+	  else
+	    // decrement one, because of diagonal element outside
+	    for (j = 0; j < ls-1; j++)
+	      sum += valp[j] * vp[col[j]];
+
+	  
+	  linep++;
+	  prod.Set (i, sum);
+	}
+
+    }
+  else
+    {
+      prod = 0;
+      n = Height();
+      
+      const MatrixGraph::linestruct * linep = &graph->lines.Get(1);   
+
+      for (i = 1; i <= n; i++)
+	{
+	  sum = 0; 
+	  //	  col = graph->lines.Get(i).col;
+	  col = linep->col;
+	  valp = data.Get(i);
+	  vi = v.Get(i);
+	  
+	  for (j = linep->diag-1; j > 0; j--, col++, valp++)
+	    {
+	      sum += (*valp) * v.Get(*col);
+	      prod.Elem(*col) += (*valp) * vi;
+	    }
+	  
+	  linep++;
+	  sum += (*valp) * v.Get(*col);
+	  prod.Elem(i) += sum;
+	}
+    }
+  }
+
+void SparseMatrix :: MultTrans (const BaseVector & bv, BaseVector & bprod) const
+  {
+  INDEX i, j, n, coln;
+  const Vector & v = bv.CastToVector();
+  Vector & prod = bprod.CastToVector();
+  const INDEX * col;
+  const double * valp;
+  double val;
+
+  prod.SetLength (Width());
+
+  if (prod.Length() != Width() || v.Length() != Height())
+    {
+    (*myerr) << "SparseMatrix::Mult: Dimensions don't fit" << endl;
+    return;
+    }
+
+  if (!Symmetric())
+    {
+    n = Height();
+    prod = 0;
+
+    for (i = 1; i <= n; i++)
+      {
+	col = graph->lines.Get(i).col;
+	valp = data.Get(i);
+	coln = graph->lines.Get(i).size;
+	val = v.Get(i);
+
+	//      lin = &lins.Get(i);
+	//      col = lin->col;
+	//      val = v.Get(i);
+      
+      for (j = 1; j <= coln; j++, col++, valp++)
+        prod.Elem(*col) += (*valp) * val;
+      }
+    }
+  else
+    {
+    Mult (v, prod);
+    }
+  }
+
+
+
+
+void SparseMatrix :: Residuum (const BaseVector & bx, const BaseVector & bb,
+      BaseVector & bres) const
+  {
+    BaseMatrix :: Residuum (bx, bb, bres);
+    /*
+  double sum, xi;
+  INDEX i, j, n;
+  colstruct * col;
+  const linestruct * lin;
+  const Vector & x = bx.CastToVector();
+  const Vector & b = bb.CastToVector();
+  Vector & res = bres.CastToVector();
+
+  res.SetLength (b.Length());
+
+  if (res.Length() != b.Length() || b.Length() != Height() ||
+      x.Length() != Width())
+    {
+    (*myerr) << "SparseMatrix::Residuum: Dimensions don't fit" << endl;
+    return;
+    }
+
+  n = Height();
+  if (!Symmetric())
+    {
+    for (i = 1; i <= Height(); i++)
+      {
+      lin = &lins.Get(i);
+      sum = b.Get(i);
+      col = lin->col;
+
+      for (j = lin->size; j > 0; j--, col++)
+        sum -= col->data * x.Get(col->colnr);
+
+      res.Set (i, sum);
+      }
+    }
+  else
+    {
+    res = b;
+    for (i = 1; i <= n; i++)
+      {
+      lin = &lins.Get(i);
+      sum = 0;
+      col = lin->col;
+      xi = x.Get(i);
+
+      for (j = lin->size; j > 0; j--, col++)
+        {
+        sum -= col->data * x.Get(col->colnr);
+        if (col->colnr != i)
+          res.Elem(col->colnr) -= col->data * xi;
+        }
+
+      res.Elem(i) += sum;
+      }
+    }
+    */
+  }
+
+
+void SparseMatrix :: ResiduumTrans (const BaseVector & /* bx */, 
+				    const BaseVector & /* bb */,
+				    BaseVector & /* bres */) const
+  {
+    cerr << "SparseMastrix :: Residuumtrans called, but not implemented" << endl;
+
+    /*
+  INDEX i, j, n;
+  colstruct * col;
+  const linestruct * lin;
+  const Vector & x = bx.CastToVector();
+  const Vector & b = bb.CastToVector();
+  Vector & res = bres.CastToVector();
+
+
+  res.SetLength (Width());
+
+  if (res.Length() != b.Length() || b.Length() != Width() ||
+      x.Length() != Height())
+    {
+    (*myerr) << "SparseMatrix::ResiduumTrans: Dimensions don't fit" << endl;
+    return;
+    }
+  
+  if (!Symmetric())
+    {
+    n = Height();
+
+    res = b;
+
+    for (i = 1; i <= n; i++)
+      {
+      lin = &lins.Get(i);
+      col = lin->col;
+
+      for (j = lin->size; j > 0; j--, col++)
+        res.Elem(col->colnr) -= col->data * x.Get(i);
+      }
+    }
+  else
+    {
+    Residuum (bx, bb, bres);
+    }
+    */
+  }
+
+
+
+ostream & SparseMatrix :: Print (ostream & s) const
+  {
+  INDEX i, j;
+
+  if (Symmetric()) s << "Lower half of matrix:" << endl;
+
+  for (i = 1; i <= Height(); i++)
+    {
+    s << "Line " << i << " ";
+
+    if (Symmetric())
+      {
+	for (j = 1 ; j <= GetDiagPos (i); j++)
+	  s << "(" << GetColIndex (i, j) << ": " << GetData (i, j) << ") ";
+      }
+    else
+      {
+	for (j = 1 ; j <= ElementsInLine (i); j++)
+	  s << "(" << GetColIndex (i, j) << ": " << GetData (i, j) << ") ";
+      }
+
+    s << endl;
+    }
+  return s;
+  }
+
+
+
+
+
+
+void SparseMatrix :: AddElementMatrix (const ARRAY<INDEX> & pnum,
+      const BaseMatrix & elemmat)
+{
+  int i, j, i1, i2, n;
+
+  n = pnum.Size();
+  static ARRAY<int> spnum, map;
+  spnum.SetSize (n);
+  map.SetSize (n);
+
+  for (i = 1; i <= n; i++)
+    spnum.Elem(i) = pnum.Get(i);
+
+  for (i = 1; i <= n; i++)
+    for (j = 1; j <= n-1; j++)
+      if (spnum.Elem(j) > spnum.Elem(j+1))
+	swap (spnum.Elem(j), spnum.Elem(j+1));
+
+  for (i = 1; i <= n; i++)
+    for (j = 1; j <= n; j++)
+      if (pnum.Get(i) == spnum.Get(j))
+	map.Elem(j) = i;
+
+
+  const DenseMatrix & delemmat = (const DenseMatrix&)elemmat;
+  if (Symmetric())
+    {
+      for (i1 = 1; i1 <= n; i1++)
+	{
+	  INDEX ii1 = spnum.Get(i1);
+	  const INDEX * coli = graph->lines.Get(ii1).col;
+	  double * val = data.Get(ii1);
+	  int ncol = graph->lines.Get(ii1).size;
+
+	  int hi = 0;
+	  for (i2 = 1; i2 <= i1; i2++)
+	    {
+	      while (coli[hi] < spnum.Get(i2))
+		hi++;
+	      val[hi] += delemmat.Get(map.Get(i1), map.Get(i2));
+	    }
+	}
+
+      /*
+      for (i1 = 1; i1 <= pnum.Size(); i1++)
+	for (i2 = 1; i2 <= i1; i2++)
+	  Elem(pnum.Get(i1), pnum.Get(i2)) += delemmat.Get(i1, i2);
+	  */
+    }
+  else
+    {
+      for (i1 = 1; i1 <= n; i1++)
+	{
+	  INDEX ii1 = spnum.Get(i1);
+	  const INDEX * coli = graph->lines.Get(ii1).col;
+	  double * val = data.Get(ii1);
+	  int ncol = graph->lines.Get(ii1).size;
+
+	  int hi = 0;
+	  for (i2 = 1; i2 <= n; i2++)
+	    {
+	      while (coli[hi] < spnum.Get(i2))
+		hi++;
+	      val[hi] += delemmat.Get(map.Get(i1), map.Get(i2));
+	    }
+	}
+
+      /*
+      for (i1 = 1; i1 <= pnum.Size(); i1++)
+	for (i2 = 1; i2 <= pnum.Size(); i2++)
+	  Elem(pnum.Get(i1), pnum.Get(i2)) += delemmat.Get(i1, i2);
+	  */
+    }
+}
+
+
+
+
+double SparseMatrix :: RowTimesVector (INDEX i, const Vector & v) const
+  {
+  const double * valp;
+  const INDEX * col;
+  int coln;
+  double sum;
+  int j;
+
+  /*
+  if (Width() > v.Length())
+    {
+    cerr << "SparseMatrix::RowTimesVector: Size doesn't fit" << endl;
+    return 0;
+    }
+    */
+
+  col = graph->lines.Get(i).col;
+  valp = data.Get(i);
+  sum = 0;
+  coln = Symmetric() ? graph->lines.Get(i).diag : graph->lines.Get(i).size;
+
+  for (j = 1; j <= coln; ++j, ++col, ++valp)
+    sum += (*valp) * v.Get(*col);
+
+  return sum;
+
+  /*
+	col = graph->lines.Get(i).col;
+	valp = data.Get(i);
+	coln = graph->lines.Get(i).size;
+	val = v.Get(i);
+
+	//      lin = &lins.Get(i);
+	//      col = lin->col;
+	//      val = v.Get(i);
+      
+      for (j = 1; j <= coln; j++, col++, valp++)
+        prod.Elem(*col) += (*valp) * val;
+	*/
+
+
+  }
+  
+
+
+void SparseMatrix :: AddRowToVector (INDEX i, double s, Vector & v) const
+{
+  const double * valp;
+  const INDEX * col;
+  double * vp;
+  int coln, j;
+  
+#ifdef debug  
+  if (Width() > v.Length())
+    {
+      cerr << "SparseMatrix::AddRowToVector: Size doesn't fit" 
+	   << "w = " << Width() << " len = " << v.Length() << endl;
+      return;
+    }
+#endif    
+
+  vp = &v.Elem(1) - 1;
+  valp = data.Get(i);
+  col = graph->lines.Get(i).col;
+  coln =  Symmetric() ? graph->lines.Get(i).diag : graph->lines.Get(i).size;
+
+  //  for (j = 0; j < coln; j++)
+  //    vp[col[j]] += s * valp[j];
+
+  for (j = coln-1; j >= 0; --j, ++valp, ++col)
+    vp[*col] += s * (*valp);
+}
+
+
+
+
+
+
+char SparseMatrix :: Used (INDEX i, INDEX j) const
+  {
+  return (graph->GetPosition(i, j) != 0);
+  }
+
+
+
+double SparseMatrix :: Get(INDEX i, INDEX j) const
+  {
+  if (Symmetric() && (j > i)) swap (i, j);
+    
+  int pos = graph->GetPosition(i, j);
+  if (pos)
+    return data.Get(i)[pos-1];
+  else 
+    return 0;
+  }
+  
+
+/*
+  quick search:
+
+  const colstruct * col = lins.Get(i).col;
+  INDEX max = lins.Get(i).size;
+
+  int l = 0, k = 1, newind;
+
+  while (k < max)
+    k <<= 1;
+
+
+  while (k > 0)
+    {
+    k >>= 1;
+    newind = k+l;
+    if (newind >= max) continue;
+    if (col[newind].colnr <= j)
+      l += k;
+    }
+
+  if (l < max && col[l].colnr == j) return col[l].data;
+
+  return 0;
+  */
+  
+
+
+void SparseMatrix :: Set(INDEX i, INDEX j, double v)
+  {
+  Elem (i, j) = v;
+  }
+
+
+
+double & SparseMatrix :: Elem(INDEX i, INDEX j)
+  {
+  if (Symmetric() && j > i) swap (i, j);
+  
+  int pos = graph->GetPosition (i, j);
+  if (!pos)
+    {
+      CreatePosition (i, j);
+      pos = graph->GetPosition (i, j);
+    }
+
+  return data.Elem(i)[pos-1];
+  }
+
+
+
+
+
+
+
+
+SparseMatrixFlex :: SparseMatrixFlex (INDEX h, INDEX w)
+  : SparseMatrix (h, w)
+{
+  INDEX i;
+  graph = 
+    mygraph = new MatrixGraph (h);
+
+  data.SetSize (h);
+  for (i = 1; i <= graph->Size(); i++)
+    {
+      data.Elem(i) = new double[graph->lines.Get(i).allocsize];
+      data.Elem(i)[0] = 0;
+    }
+}
+
+SparseMatrixFlex :: ~SparseMatrixFlex ()
+{
+  ;
+}
+
+
+void SparseMatrixFlex :: SetSize (INDEX /* h */, INDEX /* w */)
+{
+  cerr << "SparseMatrixFlex :: SetSize() not implemented" << endl;
+}
+
+void SparseMatrixFlex :: SetSymmetric (int sym)
+{
+  BaseMatrix::SetSymmetric (sym);
+}
+
+void SparseMatrixFlex :: ChangeSize (INDEX /* h */, INDEX /* w */)
+{
+  cerr << "SparseMatrixFlex :: ChangeSize() not implemented" << endl;
+}
+
+
+void SparseMatrixFlex :: DeleteElements ()
+{
+  ;
+} 
+
+BaseMatrix * SparseMatrixFlex :: Copy () const
+{
+  return (SparseMatrixFlex*)this;
+}
+
+
+int SparseMatrixFlex :: CreatePosition (INDEX i, INDEX j)
+{
+  int oldlinesize = graph->lines.Get(i).allocsize;
+  if (mygraph->CreatePosition(i, j))
+    {
+      int newlinesize = graph->lines.Get(i).allocsize;
+      if (oldlinesize != newlinesize)
+	{
+	  double * hdp = new double[newlinesize];
+	  memcpy (hdp, data.Elem(i), sizeof(double) * oldlinesize);
+	  delete data.Elem(i);
+	  data.Elem(i) = hdp;
+	}
+
+      int pos = graph->GetPosition (i, j);
+      int size = graph->lines.Get(i).size;
+
+      memmove (&data.Elem(i)[pos], &data.Elem(i)[pos-1], 
+	       sizeof(double) * (size-pos));
+      data.Elem(i)[pos-1] = 0;
+    }
+
+  return 0;
+}
+
+
+
+
+SparseMatrixFix :: SparseMatrixFix (const MatrixGraph & agraph,
+				     int asymmetric)
+  : SparseMatrix (agraph.Size())
+{
+  graph = &agraph;
+  SetSymmetric (asymmetric);
+
+  data.SetSize (graph->Size());
+
+  int i, nne;
+  double * block;
+  
+  nne = 0;
+  for (i = 1; i <= graph->Size(); i++)
+    {
+    if (Symmetric())
+      nne += graph->lines.Get(i).diag;
+    else
+      nne += graph->lines.Get(i).size;
+    }
+    
+  block = new double[nne];
+  
+  for (i = 0; i < nne; i++)
+    block[i] = 0;
+
+  nne = 0;
+  for (i = 1; i <= graph->Size(); i++)
+    {
+    data.Elem(i) = &block[nne];
+    if (Symmetric())
+      nne += graph->lines.Get(i).diag;
+    else
+      nne += graph->lines.Get(i).size;
+    }
+
+}
+
+
+SparseMatrixFix :: ~SparseMatrixFix ()
+{
+  ;
+}
+
+int SparseMatrixFix :: CreatePosition (INDEX i, INDEX j)
+{
+  (*myerr) << "SparseMatrixFix cannot change graph, requested: " 
+       << i << "-" << j << endl;
+  return 0;
+}
+
+#ifdef nothing
+
+
+SparseMatrix :: SparseMatrix () : BaseMatrix (), lins()
+  {
+  };
+
+SparseMatrix :: SparseMatrix (INDEX h, INDEX w) : BaseMatrix (h, w), lins (h)
+  {
+  if (!w) w = h;
+
+  for (INDEX i = 1; i <= h; i++)
+    {
+    lins[i].size = 0;
+    lins[i].maxsize = 0;
+    lins[i].col = NULL;
+    }
+  }
+
+SparseMatrix :: SparseMatrix (const SparseMatrix & m2) : BaseMatrix(), lins()
+  {
+  (*this) = m2;
+  }
+
+
+SparseMatrix :: ~SparseMatrix ()
+  {
+  DeleteElements ();
+  }
+
+
+
+void SparseMatrix :: SetSize (INDEX h, INDEX w)
+  {
+  if (!w) w = h;
+  DeleteElements ();
+
+  if (height == h && width == w) return;
+
+  height = h;
+  width = w;
+  lins.SetSize (height);
+
+  if (lins.Size () == height)
+    {
+    for (INDEX i = 1; i <= h; i++)
+      {
+      lins[i].size = 0;
+      lins[i].maxsize = 0;
+      lins[i].col = NULL;
+      }
+    }
+  else
+    {
+    height = width = 0;
+    (*myerr) << "SparseMatrix::SetSize: Out of memory" << endl;
+    }
+  }
+
+
+void SparseMatrix :: ChangeSize (INDEX h, INDEX w)
+  {
+  INDEX i;
+
+  if (!w) w = h;
+  if (height == h && width == w) return;
+
+  lins.SetSize (h);
+
+  if (lins.Size () == h)
+    {
+    for (i = height+1; i <= h; i++)
+      {
+      lins[i].size = 0;
+      lins[i].maxsize = 0;
+      lins[i].col = NULL;
+      }
+    for (i = h+1; i <= height; i++)
+      {
+      if (lins[i].col)
+        {
+        DeleteColStruct (lins[i].col, lins[i].maxsize);
+
+        lins[i].col = NULL;
+        lins[i].size = 0;
+        lins[i].maxsize = 0;
+        }
+      }
+
+    height = h;
+    width = w;
+    }
+  else
+    {
+    height = width = 0;
+    (*myerr) << "SparseMatrix::SetSize: Out of memory" << endl;
+    }
+  }
+
+
+void SparseMatrix :: SetSymmetric (int sym)
+  {
+  INDEX i, j;
+  int nr;
+
+  if (sym != Symmetric())
+    {
+    BaseMatrix :: SetSymmetric (sym);
+
+    if (!sym)
+      {
+      for (i = 1; i <= Height(); i++)
+        for (nr = 1; nr <= ElementsInLine (i); nr++)
+          {
+          j = GetIndex (i, nr);
+          if (j < i)
+            Elem (j, i) = GetData (i, nr);
+          }
+      }
+    else
+      {
+      DeleteElements();
+      }
+    }
+  }
+
+
+void SparseMatrix :: DeleteElements ()
+  {
+  for (INDEX i = 1; i <= lins.Size(); i++)
+    {
+    if (lins[i].col)
+      {
+      DeleteColStruct (lins[i].col, lins[i].maxsize);
+
+      lins[i].col = NULL;
+      lins[i].size = 0;
+      lins[i].maxsize = 0;
+      }
+    }
+  }
+
+
+
+double & SparseMatrix::operator() (INDEX i, INDEX j)
+{
+  if (i >= 1 && j >= 1 && i <= height && j <= width)
+    {
+      return Elem(i, j);
+    }
+  else (*myerr) << "\nindex (" << i << "," << j << ") out of range (1.."
+	     << height << ",1.." << width << ")\n";
+  return shit;
+}
+
+double SparseMatrix::operator() (INDEX i, INDEX j) const
+{
+  if (i >= 1 && j >= 1 && i <= height && j <= width)
+    {
+    return Get(i, j);
+    }
+  else (*myerr) << "\nindex (" << i << "," << j << ") out of range (1.."
+	     << height << ",1.." << width << ")\n";
+  return 0;
+}
+
+SparseMatrix & SparseMatrix :: operator= (const SparseMatrix & m2)
+  {
+  INDEX i, j;
+
+  SetSize (m2.Height(), m2.Width());
+  SetSymmetric (m2.Symmetric());
+
+  for (i = 1; i <= m2.Height(); i++)
+    for (j = 1; j <= m2.ElementsInLine(i); j++)
+      (*this).Elem(i, m2.GetIndex(i, j)) = m2.GetData(i, j);
+  return *this;
+  }
+
+
+SparseMatrix & SparseMatrix :: operator*= (double v)
+  {
+  INDEX i, j;
+
+  for (i = 1; i <= Height(); i++)
+    for (j = 1; j <= ElementsInLine(i); j++)
+      GetDataRef(i, j) *= v;
+  return *this;
+  }
+
+
+
+char SparseMatrix :: Used (INDEX i, INDEX j) const
+  {
+  if (Symmetric() && j > i) swap (i, j);
+
+  if (i < 1 || i > height) return 0;
+
+  const colstruct * col = lins.Get(i).col;
+  INDEX max = lins.Get(i).size;
+
+  for (int k = 0; k < max; k++, col++)
+    if (col->colnr == j) return 1;
+
+  return 0;
+  }
+
+
+
+double SparseMatrix :: Get(INDEX i, INDEX j) const
+  {
+  if (Symmetric() && j > i) swap (i, j);
+
+  const colstruct * col = lins.Get(i).col;
+  INDEX max = lins.Get(i).size;
+
+  int l = 0, k = 1, newind;
+
+  while (k < max)
+    k <<= 1;
+
+
+  while (k > 0)
+    {
+    k >>= 1;
+    newind = k+l;
+    if (newind >= max) continue;
+    if (col[newind].colnr <= j)
+      l += k;
+    }
+
+  if (l < max && col[l].colnr == j) return col[l].data;
+
+  return 0;
+
+  /*
+  for (INDEX k = 0; k < max; k++, col++)
+    if (col->colnr == j) 
+      {
+	if (l != k) cerr << "Set: ind not ok" << endl;
+        else cerr << "is ok" << endl;
+      return col->data;
+      }
+
+  return 0;
+  */
+  }
+
+
+void SparseMatrix :: Set(INDEX i, INDEX j, double v)
+  {
+  Elem (i, j) = v;
+  }
+
+
+
+double & SparseMatrix :: Elem(INDEX i, INDEX j)
+  {
+  if (Symmetric() && j > i) swap (i, j);
+
+  linestruct * lin = &lins.Elem(i);
+  colstruct * col, *ncol;
+
+  int size = lin->size;
+  int pos;
+
+  if (size)
+    {
+
+    // bereits Elemente in der Liste
+
+    if (j > lin->col[size-1].colnr)
+      {
+
+      // neues Element an letzter Position einfuegen
+
+      if (lin->maxsize > size)
+        {
+        lin->size++;
+        lin->col[size].colnr = j;
+        return lin->col[size].data = 0;
+        }
+
+      if ( (ncol = NewColStruct(lin->maxsize+4)/* new colstruct[lin->maxsize+4] */) != NULL)
+        {
+        memcpy (ncol, lin->col, sizeof(colstruct) * size);
+
+        DeleteColStruct (lin->col, lin->maxsize);
+
+        lin->maxsize += 4;
+        lin->col = ncol;
+        lin->size++;
+        ncol[size].colnr = j;
+        return ncol[size].data = 0;
+        }
+      else
+        {
+        (*myerr) << "SparseMatrix::Elem: Out of memory 1" << endl;
+        return shit;
+        }
+
+      }
+    else
+      {
+
+      for (col = lin->col; col->colnr < j; col++);
+                                        // Zeilenliste durchsuchen
+
+      if (col->colnr == j) return col->data;
+                                        // Element exisitiert bereits
+
+      if (lin->maxsize > size)
+        {
+        memmove (col+1, col, size_t((char*)&lin->col[size] - (char*)col));
+
+        lin->size++;
+        col->colnr = j;
+        return col->data = 0;
+        }
+
+      pos = size_t (col - lin->col);
+
+      if ( (ncol = NewColStruct(lin->maxsize+4) ) != NULL)
+        {
+
+        if (pos) memcpy (ncol, lin->col, sizeof(colstruct) * pos);
+        memcpy (ncol+(pos+1), col, sizeof(colstruct) * (size-pos));
+
+        DeleteColStruct (lin->col, lin->maxsize);
+//        delete lin->col;
+
+        lin->maxsize += 4;
+        lin->col = ncol;
+        lin->size++;
+        ncol[pos].colnr = j;
+        return ncol[pos].data = 0;
+        }
+      else
+        {
+        (*myerr) << "SparseMatrix::Elem: Out of memory 2" << endl;
+        return shit;
+        }
+      }
+    }
+  else
+    {
+    // kein Element in der Liste
+
+    if (lin->maxsize)
+      {
+      // Liste bereits angelegt
+
+      lin->size = 1;
+      lin->col->colnr = j;
+      return lin->col->data = 0;
+      }
+    else
+      {
+      if ( (lin->col = NewColStruct(6) ) != NULL )
+        {
+        lin->maxsize = 6;
+        lin->size = 1;
+        lin->col->colnr = j;
+        return lin->col->data = 0;
+        }
+      else
+        {
+        (*myerr) << "SparseMatrix::Elem: Out of memory 3" << endl;
+        return shit;
+        }
+      }
+    }
+  }
+
+
+
+void SparseMatrix :: Delete (INDEX i, int nr)
+  {
+  colstruct * col = lins[i].col;
+
+  nr--;
+  while (nr < lins[i].size-1)
+    {
+    col[nr].data = col[nr+1].data;
+    col[nr].colnr = col[nr+1].colnr;
+    nr++;
+    }
+  lins[i].size--;
+  }
+
+void SparseMatrix :: DeleteElem (INDEX i, INDEX j)
+  {
+  int nr;
+  int dec = 0;
+
+  if (Symmetric() && j > i) swap (i, j);
+
+  colstruct * col = lins[i].col;
+
+  for (nr = 0; nr < lins[i].size; nr++)
+    {
+    if (dec)
+      {
+      col[nr-1].data = col[nr].data;
+      col[nr-1].colnr = col[nr].colnr;
+      }
+    if (col[nr].colnr == j) dec = 1;
+    }
+  if (dec)
+    lins[i].size--;
+  }
+
+
+void SparseMatrix :: SetLineAllocSize (INDEX i, int j)
+  {
+  colstruct * ncol;
+
+
+  if (lins[i].maxsize < j)
+    {
+    if ( (ncol = NewColStruct(j)) != NULL)
+      {
+      memcpy (ncol, lins[i].col, sizeof(colstruct) * lins[i].size);
+
+      if (lins[i].maxsize)
+        DeleteColStruct (lins[i].col, lins[i].maxsize);
+
+      lins[i].maxsize = j;
+      lins[i].col = ncol;
+      }
+    else
+      (*myerr) << "SPARSE_MATIRX :: SetLineAllocSize: Out of Memory" << endl;
+    }
+  }
+
+
+
+
+
+
+
+
+
+  
+  
+
+
+
+SparseMatrix operator* (const SparseMatrix & m1,
+                         const SparseMatrix & m2)
+  {
+  SparseMatrix m(m1.Height(), m2.Width());
+  INDEX i, j, k, nr;
+
+  if (!m1.Symmetric() && !m2.Symmetric())
+    {
+    for (i = 1; i <= m1.Height(); i++)
+      {
+      for (j = 1; j <= m1.ElementsInLine(i); j++)
+        {
+        nr = m1.GetIndex (i, j);
+        for (k = 1; k <= m2.ElementsInLine(nr); k++)
+          {
+          m(i, m2.GetIndex(nr, k)) += m1.GetData(i, j) * m2.GetData(nr, k);
+          }
+        }
+      }
+    }
+  else
+    {
+    (*myerr) << "SparseMatrix :: operator* not implemented for symmetric case" << endl;
+    }
+  return m;
+  }
+
+
+SparseMatrix & SparseMatrix :: operator+= (const SparseMatrix & m2)
+  {
+  INDEX i, k;
+  int j;
+
+  if (Symmetric() == m2.Symmetric())
+    {
+    for (i = 1; i <= Height(); i++)
+      for (j = 1; j <= m2.ElementsInLine (i); j++)
+        {
+        k = m2.GetIndex (i, j);
+        Elem(i, k) += m2.GetData (i, j);
+        }
+    }
+  else
+    {
+    (*myerr) << "SparseMatrix :: operator+= not implemented for different cases" << endl;
+    }
+  return *this;
+  }
+
+
+
+SparseMatrix & SparseMatrix :: operator*= (const SparseMatrix & m2)
+  {
+  INDEX i, k;
+  int j, l;
+  colstruct * cs;
+  int ms, s;
+
+  if (!Symmetric() && !m2.Symmetric())
+    {
+    for (i = 1; i <= Height(); i++)
+      {
+      cs = lins[i].col;
+      s = lins[i].size;
+      ms = lins[i].maxsize;
+
+      lins[i].col = NULL;
+      lins[i].size = 0;
+      lins[i].maxsize = 0;
+
+
+      for (j = 0; j < s; j++)
+        {
+        k = cs[j].colnr;
+
+        for (l = 1; l <= m2.ElementsInLine (k); l++)
+          Elem(i, m2.GetIndex(k, l)) += cs[j].data * m2.GetData(k, l);
+        }
+
+      DeleteColStruct (cs, ms);
+      }
+    }
+  else
+    {
+    (*myerr) << "SparseMatrix :: operator*= not implemented for Symmetric matrices" << endl;
+    }
+
+  return *this;
+  }
+
+
+void SparseMatrix :: Solve (const Vector & v, Vector & sol) const
+  {
+  SparseMatrix temp = *this;
+  INDEX i, j, nr, k;
+  double q;
+
+  sol = v;
+
+
+  if (!Symmetric())
+    {
+    for (i = 1; i <= Height(); i++)
+      {
+      if (temp.ElementsInLine(i) < 1 || temp.GetIndex(i, 1) != i)
+        {
+        (*myerr) << "i = " << i << endl;
+        (*myerr) << "Solve: Matrix singular" << endl;
+        char ch;
+        cin >> ch;
+        }
+      for (j = 2; j <= temp.ElementsInLine(i); j++)
+        {
+        nr = temp.GetIndex(i, j);
+        if (temp.GetIndex(nr, 1) != i)
+          {
+          (*myerr) << temp << endl;
+          (*myerr) << "i = " << i << "j = " << j << "nr = " << nr << endl;
+          (*myerr) << "Solve: Graph not symmetrix" << endl;
+          char ch;
+          cin >> ch;
+          }
+
+        q = temp.GetData (nr, 1) / temp.GetData(i, 1);
+        temp.Delete (nr, 1);
+
+        for (k = 2; k <= temp.ElementsInLine (i); k++)
+          temp.Elem(nr, temp.GetIndex(i, k)) -= q * temp.GetData(i, k);
+
+        sol(nr) -= q * sol(i);
+        }
+      }
+
+    for (i = temp.Height(); i >= 1; i--)
+      {
+      for (j = 2; j <= temp.ElementsInLine(i); j++)
+        {
+        sol(i) -= temp.GetData(i, j) * sol(temp.GetIndex(i, j));
+        }
+      sol(i) /= temp.GetData(i, 1);
+      }
+    }
+  else
+    (*myerr) << "SparseMatrix :: Solve not implemented for symmetic case" << endl;
+  }
+
+
+
+
+
+void Transpose (const SparseMatrix & m1, SparseMatrix & m2)
+  {
+  INDEX i, j;
+
+  m2.SetSize(m1.Width(), m1.Height());
+  m2.SetSymmetric(m1.Symmetric());
+
+  if (!m1.Symmetric())
+    {
+    for (i = 1; i <= m1.Height(); i++)
+      for (j = 1; j <= m1.ElementsInLine(i); j++)
+        m2(m1.GetIndex(i, j), i) = m1.GetData(i, j);
+    }
+  else
+    m2 = m1;
+  }
+
+
+
+BaseMatrix * SparseMatrix :: Copy () const
+  {
+  return new SparseMatrix (*this);
+  }
+
+
+
+
+
+
+
+void SparseMatrix :: AddRowMatrix (INDEX row, const SparseMatrix & m2)
+  {
+  int i1, i2, i;
+  colstruct * cs1, * cs2, * ncs;
+  int s1, s2, s;
+
+  s1 = lins[row].size;
+  s2 = m2.lins[1].size;
+  cs1 = lins[row].col;
+  cs2 = m2.lins[1].col;
+
+  i1 = 0;
+  i2 = 0;
+  i = 0;
+
+
+  if (Symmetric())
+    {
+    while (s2 && cs2[s2-1].colnr > row) s2--;
+    }
+
+
+  while (i1 < s1 && i2 < s2)
+    {
+    if (cs1[i1].colnr < cs2[i2].colnr) i1++;
+    else if (cs1[i1].colnr > cs2[i2].colnr) i2++;
+    else { i1++; i2++; }
+    i++;
+    }
+
+  i += (s1 - i1);
+  i += (s2 - i2);
+
+  s = i;
+
+  if (s > s1)
+    {
+    ncs = NewColStruct (s);
+
+    i1 = 0;
+    i2 = 0;
+    i = 0;
+
+    while (i1 < s1 && i2 < s2)
+      {
+      if (cs1[i1].colnr < cs2[i2].colnr)
+        {
+        ncs[i].colnr = cs1[i1].colnr;
+        ncs[i].data = cs1[i1].data;
+        i1++;
+        }
+      else if (cs1[i1].colnr > cs2[i2].colnr)
+        {
+        ncs[i].colnr = cs2[i2].colnr;
+        ncs[i].data = cs2[i2].data;
+        i2++;
+        }
+      else
+        {
+        ncs[i].colnr = cs1[i1].colnr;
+        ncs[i].data = cs1[i1].data + cs2[i2].data;
+        i1++;
+        i2++;
+        }
+      i++;
+      }
+
+    while (i1 < s1)
+      {
+      ncs[i].colnr = cs1[i1].colnr;
+      ncs[i].data = cs1[i1].data;
+      i1++;
+      i++;
+      }
+
+    while (i2 < s2)
+      {
+      ncs[i].colnr = cs2[i2].colnr;
+      ncs[i].data = cs2[i2].data;
+      i2++;
+      i++;
+      }
+
+    if (lins[row].maxsize)
+      DeleteColStruct (cs1, lins[row].maxsize);
+
+    lins[row].col = ncs;
+    lins[row].size = s;
+    lins[row].maxsize = s;
+    }
+
+
+  else
+    {
+    i1 = 0;
+    i2 = 0;
+
+    while (i2 < s2)
+      {
+      if (cs1[i1].colnr == cs2[i2].colnr)
+        {
+        cs1[i1].data += cs2[i2].data;
+        i2++;
+        }
+      i1++;
+      }
+    }
+  }
+
+
+double SparseMatrix :: RowTimesVector (INDEX i, const Vector & v) const
+  {
+  const linestruct * lin;
+  const colstruct * col;
+  double sum;
+  int j;
+
+  if (Width() > v.Length())
+    {
+    cerr << "SparseMatrix::RowTimesVector: Size doesn't fit" << endl;
+    return 0;
+    }
+
+  lin = &lins.Get(i);
+  sum = 0;
+  col = lin->col;
+
+  for (j = lin->size; j > 0; j--, col++)
+    sum += col->data * v.Get(col->colnr);
+
+  return sum;
+  }
+  
+void SparseMatrix :: AddRowToVector (INDEX i, double s, Vector & v) const
+  {
+  const linestruct * lin;
+  const colstruct * col;
+  int j;
+
+  if (Width() > v.Length())
+    {
+    cerr << "SparseMatrix::AddRowToVector: Size doesn't fit" 
+    	 << "w = " << Width() << " len = " << v.Length() << endl;
+    return;
+    }
+
+  lin = &lins.Get(i);
+  col = lin->col;
+
+  for (j = lin->size; j > 0; j--, col++)
+    v.Elem(col->colnr) += s * col->data;
+  }
+
+
+static ARRAY<void*> poolarray;
+static ARRAY<int> poolsizes;
+
+
+SparseMatrix::colstruct * SparseMatrix :: NewColStruct (int s)
+  {
+//  return new colstruct[s];
+
+
+  int i, j;
+  void * p;
+  colstruct * cs;
+
+  if (s > 20) return new colstruct[s];
+
+  for (i = 1; i <= poolsizes.Size(); i++)
+    if (poolsizes.Get(i) == s) break;
+
+  if (i > poolsizes.Size())
+    {
+    poolsizes.Append(s);
+    poolarray.Append((void*)NULL);
+    i = poolsizes.Size();
+    }
+
+  p = poolarray.Get(i);
+  if (!p)
+    {
+    poolarray.Elem(i) = p = cs = new colstruct[10 * s];
+    for (j = 0; j < 9; j++)
+      *(void**)(void*)(&cs[s * j]) = &cs[s * (j+1)];
+    *(void**)(void*)(&cs[s * 9]) = NULL;
+    }
+
+  poolarray.Elem(i) = *(void**)p;
+  return (colstruct*)p;
+  }
+
+void SparseMatrix :: DeleteColStruct (colstruct * cs, int s)
+  {
+//  delete cs;
+//  return;
+
+  int i;
+
+  if (s > 20)
+    {
+    delete cs;
+    return;
+    }
+
+  for (i = 1; i <= poolsizes.Size(); i++)
+    if (poolsizes.Get(i) == s) break;
+
+
+  if (i > poolsizes.Size())
+    {
+    (*myerr) << "SparseMatrix :: DeleteColStruct: Size not found" << endl;
+    return;
+    }
+
+
+  *(void**)(void*)cs = poolarray.Get(i);
+  poolarray.Elem(i) = cs;
+  }
+
+void SparseMatrix :: SetGraph (const class TABLE<INDEX> & graph)
+  { 
+  int i, j, es, ad, nne;
+  colstruct * block;
+  
+  nne = 0;
+  for (i = 1; i <= graph.Size(); i++)
+    {
+    if (Symmetric())
+      {
+      es = 0;
+      for (j = 1; j <= graph.EntrySize(i); j++)
+        if (graph.Get(i, j) <= i)
+          es++;
+      }
+    else
+      es = graph.EntrySize(i);
+    nne += es;
+    }
+    
+  oneblock = 1;
+  block = new colstruct[nne];
+  
+  ad = 0;
+  for (i = 1; i <= graph.Size(); i++)
+    {
+    if (Symmetric())
+      {
+      es = 0;
+      for (j = 1; j <= graph.EntrySize(i); j++)
+        if (graph.Get(i, j) <= i)
+          es++;
+      }
+    else
+      es = graph.EntrySize(i);
+      
+    lins.Elem(i).size = 0;
+    lins.Elem(i).maxsize = es;
+    lins.Elem(i).col = &block[ad];
+    ad += es;
+    }
+  }
+
+
+
+
+#endif
+}
diff --git a/Netgen/libsrc/linalg/sparsmat.hpp b/Netgen/libsrc/linalg/sparsmat.hpp
new file mode 100644
index 0000000000..884ab6575c
--- /dev/null
+++ b/Netgen/libsrc/linalg/sparsmat.hpp
@@ -0,0 +1,261 @@
+#ifndef FILE_SPARSMAT
+#define FILE_SPARSMAT
+
+/* *************************************************************************/
+/* File:   sparsmat.hh                                                    */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Oct. 94                                                    */
+/* *************************************************************************/
+
+
+class SparseMatrix;
+
+/** 
+  The graph of a sparse matrix.
+  The graph is stored for a non-symmetric matrix
+*/
+class MatrixGraph
+{
+  /// data structure for one row of matrix
+  struct linestruct 
+  { 
+    /// allocated size
+    int allocsize;    
+    /// used size
+    int size;    
+    /// diag element (always allocated)      
+    int diag;  
+    /// colume numbers  
+    INDEX* col;
+  };
+
+  /// graph of matrix
+  ARRAY<linestruct> lines;
+  /// increment of allocated line-memory on overflow
+  int increment;
+  
+public:
+  //@{ @name Constructors, Destructor
+
+  /// Height of matrix, increment value for line-overflow
+  MatrixGraph (int size, int aincrement = 5);
+  /// Allocates graph with elements per row given in ARRAY linesize
+  MatrixGraph (const ARRAY<int> & linesize);
+  //@}
+
+  
+  /// returns position of Element (i, j), 0 for unused
+  int GetPosition (INDEX i, INDEX j) const;
+
+  /// returns position of new element
+  int CreatePosition (INDEX i, INDEX j); 
+
+  /// Returns height of matrix
+  int Size() const { return lines.Size(); }
+
+
+  friend class SparseMatrix;
+  friend class SparseMatrixFlex;
+  friend class SparseMatrixFix;
+  friend class PointJacobiPrecond;
+};
+
+
+
+
+
+
+/**
+  Base class for sparse matrix.
+  Matrix to work with in most applications
+  */
+class SparseMatrix : public BaseMatrix
+{
+protected:
+  /// graph of matrix
+  const MatrixGraph * graph;
+  /// pointer to matrix values in each row
+  ARRAY<double*> data;
+
+public:
+
+  /// returns reference, fail save but slow
+  virtual double & operator() (INDEX i, INDEX j);
+  /// returns value, fail save but slow
+  virtual double operator() (INDEX i, INDEX j) const;
+
+
+  /// prod = matrix x v
+  virtual void Mult (const BaseVector & v, BaseVector & prod) const;
+  /// prod = matrix^T x v
+  virtual void MultTrans (const BaseVector & v, BaseVector & prod) const;
+  /// res = b - mat x x
+  virtual void Residuum (const BaseVector & x, const BaseVector & b, 
+			 BaseVector & res) const;
+  /// res = b - mat^T x x
+  virtual void ResiduumTrans (const BaseVector & x, const BaseVector & b,
+			      BaseVector & res) const;
+
+
+  /**
+    Add element matrix to sparse matrix.
+    The graph of the element-matrix must be symmetric.
+    Global point numbers are given in pnum.
+   */
+  virtual void AddElementMatrix (const ARRAY<INDEX> & pnum, const BaseMatrix & elemmat);
+
+  /// for multigrid-extension, should be removed from here
+  void GSStepToInner (const Vector & b, Vector & x, double dump,
+      const BitArray & inner) const;
+
+  /// for multigrid-extension, should be removed from here
+  void GSStepBackToInner (const Vector & b, Vector & x, double dump,
+      const BitArray & inner) const;
+
+  /// 
+  virtual ostream & Print (ostream & s) const;
+
+  /** Scalar product of i-th row times vector.
+    For symmetric matrices only lower left block 
+    (including diagonal) is used.
+    */
+  double RowTimesVector (INDEX i, const Vector & v) const;
+  /** Adds s times the i-th row of matrix to vector v.
+    For symmetric matrices only lower left block 
+    (including diagonal) is used.
+    */
+  void AddRowToVector (INDEX i, double s, Vector & v) const;
+
+  /** Number of elements in line.
+    For symmetric matrices GetDiagPos must be used for
+    most purposes.
+    */
+  int ElementsInLine (INDEX i) const 
+    { return graph->lines.Get(i).size; }
+
+  /** Columne index of nr-th non-zero element in row i */
+  INDEX GetColIndex (INDEX i, int nr) const
+    { return graph->lines.Get(i).col[nr-1]; }
+
+  /** Referece to columne index of nr-th non-zero 
+    element in row i */
+  const INDEX & GetColIndexRef (INDEX i, int nr) const
+    { return graph->lines.Get(i).col[nr-1]; }
+
+  /** Value of nr-th non-zero element in row i */
+  double GetData (INDEX i, int nr) const 
+    { return data.Get(i)[nr-1]; }
+
+  /** Reference to value of nr-th non-zero element in row i */
+  const double & GetDataRef (INDEX i, int nr) const
+    { return data.Get(i)[nr-1]; }
+
+  /** Returns value of diagonal element in row i */
+  double GetDiag (INDEX i) const 
+    { return data.Get(i)[graph->lines.Get(i).diag-1]; }
+
+  /** Which position has diagonal element in row i ? */
+  int GetDiagPos (INDEX i) const
+    { return graph->lines.Get(i).diag; }
+
+  /** Returns matrix value of row i, col j.
+    For symmetric matrices the indices will be sorted in
+    this function */
+  double Get(INDEX i, INDEX j) const;
+
+  /** Set value of element (i, j) to v.
+    For symmetric matrices element (j, i) is set. */
+  void Set(INDEX i, INDEX j, double v);
+
+  /** Returns reference to element (i, j).
+    For symmetric matrices a reference to (j, i) is returned */
+  double & Elem(INDEX i, INDEX j);
+
+  /** Is element (i, j) used ? */
+  char Used (INDEX i, INDEX j) const;
+
+protected:
+  /// A sparse matrix must not be constructed
+  SparseMatrix (INDEX h, INDEX w = 0);
+  /// Allocates matrix position
+  virtual int CreatePosition (INDEX i, INDEX j) = 0;
+
+private:
+  ///
+  friend class ScalarBlockJacobiPrecond;
+  friend class PointJacobiPrecond;
+};
+
+
+
+
+/** Sparse matrix with flexible graph.
+  On demand, a matrix position is allocated */
+class SparseMatrixFlex : public SparseMatrix
+{ 
+ /// non-const pointer to graph.
+ MatrixGraph * mygraph;
+
+public:
+  ///
+  SparseMatrixFlex ();
+  ///
+  SparseMatrixFlex (INDEX h, INDEX w = 0);
+  ///
+  SparseMatrixFlex (const SparseMatrix & m2);
+  ///
+  virtual ~SparseMatrixFlex ();
+
+  /// 
+  virtual void SetSize (INDEX h, INDEX w = 0);
+  ///
+  virtual void SetSymmetric (int sym = 1);
+  ///
+  virtual void ChangeSize (INDEX h, INDEX w = 0);
+  ///
+  void DeleteElements ();
+
+
+  ///
+  SparseMatrix & operator= (const SparseMatrix & m2);
+  ///
+  SparseMatrix & operator*= (double v);
+
+
+  ///
+  virtual BaseMatrix * Copy () const;
+  ///
+  void Delete (INDEX i, int nr);
+  ///
+  void DeleteElem (INDEX i, INDEX j);
+
+  ///
+  void SetLineAllocSize (INDEX i, int j);
+
+protected:
+  ///
+  virtual int CreatePosition (INDEX i, INDEX j);
+
+};
+
+
+
+
+/** Sparse matrix with fixed graph.
+  After construction of the matrix, the graph
+  must not be changed. */
+class SparseMatrixFix : public SparseMatrix
+{
+public:
+  ///
+  SparseMatrixFix (const MatrixGraph & agraph, int asymmetric = 0);
+  ///
+  virtual ~SparseMatrixFix ();
+  
+protected:
+  /// CreatePosition is not allowed for SparseMatrixFix -> error
+  virtual int CreatePosition (INDEX i, INDEX j);
+};
+
+
+#endif
diff --git a/Netgen/libsrc/linalg/vector.cpp b/Netgen/libsrc/linalg/vector.cpp
new file mode 100644
index 0000000000..47be4eefd9
--- /dev/null
+++ b/Netgen/libsrc/linalg/vector.cpp
@@ -0,0 +1,786 @@
+#ifdef abc
+#include <mystdlib.h>
+#include <linalg.hpp>
+
+namespace netgen
+{
+
+double BaseVector :: shit = 0;
+
+// %FD Constructs a vector of length zero
+BaseVector :: BaseVector ()
+  {
+  length = 0;
+  }
+
+// %FD Constructs a vector of given length
+BaseVector :: BaseVector (
+    INDEX alength  // length of the vector
+    )
+  {
+  length = alength;
+  }
+
+// %FD Sets length of the vector, old vector will be destroyed
+void
+BaseVector :: SetLength (
+    INDEX alength        // new length of the vector
+    )
+  {
+  length = alength;
+  }
+
+// %FD Changes length of the vector, old values stay valid
+void
+BaseVector :: ChangeLength (
+    INDEX alength        // new length of the vector
+    )
+  {
+  length = alength;
+  }
+
+
+
+// %FD { Write a vector with the help of the '<<' operator onto a stream }
+ostream &    // stream for further use
+operator<< (
+    ostream & s,            // stream to write vector onto
+    const BaseVector & v   // vector to write
+    )
+  {
+  return v.Print (s);
+  }
+
+
+// %FD{ Divides every component of the vector by the scalar c.
+//      The function checks for division by zero }
+BaseVector &      // result vector
+BaseVector :: operator/= (
+    double c       // scalar to divide by
+    )
+  {
+  if (c)
+    return (*this) *= (1/c);
+  else
+    {
+    (*myerr) << "operator/=: division by zero" << endl;
+    return *this;
+    }
+  }
+
+
+// %FD Creates a copy of the object
+BaseVector *      // pointer to the new vector
+BaseVector :: Copy () const
+  {
+  cerr << "Base_vector::Copy called" << endl << flush;
+  return NULL;
+  }
+
+
+
+
+void BaseVector :: GetElementVector (const ARRAY<INDEX> & pnum,
+				 BaseVector & elvec) const
+{
+  int i;
+  for (i = 1; i <= pnum.Size(); i++)
+    elvec(i) = (*this)(pnum.Get(i));
+}
+
+void BaseVector :: SetElementVector (const ARRAY<INDEX> & pnum,
+				 const BaseVector & elvec)
+{
+  int i;
+  for (i = 1; i <= pnum.Size(); i++)
+    (*this)(pnum.Get(i)) = elvec(i);
+}
+
+
+void BaseVector :: AddElementVector (const ARRAY<INDEX> & pnum,
+				 const BaseVector & elvec)
+{
+  int i;
+  for (i = 1; i <= pnum.Size(); i++)
+    (*this)(pnum.Get(i)) += elvec(i);
+}
+
+
+
+
+
+
+
+
+
+
+
+TempVector :: ~TempVector ()
+  {
+  delete vec;
+  }
+
+TempVector BaseVector :: operator+ (const BaseVector & v2) const
+  {
+  return (*Copy()) += v2;
+  }
+
+TempVector BaseVector :: operator- (const BaseVector & v2) const
+  {
+  return (*Copy()) -= v2;
+  }
+
+TempVector BaseVector :: operator- () const
+  {
+  return (*Copy()) *= -1;
+  }
+
+
+TempVector operator* (const BaseVector & v1, double scal) 
+  {
+  return (*v1.Copy()) *= scal;
+  }
+
+TempVector operator/ (const BaseVector & v1, double scal) 
+  {
+  return (*v1.Copy()) /= scal;
+  }
+
+
+TempVector operator* (double scal, const BaseVector & v1)
+  {
+  return v1 * scal;
+  }
+
+
+
+
+
+BaseVector * TempVector :: Copy () const
+  {
+  return vec->Copy();
+  }
+
+
+
+
+
+
+
+
+
+
+double Vector :: shit = 0;
+
+class clVecpool
+{
+public:
+  ARRAY<double *> vecs;
+  ARRAY<INDEX> veclens;
+
+  ~clVecpool();
+};
+
+clVecpool :: ~clVecpool()
+{
+  int i;
+  for (i = 1; i <= vecs.Size(); i++)
+    delete vecs.Elem(i);
+}
+
+static clVecpool vecpool;
+
+
+
+static double * NewDouble (INDEX len)
+{
+  if (len < 10)
+    return new double[len];
+  else
+    {
+      int i;
+      for (i = 1; i <= vecpool.veclens.Size(); i++)
+	if (vecpool.veclens.Get(i) == len)
+	  {
+	    double * hvec = vecpool.vecs.Get(i);
+	    vecpool.vecs.DeleteElement(i);
+	    vecpool.veclens.DeleteElement(i);
+	    return hvec;
+	  }
+
+      return new double[len];
+    }
+}
+
+static void DeleteDouble (INDEX len, double * dp)
+{
+  if (len < 10)
+    delete [] dp;
+  else
+    {
+      vecpool.vecs.Append (dp);
+      vecpool.veclens.Append (len);
+    }
+}
+
+
+
+Vector :: Vector () : BaseVector()
+  {
+  data = NULL;
+  }
+
+Vector :: Vector (INDEX alength) : BaseVector (alength)
+  {
+  if (length)
+    {
+      //    data = new double[length];
+      data = NewDouble (length);
+
+    if (!data)
+      {
+      length = 0;
+      (*myerr) << "Vector not allocated" << endl;
+      }
+    }
+  else
+    data = NULL;
+  }
+
+
+Vector :: Vector (const Vector & v2)
+  {
+  length = v2.length;
+
+  if (length)
+    {
+      //    data = new double[length];
+      data = NewDouble (length);
+
+    if (data)
+      {
+      memcpy (data, v2.data, length * sizeof (double));
+      }
+    else
+      {
+      length = 0;
+      (*myerr) << "Vector::Vector : Vector not allocated" << endl;
+      }
+    }
+  else
+    data = NULL;
+  }
+
+
+Vector :: ~Vector ()
+{
+  //  veclenfile << "~Vector delete: " << length << endl;
+  if (data) 
+    {
+      DeleteDouble (length, data);
+      //      delete [] data;
+    }
+
+}
+
+void Vector :: SetLength (INDEX alength)
+  {
+  if (length == alength) return;
+
+  if (data) 
+    {
+      DeleteDouble (length, data);
+      //      delete [] data;
+    }
+  data = NULL;
+  length = alength;
+
+  if (length == 0) return;
+  //  data = new double[length];
+  data = NewDouble (length);
+
+  if (!data)
+    {
+    length = 0;
+    (*myerr) << "Vector::SetLength: Vector not allocated" << endl;
+    }
+  }
+
+void Vector :: ChangeLength (INDEX alength)
+{
+  (*mycout) << "Vector::ChangeLength called" << endl;
+  if (length == alength) return;
+  
+  if (alength == 0)
+    {
+      //    delete [] data;
+      DeleteDouble (length, data);
+      length = 0;
+      return;
+    }
+  
+  double * olddata = data;
+
+  data = NewDouble (alength);
+  //  data = new double[alength];
+  if (!data)
+    {
+    length = 0;
+    (*myerr) << "Vector::SetLength: Vector not allocated" << endl;
+    delete [] olddata;
+    }
+
+  memcpy (data, olddata, min2(alength, length));
+
+  delete [] olddata;
+  length = alength;
+  }
+
+/// NEW RM
+void Vector::SetBlockLength (INDEX /* blength */)
+{
+  MyError("BaseVector::SetBlockLength was called for a Vector");
+}
+
+
+double & Vector :: operator() (INDEX i)
+  {
+  if (i >= 1 && i <= length) return Elem(i);
+  else (*myerr) << "\nindex " << i << " out of range ("
+                                << 1 << "," << Length() << ")\n";
+  return shit;
+  }
+
+double Vector :: operator() (INDEX i) const
+  {
+  if (i >= 1 && i <= length) return Get(i);
+  else (*myerr) << "\nindex " << i << " out of range ("
+                                << 1 << "," << Length() << ")\n" << flush;
+  return shit;
+  }
+
+
+
+double Vector :: SupNorm () const
+  {
+  double sup = 0;
+
+  for (INDEX i = 1; i <= Length(); i++)
+    if (fabs (Get(i)) > sup)
+      sup = fabs(Get(i));
+
+  return sup;
+  }
+
+double Vector :: L2Norm () const
+  {
+  double sum = 0;
+
+  for (INDEX i = 1; i <= Length(); i++)
+    sum += Get(i) * Get(i);
+
+  return sqrt (sum);
+  }
+
+double Vector :: L1Norm () const
+  {
+  double sum = 0;
+
+  for (INDEX i = 1; i <= Length(); i++)
+    sum += fabs (Get(i));
+
+  return sum;
+  }
+
+double Vector :: Max () const
+  {
+  if (!Length()) return 0;
+  double m = Get(1);
+  for (INDEX i = 2; i <= Length(); i++)
+    if (Get(i) > m) m = Get(i);
+  return m;
+  }
+
+double Vector :: Min () const
+  {
+  if (!Length()) return 0;
+  double m = Get(1);
+  for (INDEX i = 2; i <= Length(); i++)
+    if (Get(i) < m) m = Get(i);
+  return m;
+  }
+
+
+/*
+ostream & operator<<(ostream & s, const Vector & v)
+  {
+  int w = s.width();
+  if (v.Length())
+    {
+    s.width(0);
+    s << '(';
+    for (INDEX i = 1; i < v.Length(); i++)
+      {
+      s.width(w);
+      s << v.Get(i) << ",";
+      if (i % 8 == 0) s << endl << ' ';
+      }
+    s.width(w);
+    s << v.Get(v.Length()) << ')';
+    }
+  else
+    s << "(Vector not allocated)";
+
+  return s;
+  }
+*/
+
+ostream & Vector :: Print (ostream & s) const
+  {
+  int w = s.width();
+  if (Length())
+    {
+    s.width(0);
+    s << '(';
+    for (INDEX i = 1; i < Length(); i++)
+      {
+      s.width(w);
+      s << Get(i) << ",";
+      if (i % 8 == 0) s << endl << ' ';
+      }
+    s.width(w);
+    s << Get(Length()) << ')';
+    }
+  else
+    s << "(Vector not allocated)";
+
+  return s;
+  }
+
+
+
+BaseVector & Vector :: operator+= (const BaseVector & v2)
+  {
+  const Vector & hv2 = v2.CastToVector();
+
+  if (Length() == hv2.Length())
+    for (INDEX i = 1; i <= Length(); i++)
+      Elem (i) += hv2.Get(i);
+  else
+    (*myerr) << "operator+= illegal dimension" << endl;
+  return *this;
+  }
+
+BaseVector & Vector :: operator-= (const BaseVector & v2)
+  {
+  const Vector & hv2 = v2.CastToVector();
+
+  if (Length() == hv2.Length())
+    for (INDEX i = 1; i <= Length(); i++)
+      Elem (i) -= hv2.Get(i);
+  else
+    (*myerr) << "operator-= illegal dimension" << endl;
+  return *this;
+  }
+
+BaseVector & Vector :: operator*= (double c)
+  {
+  for (INDEX i = 1; i <= Length(); i++)
+    Elem(i) *= c;
+  return *this;
+  }
+
+
+
+BaseVector & Vector :: Add (double scal, const BaseVector & v2)
+  {
+  const Vector & hv2 = v2.CastToVector();
+
+  if (Length() == hv2.Length())
+    {
+    double * p1 = data;
+    double * p2 = hv2.data;
+
+    for (INDEX i = Length(); i > 0; i--)
+      {
+      (*p1) += scal * (*p2);
+      p1++; p2++;
+      }
+    }
+  else
+    (*myerr) << "Vector::Add: illegal dimension" << endl;
+  return *this;
+  }
+
+BaseVector & Vector :: Add2 (double scal, const BaseVector & v2,
+                             double scal3, const BaseVector & v3)
+  {
+  const Vector & hv2 = v2.CastToVector();
+  const Vector & hv3 = v3.CastToVector();
+
+  if (Length() == hv2.Length())
+    {
+    double * p1 = data;
+    double * p2 = hv2.data;
+    double * p3 = hv3.data;
+
+    for (INDEX i = Length(); i > 0; i--)
+      {
+      (*p1) += (scal * (*p2) + scal3 * (*p3));
+      p1++; p2++; p3++;
+      }
+    }
+  else
+    (*myerr) << "Vector::Add: illegal dimension" << endl;
+  return *this;
+  }
+
+BaseVector & Vector :: Set (double scal, const BaseVector & v2)
+  {
+  const Vector & hv2 = v2.CastToVector();
+
+  if (Length() == hv2.Length())
+    {
+    double * p1 = data;
+    double * p2 = hv2.data;
+
+    for (INDEX i = Length(); i > 0; i--)
+      {
+      (*p1) = scal * (*p2);
+      p1++; p2++;
+      }
+    }
+  else
+    (*myerr) << "Vector::Set: illegal dimension" << endl;
+  return *this;
+  }
+
+
+BaseVector & Vector :: Set2 (double scal , const BaseVector & v2,
+      double scal3, const BaseVector & v3)
+  {
+  const Vector & hv2 = v2.CastToVector();
+  const Vector & hv3 = v3.CastToVector();
+
+
+  if (Length() == hv2.Length())
+    {
+    double * p1 = data;
+    double * p2 = hv2.data;
+    double * p3 = hv3.data;
+
+    for (INDEX i = Length(); i > 0; i--)
+      {
+      (*p1) = scal * (*p2) + scal3 * (*p3);
+      p1++; p2++; p3++;
+      }
+    }
+  else
+    (*myerr) << "Vector::Set: illegal dimension" << endl;
+  return *this;
+  }
+
+
+void Vector :: GetPart (int startpos, BaseVector & v2) const
+{
+  Vector & hv2 = v2.CastToVector();
+
+  if (Length() >= startpos + v2.Length() - 1)
+    {
+      const double * p1 = &Get(startpos);
+      double * p2 = &hv2.Elem(1);
+      
+      memcpy (p2, p1, hv2.Length() * sizeof(double));
+    }
+  else
+    MyError ("Vector::GetPart: Vector to short");
+}
+
+
+// NEW RM
+void Vector :: SetPart (int startpos, const BaseVector & v2)
+{
+  const Vector & hv2 = v2.CastToVector();
+  INDEX i;
+  INDEX n = v2.Length();
+
+  if (Length() >= startpos + n - 1)
+    {
+      double * p1 = &Elem(startpos);
+      const double * p2 = &hv2.Get(1);
+
+      for (i = 1; i <= n; i++)
+	{
+	  (*p1) = (*p2);
+	  p1++;
+	  p2++;
+	}
+    }
+  else
+    MyError ("Vector::SetPart: Vector to short");
+}
+
+void Vector :: AddPart (int startpos, double val, const BaseVector & v2)
+{
+  const Vector & hv2 = v2.CastToVector();
+  INDEX i;
+  INDEX n = v2.Length();
+
+  if (Length() >= startpos + n - 1)
+    {
+      double * p1 = &Elem(startpos);
+      const double * p2 = &hv2.Get(1);
+
+      for (i = 1; i <= n; i++)
+	{
+	  (*p1) += val * (*p2);
+	  p1++;
+	  p2++;
+	}
+    }
+  else
+    MyError ("Vector::AddPart: Vector to short");
+}
+
+
+
+
+double Vector :: operator* (const BaseVector & v2) const
+  {
+  const Vector & hv2 = v2.CastToVector();
+
+  double sum = 0;
+  double * p1 = data;
+  double * p2 = hv2.data;
+
+  if (Length() == hv2.Length())
+    {
+    for (INDEX i = Length(); i > 0; i--)
+      {
+      sum += (*p1) * (*p2);
+      p1++; p2++;
+      }
+    }
+  else
+    (*myerr) << "Scalarproduct illegal dimension" << endl;
+  return sum;
+  }
+
+void Vector :: SetRandom ()
+  {
+  INDEX i;
+  for (i = 1; i <= Length(); i++)
+    Elem(i) = rand ();
+
+  double l2 = L2Norm();
+  if (l2 > 0)
+    (*this) /= l2;
+    //    Elem(i) = 1.0 / double(i);
+    //    Elem(i) = drand48();
+  }
+
+
+/*
+TempVector Vector :: operator- () const
+  {
+  Vector & sum = *(Vector*)Copy();
+
+  if (sum.Length () == Length())
+    {
+    for (INDEX i = 1; i <= Length(); i++)
+      sum.Set (i, Get(i));
+    }
+  else
+    (*myerr) << "operator+ (Vector, Vector): sum.Length() not ok" << endl;
+  return sum;
+  }
+*/
+
+BaseVector & Vector::operator= (const Vector & v2)
+  {
+  SetLength (v2.Length());
+
+  if (data == v2.data) return *this;
+  
+  if (v2.Length() == Length())
+    memcpy (data, v2.data, sizeof (double) * Length());
+  else
+    (*myerr) << "Vector::operator=: not allocated" << endl;
+
+  return *this;
+  }
+
+BaseVector & Vector::operator= (const BaseVector & v2)
+  {
+  const Vector & hv2 = v2.CastToVector();
+
+  SetLength (hv2.Length());
+
+  if (data == hv2.data) return *this;
+  
+  if (hv2.Length() == Length())
+    memcpy (data, hv2.data, sizeof (double) * Length());
+  else
+    (*myerr) << "Vector::operator=: not allocated" << endl;
+
+  return *this;
+  }
+
+
+BaseVector & Vector::operator= (double scal)
+  {
+  if (!Length()) (*myerr) << "Vector::operator= (double) : data not allocated"
+                      << endl;
+
+  for (INDEX i = 1; i <= Length(); i++)
+    Set (i, scal);
+
+  return *this;
+  }
+
+
+BaseVector * Vector :: Copy () const
+  {
+  return new Vector (*this);
+  }
+
+
+void Vector :: Swap (BaseVector & v2)
+  {
+  Vector & hv2 = v2.CastToVector();
+  swap (length, hv2.length);
+  swap (data, hv2.data);
+  }
+
+
+
+
+void Vector :: GetElementVector (const ARRAY<INDEX> & pnum,
+				 BaseVector & elvec) const
+{
+  int i;
+  Vector & helvec = elvec.CastToVector();
+  for (i = 1; i <= pnum.Size(); i++)
+    helvec.Elem(i) = Get(pnum.Get(i));
+}
+
+void Vector :: SetElementVector (const ARRAY<INDEX> & pnum,
+				 const BaseVector & elvec)
+{
+  int i;
+  const Vector & helvec = elvec.CastToVector();
+  for (i = 1; i <= pnum.Size(); i++)
+    Elem(pnum.Get(i)) = helvec.Get(i);
+}
+
+
+void Vector :: AddElementVector (const ARRAY<INDEX> & pnum,
+				 const BaseVector & elvec)
+{
+  int i;
+  const Vector & helvec = elvec.CastToVector();
+  for (i = 1; i <= pnum.Size(); i++)
+    Elem(pnum.Get(i)) += helvec.Get(i);
+}
+}
+#endif
diff --git a/Netgen/libsrc/linalg/vector.hpp b/Netgen/libsrc/linalg/vector.hpp
new file mode 100644
index 0000000000..acba491792
--- /dev/null
+++ b/Netgen/libsrc/linalg/vector.hpp
@@ -0,0 +1,485 @@
+#ifndef FILE_VECTOR
+#define FILE_VECTOR
+
+/* *************************************************************************/
+/* File:   vector.hh                                                      */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Oct. 94                                                    */
+/* *************************************************************************/
+
+
+class FlatVector
+{
+protected:
+  int s;
+  double *data;
+public:
+  FlatVector () { ; }
+  FlatVector (int as, double * adata)
+  { s = as; data = adata; }
+
+  int Size () const
+  { return s; }
+
+  FlatVector & operator= (const FlatVector & v) 
+  { memcpy (data, v.data, s*sizeof(double)); return *this; }
+
+  FlatVector & operator= (double scal) 
+  {
+    for (int i = 0; i < s; i++) data[i] = scal; 
+    return *this;
+  }
+
+  double & operator[] (int i) { return data[i]; }
+  const double & operator[] (int i) const { return data[i]; }
+  double & operator() (int i) { return data[i]; }
+  const double & operator() (int i) const { return data[i]; }
+
+  double & Elem (int i) { return data[i-1]; }
+  const double & Get (int i) const { return data[i-1]; }
+  void Set (int i, double val) { data[i-1] = val; }
+
+  FlatVector & operator*= (double scal)
+  {
+    for (int i = 0; i < s; i++) data[i] *= scal;
+    return *this;
+  }
+
+  FlatVector & Add (double scal, const FlatVector & v2)
+  {
+    for (int i = 0; i < s; i++) 
+      data[i] += scal * v2.data[i];
+    return *this;
+  }
+
+  FlatVector & Set (double scal, const FlatVector & v2)
+  {
+    for (int i = 0; i < s; i++) 
+      data[i] = scal * v2.data[i];
+    return *this;
+  }
+
+  FlatVector & Set2 (double scal1, const FlatVector & v1,
+		 double scal2, const FlatVector & v2)
+  {
+    for (int i = 0; i < s; i++) 
+      data[i] = scal1 * v1.data[i] + scal2 * v2.data[i];
+    return *this;
+  }
+  
+  double L2Norm() const
+  {
+    double sum = 0;
+    for (int i = 0; i < s; i++)
+      sum += data[i] * data[i];
+    return sqrt (sum);
+  }
+
+  friend double operator* (const FlatVector & v1, const FlatVector & v2);
+};
+
+
+
+class Vector : public FlatVector
+{
+
+public:
+  Vector () 
+  { s = 0; data = 0; }
+  Vector (int as)
+  { s = as; data = new double[s]; }
+  ~Vector ()
+  { delete [] data; }
+
+  Vector & operator= (const FlatVector & v) 
+  { memcpy (data, &v.Get(1), s*sizeof(double)); return *this; }
+
+  Vector & operator= (double scal) 
+  {
+    for (int i = 0; i < s; i++) data[i] = scal; 
+    return *this;
+  }
+
+  void SetSize (int as)
+  {
+    if (s != as)
+      {
+	s = as;
+	delete [] data;
+	data = new double [s];
+      }
+  }
+
+};
+
+
+inline double operator* (const FlatVector & v1, const FlatVector & v2)
+{
+  double sum = 0;
+  for (int i = 0; i < v1.s; i++)
+    sum += v1.data[i] * v2.data[i];
+  return sum;
+}
+
+
+
+
+inline ostream & operator<< (ostream & ost, const FlatVector & v)
+{
+  for (int i = 0; i < v.Size(); i++)
+    ost << " " << setw(7) << v[i];
+  return ost;
+}
+
+
+
+
+
+
+
+
+
+
+#ifdef OLDVEC
+
+class TempVector;
+class Vector;
+class BlockVector;
+
+/** Data types for vectors.
+   
+   Every Vector data structure is derived from a BaseVector class.
+   A BaseVector provides virtual functions for the scalar-vector
+   and vector-vector operations. 
+   If the return value of a function is a vector, then there should
+   be used a TempVector class. This avoids one additional constructor/
+   destructor call.
+   Finally, a Vector - class contains the data of a Vector in dense
+   form.
+   
+   Vector - Operations:
+   
+     Vector ( x )       Constructor empty, with given length or 
+                        given vector to copy  
+                       
+     SetLength () 
+     ChangeLength()     Change vector-length with/without destroing the vector
+     Length()           return vector-length
+     
+     Copy()             Construct a vector of same type and contents
+     
+     operator()         Save vector access
+     Set, Get, Elem:    Fast vector access for setting, receiving and reference
+
+     +, -, *, =, +=, -=, *=, /=
+     			virtual vector operations
+                     
+     SupNorm, L2Norm, L1Norm, Min, Max
+			Vector operations 
+			
+     Set (s, v), Add (s, v)
+     			Fast scalar-vector operations
+     			
+     Print ()           stream output of a vector
+
+*/
+
+class BaseVector
+{
+protected:
+  ///
+  INDEX length;
+  ///
+  static double shit;
+  
+public:
+  ///
+  BaseVector ();
+  ///
+  BaseVector (INDEX alength);
+  ///
+  virtual ~BaseVector () { };
+  ///
+  virtual void SetSize (INDEX asize) { SetLength(asize); }
+  ///
+  virtual void SetLength (INDEX alength);
+  ///
+  virtual void ChangeLength (INDEX alength);
+  /// Size should be prefered !!!
+  INDEX Length () const { return length; }
+  /// 
+  INDEX Size() const { return length; }
+
+    // NEW RM ---> in BlockVector
+    // rtual void SetBlockLength (INDEX blength) = 0;
+
+  ///
+  virtual BaseVector & operator= (const BaseVector & /* v2 */) { return *this; }
+  ///
+  virtual BaseVector & operator= (double /* scal */) { return *this; }
+
+  ///
+  virtual double & operator() (INDEX /* i */) { return shit; }
+  ///
+  virtual double operator() (INDEX /* i */) const { return 0; }
+
+  ///
+  virtual double SupNorm () const = 0;
+  ///
+  virtual double L2Norm () const = 0;
+  ///
+  virtual double L1Norm () const = 0;
+  ///
+  virtual double Min () const = 0;
+  ///
+  virtual double Max () const = 0;
+
+  ///
+  virtual BaseVector & operator+= (const BaseVector & v2) = 0;
+  ///
+  virtual BaseVector & operator-= (const BaseVector & v2) = 0;
+  ///
+  virtual BaseVector & operator*= (double scal) = 0;
+  ///
+  virtual BaseVector & operator/= (double scal);
+
+  ///
+  virtual TempVector operator+ (const BaseVector & v2) const;
+  ///
+  virtual TempVector operator- (const BaseVector & v2) const;
+  ///
+  virtual TempVector operator- () const;
+  ///
+  virtual double operator* (const BaseVector & v2) const = 0;
+  ///
+  friend TempVector operator* (const BaseVector & v1, double scal);
+  ///
+  friend TempVector operator/ (const BaseVector & v1, double scal);
+  ///
+  friend TempVector operator* (double scal, const BaseVector & v1);
+
+  ///
+  virtual BaseVector & Add (double /* scal */, const BaseVector & /* v2 */) { return *this; }
+  ///
+  virtual BaseVector & Add2 (double /* scal */, const BaseVector & /* v2 */,
+                        double /* scal3 */, const BaseVector & /* v3 */) { return *this; }
+  ///
+  virtual BaseVector & Set (double /* scal */, const BaseVector & /* v2 */) { return *this; }
+  ///
+  virtual BaseVector & Set2 (double /* scal */, const BaseVector & /* v2 */,
+                        double /* scal3 */, const BaseVector & /* v3 */) { return *this; }
+
+    ///
+    virtual void SetRandom () { };
+
+    
+    ///
+    virtual void GetPart (int /* startpos */, 
+			  BaseVector & /* v2*/ ) const { };
+    ///
+    virtual void SetPart (int /* startpos */,  
+			  const BaseVector & /* v2 */) { };
+    ///
+    virtual void AddPart (int /* startpos */, double /* val */, 
+			  const BaseVector & /* v2 */) { };
+
+  ///
+  virtual void GetElementVector (const ARRAY<INDEX> & pnum,
+				 BaseVector & elvec) const;
+  ///
+  virtual void SetElementVector (const ARRAY<INDEX> & pnum,
+				 const BaseVector & elvec);
+  ///
+  virtual void AddElementVector (const ARRAY<INDEX> & pnum,
+				 const BaseVector & elvec);
+
+  ///
+  friend ostream & operator<<(ostream & s, const BaseVector & v);
+  ///
+  virtual ostream & Print (ostream & s) const { return s; }
+
+  ///
+  virtual BaseVector * Copy () const;
+  /// 
+  virtual int IsVector () const { return 0; }
+  ///
+  virtual int IsBlockVector () const { return 0; }
+  ///
+  virtual Vector & CastToVector () { return *(Vector*)this; }
+  ///
+  virtual const Vector & CastToVector () const { return *(Vector*)this; }
+  ///
+  virtual BlockVector & CastToBlockVector () { return *(BlockVector*)this; }
+  ///
+  virtual const BlockVector & CastToBlockVector () const { return *(BlockVector*)this; }
+  };
+
+
+///
+class TempVector : public BaseVector
+{
+  ///
+  BaseVector * vec;
+
+  public:
+  ///
+  TempVector (BaseVector & v1) { vec = & v1; }
+  ///
+  ~TempVector ();
+  ///
+  virtual Vector & CastToVector ()
+      { return vec->CastToVector(); }
+  ///
+  virtual const Vector & CastToVector () const
+      { return vec->CastToVector(); }
+  ///
+  virtual BlockVector & CastToBlockVector ()
+      { return vec->CastToBlockVector(); }
+  ///
+  virtual const BlockVector & CastToBlockVector () const
+      { return vec->CastToBlockVector(); }
+
+
+  ///
+  virtual BaseVector & operator+= (const BaseVector & /* v2 */) { return *this; }
+  ///
+  virtual BaseVector & operator-= (const BaseVector & /* v2 */) { return *this; }
+  ///
+  virtual BaseVector & operator*= (double /* scal */) { return *this; }
+  ///
+  virtual double operator* (const BaseVector & /* v2 */) const { return 0; }
+
+  ///
+  virtual double SupNorm () const { return vec->SupNorm(); }
+  ///
+  virtual double L2Norm () const { return vec->L2Norm(); }
+  ///
+  virtual double L1Norm () const { return vec->L1Norm(); }
+  ///
+  virtual double Min () const { return vec->Min(); }
+  ///
+  virtual double Max () const { return vec->Max(); }
+
+  ///
+  virtual void Swap (BaseVector &) { };
+  ///
+  virtual BaseVector * Copy () const;
+
+
+  };
+
+
+///
+class Vector : public BaseVector
+{
+  ///
+  double * data;
+  ///
+  static double shit;
+  
+public:
+  ///
+  Vector ();
+  ///
+  Vector (INDEX alength);
+  ///
+  Vector (const Vector & v2);
+  ///
+  virtual ~Vector ();
+
+  ///
+  virtual void SetLength (INDEX alength);
+  ///
+  virtual void ChangeLength (INDEX alength);
+  /// NEW RM
+  virtual void SetBlockLength (INDEX blength);
+
+  ///
+  virtual BaseVector & operator= (const BaseVector & v2);
+  ///
+  virtual BaseVector & operator= (const Vector & v2);
+  ///
+  virtual BaseVector & operator= (double scal);
+
+  ///
+  double & operator() (INDEX i);
+  ///
+  double operator() (INDEX i) const;
+
+  ///
+  virtual double SupNorm () const;
+  ///
+  virtual double L2Norm () const;
+  ///
+  virtual double L1Norm () const;
+  ///
+  virtual double Min () const;
+  ///
+  virtual double Max () const;
+
+  ///
+  virtual BaseVector & operator+= (const BaseVector & v2);
+  ///
+  virtual BaseVector & operator-= (const BaseVector & v2);
+  ///
+  virtual BaseVector & operator*= (double scal);
+
+  ///
+  virtual double operator* (const BaseVector & v2) const;
+
+
+  ///
+  virtual BaseVector & Add (double scal, const BaseVector & v2);
+  ///
+  virtual BaseVector & Add2 (double scal, const BaseVector & v2,
+                        double scal3, const BaseVector & v3);
+  ///
+  virtual BaseVector & Set (double scal, const BaseVector & v2);
+  ///
+  virtual BaseVector & Set2 (double scal , const BaseVector & v2,
+                        double scal3, const BaseVector & v3);
+
+    ///
+    virtual void GetPart (int startpos, BaseVector & v2) const;
+    ///
+    virtual void SetPart (int startpos, const BaseVector & v2);
+    ///
+    virtual void AddPart (int startpos, double val, const BaseVector & v2);
+
+  ///
+  virtual void SetRandom ();
+
+  ///
+  virtual ostream & Print (ostream & s) const;
+  ///
+  virtual BaseVector * Copy () const;
+  ///
+  virtual void Swap (BaseVector &);
+
+  ///
+  const double & Get (INDEX i) const { return data[i-1]; }
+  ///
+  void Set (INDEX i, double v) { data[i-1] = v; }
+  ///
+  double & Elem (INDEX i) { return data[i-1]; }
+
+  ///
+  virtual int IsVector () const { return 1; }
+
+
+  ///
+  virtual void GetElementVector (const ARRAY<INDEX> & pnum,
+				 BaseVector & elvec) const;
+  ///
+  virtual void SetElementVector (const ARRAY<INDEX> & pnum,
+				 const BaseVector & elvec);
+  ///
+  virtual void AddElementVector (const ARRAY<INDEX> & pnum,
+				 const BaseVector & elvec);
+  };
+
+#endif
+
+#endif
+
+
diff --git a/Netgen/libsrc/makefile.inc b/Netgen/libsrc/makefile.inc
new file mode 100644
index 0000000000..6a98d84e43
--- /dev/null
+++ b/Netgen/libsrc/makefile.inc
@@ -0,0 +1,46 @@
+#
+#
+# Make-Include-File for library
+# Joachim Schoeberl, 17.04.96
+#
+#
+CPP_DIR=../..
+LIBSRC_DIR=$(CPP_DIR)/libsrc
+LIB_DIR=$(CPP_DIR)/lib/$(MACHINE)
+OCC_DIR=../../occ
+# OCC_DIR=/opt/OpenCASCADE5.1/ros
+OCCINC_DIR=$(OCC_DIR)/inc
+# OCCLIB_DIR=$(OCC_DIR)/lib
+#
+include $(LIBSRC_DIR)/makefile.mach.$(MACHINE)
+#
+CPLUSPLUSFLAGS1 = -c -I$(LIBSRC_DIR)/include -I$(OCCINC_DIR) 
+#
+ARFLAGS = r
+#
+LIBB=$(LIB_DIR)/lib$(lib).a
+#
+.PRECIOUS: .cpp .hh 
+.SUFFIXES: .cpp .o 
+#
+.cpp.o:
+	$(CPLUSPLUS) $(CPLUSPLUSFLAGS1) $(CPLUSPLUSFLAGS2) $(CPLUSPLUSFLAGSLIBRARY) $<
+#
+#
+$(LIBB):: $(LIB_DIR) 
+#
+# make lib from sources:
+#
+$(LIBB):: $(src) 
+	$(CPLUSPLUS) $(CPLUSPLUSFLAGS1) $(CPLUSPLUSFLAGS2) $(CPLUSPLUSFLAGSLIBRARY)  $?
+	@$(AR) $(ARFLAGS) $@ *.o
+	-@$(RM) *.o
+	-@$(RANLIB) $@
+#
+#
+#
+$(LIB_DIR) :
+	-@mkdir $(CPP_DIR)/lib
+	@mkdir $(LIB_DIR)
+#
+#
diff --git a/Netgen/libsrc/makefile.mach.INTEL b/Netgen/libsrc/makefile.mach.INTEL
new file mode 100644
index 0000000000..c445191a24
--- /dev/null
+++ b/Netgen/libsrc/makefile.mach.INTEL
@@ -0,0 +1,18 @@
+#
+# Machine dependent make include file for Intel compiler
+#
+CC=icc
+CPLUSPLUS=$(CC)
+AR=ar
+LINK=$(CC)
+MAKE=make
+RM=rm
+RANLIB=ranlib
+#
+# Machine dependent flags:
+#
+CFLAGS2 =
+CPLUSPLUSFLAGS2 = -O2  -wd654 -DLINUX -DOPENGL 
+#  
+LINKFLAGS2 =  -L/usr/openwin/lib -L/usr/X11R6/lib -L/usr/lib/GL3.5 
+
diff --git a/Netgen/libsrc/makefile.mach.LINUX b/Netgen/libsrc/makefile.mach.LINUX
new file mode 100644
index 0000000000..44e4a5ccdd
--- /dev/null
+++ b/Netgen/libsrc/makefile.mach.LINUX
@@ -0,0 +1,20 @@
+#
+# Machine dependent make include file for gcc
+# 
+#
+CC=gcc
+CPLUSPLUS=$(CC)
+AR=ar
+LINK=$(CC)
+MAKE=make
+RM=rm
+RANLIB=ranlib
+#
+# Machine dependent flags:
+#
+CFLAGS2 =
+CPLUSPLUSFLAGS2 = -O2 -I/usr/X11R6/include -DLINUX -DOPENGL 
+#
+LINKFLAGS2 =  -L/usr/openwin/lib -L/usr/X11R6/lib
+
+SYSLIB2 = -lstdc++
diff --git a/Netgen/libsrc/makefile.mach.SGI b/Netgen/libsrc/makefile.mach.SGI
new file mode 100644
index 0000000000..b75920ce26
--- /dev/null
+++ b/Netgen/libsrc/makefile.mach.SGI
@@ -0,0 +1,19 @@
+#
+# Machine dependent make include file
+# 
+CC=CC
+CPLUSPLUS=$(CC)
+AR=ar
+LINK=$(CC)
+MAKE=make -k
+RM=rm
+RANLIB=echo
+#
+CFLAGS2 =
+#
+CPLUSPLUSFLAGS2 = -O2 -LANG:std -OPT:Olimit=0 -I/usr/X11R6/include -I/usr/local/include -I/nfs/home/joachim/tcltk/include -DOPENGL -woff 1174 -woff 1682 -woff 1681 -woff 1552 -DOLDCINCLUDE
+# -woff 3262,3203,1174,1110
+#
+#  -I/usr/freeware/include
+LINKFLAGS2 = -LANG:std  -L/usr/openwin/lib -L/usr/freeware/lib32 -L/usr/X11R6/lib -L/usr/local/lib  -w -L/nfs/home/joachim/tcltk/lib
+
diff --git a/Netgen/libsrc/makefile.mach.SGIGCC b/Netgen/libsrc/makefile.mach.SGIGCC
new file mode 100644
index 0000000000..c43363c5e7
--- /dev/null
+++ b/Netgen/libsrc/makefile.mach.SGIGCC
@@ -0,0 +1,53 @@
+#
+# Machine dependent make include file
+# 
+#
+# CC=/opt/experimental/bin/gcc 
+CC=/usr/freeware/bin/gcc
+CPLUSPLUS=$(CC)
+AR=ar
+LINK=$(CC)
+MAKE=make
+RM=rm
+RANLIB=ranlib
+#
+# Machine dependent flags:
+#
+CFLAGS2 =
+# I/opt/experimental/include/g++-v3 
+CPLUSPLUSFLAGS2 = -O2 -save-temps -fverbose-asm -I/usr/local/include -I/usr/freeware/include -I/usr/freeware/include/tcl -I/usr/freeware/include/tk -I/usr/include/GL3.5 -DLINUX -DOPENGL -I../lapack/\
+	-ftemplate-depth-99
+#  -finline-limit=10000 
+#	-mcpu=pentiumpro -fforce-addr -Wdisabled-optimization  -funroll-loops 
+#   -funroll-all-loops   
+# -dr -dt -df
+#	-fforce-addr \
+#	-fssa -fdce -fschedule-insns2 -fstrict-aliasing -frename-registers \
+#	-freg-struct-return 
+#	-fargument-noalias-global -fargument-noalias \
+#	--param max-gcse-memory=100000000 \
+#	--param max-delay-slot-live-search=100000 \
+#	--param max-pending-list-length=10000 \
+#	-fssa \
+#	-fomit-frame-pointer -fno-enforce-eh-specs -fno-defer-pop \
+#	-fforce-mem -fstrict-aliasing \
+#	-fno-implement-inlines \
+#	-foptimize-sibling-calls \
+#	-frerun-cse-after-loop -fcse-follow-jumps -fexpensive-optimizations \
+#	-fstrength-reduce -frerun-loop-opt -fcse-skip-blocks -fgcse \
+#	  -pedantic \
+# -fno-implicit-templates
+#
+#  -I/usr/local/intel/mkl/INCLUDE
+# -fsyntax-only
+# -fomit-frame-pointer
+# -funroll-loops
+#  
+LINKFLAGS2 = -L/usr/local/lib -L/usr/openwin/lib -L/usr/X11R6/lib -L/usr/lib/GL3.5  -L/usr/freeware/lib32 -L/usr/X11R6/lib -L/usr/local/lib
+
+# SYSLIB2 = libstdc++.
+# SYSLIB2 = -lstdc++ 
+# -lgcc_s
+# SYSLIB2 = -L/usr/lib/lapack -lblas -lstdc++
+
+
diff --git a/Netgen/libsrc/makefile.mach.SUN b/Netgen/libsrc/makefile.mach.SUN
new file mode 100644
index 0000000000..f927ae06f1
--- /dev/null
+++ b/Netgen/libsrc/makefile.mach.SUN
@@ -0,0 +1,16 @@
+#
+# Machine dependent make include file
+# 
+CC=CC
+CPLUSPLUS=$(CC)
+AR=ar
+LINK=$(CC)
+MAKE=make -k
+RM=rm
+RANLIB=ranlib
+#
+CFLAGS2 =
+#
+CPLUSPLUSFLAGS2 =  -fast -O2 -I/usr/openwin/share/include 
+LINKFLAGS2 = -L/usr/openwin/lib 
+
diff --git a/Netgen/libsrc/meshing/Makefile b/Netgen/libsrc/meshing/Makefile
new file mode 100644
index 0000000000..c0f17db986
--- /dev/null
+++ b/Netgen/libsrc/meshing/Makefile
@@ -0,0 +1,16 @@
+src = adfront2.cpp adfront3.cpp geomsearch.cpp global.cpp \
+        meshtool.cpp \
+        netrule2.cpp netrule3.cpp parser2.cpp parser3.cpp ruler2.cpp ruler3.cpp \
+        meshtype.cpp meshclass.cpp improve2.cpp smoothing2.cpp improve3.cpp smoothing3.cpp \
+	improve2gen.cpp meshing2.cpp meshing3.cpp  \
+	localh.cpp delaunay.cpp topology.cpp clusters.cpp \
+	tetrarls.cpp triarls.cpp quadrls.cpp meshfunc.cpp meshfunc2d.cpp \
+	refine.cpp bisect.cpp zrefine.cpp secondorder.cpp hprefinement.cpp \
+	boundarylayer.cpp specials.cpp msghandler.cpp \
+	pyramidrls.cpp pyramid2rls.cpp prism2rls.cpp curvedelems.cpp curvedelems2.cpp
+#
+lib = mesh
+libpath = libsrc/meshing
+#
+include ../makefile.inc
+#
diff --git a/Netgen/libsrc/meshing/adfront2.cpp b/Netgen/libsrc/meshing/adfront2.cpp
new file mode 100644
index 0000000000..e273144501
--- /dev/null
+++ b/Netgen/libsrc/meshing/adfront2.cpp
@@ -0,0 +1,535 @@
+/*
+  Advancing front class for surfaces
+*/
+
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+
+namespace netgen
+{
+
+  /*
+AdFront2::FrontPoint2 :: FrontPoint2 ()
+{
+  globalindex = 0;
+  nlinetopoint = 0;
+  frontnr = INT_MAX-10;    // attention: overflow on calculating  INT_MAX + 1
+  mgi = NULL;
+}
+  */
+
+AdFront2::FrontPoint2 :: FrontPoint2 (const Point3d & ap, PointIndex agi,
+				      MultiPointGeomInfo * amgi)
+{
+  p = ap;
+  globalindex = agi;
+  nlinetopoint = 0;
+  frontnr = INT_MAX-10;
+
+  if (amgi)
+    {
+      mgi = new MultiPointGeomInfo (*amgi);
+      for (int i = 1; i <= mgi->GetNPGI(); i++)
+	if (mgi->GetPGI(i).trignum <= 0)
+	  cout << "Add FrontPoint2, illegal geominfo = " << mgi->GetPGI(i).trignum << endl;
+    }
+  else
+    mgi = NULL;
+}
+
+/*
+AdFront2::FrontPoint2 :: ~FrontPoint2 ()
+{
+//  if (mgi) delete mgi;
+}
+*/
+
+
+AdFront2::FrontLine :: FrontLine ()
+{
+  lineclass = 1;
+}
+
+AdFront2::FrontLine :: FrontLine (const INDEX_2 & al)
+{
+  l = al;
+  lineclass = 1;
+}
+
+
+
+
+
+
+AdFront2 :: AdFront2 (const Box3d & aboundingbox)
+  : boundingbox(aboundingbox), 
+    linesearchtree(boundingbox.PMin(), boundingbox.PMax()),
+    cpointsearchtree(boundingbox.PMin(), boundingbox.PMax())
+{
+  nfl = 0;
+  //  allflines = new INDEX_2_HASHTABLE<int> (100000);
+  allflines = 0;
+
+  minval = 0;
+  starti = 1;
+}
+
+AdFront2 :: ~AdFront2 ()
+{
+  delete allflines;
+}
+
+
+void AdFront2 :: PrintOpenSegments (ostream & ost) const
+{
+ if (nfl > 0)
+    {
+      int i;
+      ost << nfl << " open front segments left:" << endl;
+      for (i = 1; i <= lines.Size(); i++)
+	if (lines.Get(i).Valid())
+	  ost << GetGlobalIndex (lines.Get(i).L().I1()) << "-"
+	      << GetGlobalIndex (lines.Get(i).L().I2()) << endl;
+	    
+    }
+}
+
+
+void AdFront2 :: GetPoints (ARRAY<Point3d> & apoints) const
+{
+  for (int i = 0; i < points.Size(); i++)
+    apoints.Append (points[i].P());
+}
+
+
+
+
+
+INDEX AdFront2 :: AddPoint (const Point3d & p, PointIndex globind, 
+			    MultiPointGeomInfo * mgi)
+{
+  // inserts at empty position or resizes array
+  int pi;
+
+  if (delpointl.Size() != 0)
+    {
+      pi = delpointl.Last();
+      delpointl.DeleteLast ();
+
+      points.Elem(pi) = FrontPoint2 (p, globind, mgi);
+    }
+  else
+    {
+      pi = points.Append (FrontPoint2 (p, globind, mgi));
+    }
+
+  if (mgi)
+    {
+      cpointsearchtree.Insert (p, pi);
+    }
+
+  return pi;
+}
+
+
+INDEX AdFront2 :: AddLine (INDEX pi1, INDEX pi2,
+			   const PointGeomInfo & gi1, const PointGeomInfo & gi2)
+{
+  int minfn;
+  INDEX li;
+
+  FrontPoint2 & p1 = points.Elem(pi1);
+  FrontPoint2 & p2 = points.Elem(pi2);
+
+  nfl++;
+
+  p1.AddLine();
+  p2.AddLine();
+
+  minfn = min2 (p1.FrontNr(), p2.FrontNr());
+  p1.DecFrontNr (minfn+1);
+  p2.DecFrontNr (minfn+1);
+
+  if (dellinel.Size() != 0)
+    {
+      li = dellinel.Last();
+      dellinel.DeleteLast ();
+
+      lines.Elem(li) = FrontLine (INDEX_2(pi1, pi2));
+    }
+  else
+    {
+      li = lines.Append(FrontLine (INDEX_2(pi1, pi2)));
+    }
+
+  
+  if (!gi1.trignum || !gi2.trignum)
+    {
+      cout << "ERROR: in AdFront::AddLine, illegal geominfo" << endl;
+    }
+  
+  lines.Elem(li).SetGeomInfo (gi1, gi2);
+
+  Box3d lbox;
+  lbox.SetPoint(p1.P());
+  lbox.AddPoint(p2.P());
+
+  linesearchtree.Insert (lbox.PMin(), lbox.PMax(), li);
+
+  /*
+  (*testout) << "add front line: " << p1.P() << " - " << p2.P()
+  	     << " Dist = " << Dist (p1.P(), p2.P()) << endl;
+  */
+
+  if (allflines)
+    {
+      if (allflines->Used (INDEX_2 (GetGlobalIndex (pi1), 
+				    GetGlobalIndex (pi2))))
+	{
+	  cerr << "ERROR Adfront2::AddLine: line exists" << endl;
+	  (*testout) << "ERROR Adfront2::AddLine: line exists" << endl;
+	}
+
+      allflines->Set (INDEX_2 (GetGlobalIndex (pi1), 
+			       GetGlobalIndex (pi2)), 1);
+    }
+
+  return li;
+}
+
+
+void AdFront2 :: DeleteLine (INDEX li)
+{
+  int i;
+  INDEX pi;
+
+  nfl--;
+
+  for (i = 1; i <= 2; i++)
+    {
+      pi = lines.Get(li).L().I(i);
+      points.Elem(pi).RemoveLine();
+
+      if (!points.Get(pi).Valid())
+	{
+	  delpointl.Append (pi);
+	  if (points.Elem(pi).mgi)
+	    {
+	      cpointsearchtree.DeleteElement (pi);
+	      delete points.Elem(pi).mgi;
+	      points.Elem(pi).mgi = NULL;
+	    }
+	}
+    }
+
+  if (allflines)
+    {
+      allflines->Set (INDEX_2 (GetGlobalIndex (lines.Get(li).L().I1()),
+			       GetGlobalIndex (lines.Get(li).L().I2())), 2);
+    }
+
+  lines.Elem(li).Invalidate();
+  linesearchtree.DeleteElement (li);
+
+
+
+  dellinel.Append (li);
+}
+
+
+int AdFront2 :: ExistsLine (int pi1, int pi2)
+{
+  if (!allflines)
+    return 0;
+  if (allflines->Used (INDEX_2(pi1, pi2)))
+    return allflines->Get (INDEX_2 (pi1, pi2));
+  else
+    return 0;
+}
+
+
+
+void AdFront2 :: IncrementClass (INDEX li)
+{
+  lines.Elem(li).IncrementClass();
+}
+
+
+void AdFront2 :: ResetClass (INDEX li)
+{
+  lines.Elem(li).ResetClass();
+}
+
+
+
+int AdFront2 :: SelectBaseLine (Point3d & p1, Point3d & p2, 
+				const PointGeomInfo *& geominfo1,
+				const PointGeomInfo *& geominfo2)
+{
+  int i, hi;
+
+  /*  
+      int minval;
+      int baselineindex;
+      minval = INT_MAX;
+  for (i = 1; i <= lines.Size(); i++)
+    if (lines.Get(i).Valid())
+      {
+	hi = lines.Get(i).LineClass() +
+	  points.Get(lines.Get(i).L().I1()).FrontNr() +
+	  points.Get(lines.Get(i).L().I2()).FrontNr();
+	
+	if (hi < minval)
+	  {
+	    minval = hi;
+	    baselineindex = i;
+	  }
+      }
+  */
+
+  /*
+  static int minval = 0;
+  static int starti = 1;
+  */
+  int baselineindex = 0; 
+
+  for (i = starti; i <= lines.Size(); i++)
+    {
+      if (lines.Get(i).Valid())
+	//      const ILINE * lp = &lines.Get(i).l;
+	//      if (lp->I1() >= 0)
+	{
+	  hi = lines.Get(i).LineClass() +
+	    points.Get(lines.Get(i).L().I1()).FrontNr() +
+	    points.Get(lines.Get(i).L().I2()).FrontNr();
+	  
+	  if (hi <= minval)
+	    {
+	      minval = hi;
+	      baselineindex = i;
+	      break;
+	    }
+	}
+    }
+  
+  if (!baselineindex)
+    {
+      (*testout) << "nfl = " << nfl << " tot l = " << lines.Size() << endl;
+      minval = INT_MAX;
+      for (i = 1; i <= lines.Size(); i++)
+	if (lines.Get(i).Valid())
+	  {
+	    hi = lines.Get(i).LineClass() +
+	      points.Get(lines.Get(i).L().I1()).FrontNr() +
+	      points.Get(lines.Get(i).L().I2()).FrontNr();
+	    
+	    if (hi < minval)
+	      {
+		minval = hi;
+		baselineindex = i;
+	      }
+	  }
+    }
+  starti = baselineindex+1;
+
+
+
+  p1 = points.Get(lines.Get(baselineindex).L().I1()).P();
+  p2 = points.Get(lines.Get(baselineindex).L().I2()).P();
+  geominfo1 = &lines.Get(baselineindex).GetGeomInfo(1);
+  geominfo2 = &lines.Get(baselineindex).GetGeomInfo(2);
+  return baselineindex;
+}
+
+
+
+
+int AdFront2 :: GetLocals (int baselineindex,
+			   ARRAY<Point3d> & locpoints,
+			   ARRAY<MultiPointGeomInfo> & pgeominfo,
+			   ARRAY<INDEX_2> & loclines,   // local index
+			   ARRAY<INDEX> & pindex,
+			   ARRAY<INDEX> & lindex,
+			   double xh)
+{
+  int i, j, ii;
+  int pstind;
+  int pi;
+  Point3d midp, p0;
+
+  pstind = lines.Get(baselineindex).L().I1();
+  p0 = points.Get(pstind).P();
+
+  loclines.Append(lines.Get(baselineindex).L());
+  lindex.Append(baselineindex);
+
+  static ARRAY<int> nearlines;
+
+  nearlines.SetSize(0);
+  double dist = xh;
+  linesearchtree.GetIntersecting (p0 - Vec3d(dist, dist, dist),
+				  p0 + Vec3d(dist, dist, dist),
+				  nearlines);
+
+  //  for (i = 1; i <= lines.Size(); i++)
+  for (ii = 1; ii <= nearlines.Size(); ii++)
+    {
+      i = nearlines.Get(ii);
+
+      if (lines.Get(i).Valid() && i != baselineindex)
+	{
+	  const Point3d & p1 = points.Get(lines.Get(i).L().I1()).P();
+	  const Point3d & p2 = points.Get(lines.Get(i).L().I2()).P();
+
+	  midp = Center (p1, p2);
+	  
+	  if (Dist (midp, p0) <= xh + 0.5 * Dist (p1, p2))
+	    {
+	      loclines.Append(lines.Get(i).L());
+	      lindex.Append(i);
+	    }
+	}
+    }
+
+  static ARRAY<int> invpindex;
+
+  invpindex.SetSize (points.Size());
+  for (i = 1; i <= loclines.Size(); i++)
+    for (j = 1; j <= 2; j++)
+      invpindex.Elem(loclines.Get(i).I(j)) = 0;
+
+  for (i = 1; i <= loclines.Size(); i++)
+    {
+      for (j = 1; j <= 2; j++)
+	{
+	  pi = loclines.Get(i).I(j);
+	  if (invpindex.Get(pi) == 0)
+	    {
+	      pindex.Append (pi);
+	      invpindex.Elem(pi) = pindex.Size();
+	      loclines.Elem(i).I(j) = locpoints.Append (points.Get(pi).P());
+	    }
+	  else
+	    loclines.Elem(i).I(j) = invpindex.Get(pi);
+	}
+    }
+
+  pgeominfo.SetSize (locpoints.Size());
+  for (i = 1; i <= pgeominfo.Size(); i++)
+    pgeominfo.Elem(i).Init();
+
+
+  for (i = 1; i <= loclines.Size(); i++)
+    for (j = 1; j <= 2; j++)
+      {
+	int lpi = loclines.Get(i).I(j);
+	
+	const PointGeomInfo & gi = 
+	  lines.Get(lindex.Get(i)).GetGeomInfo (j);
+	pgeominfo.Elem(lpi).AddPointGeomInfo (gi);
+	
+	/*
+	if (pgeominfo.Elem(lpi).cnt == MULTIPOINTGEOMINFO_MAX)
+	  break;
+
+	const PointGeomInfo & gi = 
+	  lines.Get(lindex.Get(i)).GetGeomInfo (j);
+	
+	PointGeomInfo * pgi = pgeominfo.Elem(lpi).mgi;
+
+	int found = 0;
+	for (k = 0; k < pgeominfo.Elem(lpi).cnt; k++)
+	  if (pgi[k].trignum == gi.trignum)
+	    found = 1;
+
+	if (!found)
+	  {
+	    pgi[pgeominfo.Elem(lpi).cnt] = gi;
+	    pgeominfo.Elem(lpi).cnt++;
+	  }
+	*/
+      }
+
+  for (i = 1; i <= locpoints.Size(); i++)
+    {
+      int pi = pindex.Get(i);
+
+
+      
+      if (points.Get(pi).mgi)
+	for (j = 1; j <= points.Get(pi).mgi->GetNPGI(); j++)
+	  pgeominfo.Elem(i).AddPointGeomInfo (points.Get(pi).mgi->GetPGI(j));
+/*
+	{
+	  for (j = 0; j < points.Get(pi).mgi->cnt; j++)
+	    {
+	      pgeominfo.Elem(i).mgi[pgeominfo.Elem(i).cnt] = 
+		points.Get(pi).mgi->mgi[j];
+	      pgeominfo.Elem(i).cnt++;
+	    }
+	}
+*/
+    }
+	
+  
+
+  /*
+  for (i = 1; i <= points.Size(); i++)
+    if (points.Get(i).Valid() && 
+	Dist (points.Get(i).P(), p0) <= xh &&
+	invpindex.Get(i) == 0)
+      {
+	invpindex.Elem(i) =
+	  locpoints.Append (points.Get(pi).P());
+      }
+  */
+
+
+  if (loclines.Size() == 1)
+    {
+      cout << "loclines.Size = 1" << endl;
+      (*testout) << "loclines.size = 1" << endl
+		 << " h = " << xh << endl
+		 << " nearline.size = " << nearlines.Size() << endl
+		 << " p0 = " << p0 << endl;
+    }
+
+
+
+  return lines.Get(baselineindex).LineClass();
+}
+
+
+
+void AdFront2 :: SetStartFront ()
+{
+  INDEX i;
+  int j;
+
+  for (i = 1; i <= lines.Size(); i++)
+    if (lines.Get(i).Valid())
+      for (j = 1; j <= 2; j++)
+        points.Elem(lines.Get(i).L().I(j)).DecFrontNr(0);
+}
+
+
+
+
+void AdFront2 :: Print (ostream & ost) const
+{
+  INDEX i;
+
+  ost << points.Size() << " Points: " << endl;
+  for (i = 1; i <= points.Size(); i++)
+    if (points.Get(i).Valid())
+      ost << i << "  " << points.Get(i).P() << endl;
+
+  ost << nfl << " Lines: " << endl;
+  for (i = 1; i <= lines.Size(); i++)
+    if (lines.Get(i).Valid())
+      ost << lines.Get(i).L().I1() << " - " << lines.Get(i).L().I2() << endl;
+
+  ost << flush;
+}
+}
diff --git a/Netgen/libsrc/meshing/adfront2.hpp b/Netgen/libsrc/meshing/adfront2.hpp
new file mode 100644
index 0000000000..b7a45e34e8
--- /dev/null
+++ b/Netgen/libsrc/meshing/adfront2.hpp
@@ -0,0 +1,336 @@
+#ifndef FILE_ADFRONT2
+#define FILE_ADFRONT2
+
+/**************************************************************************/
+/* File:   adfront2.hh                                                    */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Okt. 95                                                    */
+/**************************************************************************/
+
+/*
+    Advancing front class for surfaces
+*/
+
+
+/*
+#define FRONTLINE_GEOMINFO_SIZE 8
+#define FRONTPOINT_GEOMINFO_SIZE 4
+*/
+
+///
+class AdFront2
+{
+
+  ///
+  class FrontPoint2
+  {
+    /// coordinates
+    Point3d p;            
+    /// global node index
+    PointIndex globalindex;   
+    /// number of front lines connected to point 
+    int nlinetopoint;    
+    /// distance to original boundary
+    int frontnr;          
+    //   char geominfo[FRONTLINE_GEOMINFO_SIZE];    
+  public:
+    ///
+    MultiPointGeomInfo * mgi;
+
+    ///
+    FrontPoint2 ()
+    {
+      globalindex = -1;
+      nlinetopoint = 0;
+      frontnr = INT_MAX-10;    // attention: overflow on calculating  INT_MAX + 1
+      mgi = NULL;
+    }
+
+    ///
+    FrontPoint2 (const Point3d & ap, PointIndex agi,
+		 MultiPointGeomInfo * amgi);
+    ///
+    ~FrontPoint2 () { ; }
+
+    ///
+    const Point3d & P () const { return p; }
+    ///
+    PointIndex GlobalIndex () const { return globalindex; }
+
+    ///
+    void AddLine () { nlinetopoint++; }
+    ///
+    void RemoveLine ()
+    {
+      nlinetopoint--;
+      if (nlinetopoint == 0)
+	nlinetopoint = -1;
+    }
+
+    ///
+    bool Valid () const
+    { return nlinetopoint >= 0; }
+
+    ///
+    void DecFrontNr (int afrontnr)
+    {
+      if (frontnr > afrontnr) frontnr = afrontnr;
+    }
+    
+    ///
+    int FrontNr () const { return frontnr; }
+  };
+
+  
+  ///
+  class FrontLine
+  {
+  private:
+    /// Point Indizes
+    INDEX_2 l;            
+    /// quality class 
+    int lineclass;      
+    /// geometry specific data
+    //    char geominfo[FRONTLINE_GEOMINFO_SIZE];
+    PointGeomInfo geominfo[2];
+  public:
+
+    FrontLine ();
+    ///
+    FrontLine (const INDEX_2 & al);
+
+    ///
+    const INDEX_2 & L () const
+    {
+      return l;
+    }
+
+    ///
+    int LineClass() const
+    {
+      return lineclass;
+    }
+
+    ///
+    void IncrementClass ()
+    {
+      lineclass++;
+    }
+    ///
+    void ResetClass ()
+    {
+      lineclass = 1;
+    }
+
+    ///
+    bool Valid () const
+    {
+      return l.I1() != -1;
+    }
+    ///
+    void Invalidate ()
+    {
+      l.I1() = -1;
+      l.I2() = -1;
+      lineclass = 1000;
+    }
+
+    void SetGeomInfo (const PointGeomInfo & gi1, const PointGeomInfo & gi2)
+      {
+	geominfo[0] = gi1;
+	geominfo[1] = gi2;
+      }
+
+    const PointGeomInfo * GetGeomInfo () const
+    { return geominfo; }
+    
+    const PointGeomInfo & GetGeomInfo (int endp) const
+    { return geominfo[endp-1]; }
+
+    friend class AdFront2;
+  };
+
+
+
+  ///
+  ARRAY<FrontPoint2> points;  /// front points
+  ARRAY<FrontLine> lines;     /// front lines
+
+  Box3d boundingbox;
+  Box3dTree linesearchtree;       /// search tree for lines
+  Point3dTree cpointsearchtree;   /// search tree for cone points
+
+  ARRAY<INDEX> delpointl;     /// list of deleted front points
+  ARRAY<INDEX> dellinel;      /// list of deleted front lines
+
+  INDEX nfl;                  /// number of front lines;
+  INDEX_2_HASHTABLE<int> * allflines; /// all front lines ever have been
+
+
+  int minval;
+  int starti;
+
+public:
+  ///
+  //  AdFront2 ();
+  AdFront2 (const Box3d & aboundingbox);
+  ///
+  ~AdFront2 ();
+
+  ///
+  void GetPoints (ARRAY<Point3d> & apoints) const;
+  ///
+  void Print (ostream & ost) const;
+
+  ///
+  bool Empty () const
+  {
+    return nfl == 0;
+  }
+  ///
+  int GetNFL () const { return nfl; }
+  ///
+  int SelectBaseLine (Point3d & p1, Point3d & p2, 
+		      const PointGeomInfo *& geominfo1,
+		      const PointGeomInfo *& geominfo2);
+
+  ///
+  int GetLocals (int baseline, 
+		 ARRAY<Point3d> & locpoints,
+		 ARRAY<MultiPointGeomInfo> & pgeominfo,
+                 ARRAY<INDEX_2> & loclines,   // local index
+                 ARRAY<INDEX> & pindex,
+                 ARRAY<INDEX> & lindex,
+                 double xh);
+
+  ///
+  void DeleteLine (INDEX li);
+  ///
+  INDEX AddPoint (const Point3d & p, PointIndex globind, 
+		  MultiPointGeomInfo * mgi = NULL);
+  ///
+  INDEX AddLine (INDEX pi1, INDEX pi2, 
+		 const PointGeomInfo & gi1, const PointGeomInfo & gi2);
+  ///
+  int ExistsLine (int gpi1, int gpi2);
+  ///
+  void IncrementClass (INDEX li);
+  ///
+  void ResetClass (INDEX li);
+
+  ///
+  const PointGeomInfo & GetLineGeomInfo (int li, int lend) const
+    { return lines.Get(li).GetGeomInfo (lend); }
+  ///
+
+  PointIndex GetGlobalIndex (int pi) const
+  {
+    return points.Get(pi).GlobalIndex();
+  }
+  ///
+  void SetStartFront ();
+  ///
+  void PrintOpenSegments (ostream & ost) const;
+};
+
+
+
+
+
+
+/*
+inline int AdFront2::FrontPoint2 :: Valid () const
+{
+  return nlinetopoint >= 0;
+}
+*/
+/*
+inline const Point3d & AdFront2::FrontPoint2 :: P () const
+{
+  return p;
+}
+
+inline PointIndex AdFront2::FrontPoint2 :: GlobalIndex () const
+{
+  return globalindex;
+}
+
+inline void AdFront2::FrontPoint2 :: AddLine ()
+{
+  nlinetopoint++;
+}
+
+inline void AdFront2::FrontPoint2 :: RemoveLine ()
+{
+  nlinetopoint--;
+  if (nlinetopoint == 0)
+    nlinetopoint = -1;
+}
+
+inline int AdFront2::FrontPoint2 :: FrontNr () const
+{
+  return frontnr;
+}
+
+inline void AdFront2::FrontPoint2 :: DecFrontNr (int afrontnr)
+{
+  if (frontnr > afrontnr) frontnr = afrontnr;
+}
+*/
+
+
+
+
+
+
+
+
+/*
+inline int AdFront2::FrontLine :: Valid () const
+{
+  return l.I1() != 0;
+}
+
+inline void AdFront2::FrontLine :: Invalidate ()
+{
+  l.I1() = 0;
+  l.I2() = 0;
+  lineclass = 1000;
+}
+
+inline const INDEX_2 & AdFront2::FrontLine :: L () const
+{
+  return l;
+}
+
+inline int AdFront2::FrontLine :: LineClass () const
+{
+  return lineclass;
+}
+
+
+inline void AdFront2::FrontLine :: IncrementClass ()
+{
+  lineclass++;
+}
+
+inline void AdFront2::FrontLine :: ResetClass ()
+{
+  lineclass = 1;
+}
+
+
+inline int AdFront2 :: Empty () const
+{
+  return nfl == 0;
+}
+
+inline INDEX AdFront2 :: GetGlobalIndex (INDEX pi) const
+{
+  return points.Get(pi).GlobalIndex();
+}
+*/
+#endif
+
+
+
diff --git a/Netgen/libsrc/meshing/adfront3.cpp b/Netgen/libsrc/meshing/adfront3.cpp
new file mode 100644
index 0000000000..657d0bc12b
--- /dev/null
+++ b/Netgen/libsrc/meshing/adfront3.cpp
@@ -0,0 +1,895 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+
+/* ********************** FrontPoint ********************** */
+
+namespace netgen
+{
+
+FrontPoint3 :: FrontPoint3 () 
+{ 
+  globalindex = 0;
+  nfacetopoint = 0; 
+  frontnr = 1000; 
+  cluster = 0;
+}
+
+
+FrontPoint3 :: FrontPoint3 (const Point3d & ap, PointIndex agi)
+{ 
+  p = ap; 
+  globalindex = agi;
+  nfacetopoint = 0; 
+  frontnr = 1000; 
+  cluster = 0;
+}
+
+
+
+/* ********************** FrontFace ********************** */
+
+FrontFace :: FrontFace () 
+{ 
+  qualclass = 1; 
+  oldfront = 0; 
+  hashvalue = 0;
+  cluster = 0;
+}
+
+FrontFace :: FrontFace (const Element2d & af)
+{ 
+  f = af; 
+  oldfront = 0; 
+  qualclass = 1; 
+  hashvalue = 0;
+}
+
+void FrontFace :: Invalidate ()
+{ 
+  f.Delete();  // PNum(1) = 0; 
+  oldfront = 0; 
+  qualclass = 1000; 
+}
+
+
+
+
+/* ********************** AddFront ********************** */
+ 
+
+AdFront3 :: AdFront3 ()
+{
+  nff = 0;
+  nff4 = 0;
+  vol = 0;
+
+  hashon = 1;
+  hashcreated = 0;
+  if (hashon) 
+    {
+      hashtable.Init(&points, &faces);
+    }
+
+  facetree = NULL;
+  connectedpairs = NULL;
+
+  rebuildcounter = -1;
+  lasti = 0;
+  minval = -1;
+}
+
+
+AdFront3 :: ~AdFront3 ()
+{
+  if (facetree)
+    delete facetree;
+  if (connectedpairs)
+    delete connectedpairs;
+}
+
+void AdFront3 :: GetPoints (ARRAY<Point3d> & apoints) const
+{
+  for (PointIndex pi = PointIndex::BASE; 
+       pi < points.Size()+PointIndex::BASE; pi++)
+    
+    apoints.Append (points[pi].P());
+}
+
+
+INDEX AdFront3 :: AddPoint (const Point3d & p, PointIndex globind)
+{
+  if (delpointl.Size())
+    {
+      PointIndex pi = delpointl.Last();
+      delpointl.DeleteLast ();
+      
+      points[pi] = FrontPoint3 (p, globind);
+      return pi;
+    }
+  else
+    {
+      points.Append (FrontPoint3 (p, globind));
+      return points.Size()-1+PointIndex::BASE;
+    }
+}
+
+
+INDEX AdFront3 :: AddFace (const Element2d & aface)
+{
+  int i, minfn;
+
+  nff++;
+
+  for (i = 0; i < aface.GetNP(); i++)
+    points[aface[i]].AddFace();
+
+  const Point3d & p1 = points[aface[0]].P();
+  const Point3d & p2 = points[aface[1]].P();
+  const Point3d & p3 = points[aface[2]].P();
+
+  vol += 1.0/6.0 * (p1.X() + p2.X() + p3.X()) *
+    ( (p2.Y() - p1.Y()) * (p3.Z() - p1.Z()) -
+      (p2.Z() - p1.Z()) * (p3.Y() - p1.Y()) );
+
+  if (aface.GetNP() == 4)
+    {
+      nff4++;
+      const Point3d & p4 = points[aface[3]].P();      
+      vol += 1.0/6.0 * (p1.X() + p3.X() + p4.X()) *
+	( (p3.Y() - p1.Y()) * (p4.Z() - p1.Z()) -
+	  (p3.Z() - p1.Z()) * (p4.Y() - p1.Y()) );
+    }
+
+
+  minfn = 1000;
+  for (i = 0; i < aface.GetNP(); i++)
+    {
+      int fpn = points[aface[i]].FrontNr();
+      if (i == 0 || fpn < minfn)
+	minfn = fpn;
+    }
+
+
+  int cluster = 0;
+  for (i = 1; i <= aface.GetNP(); i++)
+    {
+      if (points[aface.PNum(i)].cluster)
+	cluster = points[aface.PNum(i)].cluster;
+    }
+  for (i = 1; i <= aface.GetNP(); i++)
+    points[aface.PNum(i)].cluster = cluster;
+
+
+  for (i = 1; i <= aface.GetNP(); i++)
+    points[aface.PNum(i)].DecFrontNr (minfn+1);
+
+  int nfn = faces.Append(FrontFace (aface));
+  faces.Elem(nfn).cluster = cluster;
+
+  if (hashon && hashcreated) 
+    hashtable.AddElem(aface, nfn);
+
+  return nfn;
+}
+
+
+
+void AdFront3 :: DeleteFace (INDEX fi)
+{
+  int i;
+  INDEX pi;
+
+  nff--;
+
+  for (i = 1; i <= faces.Get(fi).Face().GetNP(); i++)
+    {
+      pi = faces.Get(fi).Face().PNum(i);
+      points.Elem(pi).RemoveFace();
+      if (!points.Elem(pi).Valid())
+	delpointl.Append (pi);
+    }
+
+  const Element2d & face = faces.Get(fi).Face();
+  const Point3d & p1 = points.Get(face.PNum(1)).P();
+  const Point3d & p2 = points.Get(face.PNum(2)).P();
+  const Point3d & p3 = points.Get(face.PNum(3)).P();
+
+  vol -= 1.0/6.0 * (p1.X() + p2.X() + p3.X()) *
+    ( (p2.Y() - p1.Y()) * (p3.Z() - p1.Z()) -
+      (p2.Z() - p1.Z()) * (p3.Y() - p1.Y()) );
+
+  if (face.GetNP() == 4)
+    {
+      const Point3d & p4 = points.Get(face.PNum(4)).P();      
+      vol -= 1.0/6.0 * (p1.X() + p3.X() + p4.X()) *
+	( (p3.Y() - p1.Y()) * (p4.Z() - p1.Z()) -
+	  (p3.Z() - p1.Z()) * (p4.Y() - p1.Y()) );
+
+      nff4--;
+    }
+
+
+  faces.Elem(fi).Invalidate();
+}
+
+
+INDEX AdFront3 :: AddConnectedPair (const INDEX_2 & apair)
+{
+  if (!connectedpairs)
+    connectedpairs = new TABLE<int> (GetNP());
+
+  //  (*testout) << "addconnectedpair " << apair << endl;
+  connectedpairs->Add1 (apair.I1(), apair.I2());
+  connectedpairs->Add1 (apair.I2(), apair.I1());
+
+  return 0;
+}
+
+
+
+void AdFront3 :: IncrementClass (INDEX fi)
+{
+  faces.Elem(fi).IncrementQualClass();
+}
+
+
+void AdFront3 :: ResetClass (INDEX fi)
+{
+  faces.Elem(fi).ResetQualClass();
+}
+
+
+
+void AdFront3 :: CreateTrees ()
+{
+  int i, j;
+  PointIndex pi;
+  Point3d pmin, pmax;
+
+  for (pi = PointIndex::BASE; 
+       pi < GetNP()+PointIndex::BASE; pi++)
+    {
+      const Point3d & p = GetPoint(pi);
+      if (pi == PointIndex::BASE)
+	{
+	  pmin = p;
+	  pmax = p;
+	}
+      else
+	{
+	  pmin.SetToMin (p);
+	  pmax.SetToMax (p);
+	}
+    }
+
+  pmax = pmax + 0.5 * (pmax - pmin);
+  pmin = pmin + 0.5 * (pmin - pmax);
+  if (facetree)
+    delete facetree;
+
+  facetree = new Box3dTree (pmin, pmax);
+  
+  for (i = 1; i <= GetNF(); i++)
+    {
+      const Element2d & el = GetFace(i);
+      pmin = GetPoint (el[0]);
+      pmax = pmin;
+      for (j = 1; j < 3; j++)
+	{
+	  const Point3d & p = GetPoint (el[j]);
+	  pmin.SetToMin (p);
+	  pmax.SetToMax (p);
+	}
+      pmax = pmax + 0.01 * (pmax - pmin);
+      pmin = pmin + 0.01 * (pmin - pmax);
+      //      (*testout) << "insert " << i << ": " << pmin << " - " << pmax << "\n";
+      facetree -> Insert (pmin, pmax, i);
+    }
+}
+
+
+void AdFront3 :: GetIntersectingFaces (const Point3d & pmin, const Point3d & pmax, 
+				       ARRAY<int> & ifaces) const
+{
+  facetree -> GetIntersecting (pmin, pmax, ifaces);
+}
+
+void AdFront3 :: GetFaceBoundingBox (int i, Box3d & box) const
+{
+  const FrontFace & face = faces.Get(i);
+  box.SetPoint (points[face.f[0]].p);
+  box.AddPoint (points[face.f[1]].p);
+  box.AddPoint (points[face.f[2]].p);
+}
+
+void AdFront3 :: RebuildInternalTables ()
+{
+  int i, j, hi;
+
+  hi = 0;
+  for (i = 1; i <= faces.Size(); i++)
+    if (faces.Get(i).Valid())
+      {
+	hi++;
+	faces.Elem(hi) = faces.Get(i);
+      }
+  
+  faces.SetSize (nff);
+
+  int np = points.Size();
+
+
+  for (i = 1; i <= np; i++)
+    points.Elem(i).cluster = i;
+
+  int change;
+  do
+    {
+      change = 0;
+      for (i = 1; i <= faces.Size(); i++)
+	{
+	  const Element2d & el = faces.Get(i).Face();
+
+	  int mini = points.Get(el.PNum(1)).cluster;
+	  int maxi = mini;
+	  
+	  for (j = 2; j <= 3; j++)
+	    {
+	      int ci = points.Get(el.PNum(j)).cluster;
+	      if (ci < mini) mini = ci;
+	      if (ci > maxi) maxi = ci;
+	    }
+
+	  if (mini < maxi)
+	    {
+	      change = 1;
+	      for (j = 1; j <= 3; j++)
+		points.Elem(el.PNum(j)).cluster = mini;
+	    }
+	}
+    }
+  while (change);
+
+  BitArray usecl(np);
+  usecl.Clear();
+  for (i = 1; i <= faces.Size(); i++)
+    {
+      usecl.Set (points.Get(faces.Get(i).Face().PNum(1)).cluster);
+      faces.Elem(i).cluster =
+	points.Get(faces.Get(i).Face().PNum(1)).cluster;
+    }
+  int cntcl = 0;
+  for (i = 1; i <= np; i++)
+    if (usecl.Test(i))
+      cntcl++;
+
+  ARRAY<double> clvol (np);
+  for (i = 1; i <= np; i++)
+    clvol.Elem(i) = 0;
+
+  for (i = 1; i <= faces.Size(); i++)
+    {
+      const Element2d & face = faces.Get(i).Face();
+
+      const Point3d & p1 = points.Get(face.PNum(1)).P();      
+      const Point3d & p2 = points.Get(face.PNum(2)).P();      
+      const Point3d & p3 = points.Get(face.PNum(3)).P();      
+
+      
+      double vi = 1.0/6.0 * (p1.X() + p2.X() + p3.X()) *
+	( (p2.Y() - p1.Y()) * (p3.Z() - p1.Z()) -
+	  (p2.Z() - p1.Z()) * (p3.Y() - p1.Y()) );
+      
+      if (face.GetNP() == 4)
+	{
+	  const Point3d & p4 = points.Get(face.PNum(4)).P();      
+	  vi += 1.0/6.0 * (p1.X() + p3.X() + p4.X()) *
+	    ( (p3.Y() - p1.Y()) * (p4.Z() - p1.Z()) -
+	      (p3.Z() - p1.Z()) * (p4.Y() - p1.Y()) );
+	}
+     
+      clvol.Elem (faces.Get(i).cluster) += vi;
+    }
+
+
+  int negvol = 0;
+  for (i = 1; i <= clvol.Size(); i++)
+    {
+      if (clvol.Elem(i) < 0)
+	{
+	  negvol = 1;
+	}
+    }
+
+  if (negvol)
+    {
+      for (i = 1; i <= faces.Size(); i++)
+	faces.Elem(i).cluster = 1;
+      for (i = 1; i <= points.Size(); i++)
+	points.Elem(i).cluster = 1;
+    }
+
+  if (hashon) 
+    hashtable.Create();
+}
+
+
+
+int AdFront3 :: SelectBaseElement ()
+{
+  int i, hi, fstind;
+
+  /*
+  static int minval = -1;
+  static int lasti = 0;
+  static int counter = 0;
+  */
+  if (rebuildcounter <= 0)
+    {
+      RebuildInternalTables();
+      rebuildcounter = nff / 10 + 1;
+      
+      lasti = 0;
+    }
+  rebuildcounter--;
+
+  /*
+  if (faces.Size() > 2 * nff)
+    {
+      // compress facelist
+
+      RebuildInternalTables ();
+      lasti = 0;
+    }
+    */
+  
+  fstind = 0;
+
+  for (i = lasti+1; i <= faces.Size() && !fstind; i++)
+    if (faces.Elem(i).Valid())
+      {
+	hi = faces.Get(i).QualClass() +
+	  points.Get(faces.Get(i).Face().PNum(1)).FrontNr() +
+	  points.Get(faces.Get(i).Face().PNum(2)).FrontNr() +
+	  points.Get(faces.Get(i).Face().PNum(3)).FrontNr();
+	
+	if (hi <= minval)
+	  {
+	    minval = hi;
+	    fstind = i;
+	    lasti = fstind;
+	  }
+      }
+  
+  if (!fstind)
+    {
+      minval = INT_MAX;
+      for (i = 1; i <= faces.Size(); i++)
+	if (faces.Elem(i).Valid())
+	  {
+	    hi = faces.Get(i).QualClass() +
+	      points.Get(faces.Get(i).Face().PNum(1)).FrontNr() +
+	      points.Get(faces.Get(i).Face().PNum(2)).FrontNr() +
+	      points.Get(faces.Get(i).Face().PNum(3)).FrontNr();
+	    
+	    if (hi <= minval)
+	      {
+		minval = hi;
+		fstind = i;
+		lasti = 0;
+	      }
+	  }
+    }
+
+
+  return fstind;
+}
+
+
+
+int AdFront3 :: GetLocals (int fstind,
+			   ARRAY<Point3d> & locpoints,
+			   ARRAY<Element2d> & locfaces,   // local index
+			   ARRAY<PointIndex> & pindex,
+			   ARRAY<INDEX> & findex,
+			   INDEX_2_HASHTABLE<int> & getconnectedpairs,
+			   float xh,
+			   float relh,
+			   INDEX& facesplit)
+{
+  if (hashon && faces.Size() < 500) { hashon=0; }
+  if (hashon && !hashcreated) 
+    {
+      hashtable.Create(); hashcreated=1;
+    }
+
+  INDEX i, j;
+  INDEX pstind;
+  INDEX pi;
+  Point3d midp, p0;
+  static ARRAY<int> invpindex;
+  
+  static ARRAY<Element2d> locfaces2;           //all local faces in radius xh
+  static ARRAY<int> locfaces3;           // all faces in outer radius relh
+  static ARRAY<INDEX> findex2;
+
+  locfaces2.SetSize(0);
+  locfaces3.SetSize(0);
+  findex2.SetSize(0);
+
+  int cluster = faces.Get(fstind).cluster;
+
+  pstind = faces.Get(fstind).Face().PNum(1);
+  p0 = points.Get(pstind).P();
+  
+  locfaces2.Append(faces.Get(fstind).Face());
+  findex2.Append(fstind);
+
+
+  Box3d b1 (p0 - Vec3d(xh, xh, xh), p0 + Vec3d (xh, xh, xh));
+
+  if (hashon)
+    {
+      hashtable.GetLocals(locfaces2, findex2, fstind, p0, xh);
+    }
+  else
+    {
+      for (i = 1; i <= faces.Size(); i++)
+	{
+	  const Element2d & face = faces.Get(i).Face();
+	  if (faces.Get(i).cluster == cluster && faces.Get(i).Valid() && i != fstind)
+	    {
+	      const Point3d & p1 = points.Get(face.PNum(1)).P();
+	      const Point3d & p2 = points.Get(face.PNum(2)).P();
+	      const Point3d & p3 = points.Get(face.PNum(3)).P();
+	      
+	      Box3d b2;
+	      b2.SetPoint (p1);
+	      b2.AddPoint (p2);
+	      b2.AddPoint (p3);
+
+	      /*
+	      midp = Center (p1, p2, p3);
+	      
+	      if (Dist2 (midp, p0) <= xh*xh)
+		{
+		  locfaces2.Append(faces.Get(i).Face());
+		  findex2.Append(i);
+		}
+		*/
+	      if (b1.Intersect (b2))
+		{
+		  locfaces2.Append(faces.Get(i).Face());
+		  findex2.Append(i);
+		}
+	    }
+	}
+    }
+
+  //local faces for inner radius:
+  for (i = 1; i <= locfaces2.Size(); i++)
+    {
+      const Element2d & face = locfaces2.Get(i);
+      const Point3d & p1 = points.Get(face.PNum(1)).P();
+      const Point3d & p2 = points.Get(face.PNum(2)).P();
+      const Point3d & p3 = points.Get(face.PNum(3)).P();
+
+      midp = Center (p1, p2, p3);
+
+      if (Dist2 (midp, p0) <= relh * relh || i == 1)
+	{
+          locfaces.Append(locfaces2.Get(i));
+	  findex.Append(findex2.Get(i));
+	}
+      else
+	locfaces3.Append (i);
+    }
+  
+  facesplit=locfaces.Size();
+  
+  
+  //local faces for outer radius:
+  for (i = 1; i <= locfaces3.Size(); i++)
+    {
+      locfaces.Append (locfaces2.Get(locfaces3.Get(i)));
+      findex.Append (findex2.Get(locfaces3.Get(i)));
+    }
+
+
+  invpindex.SetSize (points.Size());
+  for (i = 1; i <= locfaces.Size(); i++)
+    for (j = 1; j <= locfaces.Get(i).GetNP(); j++)
+      {
+	pi = locfaces.Get(i).PNum(j);
+	invpindex.Elem(pi) = 0;
+      }
+
+  /*
+  for (i = 1; i <= points.Size(); i++)
+    invpindex.Elem(i) = 0;
+  */
+  for (i = 1; i <= locfaces.Size(); i++)
+    {
+      for (j = 1; j <= locfaces.Get(i).GetNP(); j++)
+	{
+	  pi = locfaces.Get(i).PNum(j);
+	  if (invpindex.Get(pi) == 0)
+	    {
+	      pindex.Append (pi);
+	      invpindex.Elem(pi) = pindex.Size();
+	      locfaces.Elem(i).PNum(j) = locpoints.Append (points.Get(pi).P());
+	    }
+	  else
+	    locfaces.Elem(i).PNum(j) = invpindex.Get(pi);
+
+	}
+    }
+
+
+
+  if (connectedpairs)
+    {
+      for (i = 1; i <= locpoints.Size(); i++)
+	{
+	  int pi = pindex.Get(i);
+	  if (pi >= 1 && pi <= connectedpairs->Size ())
+	    {
+	      for (j = 1; j <= connectedpairs->EntrySize(pi); j++)
+		{
+		  int oi = connectedpairs->Get(pi, j);
+		  int other = invpindex.Get(oi);
+		  if (other >= 1 && other <= pindex.Size() && 
+		      pindex.Get(other) == oi)
+		    {
+		      INDEX_2 coned(i, other);
+		      coned.Sort();
+		      //		      (*testout) << "connected: " << locpoints.Get(i) << "-" << locpoints.Get(other) << endl;
+		      getconnectedpairs.Set (coned, 1);
+		    }
+		}
+	    }
+	}
+    }
+  
+
+
+
+  /*
+  for (i = 1; i <= points.Size(); i++)
+    if (points.Elem(i).Valid() && Dist (points.Elem(i).P(), p0) <= xh)
+      {
+	if (!invpindex.Get(i))
+	  {
+	    locpoints.Append (points.Get(i).P());
+	    pindex.Append (i);
+	    invpindex.Elem(i) = pindex.Size();
+	  }
+      }
+      */
+  return faces.Get(fstind).QualClass();
+}
+
+
+// returns all points connected with fi
+void AdFront3 :: GetGroup (int fi,
+			   ARRAY<MeshPoint> & grouppoints,
+			   ARRAY<Element2d> & groupelements,
+			   ARRAY<PointIndex> & pindex,
+			   ARRAY<INDEX> & findex
+			   ) const
+{
+  static ARRAY<char> pingroup;
+  INDEX i;
+  int j, changed, fused;
+
+  pingroup.SetSize(points.Size());
+
+  for (i = 1; i <= pingroup.Size(); i++)
+    pingroup.Elem(i) = 0;
+  for (j = 1; j <= 3; j++)
+    pingroup.Elem (faces.Get(fi).Face().PNum(j)) = 1;
+
+  do
+    {
+      changed = 0;
+
+      for (i = 1; i <= faces.Size(); i++)
+	if (faces.Get(i).Valid())
+	  {
+	    const Element2d & face = faces.Get(i).Face();
+
+
+	    fused = 0;
+	    for (j = 1; j <= 3; j++)
+	      if (pingroup.Elem(face.PNum(j))) 
+		fused++;
+            
+	    if (fused >= 2)
+	      for (j = 1; j <= 3; j++)
+		if (!pingroup.Elem(face.PNum(j)))
+		  {
+		    pingroup.Elem(face.PNum(j)) = 1;
+		    changed = 1;
+		  }
+	  }
+
+    }
+  while (changed);
+
+
+  static ARRAY<int> invpindex;
+  invpindex.SetSize (points.Size());
+  
+
+  for (i = 1; i <= points.Size(); i++)
+    if (points.Get(i).Valid())
+      {
+	grouppoints.Append (points.Get(i).P());
+	pindex.Append (i);
+	invpindex.Elem(i) = pindex.Size();
+      }
+
+  for (i = 1; i <= faces.Size(); i++)
+    if (faces.Get(i).Valid())
+      {
+	fused = 0;
+	for (j = 1; j <= 3; j++)
+	  if (pingroup.Get(faces.Get(i).Face().PNum(j)))
+	    fused++;
+
+	if (fused >= 2)
+	  {
+	    groupelements.Append (faces.Get(i).Face());
+	    findex.Append (i);
+	  }
+      }
+      
+  for (i = 1; i <= groupelements.Size(); i++)
+    for (j = 1; j <= 3; j++)
+      {
+	groupelements.Elem(i).PNum(j) =
+	  invpindex.Get(groupelements.Elem(i).PNum(j));
+      }
+
+  /*
+  for (i = 1; i <= groupelements.Size(); i++)
+    for (j = 1; j <= 3; j++)
+      for (k = 1; k <= grouppoints.Size(); k++)
+        if (pindex.Get(k) == groupelements.Get(i).PNum(j))
+          {
+	    groupelements.Elem(i).PNum(j) = k;
+	    break;
+          }
+  */          
+}
+
+
+void AdFront3 :: SetStartFront (int /* baseelnp */)
+{
+  INDEX i;
+  int j;
+
+  for (i = 1; i <= faces.Size(); i++)
+    if (faces.Get(i).Valid())
+      {
+	const Element2d & face = faces.Get(i).Face();
+	for (j = 1; j <= 3; j++)
+	  points.Elem(face.PNum(j)).DecFrontNr(0);
+      }
+
+  /*
+  if (baseelnp)
+    {
+      for (i = 1; i <= faces.Size(); i++)
+	if (faces.Get(i).Valid() && faces.Get(i).Face().GetNP() != baseelnp)
+	  faces.Elem(i).qualclass = 1000;
+    }
+    */
+}
+
+
+int AdFront3 :: Inside (const Point3d & p) const
+{
+  int i, cnt;
+  Vec3d n, v1, v2;
+  DenseMatrix a(3), ainv(3);
+  Vector b(3), u(3);
+
+  // random numbers:
+  n.X() = 0.123871;
+  n.Y() = 0.15432;
+  n.Z() = -0.43989;
+
+  cnt = 0;
+  for (i = 1; i <= faces.Size(); i++)
+    if (faces.Get(i).Valid())
+      {
+	const Point3d & p1 = points[faces.Get(i).Face().PNum(1)].P();
+	const Point3d & p2 = points[faces.Get(i).Face().PNum(2)].P();
+	const Point3d & p3 = points[faces.Get(i).Face().PNum(3)].P();
+
+	v1 = p2 - p1;
+	v2 = p3 - p1;
+
+	a.Elem(1, 1) = v1.X();
+	a.Elem(2, 1) = v1.Y();
+	a.Elem(3, 1) = v1.Z();
+	a.Elem(1, 2) = v2.X();
+	a.Elem(2, 2) = v2.Y();
+	a.Elem(3, 2) = v2.Z();
+	a.Elem(1, 3) = -n.X();
+	a.Elem(2, 3) = -n.Y();
+	a.Elem(3, 3) = -n.Z();
+
+	b.Elem(1) = p.X() - p1.X();
+	b.Elem(2) = p.Y() - p1.Y();
+	b.Elem(3) = p.Z() - p1.Z();
+
+	CalcInverse (a, ainv);
+	ainv.Mult (b, u);
+
+	if (u.Elem(1) >= 0 && u.Elem(2) >= 0 && u.Elem(1)+u.Elem(2) <= 1 &&
+	    u.Elem(3) > 0)
+	  {
+	    cnt++;
+	  }
+      }
+
+  return (cnt % 2);
+}
+
+
+
+
+
+int AdFront3 :: SameSide (const Point3d & lp1, const Point3d & lp2,
+			  const ARRAY<int> * testfaces) const
+{
+  int i, ii, cnt;
+
+  const Point3d *line[2];
+  line[0] = &lp1;
+  line[1] = &lp2;
+
+
+  cnt = 0;
+
+  Point3d pmin(lp1);
+  Point3d pmax(lp1);
+  pmin.SetToMin (lp2);
+  pmax.SetToMax (lp2);
+
+  static ARRAY<int> aprif;
+  aprif.SetSize(0);
+  
+  if (!testfaces)
+    facetree->GetIntersecting (pmin, pmax, aprif);
+  else
+    {
+      for (i = 1; i <= testfaces->Size(); i++)
+	aprif.Append (testfaces->Get(i));
+    }
+
+  //  (*testout) << "test ss, p1,p2 = " << lp1 << lp2 << ", inters = " << aprif.Size() << endl;
+  //  for (i = 1; i <= faces.Size(); i++)
+  for (ii = 1; ii <= aprif.Size(); ii++)
+    {
+      i = aprif.Get(ii);
+      
+      if (faces.Get(i).Valid())
+	{
+	  const Point3d *tri[3];
+	  tri[0] = &points[faces.Get(i).Face().PNum(1)].P();
+	  tri[1] = &points[faces.Get(i).Face().PNum(2)].P();
+	  tri[2] = &points[faces.Get(i).Face().PNum(3)].P();
+	  	  
+	  if (IntersectTriangleLine (&tri[0], &line[0]))
+	    cnt++;
+	  
+	}
+    }
+
+  return ((cnt+1) % 2);
+}
+}
diff --git a/Netgen/libsrc/meshing/adfront3.hpp b/Netgen/libsrc/meshing/adfront3.hpp
new file mode 100644
index 0000000000..50e30c56cb
--- /dev/null
+++ b/Netgen/libsrc/meshing/adfront3.hpp
@@ -0,0 +1,274 @@
+#ifndef FILE_ADFRONT3
+#define FILE_ADFRONT3
+
+/**************************************************************************/
+/* File:   adfront3.hh                                                    */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Okt. 95                                                    */
+/**************************************************************************/
+
+/*
+    Advancing front class for volume meshing
+*/
+
+
+
+/// Point in advancing front
+class FrontPoint3
+{
+  /// coordinates
+  Point3d p;           
+  /// global node index
+  PointIndex globalindex;   
+  /// number of faces connected to point 
+  int nfacetopoint;    
+  /// distance to original boundary
+  int frontnr;
+  /// 
+  int cluster;
+public:
+  ///
+  FrontPoint3 ();
+  ///
+  FrontPoint3 (const Point3d & ap, PointIndex agi);
+  
+  ///
+  const Point3d & P () const
+    { return p; }
+  ///
+  PointIndex GlobalIndex () const
+    { return globalindex; }
+  
+  ///
+  void AddFace ()
+    { nfacetopoint++; }
+
+  ///
+  void RemoveFace()
+    { 
+      nfacetopoint--;
+      if (nfacetopoint == 0) nfacetopoint = -1;
+    }
+  
+  ///
+  int Valid () const
+  { return nfacetopoint >= 0; }
+
+  ///
+  void DecFrontNr (int afrontnr)
+    {
+      if (frontnr > afrontnr) frontnr = afrontnr;
+    }
+  
+  ///
+  int FrontNr () const
+    { return frontnr; }
+
+  ///
+  friend class AdFront3;
+};
+
+/// Face in advancing front
+class FrontFace
+{
+  ///
+  Element2d f;
+  ///
+  int qualclass;
+  ///
+  char oldfront;
+  ///
+  int hashvalue;
+  ///
+  int cluster;
+
+public:
+  ///
+  FrontFace ();
+  ///
+  FrontFace (const Element2d & af);
+  ///
+  const Element2d & Face () const
+    { return f; }
+    
+  ///
+  int QualClass () const
+    { return qualclass; }
+
+  ///
+  void IncrementQualClass ()
+    { qualclass++; }
+
+  ///
+  void ResetQualClass ()
+    {
+      if (qualclass > 1)
+	{
+	  qualclass = 1;
+	  oldfront = 0;
+	}
+    }
+  
+  ///
+  int Valid () const
+  { 
+    return !f.IsDeleted(); // PNum(1) != 0; 
+  }
+
+  ///
+  void Invalidate ();
+  ///
+  int HashValue() const {return hashvalue;}
+  ///
+  void SetHashValue(int hv) {hashvalue = hv;}
+
+  ///
+  friend class AdFront3;
+
+  int Cluster () const { return cluster; }
+      
+};  
+
+
+
+
+/// Advancing front, 3D.
+class AdFront3
+{
+  ///
+  ARRAY<FrontPoint3,PointIndex::BASE> points;
+  ///
+  ARRAY<FrontFace> faces;
+  ///
+  ARRAY<PointIndex> delpointl;
+
+  /// which points are connected to pi ?
+  TABLE<int> * connectedpairs;
+  
+  /// number of total front faces;
+  int nff;
+  /// number of quads in front
+  int nff4; 
+  
+  ///
+  double vol;
+
+  ///
+  GeomSearch3d hashtable;
+
+  /// 
+  int hashon;
+
+  ///
+  int hashcreated;
+
+  /// counter for rebuilding internal tables
+  int rebuildcounter;
+  /// last base element
+  int lasti;
+  /// minimal selection-value of baseelements
+  int minval;
+
+  ///
+  class Box3dTree * facetree;
+public:
+
+  ///
+  AdFront3 ();
+  ///
+  ~AdFront3 ();
+  ///
+  void GetPoints (ARRAY<Point3d> & apoints) const;
+  ///
+  int GetNP() const 
+    { return points.Size(); }
+  ///
+  const Point3d & GetPoint (PointIndex pi) const
+  { return points[pi].P(); }
+  ///
+  int GetNF() const
+    { return nff; }
+  ///
+  const Element2d & GetFace (int i) const
+    { return faces.Get(i).Face(); }
+  ///
+  void Print () const;
+  ///
+  int Empty () const
+    { return nff == 0; }
+  ///
+  int Empty (int elnp) const
+    {
+      if (elnp == 4)
+	return (nff4 == 0);
+      return (nff - nff4 == 0);
+    }
+  ///
+  int SelectBaseElement ();
+
+  ///
+  void CreateTrees ();
+
+  ///
+  void GetIntersectingFaces (const Point3d & pmin, const Point3d & pmax, 
+			     ARRAY<int> & ifaces) const;
+
+  ///
+  void GetFaceBoundingBox (int i, Box3d & box) const;
+
+  ///
+  int GetLocals (int baseelement,
+		 ARRAY<Point3d> & locpoints,
+                 ARRAY<Element2d> & locfaces,   // local index
+                 ARRAY<PointIndex> & pindex,
+                 ARRAY<INDEX> & findex,
+		 INDEX_2_HASHTABLE<int> & connectedpairs,
+                 float xh,
+		 float relh,
+		 INDEX& facesplit);
+  
+  ///
+  void GetGroup (int fi,
+                 ARRAY<MeshPoint> & grouppoints,
+                 ARRAY<Element2d> & groupelements,
+                 ARRAY<PointIndex> & pindex,
+                 ARRAY<INDEX> & findex
+                 ) const;
+
+  ///
+  void DeleteFace (INDEX fi);
+  ///
+  INDEX AddPoint (const Point3d & p, PointIndex globind);
+  ///
+  INDEX AddFace (const Element2d & e);
+  ///
+  INDEX AddConnectedPair (const INDEX_2 & pair);
+  ///
+  void IncrementClass (INDEX fi);
+  ///
+  void ResetClass (INDEX fi);
+  ///
+  void SetStartFront (int baseelnp = 0);
+
+  /// is Point p inside Surface ?
+  int Inside (const Point3d & p) const;
+  /// both points on same side ?
+  int SameSide (const Point3d & lp1, const Point3d & lp2, const ARRAY<int> * testfaces = NULL) const;
+
+
+  ///
+  PointIndex GetGlobalIndex (PointIndex pi) const
+    { return points[pi].GlobalIndex(); }
+  ///
+  double Volume () const
+    { return vol; }
+
+
+private:
+  void RebuildInternalTables();
+};
+
+
+
+
+#endif
diff --git a/Netgen/libsrc/meshing/bisect.cpp b/Netgen/libsrc/meshing/bisect.cpp
new file mode 100644
index 0000000000..39420983c8
--- /dev/null
+++ b/Netgen/libsrc/meshing/bisect.cpp
@@ -0,0 +1,2298 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+
+namespace netgen
+{
+#include "../interface/writeuser.hpp"
+
+  class MarkedTet;
+  class MarkedPrism;
+  class MarkedTri;
+  class MarkedQuad;
+  
+  typedef MoveableArray<MarkedTet> T_MTETS;
+  typedef MoveableArray<MarkedPrism> T_MPRISMS;
+  typedef MoveableArray<MarkedTri> T_MTRIS;
+  typedef MoveableArray<MarkedQuad> T_MQUADS;
+
+class MarkedTet
+{
+public:
+  /// pnums of tet
+  PointIndex pnums[4];
+  /// material number
+  int matindex;
+  /// element marked for refinement
+  /// marked = 1: marked by element marker, marked = 2 due to closure
+  unsigned int marked:2;
+  /// flag of Arnold-Mukherjee algorithm
+  unsigned int flagged:1;
+  /// tetedge (local coordinates 0..3)
+  unsigned int tetedge1:3;
+  unsigned int tetedge2:3;
+  /// marked edge of faces
+  /// face_j : face without node j,
+  /// mark_k : edge without node k
+  unsigned char faceedges[4];
+
+  bool incorder;
+  unsigned int order:6;
+
+  friend ostream & operator<< (ostream & ost, const MarkedTet & mt);
+};
+
+class MarkedPrism
+{
+public:
+  /// 6 point numbers
+  PointIndex pnums[6];
+  /// material number
+  int matindex;
+  /// marked for refinement
+  int marked;
+  /// edge without node k (0,1,2)
+  int markededge;
+
+  bool incorder;
+  unsigned int order:6;
+};
+
+class MarkedTri
+{
+public:
+  /// three point numbers
+  PointIndex pnums[3];
+  /// three geominfos
+  PointGeomInfo pgeominfo[3];
+  /// marked for refinement
+  int marked;
+  /// edge without node k
+  int markededge;
+  /// surface id
+  int surfid;
+
+  bool incorder;
+  unsigned int order:6;
+};
+
+class MarkedQuad
+{
+public:
+  /// point numbers
+  PointIndex pnums[4];
+  ///
+  PointGeomInfo pgeominfo[4];
+  /// marked for refinement
+  int marked;
+  /// surface id
+  int surfid;
+
+  bool incorder;
+  unsigned int order:6;
+};
+
+
+
+
+
+ostream & operator<< (ostream & ost, const MarkedTet & mt)
+{
+  int k;
+  ost << "MT: " << mt.pnums[0] << " - " << mt.pnums[1] << " - " 
+      << mt.pnums[2] << " - " << mt.pnums[3] << endl
+      << "marked edge: " << mt.tetedge1 << " - " << mt.tetedge2
+      << ", order = " << mt.order << endl;
+  for (k = 0; k < 4; k++)
+    ost << mt.faceedges[k] << "  ";
+  ost << endl;
+  return ost;
+}
+
+
+
+
+void BTSortEdges (const Mesh & mesh,
+		  INDEX_2_CLOSED_HASHTABLE<int> & edgenumber)
+{
+  cout << "sorting ... " << flush;
+
+  //  if (mesh.PureTetMesh())
+  if (1)
+    {
+      // new, fast version
+      
+      ARRAY<INDEX_2> edges;
+      ARRAY<int> eclasses;
+      
+      int i, j, k;
+      int cntedges = 0;
+      int goon;
+      int ned;
+      
+      // enumerate edges:
+      for (i = 1; i <= mesh.GetNE(); i++)
+	{
+	  const Element & el = mesh.VolumeElement (i);
+	  static int tetedges[6][2] =
+	  { { 1, 2 },
+	    { 1, 3 },
+	    { 1, 4 },
+	    { 2, 3 },
+	    { 2, 4 },
+            { 3, 4 } } ;
+	  static int prismedges[9][2] =
+	  { { 1, 2 },
+	    { 1, 3 },
+	    { 2, 3 },
+	    { 4, 5 },
+	    { 4, 6 },
+	    { 5, 6 },
+	    { 1, 4 },
+	    { 2, 5 },
+            { 3, 6 } };
+	  int pyramidedges[6][2] =
+	  { { 1, 2 },
+	    { 3, 4 },
+	    { 1, 5 },
+	    { 2, 5 },
+	    { 3, 5 },
+	    { 4, 5 } };
+	  
+	  int (*tip)[2];
+	  
+	  switch (el.GetType())
+	    {
+	    case TET:
+	    case TET10:
+	      {
+		tip = tetedges;
+		ned = 6;
+		break;
+	      }
+	    case PRISM:
+	    case PRISM12:
+	      {
+		tip = prismedges;
+		ned = 6;
+		break;
+	      }
+	    case PYRAMID:
+	      {
+		tip = pyramidedges;
+		ned = 6;
+		break;
+	      }
+	    }
+	      
+	  for (j = 0; j < ned; j++)
+	    {
+	      INDEX_2 i2(el.PNum(tip[j][0]), el.PNum(tip[j][1]));
+	      i2.Sort();
+	      if (!edgenumber.Used(i2))
+		{
+		  cntedges++;
+		  edges.Append (i2);
+		  edgenumber.Set(i2, cntedges);
+		}
+	    }
+	}
+      
+      // additional surface edges:
+      for (i = 1; i <= mesh.GetNSE(); i++)
+	{
+	  const Element2d & el = mesh.SurfaceElement (i);
+	  static int trigedges[3][2] =
+	  { { 1, 2 },
+	    { 2, 3 },
+	    { 3, 1 } };
+
+	  static int quadedges[4][2] =
+	  { { 1, 2 },
+	    { 2, 3 },
+	    { 3, 4 },
+	    { 4, 1 } };
+
+
+	  int (*tip)[2];
+	  
+	  switch (el.GetType())
+	    {
+	    case TRIG:
+	    case TRIG6:
+	      {
+		tip = trigedges;
+		ned = 3;
+		break;
+	      }
+	    case QUAD:
+	    case QUAD6:
+	      {
+		tip = quadedges;
+		ned = 4;
+		break;
+	      }
+	    default:
+	      {
+		cerr << "Error: Sort for Bisect, SE has " << el.GetNP() << " points" << endl;
+		ned = 0;
+	      }
+	    }
+	      
+	  for (j = 0; j < ned; j++)
+	    {
+	      INDEX_2 i2(el.PNum(tip[j][0]), el.PNum(tip[j][1]));
+	      i2.Sort();
+	      if (!edgenumber.Used(i2))
+		{
+		  cntedges++;
+		  edges.Append (i2);
+		  edgenumber.Set(i2, cntedges);
+		}
+	    }
+	}
+
+
+
+
+
+      eclasses.SetSize (cntedges);
+      for (i = 1; i <= cntedges; i++)
+	eclasses.Elem(i) = i;
+
+
+      // identify edges in element stack
+      do
+	{
+	  goon = 0;
+	  for (i = 1; i <= mesh.GetNE(); i++)
+	    {
+	      const Element & el = mesh.VolumeElement (i);	     
+	      
+	      if (el.GetType() != PRISM &&
+		  el.GetType() != PRISM12 &&
+		  el.GetType() != PYRAMID)
+		continue;
+
+	      int prismpairs[3][4] =
+	      { { 1, 2, 4, 5 },
+		{ 2, 3, 5, 6 },
+		{ 1, 3, 4, 6 } };
+	      
+	      int pyramidpairs[3][4] =
+	      { { 1, 2, 4, 3 },
+		{ 1, 5, 4, 5 },
+		{ 2, 5, 3, 5 } };
+		      
+	      int (*pairs)[4];
+	      switch (el.GetType())
+		{
+		case PRISM:
+		case PRISM12:
+		  {
+		    pairs = prismpairs;
+		    break;
+		  }
+		case PYRAMID:
+		  {
+		    pairs = pyramidpairs;
+		    break;
+		  }
+		}
+
+	      for (j = 0; j < 3; j++)
+		{
+		  INDEX_2 e1 (el.PNum(pairs[j][0]), 
+			      el.PNum(pairs[j][1]));
+		  INDEX_2 e2 (el.PNum(pairs[j][2]), 
+			      el.PNum(pairs[j][3]));
+		  e1.Sort();
+		  e2.Sort();
+		      
+		  int eclass1 = edgenumber.Get (e1);
+		  int eclass2 = edgenumber.Get (e2);
+
+		  //		  (*testout) << "identify edges " << eclass1 << "-" << eclass2 << endl;
+
+		  if (eclasses.Get(eclass1) >
+		      eclasses.Get(eclass2))
+		    {
+		      eclasses.Elem(eclass1) = 
+			eclasses.Get(eclass2);
+		      goon = 1;
+		    }
+		  if (eclasses.Get(eclass2) >
+		      eclasses.Get(eclass1))
+		    {
+		      eclasses.Elem(eclass2) = 
+			eclasses.Get(eclass1);
+		      goon = 1;
+		    }
+		}
+	    }
+	}
+      while (goon);
+
+      /*      
+      for (i = 1; i <= cntedges; i++)
+	{
+	  (*testout) << "edge " << i << ": " 
+		     << edges.Get(i).I1() << "-" << edges.Get(i).I2()
+		     << ", class = " << eclasses.Get(i) << endl;
+	}
+      */      
+      // compute classlength:
+      ARRAY<double> edgelength(cntedges);
+      for (i = 1; i <= cntedges; i++)
+	edgelength.Elem(i) = 1e20;
+
+      for (i = 1; i <= cntedges; i++)
+	{
+	  INDEX_2 edge = edges.Get(i);
+	  double elen = Dist (mesh.Point(edge.I1()),
+			      mesh.Point(edge.I2()));
+	  edgelength.Elem (i) = elen;
+	}
+
+      /*
+      for (i = 1; i <= mesh.GetNE(); i++)
+	{
+	  const Element & el = mesh.VolumeElement (i);
+	  
+	  if (el.GetType() == TET)
+	    {
+	      for (j = 1; j <= 3; j++)
+		for (k = j+1; k <= 4; k++)
+		  {
+		    INDEX_2 i2(el.PNum(j), el.PNum(k));
+		    i2.Sort();
+		    
+		    int enr = edgenumber.Get(i2);
+		    double elen = Dist (mesh.Point (i2.I1()), mesh.Point (i2.I2()));
+		    if (elen < edgelength.Get(enr))
+		      edgelength.Set (enr, elen);
+		  }
+	    }
+	  else if (el.GetType() == PRISM)
+	    {
+	      for (j = 1; j <= 3; j++)
+		{
+		  k = (j % 3) + 1;
+		  
+		  INDEX_2 i2(el.PNum(j), el.PNum(k));
+		  i2.Sort();
+		  
+		  int enr = edgenumber.Get(i2);
+		  double elen = Dist (mesh.Point (i2.I1()), mesh.Point (i2.I2()));
+		  if (elen < edgelength.Get(enr))
+		    edgelength.Set (enr, elen);
+		  
+		  i2 = INDEX_2(el.PNum(j+3), el.PNum(k+3));
+		  i2.Sort();
+		  
+		  enr = edgenumber.Get(i2);
+		  elen = Dist (mesh.Point (i2.I1()), mesh.Point (i2.I2()));
+		  if (elen < edgelength.Get(enr))
+		    edgelength.Set (enr, elen);
+		  
+		  if (!edgenumber.Used(i2))
+		    {
+		      cntedges++;
+		      edgenumber.Set(i2, cntedges);
+		    }
+		  i2 = INDEX_2(el.PNum(j), el.PNum(j+3));
+		  i2.Sort();
+		  
+		  enr = edgenumber.Get(i2);
+		  elen = Dist (mesh.Point (i2.I1()), mesh.Point (i2.I2()));
+		  if (elen < edgelength.Get(enr))
+		    edgelength.Set (enr, elen);
+		}
+	    }
+	}
+      */
+
+      
+      for (i = 1; i <= cntedges; i++)
+	{
+	  if (eclasses.Get(i) != i)
+	    {
+	      if (edgelength.Get(i) < edgelength.Get(eclasses.Get(i)))
+		edgelength.Elem(eclasses.Get(i)) = edgelength.Get(i);
+	      edgelength.Elem(i) = 1e20;
+	    }
+	}
+
+
+      TABLE<int> eclasstab(cntedges);
+      for (i = 1; i <= cntedges; i++)
+	eclasstab.Add1 (eclasses.Get(i), i);
+
+
+      // sort edges:
+      ARRAY<int> sorted(cntedges);
+      
+      QickSort (edgelength, sorted);
+      
+      int cnt = 0;
+      for (i = 1; i <= cntedges; i++)
+	{
+	  int ii = sorted.Get(i);
+	  for (j = 1; j <= eclasstab.EntrySize(ii); j++)
+	    {
+	      cnt++;
+	      edgenumber.Set (edges.Get(eclasstab.Get(ii, j)), cnt); 
+	    }
+	}
+    }
+
+  else
+    
+    {
+      // old version
+      
+      int i, j, k;
+      int cnt = 0;
+      int found;
+      double len2, maxlen2;
+      INDEX_2 ep;
+      
+      // sort edges by length, parallel edges (on prisms)
+      // are added in blocks
+      
+      do
+	{
+	  found = 0;
+	  maxlen2 = 1e30;
+	  
+	  for (i = 1; i <= mesh.GetNE(); i++)
+	    {
+	      const Element & el = mesh.VolumeElement (i);
+	      int ned;
+	      int tetedges[6][2] =
+	      { { 1, 2 },
+		{ 1, 3 },
+		{ 1, 4 },
+		{ 2, 3 },
+		{ 2, 4 },
+		{ 3, 4 } };
+	      int prismedges[6][2] =
+	      { { 1, 2 },
+		{ 1, 3 },
+		{ 2, 4 },
+		{ 4, 5 },
+		{ 4, 6 },
+		{ 5, 6 } };
+	      int pyramidedges[6][2] =
+	      { { 1, 2 },
+		{ 3, 4 },
+		{ 1, 5 },
+		{ 2, 5 },
+		{ 3, 5 },
+		{ 4, 5 } };
+
+	      int (*tip)[2];
+
+	      switch (el.GetType())
+		{
+		case TET:
+		  {
+		    tip = tetedges;
+		    ned = 6;
+		    break;
+		  }
+		case PRISM:
+		  {
+		    tip = prismedges;
+		    ned = 6;
+		    break;
+		  }
+		case PYRAMID:
+		  {
+		    tip = pyramidedges;
+		    ned = 6;
+		    break;
+		  }
+		}
+	      
+	      for (j = 0; j < ned; j++)
+		{
+		  INDEX_2 i2(el.PNum(tip[j][0]), el.PNum(tip[j][1]));
+		  i2.Sort();
+		  if (!edgenumber.Used(i2))
+		    {
+		      len2 = Dist (mesh.Point (i2.I1()),
+				   mesh.Point (i2.I2()));
+		      if (len2 < maxlen2)
+			{
+			  maxlen2 = len2;
+			  ep = i2;
+			  found = 1;
+			}
+		    }
+		}
+	    }
+	  if (found)
+	    {
+	      cnt++;
+	      edgenumber.Set (ep, cnt);
+	      
+	      
+	      // find connected edges:
+	      int goon = 0;
+	      do
+		{
+		  goon = 0;
+		  for (i = 1; i <= mesh.GetNE(); i++)
+		    {
+		      const Element & el = mesh.VolumeElement (i);	      
+		      if (el.GetNP() != 6) continue;
+
+		      int prismpairs[3][4] =
+		      { { 1, 2, 4, 5 },
+			{ 2, 3, 5, 6 },
+			{ 1, 3, 4, 6 } };
+
+		      int pyramidpairs[3][4] =
+		      { { 1, 2, 4, 3 },
+			{ 1, 5, 4, 5 },
+			{ 2, 5, 3, 5 } };
+		      
+		      int (*pairs)[4];
+		      switch (el.GetType())
+			{
+			case PRISM:
+			  {
+			    pairs = prismpairs;
+			    break;
+			  }
+			case PYRAMID:
+			  {
+			    pairs = pyramidpairs;
+			    break;
+			  }
+			}
+
+		      for (j = 0; j < 3; j++)
+			{
+			  INDEX_2 e1 (el.PNum(pairs[j][0]), 
+				      el.PNum(pairs[j][1]));
+			  INDEX_2 e2 (el.PNum(pairs[j][2]), 
+				      el.PNum(pairs[j][3]));
+			  e1.Sort();
+			  e2.Sort();
+			  
+			  int used1 = edgenumber.Used (e1);
+			  int used2 = edgenumber.Used (e2);
+			  
+			  if (used1 && !used2)
+			    {
+			      cnt++;
+			      edgenumber.Set (e2, cnt);
+			      goon = 1;
+			    }
+			  if (used2 && !used1)
+			    {
+			      cnt++;
+			      edgenumber.Set (e1, cnt);
+			      goon = 1;
+			    }
+			}
+		    }
+		}
+	      while (goon);
+	    }
+	}
+      while (found);
+    }
+}
+
+
+
+
+void BTDefineMarkedTet (const Element & el,
+			INDEX_2_CLOSED_HASHTABLE<int> & edgenumber,
+			MarkedTet & mt)
+{
+  int i, j, k;
+  for (i = 0; i < 4; i++)
+    mt.pnums[i] = el[i];
+
+  mt.marked = 0;
+  mt.flagged = 0;
+
+  mt.incorder = 0;
+  mt.order = 1;
+  
+  int val = 0;
+  // find marked edge of tet:
+  for (i = 0; i < 3; i++)
+    for (j = i+1; j < 4; j++)
+      {
+	INDEX_2 i2(mt.pnums[i], mt.pnums[j]);
+	i2.Sort();
+	int hval = edgenumber.Get(i2);
+	if (hval > val)
+	  {
+	    val = hval;
+	    mt.tetedge1 = i;
+	    mt.tetedge2 = j;
+	  }
+      }
+
+
+  // find marked edges of faces:
+  for (k = 0; k < 4; k++)
+    {
+      val = 0;
+      for (i = 0; i < 3; i++)
+	for (j = i+1; j < 4; j++)
+	  if (i != k && j != k)
+	    {
+	      INDEX_2 i2(mt.pnums[i], mt.pnums[j]);
+	      i2.Sort();
+	      int hval = edgenumber.Get(i2);
+	      if (hval > val)
+		{
+		  val = hval;
+		  mt.faceedges[k] = 6 - k - i - j;
+		}
+	    }
+    }
+}
+
+
+
+
+void BTDefineMarkedPrism (const Element & el,
+			  INDEX_2_CLOSED_HASHTABLE<int> & edgenumber,
+			  MarkedPrism & mp)
+{
+  int i, j, k;
+
+  if (el.GetType() == PRISM ||
+      el.GetType() == PRISM12)
+    {
+      for (i = 0; i < 6; i++)
+	mp.pnums[i] = el[i];
+    }
+  else if (el.GetType() == PYRAMID)
+    {
+      static int map[6] = 
+	{ 1, 2, 5, 4, 3, 5 };
+      for (i = 0; i < 6; i++)
+	mp.pnums[i] = el.PNum(map[i]);
+    }
+  else if (el.GetType() == TET ||
+	   el.GetType() == TET10)
+    {
+      static int map[6] = 
+      { 1, 4, 3, 2, 4, 3 };
+      for (i = 0; i < 6; i++)
+	mp.pnums[i] = el.PNum(map[i]);
+      
+    }
+  else
+    {
+      PrintSysError ("Define marked prism called for non-prism and non-pyramid");
+    }
+  
+
+
+  mp.marked = 0;
+
+  mp.incorder = 0;
+  mp.order = 1;
+
+  int val = 0;
+  for (i = 0; i < 2; i++)
+    for (j = i+1; j < 3; j++)
+      {
+	INDEX_2 i2(mp.pnums[i], mp.pnums[j]);
+	i2.Sort();
+	int hval = edgenumber.Get(i2);
+	if (hval > val)
+	  {
+	    val = hval;
+	    mp.markededge = 3 - i - j;
+	  }
+      }
+}
+
+
+
+
+
+
+void BTDefineMarkedTri (const Element2d & el,
+			INDEX_2_CLOSED_HASHTABLE<int> & edgenumber,
+			MarkedTri & mt)
+{
+  int i, j, k;
+  for (i = 0; i < 3; i++)
+    {
+      mt.pnums[i] = el[i];
+      mt.pgeominfo[i] = el.GeomInfoPi (i+1);
+    }
+
+  mt.marked = 0;
+  mt.surfid = el.GetIndex();
+
+  mt.incorder = 0;
+  mt.order = 1;
+
+  int val = 0;
+  for (i = 0; i < 2; i++)
+    for (j = i+1; j < 3; j++)
+      {
+	INDEX_2 i2(mt.pnums[i], mt.pnums[j]);
+	i2.Sort();
+	int hval = edgenumber.Get(i2);
+	if (hval > val)
+	  {
+	    val = hval;
+	    mt.markededge = 3 - i - j;
+	  }
+      }
+}
+
+
+
+
+
+void BTDefineMarkedQuad (const Element2d & el,
+			 INDEX_2_CLOSED_HASHTABLE<int> & edgenumber,
+			 MarkedQuad & mq)
+{
+  int i, j, k;
+  for (i = 0; i < 4; i++)
+    mq.pnums[i] = el[i];
+  Swap (mq.pnums[2], mq.pnums[3]);
+
+  mq.marked = 0;
+  mq.surfid = el.GetIndex();
+}
+
+
+
+
+// mark elements due to local h
+int BTMarkTets (T_MTETS & mtets,
+		T_MPRISMS & mprisms,
+		const Mesh & mesh)
+{
+  int i, j, k;
+  int step;
+
+  int marked = 0;
+
+  int np = mesh.GetNP();
+  Vector hv(np);
+  for (i = 1; i <= np; i++)
+    hv.Elem(i) = mesh.GetH (mesh.Point(i));
+
+  double hfac = 1;
+  
+  for (step = 1; step <= 2; step++)
+    {
+      for (i = 1; i <= mtets.Size(); i++)
+	{
+	  double h = 0;
+	  
+	  for (j = 0; j < 3; j++)
+	    for (k = j+1; k < 4; k++)
+	      {
+		const Point3d & p1 = mesh.Point (mtets.Get(i).pnums[j]);
+		const Point3d & p2 = mesh.Point (mtets.Get(i).pnums[k]);
+		double hh = Dist2 (p1, p2);
+		if (hh > h) h = hh;
+	      }
+	  h = sqrt (h);
+	  
+	  double hshould = 1e10;
+	  for (j = 0; j < 4; j++)
+	    {
+	      double hi = hv.Get (mtets.Get(i).pnums[j]);
+	      if (hi < hshould)
+		hshould = hi;
+	    }
+	  
+	
+	  if (step == 1)
+	    {
+	      if (h / hshould > hfac)
+		hfac = h / hshould;
+	    }
+	  else
+	    {
+	      if (h > hshould * hfac)
+		{
+		  mtets.Elem(i).marked = 1;
+		  marked = 1;
+		}
+	      else
+		mtets.Elem(i).marked = 0;
+	    }
+	  
+	}
+      for (i = 1; i <= mprisms.Size(); i++)
+	{
+	  double h = 0;
+	  
+	  for (j = 0; j < 2; j++)
+	    for (k = j+1; k < 3; k++)
+	      {
+		const Point3d & p1 = mesh.Point (mprisms.Get(i).pnums[j]);
+		const Point3d & p2 = mesh.Point (mprisms.Get(i).pnums[k]);
+		double hh = Dist2 (p1, p2);
+		if (hh > h) h = hh;
+	      }
+	  h = sqrt (h);
+	  
+	  double hshould = 1e10;
+	  for (j = 0; j < 6; j++)
+	    {
+	      double hi = hv.Get (mprisms.Get(i).pnums[j]);
+	      if (hi < hshould)
+		hshould = hi;
+	    }
+	  
+	
+	  if (step == 1)
+	    {
+	      if (h / hshould > hfac)
+		hfac = h / hshould;
+	    }
+	  else
+	    {
+	      if (h > hshould * hfac)
+		{
+		  mprisms.Elem(i).marked = 1;
+		  marked = 1;
+		}
+	      else
+		mprisms.Elem(i).marked = 0;
+	    }
+	  
+	}
+
+
+
+      if (step == 1)
+	{
+	  if (hfac > 2)
+	    hfac /= 2;
+	  else
+	    hfac = 1;
+	}
+
+    }
+  return marked;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+void BTBisectTet (const MarkedTet & oldtet, int newp, 
+		  MarkedTet & newtet1, MarkedTet & newtet2)
+{
+  int i, j, k;
+  
+  
+  // points vis a vis from tet-edge
+  int vis1, vis2;
+  vis1 = 0;
+  while (vis1 == oldtet.tetedge1 || vis1 == oldtet.tetedge2)
+    vis1++;
+  vis2 = 6 - vis1 - oldtet.tetedge1 - oldtet.tetedge2;
+
+
+  // is tet of type P ?
+  int istypep = 0;
+  for (i = 0; i < 4; i++)
+    {
+      int cnt = 0;
+      for (j = 0; j < 4; j++)
+	if (oldtet.faceedges[j] == i)
+	  cnt++;
+      if (cnt == 3)
+	istypep = 1;
+    }
+
+
+  
+  for (i = 0; i < 4; i++)
+    {
+      newtet1.pnums[i] = oldtet.pnums[i];
+      newtet2.pnums[i] = oldtet.pnums[i];
+    }
+  newtet1.flagged = istypep && !oldtet.flagged;
+  newtet2.flagged = istypep && !oldtet.flagged;
+
+  int nm = oldtet.marked - 1;
+  if (nm < 0) nm = 0;
+  newtet1.marked = nm;
+  newtet2.marked = nm;
+
+
+  for (i = 0; i < 4; i++)
+    {
+      if (i == oldtet.tetedge1)
+	{
+	  newtet2.pnums[i] = newp;
+	  newtet2.faceedges[i] = oldtet.faceedges[i];  // inherited face
+	  newtet2.faceedges[vis1] = i;        // cut faces
+	  newtet2.faceedges[vis2] = i;
+
+	  j = 0;
+	  while (j == i || j == oldtet.faceedges[i])
+	    j++;
+	  k = 6 - i - oldtet.faceedges[i] - j;
+	  newtet2.tetedge1 = j;                        // tet-edge
+	  newtet2.tetedge2 = k;         
+
+	  // new face:
+	  if (istypep && oldtet.flagged)
+	    newtet2.faceedges[oldtet.tetedge2] = 
+	      6 - oldtet.tetedge1 - j - k;
+	  else
+	    newtet2.faceedges[oldtet.tetedge2] = oldtet.tetedge1;
+	}
+
+      if (i == oldtet.tetedge2)
+	{
+	  newtet1.pnums[i] = newp;
+	  newtet1.faceedges[i] = oldtet.faceedges[i];  // inherited face
+	  newtet1.faceedges[vis1] = i;
+	  newtet1.faceedges[vis2] = i;
+	  j = 0;
+	  while (j == i || j == oldtet.faceedges[i])
+	    j++;
+	  k = 6 - i - oldtet.faceedges[i] - j;
+	  newtet1.tetedge1 = j;        
+	  newtet1.tetedge2 = k;
+
+	  // new face:
+	  if (istypep && oldtet.flagged)
+	    newtet1.faceedges[oldtet.tetedge1] = 
+	      6 - oldtet.tetedge2 - j - k;
+	  else
+	    newtet1.faceedges[oldtet.tetedge1] = oldtet.tetedge2;
+	}
+    }
+
+  newtet1.matindex = oldtet.matindex;
+  newtet2.matindex = oldtet.matindex;
+  newtet1.incorder = 0;
+  newtet1.order = oldtet.order;
+  newtet2.incorder = 0;
+  newtet2.order = oldtet.order;
+}
+
+
+
+
+void BTBisectPrism (const MarkedPrism & oldprism, int newp1, int newp2,
+		    MarkedPrism & newprism1, MarkedPrism & newprism2)
+{
+  int i, j, k;
+
+  for (i = 0; i < 6; i++)
+    {
+      newprism1.pnums[i] = oldprism.pnums[i];
+      newprism2.pnums[i] = oldprism.pnums[i];
+    }  
+
+  int pe1, pe2;
+  pe1 = 0;
+  if (pe1 == oldprism.markededge)
+    pe1++;
+  pe2 = 3 - oldprism.markededge - pe1;
+
+  newprism1.pnums[pe2] = newp1;
+  newprism1.pnums[pe2+3] = newp2;
+  newprism1.markededge = pe2;
+  newprism2.pnums[pe1] = newp1;
+  newprism2.pnums[pe1+3] = newp2;
+  newprism2.markededge = pe1;
+
+  newprism1.matindex = oldprism.matindex;
+  newprism2.matindex = oldprism.matindex;
+
+  int nm = oldprism.marked - 1;
+  if (nm < 0) nm = 0;
+  newprism1.marked = nm;
+  newprism2.marked = nm;
+
+  newprism1.incorder = 0;
+  newprism1.order = oldprism.order;
+  newprism2.incorder = 0;
+  newprism2.order = oldprism.order;
+}
+
+
+
+void BTBisectTri (const MarkedTri & oldtri, int newp, const PointGeomInfo & newpgi,
+		  MarkedTri & newtri1, MarkedTri & newtri2)
+{
+  int i, j, k;
+
+  for (i = 0; i < 3; i++)
+    {
+      newtri1.pnums[i] = oldtri.pnums[i];
+      newtri1.pgeominfo[i] = oldtri.pgeominfo[i];
+      newtri2.pnums[i] = oldtri.pnums[i];
+      newtri2.pgeominfo[i] = oldtri.pgeominfo[i];
+    }  
+
+  int pe1, pe2;
+  pe1 = 0;
+  if (pe1 == oldtri.markededge)
+    pe1++;
+  pe2 = 3 - oldtri.markededge - pe1;
+
+  newtri1.pnums[pe2] = newp;
+  newtri1.pgeominfo[pe2] = newpgi;
+  newtri1.markededge = pe2;
+
+  newtri2.pnums[pe1] = newp;
+  newtri2.pgeominfo[pe1] = newpgi;
+  newtri2.markededge = pe1;
+
+  newtri1.surfid = oldtri.surfid;
+  newtri2.surfid = oldtri.surfid;
+
+  int nm = oldtri.marked - 1;
+  if (nm < 0) nm = 0;
+  newtri1.marked = nm;
+  newtri2.marked = nm;
+
+  newtri1.incorder = 0;
+  newtri1.order = oldtri.order;
+  newtri2.incorder = 0;
+  newtri2.order = oldtri.order;
+}
+
+
+void BTBisectQuad (const MarkedQuad & oldquad, 
+		   int newp1, const PointGeomInfo & npgi1, 
+		   int newp2, const PointGeomInfo & npgi2, 
+		   MarkedQuad & newquad1, MarkedQuad & newquad2)
+{
+  int i, j, k;
+
+  for (i = 0; i < 4; i++)
+    {
+      newquad1.pnums[i] = oldquad.pnums[i];
+      newquad1.pgeominfo[i] = oldquad.pgeominfo[i];
+      newquad2.pnums[i] = oldquad.pnums[i];
+      newquad2.pgeominfo[i] = oldquad.pgeominfo[i];
+    }  
+
+  newquad1.pnums[1] = newp1;
+  newquad1.pgeominfo[1] = npgi1;
+  newquad1.pnums[3] = newp2;
+  newquad1.pgeominfo[3] = npgi2;
+
+  newquad2.pnums[0] = newp1;
+  newquad2.pgeominfo[0] = npgi1;
+  newquad2.pnums[2] = newp2;
+  newquad2.pgeominfo[2] = npgi2;
+
+  newquad1.surfid = oldquad.surfid;
+  newquad2.surfid = oldquad.surfid;
+
+
+  int nm = oldquad.marked - 1;
+  if (nm < 0) nm = 0;
+
+  newquad1.marked = nm;
+  newquad2.marked = nm;
+}
+
+
+
+
+int MarkHangingTets (T_MTETS & mtets, 
+		     const INDEX_2_CLOSED_HASHTABLE<int> & cutedges)
+{
+  int i, j, k;
+
+  int hanging = 0;
+  for (i = 1; i <= mtets.Size(); i++)
+    {
+      MarkedTet & teti = mtets.Elem(i);
+
+      if (teti.marked)
+	{
+	  hanging = 1;
+	  continue;
+	}
+
+      for (j = 0; j < 3; j++)
+	for (k = j+1; k < 4; k++)
+	  {
+	    INDEX_2 edge(teti.pnums[j],
+			 teti.pnums[k]);
+	    edge.Sort();
+	    if (cutedges.Used (edge))
+	      {
+		teti.marked = 1;
+		hanging = 1;
+	      }
+	  }
+    }
+  return hanging;
+}
+
+
+
+int MarkHangingPrisms (T_MPRISMS & mprisms, 
+		       const INDEX_2_CLOSED_HASHTABLE<int> & cutedges)
+{
+  int i, j, k;
+
+  int hanging = 0;
+  for (i = 1; i <= mprisms.Size(); i++)
+    {
+      if (mprisms.Elem(i).marked)
+	{
+	  hanging = 1;
+	  continue;
+	}
+
+      for (j = 0; j < 2; j++)
+	for (k = j+1; k < 3; k++)
+	  {
+	    INDEX_2 edge1(mprisms.Get(i).pnums[j],
+			  mprisms.Get(i).pnums[k]);
+	    INDEX_2 edge2(mprisms.Get(i).pnums[j+3],
+			  mprisms.Get(i).pnums[k+3]);
+	    edge1.Sort();
+	    edge2.Sort();
+	    if (cutedges.Used (edge1) ||
+		cutedges.Used (edge2))
+	      {
+		mprisms.Elem(i).marked = 1;
+		hanging = 1;
+	      }
+	  }
+    }
+  return hanging;
+}
+
+
+
+int MarkHangingTris (T_MTRIS & mtris, 
+		     const INDEX_2_CLOSED_HASHTABLE<int> & cutedges)
+{
+  int i, j, k;
+
+  int hanging = 0;
+  for (i = 1; i <= mtris.Size(); i++)
+    {
+      if (mtris.Get(i).marked)
+	{
+	  hanging = 1;
+	  continue;
+	}
+      for (j = 0; j < 2; j++)
+	for (k = j+1; k < 3; k++)
+	  {
+	    INDEX_2 edge(mtris.Get(i).pnums[j],
+			 mtris.Get(i).pnums[k]);
+	    edge.Sort();
+	    if (cutedges.Used (edge))
+	      {
+		mtris.Elem(i).marked = 1;
+		hanging = 1;
+	      }
+	  }
+    }
+  return hanging;
+}
+
+
+
+int MarkHangingQuads (T_MQUADS & mquads, 
+		      const INDEX_2_CLOSED_HASHTABLE<int> & cutedges)
+{
+  int i;
+
+  int hanging = 0;
+  for (i = 1; i <= mquads.Size(); i++)
+    {
+      if (mquads.Elem(i).marked)
+	{
+	  hanging = 1;
+	  continue;
+	}
+
+      INDEX_2 edge1(mquads.Get(i).pnums[0],
+		    mquads.Get(i).pnums[1]);
+      INDEX_2 edge2(mquads.Get(i).pnums[2],
+		    mquads.Get(i).pnums[3]);
+      edge1.Sort();
+      edge2.Sort();
+      if (cutedges.Used (edge1) ||
+	  cutedges.Used (edge2))
+	{
+	  mquads.Elem(i).marked = 1;
+	  hanging = 1;
+	}
+    
+    }
+  return hanging;
+}
+
+
+
+void ConnectToNodeRec (int node, int tonode, 
+		       const TABLE<int> & conto, ARRAY<int> & connecttonode)
+{
+  int i, n2;
+  //  (*testout) << "connect " << node << " to " << tonode << endl;
+  for (i = 1; i <= conto.EntrySize(node); i++)
+    {
+      n2 = conto.Get(node, i);
+      if (!connecttonode.Get(n2))
+	{
+	  connecttonode.Elem(n2) = tonode;
+	  ConnectToNodeRec (n2, tonode, conto, connecttonode);
+	}
+    }
+}
+
+
+
+
+T_MTETS mtets;
+T_MPRISMS mprisms;
+T_MTRIS mtris;
+T_MQUADS mquads;
+
+
+
+void BisectTetsCopyMesh (Mesh & mesh, const class CSGeometry *,
+			 BisectionOptions & opt)
+{
+  mtets.SetName ("bisection, tets");
+  mprisms.SetName ("bisection, prisms");
+  mtris.SetName ("bisection, trigs");
+  mquads.SetName ("bisection, quads");
+
+  int np = mesh.GetNP();
+  int ne = mesh.GetNE();
+  int nse = mesh.GetNSE();
+  int i, j, k, l, m;
+
+  /*
+  if (mtets.Size() + mprisms.Size() == mesh.GetNE())
+    return;
+  */
+
+  mtets.SetSize(0);
+  mprisms.SetSize(0);
+  mtris.SetSize(0);
+  mquads.SetSize(0);
+
+
+  INDEX_2_HASHTABLE<int> shortedges(100);
+  for (i = 1; i <= ne; i++)
+    {
+      const Element & el = mesh.VolumeElement(i);
+      if (el.GetType() == PRISM ||
+	  el.GetType() == PRISM12)
+	{
+	  for (j = 1; j <= 3; j++)
+	    {
+	      INDEX_2 se(el.PNum(j), el.PNum(j+3));
+	      se.Sort();
+	      shortedges.Set (se, 1);
+	    }
+	}
+    }
+
+
+
+  // INDEX_2_HASHTABLE<int> edgenumber(np);
+  INDEX_2_CLOSED_HASHTABLE<int> edgenumber(9*ne+4*nse);  
+
+  BTSortEdges (mesh, edgenumber);
+  for (i = 1; i <= ne; i++)
+    {
+      const Element & el = mesh.VolumeElement(i);
+	  
+      switch (el.GetType())
+	{
+	case TET:
+	case TET10:
+	  {
+	    // if tet has short edge, it is handled as degenerated prism
+
+	    int foundse = 0;
+	    for (j = 1; j <= 3; j++)
+	      for (k = j+1; k <= 4; k++)
+		{
+		  INDEX_2 se(el.PNum(j), el.PNum(k));
+		  se.Sort();
+		  if (shortedges.Used (se))
+		    {
+		      //		      cout << "tet converted to prism" << endl;
+
+		      foundse = 1;
+		      int p3 = 1;
+		      while (p3 == j || p3 == k)
+			p3++;
+		      int p4 = 10 - j - k - p3;
+
+		      // even permutation ?
+		      int pi[4];
+		      pi[0] = j;
+		      pi[1] = k;
+		      pi[2] = p3;
+		      pi[3] = p4;
+		      int cnt = 0;
+		      for (l = 1; l <= 4; l++)
+			for (m = 0; m < 3; m++)
+			  if (pi[m] > pi[m+1])
+			    {
+			      Swap (pi[m], pi[m+1]);
+			      cnt++;
+			    }
+		      if (cnt % 2)
+			Swap (p3, p4);
+
+		      Element hel = el;
+		      hel.PNum(1) = el.PNum(j);
+		      hel.PNum(2) = el.PNum(k);
+		      hel.PNum(3) = el.PNum(p3);
+		      hel.PNum(4) = el.PNum(p4);
+
+		      MarkedPrism mp;
+		      BTDefineMarkedPrism (hel, edgenumber, mp);
+		      mp.matindex = el.GetIndex();
+		      mprisms.Append (mp);
+		    }
+		}
+	    if (!foundse)
+	      {
+		MarkedTet mt;
+		BTDefineMarkedTet (el, edgenumber, mt);
+		mt.matindex = el.GetIndex();
+		mtets.Append (mt);
+	      }
+	    break;
+	  }
+	case PYRAMID:
+	  {
+	    // eventually rotate
+	    MarkedPrism mp;
+	    
+	    INDEX_2 se(el.PNum(1), el.PNum(2));
+	    se.Sort();
+	    if (shortedges.Used (se))
+	      {
+		Element hel = el;
+		hel.PNum(1) = el.PNum(2);
+		hel.PNum(2) = el.PNum(3);
+		hel.PNum(3) = el.PNum(4);
+		hel.PNum(4) = el.PNum(1);
+		BTDefineMarkedPrism (hel, edgenumber, mp);
+	      }
+	    else
+	      {
+		BTDefineMarkedPrism (el, edgenumber, mp);
+	      }
+
+	    mp.matindex = el.GetIndex();
+	    mprisms.Append (mp);
+	    break;
+	  }
+	case PRISM:
+	case PRISM12:
+	  {
+	    MarkedPrism mp;
+	    BTDefineMarkedPrism (el, edgenumber, mp);
+	    mp.matindex = el.GetIndex();
+	    mprisms.Append (mp);
+	    break;
+	  }
+	}
+    }
+
+  for (i = 1; i <= nse; i++)
+    {
+      const Element2d & el = mesh.SurfaceElement(i);
+      if (el.GetType() == TRIG ||
+	  el.GetType() == TRIG6)
+	{
+	  MarkedTri mt;
+	  BTDefineMarkedTri (el, edgenumber, mt);
+	  mtris.Append (mt);
+	}
+      else
+	{
+	  MarkedQuad mq;
+	  BTDefineMarkedQuad (el, edgenumber, mq);
+	  mquads.Append (mq);
+	}
+    }
+
+
+
+  mesh.mlparentelement.SetSize(ne);
+  for (i = 1; i <= ne; i++)
+    mesh.mlparentelement.Elem(i) = 0;
+  mesh.mlparentsurfaceelement.SetSize(nse);
+  for (i = 1; i <= nse; i++)
+    mesh.mlparentsurfaceelement.Elem(i) = 0;
+
+
+  cout << "copied " << mtets.Size() << " tets, " << mtris.Size() << " trigs" << endl;
+}
+
+
+void Refinement :: Bisect (Mesh & mesh, 
+			   BisectionOptions & opt)
+{
+  cout << "Mesh bisection" << endl;
+
+  if (mesh.mglevels == 1)
+    BisectTetsCopyMesh(mesh, NULL, opt);
+
+  mesh.ComputeNVertices();
+  
+  int np = mesh.GetNV();
+  mesh.SetNP(np);
+
+  // int ne = mesh.GetNE();
+  // int nse = mesh.GetNSE();
+  int i, j, l;
+
+  // int initnp = np;
+  //  int maxsteps = 3;
+
+  mesh.mglevels++;
+
+  /*
+  if (opt.refinementfilename || opt.usemarkedelements)
+    maxsteps = 3;
+  */
+
+
+  // INDEX_2_HASHTABLE<int> cutedges(10 + 5 * (mtets.Size()+mprisms.Size()+mtris.Size()+mquads.Size()));
+  INDEX_2_CLOSED_HASHTABLE<int> cutedges(10 + 9 * (mtets.Size()+mprisms.Size()+mtris.Size()+mquads.Size()));
+
+  
+  for (l = 1; l <= 1; l++)
+    {
+      int marked = 0;
+      if (opt.refinementfilename)
+	{
+	  ifstream inf(opt.refinementfilename);
+	  cout << "load refinementinfo from file " << opt.refinementfilename << endl;
+	  char ch;
+	  for (i = 1; i <= mtets.Size(); i++)
+	    {
+	      inf >> ch;
+	      mtets.Elem(i).marked = (ch == '1');
+	    }
+	  marked = 1;
+	}
+
+      else if (opt.usemarkedelements)
+	{
+	  int cntm = 0;
+
+	  // all in one !
+	  if (mprisms.Size())
+	    {
+	      int cnttet = 0;
+	      int cntprism = 0;
+	      for (i = 1; i <= mesh.GetNE(); i++)
+		{
+		  if (mesh.VolumeElement(i).GetType() == TET ||
+		      mesh.VolumeElement(i).GetType() == TET10)
+		    {
+		      cnttet++;
+		      mtets.Elem(cnttet).marked = 
+			3 * mesh.VolumeElement(i).TestRefinementFlag();
+		      if (mtets.Elem(cnttet).marked)
+			cntm++;
+		    }
+		  else
+		    {
+		      cntprism++;
+		      mprisms.Elem(cntprism).marked = 
+			2 * mesh.VolumeElement(i).TestRefinementFlag();
+		      if (mprisms.Elem(cntprism).marked)
+			cntm++; 
+		    }
+		    
+		}
+	    }
+	  else
+	    for (i = 1; i <= mtets.Size(); i++)
+	      {
+		mtets.Elem(i).marked = 
+		  3 * mesh.VolumeElement(i).TestRefinementFlag();
+		if (mtets.Elem(i).marked)
+		  cntm++;
+	      }
+
+	  // (*testout) << "mtets = " << mtets << endl;
+
+	  /*
+	  for (i = 1; i <= mtris.Size(); i++)
+	    mtris.Elem(i).marked = 0;
+	  for (i = 1; i <= mquads.Size(); i++)
+	    mquads.Elem(i).marked = 0;
+	    */
+
+	  cout << "marked elements: " << cntm << endl;
+
+	  int cnttrig = 0;
+	  int cntquad = 0;
+	  for (i = 1; i <= mesh.GetNSE(); i++)
+	    {
+	      if (mesh.SurfaceElement(i).GetType() == TRIG ||
+		  mesh.SurfaceElement(i).GetType() == TRIG6)
+		{
+		  cnttrig++;
+		  mtris.Elem(cnttrig).marked = 
+		    2*mesh.SurfaceElement(i).TestRefinementFlag();
+		  // mtris.Elem(cnttrig).marked = 0;
+		  if (mtris.Elem(cnttrig).marked)
+		    cntm++;
+		}
+	      else
+		{
+		  cntquad++;
+		  mquads.Elem(cntquad).marked = 
+		    mesh.SurfaceElement(i).TestRefinementFlag();
+		  // mquads.Elem(cntquad).marked = 0;
+		  if (mquads.Elem(cntquad).marked)
+		    cntm++;
+		}
+	    }
+
+	  cout << "with surface-elements: " << cntm << endl;
+
+	  if (mesh.GetDimension() == 2)
+	    {
+	      cntm = 0;
+	      for (i = 1; i <= mtris.Size(); i++)
+		{
+		  mtris.Elem(i).marked = 
+		    2 * mesh.SurfaceElement(i).TestRefinementFlag();
+		  //		  mtris.Elem(i).marked = 2;
+		  if (mtris.Elem(i).marked)
+		    cntm++;
+		}
+	      
+	      if (!cntm)
+		{
+		  for (i = 1; i <= mtris.Size(); i++)
+		    {
+		      mtris.Elem(i).marked = 2;
+		      cntm++;
+		    }
+		}
+	      cout << "trigs: " << mtris.Size() << " ";
+	      cout << "marked: " << cntm << endl;
+	    }
+
+	  marked = (cntm > 0);
+	}
+      else
+	{
+	  marked = BTMarkTets (mtets, mprisms, mesh);
+	}
+
+      if (!marked) break;
+
+
+
+	  if (opt.refine_hp)
+	    {
+	      cout << "refine hp" << endl;
+	      BitArray singv(np);
+	      singv.Clear();
+	      
+	      if (mesh.GetDimension() == 3)
+		for (i = 1; i <= mesh.GetNSeg(); i++)
+		  {
+		    const Segment & seg = mesh.LineSegment(i);
+		    singv.Set (seg.p1);
+		    singv.Set (seg.p2);
+		  }
+	      else
+		{
+		  // vertices with 2 different bnds
+		  ARRAY<int> bndind(np);
+		  bndind = 0;
+		  for (i = 1; i <= mesh.GetNSeg(); i++)
+		    {
+		      const Segment & seg = mesh.LineSegment(i);
+		      for (int j = 0; j < 2; j++)
+			{
+			  int pi = (j == 0) ? seg.p1 : seg.p2;
+			  if (bndind.Elem(pi) == 0)
+			    bndind.Elem(pi) = seg.edgenr;
+			  else if (bndind.Elem(pi) != seg.edgenr)
+			    singv.Set (pi);
+			}
+		    }
+		}
+		
+
+
+	      for (i = 1; i <= mtets.Size(); i++)
+		mtets.Elem(i).incorder = 1;
+	      for (i = 1; i <= mtets.Size(); i++)
+		{
+		  if (!mtets.Elem(i).marked)
+		    mtets.Elem(i).incorder = 0;
+		  for (j = 0; j < 4; j++)
+		    if (singv.Test (mtets.Elem(i).pnums[j]))
+		      mtets.Elem(i).incorder = 0;
+		}
+	      for (i = 1; i <= mtets.Size(); i++)
+		if (mtets.Elem(i).incorder)
+		  mtets.Elem(i).marked = 0;
+
+
+	      for (i = 1; i <= mprisms.Size(); i++)
+		mprisms.Elem(i).incorder = 1;
+	      for (i = 1; i <= mprisms.Size(); i++)
+		{
+		  if (!mprisms.Elem(i).marked)
+		    mprisms.Elem(i).incorder = 0;
+		  for (j = 0; j < 6; j++)
+		    if (singv.Test (mprisms.Elem(i).pnums[j]))
+		      mprisms.Elem(i).incorder = 0;
+		}
+	      for (i = 1; i <= mprisms.Size(); i++)
+		if (mprisms.Elem(i).incorder)
+		  mprisms.Elem(i).marked = 0;
+
+
+	      for (i = 1; i <= mtris.Size(); i++)
+		mtris.Elem(i).incorder = 1;
+	      for (i = 1; i <= mtris.Size(); i++)
+		{
+		  if (!mtris.Elem(i).marked)
+		    mtris.Elem(i).incorder = 0;
+		  for (j = 0; j < 3; j++)
+		    if (singv.Test (mtris.Elem(i).pnums[j]))
+		      mtris.Elem(i).incorder = 0;
+		}
+	      for (i = 1; i <= mtris.Size(); i++)
+		{
+		  if (mtris.Elem(i).incorder)
+		    mtris.Elem(i).marked = 0;
+		}
+	    }
+
+
+
+
+
+      int hangingvol, hangingsurf, hangingedge;
+
+      do
+	{
+	  // refine volume elements
+
+	  int nel = mtets.Size();
+	  for (i = 1; i <= nel; i++)
+	    if (mtets.Elem(i).marked)
+	      {
+		MarkedTet oldtet;
+		MarkedTet newtet1, newtet2;
+		int newp;
+
+
+		oldtet = mtets.Get(i);
+		INDEX_2 edge(oldtet.pnums[oldtet.tetedge1],
+			     oldtet.pnums[oldtet.tetedge2]);
+		edge.Sort();
+		if (cutedges.Used (edge))
+		  {
+		    newp = cutedges.Get(edge);
+		  }
+		else
+		  {
+		    Point3d np = Center (mesh.Point (edge.I1()),
+					 mesh.Point (edge.I2()));
+		    newp = mesh.AddPoint (np);
+		    cutedges.Set (edge, newp);
+		  }
+
+		BTBisectTet (oldtet, newp, newtet1, newtet2);
+		mtets.Elem(i) = newtet1;
+		mtets.Append (newtet2);
+	      }
+
+	  int npr = mprisms.Size();
+	  for (i = 1; i <= npr; i++)
+	    if (mprisms.Elem(i).marked)
+	      {
+		MarkedPrism oldprism;
+		MarkedPrism newprism1, newprism2;
+		int newp1, newp2;
+
+		oldprism = mprisms.Get(i);
+		int pi1 = 0;
+		if (pi1 == oldprism.markededge)
+		  pi1++;
+		int pi2 = 3-pi1-oldprism.markededge;
+
+		INDEX_2 edge1(oldprism.pnums[pi1],
+			      oldprism.pnums[pi2]);
+		INDEX_2 edge2(oldprism.pnums[pi1+3],
+			      oldprism.pnums[pi2+3]);
+		edge1.Sort();
+		edge2.Sort();
+
+		if (cutedges.Used (edge1))
+		  newp1 = cutedges.Get(edge1);
+		else
+		  {
+		    Point3d np = Center (mesh.Point (edge1.I1()),
+					 mesh.Point (edge1.I2()));
+		    newp1 = mesh.AddPoint (np);
+		    cutedges.Set (edge1, newp1);
+		  }
+		if (cutedges.Used (edge2))
+		  newp2 = cutedges.Get(edge2);
+		else
+		  {
+		    Point3d np = Center (mesh.Point (edge2.I1()),
+					 mesh.Point (edge2.I2()));
+		    newp2 = mesh.AddPoint (np);
+		    cutedges.Set (edge2, newp2);
+		  }
+		
+
+		BTBisectPrism (oldprism, newp1, newp2, newprism1, newprism2);
+		mprisms.Elem(i) = newprism1;
+		mprisms.Append (newprism2);
+	      }
+
+
+	  hangingvol = 
+	    MarkHangingTets (mtets, cutedges) +
+	    MarkHangingPrisms (mprisms, cutedges);
+
+
+	  int nsel = mtris.Size();
+
+	  for (i = 1; i <= nsel; i++)
+	    if (mtris.Elem(i).marked)
+	      {
+		MarkedTri oldtri;
+		MarkedTri newtri1, newtri2;
+		int newp;
+		
+		oldtri = mtris.Get(i);
+		int oldpi1 = oldtri.pnums[(oldtri.markededge+1)%3];
+		int oldpi2 = oldtri.pnums[(oldtri.markededge+2)%3];
+		INDEX_2 edge(oldpi1, oldpi2);
+		edge.Sort();
+
+		//		cerr << "edge = " << edge.I1() << "-" << edge.I2() << endl;
+
+		if (cutedges.Used (edge))
+		  {
+		    newp = cutedges.Get(edge);
+		  }
+		else
+		  {
+		    Point3d np = Center (mesh.Point (edge.I1()),
+					 mesh.Point (edge.I2()));
+		    newp = mesh.AddPoint (np);
+		    cutedges.Set (edge, newp);
+		  }
+		//		newp = cutedges.Get(edge);
+		
+		int si = mesh.GetFaceDescriptor (oldtri.surfid).SurfNr();
+		//  geom->GetSurface(si)->Project (mesh.Point(newp));
+		PointGeomInfo npgi;
+		
+		if (mesh.PointType(newp) != EDGEPOINT)
+		  PointBetween (mesh.Point (oldpi1), mesh.Point (oldpi2),
+				0.5, si,
+				oldtri.pgeominfo[(oldtri.markededge+1)%3],
+				oldtri.pgeominfo[(oldtri.markededge+2)%3],
+				mesh.Point (newp), npgi);
+		
+		BTBisectTri (oldtri, newp, npgi, newtri1, newtri2);
+		
+		
+		mtris.Elem(i) = newtri1;
+		mtris.Append (newtri2);
+		mesh.mlparentsurfaceelement.Append (i);
+	      }
+	  
+	  int nquad = mquads.Size();
+	  for (i = 1; i <= nquad; i++)
+	    if (mquads.Elem(i).marked)
+	      {
+		MarkedQuad oldquad;
+		MarkedQuad newquad1, newquad2;
+		int newp1, newp2;
+		
+		oldquad = mquads.Get(i);
+		INDEX_2 edge1(oldquad.pnums[0],
+			      oldquad.pnums[1]);
+		INDEX_2 edge2(oldquad.pnums[2],
+			      oldquad.pnums[3]);
+		edge1.Sort();
+		edge2.Sort();
+
+		if (cutedges.Used (edge1))
+		  {
+		    newp1 = cutedges.Get(edge1);
+		  }
+		else
+		  {
+		    Point3d np = Center (mesh.Point (edge1.I1()),
+					 mesh.Point (edge1.I2()));
+		    newp1 = mesh.AddPoint (np);
+		    cutedges.Set (edge1, newp1);
+		  }
+
+		if (cutedges.Used (edge2))
+		  {
+		    newp2 = cutedges.Get(edge2);
+		  }
+		else
+		  {
+		    Point3d np = Center (mesh.Point (edge2.I1()),
+					 mesh.Point (edge2.I2()));
+		    newp2 = mesh.AddPoint (np);
+		    cutedges.Set (edge2, newp2);
+		  }
+
+		PointGeomInfo npgi1, npgi2;
+		
+		int si = mesh.GetFaceDescriptor (oldquad.surfid).SurfNr();
+		//		geom->GetSurface(si)->Project (mesh.Point(newp1));
+		//		geom->GetSurface(si)->Project (mesh.Point(newp2));
+
+		(*testout) << "project point " << newp1 << " old: " << mesh.Point(newp1);
+		PointBetween (mesh.Point (edge1.I1()), mesh.Point (edge1.I2()),
+			      0.5, si,
+			      oldquad.pgeominfo[0],
+			      oldquad.pgeominfo[1],
+			      mesh.Point (newp1), npgi1);
+		(*testout) << " new: " << mesh.Point(newp1) << endl;
+
+		
+		PointBetween (mesh.Point (edge2.I1()), mesh.Point (edge2.I2()),
+			      0.5, si,
+			      oldquad.pgeominfo[2],
+			      oldquad.pgeominfo[3],
+			      mesh.Point (newp2), npgi2);
+		
+
+		BTBisectQuad (oldquad, newp1, npgi1, newp2, npgi2,
+			      newquad1, newquad2);
+		mquads.Elem(i) = newquad1;
+		mquads.Append (newquad2);
+	      }
+	  
+
+	  hangingsurf = 
+	    MarkHangingTris (mtris, cutedges) +
+	    MarkHangingQuads (mquads, cutedges);
+
+	  hangingedge = 0;
+	  
+	  int nseg = mesh.GetNSeg ();
+	  for (i = 1; i <= nseg; i++)
+	    {
+	      Segment & seg = mesh.LineSegment (i);
+	      INDEX_2 edge(seg.p1, seg.p2);
+	      edge.Sort();
+	      if (cutedges.Used (edge))
+		{
+		  hangingedge = 1;
+		  Segment nseg1 = seg;
+		  Segment nseg2 = seg;
+		  
+		  int newpi = cutedges.Get(edge);
+		  
+		  nseg1.p2 = newpi;
+		  nseg2.p1 = newpi;
+		  
+		  EdgePointGeomInfo newepgi;
+		  
+		  //		  (*testout) << "move edgepoint " << newpi << " from " << mesh.Point(newpi);
+		  PointBetween (mesh.Point (seg.p1), mesh.Point (seg.p2),
+				0.5, seg.surfnr1, seg.surfnr2, 
+				seg.epgeominfo[0], seg.epgeominfo[1],
+				mesh.Point (newpi), newepgi);
+		  //		  (*testout) << " to " << mesh.Point (newpi) << endl;
+		  nseg1.epgeominfo[1] = newepgi;
+		  nseg2.epgeominfo[0] = newepgi;
+		  
+		  mesh.LineSegment (i) = nseg1;
+		  mesh.AddSegment (nseg2);
+		}
+	    }
+
+	}
+      while (hangingvol || hangingsurf || hangingedge);
+      
+      
+      cout << mtets.Size() << " tets" << endl;
+      cout << mtris.Size() << " trigs" << endl;
+      if (mprisms.Size())
+	{
+	  cout << mprisms.Size() << " prisms" << endl;
+	  cout << mquads.Size() << " quads" << endl;
+	}
+      cout << mesh.GetNP() << " points" << endl;
+    }
+
+  /*
+  cout << "mem in mtets: " << endl;
+  mtets.PrintMemInfo(cout);
+  cout << "cutedges" << endl;
+  cutedges.PrintMemInfo(cout);
+  */
+
+  // (*testout) << "mtets = " << mtets << endl;
+
+  if (opt.refine_hp)
+    {
+      //
+      ARRAY<int> v_order (mesh.GetNP());
+      v_order = 0;
+      if (mesh.GetDimension() == 3)
+	{
+	  for (i = 1; i <= mtets.Size(); i++)
+	    if (mtets.Elem(i).incorder)
+	      mtets.Elem(i).order++;
+      
+	  for (i = 0; i < mtets.Size(); i++)
+	    for (j = 0; j < 4; j++)
+	    if (mtets[i].order > v_order.Elem(mtets[i].pnums[j]))
+	      v_order.Elem(mtets[i].pnums[j]) = mtets[i].order;
+	  for (i = 0; i < mtets.Size(); i++)
+	    for (j = 0; j < 4; j++)
+	      if (mtets[i].order < v_order.Elem(mtets[i].pnums[j])-1)
+		mtets[i].order = v_order.Elem(mtets[i].pnums[j])-1;
+	}
+      else
+	{
+	  for (i = 1; i <= mtris.Size(); i++)
+	    if (mtris.Elem(i).incorder)
+	      {
+		mtris.Elem(i).order++;
+	      }
+
+	  for (i = 0; i < mtris.Size(); i++)
+	    for (j = 0; j < 3; j++)
+	      if (mtris[i].order > v_order.Elem(mtris[i].pnums[j]))
+		v_order.Elem(mtris[i].pnums[j]) = mtris[i].order;
+	  for (i = 0; i < mtris.Size(); i++)
+	    {
+	      for (j = 0; j < 3; j++)
+		if (mtris[i].order < v_order.Elem(mtris[i].pnums[j])-1)
+		  mtris[i].order = v_order.Elem(mtris[i].pnums[j])-1;
+	    }
+	}
+    }
+  
+  mtets.SetAllocSize (mtets.Size());
+  mprisms.SetAllocSize (mprisms.Size());
+  mtris.SetAllocSize (mtris.Size());
+  mquads.SetAllocSize (mquads.Size());
+  
+  
+  mesh.ClearVolumeElements();
+  mesh.VolumeElements().SetAllocSize (mtets.Size()+mprisms.Size());
+  for (i = 1; i <= mtets.Size(); i++)
+    {
+      Element el(TET);
+      el.SetIndex (mtets.Get(i).matindex);
+      for (j = 1; j <= 4; j++)
+	el.PNum(j) = mtets.Get(i).pnums[j-1];
+      el.SetOrder (mtets.Get(i).order);
+      mesh.AddVolumeElement (el);
+    }
+  for (i = 1; i <= mprisms.Size(); i++)
+    {
+      Element el(PRISM);
+      el.SetIndex (mprisms.Get(i).matindex);
+      for (j = 1; j <= 6; j++)
+	el.PNum(j) = mprisms.Get(i).pnums[j-1];
+      el.SetOrder (mprisms.Get(i).order);
+
+      // degenerated prism ?
+      static const int map1[] = { 3, 2, 5, 6, 1 };
+      static const int map2[] = { 1, 3, 6, 4, 2 };
+      static const int map3[] = { 2, 1, 4, 5, 3 };
+      
+
+      const int * map = NULL;
+      int deg1 = 0, deg2 = 0, deg3 = 0;
+      // int deg = 0;
+      if (el.PNum(1) == el.PNum(4)) { map = map1; deg1 = 1; }
+      if (el.PNum(2) == el.PNum(5)) { map = map2; deg2 = 1; }
+      if (el.PNum(3) == el.PNum(6)) { map = map3; deg3 = 1; }
+	  
+      switch (deg1+deg2+deg3)
+	{
+	case 1:
+	  {
+	    for (j = 1; j <= 5; j++)
+	      el.PNum(j) = mprisms.Get(i).pnums[map[j-1]-1];
+	    
+	    el.SetType (PYRAMID);
+	    break;
+	  }
+	case 2:
+	  {
+	    static const int tetmap1[] = { 1, 2, 3, 4 };
+	    static const int tetmap2[] = { 2, 3, 1, 5 };
+	    static const int tetmap3[] = { 3, 1, 2, 6 };
+	    if (!deg1) map = tetmap1;
+	    if (!deg2) map = tetmap2;
+	    if (!deg3) map = tetmap3; 
+	    for (j = 1; j <= 4; j++)
+	      el.PNum(j) = mprisms.Get(i).pnums[map[j-1]-1];
+	    /*
+	    if (!deg1) el.PNum(4) = el.PNum(4);
+	    if (!deg2) el.PNum(4) = el.PNum(5);
+	    if (!deg3) el.PNum(4) = el.PNum(6);
+	    */
+	    el.SetType(TET);
+	    break;
+	  }
+	default:
+	  ;
+	}
+      mesh.AddVolumeElement (el);
+    }
+  
+  mesh.ClearSurfaceElements();
+  for (i = 1; i <= mtris.Size(); i++)
+    {
+      Element2d el(TRIG);
+      el.SetIndex (mtris.Get(i).surfid);
+      el.SetOrder (mtris.Get(i).order);
+      for (j = 1; j <= 3; j++)
+	{
+	  el.PNum(j) = mtris.Get(i).pnums[j-1];
+	  el.GeomInfoPi(j) = mtris.Get(i).pgeominfo[j-1];
+	}
+      mesh.AddSurfaceElement (el);
+    }
+  for (i = 1; i <= mquads.Size(); i++)
+    {
+      Element2d el(QUAD);
+      el.SetIndex (mquads.Get(i).surfid);
+      for (j = 1; j <= 4; j++)
+	el.PNum(j) = mquads.Get(i).pnums[j-1];
+      Swap (el.PNum(3), el.PNum(4));
+      mesh.AddSurfaceElement (el);
+    }
+
+
+      
+  // write multilevel hierarchy to mesh:
+  np = mesh.GetNP();
+  mesh.mlbetweennodes.SetSize(np);
+  if (mesh.mglevels <= 2)
+    for (i = 1; i <= np; i++)
+      {
+	mesh.mlbetweennodes.Elem(i).I1() = 0;
+	mesh.mlbetweennodes.Elem(i).I2() = 0;
+      }
+
+  /*
+  for (i = 1; i <= cutedges.GetNBags(); i++)
+    for (j = 1; j <= cutedges.GetBagSize(i); j++)
+      {
+	INDEX_2 edge;
+	int newpi;
+	cutedges.GetData (i, j, edge, newpi);
+	mesh.mlbetweennodes.Elem(newpi) = edge;
+      }
+  */
+  for (i = 1; i <= cutedges.Size(); i++)
+    if (cutedges.UsedPos(i))
+      {
+	INDEX_2 edge;
+	int newpi;
+	cutedges.GetData (i, edge, newpi);
+	mesh.mlbetweennodes.Elem(newpi) = edge;
+      }
+
+
+  /*
+  mesh.PrintMemInfo (cout);
+  cout << "tets ";
+  mtets.PrintMemInfo (cout);
+  cout << "prims ";
+  mprisms.PrintMemInfo (cout);
+  cout << "tris ";
+  mtris.PrintMemInfo (cout);
+  cout << "quads ";
+  mquads.PrintMemInfo (cout);
+  cout << "cutedges ";
+  cutedges.PrintMemInfo (cout);
+  */
+
+
+  /*
+
+  // find connected nodes (close nodes)
+  TABLE<int> conto(np);
+  for (i = 1; i <= mprisms.Size(); i++)
+    for (j = 1; j <= 6; j++)
+      {
+	int n1 = mprisms.Get(i).pnums[j-1];
+	int n2 = mprisms.Get(i).pnums[(j+2)%6];
+	//	    if (n1 != n2)
+	{
+	  int found = 0;
+	  for (k = 1; k <= conto.EntrySize(n1); k++)
+	    if (conto.Get(n1, k) == n2)
+	      {
+		found = 1;
+		break;
+	      }
+	  if (!found)
+	    conto.Add (n1, n2);
+	}
+      }
+  mesh.connectedtonode.SetSize(np);
+  for (i = 1; i <= np; i++)
+    mesh.connectedtonode.Elem(i) = 0;
+  
+
+//       (*testout) << "connection table: " << endl;
+//       for (i = 1; i <= np; i++)
+//       {
+//       (*testout) << "node " << i << ": ";
+// 	  for (j = 1; j <= conto.EntrySize(i); j++)
+// 	  (*testout) << conto.Get(i, j) << " ";
+// 	  (*testout) << endl;
+// 	}
+
+  
+  for (i = 1; i <= np; i++)
+    if (mesh.connectedtonode.Elem(i) == 0)
+      {
+	mesh.connectedtonode.Elem(i) = i;
+	ConnectToNodeRec (i, i, conto, mesh.connectedtonode);
+      }
+*/  
+
+  //  mesh.BuildConnectedNodes();
+
+  mesh.ComputeNVertices();
+  mesh.UpdateTopology();
+
+  // update identification tables
+  for (i = 1; i <= mesh.GetIdentifications().GetMaxNr(); i++)
+    {
+      ARRAY<int,PointIndex::BASE> identmap;
+      mesh.GetIdentifications().GetMap (i, identmap);
+
+
+      /*
+      for (j = 1; j <= cutedges.GetNBags(); j++)
+	for (k = 1; k <= cutedges.GetBagSize(j); k++)
+	  {
+	    INDEX_2 i2;
+	    int newpi;
+	    cutedges.GetData (j, k, i2, newpi);
+	    INDEX_2 oi2(identmap.Get(i2.I1()),
+			identmap.Get(i2.I2()));
+	    oi2.Sort();
+	    if (cutedges.Used (oi2))
+	      {
+		int onewpi = cutedges.Get(oi2);
+		mesh.GetIdentifications().Add (newpi, onewpi, i);
+	      }
+	  }
+      */
+
+      for (j = 1; j <= cutedges.Size(); j++)
+	if (cutedges.UsedPos(j))
+	  {
+	    INDEX_2 i2;
+	    int newpi;
+	    cutedges.GetData (j, i2, newpi);
+	    INDEX_2 oi2(identmap.Get(i2.I1()),
+			identmap.Get(i2.I2()));
+	    oi2.Sort();
+	    if (cutedges.Used (oi2))
+	      {
+		int onewpi = cutedges.Get(oi2);
+		mesh.GetIdentifications().Add (newpi, onewpi, i);
+	      }
+	  }
+
+    }
+  PrintMessage (5, "Bisection done");
+}
+
+
+
+
+BisectionOptions :: BisectionOptions ()
+{
+  outfilename = NULL;
+  mlfilename = NULL;
+  refinementfilename = NULL;
+  femcode = NULL;
+  maxlevel = 50;
+  usemarkedelements = 0;
+  refine_hp = 0;
+}
+
+
+
+void Refinement :: PointBetween (const Point3d & p1, const Point3d & p2, double secpoint,
+				 int surfi, 
+				 const PointGeomInfo & gi1, 
+				 const PointGeomInfo & gi2,
+				 Point3d & newp, PointGeomInfo & newgi)
+{
+  newp = p1+secpoint*(p2-p1);
+}
+
+void Refinement :: PointBetween (const Point3d & p1, const Point3d & p2, double secpoint,
+				 int surfi1, int surfi2, 
+				 const EdgePointGeomInfo & ap1, 
+				 const EdgePointGeomInfo & ap2,
+				 Point3d & newp, EdgePointGeomInfo & newgi)
+{
+  newp = p1+secpoint*(p2-p1);
+}
+
+void Refinement :: ProjectToSurface (Point<3> & p, int surfi)
+{
+  cout << "Refinement :: ProjectToSurface    ERROR: no geometry set" << endl;
+};
+
+
+}
diff --git a/Netgen/libsrc/meshing/bisect.hpp b/Netgen/libsrc/meshing/bisect.hpp
new file mode 100644
index 0000000000..2d8988de0e
--- /dev/null
+++ b/Netgen/libsrc/meshing/bisect.hpp
@@ -0,0 +1,71 @@
+#ifndef BISECT
+#define BISECT
+
+class BisectionOptions
+{
+public:
+  const char * outfilename;
+  const char * mlfilename;
+  const char * refinementfilename;
+  const char * femcode;
+  int maxlevel;
+  int usemarkedelements;
+  bool refine_hp;
+  BisectionOptions ();
+};
+
+class ZRefinementOptions
+{
+public:
+  int minref;
+  ZRefinementOptions();
+};
+
+
+/*
+extern void BisectTets (Mesh &, const CSGeometry *,
+			BisectionOptions & opt);
+*/
+
+extern void BisectTetsCopyMesh (Mesh &, const class CSGeometry *,
+				BisectionOptions & opt);
+
+extern void ZRefinement (Mesh &, const CSGeometry *,
+			 ZRefinementOptions & opt);
+
+
+
+
+
+class Refinement
+{
+public:
+  Refinement ();
+  virtual ~Refinement ();
+  
+  void Refine (Mesh & mesh, int levels);
+  void Bisect (Mesh & mesh, class BisectionOptions & opt);
+  void MakeSecondOrder (Mesh & mesh);
+
+  virtual void PointBetween (const Point3d & p1, const Point3d & p2, double secpoint, 
+			     int surfi, 
+			     const PointGeomInfo & gi1, 
+			     const PointGeomInfo & gi2,
+			     Point3d & newp, PointGeomInfo & newgi);
+
+  virtual void PointBetween (const Point3d & p1, const Point3d & p2, double secpoint,
+			     int surfi1, int surfi2, 
+			     const EdgePointGeomInfo & ap1, 
+			     const EdgePointGeomInfo & ap2,
+			     Point3d & newp, EdgePointGeomInfo & newgi);
+
+  virtual void ProjectToSurface (Point<3> & p, int surfi);
+
+
+  void ValidateSecondOrder (Mesh & mesh);
+  void ValidateRefinedMesh (Mesh & mesh, 
+			    ARRAY<INDEX_2> & parents);
+
+};
+
+#endif
diff --git a/Netgen/libsrc/meshing/boundarylayer.cpp b/Netgen/libsrc/meshing/boundarylayer.cpp
new file mode 100644
index 0000000000..6f564586b6
--- /dev/null
+++ b/Netgen/libsrc/meshing/boundarylayer.cpp
@@ -0,0 +1,91 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+namespace netgen
+{
+
+void InsertVirtualBoundaryLayer (Mesh & mesh)
+{
+  cout << "Insert virt. b.l." << endl;
+  
+  int surfid;
+
+  cout << "Boundary Nr:";
+  cin >> surfid;
+
+  int i, j;
+  int np = mesh.GetNP();
+
+  cout << "Old NP: " << mesh.GetNP() << endl;
+  cout << "Trigs: " << mesh.GetNSE() << endl;
+
+  BitArray bndnodes(np);
+  ARRAY<int> mapto(np);
+
+  bndnodes.Clear();
+  for (i = 1; i <= mesh.GetNSeg(); i++)
+    {
+      int snr = mesh.LineSegment(i).edgenr;
+      cout << "snr = " << snr << endl;
+      if (snr == surfid)
+	{
+	  bndnodes.Set (mesh.LineSegment(i).p1);
+	  bndnodes.Set (mesh.LineSegment(i).p2);
+	}
+    }
+  for (i = 1; i <= mesh.GetNSeg(); i++)
+    {
+      int snr = mesh.LineSegment(i).edgenr;
+      if (snr != surfid)
+	{
+	  bndnodes.Clear (mesh.LineSegment(i).p1);
+	  bndnodes.Clear (mesh.LineSegment(i).p2);
+	}
+    }
+  
+  for (i = 1; i <= np; i++)
+    {
+      if (bndnodes.Test(i))
+	mapto.Elem(i) = mesh.AddPoint (mesh.Point (i));
+      else
+	mapto.Elem(i) = 0;
+    }
+
+  for (i = 1; i <= mesh.GetNSE(); i++)
+    {
+      Element2d & el = mesh.SurfaceElement(i);
+      for (j = 1; j <= el.GetNP(); j++)
+	if (mapto.Get(el.PNum(j)))
+	  el.PNum(j) = mapto.Get(el.PNum(j));
+    }
+
+
+  int nq = 0;
+  for (i = 1; i <= mesh.GetNSeg(); i++)
+    {
+      int snr = mesh.LineSegment(i).edgenr;
+      if (snr == surfid)
+	{
+	  int p1 = mesh.LineSegment(i).p1;
+	  int p2 = mesh.LineSegment(i).p2;
+	  int p3 = mapto.Get (p1);
+	  if (!p3) p3 = p1;
+	  int p4 = mapto.Get (p2);
+	  if (!p4) p4 = p2;
+	  
+	  Element2d el(4);
+	  el.PNum(1) = p1;
+	  el.PNum(2) = p2;
+	  el.PNum(3) = p3;
+	  el.PNum(4) = p4;
+	  el.SetIndex (2);
+	  mesh.AddSurfaceElement (el);
+	  nq++;
+	}
+    }
+
+  cout << "New NP: " << mesh.GetNP() << endl;
+  cout << "Quads: " << nq << endl;
+}
+
+}
diff --git a/Netgen/libsrc/meshing/boundarylayer.hpp b/Netgen/libsrc/meshing/boundarylayer.hpp
new file mode 100644
index 0000000000..e5a047b6bb
--- /dev/null
+++ b/Netgen/libsrc/meshing/boundarylayer.hpp
@@ -0,0 +1,9 @@
+#ifndef FILE_BOUNDARYLAYER
+#define FILE_BOUNDARYLAYER
+
+
+///
+extern void InsertVirtualBoundaryLayer (Mesh & mesh);
+
+
+#endif
diff --git a/Netgen/libsrc/meshing/clusters.cpp b/Netgen/libsrc/meshing/clusters.cpp
new file mode 100644
index 0000000000..ed76676746
--- /dev/null
+++ b/Netgen/libsrc/meshing/clusters.cpp
@@ -0,0 +1,253 @@
+#include <mystdlib.h>
+
+#include "meshing.hpp"
+
+namespace netgen
+{
+
+AnisotropicClusters ::  AnisotropicClusters (const Mesh & amesh)
+  : mesh(amesh)
+{
+  ;
+}
+
+AnisotropicClusters ::  ~AnisotropicClusters ()
+{
+  ;
+}
+
+void AnisotropicClusters ::  Update()
+{
+  int i, j, k;
+
+  const MeshTopology & top = mesh.GetTopology();
+  if (!top.HasEdges())
+    return;
+
+  PrintMessage (3, "Update Clusters");
+
+  nv = mesh.GetNV();
+  ned = top.GetNEdges();
+  nfa = top.GetNFaces();
+  ne = mesh.GetNE();
+  int nse = mesh.GetNSE();
+
+  cluster_reps.SetSize (nv+ned+nfa+ne);
+  
+  ARRAY<int> nnums, ednums, fanums;
+  int changed;
+
+  for (i = 1; i <= cluster_reps.Size(); i++)
+    cluster_reps.Elem(i) = i;
+
+  for (i = 1; i <= cluster_reps.Size(); i++)
+    cluster_reps.Elem(i) = -1;
+
+  for (i = 1; i <= ne; i++)
+    {
+      const Element & el = mesh.VolumeElement(i);
+      ELEMENT_TYPE typ = el.GetType();
+      
+      top.GetElementEdges (i, ednums);
+      top.GetElementFaces (i, fanums);
+      
+      int elnv = top.GetNVertices (typ);
+      int elned = ednums.Size();
+      int elnfa = fanums.Size();
+	  
+      nnums.SetSize(elnv+elned+elnfa+1);
+      for (j = 1; j <= elnv; j++)
+	nnums.Elem(j) = el.PNum(j);
+      for (j = 1; j <= elned; j++)
+	nnums.Elem(elnv+j) = nv+ednums.Elem(j);
+      for (j = 1; j <= elnfa; j++)
+	nnums.Elem(elnv+elned+j) = nv+ned+fanums.Elem(j);
+      nnums.Elem(elnv+elned+elnfa+1) = nv+ned+nfa+i;
+
+      for (j = 0; j < nnums.Size(); j++)
+	cluster_reps.Elem(nnums[j]) = nnums[j];
+    }
+
+
+  for (i = 1; i <= nse; i++)
+    {
+      const Element2d & el = mesh.SurfaceElement(i);
+      ELEMENT_TYPE typ = el.GetType();
+      
+      top.GetSurfaceElementEdges (i, ednums);
+      int fanum = top.GetSurfaceElementFace (i);
+      
+      int elnv = top.GetNVertices (typ);
+      int elned = ednums.Size();
+	  
+      nnums.SetSize(elnv+elned+1);
+      for (j = 1; j <= elnv; j++)
+	nnums.Elem(j) = el.PNum(j);
+      for (j = 1; j <= elned; j++)
+	nnums.Elem(elnv+j) = nv+ednums.Elem(j);
+      nnums.Elem(elnv+elned+1) = fanum;
+
+      for (j = 0; j < nnums.Size(); j++)
+	cluster_reps.Elem(nnums[j]) = nnums[j];
+    }
+
+
+
+
+
+  static const int prism_cluster[] =
+    { 
+      1, 2, 3, 1, 2, 3,
+      4, 5, 6, 4, 5, 6, 3, 1, 2,
+      7, 7, 4, 5, 6, 
+      7
+    };
+  static const int pyramid_cluster[] =
+    { 
+      1, 2, 2, 1, 3,
+      4, 2, 1, 4, 6, 5, 5, 6,
+      7, 5, 7, 6, 4, 
+      7
+    };
+  static const int tet_cluster14[] =
+    { 1, 2, 3, 1,   1, 4, 5, 4, 5, 6,   7, 5, 4, 7, 7 };
+  
+  static const int tet_cluster12[] =
+    { 1, 1, 2, 3,   4, 4, 5, 1, 6, 6,   7, 7, 4, 6, 7 };
+
+  static const int tet_cluster13[] =
+    { 1, 2, 1, 3,   4, 6, 4, 5, 1, 5,   7, 4, 7, 5, 7 };
+
+  static const int tet_cluster23[] =
+    { 2, 1, 1, 3, 6, 5, 5, 4, 4, 1, 5, 7, 7, 4, 7 };
+
+  static const int tet_cluster24[] =
+    { 2, 1, 3, 1, 4, 1, 5, 4, 6, 5, 5, 7, 4, 7, 7 };
+
+  static const int tet_cluster34[] =
+    { 2, 3, 1, 1, 4, 5, 1, 6, 4, 5, 5, 4, 7, 7, 7 };
+
+  int cnt = 0;
+  do
+    {
+      cnt++;
+      changed = 0;
+      
+      for (i = 1; i <= ne; i++)
+	{
+	  const Element & el = mesh.VolumeElement(i);
+	  ELEMENT_TYPE typ = el.GetType();
+	  
+	  top.GetElementEdges (i, ednums);
+	  top.GetElementFaces (i, fanums);
+	  
+	  int elnv = top.GetNVertices (typ);
+	  int elned = ednums.Size();
+	  int elnfa = fanums.Size();
+	  
+	  nnums.SetSize(elnv+elned+elnfa+1);
+	  for (j = 1; j <= elnv; j++)
+	    nnums.Elem(j) = el.PNum(j);
+	  for (j = 1; j <= elned; j++)
+	    nnums.Elem(elnv+j) = nv+ednums.Elem(j);
+	  for (j = 1; j <= elnfa; j++)
+	    nnums.Elem(elnv+elned+j) = nv+ned+fanums.Elem(j);
+	  nnums.Elem(elnv+elned+elnfa+1) = nv+ned+nfa+i;
+
+	  
+	  const int * clustertab = NULL;
+	  switch (typ)
+	    {
+	    case PRISM:
+	    case PRISM12:
+	      clustertab = prism_cluster;
+	      break;
+	    case PYRAMID:
+	      clustertab = pyramid_cluster;
+	      break;
+	    case TET:
+	    case TET10:
+	      if (cluster_reps.Get(el.PNum(1)) == 
+		  cluster_reps.Get(el.PNum(2)))
+		clustertab = tet_cluster12;
+	      else if (cluster_reps.Get(el.PNum(1)) == 
+		       cluster_reps.Get(el.PNum(3)))
+		clustertab = tet_cluster13;
+	      else if (cluster_reps.Get(el.PNum(1)) == 
+		       cluster_reps.Get(el.PNum(4)))
+		clustertab = tet_cluster14;
+	      else if (cluster_reps.Get(el.PNum(2)) == 
+		       cluster_reps.Get(el.PNum(3)))
+		clustertab = tet_cluster23;
+	      else if (cluster_reps.Get(el.PNum(2)) == 
+		       cluster_reps.Get(el.PNum(4)))
+		clustertab = tet_cluster24;
+	      else if (cluster_reps.Get(el.PNum(3)) == 
+		       cluster_reps.Get(el.PNum(4)))
+		clustertab = tet_cluster34;
+	      else
+		clustertab = NULL;
+	      break;
+	    default:
+	      clustertab = NULL;
+	    }
+	  
+	  if (clustertab)
+	    for (j = 0; j < nnums.Size(); j++)
+	      for (k = 0; k < j; k++)
+		if (clustertab[j] == clustertab[k])
+		  {
+		    int jj = nnums[j];
+		    int kk = nnums[k];
+		    if (cluster_reps.Get(jj) < cluster_reps.Get(kk))
+		      {
+			cluster_reps.Elem(kk) = cluster_reps.Get(jj);
+			changed = 1;
+		      }
+		    else if (cluster_reps.Get(kk) < cluster_reps.Get(jj))
+		      {
+			cluster_reps.Elem(jj) = cluster_reps.Get(kk);
+			changed = 1;
+		      }
+		  }
+
+	  /*
+	  if (clustertab)
+	    {
+	      if (typ == PYRAMID)
+		(*testout) << "pyramid";
+	      else if (typ == PRISM || typ == PRISM12)
+		(*testout) << "prism";
+	      else if (typ == TET || typ == TET10)
+		(*testout) << "tet";
+	      else
+		(*testout) << "unknown type" << endl;
+		
+	      (*testout) << ", nnums  = ";
+	      for (j = 0; j < nnums.Size(); j++)
+		(*testout) << "node " << j << " = " << nnums[j] << ", rep = "
+			   << cluster_reps.Get(nnums[j]) << endl;
+	    }
+	  */
+	}
+    }
+  while (changed);
+
+  /*
+    (*testout) << "cluster reps:" << endl;
+    for (i = 1; i <= cluster_reps.Size(); i++)
+    {
+    (*testout) << i << ": ";
+    if (i <= nv)
+    (*testout) << "v" << i << " ";
+    else if (i <= nv+ned)
+    (*testout) << "e" << i-nv << " ";
+    else if (i <= nv+ned+nfa)
+    (*testout) << "f" << i-nv-ned << " ";
+    else
+    (*testout) << "c" << i-nv-ned-nfa << " ";
+    (*testout) << cluster_reps.Get(i) << endl;
+    }
+  */
+}
+}
diff --git a/Netgen/libsrc/meshing/clusters.hpp b/Netgen/libsrc/meshing/clusters.hpp
new file mode 100644
index 0000000000..b0eea1b5e0
--- /dev/null
+++ b/Netgen/libsrc/meshing/clusters.hpp
@@ -0,0 +1,42 @@
+#ifndef CLUSTERS
+#define CLUSTERS
+
+/**************************************************************************/
+/* File:   clusers.hh                                                     */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   28. Apr. 01                                                    */
+/**************************************************************************/
+
+/*
+  Anisotropic clusters
+
+  nodes, edges, faces, elements
+*/
+
+
+class AnisotropicClusters
+{
+  const Mesh & mesh;
+
+  int nv, ned, nfa, ne;
+
+  // connected nodes, nodes = vertices, edges, faces, elements
+  ARRAY<int> cluster_reps;
+
+public:
+  AnisotropicClusters (const Mesh & amesh);
+  ~AnisotropicClusters();
+
+  void Update();
+
+  int GetVertexRepresentant (int vnr) const
+  { return cluster_reps.Get(vnr); }
+  int GetEdgeRepresentant (int ednr) const
+  { return cluster_reps.Get(nv+ednr); }
+  int GetFaceRepresentant (int fnr) const
+  { return cluster_reps.Get(nv+ned+fnr); }
+  int GetElementRepresentant (int enr) const
+  { return cluster_reps.Get(nv+ned+nfa+enr); }
+};
+
+#endif
diff --git a/Netgen/libsrc/meshing/curvedelems.cpp b/Netgen/libsrc/meshing/curvedelems.cpp
new file mode 100644
index 0000000000..fc0e590366
--- /dev/null
+++ b/Netgen/libsrc/meshing/curvedelems.cpp
@@ -0,0 +1,1910 @@
+#include <mystdlib.h>
+
+#include "meshing.hpp"
+
+namespace netgen
+{
+    
+    
+    // computes Gaussean integration formula on (0,1) with n points
+    // in: Numerical algs in C (or, was it the Fortran book ?)
+    void ComputeGaussRule (int n, ARRAY<double> & xi, ARRAY<double> & wi)
+    {
+	xi.SetSize (n);
+	wi.SetSize (n);
+	
+	int m = (n+1)/2;
+	double p1, p2, p3;
+	double pp, z, z1;
+	for (int i = 1; i <= m; i++)
+	{
+	    z = cos ( M_PI * (i - 0.25) / (n + 0.5));
+	    while(1)
+	    {
+		p1 = 1; p2 = 0;
+		for (int j = 1; j <= n; j++)
+		{
+		    p3 = p2; p2 = p1;
+		    p1 = ((2 * j - 1) * z * p2 - (j - 1) * p3) / j;
+		}
+		// p1 is legendre polynomial
+
+		pp = n * (z*p1-p2) / (z*z - 1);
+		z1 = z;
+		z = z1-p1/pp;
+
+		if (fabs (z - z1) < 1e-14) break;
+	    }
+
+	    xi[i-1] = 0.5 * (1 - z);
+	    xi[n-i] = 0.5 * (1 + z);
+	    wi[i-1] = wi[n-i] = 1.0 / ( (1  - z * z) * pp * pp);
+	}
+    }
+
+
+
+// ----------------------------------------------------------------------------
+//      PolynomialBasis
+// ----------------------------------------------------------------------------
+
+
+    void PolynomialBasis :: CalcLegendrePolynomials (double x)
+    {
+	double p1 = 1.0, p2 = 0.0, p3;
+
+	lp[0] = 1.0;
+
+	for (int j=1; j<=order; j++)
+	{
+	    p3=p2; p2=p1;
+	    p1=((2.0*j-1.0)*(2*x-1)*p2-(j-1.0)*p3)/j;
+	    lp[j] = p1;
+	}
+    }
+
+
+    void PolynomialBasis :: CalcDLegendrePolynomials (double x)
+    {
+	double p1 = 0., p2 = 0., p3;
+
+	dlp[0] = 0.;
+
+	for (int j = 1; j <= order-1; j++)
+	{
+	    p3=p2; p2=p1;
+	    p1=((2.*j-1.)*(2*lp[j-1]+(2*x-1)*p2)-(j-1.)*p3)/j;
+	    dlp[j] = p1;
+	}
+    }
+
+
+    void PolynomialBasis :: CalcF (double x)
+    {
+	CalcLegendrePolynomials (x);
+
+	for (int j = 0; j<=order-2; j++)
+	    f[j] = (lp[j+2]-lp[j])/(2.0*(j+1)+1)/2.0;
+    }
+
+
+    void PolynomialBasis :: CalcDf (double x)
+    {
+	CalcLegendrePolynomials (x);
+
+	for (int j = 0; j <= order-2; j++)
+	    df[j] = lp[j+1];
+    }
+
+
+    void PolynomialBasis :: CalcFDf (double x)
+    {
+	CalcLegendrePolynomials (x);
+
+	for (int j = 0; j<=order-2; j++)
+	{
+	    f[j] = (lp[j+2]-lp[j])/(2.0*(j+1)+1)/2.0;
+	    df[j] = lp[j+1];
+	}
+    }
+
+
+    void PolynomialBasis :: CalcDDf (double x)
+    {
+        CalcLegendrePolynomials (x);
+	CalcDLegendrePolynomials (x);
+
+	for (int j = 0; j <= order-2; j++) ddf[j] = dlp[j+1];
+    }
+
+
+
+// ----------------------------------------------------------------------------
+//      BaseFiniteElement1D
+// ----------------------------------------------------------------------------
+
+
+    void BaseFiniteElement1D :: CalcVertexShapes ()
+    {
+	vshape[0] = xi(0);
+	vshape[1] = 1-xi(0);
+
+	vdshape[0] = 1;
+	vdshape[1] = -1;
+
+	if (edgeorient == -1)
+	{
+	    Swap (vshape[0], vshape[1]);
+	    Swap (vdshape[0], vdshape[1]);
+	}
+    }
+
+
+    void BaseFiniteElement1D :: CalcEdgeShapes ()
+    {
+	b.SetOrder (edgeorder);
+	b.CalcFDf( 1-xi(0) );
+
+	for (int k = 2; k <= edgeorder; k++)
+	{
+	    eshape[k-2] = b.GetF(k);
+	    edshape[k-2] = -b.GetDf(k);
+	}
+    }
+
+
+    void BaseFiniteElement1D :: CalcEdgeLaplaceShapes ()
+    {
+        b.SetOrder (edgeorder);
+	b.CalcDDf( 1-xi(0) );
+
+	for (int k = 2; k <= edgeorder; k++)
+	    eddshape[k-2] = b.GetDDf(k);
+ }
+
+
+
+
+// ----------------------------------------------------------------------------
+//      BaseFiniteElement2D
+// ----------------------------------------------------------------------------
+
+
+    void BaseFiniteElement2D :: SetElementNumber (int aelnr)
+    {
+	int locmaxedgeorder = -1;
+	
+	BaseFiniteElement<2> :: SetElementNumber (aelnr);
+	Element2d elem = mesh[(SurfaceElementIndex) (elnr-1)]; 
+	top.GetSurfaceElementEdges (elnr, &(edgenr[0]), &(edgeorient[0]));
+	facenr = top.GetSurfaceElementFace (elnr);
+	faceorient = top.GetSurfaceElementFaceOrientation (elnr);
+	
+	for (int v = 0; v < nvertices; v++)
+	    vertexnr[v] = elem[v];
+	
+	for (int e = 0; e < nedges; e++)
+	{
+	    edgeorder[e] = curv.GetEdgeOrder (edgenr[e]-1); // 1-based
+	    locmaxedgeorder = max2 (edgeorder[e], locmaxedgeorder);
+	}
+	
+	faceorder = curv.GetFaceOrder (facenr-1); // 1-based
+	CalcNFaceShapes ();
+	
+	if (locmaxedgeorder > maxedgeorder)
+	{
+	    maxedgeorder = locmaxedgeorder;
+	    eshape.SetSize(nedges * (maxedgeorder-1));
+	    edshape.SetSize(nedges * (maxedgeorder-1));
+	}
+	
+	if (faceorder > maxfaceorder)
+	{
+	    maxfaceorder = faceorder;
+	    fshape.SetSize( nfaceshapes ); // number of face shape functions
+	    fdshape.SetSize( nfaceshapes );
+	    fddshape.SetSize ( nfaceshapes );
+	}
+    };
+    
+
+
+
+// ----------------------------------------------------------------------------
+//      BaseFiniteElement3D
+// ----------------------------------------------------------------------------
+
+
+    void BaseFiniteElement3D :: SetElementNumber (int aelnr)
+    {
+	int locmaxedgeorder = -1;
+	int locmaxfaceorder = -1;
+	int v, f, e;
+
+	BaseFiniteElement<3> :: SetElementNumber (aelnr);
+	Element elem = mesh[(ElementIndex) (elnr-1)];
+	top.GetElementEdges (elnr, &(edgenr[0]), &(edgeorient[0]));
+	top.GetElementFaces (elnr, &(facenr[0]), &(faceorient[0]));
+	
+	for (v = 0; v < nvertices; v++)
+	    vertexnr[v] = elem[v];
+	
+	for (f = 0; f < nfaces; f++)
+	{
+	    surfacenr[f] = top.GetFace2SurfaceElement (facenr[f]);
+	    surfaceorient[f] = top.GetSurfaceElementFaceOrientation (surfacenr[f]);
+	}
+	
+	for (e = 0; e < nedges; e++)
+	{
+	    edgeorder[e] = curv.GetEdgeOrder (edgenr[e]-1); // 1-based
+	    locmaxedgeorder = max2 (edgeorder[e], locmaxedgeorder);
+	}
+	
+	for (f = 0; f < nfaces; f++)
+	{
+	    faceorder[f] = curv.GetFaceOrder (facenr[f]-1); // 1-based
+	    locmaxfaceorder = max2 (faceorder[f], locmaxfaceorder);
+	}
+	
+	CalcNFaceShapes ();
+	
+	if (locmaxedgeorder > maxedgeorder)
+	{
+	    maxedgeorder = locmaxedgeorder;
+	    eshape.SetSize(nedges * (maxedgeorder-1));
+	    edshape.SetSize(nedges * (maxedgeorder-1));
+	}
+	
+	if (locmaxfaceorder > maxfaceorder)
+	{
+	    maxfaceorder = locmaxfaceorder;
+	    fshape.SetSize( nfaces * (maxfaceorder-1) * (maxfaceorder-1)); // number of face shape functions
+	    fdshape.SetSize( nfaces * (maxfaceorder-1) * (maxfaceorder-1));
+	}
+    };
+    
+    
+
+
+// ----------------------------------------------------------------------------
+//      FETrig
+// ----------------------------------------------------------------------------
+
+
+    void FETrig :: SetReferencePoint (Point<2> axi)
+    {
+	BaseFiniteElement2D :: SetReferencePoint (axi);
+	lambda(0) = xi(0);
+	lambda(1) = xi(1);
+	lambda(2) = 1-xi(0)-xi(1);
+
+	dlambda(0,0) =  1; dlambda(0,1) =  0;
+	dlambda(1,0) =  0; dlambda(1,1) =  1;
+	dlambda(2,0) = -1; dlambda(2,1) = -1;
+    }
+
+
+    void FETrig :: SetVertexSingularity (int v, int exponent)
+    {
+      int i;
+	if (1-lambda(v) < EPSILON) return;
+
+	Point<3> lamold = lambda;
+
+	Vec<2> dfac;
+
+	double fac = pow(1-lambda(v),exponent-1);
+
+	for (i = 0; i < 2; i++)
+	{
+	    dfac(i) = -(exponent-1)*pow(1-lambda(v),exponent-2)*dlambda(v,i);
+	    dlambda(v,i) *= exponent * pow(1-lambda(v),exponent-1);
+	}
+
+	lambda(v) = 1-pow(1-lambda(v),exponent);
+
+	for (i = 0; i < nvertices; i++)
+	{
+	    if (i == v) continue;
+	    for (int j = 0; j < 2; j++)
+		dlambda(i,j) = dlambda(i,j) * fac + lamold(i) * dfac(j);
+
+	    lambda(i) *= fac;
+	}
+    }
+
+
+
+    void FETrig :: CalcVertexShapes ()
+    {
+	for (int v = 0; v < nvertices; v++)
+	{
+	    vshape[v] = lambda(v);
+	    vdshape[v](0) = dlambda(v,0);
+	    vdshape[v](1) = dlambda(v,1);
+	}
+    }
+
+
+    void FETrig :: CalcEdgeShapes ()
+    {
+	int index = 0;
+	for (int e = 0; e < nedges; e++)
+	{
+	    int i0 = eledge[e][0]-1;
+	    int i1 = eledge[e][1]-1;
+
+	    double arg = lambda(i0) + lambda(i1); // = 1-lambda[i2];
+
+	    if (fabs(arg) < EPSILON) // division by 0
+	    {
+		for (int k = 2; k <= edgeorder[e]; k++)
+		{
+		    eshape[index] = 0;
+		    edshape[index] = Vec<2>(0,0);
+		    index++;
+		}
+		continue;
+	    }
+
+	    if (edgeorient[e] == -1) Swap (i0, i1); // reverse orientation
+
+	    double xi = lambda(i1)/arg;
+
+	    b1.SetOrder (edgeorder[e]);
+	    b1.CalcFDf (xi);
+
+	    double decay = arg;
+	    double ddecay;
+	    
+	    double l0 = lambda(i0);
+	    double l0x = dlambda(i0,0);
+	    double l0y = dlambda(i0,1);
+
+	    double l1 = lambda(i1);
+	    double l1x = dlambda(i1,0);
+	    double l1y = dlambda(i1,1);
+
+	    for (int k = 2; k <= edgeorder[e]; k++)
+	    {        
+		ddecay = k*decay;
+		decay *= arg;
+		
+		eshape[index] = b1.GetF (k) * decay;
+		edshape[index] = Vec<2>
+		    (b1.GetDf(k) * (l1x*arg - l1*(l0x+l1x)) * 
+		     decay / (arg * arg) + b1.GetF(k) * ddecay * (l0x+l1x),
+		     b1.GetDf(k) * (l1y*arg - l1*(l0y+l1y)) *
+		     decay / (arg * arg) + b1.GetF(k) * ddecay * (l0y+l1y));
+		index++;
+	    }
+	}
+	// (*testout) << "eshape = " << eshape << ", edshape = " << edshape << endl;
+	/*
+	index = 0;
+	for (int e = 0; e < nedges; e++)
+	  {
+	    int i0 = eledge[e][0]-1;
+	    int i1 = eledge[e][1]-1;
+
+	    if (edgeorient[e] == -1) Swap (i0, i1); // reverse orientation
+	    
+	    double x = lambda(i1)-lambda(i0);
+	    double y = 1-lambda(i0)-lambda(i1);
+	    double fy = (1-y)*(1-y);
+
+	    // double p3 = 0, p3x = 0, p3y = 0;
+	    // double p2 = -1, p2x = 0, p2y = 0;
+	    // double p1 = x, p1x = 1, p1y = 0;
+
+	    double p3 = 0, p3x = 0, p3y = 0;
+	    double p2 = -0.5, p2x = 0, p2y = 0;
+	    double p1 = 0.5*x, p1x = 0.5, p1y = 0;
+
+	    for (int j=2; j<= edgeorder[e]; j++)
+	      {
+		p3=p2; p3x = p2x; p3y = p2y;
+		p2=p1; p2x = p1x; p2y = p1y;
+		double c1 = (2.0*j-3) / j;
+		double c2 = (j-3.0) / j;
+		
+		p1  = c1 * x * p2 - c2 * fy * p3;
+		p1x = c1 * p2 + c1 * x * p2x - c2 * fy * p3x;
+		p1y = c1 * x * p2y - (c2 * 2 * (y-1) * p3 + c2 * fy * p3y);
+		eshape[index] = p1;
+		// edshape[index] = Vec<2> (p1x, p1y);
+		edshape[index](0) = -2*p1x;
+		edshape[index](1) = p1y-p1x;
+		index++;
+	      }    
+
+	  }
+	  // (*testout) << "eshape = " << eshape << ", edshape = " << edshape << endl;
+	  */
+    }
+
+
+    void FETrig :: CalcFaceShapes ()
+    {
+	int index = 0;
+
+	int i0 = elface[0][0]-1;
+	int i1 = elface[0][1]-1;
+	int i2 = elface[0][2]-1;
+
+	// sort lambda_i's by the corresponing vertex numbers
+
+	if (vertexnr[i1] < vertexnr[i0]) Swap (i0, i1);
+	if (vertexnr[i2] < vertexnr[i0]) Swap (i0, i2);
+	if (vertexnr[i2] < vertexnr[i1]) Swap (i1, i2);
+
+	double arg = lambda(i1) + lambda(i2);
+
+	if (fabs(arg) < EPSILON) // division by 0
+	{
+	    for (int k = 0; k < nfaceshapes; k++)
+	    {
+		fshape[index] = 0;
+		fdshape[index] = Vec<2>(0,0);
+		index++;
+	    }
+	    return;
+	}
+
+	b1.SetOrder (faceorder);
+	b2.SetOrder (faceorder);
+
+	b1.CalcFDf (lambda(i0));
+	b2.CalcFDf (lambda(i2)/arg);
+
+	double decay = 1;
+	double ddecay;
+
+	double l0 = lambda(i0);
+	double l1 = lambda(i1);
+	double l2 = lambda(i2);
+	double dl0x = dlambda(i0,0);
+	double dl0y = dlambda(i0,1);
+	double dl1x = dlambda(i1,0);
+	double dl1y = dlambda(i1,1);
+	double dl2x = dlambda(i2,0);
+	double dl2y = dlambda(i2,1);
+
+	double dargx = dl1x + dl2x;
+	double dargy = dl1y + dl2y;
+
+	for (int n1 = 2; n1 < faceorder; n1++)
+	{
+	    ddecay = (n1-1)*decay;
+	    decay *= arg;
+	    
+	    for (int n0 = 2; n0 < faceorder-n1+2; n0++)
+	    {
+		fshape[index] = b1.GetF(n0) * b2.GetF(n1) * decay;
+		fdshape[index] = Vec<2>
+		    (b1.GetDf(n0) * dl0x * b2.GetF(n1) * decay +
+		     b1.GetF(n0) * b2.GetDf(n1) * (dl2x * arg - l2 * dargx)/(arg*arg) * decay +
+		     b1.GetF(n0) * b2.GetF(n1) * ddecay * dargx,
+		     b1.GetDf(n0) * dl0y * b2.GetF(n1) * decay +
+		     b1.GetF(n0) * b2.GetDf(n1) * (dl2y * arg - l2 * dargy)/(arg*arg) * decay +
+		     b1.GetF(n0) * b2.GetF(n1) * ddecay * dargy);
+		index++;
+	    }
+	}
+    }
+
+
+
+    void FETrig :: CalcFaceLaplaceShapes ()
+    {
+	int index = 0;
+
+	int i0 = elface[0][0]-1;
+	int i1 = elface[0][1]-1;
+	int i2 = elface[0][2]-1;
+
+	if (vertexnr[i1] < vertexnr[i0]) Swap (i0, i1);
+	if (vertexnr[i2] < vertexnr[i0]) Swap (i0, i2);
+	if (vertexnr[i2] < vertexnr[i1]) Swap (i1, i2);
+
+	double arg = lambda(i1) + lambda(i2);
+
+	if (fabs(arg) < EPSILON) // division by 0
+	{
+	    for (int k = 0; k < nfaceshapes; k++)
+		fddshape[k] = 0;
+	    return;
+	}
+
+	b1.SetOrder (faceorder);
+	b2.SetOrder (faceorder);
+
+	b1.CalcFDf (lambda(i0));
+	b1.CalcDDf (lambda(i0));
+	b2.CalcFDf (lambda(i2)/arg);
+	b2.CalcDDf (lambda(i2)/arg);
+
+	double decay = 1;
+	double ddecay = 0;
+	double dddecay;
+
+	double l0 = lambda(i0);
+	double l1 = lambda(i1);
+	double l2 = lambda(i2);
+	double dl0x = dlambda(i0,0);
+	double dl0y = dlambda(i0,1);
+	double dl1x = dlambda(i1,0);
+	double dl1y = dlambda(i1,1);
+	double dl2x = dlambda(i2,0);
+	double dl2y = dlambda(i2,1);
+
+	double dargx = dl1x + dl2x;
+	double dargy = dl1y + dl2y;
+
+	for (int n1 = 2; n1 < faceorder; n1++)
+	{
+	    dddecay = (n1-1)*ddecay;
+	    ddecay = (n1-1)*decay;
+	    decay *= arg;
+	    
+	    for (int n0 = 2; n0 < faceorder-n1+2; n0++)
+	    {
+		fddshape[index] = 
+
+		//  b1.GetDf(n0) * dl0x * b2.GetF(n1) * decay .... derived
+
+		    b1.GetDDf(n0) * dl0x * dl0x * b2.GetF(n1) * decay +
+		    b1.GetDf(n0) * dl0x * b2.GetDf(n1) * (dl2x * arg - l2 * dargx)/(arg*arg) * decay +
+		    b1.GetDf(n0) * dl0x * b2.GetF(n1) * ddecay * dargx +
+
+		    
+	        //  b1.GetF(n0) * b2.GetDf(n1) * (dl2x * arg - l2 * dargx)/(arg*arg) * decay ... derived
+
+		    b1.GetDf(n0) * dl0x * b2.GetDf(n1) * (dl2x * arg - l2 * dargx)/(arg*arg) * decay +
+		    b1.GetF(n0) * b2.GetDDf(n1) * pow((dl2x * arg - l2 * dargx)/(arg*arg),2) * decay +
+		    b1.GetF(n0) * b2.GetDf(n1) * (-2*dargx/arg) * (dl2x * arg - l2 * dargx)/(arg*arg) * decay +
+		    b1.GetF(n0) * b2.GetDf(n1) * (dl2x * arg - l2 * dargx)/(arg*arg) * ddecay * dargx +
+
+		    
+		//  b1.GetF(n0) * b2.GetF(n1) * ddecay * dargx ... derived
+
+		    b1.GetDf(n0) * dl0x * b2.GetF(n1) * ddecay * dargx +
+		    b1.GetF(n0) * b2.GetDf(n1) * (dl2x * arg - l2 * dargx)/(arg*arg) * ddecay * dargx +
+		    b1.GetF(n0) * b2.GetF(n1) * dddecay * dargx * dargx +
+
+		    
+		//  b1.GetDf(n0) * dl0y * b2.GetF(n1) * decay ... derived
+
+		    b1.GetDDf(n0) * dl0y * dl0y * b2.GetF(n1) * decay +
+		    b1.GetDf(n0) * dl0y * b2.GetDf(n1) * (dl2y * arg - l2 * dargy)/(arg*arg) * decay +
+		    b1.GetDf(n0) * dl0y * b2.GetF(n1) * ddecay * dargy +
+		    
+
+		//  b1.GetF(n0) * b2.GetDf(n1) * (dl2y * arg - l2 * dargy)/(arg*arg) * decay ... derived
+
+		    b1.GetDf(n0) * dl0y * b2.GetDf(n1) * (dl2y * arg - l2 * dargy)/(arg*arg) * decay +
+		    b1.GetF(n0) * b2.GetDDf(n1) * pow((dl2y * arg - l2 * dargy)/(arg*arg),2) * decay +
+		    b1.GetF(n0) * b2.GetDf(n1) * (-2*dargy/arg) * (dl2y * arg - l2 * dargy)/(arg*arg) * decay +
+		    b1.GetF(n0) * b2.GetDf(n1) * (dl2y * arg - l2 * dargy)/(arg*arg) * ddecay * dargy +
+		    
+
+		//  b1.GetF(n0) * b2.GetF(n1) * ddecay * dargy ... derived
+
+		    b1.GetDf(n0) * dl0y * b2.GetF(n1) * ddecay * dargy +
+		    b1.GetF(n0) * b2.GetDf(n1) * (dl2y * arg - l2 * dargy)/(arg*arg) * ddecay * dargy +
+		    b1.GetF(n0) * b2.GetF(n1) * dddecay * dargy * dargy;
+
+		index++;
+	    }
+	}
+    }
+
+
+
+// ----------------------------------------------------------------------------
+//      FEQuad
+// ----------------------------------------------------------------------------
+
+
+    void FEQuad :: CalcVertexShapes ()
+    {
+	vshape[0] = (1-xi(0)) * (1-xi(1));
+	vshape[1] = (  xi(0)) * (1-xi(1));
+	vshape[2] = (  xi(0)) * (  xi(1));
+	vshape[3] = (1-xi(0)) * (  xi(1));
+
+	vdshape[0] = Vec<2> ( -(1-xi(1)), -(1-xi(0)) );
+	vdshape[1] = Vec<2> (  (1-xi(1)), -(  xi(0)) );
+	vdshape[2] = Vec<2> (  (  xi(1)),  (  xi(0)) );
+	vdshape[3] = Vec<2> ( -(  xi(1)),  (1-xi(0)) );
+    }
+
+
+    void FEQuad :: CalcEdgeShapes ()
+    {
+	int index = 0;
+
+	double arg0[4] = { xi(0), 1-xi(0), 1-xi(1), xi(1) };
+	double arg1[4] = { 1-xi(1), xi(1), 1-xi(0), xi(0) };
+	double darg0[4] = {  1, -1, -1,  1 };
+	double darg1[4] = { -1,  1, -1,  1 };
+	
+	for (int e = 0; e < nedges; e++)
+	{
+	    b1.SetOrder (edgeorder[e]);
+	    b1.CalcFDf (edgeorient[e] == 1 ? arg0[e] : 1-arg0[e]);
+
+	    double decay = arg1[e];
+	    double ddecay;
+
+	    for (int k = 2; k <= edgeorder[e]; k++, index++)
+	    {
+		ddecay = k*decay;
+		decay *= arg1[e];
+// linear decay
+		eshape[index] = b1.GetF(k) * arg1[e];
+
+		if (e < 2)
+		    edshape[index] = Vec<2>
+			(darg0[e] * edgeorient[e] * b1.GetDf(k) * arg1[e],
+			 b1.GetF(k) * darg1[e]);
+		else
+		    edshape[index] = Vec<2>
+			(b1.GetF(k) * darg1[e],
+			 darg0[e] * edgeorient[e] * b1.GetDf(k) * arg1[e]);
+
+// exponential decay
+/*		eshape[index] = b1.GetF(k) * decay;
+
+		if (e < 2)
+		    edshape[index] = Vec<2>
+			(darg0[e] * edgeorient[e] * b1.GetDf(k) * decay,
+			 b1.GetF(k) * ddecay * darg1[e]);
+		else
+		    edshape[index] = Vec<2>
+			(b1.GetF(k) * ddecay * darg1[e],
+			 darg0[e] * edgeorient[e] * b1.GetDf(k) * decay);
+*/
+	    }
+	}
+    }
+
+
+    void FEQuad :: CalcFaceShapes ()
+    {
+	int index = 0;
+
+	// find index of point with smallest number
+
+	int i0 = 0;
+	for (int i = 1; i < 4; i++)
+	    if (vertexnr[elface[0][i]-1] < vertexnr[elface[0][i0]-1]) i0 = i;
+
+	double x;
+	double y;
+	double dxx;
+	double dxy;
+	double dyx;
+	double dyy;
+
+	switch (i0)
+	{
+	    case 0:
+		x = xi(0); y = xi(1);
+		dxx = 1; dxy = 0;
+		dyx = 0; dyy = 1;
+		break;
+	    case 1:
+		x = xi(1); y = 1-xi(0);
+		dxx = 0; dxy = 1;
+		dyx = -1; dyy = 0;
+		break;
+	    case 2: 
+		x = 1-xi(0); y = 1-xi(1);
+		dxx = -1; dxy = 0;
+		dyx = 0; dyy = -1;
+		break;
+	    case 3:
+		x = 1-xi(1); y = xi(0);
+		dxx = 0; dxy =-1;
+		dyx = 1; dyy = 0;
+		break;
+	}
+
+	if (vertexnr[elface[0][(i0+1) % 4]-1] > vertexnr[elface[0][(i0+3) % 4]-1]) 
+	{
+	    Swap (x,y);
+	    Swap (dxx, dyx);
+	    Swap (dxy, dyy);
+	}
+
+	b1.SetOrder (faceorder);
+	b2.SetOrder (faceorder);
+
+	b1.CalcFDf (x);
+	b2.CalcFDf (y);
+
+	for (int n0 = 2; n0 <= faceorder; n0++)
+	    for (int n1 = 2; n1 <= faceorder; n1++)
+	    {
+		fshape[index] = b1.GetF(n0) * b2.GetF(n1);
+		fdshape[index] = Vec<2> (b1.GetDf(n0) * dxx * b2.GetF(n1) + b1.GetF(n0) * b2.GetDf(n1) * dyx,
+					 b1.GetDf(n0) * dxy * b2.GetF(n1) + b1.GetF(n0) * b2.GetDf(n1) * dyy);
+		index++;
+	    }
+    }
+
+
+    void FEQuad :: CalcFaceLaplaceShapes ()
+    {
+	int index = 0;
+
+	// find index of point with smallest number
+
+	int i0 = 0;
+	for (int i = 1; i < 4; i++)
+	    if (vertexnr[elface[0][i]-1] < vertexnr[elface[0][i0]-1]) i0 = i;
+
+	double x;
+	double y;
+	double dxx;
+	double dxy;
+	double dyx;
+	double dyy;
+
+	switch (i0)
+	{
+	    case 0:
+		x = xi(0); y = xi(1);
+		dxx = 1; dxy = 0;
+		dyx = 0; dyy = 1;
+		break;
+	    case 1:
+		x = xi(1); y = 1-xi(0);
+		dxx = 0; dxy = 1;
+		dyx = -1; dyy = 0;
+		break;
+	    case 2: 
+		x = 1-xi(0); y = 1-xi(1);
+		dxx = -1; dxy = 0;
+		dyx = 0; dyy = -1;
+		break;
+	    case 3:
+		x = 1-xi(1); y = xi(0);
+		dxx = 0; dxy =-1;
+		dyx = 1; dyy = 0;
+		break;
+	}
+
+	if (vertexnr[elface[0][(i0+1) % 4]-1] > vertexnr[elface[0][(i0+3) % 4]-1]) 
+	{
+	    Swap (x,y);
+	    Swap (dxx, dyx);
+	    Swap (dxy, dyy);
+	}
+
+	b1.SetOrder (faceorder);
+	b2.SetOrder (faceorder);
+
+	b1.CalcFDf (x);
+	b1.CalcDDf (x);
+	b2.CalcFDf (y);
+	b2.CalcDDf (y);
+
+	for (int n0 = 2; n0 <= faceorder; n0++)
+	    for (int n1 = 2; n1 <= faceorder; n1++)
+	    {
+		fddshape[index] =
+		    b1.GetDDf(n0) * dxx * dxx * b2.GetF(n1) +
+		2*  b1.GetDf(n0) * dxx * b2.GetDf(n1) * dyx +
+		    b1.GetF(n0) * b2.GetDDf(n1) * dyx * dyx +
+
+		    b1.GetDDf(n0) * dxy * dxy * b2.GetF(n1) +
+		2*  b1.GetDf(n0) * dxy * b2.GetDf(n1) * dyy +
+		    b1.GetF(n0) * b2.GetDDf(n1) * dyy * dyy;
+
+		index++;
+	    }
+    }
+
+
+
+// ----------------------------------------------------------------------------
+//      FETet
+// ----------------------------------------------------------------------------
+
+
+    void FETet :: SetReferencePoint (Point<3> axi)
+    {
+	BaseFiniteElement3D :: SetReferencePoint (axi);
+	
+	lambda(0) = xi(0);
+	lambda(1) = xi(1);
+	lambda(2) = xi(2);
+	lambda(3) = 1-xi(0)-xi(1)-xi(2);
+
+	dlambda(0,0) =  1; dlambda(0,1) =  0; dlambda(0,2) =   0;
+	dlambda(1,0) =  0; dlambda(1,1) =  1; dlambda(1,2) =   0;
+	dlambda(2,0) =  0; dlambda(2,1) =  0; dlambda(2,2) =   1;
+	dlambda(3,0) = -1; dlambda(3,1) = -1; dlambda(3,2) =  -1;
+    }
+
+
+    void FETet :: CalcVertexShapes ()
+    {
+	for (int v = 0; v < nvertices; v++)
+	{
+	    vshape[v] = lambda(v);
+	    vdshape[v](0) = dlambda(v,0);
+	    vdshape[v](1) = dlambda(v,1);
+	    vdshape[v](2) = dlambda(v,2);
+	}
+    }
+
+
+    void FETet :: CalcEdgeShapes ()
+    {
+	int index = 0;
+
+	for (int e = 0; e < nedges; e++)
+	{
+	    int i0 = eledge[e][0]-1;
+	    int i1 = eledge[e][1]-1;
+
+	    double arg = lambda(i0)+lambda(i1);
+
+	    if (fabs(arg) < EPSILON) // division by 0
+	    {
+		for (int k = 2; k <= edgeorder[e]; k++)
+		{
+		    eshape[index] = 0;
+		    edshape[index] = Vec<3>(0,0,0);
+		    index++;
+		}
+		continue;
+	    }
+
+	    if (edgeorient[e] == -1) Swap (i0, i1);
+
+	    double xi = lambda[i1]/arg;
+
+	    b1.SetOrder (edgeorder[e]);
+	    b1.CalcFDf (xi);
+
+	    double decay = arg;
+	    double ddecay;
+	    
+	    double l0 = lambda(i0);
+	    double dl0x = dlambda(i0,0);
+	    double dl0y = dlambda(i0,1);
+	    double dl0z = dlambda(i0,2);
+
+	    double l1 = lambda(i1);
+	    double dl1x = dlambda(i1,0);
+	    double dl1y = dlambda(i1,1);
+	    double dl1z = dlambda(i1,2);
+
+	    double dargx = dl0x + dl1x;
+	    double dargy = dl0y + dl1y;
+	    double dargz = dl0z + dl1z;
+                           
+	    for (int k = 2; k <= edgeorder[e]; k++)
+	    {        
+		ddecay = k*decay;
+		decay *= arg;
+
+		eshape[index] = b1.GetF (k) * decay;
+		edshape[index] = Vec<3>
+		    (b1.GetDf(k) * (dl1x*arg - l1*dargx) * 
+		     decay / (arg * arg) + b1.GetF(k) * ddecay * dargx,
+		     b1.GetDf(k) * (dl1y*arg - l1*dargy) * 
+		     decay / (arg * arg) + b1.GetF(k) * ddecay * dargy,
+		     b1.GetDf(k) * (dl1z*arg - l1*dargz) * 
+		     decay / (arg * arg) + b1.GetF(k) * ddecay * dargz);
+
+		index++;
+	    }
+	}
+    }
+
+
+    void FETet :: CalcFaceShapes ()
+    {
+	int index = 0;
+
+	for (int f = 0; f < nfaces; f++)
+	{
+	    int i0 = elface[f][0]-1;
+	    int i1 = elface[f][1]-1;
+	    int i2 = elface[f][2]-1;
+
+	    if (vertexnr[i1] < vertexnr[i0]) Swap (i0, i1);
+	    if (vertexnr[i2] < vertexnr[i0]) Swap (i0, i2);
+	    if (vertexnr[i2] < vertexnr[i1]) Swap (i1, i2);
+
+	    double arg = lambda(i1) + lambda(i2);
+	    double arg2 = lambda(i0) + lambda(i1) + lambda(i2);
+
+	    if (fabs(arg) < EPSILON || fabs(arg2) < EPSILON) // division by 0
+	    {
+		for (int k = 0; k < nfaceshapes[f]; k++)
+		{
+		    fshape[index] = 0;
+		    fdshape[index] = Vec<3>(0,0,0);
+		    index++;
+		}
+		continue;
+	    }
+
+	    b1.SetOrder (faceorder[f]);
+	    b2.SetOrder (faceorder[f]);
+	    
+	    b1.CalcFDf (lambda(i0)/arg2);
+	    b2.CalcFDf (lambda(i2)/arg);
+	    
+	    double decay = 1;
+	    double ddecay;
+	    
+	    double l0 = lambda(i0);
+	    double l1 = lambda(i1);
+	    double l2 = lambda(i2);
+	    double dl0x = dlambda(i0,0);
+	    double dl0y = dlambda(i0,1);
+	    double dl0z = dlambda(i0,2);
+	    double dl1x = dlambda(i1,0);
+	    double dl1y = dlambda(i1,1);
+	    double dl1z = dlambda(i1,2);
+	    double dl2x = dlambda(i2,0);
+	    double dl2y = dlambda(i2,1);
+	    double dl2z = dlambda(i2,2);
+	    
+	    double dargx = dl1x + dl2x;
+	    double dargy = dl1y + dl2y;
+	    double dargz = dl1z + dl2z;
+	    double darg2x = dl0x + dl1x + dl2x;
+	    double darg2y = dl0y + dl1y + dl2y;
+	    double darg2z = dl0z + dl1z + dl2z;
+
+	    for (int n1 = 2; n1 < faceorder[f]; n1++)
+	    {
+		ddecay = (n1-1)*decay;
+		decay *= arg;
+		
+		double decay2 = arg2;
+		double ddecay2;
+
+		for (int n0 = 2; n0 < faceorder[f]-n1+2; n0++)
+		{
+		    ddecay2 = n0*decay2;
+		    decay2 *= arg2;
+
+		    fshape[index] = b1.GetF(n0) * b2.GetF(n1) * decay * decay2;
+		    fdshape[index] = Vec<3>
+			(b1.GetDf(n0) * (dl0x * arg2 - l0 * darg2x)/(arg2*arg2) * b2.GetF(n1) * decay * decay2 +
+			 b1.GetF(n0) * b2.GetDf(n1) * (dl2x * arg - l2 * dargx)/(arg*arg) * decay * decay2 +
+			 b1.GetF(n0) * b2.GetF(n1) * ddecay * dargx * decay2 +
+			 b1.GetF(n0) * b2.GetF(n1) * decay * ddecay2 * darg2x,
+			
+			 b1.GetDf(n0) * (dl0y * arg2 - l0 * darg2y)/(arg2*arg2) * b2.GetF(n1) * decay * decay2 +
+			 b1.GetF(n0) * b2.GetDf(n1) * (dl2y * arg - l2 * dargy)/(arg*arg) * decay * decay2 +
+			 b1.GetF(n0) * b2.GetF(n1) * ddecay * dargy * decay2 +
+			 b1.GetF(n0) * b2.GetF(n1) * decay * ddecay2 * darg2y,
+
+			 b1.GetDf(n0) * (dl0z * arg2 - l0 * darg2z)/(arg2*arg2) * b2.GetF(n1) * decay * decay2 +
+			 b1.GetF(n0) * b2.GetDf(n1) * (dl2z * arg - l2 * dargz)/(arg*arg) * decay * decay2 +
+			 b1.GetF(n0) * b2.GetF(n1) * ddecay * dargz * decay2 +
+			 b1.GetF(n0) * b2.GetF(n1) * decay * ddecay2 * darg2z);
+
+		    index++;
+		}
+	    }
+	}
+    }
+
+
+
+
+// ----------------------------------------------------------------------------
+//      FEPrism
+// ----------------------------------------------------------------------------
+
+
+    void FEPrism :: SetReferencePoint (Point<3> axi)
+    {
+	BaseFiniteElement3D :: SetReferencePoint (axi);
+	
+	lambda(0) = xi(0);
+	lambda(1) = xi(1);
+	lambda(2) = 1-xi(0)-xi(1);
+	lambda(3) = xi(2);
+
+	dlambda(0,0) =  1; dlambda(0,1) =  0; dlambda(0,2) =   0;
+	dlambda(1,0) =  0; dlambda(1,1) =  1; dlambda(1,2) =   0;
+	dlambda(2,0) = -1; dlambda(2,1) = -1; dlambda(2,2) =   0;
+	dlambda(3,0) =  0; dlambda(3,1) =  0; dlambda(3,2) =   1;
+    }
+
+
+    void FEPrism :: CalcVertexShapes ()
+    {
+	double zcomp = 1-lambda(3);
+
+	for (int v = 0; v < nvertices; v++)
+	{
+	    if (v == 3) zcomp = 1-zcomp;
+
+	    vshape[v] = lambda(v % 3) * zcomp;
+	    vdshape[v](0) = dlambda(v % 3,0) * zcomp;
+	    vdshape[v](1) = dlambda(v % 3,1) * zcomp;
+	    vdshape[v](2) = lambda(v % 3) * (-dlambda(3,2));
+
+	    if (v >= 3) vdshape[v](2) *= -1;
+	}
+    }
+
+
+    void FEPrism :: CalcEdgeShapes ()
+    {
+	int index = 0;
+	int e;
+	// triangle edge shapes
+	
+	for (e = 0; e < 6; e++)
+	{
+	    int i0 = (eledge[e][0]-1) % 3;
+	    int i1 = (eledge[e][1]-1) % 3;
+
+	    double arg = lambda[i0]+lambda[i1];
+
+	    if (fabs(arg) < EPSILON) // division by 0
+	    {
+		for (int k = 2; k <= edgeorder[e]; k++)
+		{
+		    eshape[index] = 0;
+		    edshape[index] = Vec<3>(0,0,0);
+		    index++;
+		}
+		continue;
+	    }
+
+	    if (edgeorient[e] == -1) Swap (i0, i1);
+
+	    double xi = lambda[i1]/arg;
+
+	    b1.SetOrder (edgeorder[e]);
+	    b1.CalcFDf (xi);
+
+	    double decay = arg;
+	    double ddecay;
+
+	    double zarg = e < 3 ? (1-lambda(3)) : lambda(3);
+	    double zcomp = zarg;
+	    double dzcomp;
+	    
+	    double l0 = lambda(i0);
+	    double dl0x = dlambda(i0,0);
+	    double dl0y = dlambda(i0,1);
+
+	    double l1 = lambda(i1);
+	    double dl1x = dlambda(i1,0);
+	    double dl1y = dlambda(i1,1);
+
+	    double dargx = dl0x + dl1x;
+	    double dargy = dl0y + dl1y;
+                           
+	    for (int k = 2; k <= edgeorder[e]; k++)
+	    {        
+		ddecay = k*decay;
+		decay *= arg;
+
+		dzcomp = k*zcomp;
+		zcomp *= zarg;
+
+		eshape[index] = b1.GetF (k) * decay * zcomp;
+		edshape[index] = Vec<3>
+		    ((b1.GetDf(k) * (dl1x*arg - l1*dargx) * 
+		     decay / (arg * arg) + b1.GetF(k) * ddecay * dargx) * zcomp,
+		     (b1.GetDf(k) * (dl1y*arg - l1*dargy) * 
+		     decay / (arg * arg) + b1.GetF(k) * ddecay * dargy) * zcomp,
+		     b1.GetF(k) * decay * dzcomp * (e < 3 ? -1 : 1));
+		index++;
+	    }
+	}
+
+	// rectangle edge shapes
+	
+	for (e = 6; e < nedges; e++)
+	{
+	    int i0 = eledge[e][0]-1;
+
+	    double arg = lambda[i0]; 
+
+	    if (fabs(arg) < EPSILON) // division by 0
+	    {
+		for (int k = 2; k <= edgeorder[e]; k++)
+		{
+		    eshape[index] = 0.;
+		    edshape[index] = Vec<3>(0.,0.,0.);
+		    index++;
+		}
+		continue;
+	    }
+
+	    double xi = lambda[3];
+
+	    if (edgeorient[e] == -1) xi = 1-xi;
+
+	    b1.SetOrder (edgeorder[e]);
+	    b1.CalcFDf (xi);
+
+	    double decay = arg;
+	    double ddecay;
+	    
+	    double l0 = lambda(i0);
+	    double l0x = dlambda(i0,0);
+	    double l0y = dlambda(i0,1);
+
+	    for (int k = 2; k <= edgeorder[e]; k++)
+	    {        
+		ddecay = k*decay;
+		decay *= arg;
+		
+		eshape[index] = b1.GetF (k) * decay;
+		edshape[index] = Vec<3>
+		    (b1.GetF(k) * ddecay * l0x,
+		     b1.GetF(k) * ddecay * l0y,
+		     b1.GetDf(k) * edgeorient[e] * decay);
+		index++;
+	    }
+	}
+    }
+
+
+    void FEPrism :: CalcFaceShapes ()
+    {
+	int index = 0;
+	int f;
+
+	// triangle face parts
+
+	for (f = 0; f < 2; f++)
+	{
+	    int i0 = elface[f][0]-1;
+	    int i1 = elface[f][1]-1;
+	    int i2 = elface[f][2]-1;
+
+	    if (vertexnr[i1] < vertexnr[i0]) Swap (i0, i1);
+	    if (vertexnr[i2] < vertexnr[i0]) Swap (i0, i2);
+	    if (vertexnr[i2] < vertexnr[i1]) Swap (i1, i2);
+
+	    i0 = i0 % 3;
+	    i1 = i1 % 3;
+	    i2 = i2 % 3;
+
+	    double arg = lambda(i1) + lambda(i2);
+
+	    if (fabs(arg) < EPSILON) // division by 0
+	    {
+		for (int k = 0; k < nfaceshapes[f]; k++)
+		{
+		    fshape[index] = 0;
+		    fdshape[index] = Vec<3>(0,0,0);
+		    index++;
+		}
+		continue;
+	    }
+
+	    b1.SetOrder (faceorder[f]);
+	    b2.SetOrder (faceorder[f]);
+	    
+	    b1.CalcFDf (lambda(i0));
+	    b2.CalcFDf (lambda(i2)/arg);
+	    
+	    double decay = 1;
+	    double ddecay;
+	    
+	    double l0 = lambda(i0);
+	    double l1 = lambda(i1);
+	    double l2 = lambda(i2);
+	    double dl0x = dlambda(i0,0);
+	    double dl0y = dlambda(i0,1);
+	    double dl0z = dlambda(i0,2);
+	    double dl1x = dlambda(i1,0);
+	    double dl1y = dlambda(i1,1);
+	    double dl1z = dlambda(i1,2);
+	    double dl2x = dlambda(i2,0);
+	    double dl2y = dlambda(i2,1);
+	    double dl2z = dlambda(i2,2);
+	    
+	    double dargx = dl1x + dl2x;
+	    double dargy = dl1y + dl2y;
+	    double dargz = dl1z + dl2z;
+
+	    double arg2 = f == 0 ? 1-xi(2) : xi(2);
+	    double darg2z = f == 0 ? -1 : 1;
+	    
+	    for (int n1 = 2; n1 < faceorder[f]; n1++)
+	    {
+		ddecay = (n1-1)*decay;
+		decay *= arg;
+		
+		double decay2 = arg2;
+		double ddecay2;
+
+		for (int n0 = 2; n0 < faceorder[f]-n1+2; n0++)
+		{
+		    ddecay2 = n0*decay2;
+		    decay2 *= arg2;
+
+		    fshape[index] = b1.GetF(n0) * b2.GetF(n1) * decay * decay2;
+		    fdshape[index] = Vec<3>
+			(b1.GetDf(n0) * dl0x * b2.GetF(n1) * decay * decay2 +
+			 b1.GetF(n0) * b2.GetDf(n1) * (dl2x * arg - l2 * dargx)/(arg*arg) * decay * decay2 +
+			 b1.GetF(n0) * b2.GetF(n1) * ddecay * dargx * decay2,
+			
+			 b1.GetDf(n0) * dl0y * b2.GetF(n1) * decay * decay2 +
+			 b1.GetF(n0) * b2.GetDf(n1) * (dl2y * arg - l2 * dargy)/(arg*arg) * decay * decay2 +
+			 b1.GetF(n0) * b2.GetF(n1) * ddecay * dargy * decay2,
+
+			 b1.GetDf(n0) * dl0z * b2.GetF(n1) * decay * decay2 +
+			 b1.GetF(n0) * b2.GetDf(n1) * (dl2z * arg - l2 * dargz)/(arg*arg) * decay * decay2 +
+			 b1.GetF(n0) * b2.GetF(n1) * ddecay * dargz * decay2 +
+			 b1.GetF(n0) * b2.GetF(n1) * decay * ddecay2 * darg2z);
+
+		    index++;
+		}
+	    }
+	}
+
+
+	// quad parts
+
+	for (f = 2; f < nfaces; f++)
+	{
+	    // find index of point with smallest number
+	  
+	    int i, i0 = 0;
+	    for (i = 1; i < 4; i++)
+		if (vertexnr[elface[f][i]-1] < vertexnr[elface[f][i0]-1]) i0 = i;
+	    
+	    double arg = 0;
+	    double dargx = 0;
+	    double dargy = 0;
+	    double dargz = 0;
+	    for (i = 0; i < 4; i++)
+	    {
+		arg += lambda((elface[f][i]-1) % 3)/2.0;
+		dargx += dlambda((elface[f][i]-1) % 3,0)/2.0;
+		dargy += dlambda((elface[f][i]-1) % 3,1)/2.0;
+		dargz += dlambda((elface[f][i]-1) % 3,2)/2.0;
+	    }
+	    
+	    if (fabs(arg) < EPSILON) // division by 0
+	    {
+		for (int k = 0; k < nfaceshapes[f]; k++)
+		{
+		    fshape[index] = 0;
+		    fdshape[index] = Vec<3>(0,0,0);
+		    index++;
+		}
+		continue;
+	    }
+
+	    int i1 = (i0+3) % 4;
+	    int j = (elface[f][i0]-1) % 3;
+
+	    double lam = lambda(j)/arg;
+	    double dlamx = (dlambda(j,0)*arg-lambda(j)*dargx)/(arg*arg);
+	    double dlamy = (dlambda(j,1)*arg-lambda(j)*dargy)/(arg*arg);
+	    double dlamz = (dlambda(j,2)*arg-lambda(j)*dargz)/(arg*arg);
+			    
+	    double x;
+	    double z;
+	    double dxx;
+	    double dxy;
+	    double dxz;
+	    double dzx;
+	    double dzy;
+	    double dzz;
+
+	    int ratvar;
+	    /*
+	    switch (i0)
+	    {
+		case 0:
+		    x = xi(2); z = lam;
+
+		    dxx = 0;     dxy = 0;     dxz = 1;
+		    dzx = dlamx; dzy = dlamy; dzz = dlamz;
+		    ratvar = 1;
+		    break;
+		case 1:
+		    x = 1-lam; z = xi(2);
+		    dxx = -dlamx; dxy = -dlamy; dxz = -dlamz;
+		    dzx = 0;      dzy = 0;      dzz = 1;
+		    ratvar = 0;
+		    break;
+		case 2: 
+		    x = 1-xi(2); z = 1-lam;
+		    dxx = 0;      dxy = 0;      dxz = -1;
+		    dzx = -dlamx; dzy = -dlamy; dzz = -dlamz;
+		    ratvar = 1;
+		    break;
+		case 3:
+		    x = lam; z = 1-xi(2);
+		    dxx = dlamx; dxy = dlamy; dxz = dlamz;
+		    dzx = 0;     dzy = 0;     dzz = -1;
+		    ratvar = 0;
+		    break;
+	    }
+	    */
+
+	    ratvar = 0;
+	    x = 1-lam;
+	    dxx = -dlamx; dxy = -dlamy; dxz = -dlamz;
+	    if (i0 == 0 || i0 == 1)
+	    {
+		z = xi(2);
+		dzx = 0; dzy = 0; dzz = 1;
+	    }
+	    else
+	    {
+		z = 1-xi(2);
+		dzx = 0; dzy = 0; dzz = -1;
+	    }
+
+	    int ix = i0 ^ 1;
+	    int iz = 3-i0;
+
+	    if (vertexnr[elface[f][ix]-1] > vertexnr[elface[f][iz]-1])
+	    {
+	        Swap (x,z);
+	        Swap (dxx, dzx);
+	        Swap (dxy, dzy);
+		Swap (dxz, dzz);
+		ratvar = 1-ratvar;
+	    }
+
+	    b1.SetOrder (faceorder[f]);
+	    b2.SetOrder (faceorder[f]);
+	    
+	    b1.CalcFDf (x);
+	    b2.CalcFDf (z);
+	    
+	    double decay = arg;
+	    double ddecay;
+	    
+	    for (int n0 = 2; n0 <= faceorder[f]; n0++)
+	    {
+		ddecay = n0*decay;
+		decay *= arg;
+		
+		if (ratvar == 1) decay = arg;
+
+		for (int n1 = 2; n1 <= faceorder[f]; n1++)
+		{
+		    if (ratvar == 1)
+		    {
+			ddecay = n1*decay;
+			decay *= arg;
+		    }
+
+		    fshape[index] = b1.GetF(n0) * b2.GetF(n1) * decay;
+		    fdshape[index] = Vec<3>
+			(b1.GetDf(n0) * dxx * b2.GetF(n1) * decay +
+			 b1.GetF(n0) * b2.GetDf(n1) * dzx * decay +
+			 b1.GetF(n0) * b2.GetF(n1) * ddecay * dargx,
+
+			 b1.GetDf(n0) * dxy * b2.GetF(n1) * decay +
+			 b1.GetF(n0) * b2.GetDf(n1) * dzy * decay +
+			 b1.GetF(n0) * b2.GetF(n1) * ddecay * dargy,
+			
+			 b1.GetDf(n0) * dxz * b2.GetF(n1) * decay +
+			 b1.GetF(n0) * b2.GetDf(n1) * dzz * decay +
+			 b1.GetF(n0) * b2.GetF(n1) * ddecay * dargz);
+
+		    index++;
+		}
+	    }
+	}
+    }
+    
+
+
+// ----------------------------------------------------------------------------
+//      FEPyramid
+// ----------------------------------------------------------------------------
+
+
+    void FEPyramid :: SetReferencePoint (Point<3> axi)
+    {
+	BaseFiniteElement3D :: SetReferencePoint (axi);
+    }
+
+
+    void FEPyramid :: CalcVertexShapes ()
+    {
+	double x = xi(0);
+	double y = xi(1);
+	double z = xi(2);
+
+	if (z == 1.) z = 1-1e-10;
+	vshape[0] = (1-z-x)*(1-z-y) / (1-z);
+	vshape[1] = x*(1-z-y) / (1-z);
+	vshape[2] = x*y / (1-z);
+	vshape[3] = (1-z-x)*y / (1-z);
+	vshape[4] = z;
+
+	double z1 = 1-z;
+	double z2 = z1*z1;
+
+	vdshape[0] = Vec<3>( -(z1-y)/z1, -(z1-x)/z1, ((x+y+2*z-2)*z1+(z1-y)*(z1-x))/z2 );
+	vdshape[1] = Vec<3>( (z1-y)/z1,  -x/z1,      (-x*z1+x*(z1-y))/z2 );
+	vdshape[2] = Vec<3>( y/z1,       x/z1,       x*y/z2 );
+	vdshape[3] = Vec<3>( -y/z1,      (z1-x)/z1,  (-y*z1+y*(z1-x))/z2 );
+	vdshape[4] = Vec<3>( 0, 0, 1 );
+    }
+
+
+    void FEPyramid :: CalcEdgeShapes ()
+    {
+	int index = 0;
+
+	for (int e = 0; e < GetNEdges(); e++)
+	{
+	    for (int k = 2; k <= edgeorder[e]; k++)
+	    {        
+		eshape[index] = 0;
+		edshape[index] = Vec<3>(0,0,0);
+		index++;
+	    }
+	}
+    }
+
+
+    void FEPyramid :: CalcFaceShapes ()
+    {
+	int index = 0;
+
+	for (int f = 0; f < GetNFaces(); f++)
+	{
+	    for (int k = 0; k < nfaceshapes[f]; k++)
+	    {
+		fshape[index] = 0;
+		fdshape[index] = Vec<3>(0,0,0);
+		index++;
+	    }
+	}
+    }
+    
+
+
+
+
+// ----------------------------------------------------------------------------
+//      FEHex
+// ----------------------------------------------------------------------------
+
+
+    void FEHex :: SetReferencePoint (Point<3> axi)
+    {
+	BaseFiniteElement3D :: SetReferencePoint (axi);
+    }
+
+
+    void FEHex :: CalcVertexShapes ()
+    {
+	double x = xi(0);
+	double y = xi(1);
+	double z = xi(2);
+
+	vshape[0] = (1-x)*(1-y)*(1-z);
+	vshape[1] =    x *(1-y)*(1-z); 
+	vshape[2] =    x *   y *(1-z);
+	vshape[3] = (1-x)*   y *(1-z);
+	vshape[4] = (1-x)*(1-y)* z;
+	vshape[5] =    x *(1-y)* z;
+	vshape[6] =    x *   y * z;
+	vshape[7] = (1-x)*   y * z;
+
+	vdshape[0] = Vec<3>(-(1-y)*(1-z), -(1-x)*(1-z), -(1-x)*(1-y));
+	vdshape[1] = Vec<3>( (1-y)*(1-z),    -x *(1-z),    -x *(1-y));
+	vdshape[2] = Vec<3>(    y *(1-z),     x *(1-z),    -x * y);
+	vdshape[3] = Vec<3>(   -y *(1-z),  (1-x)*(1-z), -(1-x)*y);
+	vdshape[4] = Vec<3>(-(1-y)*   z, -(1-x)* z,  (1-x)*(1-y));
+	vdshape[5] = Vec<3>( (1-y)*   z,    -x * z,     x *(1-y));
+	vdshape[6] = Vec<3>(    y *   z,     x * z,     x * y);
+	vdshape[7] = Vec<3>(   -y *   z,  (1-x)* z,  (1-x)*y);
+
+    }
+
+
+    void FEHex :: CalcEdgeShapes ()
+    {
+	int index = 0;
+
+	for (int e = 0; e < GetNEdges(); e++)
+	{
+	    for (int k = 2; k <= edgeorder[e]; k++)
+	    {        
+		eshape[index] = 0;
+		edshape[index] = Vec<3>(0,0,0);
+		index++;
+	    }
+	}
+    }
+
+
+    void FEHex :: CalcFaceShapes ()
+    {
+	int index = 0;
+
+	for (int f = 0; f < GetNFaces(); f++)
+	{
+	    for (int k = 0; k < nfaceshapes[f]; k++)
+	    {
+		fshape[index] = 0;
+		fdshape[index] = Vec<3>(0,0,0);
+		index++;
+	    }
+	}
+    }
+    
+
+
+
+
+
+
+
+
+  int CurvedElements :: IsSurfaceElementCurved (int elnr) const
+  {
+    Element2d elem = mesh[(SurfaceElementIndex) elnr];
+
+    switch (elem.GetType())
+      {
+      case TRIG:
+	{
+	  FETrig fe2d(*this);
+	  fe2d.SetElementNumber (elnr+1);
+	  return (fe2d.IsCurved());
+	  break;
+	}
+
+      case QUAD:
+	{
+	  FEQuad fe2d(*this);
+	  fe2d.SetElementNumber (elnr+1);
+	  return (fe2d.IsCurved());
+	  break;
+	}
+
+      }
+    return 0;
+  }
+
+
+
+  int CurvedElements :: IsElementCurved (int elnr) const
+  {
+    Element elem = mesh[(ElementIndex) elnr];
+
+    switch (elem.GetType())
+      {
+      case TET:
+	{
+	  FETet fe3d(*this);
+	  fe3d.SetElementNumber (elnr+1);
+	  return (fe3d.IsCurved());
+	  break;
+	}
+
+      case PRISM:
+	{
+	  FEPrism fe3d(*this);
+	  fe3d.SetElementNumber (elnr+1);
+	  return (fe3d.IsCurved());
+	  break;
+	}
+
+      case PYRAMID:
+	{
+	  FEPyramid fe3d(*this);
+	  fe3d.SetElementNumber (elnr+1);
+	  return (fe3d.IsCurved());
+	  break;
+	}
+
+      case HEX:
+	{
+	  FEHex fe3d(*this);
+	  fe3d.SetElementNumber (elnr+1);
+	  return (fe3d.IsCurved());
+	  break;
+	}
+
+      }
+
+    return 0;
+  }
+
+
+    void CurvedElements :: CalcSegmentTransformation (double xi, int segnr,
+						      Point<3> * x, Vec<3> * dxdxi)
+    {
+	FESegm segm (*this);
+	segm.SetElementNumber (segnr+1);
+	segm.SetReferencePoint (Point<1>(xi));
+
+//	segm.CalcVertexShapes (x != NULL, dxdxi != NULL);
+	segm.CalcVertexShapes ();
+
+	if (x)
+	{
+	    (*x) = Point<3>(0,0,0);
+	    for (int v = 0; v < 2; v++)
+		(*x) = (*x) + segm.GetVertexShape(v) * mesh.Point(segm.GetVertexNr(v));
+	}
+
+	if (dxdxi)
+	{
+	    (*dxdxi) = Vec<3>(0,0,0);
+	    for (int v = 0; v < 2; v++)
+		(*dxdxi) = (*dxdxi) + segm.GetVertexDShape(v) * mesh.Point(segm.GetVertexNr(v));
+	}
+
+	if (segm.GetEdgeOrder() > 1)
+	{
+//	    segm.CalcEdgeShapes (x != NULL, dxdxi != NULL);
+	    segm.CalcEdgeShapes ();
+
+	    if (x)
+	    {
+		int gindex = edgecoeffsindex[segm.GetEdgeNr()-1];
+		for (int k = 2; k <= segm.GetEdgeOrder(); k++, gindex++)
+		    (*x) = (*x) + segm.GetEdgeShape(k-2) * edgecoeffs[gindex];
+	    }
+
+	    if (dxdxi)
+	    {
+		int gindex = edgecoeffsindex[segm.GetEdgeNr()-1];
+		for (int k = 2; k <= segm.GetEdgeOrder(); k++, gindex++)
+		    (*dxdxi) = (*dxdxi) + segm.GetEdgeDShape(k-2) * edgecoeffs[gindex];
+	    }
+	}
+    }
+
+
+
+    void CurvedElements :: CalcSurfaceTransformation (Point<2> xi, int elnr,
+						      Point<3> * x, Mat<3,2> * dxdxi)
+    {
+	Element2d elem = mesh[(SurfaceElementIndex) elnr];
+
+	BaseFiniteElement2D * fe2d;
+
+	// char locmem[max2(sizeof(FEQuad), sizeof(FETrig))];
+	char locmemtrig[sizeof(FETrig)];
+	char locmemquad[sizeof(FEQuad)];
+	switch (elem.GetType())
+	  {
+	  case TRIG: fe2d = new (locmemtrig) FETrig (*this); break;
+	  case QUAD: fe2d = new (locmemquad) FEQuad (*this); break;
+	  }
+
+	fe2d->SetElementNumber (elnr+1);
+	fe2d->SetReferencePoint (xi);
+
+	/*
+	for (int v = 0; v < fe2d->GetNVertices(); v++)
+	{
+	  // if (fe2d->GetVertexNr(v) == 1)
+	  fe2d->SetVertexSingularity (v, 2);
+	}
+	*/
+	/*
+	int imin = 0, imax = 0;
+	if (fe2d->GetVertexNr(1) < fe2d->GetVertexNr(0)) imin = 1;
+	if (fe2d->GetVertexNr(2) < fe2d->GetVertexNr(imin)) imin = 2;
+	if (fe2d->GetVertexNr(1) > fe2d->GetVertexNr(0)) imax = 1;
+	if (fe2d->GetVertexNr(2) > fe2d->GetVertexNr(imax)) imax = 2;
+
+	fe2d->SetVertexSingularity (imin, 3);
+	fe2d->SetVertexSingularity (3-imin-imax, 3);
+	fe2d->SetVertexSingularity (imax, 3);
+	*/
+	fe2d->CalcVertexShapes ();
+
+	if (x)
+	{
+	    (*x) = Point<3>(0,0,0);
+	    for (int v = 0; v < fe2d->GetNVertices(); v++)
+		(*x) = (*x) + fe2d->GetVertexShape(v) * mesh.Point(fe2d->GetVertexNr(v));
+	}
+
+	if (dxdxi)
+	{
+	    for (int i = 0; i < 3; i++)
+                for (int j = 0; j < 2; j++)
+                  (*dxdxi)(i,j) = 0;
+                  
+	    for (int v = 0; v < elem.GetNV(); v++)
+		for (int i = 0; i < 3; i++)
+		    for (int j = 0; j < 2; j++)
+			(*dxdxi)(i,j) += fe2d->GetVertexDShape(v)(j) * mesh.Point(fe2d->GetVertexNr(v)).X(i+1);
+	}
+
+	if (IsHighOrder())
+	{
+//	    fe2d->CalcEdgeShapes (x != NULL, dxdxi != NULL);
+	    fe2d->CalcEdgeShapes ();
+	    if (x)
+	    {
+		int index = 0;
+		for (int e = 0; e < fe2d->GetNEdges(); e++)
+		{
+		    int gindex = edgecoeffsindex[fe2d->GetEdgeNr(e)-1];
+
+		    for (int k = 2; k <= fe2d->GetEdgeOrder(e); k++, index++, gindex++)
+			(*x) = (*x) + fe2d->GetEdgeShape(index) * edgecoeffs[gindex];
+ 		}
+	    }
+
+	    if (dxdxi)
+	    {
+		int index = 0;
+		for (int e = 0; e < fe2d->GetNEdges(); e++)
+		{
+		    int gindex = edgecoeffsindex[fe2d->GetEdgeNr(e)-1];
+		    for (int k = 2; k <= fe2d->GetEdgeOrder(e); k++, index++, gindex++)
+			for (int i = 0; i < 3; i++)
+			    for (int j = 0; j < 2; j++)
+				(*dxdxi)(i,j) += fe2d->GetEdgeDShape(index)(j) * edgecoeffs[gindex](i);
+		}
+	    }
+
+	    if (mesh.GetDimension() == 3)
+	    {
+//		fe2d->CalcFaceShapes (x != NULL, dxdxi != NULL);
+		fe2d->CalcFaceShapes ();
+
+		if (x)
+		{
+		    int gindex = facecoeffsindex[fe2d->GetFaceNr()-1];
+		    for (int index = 0; index < fe2d->GetNFaceShapes(); index++, gindex++)
+		    {
+			(*x) = (*x) + fe2d->GetFaceShape(index) * facecoeffs[gindex];
+		    }
+		}
+
+		if (dxdxi)
+		{
+		    int gindex = facecoeffsindex[fe2d->GetFaceNr()-1];
+		    for (int index = 0; index < fe2d->GetNFaceShapes(); index++, gindex++)
+			for (int i = 0; i < 3; i++)
+			    for (int j = 0; j < 2; j++)
+				(*dxdxi)(i,j) += fe2d->GetFaceDShape(index)(j) * facecoeffs[gindex](i);
+		}
+	    }
+	} 
+
+	fe2d -> ~BaseFiniteElement2D();
+    }	
+
+
+
+
+    void CurvedElements :: CalcElementTransformation (Point<3> xi, int elnr,
+				    Point<3> * x, Mat<3,3> * dxdxi)
+    {
+	Element elem = mesh[(ElementIndex) elnr];
+	BaseFiniteElement3D * fe3d;
+
+	// char locmem[max2(sizeof(FETet), sizeof(FEPrism))];
+	char locmemtet[sizeof(FETet)];
+	char locmemprism[sizeof(FEPrism)];
+	char locmempyramid[sizeof(FEPyramid)];
+	char locmemhex[sizeof(FEHex)];
+	switch (elem.GetType())
+	{
+	    case TET: fe3d = new (locmemtet) FETet (*this); break;
+	    case PRISM: fe3d = new (locmemprism) FEPrism (*this); break;
+	    case PYRAMID: fe3d = new (locmempyramid) FEPyramid (*this); break;
+	    case HEX: fe3d = new (locmemhex) FEHex (*this); break;
+	}
+	
+	fe3d->SetElementNumber (elnr+1);
+	fe3d->SetReferencePoint (xi);
+
+	fe3d->CalcVertexShapes ();
+//	fe3d->CalcVertexShapes (x != NULL, dxdxi != NULL);
+
+	if (x)
+	{
+	    (*x) = Point<3>(0,0,0);
+	    for (int v = 0; v < fe3d->GetNVertices(); v++)
+		(*x) += fe3d->GetVertexShape(v) * Vec<3> (mesh.Point(fe3d->GetVertexNr(v)));
+	}
+
+	if (dxdxi)
+	{
+            for (int i = 0; i < 3; i++)
+                for (int j = 0; j < 3; j++)
+                    (*dxdxi)(i,j) = 0;
+                    
+	    for (int v = 0; v < fe3d->GetNVertices(); v++)
+		for (int i = 0; i < 3; i++)
+		    for (int j = 0; j < 3; j++)
+			(*dxdxi)(i,j) += fe3d->GetVertexDShape(v)(j) * mesh.Point(fe3d->GetVertexNr(v)).X(i+1);
+	}
+
+	if (IsHighOrder())
+	{
+//	    fe3d->CalcEdgeShapes (x != NULL, dxdxi != NULL);
+	    fe3d->CalcEdgeShapes ();
+
+	    if (x)
+	    {
+		int index = 0;
+		for (int e = 0; e < fe3d->GetNEdges(); e++)
+		{
+		    int gindex = edgecoeffsindex[fe3d->GetEdgeNr(e)-1];
+		    for (int k = 2; k <= fe3d->GetEdgeOrder(e); k++, index++, gindex++)
+			(*x) += fe3d->GetEdgeShape(index) * edgecoeffs[gindex];
+		}
+	    }
+
+	    if (dxdxi)
+	    {
+		int index = 0;
+		for (int e = 0; e < fe3d->GetNEdges(); e++)
+		{
+		    int gindex = edgecoeffsindex[fe3d->GetEdgeNr(e)-1];
+		    for (int k = 2; k <= fe3d->GetEdgeOrder(e); k++, index++, gindex++)
+			for (int i = 0; i < 3; i++)
+			    for (int j = 0; j < 3; j++)
+				(*dxdxi)(i,j) += fe3d->GetEdgeDShape(index)(j) * edgecoeffs[gindex](i);
+		}
+	    }
+
+	    if (mesh.GetDimension() == 3)
+	    {
+		fe3d->CalcFaceShapes ();
+//		fe3d->CalcFaceShapes (x != NULL, dxdxi != NULL);
+
+		if (x)
+		{
+		    int index = 0;
+		    for (int f = 0; f < fe3d->GetNFaces(); f++)
+		    {
+			int gindex = facecoeffsindex[fe3d->GetFaceNr(f)-1];
+			for (int k = 0; k < fe3d->GetNFaceShapes(f); k++, index++, gindex++)
+			    (*x) += fe3d->GetFaceShape(index) * facecoeffs[gindex];
+		    }
+		}
+
+		if (dxdxi)
+		{
+		    int index = 0;
+		    for (int f = 0; f < fe3d->GetNFaces(); f++)
+		    {
+			int gindex = facecoeffsindex[fe3d->GetFaceNr(f)-1];
+			for (int k = 0; k < fe3d->GetNFaceShapes(f); k++, index++, gindex++)
+			    for (int i = 0; i < 3; i++)
+				for (int j = 0; j < 3; j++)
+				    (*dxdxi)(i,j) += fe3d->GetFaceDShape(index)(j) * facecoeffs[gindex](i);
+		    }
+		}
+	    } 
+	}
+	
+	fe3d -> ~BaseFiniteElement3D();
+    }
+
+
+} // namespace netgen
+
+
diff --git a/Netgen/libsrc/meshing/curvedelems.hpp b/Netgen/libsrc/meshing/curvedelems.hpp
new file mode 100644
index 0000000000..7328d27d66
--- /dev/null
+++ b/Netgen/libsrc/meshing/curvedelems.hpp
@@ -0,0 +1,835 @@
+#ifndef CURVEDELEMS
+#define CURVEDELEMS
+
+/**************************************************************************/
+/* File:   curvedelems.hpp                                                */
+/* Author: Robert Gaisbauer                                               */
+/* Date:   27. Sep. 02 (second version: 30. Jan. 03)                      */
+/**************************************************************************/
+
+#include "bisect.hpp"
+#include <iostream>
+
+#define EPSILON 1e-20
+
+
+
+void ComputeGaussRule (int n, ARRAY<double> & xi, ARRAY<double> & wi);
+
+
+
+
+
+// ----------------------------------------------------------------------------
+//      CurvedElements
+// ----------------------------------------------------------------------------
+
+class CurvedElements
+{
+  const Mesh & mesh;
+  const MeshTopology & top;
+
+  bool isHighOrder;
+  int nvisualsubsecs;
+  int nIntegrationPoints;
+
+  ARRAY<int> edgeorder;
+  ARRAY<int> faceorder;
+
+  /*
+
+  ARRAY< Vec<3> > edgecoeffs;
+  ARRAY< Vec<3> > facecoeffs;
+
+  ARRAY<int> edgecoeffsindex;
+  ARRAY<int> facecoeffsindex;
+
+  */
+
+  inline Vec<3> GetEdgeCoeff (int edgenr, int k);
+  inline Vec<3> GetFaceCoeff (int facenr, int k);
+
+  
+  void CalcSegmentTransformation (double xi, int segnr,
+				  Point<3> * x = NULL, Vec<3> * dxdxi = NULL);
+
+  void CalcSurfaceTransformation (Point<2> xi, int elnr,
+				  Point<3> * x = NULL, Mat<3,2> * dxdxi = NULL);
+
+  void CalcElementTransformation (Point<3> xi, int elnr,
+				  Point<3> * x = NULL, Mat<3,3> * dxdxi = NULL);
+
+public:
+
+  Refinement * refinement;
+
+  ARRAY< Vec<3> > edgecoeffs;
+  ARRAY< Vec<3> > facecoeffs;
+
+  ARRAY<int> edgecoeffsindex;
+  ARRAY<int> facecoeffsindex;
+
+
+
+
+
+  CurvedElements (const Mesh & amesh);
+  ~CurvedElements();
+
+  bool IsHighOrder() const
+  { return isHighOrder; };
+
+  int GetNVisualSubsecs() const
+  { return nvisualsubsecs; };
+
+  const class Mesh & GetMesh() const
+  { return mesh; };
+
+  void BuildCurvedElements(Refinement * ref, int polydeg);
+
+  int GetEdgeOrder (int edgenr) const
+  { return edgeorder[edgenr]; };
+
+  int GetFaceOrder (int facenr) const
+  { return faceorder[facenr]; };
+
+  int IsEdgeCurved (int edgenr) const;
+
+  int IsFaceCurved (int facenr) const;
+
+  int IsSurfaceElementCurved (int elnr) const;
+
+  int IsElementCurved (int elnr) const;
+
+
+  void CalcSegmentTransformation (double xi, int segnr,
+				  Point<3> & x)
+  { CalcSegmentTransformation (xi, segnr, &x, NULL); };
+
+  void CalcSegmentTransformation (double xi, int segnr,
+				  Vec<3> & dxdxi)
+  { CalcSegmentTransformation (xi, segnr, NULL, &dxdxi); };
+
+  void CalcSegmentTransformation (double xi, int segnr,
+				  Point<3> & x, Vec<3> & dxdxi)
+  { CalcSegmentTransformation (xi, segnr, &x, &dxdxi); };
+
+
+  void CalcSurfaceTransformation (Point<2> & xi, int elnr,
+				  Point<3> & x)
+  { CalcSurfaceTransformation (xi, elnr, &x, NULL); };
+
+  void CalcSurfaceTransformation (Point<2> & xi, int elnr,
+				  Mat<3,2> & dxdxi)
+  { CalcSurfaceTransformation (xi, elnr, NULL, &dxdxi); };
+
+  void CalcSurfaceTransformation (Point<2> & xi, int elnr,
+				  Point<3> & x, Mat<3,2> & dxdxi)
+  { CalcSurfaceTransformation (xi, elnr, &x, &dxdxi); };
+
+
+  void CalcElementTransformation (Point<3> xi, int elnr,
+				  Point<3> & x)
+  { CalcElementTransformation (xi, elnr, &x, NULL); };
+
+  void CalcElementTransformation (Point<3> xi, int elnr,
+				  Mat<3,3> & dxdxi)
+  { CalcElementTransformation (xi, elnr, NULL, &dxdxi); };
+
+  void CalcElementTransformation (Point<3> xi, int elnr,
+				  Point<3> & x, Mat<3,3> & dxdxi)
+  { CalcElementTransformation (xi, elnr, &x, &dxdxi); };
+
+};
+
+
+
+// ----------------------------------------------------------------------------
+//      PolynomialBasis
+// ----------------------------------------------------------------------------
+
+class PolynomialBasis
+{
+  int order;
+  int maxorder;
+  ArrayMem<double,20> f;
+  ArrayMem<double,20> df;
+  ArrayMem<double,20> ddf;
+
+  ArrayMem<double,20> lp;
+  ArrayMem<double,20> dlp;
+
+  inline void CalcLegendrePolynomials (double x);
+  inline void CalcDLegendrePolynomials (double x);
+
+public:
+
+  PolynomialBasis ()
+  { maxorder = -1; };
+
+  ~PolynomialBasis ()
+  {};
+
+  void SetOrder (int aorder)
+  {
+    order = aorder;
+    if (order > maxorder)
+      {
+	maxorder = order;
+	f.SetSize(order-1);
+	df.SetSize(order-1);
+	ddf.SetSize(order-1);
+	lp.SetSize(order+1);
+	dlp.SetSize(order);
+      };
+  };
+
+  inline void CalcF (double x);
+  inline void CalcDf (double x);
+  inline void CalcDDf (double x);
+
+  inline void CalcFDf (double x);
+
+  double GetF (int p) { return f[p-2]; };
+  double GetDf (int p) { return df[p-2]; };
+  double GetDDf (int p) { return ddf[p-2]; };
+};
+
+
+
+// ----------------------------------------------------------------------------
+//      BaseFiniteElement
+// ----------------------------------------------------------------------------
+
+template <int DIM>
+class BaseFiniteElement
+{
+protected:
+
+  Point<DIM> xi;
+  int elnr;
+  const CurvedElements & curv;
+  const Mesh & mesh;
+  const MeshTopology & top;
+
+public:
+
+  BaseFiniteElement(const CurvedElements & acurv)
+    : curv(acurv), mesh(curv.GetMesh()), top(mesh.GetTopology())
+  {};
+
+  virtual ~BaseFiniteElement()
+  {};
+
+  void SetElementNumber (int aelnr)
+  { elnr = aelnr; }; // 1-based arrays in netgen
+
+  virtual void SetReferencePoint (Point<DIM> axi)
+  { xi = axi; };
+};
+
+
+
+// ----------------------------------------------------------------------------
+//      BaseFiniteElement1D
+// ----------------------------------------------------------------------------
+
+class BaseFiniteElement1D : public BaseFiniteElement<1>
+{
+protected:
+  PolynomialBasis b;
+
+  int vertexnr[2];
+  int edgenr;
+  int edgeorient;
+  int edgeorder;
+
+  int maxedgeorder;
+
+  double vshape[2];
+  double vdshape[2];
+  ArrayMem<double,20> eshape;
+  ArrayMem<double,20> edshape;
+  ArrayMem<double,20> eddshape;
+
+public:
+
+  BaseFiniteElement1D (const CurvedElements & acurv) : BaseFiniteElement<1>(acurv)
+  { maxedgeorder = 1; };
+
+  virtual ~BaseFiniteElement1D()
+  {};
+
+  int GetVertexNr (int v)
+  { return vertexnr[v]; };
+
+  int GetEdgeNr ()
+  { return edgenr; };
+
+  int GetEdgeOrder ()
+  { return edgeorder; };
+
+  int GetEdgeOrientation ()
+  { return edgeorient; };
+
+  void CalcVertexShapes();
+  void CalcEdgeShapes();
+  void CalcEdgeLaplaceShapes();
+
+  double GetVertexShape (int v)
+  { return vshape[v]; };
+
+  double GetEdgeShape (int index)
+  { return eshape[index]; };
+
+  double GetVertexDShape (int v)
+  { return vdshape[v]; };
+
+  double GetEdgeDShape (int index)
+  { return edshape[index]; };
+
+  double GetEdgeLaplaceShape (int index)
+  { return eddshape[index]; };
+
+};
+
+
+
+
+// ----------------------------------------------------------------------------
+//      FESegm
+// ----------------------------------------------------------------------------
+
+class FESegm : public BaseFiniteElement1D
+{
+
+public:
+
+  FESegm(const CurvedElements & acurv) : BaseFiniteElement1D(acurv)
+  {};
+
+  virtual ~FESegm()
+  {};
+
+  void SetElementNumber (int aelnr)
+  { 
+    BaseFiniteElement<1> :: SetElementNumber (aelnr);
+    Segment s = mesh.LineSegment(elnr);
+    vertexnr[0] = s.p1;
+    vertexnr[1] = s.p2;
+    edgenr = top.GetSegmentEdge(elnr);
+    edgeorient = top.GetSegmentEdgeOrientation(elnr);
+    edgeorder = curv.GetEdgeOrder(edgenr-1); // 1-based arrays in netgen
+
+    if (edgeorder > maxedgeorder)
+      {
+	maxedgeorder = edgeorder;
+	eshape.SetSize(maxedgeorder-1);
+	edshape.SetSize(maxedgeorder-1);
+	eddshape.SetSize(maxedgeorder-1);
+      }
+  };
+
+};
+
+
+
+// ----------------------------------------------------------------------------
+//      FEEdge
+// ----------------------------------------------------------------------------
+
+class FEEdge : public BaseFiniteElement1D
+{
+
+public:
+
+  FEEdge(const CurvedElements & acurv) : BaseFiniteElement1D(acurv)
+  {};
+
+  virtual ~FEEdge()
+  {};
+
+  void SetElementNumber (int aelnr)
+  { 
+    BaseFiniteElement<1> :: SetElementNumber (aelnr);
+    top.GetEdgeVertices (elnr, vertexnr[0], vertexnr[1]);
+    edgenr = elnr;
+    edgeorient = 1;
+    edgeorder = curv.GetEdgeOrder(edgenr-1); // 1-based arrays in netgen
+
+    if (edgeorder > maxedgeorder)
+      {
+	maxedgeorder = edgeorder;
+	eshape.SetSize(maxedgeorder-1);
+	edshape.SetSize(maxedgeorder-1);
+	eddshape.SetSize(maxedgeorder-1);
+      }
+  };
+    
+};
+
+
+
+// ----------------------------------------------------------------------------
+//      BaseFiniteElement2D
+// ----------------------------------------------------------------------------
+
+class BaseFiniteElement2D : public BaseFiniteElement<2>
+{
+protected:
+
+  int nvertices;
+  int nedges;
+
+  int vertexnr[4];
+  int edgenr[4];
+  int edgeorient[4];
+  int edgeorder[4];
+  int facenr;
+  int faceorient;
+  int faceorder;
+ 
+  int nfaceshapes;
+
+  int maxedgeorder;
+  int maxfaceorder;
+
+  PolynomialBasis b1, b2;
+
+  double vshape[4];
+  Vec<2> vdshape[4];
+  ArrayMem<double,80> eshape;
+  ArrayMem< Vec<2>,80> edshape;
+  ArrayMem<double,400> fshape;
+  ArrayMem<Vec<2>,400> fdshape;
+  ArrayMem<double,400> fddshape;
+
+  virtual void CalcNFaceShapes () = 0;
+
+public:
+
+  BaseFiniteElement2D (const CurvedElements & acurv) : BaseFiniteElement<2>(acurv)
+  { maxedgeorder = maxfaceorder = -1; };
+
+    virtual ~BaseFiniteElement2D()
+	{};
+
+  void SetElementNumber (int aelnr);
+
+  virtual void SetVertexSingularity (int v, int exponent) = 0;
+
+  int GetVertexNr (int v)
+  { return vertexnr[v]; };
+
+  int GetEdgeNr (int e)
+  { return edgenr[e]; };
+
+  int GetFaceNr ()
+  { return facenr; };
+
+  int GetEdgeOrder (int e)
+  { return edgeorder[e]; };
+
+  int GetFaceOrder ()
+  { return faceorder; }
+
+  int GetNVertices ()
+  { return nvertices; };
+
+  int GetNEdges ()
+  { return nedges; };
+
+  int GetNFaceShapes ()
+  { return nfaceshapes; };
+
+  int IsCurved ()
+  {
+    bool iscurved = 0;
+    int e;
+
+    for (e = 0; e < GetNEdges(); e++)
+      iscurved = iscurved || (GetEdgeOrder(e) > 1);
+
+    return iscurved || (GetFaceOrder() > 1);
+  }
+
+  virtual void CalcVertexShapes() = 0;
+  virtual void CalcEdgeShapes() = 0; 
+  virtual void CalcFaceShapes() = 0;
+
+  virtual void CalcFaceLaplaceShapes() = 0;
+
+  double GetVertexShape (int v)
+  { return vshape[v]; };
+
+  double GetEdgeShape (int index)
+  { return eshape[index]; };
+
+  double GetFaceShape (int index)
+  { return fshape[index]; };
+
+  Vec<2> GetVertexDShape (int v)
+  { return vdshape[v]; };
+
+  Vec<2> GetEdgeDShape (int index)
+  { return edshape[index]; };
+
+  Vec<2> GetFaceDShape (int index)
+  { return fdshape[index]; };
+
+  double GetFaceLaplaceShape (int index)
+  { return fddshape[index]; };
+};
+
+
+
+// ----------------------------------------------------------------------------
+//      FETrig
+// ----------------------------------------------------------------------------
+
+class FETrig : public BaseFiniteElement2D
+{
+  Point<3> lambda;
+  Mat<3,2> dlambda;
+
+  const ELEMENT_EDGE * eledge;
+  const ELEMENT_FACE * elface;
+
+  virtual void CalcNFaceShapes ()
+  { nfaceshapes = ((faceorder-1)*(faceorder-2))/2; };
+
+public:
+
+  FETrig (const CurvedElements & acurv) : BaseFiniteElement2D(acurv)
+  {
+    nvertices = 3;
+    nedges = 3;
+    eledge = MeshTopology :: GetEdges (TRIG);
+    elface = MeshTopology :: GetFaces (TRIG);
+  };
+
+    virtual ~FETrig()
+	{};
+
+  virtual void SetReferencePoint (Point<2> axi);
+
+  virtual void SetVertexSingularity (int v, int exponent);
+
+  virtual void CalcVertexShapes();
+  virtual void CalcEdgeShapes();
+  virtual void CalcFaceShapes();
+
+  virtual void CalcFaceLaplaceShapes();
+};
+
+
+
+// ----------------------------------------------------------------------------
+//      FEQuad
+// ----------------------------------------------------------------------------
+
+class FEQuad : public BaseFiniteElement2D
+{
+  const ELEMENT_FACE * elface;
+
+  virtual void CalcNFaceShapes ()
+  { nfaceshapes = (faceorder-1)*(faceorder-1); };
+
+public:
+
+  FEQuad (const CurvedElements & acurv) : BaseFiniteElement2D(acurv)
+  {
+    nvertices = 4;
+    nedges = 4;
+    elface = MeshTopology :: GetFaces (QUAD);
+  };
+
+    virtual ~FEQuad()
+	{};
+
+  virtual void SetVertexSingularity (int v, int exponent)
+	{};
+
+  virtual void CalcVertexShapes();
+  virtual void CalcEdgeShapes();
+  virtual void CalcFaceShapes();
+
+  virtual void CalcFaceLaplaceShapes();
+};
+
+
+
+
+// ----------------------------------------------------------------------------
+//      BaseFiniteElement3D
+// ----------------------------------------------------------------------------
+
+class BaseFiniteElement3D : public BaseFiniteElement<3>
+{
+protected:
+
+  int nvertices;
+  int nedges;
+  int nfaces;
+
+  int vertexnr[8];
+  int edgenr[12];
+  int edgeorient[12];
+  int edgeorder[12];
+  int facenr[6];
+  int faceorient[6];
+  int faceorder[6];
+  int surfacenr[6];
+  int surfaceorient[6];
+
+  int nfaceshapes[6];
+
+  int maxedgeorder;
+  int maxfaceorder;
+
+  PolynomialBasis b1, b2;
+
+  double vshape[8];
+  Vec<3> vdshape[8];
+  ArrayMem<double,120> eshape;
+  ArrayMem<Vec<3>,120> edshape;
+  ArrayMem<double,2000> fshape;
+  ArrayMem<Vec<3>,2000> fdshape;
+
+  virtual void CalcNFaceShapes () = 0;
+
+public:
+
+  int locmaxedgeorder;
+  int locmaxfaceorder;
+
+  BaseFiniteElement3D (const CurvedElements & acurv) : BaseFiniteElement<3>(acurv)
+  { maxedgeorder = maxfaceorder = -1; };
+
+  void SetElementNumber (int aelnr);
+
+  int GetVertexNr (int v)
+  { return vertexnr[v]; };
+
+  int GetEdgeNr (int e)
+  { return edgenr[e]; };
+
+  int GetFaceNr (int f)
+  { return facenr[f]; };
+
+  int GetNFaceShapes (int f)
+  { return nfaceshapes[f]; };
+
+  int GetEdgeOrder (int e)
+  { return edgeorder[e]; };
+
+  int GetFaceOrder (int f)
+  { return faceorder[f]; };
+
+  int GetNVertices ()
+  { return nvertices; };
+
+  int GetNEdges ()
+  { return nedges; };
+
+  int GetNFaces ()
+  { return nfaces; };
+
+  int IsCurved ()
+  {
+    bool iscurved = 0;
+    int e, f;
+
+    for (e = 0; e < GetNEdges(); e++)
+      iscurved = iscurved || (GetEdgeOrder(e) > 1);
+
+    for (f = 0; f < GetNFaces(); f++)
+      iscurved = iscurved || (GetFaceOrder(f) > 1);
+
+    return iscurved;
+  }
+
+  virtual void CalcVertexShapes() = 0;
+  virtual void CalcEdgeShapes() = 0;
+  virtual void CalcFaceShapes() = 0;
+
+  double GetVertexShape (int v)
+  { return vshape[v]; };
+
+  double GetEdgeShape (int index)
+  { return eshape[index]; };
+
+  double GetFaceShape (int index)
+  { return fshape[index]; };
+
+  Vec<3> GetVertexDShape (int v)
+  { return vdshape[v]; };
+
+  Vec<3> GetEdgeDShape (int index)
+  { return edshape[index]; };
+
+  Vec<3> GetFaceDShape (int index)
+  { return fdshape[index]; };
+};
+
+
+
+// ----------------------------------------------------------------------------
+//      FETet
+// ----------------------------------------------------------------------------
+
+class FETet : public BaseFiniteElement3D
+{
+  Point<4> lambda;
+  Mat<4,3> dlambda;
+
+  const ELEMENT_EDGE * eledge;
+  const ELEMENT_FACE * elface;
+
+  virtual void CalcNFaceShapes ()
+  {
+    for (int f = 0; f < nfaces; f++)
+      nfaceshapes[f] = ((faceorder[f]-1)*(faceorder[f]-2))/2;
+  };
+
+public:
+
+  FETet (const CurvedElements & acurv) : BaseFiniteElement3D(acurv)
+  {
+    nvertices = 4;
+    nedges = 6;
+    nfaces = 4;
+    eledge = MeshTopology :: GetEdges (TET);
+    elface = MeshTopology :: GetFaces (TET);
+  };
+
+  void SetReferencePoint (Point<3> axi);
+
+  virtual void CalcVertexShapes();
+  virtual void CalcEdgeShapes();
+  virtual void CalcFaceShapes();
+};
+
+
+
+// ----------------------------------------------------------------------------
+//      FEPrism
+// ----------------------------------------------------------------------------
+
+class FEPrism : public BaseFiniteElement3D
+{
+  Point<4> lambda;   // mixed barycentric coordinates
+  Mat<4,3> dlambda;
+
+  const ELEMENT_EDGE * eledge;
+  const ELEMENT_FACE * elface;
+
+  virtual void CalcNFaceShapes ()
+  {
+    int f;
+    for (f = 0; f < 2; f++)
+      nfaceshapes[f] = ((faceorder[f]-1)*(faceorder[f]-2))/2;
+    for (f = 2; f < nfaces; f++)
+      nfaceshapes[f] = (faceorder[f]-1)*(faceorder[f]-1);
+  };
+
+public:
+
+  FEPrism (const CurvedElements & acurv) : BaseFiniteElement3D(acurv)
+  {
+    nvertices = 6;
+    nedges = 9;
+    nfaces = 5;
+    eledge = MeshTopology :: GetEdges (PRISM);
+    elface = MeshTopology :: GetFaces (PRISM);
+  };
+
+  void SetReferencePoint (Point<3> axi);
+
+  virtual void CalcVertexShapes();
+  virtual void CalcEdgeShapes();
+  virtual void CalcFaceShapes();
+};
+
+
+
+
+// ----------------------------------------------------------------------------
+//      FEPyramid
+// ----------------------------------------------------------------------------
+
+class FEPyramid : public BaseFiniteElement3D
+{
+
+  const ELEMENT_EDGE * eledge;
+  const ELEMENT_FACE * elface;
+
+  virtual void CalcNFaceShapes ()
+  {
+    int f;
+    for (f = 0; f < 4; f++)
+      nfaceshapes[f] = ((faceorder[f]-1)*(faceorder[f]-2))/2;
+    for (f = 4; f < nfaces; f++)
+      nfaceshapes[f] = (faceorder[f]-1)*(faceorder[f]-1);
+  };
+
+public:
+
+  FEPyramid (const CurvedElements & acurv) : BaseFiniteElement3D(acurv)
+  {
+    nvertices = 5;
+    nedges = 8;
+    nfaces = 5;
+    eledge = MeshTopology :: GetEdges (PYRAMID);
+    elface = MeshTopology :: GetFaces (PYRAMID);
+  };
+
+  void SetReferencePoint (Point<3> axi);
+
+  virtual void CalcVertexShapes();
+  virtual void CalcEdgeShapes();
+  virtual void CalcFaceShapes();
+};
+
+
+
+
+// ----------------------------------------------------------------------------
+//      FEHex
+// ----------------------------------------------------------------------------
+
+class FEHex : public BaseFiniteElement3D
+{
+
+  const ELEMENT_EDGE * eledge;
+  const ELEMENT_FACE * elface;
+
+  virtual void CalcNFaceShapes ()
+  {
+    int f;
+    for (f = 0; f < 6; f++)
+      nfaceshapes[f] = (faceorder[f]-1)*(faceorder[f]-1);
+  };
+
+public:
+
+  FEHex (const CurvedElements & acurv) : BaseFiniteElement3D(acurv)
+  {
+    nvertices = 8;
+    nedges = 12;
+    nfaces = 6;
+    eledge = MeshTopology :: GetEdges (HEX);
+    elface = MeshTopology :: GetFaces (HEX);
+  };
+
+  void SetReferencePoint (Point<3> axi);
+
+  virtual void CalcVertexShapes();
+  virtual void CalcEdgeShapes();
+  virtual void CalcFaceShapes();
+};
+
+
+
+
+#endif
diff --git a/Netgen/libsrc/meshing/curvedelems2.cpp b/Netgen/libsrc/meshing/curvedelems2.cpp
new file mode 100644
index 0000000000..d01a13af79
--- /dev/null
+++ b/Netgen/libsrc/meshing/curvedelems2.cpp
@@ -0,0 +1,719 @@
+#include <mystdlib.h>
+
+#include "meshing.hpp"
+
+namespace netgen
+{
+    
+
+// ----------------------------------------------------------------------------
+//      CurvedElements
+// ----------------------------------------------------------------------------
+
+    CurvedElements :: CurvedElements (const Mesh & amesh)
+	: mesh(amesh), top(mesh.GetTopology())
+    {
+	isHighOrder = 0;
+	nvisualsubsecs = 2;
+	nIntegrationPoints = 10;
+    }
+
+
+    CurvedElements :: ~CurvedElements ()
+    {
+      ;
+    }
+
+
+    void CurvedElements :: BuildCurvedElements(Refinement * ref, int polydeg)
+    {
+      NgLock lock(const_cast<Mesh&>(mesh).Mutex(), 1);
+      isHighOrder = 0;
+      lock.UnLock();
+
+	const_cast<Mesh &>(mesh).UpdateTopology();
+
+	// set order of edges and faces
+
+	BaseFiniteElement2D * fe2d;
+
+	FEEdge edge (*this);
+	FESegm segm (*this);
+	FETrig trig (*this);
+	FEQuad quad (*this);
+
+	int i, k, e, f;
+
+	ARRAY<bool> edgedone;
+
+	edgedone.SetSize (top.GetNEdges());
+
+	edgeorder.SetSize (top.GetNEdges());
+	faceorder.SetSize (top.GetNFaces());
+
+	int nedgestocurve = top.GetNEdges();
+
+	edgedone = 0;
+	edgeorder = 1;
+	faceorder = 1;
+	
+	/*
+	for (e = 0; e < top.GetNEdges(); e++)
+	  {
+	    edgedone = 0;
+	    edgeorder[e] = 1;
+	  }
+
+	for (f = 0; f < top.GetNFaces(); f++)
+	    faceorder[f] = 1;
+	*/
+
+	for (i = 1; i <= mesh.GetNSeg(); i++) 
+	    edgeorder[top.GetSegmentEdge(i)-1] = polydeg;
+
+
+	if (mesh.GetDimension() == 3)
+	  {
+	    for (i = 1; i <= mesh.GetNSE(); i++)
+	      {
+		faceorder[top.GetSurfaceElementFace(i)-1] = polydeg;
+		
+		Element2d elem = mesh[(SurfaceElementIndex) (i-1)];
+		
+		ARRAY<int> edgenrs;
+		top.GetSurfaceElementEdges(i, edgenrs);
+		
+		nedgestocurve += top.GetNEdges(elem.GetType());
+		
+		for (int e = 0; e < top.GetNEdges(elem.GetType()); e++)
+		  edgeorder[edgenrs[e]-1] = polydeg;
+	      }
+	  }
+
+	if (polydeg == 1)
+	{
+	    isHighOrder = 0;
+	    return;
+	}
+
+	PrintMessage (1, "Building curved elements, order = ", polydeg);
+	PushStatusF ("curving edges");
+
+
+
+        // set edgecoeffs and facecoeffs arrays index and size
+
+	edgecoeffsindex.SetSize (top.GetNEdges()+1);
+	facecoeffsindex.SetSize (top.GetNFaces()+1);
+
+	edgecoeffsindex[0] = 0;
+	for (e = 2; e <= top.GetNEdges()+1; e++)
+	    edgecoeffsindex[e-1] = edgecoeffsindex[e-2] + edgeorder[e-2]-1;
+
+	facecoeffsindex[0] = 0;
+	for (f = 2; f <= top.GetNFaces()+1; f++)
+	{
+	    switch (top.GetFaceType (f-1))
+	    {
+		case TRIG:
+		    facecoeffsindex[f-1] = facecoeffsindex[f-2] + 
+			(faceorder[f-2]-1)*(faceorder[f-2]-2)/2;
+		    break;
+		case QUAD:
+		    facecoeffsindex[f-1] = facecoeffsindex[f-2] +
+			(faceorder[f-2]-1)*(faceorder[f-2]-1);
+		    break;
+	    }
+	}
+
+	edgecoeffs.SetSize(edgecoeffsindex[top.GetNEdges()]);
+	facecoeffs.SetSize(facecoeffsindex[top.GetNFaces()]);
+
+
+        
+	// evaluate edge points
+
+	PointGeomInfo newgi;          // dummy variable, only needed for function call
+	EdgePointGeomInfo newepgi;    // dummy variable, only needed for function call
+	Point3d xexact;               // new point to be stored in ARRAY edgepts
+
+	ARRAY<double> xi, wi;
+	ComputeGaussRule(nIntegrationPoints, xi, wi);
+
+	for (i=0; i<edgecoeffsindex[top.GetNEdges()]; i++)
+	    edgecoeffs[i] = Vec<3>(0.,0.,0.);
+
+
+
+
+	// all edges belonging to segments
+
+	for (i=0; i<mesh.GetNSeg(); i++) 
+	{
+	  if (multithread.terminate) return;
+
+	  SetThreadPercent( double(100*i/nedgestocurve) );
+
+	  int edgenr = top.GetSegmentEdge(i+1);
+
+	  if (edgedone[edgenr-1]) continue;
+
+	  edgedone[edgenr-1] = 1;
+
+            Segment s = mesh.LineSegment(i+1); 
+
+	    segm.SetElementNumber (i+1);
+	
+	    for (k = 2; k <= segm.GetEdgeOrder(); k++)
+	      edgecoeffs[edgecoeffsindex[edgenr-1]+k-2] = Vec<3>(0.,0.,0.);
+
+	    for (int l = 0; l < nIntegrationPoints; l++)
+	      {
+		segm.SetReferencePoint (Point<1>(xi[l]));
+		segm.CalcVertexShapes ();
+		segm.CalcEdgeLaplaceShapes ();
+		
+		Point<3> xv(0,0,0);
+		for (int v = 0; v < 2; v++)
+		  xv = xv + segm.GetVertexShape(v) * mesh.Point(segm.GetVertexNr(v));
+		
+		double secpoint = xi[l];
+
+		if (segm.GetEdgeOrientation() == -1) secpoint = 1. - secpoint; // reverse orientation
+		
+		ref->PointBetween (mesh.Point(segm.GetVertexNr(1)),
+				   mesh.Point(segm.GetVertexNr(0)), secpoint,
+				   s.surfnr2, s.surfnr1,
+				   s.epgeominfo[1], s.epgeominfo[0],
+				   xexact, newepgi);
+		
+		for (int k = 2; k <= segm.GetEdgeOrder(); k++)
+		  edgecoeffs[edgecoeffsindex[edgenr-1]+k-2] -=
+		    wi[l] * segm.GetEdgeLaplaceShape(k-2) * Vec<3>(xexact - xv);
+		
+	      }
+	    
+	    for (k = 2; k <= segm.GetEdgeOrder(); k++)
+	      edgecoeffs[edgecoeffsindex[edgenr-1]+k-2] =
+		(2.0*(k-1.0)+1.0)*edgecoeffs[edgecoeffsindex[edgenr-1]+k-2];
+	
+	}
+
+
+
+
+
+	// all edges belonging to surface elements
+	
+	if (mesh.GetDimension() == 3)
+	  {
+	    for (int i=0; i<mesh.GetNSE(); i++) 
+	      {
+		if (multithread.terminate) return;
+		
+		SetThreadPercent( double(100*(mesh.GetNSeg()+i)/nedgestocurve) );
+		Element2d elem = mesh[(SurfaceElementIndex) i];
+		const ELEMENT_EDGE * eledges = MeshTopology::GetEdges(elem.GetType());
+		
+		ARRAY<int> edgenrs;
+		ARRAY<int> orient;
+		top.GetSurfaceElementEdges(i+1, edgenrs);
+		top.GetSurfaceElementEdgeOrientations(i+1, orient);
+		
+		for (int e = 0; e < top.GetNEdges(elem.GetType()); e++)
+		  {
+		    if (edgedone[edgenrs[e]-1]) continue;
+		    
+		    edgedone[edgenrs[e]-1] = 1;
+
+		    edge.SetElementNumber (edgenrs[e]);
+
+		    for (k = 2; k <= edge.GetEdgeOrder(); k++)
+		      edgecoeffs[edgecoeffsindex[edgenrs[e]-1]+k-2] = Vec<3>(0.,0.,0.);
+
+		    for (int l = 0; l < nIntegrationPoints; l++)
+		      {
+			edge.SetReferencePoint (Point<1>(xi[l]));
+			edge.CalcVertexShapes ();
+			edge.CalcEdgeLaplaceShapes ();
+			
+			Point<3> xv(0,0,0);
+			for (int v = 0; v < 2; v++)
+			  xv = xv + edge.GetVertexShape(v) * mesh.Point(edge.GetVertexNr(v));
+
+			double secpoint = xi[l];
+
+			ref->PointBetween (mesh.Point(edge.GetVertexNr(1)),
+					   mesh.Point(edge.GetVertexNr(0)), secpoint,
+					   mesh.GetFaceDescriptor(elem.GetIndex()).SurfNr(),
+					   elem.GeomInfoPi(eledges[e][1]),
+					   elem.GeomInfoPi(eledges[e][0]),
+					   xexact, newgi);
+
+			for (k = 2; k <= edge.GetEdgeOrder(); k++)
+			  edgecoeffs[edgecoeffsindex[edgenrs[e]-1]+k-2] -=
+			    wi[l] * edge.GetEdgeLaplaceShape(k-2) * Vec<3>(xexact - xv);
+		      }	
+
+		    for (k = 2; k <= edge.GetEdgeOrder(); k++)
+		      edgecoeffs[edgecoeffsindex[edgenrs[e]-1]+k-2] =
+			(2.0*(k-1.0)+1.0)*edgecoeffs[edgecoeffsindex[edgenrs[e]-1]+k-2];
+		    
+		}
+	      }
+	  }
+
+
+
+
+/*
+
+	// L2-Projection for edges
+
+
+	cout << "WARNING: L2-Projection for edges" << endl;
+
+	if (mesh.GetDimension() == 3)
+	{
+	    for (int i=0; i<mesh.GetNSE(); i++) 
+	    {
+		Element2d elem = mesh[(SurfaceElementIndex) i];
+		const ELEMENT_EDGE * eledges = MeshTopology::GetEdges(elem.GetType());
+		
+		ARRAY<int> edgenrs;
+		ARRAY<int> orient;
+		top.GetSurfaceElementEdges(i+1, edgenrs);
+		top.GetSurfaceElementEdgeOrientations(i+1, orient);
+		
+		for (int e = 0; e < top.GetNEdges(elem.GetType()); e++)
+		{
+		    edge.SetElementNumber (edgenrs[e]);
+
+		    int npoints = edge.GetEdgeOrder()-1;
+
+		    if (npoints == 0) continue;
+
+		    DenseMatrix mat(npoints);
+		    DenseMatrix inv(npoints);
+		    Vector vec[3];
+	    
+		    for (int k = 0; k < 3; k++)
+		    {
+			vec[k].SetSize(npoints);
+			for (int n = 1; n <= npoints; n++) vec[k].Set(n, 0.);
+		    }
+		    
+		    for (int l = 0; l < nIntegrationPoints; l++)
+		    {
+			double w = wi[l];
+			
+			edge.SetReferencePoint (Point<1>(xi[l]));
+			edge.CalcVertexShapes ();
+			edge.CalcEdgeShapes ();
+		
+			for (int n = 0; n < npoints; n++)
+			    for (int m = 0; m < npoints; m++)
+				mat.Set(n+1, m+1, mat.Get(n+1,m+1) +
+					edge.GetEdgeShape(n) * edge.GetEdgeShape(m) * w);
+		
+			Point<3> xv(0,0,0);
+			for (int v = 0; v < 2; v++)
+			    xv = xv + edge.GetVertexShape(v) * mesh.Point(edge.GetVertexNr(v));
+			
+			double secpoint = xi[l];
+			
+			ref->PointBetween (mesh.Point(edge.GetVertexNr(1)),
+					   mesh.Point(edge.GetVertexNr(0)), secpoint,
+					   mesh.GetFaceDescriptor(elem.GetIndex()).SurfNr(),
+					   elem.GeomInfoPi(eledges[e][1]),
+					   elem.GeomInfoPi(eledges[e][0]),
+					   xexact, newgi);
+		
+			for (int k = 2; k <= edge.GetEdgeOrder(); k++)
+			{
+			    vec[0].Set(k-1, vec[0].Get(k-1) + Vec<3>(xexact - xv)(0)*edge.GetEdgeShape(k-2)*w );
+			    vec[1].Set(k-1, vec[1].Get(k-1) + Vec<3>(xexact - xv)(1)*edge.GetEdgeShape(k-2)*w );
+			    vec[2].Set(k-1, vec[2].Get(k-1) + Vec<3>(xexact - xv)(2)*edge.GetEdgeShape(k-2)*w );
+			}
+		
+		    }
+
+
+		    CalcInverse(mat,inv);
+	    
+		    Vector a0, a1, a2;
+		    
+		    a0 = inv*vec[0];
+		    a1 = inv*vec[1];
+		    a2 = inv*vec[2];
+
+		    int index = edgecoeffsindex[edge.GetEdgeNr()-1];
+
+		    for (int n = 0; n < npoints; n++, index++)
+			edgecoeffs[index] =  Vec<3>(a0(n+1), a1(n+1), a2(n+1));
+		}
+	    }
+	}
+
+
+	for (int i=0; i<mesh.GetNSeg(); i++) 
+	{
+	    int edgenr = top.GetSegmentEdge(i+1);
+
+            Segment s = mesh.LineSegment(i+1); 
+
+	    segm.SetElementNumber (i+1);
+
+	    int npoints = segm.GetEdgeOrder()-1;
+
+	    if (npoints == 0) continue;
+
+	    DenseMatrix mat(npoints);
+	    DenseMatrix inv(npoints);
+	    Vector vec[3];
+
+	    for (int k = 0; k < 3; k++)
+	    {
+		vec[k].SetSize(npoints);
+		for (int n = 1; n <= npoints; n++) vec[k].Set(n, 0.);
+	    }
+	
+	    for (int l = 0; l < nIntegrationPoints; l++)
+	    {
+		double w = wi[l];
+
+		segm.SetReferencePoint (Point<1>(xi[l]));
+		segm.CalcVertexShapes ();
+		segm.CalcEdgeShapes ();
+		
+		for (int n = 0; n < npoints; n++)
+		    for (int m = 0; m < npoints; m++)
+			mat.Set(n+1, m+1, mat.Get(n+1,m+1) +
+				segm.GetEdgeShape(n) * segm.GetEdgeShape(m) * w);
+		
+		Point<3> xv(0,0,0);
+		for (int v = 0; v < 2; v++)
+		    xv = xv + segm.GetVertexShape(v) * mesh.Point(segm.GetVertexNr(v));
+		
+		double secpoint = xi[l];
+		
+		if (segm.GetEdgeOrientation() == -1) secpoint = 1. - secpoint; // reverse orientation
+		
+		ref->PointBetween (mesh.Point(segm.GetVertexNr(1)),
+				   mesh.Point(segm.GetVertexNr(0)), secpoint,
+				   s.surfnr2, s.surfnr1,
+				   s.epgeominfo[1], s.epgeominfo[0],
+				   xexact, newepgi);
+		
+		for (int k = 2; k <= segm.GetEdgeOrder(); k++)
+		{
+		    vec[0].Set(k-1, vec[0].Get(k-1) + Vec<3>(xexact - xv)(0)*segm.GetEdgeShape(k-2)*w );
+		    vec[1].Set(k-1, vec[1].Get(k-1) + Vec<3>(xexact - xv)(1)*segm.GetEdgeShape(k-2)*w );
+		    vec[2].Set(k-1, vec[2].Get(k-1) + Vec<3>(xexact - xv)(2)*segm.GetEdgeShape(k-2)*w );
+		}
+		
+	    }
+
+
+	    CalcInverse(mat,inv);
+	    
+	    Vector a0, a1, a2;
+
+	    a0 = inv*vec[0];
+	    a1 = inv*vec[1];
+	    a2 = inv*vec[2];
+
+	    int index = edgecoeffsindex[segm.GetEdgeNr()-1];
+
+	    for (int n = 0; n < npoints; n++, index++)
+		edgecoeffs[index] =  Vec<3>(a0(n+1), a1(n+1), a2(n+1));
+
+
+
+	}
+
+*/
+
+
+
+
+
+	// evaluate face points
+
+	if (mesh.GetDimension() == 3)
+	  {
+	    PopStatus ();
+	    PushStatusF ("curving faces");
+	    
+	    for (int j=0; j<facecoeffsindex[top.GetNFaces()]; j++)
+	      facecoeffs[j] = Vec<3>(0.,0.,0.);
+	    
+	    for (SurfaceElementIndex i = 0; i < mesh.GetNSE(); i++)   // for all surface elements
+	      {
+		if (multithread.terminate) return;
+
+	        SetThreadPercent( double(100*i/mesh.GetNSE()) );
+
+		Element2d elem = mesh[i];
+		
+		if (elem.GetType() == TRIG)
+		    fe2d = &trig;
+                else
+		    fe2d = &quad;
+
+		fe2d->SetElementNumber (i+1);
+
+		int npoints = fe2d->GetNFaceShapes();
+
+		if (npoints == 0) continue;
+
+		DenseMatrix mat(npoints);
+		DenseMatrix inv(npoints);
+		Vector vec[3];
+
+		for (int k = 0; k < 3; k++)
+		{
+		    vec[k].SetSize(npoints);
+		    for (int n = 1; n <= npoints; n++) vec[k].Set(n, 0.);
+		}
+
+		for (int j = 0; j < nIntegrationPoints; j++)
+		{
+		    for (int k = 0; k < nIntegrationPoints; k++)
+		    {
+			double w;
+			Point<2> xr;
+
+			if (elem.GetType() == TRIG)
+			  {
+			    w = wi[j]*wi[k]*(1-xi[j]);
+			    xr = Point<2> (xi[j], xi[k]*(1-xi[j]));
+			  }
+			else
+			  {
+			    w = wi[j]*wi[k];
+			    xr = Point<2> (xi[j], xi[k]);
+			  }
+
+			fe2d->SetReferencePoint (xr);
+			fe2d->CalcFaceShapes ();
+			fe2d->CalcVertexShapes ();
+			fe2d->CalcEdgeShapes ();
+			fe2d->CalcFaceLaplaceShapes ();
+
+			// integration over the product of the gradients of the face shapes
+
+			for (int n = 0; n < npoints; n++)
+			  for (int m = 0; m < npoints; m++)
+			    mat.Set(n+1, m+1,
+				    mat.Get(n+1,m+1) +
+				    fe2d->GetFaceDShape(n)*fe2d->GetFaceDShape(m)*w);
+
+			// integration over the difference between the exact geometry and the one
+			// defined by vertex and edge shape functions times face shape
+
+			Point<3> xve(0.,0.,0.);
+
+			// vertex shape functions
+			for (int v = 0; v < fe2d->GetNVertices(); v++)
+			  xve = xve + fe2d->GetVertexShape(v) * mesh.Point(fe2d->GetVertexNr(v));
+
+			// edge shape functions
+			int index = 0;
+			for (int e = 0; e < fe2d->GetNEdges(); e++)
+			  {
+			    int gindex = edgecoeffsindex[fe2d->GetEdgeNr(e)-1];
+			    for (int k = 2; k <= fe2d->GetEdgeOrder(e); k++, index++, gindex++)
+			      xve = xve + fe2d->GetEdgeShape(index) * edgecoeffs[gindex];
+			  }
+
+			// exact point
+
+			Point<3> xexact = xve;
+			ref->ProjectToSurface (xexact, mesh.GetFaceDescriptor(elem.GetIndex()).SurfNr());
+
+			Vec<3> v2 = w*(Vec<3>(xexact)-Vec<3>(xve));
+
+			for (int k = 0; k < 3; k++)
+			  for (int n = 0; n < npoints; n++)
+			    vec[k].Set(n+1, vec[k].Get(n+1) - fe2d->GetFaceLaplaceShape(n)*v2(k));
+		    }
+		}
+
+		CalcInverse(mat,inv);
+		
+		Vector a0(npoints), a1(npoints), a2(npoints);
+		
+		/*
+		a0 = inv*vec[0];
+		a1 = inv*vec[1];
+		a2 = inv*vec[2];
+		*/
+		inv.Mult (vec[0], a0);
+		inv.Mult (vec[1], a1);
+		inv.Mult (vec[2], a2);
+
+		int index = facecoeffsindex[fe2d->GetFaceNr()-1];
+		
+		for (int n = 0; n < npoints; n++, index++)
+		  facecoeffs[index] =  Vec<3>(a0.Elem(n+1), a1.Elem(n+1), a2.Elem(n+1));
+	      }
+	  }
+	
+
+
+	
+/*
+	cout << "WARNING: L2-Projection for faces" << endl;
+
+	// evaluate face points
+
+	if (mesh.GetDimension() == 3)
+	{
+	    for (int i=0; i<facecoeffsindex[top.GetNFaces()]; i++)
+		facecoeffs[i] = Vec<3>(0.,0.,0.);
+
+	    for (SurfaceElementIndex i = 0; i < mesh.GetNSE(); i++)   // for all surface elements
+	    {
+		Element2d elem = mesh[i];
+		
+		if (elem.GetType() == TRIG)
+		    fe2d = &trig;
+                else
+		    fe2d = &quad;
+
+		fe2d->SetElementNumber (i+1);
+
+		int npoints = fe2d->GetNFaceShapes();
+
+		if (npoints == 0) continue;
+
+		DenseMatrix mat(npoints);
+		DenseMatrix inv(npoints);
+		Vector vec[3];
+
+		for (int k = 0; k < 3; k++)
+		{
+		    vec[k].SetSize(npoints);
+		    for (int n = 1; n <= npoints; n++) vec[k].Set(n, 0.);
+		}
+
+		for (int j = 0; j < nIntegrationPoints; j++)
+		{
+		    for (int k = 0; k < nIntegrationPoints; k++)
+		    {
+			double w;
+			Point<2> xr;
+
+			if (elem.GetType() == TRIG)
+			{
+			    w = wi[j]*wi[k]*(1-xi[j]);
+			    xr = Point<2> (xi[j], xi[k]*(1-xi[j]));
+			}
+			else
+			{
+			    w = wi[j]*wi[k];
+			    xr = Point<2> (xi[j], xi[k]);
+			}
+
+			fe2d->SetReferencePoint (xr);
+//			fe2d->CalcFaceDShape (false, true);
+			fe2d->CalcFaceShapes ();
+
+			// integration over the product of the gradients of the face shapes
+
+			for (int n = 0; n < npoints; n++)
+			    for (int m = 0; m < npoints; m++)
+				    mat.Set(n+1, m+1, mat.Get(n+1,m+1) +
+					    fe2d->GetFaceShape(n)*fe2d->GetFaceShape(m)*w);
+
+			// integration over the difference between the exact geometry and the one
+			// defined by vertex and edge shape functions times face shape
+
+			Point<3> xve(0.,0.,0.);
+
+			// vertex shape functions
+			fe2d->CalcVertexShapes ();
+//			fe2d->CalcVertexShape (true, false);
+			for (int v = 0; v < fe2d->GetNVertices(); v++)
+			    xve = xve + fe2d->GetVertexShape(v) * mesh.Point(fe2d->GetVertexNr(v));
+
+			// edge shape functions
+//			fe2d->CalcEdgeShape (true, false);
+			fe2d->CalcEdgeShapes ();
+
+			int index = 0;
+			for (int e = 0; e < fe2d->GetNEdges(); e++)
+			{
+			    int gindex = edgecoeffsindex[fe2d->GetEdgeNr(e)-1];
+
+			    for (int k = 2; k <= fe2d->GetEdgeOrder(e); k++, index++, gindex++)
+				xve = xve + fe2d->GetEdgeShape(index) * edgecoeffs[gindex];
+			}
+
+			// exact point
+
+			Point<3> xexact = xve;
+			ref->ProjectToSurface (xexact, mesh.GetFaceDescriptor(elem.GetIndex()).SurfNr());
+
+			Vec<3> v = w*(Vec<3>(xexact)-Vec<3>(xve));
+
+			fe2d->CalcFaceLaplaceShapes ();
+
+			for (int k = 0; k < 3; k++)
+			    for (int n = 0; n < npoints; n++)
+				vec[k].Set(n+1, vec[k].Get(n+1) + fe2d->GetFaceShape(n)*v(k));
+			}
+		    }
+
+ 		    CalcInverse(mat,inv);
+
+		    Vector a0, a1, a2;
+
+		    a0 = inv*vec[0];
+		    a1 = inv*vec[1];
+		    a2 = inv*vec[2];
+
+		    int index = facecoeffsindex[fe2d->GetFaceNr()-1];
+
+		    for (int n = 0; n < npoints; n++, index++)
+			facecoeffs[index] =  Vec<3>(a0(n+1), a1(n+1), a2(n+1));
+	    }
+	}
+*/
+
+
+    PrintMessage (5, "reducing order");
+   
+    for (e = 0; e < top.GetNEdges(); e++)
+      if (edgeorder[e] > 1)
+	{
+	  int i;
+	  double maxcoeff = 0.;
+
+	  for (i = edgecoeffsindex[e]; i < edgecoeffsindex[e+1]; i++)
+	    maxcoeff = max2 (maxcoeff, edgecoeffs[i].Length());
+
+	  if (maxcoeff < 1e-12) edgeorder[e] = 1;
+	}
+
+    for (f = 0; f < top.GetNFaces(); f++)
+      if (faceorder[f] > 1)
+	{
+	  int i;
+	  double maxcoeff = 0.;
+
+	  for (i = facecoeffsindex[f]; i < facecoeffsindex[f+1]; i++)
+	    maxcoeff = max2 (maxcoeff, facecoeffs[i].Length());
+
+	  if (maxcoeff < 1e-12) faceorder[f] = 1;
+	}
+
+    isHighOrder = 1;              // true
+
+    PrintMessage(1, "done");
+    PopStatus();
+    //	cout << "finished" << endl;
+    }
+
+} // namespace netgen
diff --git a/Netgen/libsrc/meshing/delaunay.cpp b/Netgen/libsrc/meshing/delaunay.cpp
new file mode 100644
index 0000000000..8e44c5f739
--- /dev/null
+++ b/Netgen/libsrc/meshing/delaunay.cpp
@@ -0,0 +1,1652 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+
+// #define TEST 
+// #define TEST2
+
+namespace netgen
+{
+  class DelaunayTet
+  {
+    PointIndex pnums[4];
+    int nb[4];
+
+  public:
+    DelaunayTet () { ; }
+
+    DelaunayTet (const DelaunayTet & el)
+    {
+      for (int i = 0; i < 4; i++)
+	pnums[i] = el[i];
+    }
+
+    DelaunayTet (const Element & el)
+    {
+      for (int i = 0; i < 4; i++)
+	pnums[i] = el[i];
+    }
+    
+    PointIndex & PNum(int i) { return pnums[i-1]; }
+    PointIndex PNum(int i) const { return pnums[i-1]; }
+
+    PointIndex & operator[] (int i) { return pnums[i]; }
+    PointIndex operator[] (int i) const { return pnums[i]; }
+
+    int & NB(int i) { return nb[i-1]; }
+    int NB(int i) const { return nb[i-1]; }
+
+    inline void GetFace (int i, INDEX_3 & face) const;
+    inline int FaceNr (INDEX_3 & face) const;  // which face nr is it ?
+    inline void GetFace (int i, Element2d & face) const;
+  };
+
+
+
+  inline int DelaunayTet :: FaceNr (INDEX_3 & face) const
+  {
+    for (int i = 0; i < 3; i++)
+      if (pnums[i] != face.I1() && 
+	  pnums[i] != face.I2() && 
+	  pnums[i] != face.I3())
+	return i+1;
+    return 4;
+  }
+
+  static const int deltetfaces[][3] = 
+    { { 2, 3, 4 },
+      { 3, 1, 4 },
+      { 1, 2, 4 },
+      { 2, 1, 3 } };
+
+
+  inline void DelaunayTet :: GetFace (int i, INDEX_3 & face) const
+  {
+    face.I(1) = PNum(deltetfaces[i-1][0]);
+    face.I(2) = PNum(deltetfaces[i-1][1]);
+    face.I(3) = PNum(deltetfaces[i-1][2]);
+  }
+
+  inline void DelaunayTet :: GetFace (int i, Element2d & face) const
+  {
+    face.SetType(TRIG);
+    face[0] = PNum(deltetfaces[i-1][0]);
+    face[1] = PNum(deltetfaces[i-1][1]);
+    face[2] = PNum(deltetfaces[i-1][2]);
+  }
+
+
+
+
+
+
+
+
+
+  /*
+    Table to maintain neighbour elements
+  */
+  class MeshNB
+  {
+    // face nodes -> one element
+    INDEX_3_CLOSED_HASHTABLE<int> faces;
+    //
+    ARRAY<DelaunayTet> & tets;
+  public:
+
+    // estimated number of points
+    MeshNB (ARRAY<DelaunayTet> & atets, int np)
+      : faces(200), tets(atets)
+    { ; }
+
+
+    // add element with 4 nodes
+    void Add (int elnr);
+
+    // delete element with 4 nodes
+    void Delete (int elnr);
+
+    // get neighbour of element elnr in direction fnr 
+    int GetNB (int elnr, int fnr)
+    { return tets.Get(elnr).NB(fnr); }
+
+    //
+    void ResetFaceHT (int size)
+    {
+      faces.SetSize (size);
+    }
+    
+    void PrintMemInfo (ostream & ost) const;
+  };
+
+
+
+  void MeshNB :: Add (int elnr)
+  {
+    INDEX_3 i3, i32; 
+
+    DelaunayTet & el = tets.Elem(elnr);
+
+    for (int i = 1; i <= 4; i++)
+      {
+	el.GetFace (i, i3);
+	i3.Sort();
+      
+	int bnr, posnr, othertet;
+
+	if (!faces.PositionCreate (i3, posnr))
+	  {
+	    // face already in use
+	    faces.GetData (posnr, othertet);
+
+	    el.NB(i) = othertet;
+	  
+	    if (othertet)
+	      {
+		int fnr = tets.Get(othertet).FaceNr (i3);
+		tets.Elem(othertet).NB(fnr) = elnr;
+	      }
+	  }
+	else
+	  {
+	    faces.SetData (posnr, elnr);	
+	    el.NB(i) = 0;
+	  }
+      }
+  }
+
+
+  void MeshNB :: Delete (int elnr)
+  {
+    INDEX_3 i3; 
+    DelaunayTet & el = tets.Elem(elnr);
+
+    for (int i = 1; i <= 4; i++)
+      {
+	el.GetFace (i, i3);
+	i3.Sort();
+	faces.Set (i3, el.NB(i));
+      } 
+  }
+
+
+  void MeshNB :: PrintMemInfo (ostream & ost) const
+  {
+    /*
+      int uf = 0;
+      for (int i = 1; i <= face2el.Size(); i++)
+      if (face2el.Get(i).I1())
+      uf++;
+
+      ost << "MeshNB: "
+      << "validels = " << validels << " totels = " << el2face.Size() << endl
+      << "validfaces = " << uf << " totfaces = " << face2el.Size() << endl
+      << "face2el: " << face2el.Size() * sizeof(INDEX_2) << endl
+      << "el2face: " << el2face.Size() * sizeof(INDEX_4) << endl;
+    */
+  }
+
+
+
+
+
+  /*
+    connected lists of cosphereical elements
+  */
+  class SphereList 
+  {
+    ARRAY<int> links;
+  public:
+    SphereList () { ; }
+    inline void AddElement (int elnr);
+    inline void DeleteElement (int elnr);
+    inline void ConnectElement (int eli, int toi);
+    void GetList (int eli, ARRAY<int> & linked) const;
+  };
+
+  inline void SphereList :: AddElement (int elnr)
+  {
+    if (elnr > links.Size())
+      links.Append (1);
+    links.Elem(elnr) = elnr;
+  }
+
+  inline void SphereList :: DeleteElement (int elnr)
+  {
+    links.Elem(elnr) = 0;
+  }
+
+  inline void SphereList :: ConnectElement (int eli, int toi)
+  {
+    links.Elem (eli) = links.Get (toi);
+    links.Elem (toi) = eli;
+  }
+
+  void SphereList :: GetList (int eli, ARRAY<int> & linked) const
+  {
+    linked.SetSize (0);
+    int pi = eli;
+
+    do
+      {
+	if (pi <= 0 || pi > links.Size())
+	  {
+	    cerr << "link, error " << endl;
+	    cerr << "pi = " << pi << " linked.s = " << linked.Size() << endl;
+	    exit(1);
+	  }
+	if (linked.Size() > links.Size())
+	  {
+	    cerr << "links have loop" << endl;
+	    exit(1);
+	  }
+
+	linked.Append (pi);
+	pi = links.Get(pi);
+      }
+    while (pi != eli);
+  }
+
+
+
+
+
+  void AddDelaunayPoint (PointIndex newpi, const Point3d & newp, 
+			 ARRAY<DelaunayTet> & tempels, 
+			 Mesh & mesh,
+			 Box3dTree & tettree, 
+			 MeshNB & meshnb,
+			 ARRAY<Point3d> & centers, ARRAY<double> & radi2,
+			 ARRAY<int> & connected, ARRAY<int> & treesearch, 
+			 ARRAY<int> & freelist, SphereList & list,
+			 IndexSet & insphere, IndexSet & closesphere)
+  {
+    int i, j, k, l;
+
+#ifdef TEST2
+    (*testout) << endl << "add point " << newp << endl;
+#endif
+  
+    /*
+      find any sphere, such that newp is contained in
+    */
+  
+    DelaunayTet el;
+    int cfelind = -1;
+
+    const Point3d * pp[4];
+    Point3d pc;
+    double r2;
+    Point3d tpmin, tpmax;
+
+    tettree.GetIntersecting (newp, newp, treesearch);
+    for (j = 0; j < treesearch.Size(); j++)
+      {
+	int jjj = treesearch[j];
+	if (Dist2 (centers.Get(jjj), newp) < radi2.Get(jjj))
+	  {
+	    el = tempels.Get(jjj);
+	    cfelind = jjj;
+	    break;
+	  }
+      }
+  
+    /*
+      if (!felind)
+      {
+      cerr << "not in any sphere, 1" << endl;
+      // old, non tree search
+
+      double mindist = 1e10;
+      for (j = 1; j <= tempels.Size(); j++)
+      {
+      if (tempels.Get(j).PNum(1))
+      {
+      double toofar = 
+      Dist2 (centers.Get(j), newp) - radi2.Get(j);
+      if (toofar < mindist || toofar < 1e-7) 
+      {
+      mindist = toofar;
+      cout << " dist2 = " << Dist2 (centers.Get(j), newp)
+      << " radi2 = " << radi2.Get(j) << endl;
+      }
+      if (toofar < 0)
+      {
+      el = tempels.Get(j);
+      felind = j;
+      cout << "sphere found !" << endl;
+      break; 
+      }
+      }
+      }
+      cout << "point is too far from sheres: " << mindist << endl;
+      }
+    */      
+
+    if (cfelind == -1)
+      {
+	PrintWarning ("Delaunay, point not in any sphere");
+	return;
+      }
+	
+
+    /*
+      insphere:     point is in sphere -> delete element
+      closesphere:  point is close to sphere -> considered for same center
+    */
+
+    // save overestimate
+    insphere.SetMaxIndex (2 * tempels.Size() + 5 * mesh.GetNP());
+    closesphere.SetMaxIndex (2 * tempels.Size() + 5 * mesh.GetNP());
+
+    insphere.Clear();
+    closesphere.Clear();
+
+
+    insphere.Add (cfelind);
+      
+    int changed = 1;
+    int nstarti = 1, starti;
+    while (changed)
+      {
+	changed = 0;
+	starti = nstarti;
+	nstarti = insphere.Array().Size()+1;
+
+	// if point in sphere, then it is also closesphere
+	for (j = starti; j < nstarti; j++)
+	  {
+	    int helind = insphere.Array().Get(j);
+	    if (!closesphere.IsIn (helind))
+	      closesphere.Add (helind);
+	  }
+
+	// add connected spheres to insphere - list
+	for (j = starti; j < nstarti; j++)
+	  {
+	    list.GetList (insphere.Array().Get(j), connected);
+	    for (k = 1; k <= connected.Size(); k++)
+	      {
+		int celind = connected.Get(k);
+
+		if (tempels.Get(celind).PNum(1) != -1 && 
+		    !insphere.IsIn (celind))
+		  {
+		    changed = 1;
+		    insphere.Add (celind);
+		  }
+	      }
+	  }
+
+	// check neighbour-tets
+	for (j = starti; j < nstarti; j++)
+	  for (k = 1; k <= 4; k++)
+	    {
+	      int helind = insphere.Array().Get(j);
+	      int nbind = meshnb.GetNB (helind, k);
+
+	      if (nbind && !insphere.IsIn (nbind) )
+		{
+		  if (Dist2 (centers.Get(nbind), newp) 
+		      < radi2.Get(nbind) * (1+1e-8) )
+		    {
+		      closesphere.Add (nbind);
+		    }
+
+		  if (Dist2 (centers.Get(nbind), newp) 
+		      < radi2.Get(nbind) * (1 + 1e-12))
+		    {
+		      // point is in sphere -> remove tet
+		      insphere.Add (nbind);
+		      changed = 1;
+		    }
+		  else
+		    {
+		      Element2d face;
+		      tempels.Get(helind).GetFace (k, face);
+
+		      const Point3d & p1 = mesh.Point (face.PNum(1));
+		      const Point3d & p2 = mesh.Point (face.PNum(2));
+		      const Point3d & p3 = mesh.Point (face.PNum(3));
+
+		      Vec3d v1(p1, p2);
+		      Vec3d v2(p1, p3);
+		      Vec3d n = Cross (v1, v2);
+		      n /= n.Length();
+
+		      if (n * Vec3d (p1, mesh.Point (tempels.Get(helind).PNum(k))) > 0)
+			n *= -1;
+
+		      double dist = n * Vec3d (p1, newp);
+
+
+		      if (dist > -1e-10)  // 1e-10
+			{
+			  insphere.Add (nbind);
+			  changed = 1;
+			}
+
+
+		    }
+		}
+	    }
+      } // while (changed)
+
+    //      (*testout) << "newels: " << endl;
+    ARRAY<Element> newels;
+
+    for (j = 1; j <= insphere.Array().Size(); j++)
+      for (k = 1; k <= 4; k++)
+	{
+	  //	    int elind = insphere.Array().Get(j);
+	  int celind = insphere.Array().Get(j);
+	  int nbind = meshnb.GetNB (celind, k);
+
+	  if (!nbind || !insphere.IsIn (nbind))
+	    {
+	      Element2d face;
+	      tempels.Get (celind).GetFace (k, face);
+		
+	      Element newel(4);
+	      for (l = 1; l <= 3; l++)
+		newel.PNum(l) = face.PNum(l);
+	      newel.PNum(4) = newpi;
+
+	      newels.Append (newel);
+
+	      Vec3d v1(mesh.Point (face.PNum(1)), mesh.Point (face.PNum(2)));
+	      Vec3d v2(mesh.Point (face.PNum(1)), mesh.Point (face.PNum(3)));
+	      Vec3d n = Cross (v1, v2);
+	      n /= n.Length();
+	      if (n * Vec3d(mesh.Point (face.PNum(1)), 
+			    mesh.Point (tempels.Get(insphere.Array().Get(j)).PNum(k)))
+		  > 0)
+		n *= -1;
+
+	      double hval = n * Vec3d (mesh.Point (face.PNum(1)), newp);
+		
+	      if (hval > -1e-12)
+		{
+		  cerr << "vec to outer" << endl;
+		  (*testout) << "vec to outer, hval = " << hval << endl;
+		  (*testout) << "v1 x v2 = " << Cross (v1, v2) << endl;
+		  (*testout) << "facep: "
+			     << mesh.Point (face.PNum(1)) << " "
+			     << mesh.Point (face.PNum(2)) << " "
+			     << mesh.Point (face.PNum(3)) << endl;
+		}
+	    }
+	}
+
+    meshnb.ResetFaceHT (10*insphere.Array().Size()+1);
+
+    for (j = 1; j <= insphere.Array().Size(); j++)
+      {
+	//	  int elind = 
+	int celind = insphere.Array().Get(j);
+
+	meshnb.Delete (celind); 
+	list.DeleteElement (celind);
+	  
+	for (k = 1; k <= 4; k++)
+	  tempels.Elem(celind).PNum(k) = -1;
+
+	((ADTree6&)tettree.Tree()).DeleteElement (celind);
+	freelist.Append (celind);
+      }
+
+
+    int hasclose = 0;
+    for (j = 1; j <= closesphere.Array().Size(); j++)
+      {
+	int ind = closesphere.Array().Get(j);
+	if (!insphere.IsIn(ind) &&
+	    fabs (Dist2 (centers.Get (ind), newp) - radi2.Get(ind)) < 1e-8 )
+	  hasclose = 1;
+      }
+
+    for (j = 1; j <= newels.Size(); j++)
+      {
+	int nelind;
+
+	if (!freelist.Size())
+	  {
+	    tempels.Append (newels.Get(j));
+	    nelind = tempels.Size();
+	  }
+	else
+	  {
+	    nelind = freelist.Last();
+	    freelist.DeleteLast();
+
+	    tempels.Elem(nelind) = newels.Get(j);
+	  }
+
+	meshnb.Add (nelind);
+	list.AddElement (nelind);
+
+	for (k = 1; k <= 4; k++)
+	  pp[k-1] = &mesh.Point (newels.Get(j).PNum(k));
+
+	if (CalcSphereCenter (&pp[0], pc) )
+	  {
+	    PrintSysError ("Delaunay: New tet is flat");
+
+	    (*testout) << "new tet is flat" << endl;
+	    for (k = 1; k <= 4; k++)
+	      (*testout) << newels.Get(j).PNum(k) << " ";
+	    (*testout) << endl;
+	    for (k = 1; k <= 4; k++)
+	      (*testout) << *pp[k-1] << " ";
+	    (*testout) << endl;
+	  }
+
+	r2 = Dist2 (*pp[0], pc);
+	if (hasclose)
+	  for (k = 1; k <= closesphere.Array().Size(); k++)
+	    {
+	      int csameind = closesphere.Array().Get(k); 
+	      if (!insphere.IsIn(csameind) &&
+		  fabs (r2 - radi2.Get(csameind)) < 1e-10 && 
+		  Dist (pc, centers.Get(csameind)) < 1e-10)
+		{
+		  pc = centers.Get(csameind);
+		  r2 = radi2.Get(csameind);
+		  list.ConnectElement (nelind, csameind);
+		  break;
+		}
+	    }
+      
+	if (centers.Size() < nelind)
+	  {
+	    centers.Append (pc);
+	    radi2.Append (r2);
+	  }
+	else
+	  {
+	    centers.Elem(nelind) = pc;
+	    radi2.Elem(nelind) = r2;
+	  }
+
+	closesphere.Add (nelind);
+	  
+	tpmax = tpmin = *pp[0];
+	for (k = 1; k <= 3; k++)
+	  {
+	    tpmin.SetToMin (*pp[k]);
+	    tpmax.SetToMax (*pp[k]);
+	  }
+	tpmax = tpmax + 0.01 * (tpmax - tpmin);
+	tettree.Insert (tpmin, tpmax, nelind);
+      }
+  }
+
+
+
+
+
+
+  void Delaunay1 (Mesh & mesh, const MeshingParameters & mp, AdFront3 * adfront,
+		  ARRAY<DelaunayTet> & tempels,
+		  int oldnp, DelaunayTet & startel, Point3d & pmin, Point3d & pmax)
+  {
+    int i, j, k, l;
+    const Point3d * pp[4];
+
+    ARRAY<Point3d> centers;
+    ARRAY<double> radi2;
+  
+    Point3d tpmin, tpmax;
+
+
+    // new: local box
+    mesh.GetBox (pmax, pmin);
+    for (i = 1; i <= adfront->GetNF(); i++)
+      {
+	const Element2d & face = adfront->GetFace(i);
+	for (j = 0; j < face.GetNP(); j++)
+	  {
+	    pmin.SetToMin  (mesh.Point (face[j]));
+	    pmax.SetToMax  (mesh.Point (face[j]));
+	  }
+      }
+  
+
+    Vec3d vdiag(pmin, pmax);
+    // double r1 = vdiag.Length();
+    double r1 = sqrt (3.0) * max3(vdiag.X(), vdiag.Y(), vdiag.Z());
+    vdiag = Vec3d (r1, r1, r1);
+    double r2;
+
+    Point3d pmin2 = pmin - 8 * vdiag;
+    Point3d pmax2 = pmax + 8 * vdiag;
+
+    Point3d cp1(pmin2), cp2(pmax2), cp3(pmax2), cp4(pmax2);
+    cp2.X() = pmin2.X();
+    cp3.Y() = pmin2.Y();
+    cp4.Z() = pmin2.Z();
+
+
+
+
+    int np = mesh.GetNP();
+
+    startel.PNum(1) = mesh.AddPoint (cp1);
+    startel.PNum(2) = mesh.AddPoint (cp2);
+    startel.PNum(3) = mesh.AddPoint (cp3);
+    startel.PNum(4) = mesh.AddPoint (cp4);
+
+    // flag points to use for Delaunay:
+    BitArrayChar<PointIndex::BASE> usep(np);
+    usep.Clear();
+    for (i = 1; i <= adfront->GetNF(); i++)
+      {
+	const Element2d & face = adfront->GetFace(i);
+	for (j = 0; j < face.GetNP(); j++)
+	  usep.Set (face[j]);
+      }
+
+    for (i = oldnp + PointIndex::BASE; 
+	 i < np + PointIndex::BASE; i++)
+      usep.Set (i);
+
+    for (i = 0; i < mesh.LockedPoints().Size(); i++)
+      usep.Set (mesh.LockedPoints()[i]);
+  
+
+    ARRAY<int> freelist;
+
+
+    int cntp = 0;
+
+    MeshNB meshnb (tempels, mesh.GetNP() + 5);
+    SphereList list;
+
+    pmin2 = pmin2 + 0.1 * (pmin2 - pmax2);
+    pmax2 = pmax2 + 0.1 * (pmax2 - pmin2);
+
+    Box3dTree tettree(pmin2, pmax2);
+
+
+    tempels.Append (startel);
+    meshnb.Add (1);
+    list.AddElement (1);
+    ARRAY<int> connected, treesearch;
+
+
+    tpmin = tpmax = mesh.Point(startel.PNum(1));
+    for (k = 2; k <= 4; k++)
+      {
+	tpmin.SetToMin (mesh.Point (startel.PNum(k)));
+	tpmax.SetToMax (mesh.Point (startel.PNum(k)));
+      }
+    tpmax = tpmax + 0.01 * (tpmax - tpmin);
+    tettree.Insert (tpmin, tpmax, 1);
+
+
+    Point3d pc;
+	  
+    for (k = 1; k <= 4; k++)
+      pp[k-1] = &mesh.Point (startel.PNum(k));
+  
+    CalcSphereCenter (&pp[0], pc);
+
+    centers.Append (pc);
+    radi2.Append (Dist2 (*pp[0], pc));
+
+
+    IndexSet insphere(mesh.GetNP());
+    IndexSet closesphere(mesh.GetNP());
+
+
+
+#ifdef MARK
+    MARK (delaunay1);
+#endif
+
+
+    // "random" reordering of points  (speeds a factor 3 - 5 !!!)
+
+    ARRAY<int> mixed(np);
+    int prims[] = { 11, 13, 17, 19, 23, 29, 31, 37 };
+    int prim;
+  
+    i = 0;
+    while (np % prims[i] == 0) i++;
+    prim = prims[i];
+
+    for (i = 1; i <= np; i++)
+      mixed.Elem(i) = (prim * i) % np + PointIndex::BASE;
+
+    for (i = 1; i <= np; i++)
+      {
+	if (i % 100 == 0)
+	  PrintDot ('+');
+
+	multithread.percent = 100.0 * i / np;
+	if (multithread.terminate)
+	  break;
+
+	PointIndex newpi = mixed.Get(i);
+
+	if (!usep.Test(newpi)) 
+	  continue;
+
+	cntp++;
+
+	const Point3d & newp = mesh.Point(newpi);
+      
+	AddDelaunayPoint (newpi, newp, tempels, mesh,
+			  tettree, meshnb, centers, radi2, 
+			  connected, treesearch, freelist, list, insphere, closesphere);
+      }
+
+#ifdef MARK
+    MARK (delaunay3);
+#endif  
+
+
+
+    for (i = tempels.Size(); i >= 1; i--)
+      if (tempels.Get(i).PNum(1) <= 0)
+	tempels.DeleteElement (i);
+
+    PrintDot ('\n');
+
+    PrintMessage (3, "Points: ", cntp);
+    PrintMessage (3, "Elements: ", tempels.Size());
+    //   (*mycout) << cntp << " / " << tempels.Size() << " points/elements" << endl;
+
+    /*
+      cout << "tempels: ";
+      tempels.PrintMemInfo(cout);
+      cout << "Searchtree: ";
+      tettree.Tree().PrintMemInfo(cout);
+      cout << "MeshNB: ";
+      meshnb.PrintMemInfo(cout);
+    */
+  }
+
+
+
+
+
+
+  void Meshing3 :: Delaunay (Mesh & mesh, const MeshingParameters & mp)
+  {
+    PointIndex pi;
+    int i, j, k, l;
+    int ii;
+    int np, ne;
+
+    PrintMessage (1, "Delaunay meshing");
+    PrintMessage (3, "number of points: ", mesh.GetNP());
+    PushStatus ("Delaunay meshing");
+
+
+
+    ARRAY<DelaunayTet> tempels;
+
+    Point3d pmin, pmax;
+    Point3d tpmin, tpmax;
+    const Point3d * pp[4];
+  
+  
+    DelaunayTet startel;
+
+    int oldnp = mesh.GetNP();
+    if (mp.blockfill)
+      {
+	BlockFillLocalH (mesh, mp);
+	PrintMessage (3, "number of points: ", mesh.GetNP());
+      }
+
+    np = mesh.GetNP();
+
+    Delaunay1 (mesh, mp, adfront, tempels, oldnp, startel, pmin, pmax);
+  
+
+    {
+      // improve delaunay - mesh by swapping !!!!
+
+      Mesh tempmesh;
+      for (pi = PointIndex::BASE; pi < mesh.GetNP()+PointIndex::BASE; pi++)
+	tempmesh.AddPoint (mesh[pi]);
+      
+      for (i = 1; i <= tempels.Size(); i++)
+	{   
+	  Element el(4);
+	  for (j = 1; j <= 4; j++)
+	    el.PNum(j) = tempels.Elem(i).PNum(j);
+
+	  el.SetIndex (1);
+	  const Point3d & lp1 = mesh.Point (el.PNum(1));
+	  const Point3d & lp2 = mesh.Point (el.PNum(2));
+	  const Point3d & lp3 = mesh.Point (el.PNum(3));
+	  const Point3d & lp4 = mesh.Point (el.PNum(4));
+	  Vec3d v1(lp1, lp2);
+	  Vec3d v2(lp1, lp3);
+	  Vec3d v3(lp1, lp4);
+	  Vec3d n = Cross (v1, v2);
+	  double vol = n * v3;
+	
+	  if (vol > 0)
+	    Swap (el.PNum(3), el.PNum(4));
+	
+	  tempmesh.AddVolumeElement (el);
+	}
+
+      MeshQuality3d (tempmesh);
+    
+      for (i = 1; i <= mesh.GetNOpenElements(); i++)
+	{
+	  Element2d sel = mesh.OpenElement(i);
+	  sel.SetIndex(1);
+	  tempmesh.AddSurfaceElement (sel);
+	  Swap (sel.PNum(2), sel.PNum(3));
+	  tempmesh.AddSurfaceElement (sel);
+	}
+
+
+      for (i = 1; i <= 4; i++)
+	{
+	  Element2d self(3);
+	  self.SetIndex (1);
+	  startel.GetFace (i, self);
+	  tempmesh.AddSurfaceElement (self);
+	}
+
+      
+      tempmesh.AddFaceDescriptor (FaceDescriptor (1, 1, 0, 0));
+      tempmesh.AddFaceDescriptor (FaceDescriptor (2, 1, 0, 0));
+    
+
+      //  for (i = mesh.GetNP() - 3; i <= mesh.GetNP(); i++)
+      //    tempmesh.AddLockedPoint (i);
+      for (pi = PointIndex::BASE; 
+	   pi < tempmesh.GetNP() + PointIndex::BASE; pi++)
+	tempmesh.AddLockedPoint (pi);
+
+      //    tempmesh.PrintMemInfo(cout);
+      // tempmesh.Save ("tempmesh.vol");
+
+      for (i = 1; i <= 2; i++)
+	{ 
+	  tempmesh.FindOpenElements ();
+
+	  PrintMessage (5, "Num open: ", tempmesh.GetNOpenElements());
+	  tempmesh.CalcSurfacesOfNode ();
+
+	  tempmesh.FreeOpenElementsEnvironment (1);
+
+	  MeshOptimize3d meshopt;
+	  meshopt.SwapImprove(tempmesh, OPT_CONFORM);
+	}
+    
+
+#ifdef STAT_STREAM
+      tempmesh.FindOpenElements ();
+      PrintMessage (5, "Num open: ", tempmesh.GetNOpenElements());
+      (*statout) << tempmesh.GetNOpenElements() << " & " << endl;
+#endif   
+
+      MeshQuality3d (tempmesh);
+    
+      tempels.SetSize(0);
+      for (i = 1; i <= tempmesh.GetNE(); i++)
+	tempels.Append (tempmesh.VolumeElement(i));
+    }
+
+
+
+
+    // remove degenerated
+
+    BitArray badnode(mesh.GetNP());
+    badnode.Clear();
+    int ndeg = 0;
+    for (i = 1; i <= tempels.Size(); i++)
+      {
+	Element el(4);
+	for (j = 1; j <= 4; j++)
+	  el.PNum(j) = tempels.Elem(i).PNum(j);
+	//      Element & el = tempels.Elem(i);
+	const Point3d & lp1 = mesh.Point (el.PNum(1));
+	const Point3d & lp2 = mesh.Point (el.PNum(2));
+	const Point3d & lp3 = mesh.Point (el.PNum(3));
+	const Point3d & lp4 = mesh.Point (el.PNum(4));
+	Vec3d v1(lp1, lp2);
+	Vec3d v2(lp1, lp3);
+	Vec3d v3(lp1, lp4);
+	Vec3d n = Cross (v1, v2);
+	double vol = n * v3;
+
+	double h = v1.Length() + v2.Length() + v3.Length();
+	if (fabs (vol) < 1e-8 * (h * h * h) &&
+	    (el.PNum(1) <= np && el.PNum(2) <= np &&
+	     el.PNum(3) <= np && el.PNum(4) <= np) )   // old: 1e-12
+	  {
+	    badnode.Set(el.PNum(1));
+	    badnode.Set(el.PNum(2));
+	    badnode.Set(el.PNum(3));
+	    badnode.Set(el.PNum(4));
+	    ndeg++;
+	    (*testout) << "vol = " << vol << " h = " << h << endl;
+	  }
+
+	if (vol > 0)
+	  Swap (el.PNum(3), el.PNum(4));
+      }
+
+    ne = tempels.Size();
+    for (i = ne; i >= 1; i--)
+      {
+	const DelaunayTet & el = tempels.Get(i);
+	if (badnode.Test(el.PNum(1)) ||
+	    badnode.Test(el.PNum(2)) ||
+	    badnode.Test(el.PNum(3)) ||
+	    badnode.Test(el.PNum(4)) )
+	  tempels.DeleteElement(i);
+      }
+
+  
+    PrintMessage (3, ndeg, " degenerated elements removed");
+
+    // find surface triangles which are no face of any tet
+
+    INDEX_3_HASHTABLE<int> openeltab(mesh.GetNOpenElements()+3);
+    ARRAY<int> openels;
+    for (i = 1; i <= mesh.GetNOpenElements(); i++)
+      {
+	const Element2d & tri = mesh.OpenElement(i);
+	INDEX_3 i3(tri.PNum(1), tri.PNum(2), tri.PNum(3));
+	i3.Sort();
+	openeltab.Set (i3, i);
+      }
+
+    for (i = 1; i <= tempels.Size(); i++)
+      {
+	for (j = 1; j <= 4; j++)
+	  {
+	    Element2d face;
+	    tempels.Get(i).GetFace (j, face);
+	    INDEX_3 i3(face.PNum(1), face.PNum(2), face.PNum(3));
+	    i3.Sort();
+	    if (openeltab.Used(i3))
+	      openeltab.Set (i3, 0);
+	  }
+      }
+  
+    // and store them in openels
+    for (i = 1; i <= openeltab.GetNBags(); i++)
+      for (j = 1; j <= openeltab.GetBagSize(i); j++)
+	{
+	  INDEX_3 i3;
+	  int fnr;
+	  openeltab.GetData (i, j, i3, fnr);
+	  if (fnr)
+	    openels.Append (fnr);
+	}
+
+
+
+
+
+    // find open triangle with close edge (from halfening of surface squares)
+  
+    INDEX_2_HASHTABLE<INDEX_2> twotrias(mesh.GetNOpenElements()+5); 
+    //  for (i = 1; i <= mesh.GetNOpenElements(); i++)
+    for (ii = 1; ii <= openels.Size(); ii++)
+      {
+	i = openels.Get(ii);
+	const Element2d & el = mesh.OpenElement(i);
+	for (j = 1; j <= 3; j++)
+	  {
+	    INDEX_2 hi2 (el.PNumMod (j), el.PNumMod(j+1));
+	    hi2.Sort();
+	    if (twotrias.Used(hi2))
+	      {
+		INDEX_2 hi3;
+		hi3 = twotrias.Get (hi2);
+		hi3.I2() = el.PNumMod (j+2);
+		twotrias.Set (hi2, hi3);
+	      }
+	    else
+	      {
+		INDEX_2 hi3(el.PNumMod (j+2), 0);
+		twotrias.Set (hi2, hi3);
+	      }
+	  }
+      }
+
+    INDEX_2_HASHTABLE<int> tetedges(tempels.Size() + 5);
+    for (i = 1; i <= tempels.Size(); i++)
+      {
+	const DelaunayTet & el = tempels.Get(i);
+	INDEX_2 i2;
+	for (j = 1; j <= 6; j++)
+	  {
+	    switch (j)
+	      {
+	      case 1: i2 = INDEX_2(el.PNum(1), el.PNum(2)); break;
+	      case 2: i2 = INDEX_2(el.PNum(1), el.PNum(3)); break;
+	      case 3: i2 = INDEX_2(el.PNum(1), el.PNum(4)); break;
+	      case 4: i2 = INDEX_2(el.PNum(2), el.PNum(3)); break;
+	      case 5: i2 = INDEX_2(el.PNum(2), el.PNum(4)); break;
+	      case 6: i2 = INDEX_2(el.PNum(3), el.PNum(4)); break;
+	      }
+	    i2.Sort();
+	    tetedges.Set (i2, 1);
+	  }
+      }
+    //  cout << "tetedges:";
+    //  tetedges.PrintMemInfo (cout);
+
+    for (i = 1; i <= twotrias.GetNBags(); i++)
+      for (j = 1; j <= twotrias.GetBagSize (i); j++)
+	{
+	  INDEX_2 hi2, hi3;
+	  twotrias.GetData (i, j, hi2, hi3);
+	  hi3.Sort();
+	  if (tetedges.Used (hi3))
+	    {
+	      const Point3d & p1 = mesh.Point (hi2.I1());
+	      const Point3d & p2 = mesh.Point (hi2.I2());
+	      const Point3d & p3 = mesh.Point (hi3.I1());
+	      const Point3d & p4 = mesh.Point (hi3.I2());
+	      Vec3d v1(p1, p2);
+	      Vec3d v2(p1, p3);
+	      Vec3d v3(p1, p4);
+	      Vec3d n = Cross (v1, v2);
+	      double vol = n * v3;
+	    
+	      double h = v1.Length() + v2.Length() + v3.Length();
+	      if (fabs (vol) < 1e-4 * (h * h * h))   // old: 1e-12
+		{
+		  badnode.Set(hi3.I1());	
+		  badnode.Set(hi3.I2());	
+		}
+	    }
+	}
+
+
+    ne = tempels.Size();
+    for (i = ne; i >= 1; i--)
+      {
+	const DelaunayTet & el = tempels.Get(i);
+	if (badnode.Test(el.PNum(1)) ||
+	    badnode.Test(el.PNum(2)) ||
+	    badnode.Test(el.PNum(3)) ||
+	    badnode.Test(el.PNum(4)) )
+	  tempels.DeleteElement(i);
+      }
+
+
+
+
+    // find intersecting:
+    PrintMessage (3, "Remove intersecting");
+    if (openels.Size())
+      {
+	Box3dTree setree(pmin, pmax);
+
+	/*      
+		cout << "open elements in search tree: " << openels.Size() << endl;
+		cout << "pmin, pmax = " << pmin << " - " << pmax << endl;
+	*/
+
+	for (i = 1; i <= openels.Size(); i++)
+	  {
+	    int fnr;
+	    fnr = openels.Get(i);
+	    if (fnr)
+	      {
+		const Element2d & tri = mesh.OpenElement(fnr);
+	      
+		Point3d ltpmin (mesh.Point(tri.PNum(1)));
+		Point3d ltpmax (tpmin);
+	      
+		for (k = 2; k <= 3; k++)
+		  {
+		    ltpmin.SetToMin (mesh.Point (tri.PNum(k)));
+		    ltpmax.SetToMax (mesh.Point (tri.PNum(k)));
+		  }
+		setree.Insert (ltpmin, ltpmax, fnr);
+	      }
+	  }
+      
+	ARRAY<int> neartrias;
+	for (i = 1; i <= tempels.Size(); i++)
+	  {
+	    //      const Point3d *pp[4];
+	    int tetpi[4];
+	    DelaunayTet & el = tempels.Elem(i);
+	  
+	    int intersect = 0;
+	  
+	    for (j = 1; j <= 4; j++)
+	      {
+		pp[j-1] = &mesh.Point(el.PNum(j));
+		tetpi[j-1] = el.PNum(j);
+	      }
+	  
+	    Point3d tetpmin(*pp[0]);
+	    Point3d tetpmax(tetpmin);
+	    for (j = 1; j < 4; j++)
+	      {
+		tetpmin.SetToMin (*pp[j]);
+		tetpmax.SetToMax (*pp[j]);
+	      }
+	    tetpmin = tetpmin + 0.01 * (tetpmin - tetpmax);
+	    tetpmax = tetpmax + 0.01 * (tetpmax - tetpmin);
+	  
+	    setree.GetIntersecting (tetpmin, tetpmax, neartrias);
+	  
+	  
+	    //      for (j = 1; j <= mesh.GetNSE(); j++)
+	    //	{
+	    for (int jj = 1; jj <= neartrias.Size(); jj++)
+	      {
+		j = neartrias.Get(jj);
+	      
+		const Element2d & tri = mesh.OpenElement(j);
+		const Point3d *tripp[3];
+		int tripi[3];
+	      
+		for (k = 1; k <= 3; k++)
+		  {
+		    tripp[k-1] = &mesh.Point (tri.PNum(k));
+		    tripi[k-1] = tri.PNum(k);
+		  }
+	      
+		if (IntersectTetTriangle (&pp[0], &tripp[0], tetpi, tripi))
+		  {
+		    int il1, il2;
+		    (*testout) << "intersect !" << endl;
+		    (*testout) << "triind: ";
+		    for (il1 = 0; il1 < 3; il1++)
+		      (*testout) << " " << tripi[il1];
+		    (*testout) << endl;
+		    (*testout) << "tetind: ";
+		    for (il2 = 0; il2 < 4; il2++)
+		      (*testout) << " " << tetpi[il2];
+		    (*testout) << endl;
+		  
+		    (*testout) << "trip: ";
+		    for (il1 = 0; il1 < 3; il1++)
+		      (*testout) << " " << *tripp[il1];
+		    (*testout) << endl;
+		    (*testout) << "tetp: ";
+		    for (il2 = 0; il2 < 4; il2++)
+		      (*testout) << " " << *pp[il2];
+		    (*testout) << endl;
+	      
+		  
+		  
+		    intersect = 1;
+		    break;
+		  }
+	      }
+	  
+	  
+	    if (intersect)
+	      {
+		tempels.DeleteElement(i);
+		i--;
+	      }
+	  }
+      }
+  
+
+#ifdef MARK
+    MARK (delaunay4);
+#endif  
+
+
+
+
+
+
+
+
+    PrintMessage (3, "Remove outer");
+
+    // find connected tets (with no face between, and no hole due
+    // to removed intersecting tets.
+    //  INDEX_3_HASHTABLE<INDEX_2> innerfaces(np);
+
+  
+    INDEX_3_HASHTABLE<int> boundaryfaces(mesh.GetNOpenElements()/3+1);
+    for (i = 1; i <= mesh.GetNOpenElements(); i++)
+      {
+	const Element2d & tri = mesh.OpenElement(i);
+	INDEX_3 i3 (tri.PNum(1), tri.PNum(2), tri.PNum(3));
+	i3.Sort();
+	boundaryfaces.PrepareSet (i3);
+      }
+    boundaryfaces.AllocateElements();
+    for (i = 1; i <= mesh.GetNOpenElements(); i++)
+      {
+	const Element2d & tri = mesh.OpenElement(i);
+	INDEX_3 i3 (tri.PNum(1), tri.PNum(2), tri.PNum(3));
+	i3.Sort();
+	boundaryfaces.Set (i3, 1);
+      }
+
+    for (i = 1; i <= tempels.Size(); i++)
+      for (j = 1; j <= 4; j++)
+	tempels.Elem(i).NB(j) = 0;
+  
+    TABLE<int,PointIndex::BASE> elsonpoint(mesh.GetNP());
+    for (i = 0; i < tempels.Size(); i++)
+      {
+	const DelaunayTet & el = tempels[i];
+	INDEX_4 i4(el[0], el[1], el[2], el[3]);
+	i4.Sort();
+	elsonpoint.IncSizePrepare (i4.I1());
+	elsonpoint.IncSizePrepare (i4.I2());
+      }
+
+    elsonpoint.AllocateElementsOneBlock();
+
+    for (i = 0; i < tempels.Size(); i++)
+      {
+	const DelaunayTet & el = tempels[i];
+	INDEX_4 i4(el[0], el[1], el[2], el[3]);
+	i4.Sort();
+	elsonpoint.Add (i4.I1(), i+1);
+	elsonpoint.Add (i4.I2(), i+1);
+      }
+
+    //  cout << "elsonpoint mem: ";
+    //  elsonpoint.PrintMemInfo(cout);
+
+    INDEX_3_CLOSED_HASHTABLE<INDEX_2> faceht(100);   
+  
+    Element2d hel(3);
+    for (pi = PointIndex::BASE; 
+	 pi < mesh.GetNP()+PointIndex::BASE; pi++)
+      {
+	faceht.SetSize (4 * elsonpoint[pi].Size());
+	for (ii = 0; ii < elsonpoint[pi].Size(); ii++)
+	  {
+	    i = elsonpoint[pi][ii];
+	    const DelaunayTet & el = tempels.Get(i);
+
+	    for (j = 1; j <= 4; j++)
+	      {
+		el.GetFace (j, hel);
+		hel.Invert();
+		hel.NormalizeNumbering();
+	      
+		if (hel.PNum(1) == pi)
+		  {
+		    INDEX_3 i3(hel.PNum(1), hel.PNum(2), hel.PNum(3));
+		  
+		    if (!boundaryfaces.Used (i3))
+		      {
+			if (faceht.Used (i3))
+			  {
+			    INDEX_2 i2 = faceht.Get(i3);
+			  
+			    tempels.Elem(i).NB(j) = i2.I1();
+			    tempels.Elem(i2.I1()).NB(i2.I2()) = i;
+			  }
+			else
+			  {
+			    hel.Invert();
+			    hel.NormalizeNumbering();
+			    INDEX_3 i3(hel.PNum(1), hel.PNum(2), hel.PNum(3));
+			    INDEX_2 i2(i, j);
+			    faceht.Set (i3, i2);
+			  }
+		      }
+		  }
+	      }
+	  }
+      }
+  
+    /*
+      for (i = 1; i <= tempels.Size(); i++)
+      {
+      const DelaunayTet & el = tempels.Get(i);
+      for (j = 1; j <= 4; j++)
+      {
+      INDEX_3 i3;
+      Element2d face;
+      el.GetFace (j, face);
+      for (int kk = 1; kk <= 3; kk++)
+      i3.I(kk) = face.PNum(kk);
+
+      i3.Sort();
+      if (!boundaryfaces.Used (i3))
+      {
+      if (innerfaces.Used(i3))
+      {
+      INDEX_2 i2;
+      i2 = innerfaces.Get(i3);
+      i2.I2() = i;
+      innerfaces.Set (i3, i2);
+      }
+      else
+      {
+      INDEX_2 i2;
+      i2.I1() = i;
+      i2.I2() = 0;
+      innerfaces.Set (i3, i2);
+      }
+      }
+      }
+      }
+    */
+
+    /*
+      (*testout) << "nb elements:" << endl;
+      for (i = 1; i <= tempels.Size(); i++)
+      {
+      (*testout) << i << " ";
+      for (j = 1; j <= 4; j++)
+      (*testout) << tempels.Get(i).NB(j) << " ";
+      (*testout) << endl;
+      }
+  
+      (*testout) << "pairs:" << endl;
+      for (i = 1; i <= innerfaces.GetNBags(); i++)
+      for (j = 1; j <= innerfaces.GetBagSize(i); j++)
+      {
+      INDEX_3 i3;
+      INDEX_2 i2;
+      innerfaces.GetData (i, j, i3, i2);
+      (*testout) << i2 << endl;
+      }
+    */
+
+
+
+
+
+
+
+    /*
+      cout << "innerfaces: ";
+      innerfaces.PrintMemInfo (cout);
+    */
+
+    //  cout << "boundaryfaces: ";
+    //  boundaryfaces.PrintMemInfo (cout);
+
+
+    PrintMessage (5, "tables filled");
+ 
+
+    ne = tempels.Size();
+    BitArray inner(ne), outer(ne);
+    inner.Clear();
+    outer.Clear();
+    ARRAY<int> elstack;
+
+    /*
+      int starti = 0;
+      for (i = 1; i <= ne; i++)
+      {
+      const Element & el = tempels.Get(i);
+      for (j = 1; j <= 4; j++)
+      for (k = 1; k <= 4; k++)
+      if (el.PNum(j) == startel.PNum(k))
+      {
+      outer.Set(i);
+      starti = i;
+      }
+      }
+    */
+
+    while (1)
+      {
+	int inside;
+	bool done = 1;
+
+	for (i = 1; i <= ne; i++)
+	  if (!inner.Test(i) && !outer.Test(i))
+	    {
+	      done = 0;
+	      break;
+	    }
+
+	if (done) break;
+      
+	const DelaunayTet & el = tempels.Get(i);
+	const Point3d & p1 = mesh.Point (el.PNum(1));
+	const Point3d & p2 = mesh.Point (el.PNum(2));
+	const Point3d & p3 = mesh.Point (el.PNum(3));
+	const Point3d & p4 = mesh.Point (el.PNum(4));
+      
+	Point3d ci = Center (p1, p2, p3, p4);
+
+	inside = adfront->Inside (ci);
+
+	/*
+	  cout << "startel: " << i << endl;
+	  cout << "inside = " << inside << endl;
+	  cout << "ins2 = " << adfront->Inside (Center (ci, p1)) << endl;
+	  cout << "ins3 = " << adfront->Inside (Center (ci, p2)) << endl;
+	*/
+      
+	elstack.SetSize(0);
+	elstack.Append (i);
+  
+	while (elstack.Size())
+	  {
+	    int ei = elstack.Last();
+	    elstack.DeleteLast();
+	  
+	    if (!inner.Test(ei) && !outer.Test(ei))
+	      {
+		if (inside)
+		  inner.Set(ei);
+		else
+		  outer.Set(ei);
+
+
+		for (j = 1; j <= 4; j++)
+		  {
+		    INDEX_3 i3;
+		    Element2d face;
+		    tempels.Get(ei).GetFace(j, face);
+		    for (int kk = 1; kk <= 3; kk++)
+		      i3.I(kk) = face.PNum(kk);
+		    i3.Sort();
+		  
+
+		    if (tempels.Get(ei).NB(j))
+		      elstack.Append (tempels.Get(ei).NB(j));
+
+		    /*
+		      if (innerfaces.Used(i3))
+		      {
+		      INDEX_2 i2 = innerfaces.Get(i3);
+		      int other = i2.I1() + i2.I2() - ei;
+
+		      if (other != tempels.Get(ei).NB(j))
+		      cerr << "different1 !!" << endl;
+
+		      if (other)
+		      {
+		      elstack.Append (other);
+		      }
+		      }
+		      else
+		      if (tempels.Get(ei).NB(j))
+		      cerr << "different2 !!" << endl;
+		    */
+
+		  }
+	      }
+	  }
+      }
+
+
+
+    // check outer elements
+    if (debugparam.slowchecks)
+      {
+	for (i = 1; i <= ne; i++)
+	  {
+	    const DelaunayTet & el = tempels.Get(i);
+	    const Point3d & p1 = mesh.Point (el.PNum(1));
+	    const Point3d & p2 = mesh.Point (el.PNum(2));
+	    const Point3d & p3 = mesh.Point (el.PNum(3));
+	    const Point3d & p4 = mesh.Point (el.PNum(4));
+	  
+	    Point3d ci = Center (p1, p2, p3, p4);
+	  
+	    //       if (adfront->Inside (ci) != adfront->Inside (Center (ci, p1)))
+	    // 	cout << "ERROR: outer test unclear !!!" << endl;	
+	  
+	    if (inner.Test(i) != adfront->Inside (ci))
+	      {
+		/*
+		  cout << "ERROR: outer test wrong !!!" 
+		  << "inner = " << int(inner.Test(i))
+		  << "outer = " << int(outer.Test(i))
+		  << endl;
+	      
+		  cout << "Vol = " << Determinant(Vec3d(p1, p2),
+		  Vec3d(p1, p3),
+		  Vec3d(p1, p4)) << endl;
+	      
+		*/	      
+		for (j = 1; j <= 4; j++)
+		  {
+		    Point3d hp;
+		    switch (j)
+		      {
+		      case 1: hp = Center (ci, p1); break;
+		      case 2: hp = Center (ci, p2); break;
+		      case 3: hp = Center (ci, p3); break;
+		      case 4: hp = Center (ci, p4); break;
+		      }
+		    //		  cout << "inside(" << hp << ") = " << adfront->Inside(hp) << endl;
+		  }
+	      
+	      }
+	  
+	    if (adfront->Inside(ci))
+	      outer.Clear(i);
+	    else
+	      outer.Set(i);
+	  }
+      }
+
+
+    /*
+
+    // find bug in innerfaces
+
+    tempmesh.DeleteVolumeElements();
+
+    for (i = 1; i <= innerfaces.GetNBags(); i++)
+    for (j = 1; j <= innerfaces.GetBagSize(i); j++)
+    {
+    INDEX_3 i3;
+    INDEX_2 i2;
+    innerfaces.GetData (i, j, i3, i2);
+    if (i2.I2())
+    {
+    if (outer.Test(i2.I1()) != outer.Test(i2.I2()))
+    {
+    tempmesh.AddVolumeElement (tempels.Get(i2.I1()));
+    tempmesh.AddVolumeElement (tempels.Get(i2.I2()));
+    cerr << "outer flag different for connected els" << endl;
+    }
+    }
+    }
+
+
+    cout << "Check intersectiong once more" << endl;
+
+    for (i = 1; i <= openels.Size(); i++)
+    {
+    tempmesh.SurfaceElement(2*openels.Get(i)).SetIndex(2);
+    tempmesh.SurfaceElement(2*openels.Get(i)-1).SetIndex(2);
+    }
+
+    //  for (i = 1; i <= tempmesh.GetNE(); i++)
+    //    for (j = 1; j <= tempmesh.GetNSE(); j++)
+    i = 6; j = 403;
+    if (i <= tempmesh.GetNE() && j <= tempmesh.GetNSE())
+    if (tempmesh.SurfaceElement(j).GetIndex()==2)
+    {
+    const Element & el = tempmesh.VolumeElement(i);
+    const Element2d & sel = tempmesh.SurfaceElement(j);
+
+    const Point3d *tripp[3];
+    const Point3d *pp[4];
+    int tetpi[4], tripi[3];
+
+    for (k = 1; k <= 4; k++)
+    {
+    pp[k-1] = &tempmesh.Point(el.PNum(k));
+    tetpi[k-1] = el.PNum(k);
+    }
+
+    for (k = 1; k <= 3; k++)
+    {
+    tripp[k-1] = &tempmesh.Point (sel.PNum(k));
+    tripi[k-1] = sel.PNum(k);
+    }
+
+    (*testout) << "Check Triangle " << j << ":";
+    for (k = 1; k <= 3; k++)
+    (*testout) << " " << sel.PNum(k);
+    for (k = 1; k <= 3; k++)
+    (*testout) << " " << tempmesh.Point(sel.PNum(k));
+    (*testout) << endl;
+
+    (*testout) << "Check Tet " << i << ":";
+    for (k = 1; k <= 4; k++)
+    (*testout) << " " << el.PNum(k);
+    for (k = 1; k <= 4; k++)
+    (*testout) << " " << tempmesh.Point(el.PNum(k));
+    (*testout) << endl;
+
+    if (IntersectTetTriangle (&pp[0], &tripp[0], tetpi, tripi))
+    {
+    cout << "Intesection detected !!" << endl;
+    }
+    }
+
+    tempmesh.Save ("temp.vol");
+
+    // end bug search
+    */
+
+
+    for (i = ne; i >= 1; i--)
+      {
+	if (outer.Test(i))
+	  tempels.DeleteElement(i);
+      }
+
+
+    //  (*mycout) << "done" << endl;
+
+
+    // mesh.points.SetSize(mesh.points.Size()-4);
+
+    for (i = 1; i <= tempels.Size(); i++)
+      {
+	Element el(4);
+	for (j = 1; j <= 4; j++)
+	  el.PNum(j) = tempels.Elem(i).PNum(j);
+	mesh.AddVolumeElement (el);
+      }
+
+    PrintMessage (5, "outer removed");
+
+    mesh.FindOpenElements();
+
+    mesh.Compress();
+
+    PopStatus ();
+  }
+}
diff --git a/Netgen/libsrc/meshing/findip.cpp b/Netgen/libsrc/meshing/findip.cpp
new file mode 100644
index 0000000000..7be0ee913d
--- /dev/null
+++ b/Netgen/libsrc/meshing/findip.cpp
@@ -0,0 +1,115 @@
+// find inner point
+
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+namespace netgen
+{
+
+
+template <typename POINTARRAY, typename FACEARRAY>
+int FindInnerPoint (POINTARRAY & points,
+		    FACEARRAY & faces,
+		    Point3d & p)
+{
+  int i, j;
+  ARRAY<Vec3d> a;
+  ARRAY<double> c;
+  Point3d p1, pmin;
+  int i1, i2, i3, i4;
+  int nf;
+  DenseMatrix m(3), inv(3);
+  Vector rs(3), x(3);
+  double f, fmin, hd, hmax;
+
+  nf = faces.Size();
+
+  //  testout << "#faces  = " << faces.Size() << endl;
+  //  testout << "#points = " << points.Size() << endl;
+
+  a.SetSize (nf);
+  c.SetSize (nf);
+
+  for (i = 1; i <= nf; i++)
+    {
+      p1 = points.Get(faces.Get(i).PNum(1));
+      a.Elem(i) = Cross (points.Get(faces.Get(i).PNum(2)) - points.Get(faces.Get(i).PNum(1)),
+		    points.Get(faces.Get(i).PNum(3)) - points.Get(faces.Get(i).PNum(1)));
+      a.Elem(i) /= a.Get(i).Length();
+      c.Elem(i) = - (a.Get(i).X() * p1.X() + a.Get(i).Y() * p1.Y() + a.Get(i).Z() * p1.Z());
+    }
+
+
+  hmax = 0;
+  for (i = 1; i <= nf; i++)
+    {
+      const Element2d & el = faces.Get(i);
+      for (j = 1; j <= 3; j++)
+	{
+	  double hi = Dist (points.Get(el.PNumMod(j)),
+			    points.Get(el.PNumMod(j+1)));
+	  if (hi > hmax) hmax = hi;
+	}
+    }
+
+
+  fmin = 100;
+  pmin = Point3d (0, 0, 0);
+
+  for (i1 = 1; i1 <= nf; i1++)
+    for (i2 = i1+1; i2 <= nf; i2++)
+      for (i3 = i2+1; i3 <= nf; i3++)
+        for (i4 = i3+1; i4 <= nf; i4++)
+          {
+	    m.Elem(1, 1) = a.Get(i1).X() - a.Get(i2).X();
+	    m.Elem(1, 2) = a.Get(i1).Y() - a.Get(i2).Y();
+	    m.Elem(1, 3) = a.Get(i1).Z() - a.Get(i2).Z();
+	    rs.Elem(1) = c.Get(i2) - c.Get(i1);
+
+	    m.Elem(2, 1) = a.Get(i1).X() - a.Get(i3).X();
+	    m.Elem(2, 2) = a.Get(i1).Y() - a.Get(i3).Y();
+	    m.Elem(2, 3) = a.Get(i1).Z() - a.Get(i3).Z();
+	    rs.Elem(2) = c.Get(i3) - c.Get(i1);
+
+	    m.Elem(3, 1) = a.Get(i1).X() - a.Get(i4).X();
+	    m.Elem(3, 2) = a.Get(i1).Y() - a.Get(i4).Y();
+	    m.Elem(3, 3) = a.Get(i1).Z() - a.Get(i4).Z();
+	    rs.Elem(3) = c.Get(i4) - c.Get(i1);
+
+
+	    if (fabs (m.Det()) > 1e-10)
+	      {
+		CalcInverse (m, inv);
+		inv.Mult (rs, x);
+
+		//            testout << "x = " << x << endl;
+
+
+		f = -1e10;
+		for (i = 1; i <= nf; i++)
+		  {
+		    hd = x.Elem(1) * a.Get(i).X()
+		      + x.Elem(2) * a.Get(i).Y()
+		      + x.Elem(3) * a.Get(i).Z()
+		      + c.Get(i);
+		    if (hd > f) f = hd;
+		  }
+
+		if (f < fmin)
+		  {
+		    fmin = f;
+		    pmin.X() = x.Elem(1);
+		    pmin.Y() = x.Elem(2);
+		    pmin.Z() = x.Elem(3);
+		  }
+	      }
+          }
+
+  //  testout << "fmin = " << fmin << endl;
+  //  testout << "pmin = " << pmin << endl;
+
+  p = pmin;
+  return (fmin < -1e-3 * hmax) ? 1 : 0;
+  //  return (fmin < 0) ? 1 : 0;
+}
+}
diff --git a/Netgen/libsrc/meshing/findip.hpp b/Netgen/libsrc/meshing/findip.hpp
new file mode 100644
index 0000000000..b47c3ac6dc
--- /dev/null
+++ b/Netgen/libsrc/meshing/findip.hpp
@@ -0,0 +1,116 @@
+/*
+// find inner point
+
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+namespace netgen
+{
+*/
+
+template <typename POINTARRAY, typename FACEARRAY>
+inline int FindInnerPoint (POINTARRAY & points,
+		    FACEARRAY & faces,
+		    Point3d & p)
+{
+  int i, j;
+  ARRAY<Vec3d> a;
+  ARRAY<double> c;
+  Point3d p1, pmin;
+  int i1, i2, i3, i4;
+  int nf;
+  DenseMatrix m(3), inv(3);
+  Vector rs(3), x(3);
+  double f, fmin, hd, hmax;
+
+  nf = faces.Size();
+
+  //  testout << "#faces  = " << faces.Size() << endl;
+  //  testout << "#points = " << points.Size() << endl;
+
+  a.SetSize (nf);
+  c.SetSize (nf);
+
+  for (i = 1; i <= nf; i++)
+    {
+      p1 = points.Get(faces.Get(i).PNum(1));
+      a.Elem(i) = Cross (points.Get(faces.Get(i).PNum(2)) - points.Get(faces.Get(i).PNum(1)),
+		    points.Get(faces.Get(i).PNum(3)) - points.Get(faces.Get(i).PNum(1)));
+      a.Elem(i) /= a.Get(i).Length();
+      c.Elem(i) = - (a.Get(i).X() * p1.X() + a.Get(i).Y() * p1.Y() + a.Get(i).Z() * p1.Z());
+    }
+
+
+  hmax = 0;
+  for (i = 1; i <= nf; i++)
+    {
+      const Element2d & el = faces.Get(i);
+      for (j = 1; j <= 3; j++)
+	{
+	  double hi = Dist (points.Get(el.PNumMod(j)),
+			    points.Get(el.PNumMod(j+1)));
+	  if (hi > hmax) hmax = hi;
+	}
+    }
+
+
+  fmin = 100;
+  pmin = Point3d (0, 0, 0);
+
+  for (i1 = 1; i1 <= nf; i1++)
+    for (i2 = i1+1; i2 <= nf; i2++)
+      for (i3 = i2+1; i3 <= nf; i3++)
+        for (i4 = i3+1; i4 <= nf; i4++)
+          {
+	    m.Elem(1, 1) = a.Get(i1).X() - a.Get(i2).X();
+	    m.Elem(1, 2) = a.Get(i1).Y() - a.Get(i2).Y();
+	    m.Elem(1, 3) = a.Get(i1).Z() - a.Get(i2).Z();
+	    rs.Elem(1) = c.Get(i2) - c.Get(i1);
+
+	    m.Elem(2, 1) = a.Get(i1).X() - a.Get(i3).X();
+	    m.Elem(2, 2) = a.Get(i1).Y() - a.Get(i3).Y();
+	    m.Elem(2, 3) = a.Get(i1).Z() - a.Get(i3).Z();
+	    rs.Elem(2) = c.Get(i3) - c.Get(i1);
+
+	    m.Elem(3, 1) = a.Get(i1).X() - a.Get(i4).X();
+	    m.Elem(3, 2) = a.Get(i1).Y() - a.Get(i4).Y();
+	    m.Elem(3, 3) = a.Get(i1).Z() - a.Get(i4).Z();
+	    rs.Elem(3) = c.Get(i4) - c.Get(i1);
+
+
+	    if (fabs (m.Det()) > 1e-10)
+	      {
+		CalcInverse (m, inv);
+		inv.Mult (rs, x);
+
+		//            testout << "x = " << x << endl;
+
+
+		f = -1e10;
+		for (i = 1; i <= nf; i++)
+		  {
+		    hd = x.Elem(1) * a.Get(i).X()
+		      + x.Elem(2) * a.Get(i).Y()
+		      + x.Elem(3) * a.Get(i).Z()
+		      + c.Get(i);
+		    if (hd > f) f = hd;
+		  }
+
+		if (f < fmin)
+		  {
+		    fmin = f;
+		    pmin.X() = x.Elem(1);
+		    pmin.Y() = x.Elem(2);
+		    pmin.Z() = x.Elem(3);
+		  }
+	      }
+          }
+
+  //  testout << "fmin = " << fmin << endl;
+  //  testout << "pmin = " << pmin << endl;
+
+  p = pmin;
+  return (fmin < -1e-3 * hmax) ? 1 : 0;
+  //  return (fmin < 0) ? 1 : 0;
+}
+
diff --git a/Netgen/libsrc/meshing/geomsearch.cpp b/Netgen/libsrc/meshing/geomsearch.cpp
new file mode 100644
index 0000000000..53c04e12ac
--- /dev/null
+++ b/Netgen/libsrc/meshing/geomsearch.cpp
@@ -0,0 +1,265 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+
+namespace netgen
+{
+GeomSearch3d :: GeomSearch3d() 
+{
+  size.i1 = 0; size.i2 = 0; size.i3 = 0; 
+};
+
+GeomSearch3d :: ~GeomSearch3d()
+{
+  //delete old Hashtable:
+  if (size.i1 != 0)
+    {
+      for (int i = 1; i <= size.i1*size.i2*size.i3; i++)
+	{
+	  delete hashtable.Get(i);
+	}
+    } 
+}
+
+void GeomSearch3d :: Init (ARRAY <FrontPoint3,PointIndex::BASE> *pointsi, ARRAY <FrontFace> *facesi)
+{
+  points = pointsi;
+  faces = facesi;
+  size.i1 = 0; size.i2 = 0; size.i3 = 0; 
+  reset = 1;
+  hashcount = 1;
+}
+
+void GeomSearch3d :: ElemMaxExt(Point3d& minp, Point3d& maxp, const Element2d& elem)
+{
+  maxp.X()=points->Get(elem.PNum(1)).P().X();
+  maxp.Y()=points->Get(elem.PNum(1)).P().Y();
+  maxp.Z()=points->Get(elem.PNum(1)).P().Z();
+  minp.X()=points->Get(elem.PNum(1)).P().X();
+  minp.Y()=points->Get(elem.PNum(1)).P().Y();
+  minp.Z()=points->Get(elem.PNum(1)).P().Z();
+  
+  for (int i=2; i <= 3; i++)
+    {
+      maxp.X()=max2(points->Get(elem.PNum(i)).P().X(),maxp.X());
+      maxp.Y()=max2(points->Get(elem.PNum(i)).P().Y(),maxp.Y());
+      maxp.Z()=max2(points->Get(elem.PNum(i)).P().Z(),maxp.Z());
+      minp.X()=min2(points->Get(elem.PNum(i)).P().X(),minp.X());
+      minp.Y()=min2(points->Get(elem.PNum(i)).P().Y(),minp.Y());
+      minp.Z()=min2(points->Get(elem.PNum(i)).P().Z(),minp.Z());
+    }
+}
+
+void GeomSearch3d :: MinCoords(const Point3d& p1, Point3d& p2)
+{
+  p2.X()=min2(p1.X(),p2.X());
+  p2.Y()=min2(p1.Y(),p2.Y());
+  p2.Z()=min2(p1.Z(),p2.Z());
+}
+
+void GeomSearch3d :: MaxCoords(const Point3d& p1, Point3d& p2)
+{
+  p2.X()=max2(p1.X(),p2.X());
+  p2.Y()=max2(p1.Y(),p2.Y());
+  p2.Z()=max2(p1.Z(),p2.Z());
+}
+
+void GeomSearch3d :: Create()
+{
+  INDEX i,j,k;
+  if (reset)
+    {
+      const double hashelemsizefactor = 4;
+      reset = 0;
+      /*
+      minext=Point3d(MAXDOUBLE, MAXDOUBLE, MAXDOUBLE);
+      maxext=Point3d(MINDOUBLE, MINDOUBLE, MINDOUBLE);
+      */
+      ElemMaxExt(minext, maxext, faces->Get(1).Face());
+      Point3d maxp, minp;
+      Vec3d midext(0,0,0);
+      
+      //get max Extension of Frontfaces
+      for (i = 1; i <= faces->Size(); i++)
+	{
+	  ElemMaxExt(minp, maxp, faces->Get(i).Face());
+	  MinCoords(minp, minext);
+	  MaxCoords(maxp, maxext);
+	  midext+=maxp-minp;
+	}
+
+
+      maxextreal = maxext;
+      maxext = maxext + 1e-4 * (maxext - minext);
+
+      midext*=1./faces->Size();
+      Vec3d boxext = maxext - minext;
+      
+      //delete old Hashtable:
+      if (size.i1 != 0)
+	{
+	  for (i = 1; i <= size.i1*size.i2*size.i3; i++)
+	    {
+	      delete hashtable.Get(i);
+	    }
+	} 
+      
+      size.i1 = int (boxext.X()/midext.X()/hashelemsizefactor+1);
+      size.i2 = int (boxext.Y()/midext.Y()/hashelemsizefactor+1);
+      size.i3 = int (boxext.Z()/midext.Z()/hashelemsizefactor+1);
+      PrintMessage (5, "hashsizes = ", size.i1, ", ", size.i2, ", ", size.i3);
+      
+      elemsize.X()=boxext.X()/size.i1;
+      elemsize.Y()=boxext.Y()/size.i2;
+      elemsize.Z()=boxext.Z()/size.i3;
+
+      //create Hasharrays:
+      hashtable.SetSize(size.i1*size.i2*size.i3);
+      for (i = 1; i <= size.i1; i++)
+	{
+	  for (j = 1; j <= size.i2; j++)
+	    {
+	      for (k = 1; k <= size.i3; k++)
+		{
+		  INDEX ind=i+(j-1)*size.i1+(k-1)*size.i2*size.i1;
+		  hashtable.Elem(ind) = new ARRAY <int> ();
+		}
+	    }
+	}
+    }
+  else
+    {
+      //Clear all Hash-Arrays
+      for (i = 1; i <= size.i1; i++)
+	{
+	  for (j = 1; j <= size.i2; j++)
+	    {
+	      for (k = 1; k <= size.i3; k++)
+		{
+		  INDEX ind=i+(j-1)*size.i1+(k-1)*size.i2*size.i1;
+		  hashtable.Elem(ind)->SetSize(0);
+		}
+	    }
+	}	  
+    }
+  
+  //Faces in Hashtable einfuegen:
+  for (i = 1; i <= faces->Size(); i++)
+    {
+      AddElem(faces->Get(i).Face(),i);
+    }
+  
+}
+
+void GeomSearch3d :: AddElem(const Element2d& elem, INDEX elemnum)
+{
+  Point3d minp, maxp;
+  ElemMaxExt(minp, maxp, elem);
+  int sx = int ((minp.X()-minext.X())/elemsize.X()+1.);
+  int ex = int ((maxp.X()-minext.X())/elemsize.X()+1.);
+  int sy = int ((minp.Y()-minext.Y())/elemsize.Y()+1.);
+  int ey = int ((maxp.Y()-minext.Y())/elemsize.Y()+1.);
+  int sz = int ((minp.Z()-minext.Z())/elemsize.Z()+1.);
+  int ez = int ((maxp.Z()-minext.Z())/elemsize.Z()+1.);
+  int ix,iy,iz;
+  
+  for (ix = sx; ix <= ex; ix++)
+    {
+      for (iy = sy; iy <= ey; iy++)
+	{
+	  for (iz = sz; iz <= ez; iz++)
+	    {
+	      INDEX ind=ix+(iy-1)*size.i1+(iz-1)*size.i2*size.i1;
+	      if (ind < 1 || ind > size.i1 * size.i2 * size.i3)
+		{
+		  cerr << "Illegal hash-position";
+		  cerr << "Position: " << ix << "," << iy << "," << iz << endl;
+		}
+	      hashtable.Elem(ind)->Append(elemnum);		      
+	    }
+	}
+    }
+}
+
+void GeomSearch3d :: GetLocals(ARRAY<Element2d> & locfaces,  ARRAY<INDEX> & findex,
+			       INDEX fstind, const Point3d& p0, double xh)
+{
+  hashcount++;
+  
+  Point3d minp, maxp, midp; 
+
+  minp=p0-Vec3d(xh,xh,xh); //lay cube over sphere
+  maxp=p0+Vec3d(xh,xh,xh);
+
+  MaxCoords(minext,minp); //cube may not be out of hash-region
+  MinCoords(maxextreal,maxp);
+
+
+  int cluster = faces->Get(fstind).Cluster();
+  
+  int sx = int((minp.X()-minext.X())/elemsize.X()+1.);
+  int ex = int((maxp.X()-minext.X())/elemsize.X()+1.);
+  int sy = int((minp.Y()-minext.Y())/elemsize.Y()+1.);
+  int ey = int((maxp.Y()-minext.Y())/elemsize.Y()+1.);
+  int sz = int((minp.Z()-minext.Z())/elemsize.Z()+1.);
+  int ez = int((maxp.Z()-minext.Z())/elemsize.Z()+1.);
+  int ix,iy,iz,i,k;
+
+  int cnt1 = 0;  // test, how efficient hashtable is
+  int cnt2 = 0;
+  int cnt3 = 0;
+  
+  for (ix = sx; ix <= ex; ix++)
+    {
+      for (iy = sy; iy <= ey; iy++)
+	{
+	  for (iz = sz; iz <= ez; iz++)
+	    {
+	      INDEX ind=ix+(iy-1)*size.i1+(iz-1)*size.i2*size.i1;
+	      
+	      //go through all elements in one hash area
+	      const ARRAY <int> & area = *hashtable.Elem(ind);
+	      for (k = 1; k <= area.Size(); k++)
+		{
+		  cnt2++;
+		  i = area.Get(k);
+		  if (faces->Get(i).Cluster() == cluster && 
+		      faces->Get(i).Valid() &&
+		      faces->Get(i).HashValue() != hashcount && 
+		      i != fstind)
+		    {
+		      cnt1++;
+		      const Element2d & face = faces->Get(i).Face();
+		      
+		      const Point3d & p1 = points->Get(face.PNum(1)).P();
+		      const Point3d & p2 = points->Get(face.PNum(2)).P();
+		      const Point3d & p3 = points->Get(face.PNum(3)).P();
+		      
+		      midp = Center (p1, p2, p3);
+		      
+		      if (Dist2 (midp, p0) <= xh*xh)
+			{
+			  cnt3++;
+			  locfaces.Append(faces->Get(i).Face());
+			  findex.Append(i);
+			  faces->Elem(i).SetHashValue(hashcount);
+			}
+		    }
+		}
+	    }
+	}
+    }
+  /*
+  if (faces->Size() != 0 && hashcount % 200 == 0)
+    {
+      (*mycout) << "n.o.f= " << faces->Size();
+      (*mycout) << ", n.o.lf= " << locfaces.Size();
+      (*mycout) << ", hashf= " << (double)cnt2/(double)faces->Size();
+      (*mycout) << " (" << (double)cnt1/(double)faces->Size();
+      (*mycout) << ", " << (double)cnt3/(double)faces->Size() << ")" << endl;
+    }
+    */
+
+}
+
+}
diff --git a/Netgen/libsrc/meshing/geomsearch.hpp b/Netgen/libsrc/meshing/geomsearch.hpp
new file mode 100644
index 0000000000..5364c24f8d
--- /dev/null
+++ b/Netgen/libsrc/meshing/geomsearch.hpp
@@ -0,0 +1,116 @@
+#ifndef FILE_GEOMSEARCH
+#define FILE_GEOMSEARCH
+
+/**************************************************************************/
+/* File:   geomsearch.hh                                                  */
+/* Author: Johannes Gerstmayr                                             */
+/* Date:   19. Nov. 97                                                    */
+/**************************************************************************/
+
+class FrontPoint3;
+class FrontFace;
+
+  /// class for quick access of 3D-elements; class cannot delete elements, but only append
+class GeomSearch3d
+{
+
+public:
+  ///
+  GeomSearch3d();
+  ///
+  virtual ~GeomSearch3d();
+
+  ///
+  void Init (ARRAY <FrontPoint3,PointIndex::BASE> *pointsi, ARRAY <FrontFace> *facesi);
+
+  ///get elements max extension
+  void ElemMaxExt(Point3d& minp, Point3d& maxp, const Element2d& elem);
+  
+  ///get minimum coordinates of two points ->p2
+  void MinCoords(const Point3d& p1, Point3d& p2);
+
+  ///get minimum coordinates of two points ->p2
+  void MaxCoords(const Point3d& p1, Point3d& p2);
+
+  ///create a hashtable from an existing array of triangles
+  ///sizei = number of pieces in one direction
+  void Create();
+
+  ///add new element to Hashtable
+  void AddElem(const Element2d& elem, INDEX elemnum);
+
+  ///GetLocal faces in sphere with radius xh and middlepoint p
+  void GetLocals(ARRAY<Element2d> & locfaces,  ARRAY<INDEX> & findex,
+		 INDEX fstind, const Point3d& p0, double xh);
+
+private:
+  
+  ARRAY <FrontFace> *faces; // Pointers to Arrays in Adfront
+  ARRAY <FrontPoint3,PointIndex::BASE> *points;
+
+  ARRAY <ARRAY <int>*> hashtable;
+
+  Point3d minext; //extension of Hashdomain
+  Point3d maxext;
+  Point3d maxextreal;
+  Vec3d elemsize;  //size of one Hash-Element
+
+  threeint size; // size of Hashtable in each direction
+  int reset;
+  int hashcount;
+};
+
+#endif
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Netgen/libsrc/meshing/global.cpp b/Netgen/libsrc/meshing/global.cpp
new file mode 100644
index 0000000000..b13367b1dc
--- /dev/null
+++ b/Netgen/libsrc/meshing/global.cpp
@@ -0,0 +1,53 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+namespace netgen
+{
+  ostream * testout;
+
+  ostream * mycout;
+  ostream * myerr;
+
+
+  // Flags globflags; // not used anymoure
+  Flags parameters;
+
+
+  int silentflag = 0;
+  int testmode = 0;
+
+  MeshingParameters mparam;
+  volatile multithreadt multithread;
+
+  string ngdir = ".";
+
+  ARRAY<int> tets_in_qualclass;
+
+
+  multithreadt :: multithreadt()
+  {
+    pause =0;
+    testmode = 0;
+    redraw = 0;
+    drawing = 0;
+    terminate = 0;
+    running = 0;
+    percent = 0;
+    task = "";
+  }
+
+  DebugParameters debugparam;
+  bool verbose = 0;
+
+  int timestamp = 0;
+  int GetTimeStamp() 
+  { 
+    return timestamp; 
+  }
+
+  int NextTimeStamp()
+  {
+    timestamp++;
+    return timestamp;
+  }
+}
diff --git a/Netgen/libsrc/meshing/global.hpp b/Netgen/libsrc/meshing/global.hpp
new file mode 100644
index 0000000000..843231d0c5
--- /dev/null
+++ b/Netgen/libsrc/meshing/global.hpp
@@ -0,0 +1,54 @@
+#ifndef FILE_GLOBAL
+#define FILE_GLOBAL
+
+
+/**************************************************************************/
+/* File:   global.hh                                                      */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Okt. 95                                                    */
+/**************************************************************************/
+
+/*
+  global functions and variables
+*/
+
+///
+extern double GetTime ();
+extern void ResetTime ();
+
+///
+extern int testmode;
+
+// extern ostream * testout;
+// extern AutoPtr<ostream> testout;
+
+/// calling parameters
+extern Flags parameters;
+
+extern MeshingParameters mparam;
+
+extern ARRAY<int> tets_in_qualclass;
+
+
+class multithreadt
+{
+public:
+  int pause;
+  int testmode;
+  int redraw;
+  int drawing;
+  int terminate;
+  int running;
+  double percent;
+  char * task;
+  bool demorunning;
+  multithreadt();
+};
+
+extern volatile multithreadt multithread;
+
+extern string ngdir;
+extern DebugParameters debugparam;
+extern bool verbose;  
+
+#endif
diff --git a/Netgen/libsrc/meshing/hprefinement.cpp b/Netgen/libsrc/meshing/hprefinement.cpp
new file mode 100644
index 0000000000..be3bbf20b2
--- /dev/null
+++ b/Netgen/libsrc/meshing/hprefinement.cpp
@@ -0,0 +1,3703 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+namespace netgen
+{
+enum HPREF_ELEMENT_TYPE {
+  HP_NONE=0,
+  HP_TRIG = 10,
+  HP_TRIG_SINGCORNER,
+  HP_TRIG_SINGCORNER12,
+  HP_TRIG_SINGCORNER123,
+  HP_TRIG_SINGEDGE = 20,
+  HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_TRIG_SINGEDGECORNER12,
+  HP_TRIG_SINGEDGECORNER3,
+  HP_TRIG_SINGEDGECORNER13,
+  HP_TRIG_SINGEDGECORNER23,
+  HP_TRIG_SINGEDGECORNER123,
+  HP_TRIG_SINGEDGES = 30,
+  HP_TRIG_SINGEDGES2,
+  HP_TRIG_SINGEDGES3,
+  HP_TRIG_SINGEDGES23,
+  HP_TRIG_3SINGEDGES = 40,
+
+  HP_QUAD = 50,
+  HP_QUAD_SINGCORNER,
+  HP_DUMMY_QUAD_SINGCORNER,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGES,
+
+  HP_TET = 100,
+  HP_TET_0E_1V,
+  HP_TET_0E_2V,
+  HP_TET_0E_3V,
+  HP_TET_0E_4V,
+  HP_TET_1E_0V = 200,
+  HP_TET_1E_1VA,    // V on edge
+  HP_TET_1E_1VB,    // V not on edge
+  HP_TET_1E_2VA,    // both on edge
+  HP_TET_1E_2VB,
+  HP_TET_1E_2VC,
+  HP_TET_1E_2VD,    // non on edge
+  HP_TET_1E_3VA,    // 2 on edge
+  HP_TET_1E_3VB,    // 1 on edge
+  HP_TET_1E_4V,
+
+  // 2 connected edges, additonally marked Vs
+  HP_TET_2EA_0V = 220, 
+  HP_TET_2EA_1VA, 
+  HP_TET_2EA_1VB, 
+  HP_TET_2EA_1VC, 
+  HP_TET_2EA_2VA, 
+  HP_TET_2EA_2VB, 
+  HP_TET_2EA_2VC, 
+  HP_TET_2EA_3V, 
+
+  // 2 opposite edges
+  HP_TET_2EB_0V = 230,
+  HP_TET_2EB_1V,
+  HP_TET_2EB_2VA,
+  HP_TET_2EB_2VB,
+  HP_TET_2EB_2VC,
+  HP_TET_2EB_3V,
+  HP_TET_2EB_4V,
+
+  HP_TET_3EA_0V = 400,  // 3 edges connected
+  HP_TET_3EA_3V,
+
+  HP_TET_3EB_2V = 420,  // 3 edges chain
+  HP_TET_3EC_2V = 430,  // 3 edges chain, alter
+  HP_PRISM = 1000,
+  HP_PRISM_SINGEDGE,
+
+  HP_PYRAMID = 2000,
+  HP_PYRAMID_0E_1V,
+  HP_PYRAMID_EDGES,
+
+  HP_HEX = 3000,
+  HP_HEX_0E_1V,
+  HP_HEX_1E_0V,
+  HP_HEX_3E_0V,
+};
+
+
+struct HPRef_Struct {
+  HPREF_ELEMENT_TYPE geom;
+  int (*splitedges)[3];
+  int (*splitfaces)[4];
+  int (*splitelements)[5];
+  HPREF_ELEMENT_TYPE * neweltypes;
+  int (*newels)[8];
+};
+
+
+
+// HP_TRIG
+int reftrig_splitedges[][3] =
+{
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE reftrig_newelstypes[] =
+{
+  HP_TRIG,
+  HP_NONE,
+};
+int reftrig_newels[][8] =
+{
+  { 1, 2, 3 },
+};
+HPRef_Struct reftrig =
+{
+  HP_TRIG, 
+  reftrig_splitedges, 
+  0, 0, 
+  reftrig_newelstypes, 
+  reftrig_newels
+};
+
+
+
+
+// HP_TRIG_SINGCORNER
+int reftrig_singcorner_splitedges[][3] =
+{
+  { 1, 2, 4 },
+  { 1, 3, 5 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE reftrig_singcorner_newelstypes[] =
+{
+  HP_TRIG_SINGCORNER,
+  HP_QUAD,
+  HP_NONE,
+};
+int reftrig_singcorner_newels[][8] =
+{
+  { 1, 4, 5 },
+  { 2, 3, 5, 4 },
+};
+HPRef_Struct reftrig_singcorner =
+{
+  HP_TRIG,
+  reftrig_singcorner_splitedges, 
+  0, 0,
+  reftrig_singcorner_newelstypes, 
+  reftrig_singcorner_newels
+};
+
+
+/*
+// HP_TRIG_SINGCORNER, trigs only
+int reftrig_singcorner_splitedges[][3] =
+{
+  { 1, 2, 4 },
+  { 1, 3, 5 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE reftrig_singcorner_newelstypes[] =
+{
+  HP_TRIG_SINGCORNER,
+  HP_TRIG,
+  HP_TRIG,
+  HP_NONE,
+};
+int reftrig_singcorner_newels[][8] =
+{
+  { 1, 4, 5 },
+  { 4, 2, 5 },
+  { 5, 2, 3 },
+};
+HPRef_Struct reftrig_singcorner =
+{
+  HP_TRIG,
+  reftrig_singcorner_splitedges, 
+  0, 0,
+  reftrig_singcorner_newelstypes, 
+  reftrig_singcorner_newels
+};
+*/
+
+
+
+
+
+// HP_TRIG_SINGCORNER12
+int reftrig_singcorner12_splitedges[][3] =
+{
+  { 1, 2, 4 },
+  { 1, 3, 5 },
+  { 2, 1, 6 },
+  { 2, 3, 7 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE reftrig_singcorner12_newelstypes[] =
+{
+  HP_TRIG_SINGCORNER,
+  HP_TRIG_SINGCORNER,
+  HP_QUAD,
+  HP_TRIG,
+  HP_NONE,
+};
+int reftrig_singcorner12_newels[][8] =
+{
+  { 1, 4, 5 },
+  { 2, 7, 6 },
+  { 4, 6, 7, 5 },
+  { 5, 7, 3 },
+};
+HPRef_Struct reftrig_singcorner12 =
+{
+  HP_TRIG,
+  reftrig_singcorner12_splitedges, 
+  0, 0,
+  reftrig_singcorner12_newelstypes, 
+  reftrig_singcorner12_newels
+};
+
+
+
+
+// HP_TRIG_SINGCORNER123
+int reftrig_singcorner123_splitedges[][3] =
+{
+  { 1, 2, 4 },
+  { 1, 3, 5 },
+  { 2, 1, 6 },
+  { 2, 3, 7 },
+  { 3, 1, 8 },
+  { 3, 2, 9 },
+  { 0, 0, 0 }
+};
+int reftrig_singcorner123_splitfaces[][4] =
+{
+  { 1, 2, 3, 10 },
+  { 2, 3, 1, 11 },
+  { 3, 1, 2, 12 },
+  { 0, 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE reftrig_singcorner123_newelstypes[] =
+{
+  HP_DUMMY_QUAD_SINGCORNER,
+  HP_DUMMY_QUAD_SINGCORNER,
+  HP_DUMMY_QUAD_SINGCORNER,
+  //  HP_TRIG_SINGCORNER,
+  //  HP_TRIG,
+  //  HP_TRIG_SINGCORNER,
+  //  HP_TRIG,
+  //  HP_TRIG_SINGCORNER,
+  //  HP_TRIG,
+  HP_QUAD,
+  HP_QUAD,
+  HP_QUAD,
+  HP_TRIG,
+  HP_NONE,
+};
+int reftrig_singcorner123_newels[][8] =
+{
+  { 1, 4, 10, 5 },
+  { 2, 7, 11, 6 },
+  { 3, 8, 12, 9 },
+  //  { 1, 4, 5 },
+  //  { 5, 4, 10 },
+  //  { 2, 7, 6 },
+  //  { 6, 7, 11 },
+  //  { 3, 8, 9 },
+  //  { 8, 12, 9 },
+  { 4, 6, 11, 10 },
+  { 7, 9, 12, 11 },
+  { 8, 5, 10, 12 },
+  { 10, 11, 12 },
+};
+HPRef_Struct reftrig_singcorner123 =
+{
+  HP_TRIG,
+  reftrig_singcorner123_splitedges, 
+  reftrig_singcorner123_splitfaces, 
+  0, 
+  reftrig_singcorner123_newelstypes, 
+  reftrig_singcorner123_newels
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+// HP_TRIG_SINGEDGE
+int reftrig_singedge_splitedges[][3] =
+{
+  { 2, 3, 4 },
+  { 1, 3, 5 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE reftrig_singedge_newelstypes[] =
+{
+  HP_TRIG,
+  HP_QUAD_SINGEDGE,
+  HP_NONE,
+};
+int reftrig_singedge_newels[][8] =
+{
+  { 4, 3, 5 },
+  { 1, 2, 4, 5 },
+};
+HPRef_Struct reftrig_singedge =
+{
+  HP_TRIG,
+  reftrig_singedge_splitedges, 
+  0, 0,
+  reftrig_singedge_newelstypes, 
+  reftrig_singedge_newels
+};
+
+
+
+
+
+
+// HP_TRIG_SINGEDGECORNER1
+int reftrig_singedgecorner1_splitedges[][3] =
+{
+  { 1, 2, 6 },
+  { 1, 3, 5 },
+  { 2, 3, 4 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE reftrig_singedgecorner1_newelstypes[] =
+{
+  HP_TRIG_SINGEDGECORNER1,
+  HP_QUAD_SINGEDGE,
+  HP_TRIG,
+  HP_NONE,
+};
+int reftrig_singedgecorner1_newels[][8] =
+{
+  { 1, 6, 5 },
+  { 6, 2, 4, 5 },
+  { 5, 4, 3 },
+};
+HPRef_Struct reftrig_singedgecorner1 =
+{
+  HP_TRIG,
+  reftrig_singedgecorner1_splitedges, 
+  0, 0, 
+  reftrig_singedgecorner1_newelstypes, 
+  reftrig_singedgecorner1_newels
+};
+
+
+
+
+
+
+
+
+// HP_TRIG_SINGEDGECORNER2
+int reftrig_singedgecorner2_splitedges[][3] =
+{
+  { 2, 1, 6 },
+  { 1, 3, 5 },
+  { 2, 3, 4 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE reftrig_singedgecorner2_newelstypes[] =
+{
+  HP_TRIG_SINGEDGECORNER2,
+  HP_QUAD_SINGEDGE,
+  HP_TRIG,
+  HP_NONE,
+};
+int reftrig_singedgecorner2_newels[][8] =
+{
+  { 6, 2, 4},
+  { 1, 6, 4, 5 },
+  { 5, 4, 3 },
+};
+HPRef_Struct reftrig_singedgecorner2 =
+{
+  HP_TRIG,
+  reftrig_singedgecorner2_splitedges, 
+  0, 0,
+  reftrig_singedgecorner2_newelstypes, 
+  reftrig_singedgecorner2_newels
+};
+
+
+
+
+// HP_TRIG_SINGEDGECORNER12
+int reftrig_singedgecorner12_splitedges[][3] =
+{
+  { 1, 2, 4 },
+  { 1, 3, 5 },
+  { 2, 1, 6 },
+  { 2, 3, 7 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE reftrig_singedgecorner12_newelstypes[] =
+{
+  HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_QUAD_SINGEDGE,
+  HP_TRIG,
+  HP_NONE,
+};
+int reftrig_singedgecorner12_newels[][8] =
+{
+  { 1, 4, 5 },
+  { 6, 2, 7 },
+  { 4, 6, 7, 5 },
+  { 5, 7, 3 },
+};
+HPRef_Struct reftrig_singedgecorner12 =
+{
+  HP_TRIG,
+  reftrig_singedgecorner12_splitedges, 
+  0, 0,
+  reftrig_singedgecorner12_newelstypes, 
+  reftrig_singedgecorner12_newels
+};
+
+
+
+
+
+
+
+// HP_TRIG_SINGEDGECORNER3
+int reftrig_singedgecorner3_splitedges[][3] =
+{
+  { 1, 3, 4 },
+  { 3, 1, 5 },
+  { 2, 3, 6 },
+  { 3, 2, 7 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE reftrig_singedgecorner3_newelstypes[] =
+{
+  HP_QUAD_SINGEDGE,
+  HP_QUAD,
+  HP_TRIG_SINGCORNER,
+  HP_NONE,
+};
+int reftrig_singedgecorner3_newels[][8] =
+{
+  { 1, 2, 6, 4 },
+  { 4, 6, 7, 5 },
+  { 3, 5, 7 },
+};
+HPRef_Struct reftrig_singedgecorner3 =
+{
+  HP_TRIG,
+  reftrig_singedgecorner3_splitedges, 
+  0, 0,
+  reftrig_singedgecorner3_newelstypes, 
+  reftrig_singedgecorner3_newels
+};
+
+
+
+
+// HP_TRIG_SINGEDGECORNER13
+int reftrig_singedgecorner13_splitedges[][3] =
+{
+  { 1, 2, 4 },
+  { 1, 3, 5 },
+  { 2, 3, 6 },
+  { 3, 1, 7 },
+  { 3, 2, 8 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE reftrig_singedgecorner13_newelstypes[] =
+{
+  HP_TRIG_SINGEDGECORNER1,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD,
+  HP_TRIG_SINGCORNER,
+  HP_NONE,
+};
+int reftrig_singedgecorner13_newels[][8] =
+{
+  { 1, 4, 5 },
+  { 4, 2, 6, 5 },
+  { 5, 6, 8, 7 },
+  { 3, 7, 8 },
+};
+HPRef_Struct reftrig_singedgecorner13 =
+{
+  HP_TRIG,
+  reftrig_singedgecorner13_splitedges, 
+  0, 0,
+  reftrig_singedgecorner13_newelstypes, 
+  reftrig_singedgecorner13_newels
+};
+
+
+
+
+
+// HP_TRIG_SINGEDGECORNER23
+int reftrig_singedgecorner23_splitedges[][3] =
+{
+  { 1, 3, 4 },
+  { 2, 1, 5 },
+  { 2, 3, 6 },
+  { 3, 1, 7 },
+  { 3, 2, 8 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE reftrig_singedgecorner23_newelstypes[] =
+{
+  HP_TRIG_SINGEDGECORNER2,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD,
+  HP_TRIG_SINGCORNER,
+  HP_NONE,
+};
+int reftrig_singedgecorner23_newels[][8] =
+{
+  { 5, 2, 6 },
+  { 1, 5, 6, 4 },
+  { 4, 6, 8, 7 },
+  { 3, 7, 8 },
+};
+HPRef_Struct reftrig_singedgecorner23 =
+{
+  HP_TRIG,
+  reftrig_singedgecorner23_splitedges, 
+  0, 0,
+  reftrig_singedgecorner23_newelstypes, 
+  reftrig_singedgecorner23_newels
+};
+
+
+
+// HP_TRIG_SINGEDGECORNER123
+int reftrig_singedgecorner123_splitedges[][3] =
+{
+  { 1, 2, 4 },
+  { 1, 3, 5 },
+  { 2, 1, 6 },
+  { 2, 3, 7 },
+  { 3, 1, 8 },
+  { 3, 2, 9 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE reftrig_singedgecorner123_newelstypes[] =
+{
+  HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD,
+  HP_TRIG_SINGCORNER,
+  HP_NONE,
+};
+int reftrig_singedgecorner123_newels[][8] =
+{
+  { 1, 4, 5 },
+  { 6, 2, 7 },
+  { 4, 6, 7, 5 },
+  { 5, 7, 9, 8 },
+  { 3, 8, 9 },
+};
+HPRef_Struct reftrig_singedgecorner123 =
+{
+  HP_TRIG,
+  reftrig_singedgecorner123_splitedges, 
+  0, 0,
+  reftrig_singedgecorner123_newelstypes, 
+  reftrig_singedgecorner123_newels
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+// HP_TRIG_SINGEDGES
+int reftrig_singedges_splitedges[][3] =
+{
+  { 1, 2, 4 },
+  { 1, 3, 5 },
+  { 2, 3, 6 },
+  { 3, 2, 7 },
+  { 0, 0, 0 }
+};
+int reftrig_singedges_splitfaces[][4] =
+{
+  { 1, 2, 3, 8 },
+  { 0, 0, 0, 0 }
+};
+
+HPREF_ELEMENT_TYPE reftrig_singedges_newelstypes[] =
+{
+  //  HP_QUAD_SINGEDGES,
+  HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_TRIG,
+  HP_NONE,
+};
+int reftrig_singedges_newels[][8] =
+{
+  // { 1, 4, 8, 5 },
+  { 1, 4, 8 },
+  { 5, 1, 8 },
+  { 4, 2, 6, 8 },
+  { 3, 5, 8, 7 },
+  { 6, 7, 8 },
+};
+HPRef_Struct reftrig_singedges =
+{
+  HP_TRIG,
+  reftrig_singedges_splitedges, 
+  reftrig_singedges_splitfaces, 
+  0,
+  reftrig_singedges_newelstypes, 
+  reftrig_singedges_newels
+};
+
+
+
+
+
+
+
+
+// HP_TRIG_SINGEDGES2
+int reftrig_singedges2_splitedges[][3] =
+{
+  { 1, 2, 4 },
+  { 1, 3, 5 },
+  { 2, 1, 6 },
+  { 2, 3, 7 },
+  { 3, 2, 8 },
+  { 0, 0, 0 }
+};
+int reftrig_singedges2_splitfaces[][4] =
+{
+  { 1, 2, 3, 9 },
+  { 0, 0, 0, 0 }
+};
+
+HPREF_ELEMENT_TYPE reftrig_singedges2_newelstypes[] =
+{
+  //  HP_QUAD_SINGEDGES,
+  HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_TRIG,
+  HP_NONE,
+};
+int reftrig_singedges2_newels[][8] =
+{
+  //  { 1, 4, 9, 5 },
+  { 1, 4, 9 },
+  { 5, 1, 9 },
+  { 4, 6, 7, 9 },
+  { 3, 5, 9, 8 },
+  { 6, 2, 7 },
+  { 7, 8, 9 },
+};
+HPRef_Struct reftrig_singedges2 =
+{
+  HP_TRIG,
+  reftrig_singedges2_splitedges, 
+  reftrig_singedges2_splitfaces, 
+  0,
+  reftrig_singedges2_newelstypes, 
+  reftrig_singedges2_newels
+};
+
+
+
+
+// HP_TRIG_SINGEDGES3
+int reftrig_singedges3_splitedges[][3] =
+{
+  { 1, 2, 4 },
+  { 1, 3, 5 },
+  { 2, 3, 6 },
+  { 3, 1, 7 },
+  { 3, 2, 8 },
+  { 0, 0, 0 }
+};
+int reftrig_singedges3_splitfaces[][4] =
+{
+  { 1, 2, 3, 9 },
+  { 0, 0, 0, 0 }
+};
+
+HPREF_ELEMENT_TYPE reftrig_singedges3_newelstypes[] =
+{
+  //  HP_QUAD_SINGEDGES,
+  HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG,
+  HP_NONE,
+};
+int reftrig_singedges3_newels[][8] =
+{
+  //  { 1, 4, 9, 5 },
+  { 1, 4, 9 },
+  { 5, 1, 9 },
+  { 4, 2, 6, 9 },
+  { 7, 5, 9, 8 },
+  { 3, 7, 8 },
+  { 6, 8, 9 },
+};
+HPRef_Struct reftrig_singedges3 =
+{
+  HP_TRIG,
+  reftrig_singedges3_splitedges, 
+  reftrig_singedges3_splitfaces, 
+  0,
+  reftrig_singedges3_newelstypes, 
+  reftrig_singedges3_newels
+};
+
+
+
+
+
+
+// HP_TRIG_SINGEDGES23
+int reftrig_singedges23_splitedges[][3] =
+{
+  { 1, 2, 4 },
+  { 1, 3, 5 },
+  { 2, 1, 6 },
+  { 2, 3, 7 },
+  { 3, 1, 8 },
+  { 3, 2, 9 },
+  { 0, 0, 0 }
+};
+int reftrig_singedges23_splitfaces[][4] =
+{
+  { 1, 2, 3, 10 },
+  { 0, 0, 0, 0 }
+};
+
+HPREF_ELEMENT_TYPE reftrig_singedges23_newelstypes[] =
+{
+  //  HP_QUAD_SINGEDGES,
+  HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG_SINGEDGECORNER2,
+
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG,
+  HP_NONE,
+};
+int reftrig_singedges23_newels[][8] =
+{
+  //  { 1, 4, 10, 5 },
+  { 1 , 4, 10 },
+  { 5, 1, 10 },
+  { 4, 6, 7, 10 },
+  { 8, 5, 10, 9 },
+  { 6, 2, 7 },
+  { 3, 8, 9 },
+  { 7, 9, 10 },
+};
+HPRef_Struct reftrig_singedges23 =
+{
+  HP_TRIG,
+  reftrig_singedges23_splitedges, 
+  reftrig_singedges23_splitfaces, 
+  0,
+  reftrig_singedges23_newelstypes, 
+  reftrig_singedges23_newels
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+// HP_QUAD
+int refquad_splitedges[][3] =
+{
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refquad_newelstypes[] =
+{
+  HP_QUAD,
+  HP_NONE,
+};
+int refquad_newels[][8] =
+{
+  { 1, 2, 3, 4 },
+};
+HPRef_Struct refquad =
+{
+  HP_QUAD,
+  refquad_splitedges, 
+  0, 0,
+  refquad_newelstypes, 
+  refquad_newels
+};
+
+
+
+
+
+
+
+// HP_QUAD_SINGCORNER
+int refquad_singcorner_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 4, 6 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refquad_singcorner_newelstypes[] =
+{
+  HP_TRIG_SINGCORNER,
+  HP_QUAD,
+  HP_TRIG,
+  HP_NONE,
+};
+int refquad_singcorner_newels[][8] =
+{
+  { 1, 5, 6 },
+  { 2, 4, 6, 5 },
+  { 2, 3, 4 },
+};
+HPRef_Struct refquad_singcorner =
+{
+  HP_QUAD,
+  refquad_singcorner_splitedges, 
+  0, 0,
+  refquad_singcorner_newelstypes, 
+  refquad_singcorner_newels
+};
+
+
+
+
+
+// HP_DUMMY_QUAD_SINGCORNER
+int refdummyquad_singcorner_splitedges[][3] =
+{
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refdummyquad_singcorner_newelstypes[] =
+{
+  HP_TRIG_SINGCORNER,
+  HP_TRIG,
+  HP_NONE,
+};
+int refdummyquad_singcorner_newels[][8] =
+{
+  { 1, 2, 4 },
+  { 4, 2, 3 },
+};
+HPRef_Struct refdummyquad_singcorner =
+{
+  HP_QUAD,
+  refdummyquad_singcorner_splitedges, 
+  0, 0,
+  refdummyquad_singcorner_newelstypes, 
+  refdummyquad_singcorner_newels
+};
+
+
+
+
+
+
+
+// HP_QUAD_SINGEDGE
+int refquad_singedge_splitedges[][3] =
+{
+  { 1, 4, 5 },
+  { 2, 3, 6 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refquad_singedge_newelstypes[] =
+{
+  HP_QUAD_SINGEDGE,
+  HP_QUAD,
+  HP_NONE,
+};
+int refquad_singedge_newels[][8] =
+{
+  { 1, 2, 6, 5 },
+  { 5, 6, 3, 4 },
+};
+HPRef_Struct refquad_singedge =
+{
+  HP_QUAD,
+  refquad_singedge_splitedges, 
+  0, 0,
+  refquad_singedge_newelstypes, 
+  refquad_singedge_newels
+};
+
+
+
+
+
+// HP_QUAD_SINGEDGES
+int refquad_singedges_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 4, 6 },
+  { 2, 3, 7 },
+  { 4, 3, 8 },
+  { 0, 0, 0 }
+};
+int refquad_singedges_splitfaces[][4] =
+{
+  { 1, 2, 4, 9 },
+  { 0, 0, 0, 0 },
+};
+HPREF_ELEMENT_TYPE refquad_singedges_newelstypes[] =
+{
+  HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD,
+  HP_NONE,
+};
+int refquad_singedges_newels[][8] =
+{
+  { 1, 5, 9 },
+  { 6, 1, 9 },
+  { 5, 2, 7, 9 },
+  { 4, 6, 9, 8 },
+  { 9, 7, 3, 8 },
+};
+HPRef_Struct refquad_singedges =
+{
+  HP_QUAD,
+  refquad_singedges_splitedges, 
+  refquad_singedges_splitfaces, 
+  0,
+  refquad_singedges_newelstypes, 
+  refquad_singedges_newels
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+// HP_TET
+int reftet_splitedges[][3] =
+{
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE reftet_newelstypes[] =
+{
+  HP_TET,
+  HP_NONE,
+};
+int reftet_newels[][8] =
+{
+  { 1, 2, 3, 4 },
+};
+HPRef_Struct reftet =
+{
+  HP_TET,
+  reftet_splitedges, 
+  0, 0,
+  reftet_newelstypes, 
+  reftet_newels
+};
+
+
+
+/* *********** Tet - Refinement - 0 edges *************** */
+
+// HP_TET_0E_1V
+int reftet_0e_1v_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 3, 6 },
+  { 1, 4, 7 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE reftet_0e_1v_newelstypes[] =
+{
+  HP_TET_0E_1V,
+  HP_PRISM,
+  HP_NONE,
+};
+int reftet_0e_1v_newels[][8] =
+{
+  { 1, 5, 6, 7 },
+  { 5, 6, 7, 2, 3, 4 }
+};
+HPRef_Struct reftet_0e_1v =
+{
+  HP_TET,
+  reftet_0e_1v_splitedges, 
+  0, 0,
+  reftet_0e_1v_newelstypes, 
+  reftet_0e_1v_newels
+};
+
+
+
+// HP_TET_0E_2V
+int reftet_0e_2v_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 3, 6 },
+  { 1, 4, 7 },
+  { 2, 1, 8 },
+  { 2, 3, 9 },
+  { 2, 4, 10 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE reftet_0e_2v_newelstypes[] =
+{
+  HP_TET_0E_1V,
+  HP_TET_0E_1V,
+  HP_PRISM,
+  HP_PRISM,
+  HP_NONE,
+};
+int reftet_0e_2v_newels[][8] =
+{
+  { 1, 5, 6, 7 },
+  { 2, 10, 9, 8 },
+  { 5, 6, 7, 8, 9, 10 },
+  { 4, 10, 7, 3, 9, 6 },
+};
+HPRef_Struct reftet_0e_2v =
+{
+  HP_TET,
+  reftet_0e_2v_splitedges, 
+  0, 0,
+  reftet_0e_2v_newelstypes, 
+  reftet_0e_2v_newels
+};
+
+
+
+
+
+// HP_TET_0E_3V
+int reftet_0e_3v_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 3, 6 },
+  { 1, 4, 7 },
+  { 2, 1, 8 },
+  { 2, 3, 9 },
+  { 2, 4, 10 },
+  { 3, 1, 11 },
+  { 3, 2, 12 },
+  { 3, 4, 13 },
+  { 0, 0, 0 }
+};
+int reftet_0e_3v_splitfaces[][4] =
+  {
+    { 1, 2, 3, 14 },
+    { 2, 3, 1, 15 },
+    { 3, 1, 2, 16 },
+    { 0, 0, 0, 0 },
+  };
+HPREF_ELEMENT_TYPE reftet_0e_3v_newelstypes[] =
+{
+  HP_PYRAMID_0E_1V,
+  HP_PYRAMID_0E_1V,
+  HP_PYRAMID_0E_1V,
+  HP_PRISM,
+  HP_PRISM,
+  HP_PRISM,
+  HP_PRISM,
+  HP_TET,
+  HP_NONE,
+};
+int reftet_0e_3v_newels[][8] =
+{
+  { 1, 5, 14, 6, 7 },
+  { 2, 9, 15, 8, 10 },
+  { 3, 11, 16, 12, 13 },
+  { 5, 14, 7, 8, 15, 10 },
+  { 9, 15, 10, 12, 16, 13 },
+  { 6, 7, 14, 11, 13, 16 },
+  { 14, 15, 16, 7, 10, 13 },
+  { 7, 10, 13, 4 }
+};
+HPRef_Struct reftet_0e_3v =
+{
+  HP_TET,
+  reftet_0e_3v_splitedges, 
+  reftet_0e_3v_splitfaces, 
+  0,
+  reftet_0e_3v_newelstypes, 
+  reftet_0e_3v_newels
+};
+
+
+
+
+
+// HP_TET_0E_4V
+int reftet_0e_4v_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 3, 6 },
+  { 1, 4, 7 },
+  { 2, 1, 8 },
+  { 2, 3, 9 },
+  { 2, 4, 10 },
+  { 3, 1, 11 },
+  { 3, 2, 12 },
+  { 3, 4, 13 },
+  { 4, 1, 14 },
+  { 4, 2, 15 },
+  { 4, 3, 16 },
+  { 0, 0, 0 }
+};
+int reftet_0e_4v_splitfaces[][4] =
+  {
+    { 1, 2, 3, 17 },
+    { 1, 2, 4, 18 },
+    { 1, 3, 4, 19 },
+
+    { 2, 1, 3, 20 },
+    { 2, 1, 4, 21 },
+    { 2, 3, 4, 22 },
+
+    { 3, 1, 2, 23 },
+    { 3, 1, 4, 24 },
+    { 3, 2, 4, 25 },
+
+    { 4, 1, 2, 26 },
+    { 4, 1, 3, 27 },
+    { 4, 2, 3, 28 },
+    { 0, 0, 0, 0 },
+  };
+int reftet_0e_4v_splitelements[][5] =
+  {
+    { 1, 2, 3, 4, 29 },
+    { 2, 3, 4, 1, 30 },
+    { 3, 4, 1, 2, 31 },
+    { 4, 1, 2, 3, 32 },
+    { 0 },
+  };
+HPREF_ELEMENT_TYPE reftet_0e_4v_newelstypes[] =
+{
+  HP_HEX_0E_1V,
+  HP_HEX_0E_1V,
+  HP_HEX_0E_1V,
+  HP_HEX_0E_1V,
+  HP_PRISM, HP_PRISM, 
+  HP_PRISM, HP_PRISM, 
+  HP_PRISM, HP_PRISM, 
+  HP_PRISM, HP_PRISM, 
+  HP_PRISM, HP_PRISM, 
+  HP_PRISM, HP_PRISM, 
+  /*
+  HP_HEX, 
+  HP_HEX, 
+  HP_HEX, 
+  HP_HEX, 
+  HP_HEX, 
+  HP_HEX, 
+  */
+  HP_PRISM,
+  HP_PRISM,
+  HP_PRISM,
+  HP_PRISM,
+  HP_TET,
+  HP_NONE,
+};
+int reftet_0e_4v_newels[][8] =
+{
+  { 1, 5, 17, 6, 7, 18, 29, 19 },
+  { 2, 9, 20, 8, 10, 22, 30, 21 },
+  { 3, 11, 23, 12, 13, 24, 31, 25 },
+  { 4, 15, 26, 14, 16, 28, 32, 27 },
+  { 5, 17, 18, 8, 20, 21 },
+  { 18, 17, 29, 21, 20, 30 },
+  { 6, 19, 17,  11, 24, 23 },
+  { 17, 19, 29,  23, 24, 31 },
+  { 7, 18, 19, 14, 26, 27 },
+  { 19, 18, 29, 27, 26, 32 },
+  { 9, 20, 22, 12, 23, 25 },
+  { 22, 20, 30, 25, 23, 31 },
+  { 10, 22, 21, 15, 28, 26 },
+  { 21, 22, 30, 26, 28, 32 },
+  { 13, 24, 25, 16, 27, 28 },
+  { 25, 24, 31, 28, 27, 32 },
+  /*
+  { 5, 17, 29, 18, 8, 20, 30, 21 },
+  { 6, 19, 29, 17, 11, 24, 31, 23 },
+  { 7, 18, 29, 19, 14, 26, 32, 27 },
+  { 9, 20, 30, 22, 12, 23, 31, 25 },
+  { 10, 22, 30, 21, 15, 28, 32, 26 },
+  { 13, 24, 31, 25, 16, 27, 32, 28 },
+  */
+  { 17, 20, 23, 29, 30, 31 },
+  { 18, 26, 21, 29, 32, 30 },
+  { 19, 24, 27, 29, 31, 32 },
+  { 22, 28, 25, 30, 32, 31 },
+
+  { 29, 30, 31, 32 },
+};
+HPRef_Struct reftet_0e_4v =
+{
+  HP_TET,
+  reftet_0e_4v_splitedges, 
+  reftet_0e_4v_splitfaces, 
+  reftet_0e_4v_splitelements, 
+  reftet_0e_4v_newelstypes, 
+  reftet_0e_4v_newels
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/* *********** Tet - Refinement - 1 edge *************** */
+
+
+
+// HP_TET_1E_0V
+int reftet_1e_0v_splitedges[][3] =
+{
+  { 1, 3, 5 },
+  { 1, 4, 6 },
+  { 2, 3, 7 },
+  { 2, 4, 8 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE reftet_1e_0v_newelstypes[] =
+{
+  HP_PRISM_SINGEDGE,
+  HP_PRISM,
+  HP_NONE,
+};
+int reftet_1e_0v_newels[][8] =
+{
+  { 1, 5, 6, 2, 7, 8 },
+  { 7, 3, 5, 8, 4, 6 }
+};
+HPRef_Struct reftet_1e_0v =
+{
+  HP_TET,
+  reftet_1e_0v_splitedges, 
+  0, 0,
+  reftet_1e_0v_newelstypes, 
+  reftet_1e_0v_newels
+};
+
+
+
+
+
+// HP_TET_1E_1VA
+int reftet_1e_1va_splitedges[][3] =
+{
+  { 1, 3, 5 },
+  { 1, 4, 6 },
+  { 2, 3, 7 },
+  { 2, 4, 8 },
+  { 1, 2, 9 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE reftet_1e_1va_newelstypes[] =
+{
+  HP_TET_1E_1VA,
+  HP_PRISM_SINGEDGE,
+  HP_PRISM,
+  HP_NONE,
+};
+int reftet_1e_1va_newels[][8] =
+{
+  { 1, 9, 5, 6 },
+  { 9, 5, 6, 2, 7, 8 },
+  { 7, 3, 5, 8, 4, 6 }
+};
+HPRef_Struct reftet_1e_1va =
+{
+  HP_TET,
+  reftet_1e_1va_splitedges, 
+  0, 0,
+  reftet_1e_1va_newelstypes, 
+  reftet_1e_1va_newels
+};
+
+
+
+
+
+
+// HP_TET_1E_1VB
+int reftet_1e_1vb_splitedges[][3] =
+{
+  { 1, 3, 5 },
+  { 1, 4, 6 },
+  { 2, 3, 7 },
+  { 2, 4, 8 },
+  { 4, 1, 9 },
+  { 4, 2, 10 },
+  { 4, 3, 11 },
+  { 0, 0, 0 }
+};
+int reftet_1e_1vb_splitelements[][5] =
+{
+  { 4, 1, 2, 3, 12 },
+  { 0 }
+};
+
+HPREF_ELEMENT_TYPE reftet_1e_1vb_newelstypes[] =
+{
+  HP_PRISM_SINGEDGE,
+  HP_TET_0E_1V,
+  HP_PYRAMID,
+  HP_TET,
+  HP_PYRAMID, 
+  HP_TET,
+  HP_PYRAMID,
+  HP_TET,
+  HP_PYRAMID,
+  HP_TET,
+  HP_NONE,
+};
+int reftet_1e_1vb_newels[][8] =
+{
+  { 1, 5, 6, 2, 7, 8 },
+  { 4, 11, 10, 9 },
+  { 7, 8, 10, 11, 12 },
+  { 3, 7, 11, 12 },
+  { 5, 11, 9, 6, 12 },
+  { 5, 3, 11, 12 },
+  { 6, 9, 10, 8, 12 },
+  { 5, 7, 3, 12 },
+  { 5, 6, 8, 7, 12 },
+  { 9, 11, 10, 12 }
+};
+HPRef_Struct reftet_1e_1vb =
+{
+  HP_TET,
+  reftet_1e_1vb_splitedges, 
+  0,
+  reftet_1e_1vb_splitelements, 
+  reftet_1e_1vb_newelstypes, 
+  reftet_1e_1vb_newels
+};
+
+
+
+
+
+
+
+
+// HP_TET_1E_2VA
+int reftet_1e_2va_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 3, 6 },
+  { 1, 4, 7 },
+  { 2, 1, 8 },
+  { 2, 3, 9 },
+  { 2, 4, 10 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE reftet_1e_2va_newelstypes[] =
+{
+  HP_TET_1E_1VA,
+  HP_TET_1E_1VA,
+  HP_PRISM_SINGEDGE,
+  HP_PRISM,
+  HP_NONE,
+};
+int reftet_1e_2va_newels[][8] =
+{
+  { 1, 5, 6, 7 },
+  { 2, 8, 10, 9 },
+  { 5, 6, 7, 8, 9, 10 },
+  { 4, 10, 7, 3, 9, 6 },
+};
+HPRef_Struct reftet_1e_2va =
+{
+  HP_TET,
+  reftet_1e_2va_splitedges, 
+  0, 0,
+  reftet_1e_2va_newelstypes, 
+  reftet_1e_2va_newels
+};
+
+
+
+
+
+
+
+// HP_TET_1E_2VB
+int reftet_1e_2vb_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 3, 6 },
+  { 1, 4, 7 },
+  { 2, 3, 8 },
+  { 2, 4, 9 },
+  { 3, 1, 10 },
+  { 3, 2, 11 },
+  { 3, 4, 12 },
+  { 0, 0, 0 }
+};
+int reftet_1e_2vb_splitelements[][5] =
+{
+  { 3, 4, 1, 2, 13 },
+  { 0 }
+};
+
+HPREF_ELEMENT_TYPE reftet_1e_2vb_newelstypes[] =
+{
+  HP_TET_1E_1VA,
+  HP_PRISM_SINGEDGE,
+  HP_TET_0E_1V,
+  HP_PYRAMID,
+  HP_TET,
+  HP_PYRAMID, 
+  HP_TET,
+  HP_PYRAMID,
+  HP_TET,
+  HP_PYRAMID,
+  HP_TET,
+  HP_NONE,
+};
+int reftet_1e_2vb_newels[][8] =
+{
+  { 1, 5, 6, 7 },
+  { 5, 6, 7, 2, 8, 9 },
+  { 3, 10, 11, 12 },
+
+  { 8, 9, 12, 11, 13 },
+  { 4, 12, 9, 13 },
+  { 6, 10, 12, 7, 13 },
+  { 4, 7, 12, 13 },
+  { 6, 8, 11, 10, 13 },
+  { 4, 9, 7, 13 },
+  { 6, 7, 9, 8, 13 },
+  { 10, 11, 12, 13 },
+};
+HPRef_Struct reftet_1e_2vb =
+{
+  HP_TET,
+  reftet_1e_2vb_splitedges, 
+  0,
+  reftet_1e_2vb_splitelements, 
+  reftet_1e_2vb_newelstypes, 
+  reftet_1e_2vb_newels
+};
+
+
+
+
+
+
+// HP_TET_1E_2VC
+int reftet_1e_2vc_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 3, 6 },
+  { 1, 4, 7 },
+  { 2, 3, 8 },
+  { 2, 4, 9 },
+  { 4, 1, 10 },
+  { 4, 2, 11 },
+  { 4, 3, 12 },
+  { 0, 0, 0 }
+};
+int reftet_1e_2vc_splitelements[][5] =
+{
+  { 4, 1, 2, 3, 13 },
+  { 0 }
+};
+
+HPREF_ELEMENT_TYPE reftet_1e_2vc_newelstypes[] =
+{
+  HP_TET_1E_1VA,
+  HP_PRISM_SINGEDGE,
+  HP_TET_0E_1V,
+  HP_PYRAMID,
+  HP_TET,
+  HP_PYRAMID, 
+  HP_TET,
+  HP_PYRAMID,
+  HP_TET,
+  HP_PYRAMID,
+  HP_TET,
+  HP_NONE,
+};
+int reftet_1e_2vc_newels[][8] =
+{
+  { 1, 5, 6, 7 },
+  { 5, 6, 7, 2, 8, 9 },
+  { 4, 11, 10, 12 },
+  { 8, 9, 11, 12, 13 },
+  { 3, 8, 12, 13 },
+  { 7, 6, 12, 10, 13 },
+  { 3, 12, 6, 13 },
+  { 9, 7, 10, 11, 13 },
+  { 3, 6, 8, 13 },
+  { 6, 7, 9, 8, 13 },
+  { 10, 12, 11, 13 }
+};
+HPRef_Struct reftet_1e_2vc =
+{
+  HP_TET,
+  reftet_1e_2vc_splitedges, 
+  0,
+  reftet_1e_2vc_splitelements, 
+  reftet_1e_2vc_newelstypes, 
+  reftet_1e_2vc_newels
+};
+
+
+
+
+
+
+
+
+
+
+// HP_TET_1E_2VD
+int reftet_1e_2vd_splitedges[][3] =
+{
+  { 1, 3, 5 },
+  { 1, 4, 6 },
+  { 2, 3, 7 },
+  { 2, 4, 8 },
+  { 3, 1, 9 },
+  { 3, 2, 10 },
+  { 3, 4, 11 },
+  { 4, 1, 12 },
+  { 4, 2, 13 },
+  { 4, 3, 14 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE reftet_1e_2vd_newelstypes[] =
+{
+  HP_PRISM_SINGEDGE,
+  HP_TET_0E_1V,
+  HP_TET_0E_1V,
+  HP_PRISM,
+  HP_HEX,
+  HP_NONE,
+};
+int reftet_1e_2vd_newels[][8] =
+{
+  { 1, 5, 6, 2, 7, 8 },
+  { 4, 13, 12, 14 },
+  { 3, 10, 11, 9 },
+  { 14, 13, 12, 11, 10, 9 },
+  { 6, 12, 13, 8, 5, 9, 10, 7 },
+};
+HPRef_Struct reftet_1e_2vd =
+{
+  HP_TET,
+  reftet_1e_2vd_splitedges, 
+  0, 0,
+  reftet_1e_2vd_newelstypes, 
+  reftet_1e_2vd_newels
+};
+
+
+
+
+
+
+
+
+
+
+
+
+//  HP_TET_2EA_0V,  // 2 edges connected
+int reftet_2ea_0v_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 3, 6 },
+  { 1, 4, 7 },
+  { 2, 3, 9 },
+  { 2, 4, 10 },
+  { 3, 2, 12 },
+  { 3, 4, 13 },
+  { 0, 0, 0 }
+};
+int reftet_2ea_0v_splitfaces[][4] =
+  {
+    { 1, 2, 3, 17 },
+    { 0, 0, 0, 0 }
+  };
+HPREF_ELEMENT_TYPE reftet_2ea_0v_newelstypes[] =
+  {
+    HP_PYRAMID_EDGES,
+    HP_PRISM_SINGEDGE,
+    HP_PRISM_SINGEDGE,
+    HP_PRISM,
+    HP_TET,
+    HP_NONE,
+  };
+int reftet_2ea_0v_newels[][8] =
+{
+  { 1, 5, 17, 6, 7 },
+  { 5, 17, 7, 2, 9, 10 },
+  { 6, 7, 17, 3, 13, 12 },
+  { 17, 9, 12, 7, 10, 13 },
+  { 7, 10, 13, 4 },
+};
+HPRef_Struct reftet_2ea_0v =
+{
+  HP_TET,
+  reftet_2ea_0v_splitedges, 
+  reftet_2ea_0v_splitfaces, 
+  0,
+  reftet_2ea_0v_newelstypes, 
+  reftet_2ea_0v_newels
+};
+
+
+
+
+
+
+//  HP_TET_2EA_1VB, 
+int reftet_2ea_1vb_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 3, 6 },
+  { 1, 4, 7 },
+  { 2, 3, 9 },
+  { 2, 4, 10 },
+  { 3, 1, 11 },
+  { 3, 2, 12 },
+  { 3, 4, 13 },
+  { 0, 0, 0 }
+};
+int reftet_2ea_1vb_splitfaces[][4] =
+  {
+    { 1, 2, 3, 17 },
+    { 0, 0, 0, 0 }
+  };
+HPREF_ELEMENT_TYPE reftet_2ea_1vb_newelstypes[] =
+  {
+    HP_PYRAMID_EDGES,
+    HP_TET_1E_1VA,
+    HP_PRISM_SINGEDGE,
+    HP_PRISM_SINGEDGE,
+    HP_PRISM,
+    HP_TET,
+    HP_NONE,
+  };
+int reftet_2ea_1vb_newels[][8] =
+{
+  { 1, 5, 17, 6, 7 },
+  { 3, 11, 12, 13 },
+  { 5, 17, 7, 2, 9, 10 },
+  { 6, 7, 17, 11, 13, 12 },
+  { 17, 9, 12, 7, 10, 13 },
+  { 7, 10, 13, 4 },
+};
+HPRef_Struct reftet_2ea_1vb =
+{
+  HP_TET,
+  reftet_2ea_1vb_splitedges, 
+  reftet_2ea_1vb_splitfaces, 
+  0,
+  reftet_2ea_1vb_newelstypes, 
+  reftet_2ea_1vb_newels
+};
+
+
+
+
+
+
+
+
+
+//  HP_TET_2EA_3V,  // 2 edges connected
+int reftet_2ea_3v_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 3, 6 },
+  { 1, 4, 7 },
+  { 2, 1, 8 },
+  { 2, 3, 9 },
+  { 2, 4, 10 },
+  { 3, 1, 11 },
+  { 3, 2, 12 },
+  { 3, 4, 13 },
+  { 4, 1, 14 },
+  { 4, 2, 15 },
+  { 4, 3, 16 },
+  { 0, 0, 0 }
+};
+int reftet_2ea_3v_splitfaces[][4] =
+  {
+    { 1, 2, 3, 17 },
+    { 2, 3, 4, 18 },
+    { 3, 4, 2, 19 },
+    { 4, 2, 3, 20 },
+    { 0, 0, 0, 0 }
+  };
+int reftet_2ea_3v_splitelements[][5] =
+  {
+    { 1, 2, 3, 4, 21 },
+    { 0, 0, 0, 0 }
+  };
+HPREF_ELEMENT_TYPE reftet_2ea_3v_newelstypes[] =
+  {
+    HP_PYRAMID_EDGES,
+    HP_TET_1E_1VA,
+    HP_TET_1E_1VA,
+    HP_TET_0E_1V,
+    HP_PRISM_SINGEDGE,
+    HP_PRISM_SINGEDGE,
+
+    HP_TET, HP_TET, HP_TET, HP_TET, 
+    HP_PYRAMID, HP_PYRAMID, HP_PYRAMID, 
+    HP_PYRAMID, HP_PYRAMID, HP_TET,
+    HP_PYRAMID, HP_PYRAMID, HP_TET,
+    //     HP_PRISM,
+    //    HP_PRISM,
+    HP_NONE,
+  };
+int reftet_2ea_3v_newels[][8] =
+{
+  { 1, 5, 17, 6, 7 },
+  { 2, 8, 10, 9 },
+  { 3, 11, 12, 13 },
+  { 4, 15, 14, 16 }, 
+  { 5, 17, 7, 8, 9, 10 },
+  { 6, 7, 17, 11, 13, 12 },
+ 
+  { 9, 10, 18, 21 },
+  { 13, 12, 19, 21 },
+  { 15, 16, 20, 21 },
+  { 18, 20, 19, 21 },
+  { 10, 15, 20, 18, 21 },
+  { 13, 19, 20, 16, 21 },
+  { 9, 18, 19, 12, 21 },
+  
+  { 7, 13, 16, 14, 21 },
+  { 7, 14, 15, 10, 21 },
+  { 9, 12, 17, 21 },
+  { 7, 10, 9, 17, 21 },
+  { 7, 17, 12, 13, 21 },
+  { 14, 16, 15, 21 },
+  //  { 17, 9, 12, 7, 10, 13 },
+  //  { 7, 10, 13, 14, 15, 16 },
+};
+HPRef_Struct reftet_2ea_3v =
+{
+  HP_TET,
+  reftet_2ea_3v_splitedges, 
+  reftet_2ea_3v_splitfaces, 
+  reftet_2ea_3v_splitelements, 
+  reftet_2ea_3v_newelstypes, 
+  reftet_2ea_3v_newels
+};
+
+
+
+
+
+
+//  HP_TET_2EB_4V,  // 2 opposite edges
+int reftet_2eb_4v_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 3, 6 },
+  { 1, 4, 7 },
+  { 2, 1, 8 },
+  { 2, 3, 9 },
+  { 2, 4, 10 },
+  { 3, 1, 11 },
+  { 3, 2, 12 },
+  { 3, 4, 13 },
+  { 4, 1, 14 },
+  { 4, 2, 15 },
+  { 4, 3, 16 },
+  { 0, 0, 0 }
+};
+
+HPREF_ELEMENT_TYPE reftet_2eb_4v_newelstypes[] =
+  {
+    HP_PRISM_SINGEDGE,
+    HP_PRISM_SINGEDGE,
+    HP_TET_1E_1VA,
+    HP_TET_1E_1VA,
+    HP_TET_1E_1VA,
+    HP_TET_1E_1VA,
+    HP_HEX,
+    HP_NONE,
+  };
+int reftet_2eb_4v_newels[][8] =
+{
+  { 5, 6, 7, 8, 9, 10 },
+  { 16, 15, 14, 13, 12, 11 },
+  { 1, 5, 6, 7 },
+  { 2, 8, 10, 9 },
+  { 3, 13, 11, 12 },
+  { 4, 16, 15, 14 },
+  { 7, 14, 15, 10, 6, 11, 12, 9 }
+};
+HPRef_Struct reftet_2eb_4v =
+{
+  HP_TET,
+  reftet_2eb_4v_splitedges, 
+  0, 0,
+  reftet_2eb_4v_newelstypes, 
+  reftet_2eb_4v_newels
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+//  HP_TET_3EA_0V,  
+int reftet_3ea_0v_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 3, 6 },
+  { 1, 4, 7 },
+  { 2, 3, 8 },
+  { 2, 4, 9 },
+  { 3, 2, 10 },
+  { 3, 4, 11 },
+  { 4, 2, 12 },
+  { 4, 3, 13 },
+  { 0, 0, 0 }
+};
+int reftet_3ea_0v_splitfaces[][4] =
+  {
+    { 1, 2, 3, 14 },
+    { 1, 2, 4, 15 },
+    { 1, 3, 4, 16 },
+    { 2, 3, 4, 17 },
+    { 3, 4, 2, 18 },
+    { 4, 2, 3, 19 },
+    { 0, 0, 0, 0 }
+  };
+int reftet_3ea_0v_splitelements[][5] =
+  {
+    { 1, 2, 3, 4, 20 },
+    { 0 },
+  };
+
+HPREF_ELEMENT_TYPE reftet_3ea_0v_newelstypes[] =
+  {
+    HP_HEX_3E_0V,
+    HP_HEX_1E_0V,
+    HP_HEX_1E_0V,
+    HP_HEX_1E_0V,
+    HP_PRISM,
+    HP_PRISM,
+    HP_PRISM,
+    HP_TET,
+    HP_NONE,
+  };
+int reftet_3ea_0v_newels[][8] =
+{
+  { 1, 5, 14, 6, 7, 15, 20, 16 },
+  { 5, 2, 8, 14, 15, 9, 17, 20 },
+  { 3, 6, 14, 10, 11, 16, 20, 18 },
+  { 7, 4, 12, 15, 16, 13, 19, 20 },
+  { 11, 13, 16, 18, 19, 20 },
+  { 15, 12, 9, 20, 19, 17 },
+  { 8, 10, 14, 17, 18, 20 },
+  { 20, 17, 18, 19 },
+};
+HPRef_Struct reftet_3ea_0v =
+{
+  HP_TET,
+  reftet_3ea_0v_splitedges, 
+  reftet_3ea_0v_splitfaces, 
+  reftet_3ea_0v_splitelements, 
+  reftet_3ea_0v_newelstypes, 
+  reftet_3ea_0v_newels
+};
+
+
+
+
+
+
+
+//  HP_TET_3EA_3V,  
+int reftet_3ea_3v_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 3, 6 },
+  { 1, 4, 7 },
+  { 2, 3, 8 },
+  { 2, 4, 9 },
+  { 3, 2, 10 },
+  { 3, 4, 11 },
+  { 4, 2, 12 },
+  { 4, 3, 13 },
+  { 2, 1, 21 },
+  { 3, 1, 22 },
+  { 4, 1, 23 },
+  { 0, 0, 0 }
+};
+int reftet_3ea_3v_splitfaces[][4] =
+  {
+    { 1, 2, 3, 14 },
+    { 1, 2, 4, 15 },
+    { 1, 3, 4, 16 },
+    { 2, 3, 4, 17 },
+    { 3, 4, 2, 18 },
+    { 4, 2, 3, 19 },
+    { 0, 0, 0, 0 }
+  };
+int reftet_3ea_3v_splitelements[][5] =
+  {
+    { 1, 2, 3, 4, 20 },
+    { 0 },
+  };
+
+HPREF_ELEMENT_TYPE reftet_3ea_3v_newelstypes[] =
+  {
+    HP_HEX_3E_0V,
+    HP_TET_1E_1VA,
+    HP_PRISM_SINGEDGE,
+    HP_PRISM,
+    HP_TET_1E_1VA,
+    HP_PRISM_SINGEDGE,
+    HP_PRISM,
+    HP_TET_1E_1VA,
+    HP_PRISM_SINGEDGE,
+    HP_PRISM,
+
+    HP_PRISM,
+    HP_PRISM,
+    HP_PRISM,
+    HP_TET,
+    HP_NONE,
+  };
+int reftet_3ea_3v_newels[][8] =
+{
+  { 1, 5, 14, 6, 7, 15, 20, 16 },
+
+  { 2, 21, 9, 8 },
+  { 5, 14, 15, 21, 8, 9 },
+  { 15, 14, 20, 9, 8, 17 },
+  { 3, 22, 10, 11 },
+  { 6, 16, 14, 22, 11, 10 },
+  { 14, 16, 20, 10, 11, 18 },
+  { 4, 23, 13, 12 },
+  { 7, 15, 16, 23, 12, 13 },
+  { 16, 15, 20, 13, 12, 19 },
+
+  { 11, 13, 16, 18, 19, 20 },
+  { 15, 12, 9, 20, 19, 17 },
+  { 8, 10, 14, 17, 18, 20 },
+  { 20, 17, 18, 19 },
+};
+HPRef_Struct reftet_3ea_3v =
+{
+  HP_TET,
+  reftet_3ea_3v_splitedges, 
+  reftet_3ea_3v_splitfaces, 
+  reftet_3ea_3v_splitelements, 
+  reftet_3ea_3v_newelstypes, 
+  reftet_3ea_3v_newels
+};
+
+
+
+
+
+
+
+//  HP_TET_3EV_2V,  
+int reftet_3eb_2v_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 3, 6 },
+  { 1, 4, 7 },
+  { 2, 1, 8 },
+  { 2, 3, 9 },
+  { 2, 4, 10 },
+  { 3, 1, 11 },
+  { 3, 2, 12 },
+  { 3, 4, 13 },
+  { 4, 1, 14 },
+  { 4, 2, 15 },
+  { 4, 3, 16 },
+  { 0, 0, 0 }
+};
+int reftet_3eb_2v_splitfaces[][4] =
+  {
+    { 1, 2, 4, 17 },
+    { 2, 1, 3, 18 },
+    { 0, 0, 0, 0 }
+  };
+int reftet_3eb_2v_splitelements[][5] =
+  {
+    { 1, 2, 3, 4, 20 },
+    { 0 },
+  };
+
+HPREF_ELEMENT_TYPE reftet_3eb_2v_newelstypes[] =
+  {
+    HP_PYRAMID_EDGES,
+    HP_PYRAMID_EDGES,
+    HP_TET_1E_1VA,
+    HP_TET_1E_1VA,
+    HP_PRISM_SINGEDGE,
+    HP_PRISM_SINGEDGE,
+    HP_PRISM_SINGEDGE,
+    
+    HP_PYRAMID,
+    HP_PYRAMID,
+    HP_TET,
+    HP_TET,
+    HP_PYRAMID,
+    HP_PYRAMID,
+    HP_PYRAMID,
+    HP_NONE,
+  };
+int reftet_3eb_2v_newels[][8] =
+{
+  { 1, 7, 17, 5, 6 },
+  { 2, 9, 18, 8, 10 },
+  { 3, 12, 13, 11 },
+  { 4, 14, 16, 15 },
+  { 5, 6, 17, 8, 18, 10 },
+  { 7, 17, 6, 14, 15, 16 },
+  { 9, 18, 10, 12, 11, 13 },
+  
+  { 10, 15, 16, 13, 20 },
+  { 6, 11, 13, 16, 20 },
+  { 10, 17, 15, 20 },
+  { 6, 18, 11, 20 },
+  { 6, 17, 10, 18, 20 },
+  { 6, 16, 15, 17, 20 },
+  { 18, 10, 13, 11, 20 },
+};
+HPRef_Struct reftet_3eb_2v =
+{
+  HP_TET,
+  reftet_3eb_2v_splitedges, 
+  reftet_3eb_2v_splitfaces, 
+  reftet_3eb_2v_splitelements, 
+  reftet_3eb_2v_newelstypes, 
+  reftet_3eb_2v_newels
+};
+
+
+
+
+
+
+
+
+
+//  HP_TET_3EC_2V,  
+int reftet_3ec_2v_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 3, 6 },
+  { 1, 4, 7 },
+  { 2, 1, 8 },
+  { 2, 3, 9 },
+  { 2, 4, 10 },
+  { 3, 1, 11 },
+  { 3, 2, 12 },
+  { 3, 4, 13 },
+  { 4, 1, 14 },
+  { 4, 2, 15 },
+  { 4, 3, 16 },
+  { 0, 0, 0 }
+};
+int reftet_3ec_2v_splitfaces[][4] =
+  {
+    { 1, 2, 3, 17 },
+    { 2, 1, 4, 18 },
+    { 0, 0, 0, 0 }
+  };
+int reftet_3ec_2v_splitelements[][5] =
+  {
+    { 1, 2, 3, 4, 20 },
+    { 0 },
+  };
+
+HPREF_ELEMENT_TYPE reftet_3ec_2v_newelstypes[] =
+  {
+    HP_PYRAMID_EDGES,
+    HP_PYRAMID_EDGES,
+    HP_TET_1E_1VA,
+    HP_TET_1E_1VA,
+    HP_PRISM_SINGEDGE,
+    HP_PRISM_SINGEDGE,
+    HP_PRISM_SINGEDGE,
+    
+    HP_PYRAMID,
+    HP_PYRAMID,
+    HP_TET,
+    HP_TET,
+    HP_PYRAMID,
+    HP_PYRAMID,
+    HP_PYRAMID,
+    HP_NONE,
+  };
+int reftet_3ec_2v_newels[][8] =
+{
+  { 1, 5, 17, 6, 7 },
+  { 2, 8, 18, 10, 9 },
+  { 3, 11, 12, 13 },
+  { 4, 15, 14, 16 },
+  { 5, 17, 7, 8, 9, 18 },
+  { 6, 7, 17, 11, 13, 12 },
+  { 10, 9, 18, 15, 16, 14 },
+  
+  { 9, 16, 13, 12, 20 },
+  { 7, 13, 16, 14, 20 },
+  { 7, 14, 18, 20 },
+  { 9, 12, 17, 20 },
+  { 17, 7, 18, 9, 20 },
+  { 7, 17, 12, 13, 20 },
+  { 9, 18, 14, 16, 20 },
+};
+HPRef_Struct reftet_3ec_2v =
+{
+  HP_TET,
+  reftet_3ec_2v_splitedges, 
+  reftet_3ec_2v_splitfaces, 
+  reftet_3ec_2v_splitelements, 
+  reftet_3ec_2v_newelstypes, 
+  reftet_3ec_2v_newels
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+// HP_PRISM
+int refprism_splitedges[][3] =
+{
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refprism_newelstypes[] =
+{
+  HP_PRISM,
+  HP_NONE,
+};
+int refprism_newels[][8] =
+{
+  { 1, 2, 3, 4, 5, 6 }
+};
+HPRef_Struct refprism =
+{
+  HP_PRISM,
+  refprism_splitedges, 
+  0, 0,
+  refprism_newelstypes, 
+  refprism_newels
+};
+
+
+
+// HP_PRISM_SINGEDGE
+int refprism_singedge_splitedges[][3] =
+{
+  { 1, 2, 7 },
+  { 1, 3, 8 },
+  { 4, 5, 9 },
+  { 4, 6, 10 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refprism_singedge_newelstypes[] =
+{
+  HP_PRISM_SINGEDGE,
+  HP_HEX,
+  HP_NONE,
+};
+int refprism_singedge_newels[][8] =
+{
+  { 1, 7, 8, 4, 9, 10 },
+  { 3, 8, 7, 2, 6, 10, 9, 5 }
+};
+HPRef_Struct refprism_singedge =
+{
+  HP_PRISM,
+  refprism_singedge_splitedges, 
+  0, 0,
+  refprism_singedge_newelstypes, 
+  refprism_singedge_newels
+};
+
+
+
+
+
+
+
+// HP_PYRAMID
+int refpyramid_splitedges[][3] =
+{
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refpyramid_newelstypes[] =
+{
+  HP_PYRAMID,
+  HP_NONE,
+};
+int refpyramid_newels[][8] =
+{
+  { 1, 2, 3, 4, 5, 6 }
+};
+HPRef_Struct refpyramid =
+{
+  HP_PYRAMID,
+  refpyramid_splitedges, 
+  0, 0,
+  refpyramid_newelstypes, 
+  refpyramid_newels
+};
+
+
+
+// HP_PYRAMID_0E_1V
+int refpyramid_0e_1v_splitedges[][3] =
+{
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refpyramid_0e_1v_newelstypes[] =
+{
+  HP_TET_0E_1V,
+  HP_TET,
+  HP_NONE,
+};
+int refpyramid_0e_1v_newels[][8] =
+{
+  { 1, 2, 4, 5 },
+  { 2, 3, 4, 5 },
+};
+HPRef_Struct refpyramid_0e_1v =
+{
+  HP_PYRAMID,
+  refpyramid_0e_1v_splitedges, 
+  0, 0,
+  refpyramid_0e_1v_newelstypes, 
+  refpyramid_0e_1v_newels
+};
+
+
+
+// HP_PYRAMID_EDGES
+int refpyramid_edges_splitedges[][3] =
+{
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refpyramid_edges_newelstypes[] =
+{
+  HP_TET_1E_1VA,
+  HP_TET_1E_1VA,
+  HP_NONE,
+};
+int refpyramid_edges_newels[][8] =
+{
+  { 1, 2, 3, 5 },
+  { 1, 4, 5, 3 },
+};
+HPRef_Struct refpyramid_edges =
+{
+  HP_PYRAMID,
+  refpyramid_edges_splitedges, 
+  0, 0,
+  refpyramid_edges_newelstypes, 
+  refpyramid_edges_newels
+};
+
+
+
+
+
+
+
+// HP_HEX
+int refhex_splitedges[][3] =
+{
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refhex_newelstypes[] =
+{
+  HP_HEX,
+  HP_NONE,
+};
+int refhex_newels[][8] =
+{
+  { 1, 2, 3, 4, 5, 6, 7, 8 }
+};
+HPRef_Struct refhex =
+{
+  HP_HEX,
+  refhex_splitedges, 
+  0, 0,
+  refhex_newelstypes, 
+  refhex_newels
+};
+
+
+
+
+// HP_HEX_0E_1V
+int refhex_0e_1v_splitedges[][3] =
+{
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refhex_0e_1v_newelstypes[] =
+{
+  HP_TET_0E_1V,
+  HP_TET,
+  HP_TET,
+  HP_TET,
+  HP_TET,
+  HP_TET,
+  HP_NONE,
+};
+int refhex_0e_1v_newels[][8] =
+{
+  { 1, 5, 2, 4 },
+  { 7, 3, 6, 8 },
+  { 2, 8, 5, 6 },
+  { 2, 8, 6, 3 },
+  { 2, 8, 3, 4 },
+  { 2, 8, 4, 5 },
+};
+HPRef_Struct refhex_0e_1v =
+{
+  HP_HEX,
+  refhex_0e_1v_splitedges, 
+  0, 0,
+  refhex_0e_1v_newelstypes, 
+  refhex_0e_1v_newels
+};
+
+
+
+
+
+
+// HP_HEX_3E_0V
+int refhex_3e_0v_splitedges[][3] =
+{
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refhex_3e_0v_newelstypes[] =
+{
+  HP_TET_1E_1VA,
+  HP_TET_1E_1VA,
+  HP_TET_1E_1VA,
+  HP_TET_0E_1V,
+  HP_TET,
+  HP_NONE,
+};
+int refhex_3e_0v_newels[][8] =
+{
+  { 1, 2, 3, 6 },
+  { 1, 4, 8, 3 },
+  { 1, 5, 6, 8 },
+  { 1, 6, 3, 8 },
+  { 3, 8, 6, 7 },
+};
+HPRef_Struct refhex_3e_0v =
+{
+  HP_HEX,
+  refhex_3e_0v_splitedges, 
+  0, 0,
+  refhex_3e_0v_newelstypes, 
+  refhex_3e_0v_newels
+};
+
+
+
+
+// HP_HEX_1E_0V
+int refhex_1e_0v_splitedges[][3] =
+{
+  { 0, 0, 0 }
+};
+
+HPREF_ELEMENT_TYPE refhex_1e_0v_newelstypes[] =
+{
+  HP_PRISM_SINGEDGE,
+  HP_PRISM,
+  HP_NONE,
+};
+int refhex_1e_0v_newels[][8] =
+{
+  { 1, 4, 5, 2, 3, 6 },
+  { 5, 4, 8, 6, 3, 7 },
+};
+HPRef_Struct refhex_1e_0v =
+{
+  HP_HEX,
+  refhex_1e_0v_splitedges, 
+  0, 0,
+  refhex_1e_0v_newelstypes, 
+  refhex_1e_0v_newels
+};
+
+
+
+
+
+
+
+
+HPRef_Struct * Get_HPRef_Struct (HPREF_ELEMENT_TYPE type)
+{
+  HPRef_Struct * hps = NULL;
+  switch (type)
+    {
+    case HP_TRIG:
+      hps = &reftrig; break;
+    case HP_TRIG_SINGCORNER:
+      hps = &reftrig_singcorner; break;
+    case HP_TRIG_SINGCORNER12:
+      hps = &reftrig_singcorner12; break;
+    case HP_TRIG_SINGCORNER123:
+      hps = &reftrig_singcorner123; break;
+    case HP_TRIG_SINGEDGE:
+      hps = &reftrig_singedge; break;
+    case HP_TRIG_SINGEDGECORNER1:
+      hps = &reftrig_singedgecorner1; break;
+    case HP_TRIG_SINGEDGECORNER2:
+      hps = &reftrig_singedgecorner2; break;
+    case HP_TRIG_SINGEDGECORNER12:
+      hps = &reftrig_singedgecorner12; break;
+    case HP_TRIG_SINGEDGECORNER3:
+      hps = &reftrig_singedgecorner3; break;
+    case HP_TRIG_SINGEDGECORNER13:
+      hps = &reftrig_singedgecorner13; break;
+    case HP_TRIG_SINGEDGECORNER23:
+      hps = &reftrig_singedgecorner23; break;
+    case HP_TRIG_SINGEDGECORNER123:
+      hps = &reftrig_singedgecorner123; break;
+    case HP_TRIG_SINGEDGES:
+      hps = &reftrig_singedges; break;
+    case HP_TRIG_SINGEDGES2:
+      hps = &reftrig_singedges2; break;
+    case HP_TRIG_SINGEDGES3:
+      hps = &reftrig_singedges3; break;
+    case HP_TRIG_SINGEDGES23:
+      hps = &reftrig_singedges23; break;
+    case HP_QUAD:
+      hps = &refquad; break;
+    case HP_DUMMY_QUAD_SINGCORNER:
+      hps = &refdummyquad_singcorner; break;
+    case HP_QUAD_SINGCORNER:
+      hps = &refquad_singcorner; break;
+    case HP_QUAD_SINGEDGE:
+      hps = &refquad_singedge; break;
+    case HP_QUAD_SINGEDGES:
+      hps = &refquad_singedges; break;
+
+    case HP_TET:
+      hps = &reftet; break;
+    case HP_TET_0E_1V:
+      hps = &reftet_0e_1v; break;
+    case HP_TET_0E_2V:
+      hps = &reftet_0e_2v; break;
+    case HP_TET_0E_3V:
+      hps = &reftet_0e_3v; break;
+    case HP_TET_0E_4V:
+      hps = &reftet_0e_4v; break;
+
+    case HP_TET_1E_0V:      
+      hps = &reftet_1e_0v; break;
+    case HP_TET_1E_1VA:
+      hps = &reftet_1e_1va; break;
+    case HP_TET_1E_1VB:
+      hps = &reftet_1e_1vb; break;
+
+    case HP_TET_1E_2VA:
+      hps = &reftet_1e_2va; break;
+    case HP_TET_1E_2VB:
+      hps = &reftet_1e_2vb; break;
+    case HP_TET_1E_2VC:
+      hps = &reftet_1e_2vc; break;
+    case HP_TET_1E_2VD:
+      hps = &reftet_1e_2vd; break;
+
+    case HP_TET_2EA_0V:
+      hps = &reftet_2ea_0v; break;
+    case HP_TET_2EA_1VB:
+      hps = &reftet_2ea_1vb; break;
+    case HP_TET_2EA_3V:
+      hps = &reftet_2ea_3v; break;
+
+    case HP_TET_2EB_4V:
+      hps = &reftet_2eb_4v; break;
+
+
+    case HP_TET_3EA_0V:
+      hps = &reftet_3ea_0v; break;
+    case HP_TET_3EA_3V:
+      hps = &reftet_3ea_3v; break;
+
+    case HP_TET_3EB_2V:
+      hps = &reftet_3eb_2v; break;
+    case HP_TET_3EC_2V:
+      hps = &reftet_3ec_2v; break;
+
+    case HP_PRISM:
+      hps = &refprism; break;
+    case HP_PRISM_SINGEDGE:
+      hps = &refprism_singedge; break;
+
+    case HP_PYRAMID:
+      hps = &refpyramid; break;
+    case HP_PYRAMID_0E_1V:
+      hps = &refpyramid_0e_1v; break;
+    case HP_PYRAMID_EDGES:
+      hps = &refpyramid_edges; break;
+
+    case HP_HEX:
+      hps = &refhex; break;
+    case HP_HEX_0E_1V:
+      hps = &refhex_0e_1v; break;
+    case HP_HEX_1E_0V:
+      hps = &refhex_1e_0v; break;
+    case HP_HEX_3E_0V:
+      hps = &refhex_3e_0v; break;
+    }
+
+  return hps;
+}
+
+
+
+class HPRefElement
+{
+public:
+  HPREF_ELEMENT_TYPE type;
+  int pnums[8];
+  int index;
+  int level;
+};
+
+static ARRAY<HPRefElement> elements;
+
+void PrepareElements (Mesh & mesh)
+{
+  cout << "Transform mesh to hp-elements" << endl;
+
+  int i, j, k, pi3, pi4;
+  INDEX_2_HASHTABLE<int> edges(mesh.GetNSeg()+1);
+  BitArray edgepoint(mesh.GetNP());
+  edgepoint.Clear();
+  BitArray cornerpoint(mesh.GetNP());
+  cornerpoint.Clear();
+
+  // check, if point has as least 3 different surfs:
+  ARRAY<INDEX_3> surfonpoint(mesh.GetNP());
+
+  if (mesh.GetDimension() == 3)
+    {
+      for (i = 1; i <= mesh.GetNP(); i++)
+	surfonpoint.Elem(i) = INDEX_3(0,0,0);
+      for (i = 1; i <= mesh.GetNSE(); i++)
+	{
+	  const Element2d & el = mesh.SurfaceElement(i);
+	  int ind = el.GetIndex();
+	  for (j = 0; j < el.GetNP(); j++)
+	    {
+	      int pi = el[j];
+	      INDEX_3 & i3 = surfonpoint.Elem(pi);
+	      if (ind != i3.I1() &&
+		  ind != i3.I2() && 
+		  ind != i3.I3())
+		{
+		  i3.I1() = i3.I2();
+		  i3.I2() = i3.I3();
+		  i3.I3() = ind;
+		}
+	    }
+	}
+      for (i = 1; i <= mesh.GetNP(); i++)
+	if (surfonpoint.Get(i).I1())
+	  cornerpoint.Set(i);
+      
+      // cornerpoint.Clear();
+      //  cornerpoint.Set(1);
+
+      for (i = 1; i <= mesh.GetNSeg(); i++)
+	{
+	  INDEX_2 i2 (mesh.LineSegment(i).p1, 
+		      mesh.LineSegment(i).p2);
+	  i2.Sort();
+	  // if (i2.I1() == 11 && i2.I2() == 12)
+	  {
+	    edges.Set (i2, 1);
+	    edgepoint.Set (i2.I1());
+	    edgepoint.Set (i2.I2());
+	  }
+	}
+    }
+  else
+    {
+      for (i = 1; i <= mesh.GetNP(); i++)
+	surfonpoint.Elem(i) = INDEX_3(0,0,0);
+      
+      for (i = 1; i <= mesh.GetNSeg(); i++)
+	{
+	  const Segment & seg = mesh.LineSegment(i);
+	  int ind = seg.edgenr;
+	  if (ind <= 12) continue;
+
+	  INDEX_2 i2 (mesh.LineSegment(i).p1, 
+		      mesh.LineSegment(i).p2);
+	  i2.Sort();
+	  edges.Set (i2, 1);
+	  edgepoint.Set(i2.I1());
+	  edgepoint.Set(i2.I2());
+
+	  // (*testout) << "seg = " << ind << ", " << seg.p1 << "-" << seg.p2 << endl;
+	  for (j = 0; j < 2; j++)
+	    {
+	      int pi = (j == 0) ? seg.p1 : seg.p2;
+	      // if (pi > 20)
+		{
+		  INDEX_3 & i3 = surfonpoint.Elem(pi);
+		  if (ind != i3.I1() &&
+		      ind != i3.I2())
+		    {
+		      i3.I1() = i3.I2();
+		      i3.I2() = ind;
+		    }
+		}
+	    }
+	}
+      for (i = 1; i <= mesh.GetNP(); i++)
+	if (surfonpoint.Get(i).I1())
+	  {
+	    cornerpoint.Set(i);
+	  }
+    }
+
+  int cnt_undef = 0, cnt_nonimplement = 0;
+  ARRAY<int> misses(10000);
+  misses = 0;
+
+  for (i = 1; i <= mesh.GetNE(); i++)
+    {
+      Element & el = mesh.VolumeElement(i);
+      
+      HPREF_ELEMENT_TYPE type = HP_NONE;
+      int pnums[8] = { 0 };
+
+
+      switch (el.GetType())
+	{
+	  case TET:
+	    {
+	      int ep1, ep2, ep3, ep4, cp1, cp2, cp3, cp4;
+	      int isedge1, isedge2, isedge3, isedge4, isedge5, isedge6;
+	      
+	      for (j = 1; j <= 4; j++)
+		for (k = 1; k <= 4; k++)
+		  {
+		    if (j == k) continue;
+		    if (type) break;
+	    
+	    int pi3 = 1;
+	    while (pi3 == j || pi3 == k) pi3++;
+	    pi4 = 10 - j - k - pi3;
+
+	    // preserve orientation
+	    int sort[4];
+	    sort[0] = j; sort[1] = k; sort[2] = pi3; sort[3] = pi4;
+	    int cnt = 0;
+	    for (int jj = 0; jj < 4; jj++)
+	      for (int kk = 0; kk < 3; kk++)
+		if (sort[kk] > sort[kk+1])
+		  {
+		    cnt++;
+		    Swap (sort[kk], sort[kk+1]);
+		  }
+	    if (cnt % 2 == 1) Swap (pi3, pi4);
+
+	    ep1 = edgepoint.Test (el.PNum (j));
+	    ep2 = edgepoint.Test (el.PNum (k));
+	    ep3 = edgepoint.Test (el.PNum (pi3));
+	    ep4 = edgepoint.Test (el.PNum (pi4));
+
+	    cp1 = cornerpoint.Test (el.PNum (j));
+	    cp2 = cornerpoint.Test (el.PNum (k));
+	    cp3 = cornerpoint.Test (el.PNum (pi3));
+	    cp4 = cornerpoint.Test (el.PNum (pi4));
+	    
+	    INDEX_2 i2;
+	    i2 = INDEX_2(el.PNum (j), el.PNum (k));
+	    i2.Sort();
+	    isedge1 = edges.Used (i2);
+
+	    i2 = INDEX_2(el.PNum (j), el.PNum (pi3));
+	    i2.Sort();
+	    isedge2 = edges.Used (i2);
+
+	    i2 = INDEX_2(el.PNum (j), el.PNum (pi4));
+	    i2.Sort();
+	    isedge3 = edges.Used (i2);
+
+	    i2 = INDEX_2(el.PNum (k), el.PNum (pi3));
+	    i2.Sort();
+	    isedge4 = edges.Used (i2);
+
+	    i2 = INDEX_2(el.PNum (k), el.PNum (pi4));
+	    i2.Sort();
+	    isedge5 = edges.Used (i2);
+
+	    i2 = INDEX_2(el.PNum (pi3), el.PNum (pi4));
+	    i2.Sort();
+	    isedge6 = edges.Used (i2);
+
+	    switch (isedge1+isedge2+isedge3+isedge4+isedge5+isedge6)
+	      {
+	      case 0:
+		{		
+		  if (!ep1 && !ep2 && !ep3 && !ep4)
+		    type = HP_TET;
+		  
+		  if (ep1 && !ep2 && !ep3 && !ep4)
+		    type = HP_TET_0E_1V;
+
+		  if (ep1 && ep2 && !ep3 && !ep4)
+		    type = HP_TET_0E_2V;
+
+		  if (ep1 && ep2 && ep3 && !ep4)
+		    type = HP_TET_0E_3V;
+
+		  if (ep1 && ep2 && ep3 && ep4)
+		    type = HP_TET_0E_4V;
+
+		  break;
+		}
+		
+	      case 1:
+		{
+		  if (!isedge1) break;
+		  
+		  if (!cp1 && !cp2 && !ep3 && !ep4)
+		    type = HP_TET_1E_0V;
+		    
+		  if (cp1 && !cp2 && !ep3 && !ep4)
+		    type = HP_TET_1E_1VA;
+
+		  if (!cp1 && !cp2 && !ep3 && ep4)
+		    type = HP_TET_1E_1VB;
+
+		  if (cp1 && cp2 && !ep3 && !ep4)
+		    type = HP_TET_1E_2VA;
+
+		  if (cp1 && !cp2 && ep3 && !ep4)
+		    type = HP_TET_1E_2VB;
+
+		  if (cp1 && !cp2 && !ep3 && ep4)
+		    type = HP_TET_1E_2VC;
+
+		  if (!cp1 && !cp2 && ep3 && ep4)
+		    type = HP_TET_1E_2VD;
+
+		  if (cp1 && cp2 && ep3 && !ep4)
+		    type = HP_TET_1E_3VA;
+
+		  if (cp1 && !cp2 && ep3 && ep4)
+		    type = HP_TET_1E_3VB;
+
+		  if (cp1 && cp2 && ep3 && ep4)
+		    type = HP_TET_1E_4V;
+		  
+		  break;
+		}
+
+	      case 2:
+		{
+		  if (isedge1 && isedge2)
+		    {
+		      if (!cp2 && !cp3 && !ep4)
+			type = HP_TET_2EA_0V;
+		      if (cp2 && !cp3 && !ep4)
+			type = HP_TET_2EA_1VA;
+
+		      if (!cp2 && cp3 && !ep4)
+			type = HP_TET_2EA_1VB;
+
+		      if (!cp2 && !cp3 && ep4)
+			type = HP_TET_2EA_1VC;
+
+		      if (cp2 && cp3 && !ep4)
+			type = HP_TET_2EA_2VA;
+		      if (cp2 && !cp3 && ep4)
+			type = HP_TET_2EA_2VB;
+		      if (!cp2 && cp3 && ep4)
+			type = HP_TET_2EA_2VC;
+
+		      if (cp2 && cp3 && ep4)
+			type = HP_TET_2EA_3V;
+		    }
+
+		  if (isedge1 && isedge6)
+		    {
+		      if (!cp1 && !cp2 && !cp3 && !cp4)
+			type = HP_TET_2EB_0V;
+
+		      if (cp1 && !cp2 && !cp3 && !cp4)
+			type = HP_TET_2EB_1V;
+
+		      if (cp1 && cp2 && !cp3 && !cp4)
+			type = HP_TET_2EB_2VA;
+		      if (cp1 && !cp2 && cp3 && !cp4)
+			type = HP_TET_2EB_2VB;
+		      if (cp1 && !cp2 && !cp3 && cp4)
+			type = HP_TET_2EB_2VC;
+
+		      if (cp1 && cp2 && cp3 && !cp4)
+			type = HP_TET_2EB_3V;
+
+		      if (cp1 && cp2 && cp3 && cp4)
+			type = HP_TET_2EB_4V;
+		    }
+		}
+
+	      case 3:
+		{
+		  if (isedge1 && isedge2 && isedge3)
+		    {
+		      if (!cp2 && !cp3 && !cp4)
+			type = HP_TET_3EA_0V;
+		      if (cp2 && cp3 && ep4)
+			type = HP_TET_3EA_3V;
+		    }
+		  if (isedge1 && isedge3 && isedge4)
+		    {
+		      if (cp3 && ep4)
+			type = HP_TET_3EB_2V;
+		    }
+		  if (isedge1 && isedge2 && isedge5)
+		    {
+		      if (cp3 && ep4)
+			type = HP_TET_3EC_2V;
+		    }
+		}
+	      }
+
+	    if (type != HP_NONE)
+	      {
+		pnums[0] = el.PNumMod (j);
+		pnums[1] = el.PNumMod (k);
+		pnums[2] = el.PNumMod (pi3);
+		pnums[3] = el.PNumMod (pi4);
+		break;
+	      }
+		  }
+
+
+      if (type == HP_NONE)
+	{
+	  cnt_undef++;
+	  (*testout) << "undefined element" << endl
+		     << "cp = " << cp1 << cp2 << cp3 << cp4 << endl
+		     << "ep = " << ep1 << ep2 << ep3 << ep4 << endl
+		     << "isedge = " << isedge1 << isedge2 << isedge3 
+		     << isedge4 << isedge5 << isedge6 << endl;
+	}
+      //      cout << "hpref - element = " << type << endl;
+      
+
+
+	      break;
+	    }
+	case PRISM:
+	  {
+	    int pi1, pi2, pi3, pi4, pi5, pi6;
+	    int ep1, ep2, ep3, ep4, ep5, ep6, cp1, cp2, cp3, cp4, cp5, cp6;
+
+	    int ishedge1, ishedge2, ishedge3, ishedge4, ishedge5, ishedge6;
+	    int isvedge1, isvedge2, isvedge3;
+	    
+	    for (j = 1; j <= 3; j++)
+	      {
+		if (type) break;
+
+		pi1 = j;
+		pi2 = pi1%3 + 1;
+		pi3 = pi2%3 + 1;
+		pi4 = pi1+3;
+		pi5 = pi2+3;
+		pi6 = pi3+3;
+
+		ep1 = edgepoint.Test (el.PNum (pi1));
+		ep2 = edgepoint.Test (el.PNum (pi2));
+		ep3 = edgepoint.Test (el.PNum (pi3));
+		ep4 = edgepoint.Test (el.PNum (pi4));
+		ep5 = edgepoint.Test (el.PNum (pi5));
+		ep6 = edgepoint.Test (el.PNum (pi6));
+
+		cp1 = cornerpoint.Test (el.PNum (pi1));
+		cp2 = cornerpoint.Test (el.PNum (pi2));
+		cp3 = cornerpoint.Test (el.PNum (pi3));
+		cp4 = cornerpoint.Test (el.PNum (pi4));
+		cp5 = cornerpoint.Test (el.PNum (pi5));
+		cp6 = cornerpoint.Test (el.PNum (pi6));
+	    
+		INDEX_2 i2;
+		i2 = INDEX_2(el.PNum (pi1), el.PNum (pi4));
+		i2.Sort();
+		isvedge1 = edges.Used (i2);
+
+
+		if (isvedge1 + isvedge2 + isvedge3 == 0)
+		  {
+		    type = HP_PRISM;
+		  }
+		else if (isvedge1)
+		  {
+		    type = HP_PRISM_SINGEDGE;
+		  }
+
+
+		if (type != HP_NONE)
+		  {
+		    pnums[0] = el.PNum (pi1);
+		    pnums[1] = el.PNum (pi2);
+		    pnums[2] = el.PNum (pi3);
+		    pnums[3] = el.PNum (pi4);
+		    pnums[4] = el.PNum (pi5);
+		    pnums[5] = el.PNum (pi6);
+		    break;
+		  }
+	      }
+	    break;
+	  }
+	default:
+	  {
+	    cerr << "hp-refinement not defined for element" << endl;
+	  }
+	}
+
+      if (!Get_HPRef_Struct (type)) 
+	{
+	  (*testout) << "case " << type << " not implemented " << endl;
+	  cnt_nonimplement++;
+	  misses[type]++;
+	}
+      
+      HPRefElement hpel;
+      hpel.type = type;
+      for (j = 0; j < 8; j++)
+	hpel.pnums[j] = pnums[j];
+      hpel.index = el.GetIndex();
+      hpel.level = 1;
+      elements.Append (hpel);
+    }
+
+  cout << "undefined elements: " << cnt_undef << endl;
+  cout << "non-implemented: " << cnt_nonimplement << endl;
+
+  for (i = 0; i < misses.Size(); i++)
+    if (misses[i])
+      cout << "missing case " << i << " occured " << misses[i] << " times" << endl;
+
+  for (i = 1; i <= mesh.GetNSE(); i++)
+    {
+      Element2d & el = mesh.SurfaceElement(i);
+      
+      HPREF_ELEMENT_TYPE type = HP_NONE;
+      int pnums[8] = { 0 };
+
+      switch (el.GetType())
+	{
+	case TRIG:
+	  {
+	    for (j = 1; j <= 3; j++)
+	      {
+		int ep1 = edgepoint.Test (el.PNumMod (j));
+		int ep2 = edgepoint.Test (el.PNumMod (j+1));
+		int ep3 = edgepoint.Test (el.PNumMod (j+2));
+		
+		int cp1 = cornerpoint.Test (el.PNumMod (j));
+		int cp2 = cornerpoint.Test (el.PNumMod (j+1));
+		int cp3 = cornerpoint.Test (el.PNumMod (j+2));
+		
+		INDEX_2 i2;
+		i2 = INDEX_2(el.PNumMod (j), el.PNumMod (j+1));
+		i2.Sort();
+		int isedge1 = edges.Used (i2);
+		i2 = INDEX_2(el.PNumMod (j+1), el.PNumMod (j+2));
+		i2.Sort();
+		int isedge2 = edges.Used (i2);
+		i2 = INDEX_2(el.PNumMod (j+2), el.PNumMod (j+3));
+		i2.Sort();
+		int isedge3 = edges.Used (i2);
+		
+		if (isedge1 + isedge2 + isedge3 == 0)
+		  {
+		    if (!ep1 && !ep2 && !ep3)
+		      type = HP_TRIG;
+		    
+		    if (ep1 && !ep2 && !ep3)
+		      type = HP_TRIG_SINGCORNER;
+		    
+		    if (ep1 && ep2 && !ep3)
+		      type = HP_TRIG_SINGCORNER12;
+		    
+		    if (ep1 && ep2 && ep3)
+		      type = HP_TRIG_SINGCORNER123;
+		    
+		    if (type != HP_NONE)
+		      {
+			pnums[0] = el.PNumMod (j);
+			pnums[1] = el.PNumMod (j+1);
+			pnums[2] = el.PNumMod (j+2);
+			break;
+		      }
+		  }
+		
+		if (isedge1 && !isedge2 && !isedge3)
+		  {
+		    int code = 0;
+		    if (cp1) code += 1;
+		    if (cp2) code += 2;
+		    if (ep3) code += 4;
+		    
+		    HPREF_ELEMENT_TYPE types[] =
+		      {
+			HP_TRIG_SINGEDGE, 
+			HP_TRIG_SINGEDGECORNER1, 
+			HP_TRIG_SINGEDGECORNER2,
+			HP_TRIG_SINGEDGECORNER12, 
+			HP_TRIG_SINGEDGECORNER3, 
+			HP_TRIG_SINGEDGECORNER13, 
+			HP_TRIG_SINGEDGECORNER23, 
+			HP_TRIG_SINGEDGECORNER123, 
+		      };
+		    type = types[code];
+		    pnums[0] = el.PNumMod (j);
+		    pnums[1] = el.PNumMod (j+1);
+		    pnums[2] = el.PNumMod (j+2);
+		    break;
+		  }
+		
+		
+		if (isedge1 && !isedge2 && isedge3)
+		  {
+		    if (!cp3)
+		      {
+			if (!cp2) type = HP_TRIG_SINGEDGES;
+			else      type = HP_TRIG_SINGEDGES2;
+		      }
+		    else
+		      {
+			if (!cp2) type = HP_TRIG_SINGEDGES3;
+			else      type = HP_TRIG_SINGEDGES23;
+		      }
+		    
+		    pnums[0] = el.PNumMod (j);
+		    pnums[1] = el.PNumMod (j+1);
+		    pnums[2] = el.PNumMod (j+2);
+		    break;
+		  }
+		
+		if (isedge1 && isedge2 && isedge3)
+		  {
+		    type = HP_TRIG_3SINGEDGES;
+		    pnums[0] = el.PNumMod (j);
+		    pnums[1] = el.PNumMod (j+1);
+		    pnums[2] = el.PNumMod (j+2);
+		    break;
+		  }
+	      }
+	    break;
+	  }
+	case QUAD:
+	  {
+	    for (j = 1; j <= 4; j++)
+	      {
+		int ep1 = edgepoint.Test (el.PNumMod (j));
+		int ep2 = edgepoint.Test (el.PNumMod (j+1));
+		int ep3 = edgepoint.Test (el.PNumMod (j+2));
+		int ep4 = edgepoint.Test (el.PNumMod (j+3));
+		
+		int cp1 = cornerpoint.Test (el.PNumMod (j));
+		int cp2 = cornerpoint.Test (el.PNumMod (j+1));
+		int cp3 = cornerpoint.Test (el.PNumMod (j+2));
+		int cp4 = cornerpoint.Test (el.PNumMod (j+3));
+		
+		INDEX_2 i2;
+		i2 = INDEX_2(el.PNumMod (j), el.PNumMod (j+1));
+		i2.Sort();
+		int isedge1 = edges.Used (i2);
+		i2 = INDEX_2(el.PNumMod (j+1), el.PNumMod (j+2));
+		i2.Sort();
+		int isedge2 = edges.Used (i2);
+		i2 = INDEX_2(el.PNumMod (j+2), el.PNumMod (j+3));
+		i2.Sort();
+		int isedge3 = edges.Used (i2);
+		i2 = INDEX_2(el.PNumMod (j+3), el.PNumMod (j+4));
+		i2.Sort();
+		int isedge4 = edges.Used (i2);
+		
+	  
+		if (isedge1 + isedge2 + isedge3 + isedge4 == 0)
+		  {
+		    type = HP_QUAD;
+		  }
+		else if (isedge1)
+		  {
+		    type = HP_QUAD_SINGEDGE;
+		  }
+
+		if (type != HP_NONE)
+		  {
+		    pnums[0] = el.PNumMod (j);
+		    pnums[1] = el.PNumMod (j+1);
+		    pnums[2] = el.PNumMod (j+2);
+		    pnums[3] = el.PNumMod (j+3);
+		    break;
+		  }
+	      }
+	    break;
+	  }
+	}
+	  
+      HPRefElement hpel;
+      hpel.type = type;
+      for (j = 0; j < 8; j++)
+	hpel.pnums[j] = pnums[j];
+      hpel.index = el.GetIndex();
+      hpel.level = 1;
+      
+      elements.Append (hpel);
+    }
+}
+
+
+
+void DoRefinement (Mesh & mesh)
+{
+  int i, j, k;
+
+  INDEX_2_HASHTABLE<int> newpts(elements.Size()+1);
+  INDEX_3_HASHTABLE<int> newfacepts(elements.Size()+1);
+  
+  // prepare new points
+  
+  (*testout) << "find new points" << endl;
+  int oldelsize = elements.Size();
+  for (i = 1; i <= oldelsize; i++)
+    {
+      (*testout) << "el " << i << endl;
+
+      HPRefElement & el = elements.Elem(i);
+      HPRef_Struct * hprs = Get_HPRef_Struct (el.type);
+
+      (*testout) << "type = " << el.type << endl;
+
+      
+      if (!hprs)
+	{
+	  // cout << "Refinementstruct not defined for element " << el.type << endl;
+	  continue;
+	}
+
+      j = 0;
+      while (hprs->splitedges[j][0])
+	{
+	  INDEX_2 i2(el.pnums[hprs->splitedges[j][0]-1],
+		     el.pnums[hprs->splitedges[j][1]-1]);
+	  if (!newpts.Used (i2))
+	    {
+	      Point3d np = Center (mesh.Point (i2.I1()),
+				   mesh.Point (i2.I2()));
+	      np = Center (mesh.Point (i2.I1()),np);
+	      np = Center (mesh.Point (i2.I1()),np);
+	      int npi = mesh.AddPoint (np);
+	      newpts.Set (i2, npi);
+	    }
+	  j++;
+	}
+
+
+
+      j = 0;
+      if (hprs->splitfaces)
+	while (hprs->splitfaces[j][0])
+	  {
+	    INDEX_3 i3(el.pnums[hprs->splitfaces[j][0]-1],
+		       el.pnums[hprs->splitfaces[j][1]-1],
+		       el.pnums[hprs->splitfaces[j][2]-1]);
+	    if (i3.I2() > i3.I3())
+	      Swap (i3.I2(), i3.I3());
+	    if (!newfacepts.Used (i3))
+	      {
+		Point3d np = Center (mesh.Point (i3.I2()),
+				     mesh.Point (i3.I3()));
+		np = Center (mesh.Point (i3.I1()),np);
+		np = Center (mesh.Point (i3.I1()),np);
+		int npi = mesh.AddPoint (np);
+		newfacepts.Set (i3, npi);
+	      }
+	    j++;
+	  }
+    }
+  
+
+
+  (*testout) << "generate elements" << endl;
+
+  for (i = 1; i <= oldelsize; i++)
+    {
+      (*testout) << "el " << i << endl;
+
+      HPRefElement & el = elements.Elem(i);
+      HPRef_Struct * hprs = Get_HPRef_Struct (el.type);
+      int newlevel = el.level + 1;
+
+      if (el.type == HP_TRIG ||
+	  el.type == HP_QUAD ||
+	  el.type == HP_TET ||
+	  el.type == HP_PRISM ||
+	  el.type == HP_HEX)
+	newlevel = el.level;
+
+      (*testout) << "type = " << el.type << endl;
+
+      if (!hprs)
+	{
+	  continue;
+	}
+
+      int newpnums[33];
+      for (j = 0; j < 8; j++)
+	newpnums[j] = el.pnums[j];
+
+      j = 0;
+      while (hprs->splitedges[j][0])
+	{
+	  INDEX_2 i2(el.pnums[hprs->splitedges[j][0]-1],
+		     el.pnums[hprs->splitedges[j][1]-1]);
+
+	  int npi = newpts.Get(i2);
+	  newpnums[hprs->splitedges[j][2]-1] = npi;
+	  j++;
+	}
+
+      j = 0;
+      if (hprs->splitfaces)
+	while (hprs->splitfaces[j][0])
+	  {
+	    INDEX_3 i3(el.pnums[hprs->splitfaces[j][0]-1],
+		       el.pnums[hprs->splitfaces[j][1]-1],
+		       el.pnums[hprs->splitfaces[j][2]-1]);
+	    if (i3.I2() > i3.I3())
+	      Swap (i3.I2(), i3.I3());
+	    int npi = newfacepts.Get(i3);
+	    newpnums[hprs->splitfaces[j][3]-1] = npi;
+	    j++;
+	  }
+
+
+      j = 0;
+      if (hprs->splitelements)
+	while (hprs->splitelements[j][0])
+	  {
+	    int pi1 = el.pnums[hprs->splitelements[j][0]-1];
+	    Point3d np = 
+	      Center (Center (mesh.Point (pi1),
+			      mesh.Point (el.pnums[hprs->splitelements[j][1]-1])),
+		      Center (mesh.Point (el.pnums[hprs->splitelements[j][2]-1]),
+			      mesh.Point (el.pnums[hprs->splitelements[j][3]-1])));
+	    
+	    np = Center (mesh.Point (pi1),np);
+	    int npi = mesh.AddPoint (np);
+	    newpnums[hprs->splitelements[j][4]-1] = npi;
+	    j++;
+	  }
+      (*testout) << "type = " << el.type << endl;
+      (*testout) << "newpnums = ";
+      for (k = 0; k < 10; k++)
+	(*testout) << newpnums[k] << " ";
+      (*testout) << endl;
+
+      j = 0;
+      while (hprs->neweltypes[j])
+	{
+	  HPRefElement newel;
+	  newel.type = hprs->neweltypes[j];
+	  for (k = 0; k < 8; k++)
+	    newel.pnums[k] = newpnums[hprs->newels[j][k]-1];
+
+	  if (newel.pnums[1] == newel.pnums[3])
+	    {
+	      cout << "same node numbers !!!! " << endl;
+	      (*testout) << "same node numbers !!!! " << endl;
+	    }
+	  (*testout) << "new el: ";
+	  for (k = 0; k < 8; k++)
+	    (*testout) << newel.pnums[k] << " ";
+	  (*testout) << endl;
+
+	  newel.index = elements.Elem(i).index;
+	  newel.level = newlevel;
+
+	  if (j == 0)
+	    elements.Elem(i) = newel;
+	  else
+	    elements.Append (newel);
+	  j++;
+	}
+      (*testout) << "el complete" << endl;
+    }
+
+  cout << "refinement done" << endl;
+}
+
+
+
+void DoRefineDummies (Mesh & mesh)
+{
+  cout << "refine dummies" << endl;
+  int i, j, k;
+
+  int oldelsize = elements.Size();
+
+  for (i = 1; i <= oldelsize; i++)
+    {
+      HPRefElement & el = elements.Elem(i);
+      HPRef_Struct * hprs = Get_HPRef_Struct (el.type);
+
+      int newlevel = el.level;
+
+      if (el.type != HP_DUMMY_QUAD_SINGCORNER &&
+	  el.type != HP_PYRAMID_EDGES &&
+	  el.type != HP_PYRAMID_0E_1V &&
+	  el.type != HP_HEX_0E_1V &&
+	  el.type != HP_HEX_1E_0V &&
+	  el.type != HP_HEX_3E_0V
+	  ) continue;
+
+      if (!hprs) continue;
+
+      int newpnums[33];
+      for (j = 0; j < 8; j++)
+	newpnums[j] = el.pnums[j];
+
+      j = 0;
+      while (hprs->neweltypes[j])
+	{
+	  HPRefElement newel;
+	  newel.type = hprs->neweltypes[j];
+	  for (k = 0; k < 8; k++)
+	    newel.pnums[k] = newpnums[hprs->newels[j][k]-1];
+	  newel.index = el.index;
+
+	  newel.level = newlevel;
+
+	  if (j == 0)
+	    elements.Elem(i) = newel;
+	  else
+	    elements.Append (newel);
+	  j++;
+	}
+    }
+  cout << "refineme dummies done" << endl;
+}
+
+
+
+
+
+
+
+void CalcStatistics ()
+{
+  int i, p;
+  int ntrig = 0, nquad = 0;
+  int nhex = 0, nprism = 0, ntet = 0;
+  int maxlevel = 0;
+
+  for (i = 1; i <= elements.Size(); i++)
+    {
+      const HPRefElement & el = elements.Get(i);
+      maxlevel = max2 (el.level, maxlevel);
+      switch (el.type)
+	{
+	case HP_TRIG:
+	case HP_TRIG_SINGCORNER:
+	case HP_TRIG_SINGEDGE:
+	case HP_TRIG_SINGEDGECORNER1:
+	case HP_TRIG_SINGEDGECORNER2:
+	  {
+	    ntrig ++;
+	    break;
+	  }
+	case HP_QUAD:
+	case HP_QUAD_SINGEDGE:
+	  {
+	    nquad++;
+	    break;
+	  }
+	case HP_TET:
+	case HP_TET_0E_1V:
+	case HP_TET_1E_0V:
+	case HP_TET_1E_1VA:
+	  {
+	    ntet++;
+	    break;
+	  }
+
+	case HP_PRISM:
+	case HP_PRISM_SINGEDGE:
+	  {
+	    nprism++;
+	    break;
+	  }
+
+	case HP_HEX:
+	  {	
+	    nhex++;
+	    break;
+	  }
+	}
+    }
+
+  cout << "level = " << maxlevel << endl;
+  cout << "ntrig = " << ntrig << ", nquad = " << nquad << endl;
+  cout << "ntet = " << ntet << ", nprism = " << nprism << ", nhex = " << nhex << endl;
+
+  return;
+
+  double memcost = 0, cpucost = 0;
+  for (p = 1; p <= 20; p++)
+    {
+      memcost = (ntet + nprism + nhex) * pow (p, 6.0);
+      cpucost = (ntet + nprism + nhex) * pow (p, 9.0);
+      cout << "costs for p = " << p << ": mem = " << memcost << ", cpu = " << cpucost << endl;
+    }
+
+  double memcosttet = 0;
+  double memcostprism = 0;
+  double memcosthex = 0;
+  double memcostsctet = 0;
+  double memcostscprism = 0;
+  double memcostschex = 0;
+  double cpucosttet = 0;
+  double cpucostprism = 0;
+  double cpucosthex = 0;
+
+  for (i = 1; i <= elements.Size(); i++)
+    {
+      const HPRefElement & el = elements.Get(i);
+      switch (el.type)
+	{
+	case HP_TET:
+	case HP_TET_0E_1V:
+	case HP_TET_1E_0V:
+	case HP_TET_1E_1VA:
+	  {
+	    int p1 = maxlevel - el.level + 1;
+	    (*testout) << "p1 = " << p1 << ", P1^6 = " << pow (p1, 6.0)
+		       << " (p1-3)^6 = " << pow ( max2(p1-3, 0), 6.0) 
+		       << " p1^3 = " << pow ( p1, 3.0) 
+		       << " (p1-3)^3 = " << pow ( p1-3, 3.0) 
+		       << " [p1^3-(p1-3)^3]^2 = " << sqr (pow (p1,3.0) - pow ( p1-3, 3.0))
+		       << endl;
+
+	    p1 /= 2 +1;
+	    memcosttet += pow (p1, 6.0);
+	    memcostsctet += pow (p1, 6.0) - pow ( max2(p1-3, 1), 6.0);
+	    cpucosttet += pow (p1, 9.0);
+	    break;
+	  }
+	case HP_PRISM:
+	case HP_PRISM_SINGEDGE:
+	  {
+	    int p1 = maxlevel - el.level + 1;
+	    p1 /= 2 +1;
+	    memcostprism += pow (p1, 6.0);
+	    memcostscprism += pow (p1, 6.0) - pow ( max2(p1-3, 1), 6.0);
+	    cpucostprism += pow (p1, 9.0);
+	    break;
+	  }
+	case HP_HEX:
+	  {	
+	    int p1 = maxlevel - el.level + 1;
+	    int p2 = maxlevel;
+	    p1 /= 2 +1;
+	    p2 /= 2 +1;
+	    memcosthex += pow (p1, 4.0) * pow (p2, 2.0);
+	    memcostschex += pow (p1, 6.0) - pow ( max2(p1-2, 0), 6.0);
+	    cpucosthex += pow (p1, 6.0) * pow (p2, 3.0);
+	    break;
+	  }
+	default:
+	  ;
+	}
+    }
+  cout << "TET: hp-memcost = " << memcosttet 
+       << ", scmemcost = " << memcostsctet
+       << ", cpucost = " << cpucosttet
+       << endl;
+  cout << "PRI: hp-memcost = " << memcostprism
+       << ", scmemcost = " << memcostscprism
+       << ", cpucost = " << cpucostprism << endl;
+  cout << "HEX: hp-memcost = " << memcosthex
+       << ", scmemcost = " << memcostschex
+       << ", cpucost = " << cpucosthex << endl;
+}
+
+void HPRefinement (Mesh & mesh, int levels)
+{
+  int i, j;
+  cout << "HP Refinement called, levels = " << levels;
+
+  PrepareElements (mesh);
+
+  for (j = 1; j <= levels; j++)
+    {
+      DoRefinement (mesh);
+      DoRefineDummies (mesh);
+      CalcStatistics ();
+    }
+  
+  mesh.ClearSurfaceElements();
+  mesh.ClearVolumeElements();
+
+  for (i = 1; i <= elements.Size(); i++)
+    {
+      HPRefElement & hpel = elements.Elem(i);
+      if (Get_HPRef_Struct (hpel.type))
+	switch (Get_HPRef_Struct (hpel.type) -> geom)
+	{
+	case HP_TRIG:
+	  {
+	    Element2d el(3);
+	    el.PNum(1) = hpel.pnums[0];
+	    el.PNum(2) = hpel.pnums[1];
+	    el.PNum(3) = hpel.pnums[2];
+	    el.SetIndex (hpel.index);
+	    mesh.AddSurfaceElement (el);
+	    break;
+	  }
+	case HP_QUAD:
+	  {
+	    Element2d el(4);
+	    el.PNum(1) = hpel.pnums[0];
+	    el.PNum(2) = hpel.pnums[1];
+	    el.PNum(3) = hpel.pnums[2];
+	    el.PNum(4) = hpel.pnums[3];
+	    el.SetIndex (hpel.index);
+	    mesh.AddSurfaceElement (el);
+	    break;
+	  }
+	case HP_TET:
+	  {
+	    Element el(4);
+	    el.PNum(1) = hpel.pnums[0];
+	    el.PNum(2) = hpel.pnums[1];
+	    el.PNum(3) = hpel.pnums[2];
+	    el.PNum(4) = hpel.pnums[3];
+	    el.SetIndex (hpel.index);
+	    mesh.AddVolumeElement (el);
+	    break;
+	  }
+	case HP_PRISM:
+	  {
+	    Element el(6);
+	    el.PNum(1) = hpel.pnums[0];
+	    el.PNum(2) = hpel.pnums[1];
+	    el.PNum(3) = hpel.pnums[2];
+	    el.PNum(4) = hpel.pnums[3];
+	    el.PNum(5) = hpel.pnums[4];
+	    el.PNum(6) = hpel.pnums[5];
+	    el.SetIndex (hpel.index);
+	    mesh.AddVolumeElement (el);
+	    break;
+	  }
+
+	case HP_PYRAMID:
+	  {
+	    Element el(5);
+	    el.PNum(1) = hpel.pnums[0];
+	    el.PNum(2) = hpel.pnums[1];
+	    el.PNum(3) = hpel.pnums[2];
+	    el.PNum(4) = hpel.pnums[3];
+	    el.PNum(5) = hpel.pnums[4];
+	    el.SetIndex (hpel.index);
+	    mesh.AddVolumeElement (el);
+	    break;
+	  }
+	case HP_HEX:
+	  {
+	    Element el(8);
+	    el.PNum(1) = hpel.pnums[0];
+	    el.PNum(2) = hpel.pnums[1];
+	    el.PNum(3) = hpel.pnums[2];
+	    el.PNum(4) = hpel.pnums[3];
+	    el.PNum(5) = hpel.pnums[4];
+	    el.PNum(6) = hpel.pnums[5];
+	    el.PNum(7) = hpel.pnums[6];
+	    el.PNum(8) = hpel.pnums[7];
+	    
+	    (*testout) << "hex: " << endl;
+	    for (int ii = 1;  ii <= 8; ii++)
+	      (*testout) << hpel.pnums[ii-1] << " ";
+	    (*testout) << endl;
+
+	    el.SetIndex (hpel.index);
+	    mesh.AddVolumeElement (el);
+	    break;
+	  }
+
+	default:
+	  PrintSysError ("hpref, backconversion failed for element ", 
+			 int(Get_HPRef_Struct (hpel.type) -> geom));
+	}
+    }
+  
+  mesh.UpdateTopology();
+}
+
+
+}
diff --git a/Netgen/libsrc/meshing/hprefinement.hpp b/Netgen/libsrc/meshing/hprefinement.hpp
new file mode 100644
index 0000000000..ca21a886d6
--- /dev/null
+++ b/Netgen/libsrc/meshing/hprefinement.hpp
@@ -0,0 +1,22 @@
+#ifndef FILE_HPREFINEMENT
+#define FILE_HPREFINEMENT
+
+/**************************************************************************/
+/* File:   hprefinement.hh                                                */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   27. Oct. 2000                                                  */
+/**************************************************************************/
+
+/*
+  HP Refinement
+*/
+
+
+extern void HPRefinement (Mesh & mesh, int levels);
+
+
+#endif
+
+
+
+
diff --git a/Netgen/libsrc/meshing/improve2.cpp b/Netgen/libsrc/meshing/improve2.cpp
new file mode 100644
index 0000000000..e70944d69b
--- /dev/null
+++ b/Netgen/libsrc/meshing/improve2.cpp
@@ -0,0 +1,766 @@
+#include <mystdlib.h>
+
+#include "meshing.hpp"
+#include <opti.hpp>
+
+//removed for gmsh
+//#include <visual.hpp>
+
+
+namespace netgen
+{
+
+class Neighbour
+{
+  int nr[3];
+  int orient[3];
+
+public:
+  Neighbour () { nr[0] = nr[1] = nr[2] = -1; orient[0] = orient[1] = orient[2] = 0; }
+
+  void SetNr (int side, int anr) { nr[side-1] = anr; }
+  int GetNr (int side) { return nr[side-1]; }
+
+  void SetOrientation (int side, int aorient) { orient[side-1] = aorient; }
+  int GetOrientation (int side) { return orient[side-1]; }
+};
+
+
+
+
+class trionedge
+{
+public:
+  int tnr;
+  int sidenr;
+
+  trionedge () { tnr = 0; sidenr = 0; }
+  trionedge (int atnr, int asidenr)
+    { tnr = atnr; sidenr = asidenr; }
+};
+
+
+
+ 
+void MeshOptimize2d :: EdgeSwapping (Mesh & mesh, int usemetric)
+{
+  if (!faceindex)
+    {
+      if (usemetric)
+	PrintMessage (3, "Edgeswapping, metric");
+      else
+	PrintMessage (3, "Edgeswapping, topological");
+
+      for (faceindex = 1; faceindex <= mesh.GetNFD(); faceindex++)
+	{
+	  EdgeSwapping (mesh, usemetric);
+
+	  if (multithread.terminate)
+	    throw NgException ("Meshing stopped");
+	}
+
+      faceindex = 0;
+      return;
+    }
+
+  int i, i2, j, k, j2;
+  bool should;
+  PointIndex pi;
+
+  ARRAY<SurfaceElementIndex> seia;
+  mesh.GetSurfaceElementsOfFace (faceindex, seia);
+
+  for (i = 0; i < seia.Size(); i++)
+    if (mesh[seia[i]].GetNP() != 3)
+      {
+	GenericImprove (mesh);
+	return;
+      }
+
+  int surfnr = mesh.GetFaceDescriptor (faceindex).SurfNr();
+
+  ARRAY<Neighbour> neighbors(mesh.GetNSE());
+  INDEX_2_HASHTABLE<trionedge> other(seia.Size() + 2);
+
+
+  ARRAY<char> swapped(mesh.GetNSE());
+  ARRAY<int,PointIndex::BASE> pdef(mesh.GetNP());
+  ARRAY<double,PointIndex::BASE> pangle(mesh.GetNP());
+
+  SurfaceElementIndex t1, t2;
+  int o1, o2;
+
+  PointIndex pi1, pi2, pi3, pi4;
+  PointGeomInfo gi1, gi2, gi3, gi4;
+
+
+  int nswaps = 0;
+  int e, done;
+  double d;
+  Vec3d nv1, nv2;
+  double horder;
+  double loch;
+  static const double minangle[] = { 0, 1.481, 2.565, 3.627, 4.683, 5.736, 7, 9 };
+
+  pangle = 0;
+
+  for (i = 0; i < seia.Size(); i++)
+    {
+      const Element2d & sel = mesh[seia[i]];
+      for (j = 0; j < 3; j++)
+	{
+	  POINTTYPE typ = mesh.PointType (sel[j]);
+	  if (typ == FIXEDPOINT || typ == EDGEPOINT)
+	    {
+	      pangle[sel[j]] +=
+		Angle (mesh[sel[(j+1)%3]] - mesh[sel[j]],
+		       mesh[sel[(j+2)%3]] - mesh[sel[j]]);
+	    }
+	}
+    }
+
+  for (pi = PointIndex::BASE; 
+       pi < mesh.GetNP()+PointIndex::BASE; pi++)
+    {
+      if (mesh.PointType(pi) == INNERPOINT || mesh.PointType(pi) == SURFACEPOINT)
+	pdef[pi] = -6;
+      else
+	for (j = 0; j < 8; j++)
+	  if (pangle[pi] >= minangle[j])
+	    pdef[pi] = -1-j;
+    }
+
+  for (i = 0; i < seia.Size(); i++)
+    {
+      const Element2d & sel = mesh[seia[i]];
+      for (j = 0; j < 3; j++)
+	pdef[sel[j]]++;
+    }
+
+  for (i = 0; i < seia.Size(); i++)
+    {
+      const Element2d & sel = mesh[seia[i]];
+      for (j = 0; j < 3; j++)
+	{
+	  neighbors[seia[i]].SetNr (j+1, -1);
+	  neighbors[seia[i]].SetOrientation (j+1, 0);
+	}
+    }
+
+  /*
+  ARRAY<Vec3d> normals(mesh.GetNP());
+  for (i = 1; i <= mesh.GetNSE(); i++)
+    {
+      Element2d & hel = mesh.SurfaceElement(i);
+      if (hel.GetIndex() == faceindex)
+	for (k = 1; k <= 3; k++)
+	  {
+	    int pi = hel.PNum(k);
+	    SelectSurfaceOfPoint (mesh.Point(pi), hel.GeomInfoPi(k));
+	    int surfi = mesh.GetFaceDescriptor(faceindex).SurfNr();
+	    GetNormalVector (surfi, mesh.Point(pi), normals.Elem(pi));
+	    normals.Elem(pi) /= normals.Elem(pi).Length();
+	  }
+    }
+  */	    
+
+  
+  for (i = 0; i < seia.Size(); i++)
+    {
+      const Element2d & sel = mesh[seia[i]];
+
+      for (j = 1; j <= 3; j++)
+	{
+	  pi1 = sel.PNumMod(j+1);
+	  pi2 = sel.PNumMod(j+2);
+	  
+	  loch = mesh.GetH(mesh[pi1]);
+	    
+	  INDEX_2 edge(pi1, pi2);
+	  edge.Sort();
+	  
+	  if (mesh.IsSegment (pi1, pi2))
+	    continue;
+	  
+	  /*
+	    if (segments.Used (edge))
+	    continue;
+	  */
+	  INDEX_2 ii2 (pi1, pi2);
+	  if (other.Used (ii2))
+	    {
+	      // INDEX_2 i2s(ii2);
+	      // i2s.Sort();
+	      
+	      i2 = other.Get(ii2).tnr;
+	      j2 = other.Get(ii2).sidenr;
+		
+	      neighbors[seia[i]].SetNr (j, i2);
+	      neighbors[seia[i]].SetOrientation (j, j2);
+	      neighbors[i2].SetNr (j2, seia[i]);
+	      neighbors[i2].SetOrientation (j2, j);
+	    }
+	  else
+	    {
+	      other.Set (INDEX_2 (pi2, pi1), trionedge (seia[i], j));
+	    }
+	}
+    }
+
+  for (i = 0; i < seia.Size(); i++)
+    swapped[seia[i]] = 0;
+
+
+  int t = 4;
+  done = 0;
+  while (!done && t >= 2)
+    {
+      for (i = 0; i < seia.Size(); i++)
+	{
+	  t1 = seia[i];
+
+	  if (mesh[t1].IsDeleted())
+	    continue;
+
+	  if (mesh[t1].GetIndex() != faceindex)
+	    continue;
+
+	  if (multithread.terminate)
+	    throw NgException ("Meshing stopped");
+
+	  for (o1 = 1; o1 <= 3; o1++)
+	    {
+	      t2 = neighbors[t1].GetNr (o1);
+	      o2 = neighbors[t1].GetOrientation (o1);
+
+	      if (t2 == -1) continue;
+	      if (swapped[t1] || swapped[t2]) continue;
+	      
+
+	      pi1 = mesh[t1].PNumMod(o1+1);
+	      pi2 = mesh[t1].PNumMod(o1+2);
+	      pi3 = mesh[t1].PNumMod(o1);
+	      pi4 = mesh[t2].PNumMod(o2);
+	      
+	      gi1 = mesh[t1].GeomInfoPiMod(o1+1);
+	      gi2 = mesh[t1].GeomInfoPiMod(o1+2);
+	      gi3 = mesh[t1].GeomInfoPiMod(o1);
+	      gi4 = mesh[t2].GeomInfoPiMod(o2);
+	      
+	      // normal of old
+	      nv1 = Cross (mesh.Point(pi3)-mesh.Point(pi4), 
+			   mesh.Point(pi1)-mesh.Point(pi4));
+	      nv2 = Cross (mesh.Point(pi4)-mesh.Point(pi3), 
+			   mesh.Point(pi2)-mesh.Point(pi3));
+
+	      
+	      // normals of swapped
+	      Vec3d nv3, nv4;
+	      nv3 = Cross (mesh.Point(pi1)-mesh.Point(pi4), 
+			   mesh.Point(pi2)-mesh.Point(pi4));
+	      nv4 = Cross (mesh.Point(pi2)-mesh.Point(pi3), 
+			   mesh.Point(pi1)-mesh.Point(pi3));
+	      
+	      
+	      nv1.Normalize();
+	      nv2.Normalize();
+	    
+	      Vec3d nvp3, nvp4;
+	      SelectSurfaceOfPoint (mesh.Point(pi3), gi3);
+	      GetNormalVector (surfnr, mesh.Point(pi3), gi3, nvp3);
+
+	      nvp3.Normalize();
+
+	      SelectSurfaceOfPoint (mesh.Point(pi4), gi4);
+	      GetNormalVector (surfnr, mesh.Point(pi4), gi4, nvp4);
+	    
+	      nvp4.Normalize();
+	      
+	      
+	      
+	      double critval = cos (M_PI / 6);  // 30 degree
+	      bool allowswap = 
+		(nv1 * nvp3 > critval) && 
+		(nv1 * nvp4 > critval) && 
+		(nv2 * nvp3 > critval) && 
+		(nv2 * nvp4 > critval) &&
+		(nvp3 * nv3 > critval) && 
+		(nvp4 * nv4 > critval);
+	      
+	      horder = Dist (mesh.Point(pi1), mesh.Point(pi2));
+	      
+	      if ( // nv1 * nv2 >= 0 &&
+		  nv1.Length() > 1e-3 * horder * horder &&
+		  nv2.Length() > 1e-3 * horder * horder &&
+		  allowswap )
+		{
+		  if (!usemetric)
+		    {
+		      e = pdef[pi1] + pdef[pi2] - pdef[pi3] - pdef[pi4];
+		      d = 
+			Dist2 (mesh.Point(pi1), mesh.Point(pi2)) - 
+			Dist2 (mesh.Point(pi3), mesh.Point(pi4));
+		      
+		      should = e >= t && (e > 2 || d > 0);
+		    }
+		  else
+		    {
+		      should = 
+			CalcTriangleBadness (mesh.Point(pi4), mesh.Point(pi3), mesh.Point(pi1), 
+					     metricweight, loch) +
+			CalcTriangleBadness (mesh.Point(pi3), mesh.Point(pi4), mesh.Point(pi2), 
+					     metricweight, loch) <
+			CalcTriangleBadness (mesh.Point(pi1), mesh.Point(pi2), mesh.Point(pi3), 
+					     metricweight, loch) +
+			CalcTriangleBadness (mesh.Point(pi2), mesh.Point(pi1), mesh.Point(pi4), 
+					     metricweight, loch);
+		    }
+
+		  
+		  if (allowswap)
+		    {
+		      Element2d sw1 (pi4, pi3, pi1);
+		      Element2d sw2 (pi4, pi4, pi2);
+
+		      int legal1 = 
+			mesh.LegalTrig (mesh.SurfaceElement (t1)) + 
+			mesh.LegalTrig (mesh.SurfaceElement (t2));
+		      int legal2 = 
+			mesh.LegalTrig (sw1) + mesh.LegalTrig (sw2);
+
+		      if (legal1 < legal2) should = 1;
+		      if (legal2 < legal1) should = 0;
+		    }
+		  
+		  if (should)
+		    {
+		      // do swapping !
+		      
+		      nswaps ++;
+		      
+		    //            testout << "nv1 = " << nv1 << "   nv2 = " << nv2 << endl;
+		      
+		      done = 1;
+		      
+		      mesh[t1].PNum(1) = pi1;
+		      mesh[t1].PNum(2) = pi4;
+		      mesh[t1].PNum(3) = pi3;
+		      
+		      mesh[t2].PNum(1) = pi2;
+		      mesh[t2].PNum(2) = pi3;
+		      mesh[t2].PNum(3) = pi4;
+		      
+		      mesh[t1].GeomInfoPi(1) = gi1;
+		      mesh[t1].GeomInfoPi(2) = gi4;
+		      mesh[t1].GeomInfoPi(3) = gi3;
+		      
+		      mesh[t2].GeomInfoPi(1) = gi2;
+		      mesh[t2].GeomInfoPi(2) = gi3;
+		      mesh[t2].GeomInfoPi(3) = gi4;
+		      
+		      pdef[pi1]--;
+		      pdef[pi2]--;
+		      pdef[pi3]++;
+		      pdef[pi4]++;
+		      
+		      swapped.Elem(t1) = 1;
+		      swapped.Elem(t2) = 1;
+		    }
+		}
+	    }
+	}
+      t--;
+    }
+
+  mesh.SetNextTimeStamp();
+}
+
+
+
+
+
+
+
+ 
+void MeshOptimize2d :: CombineImprove (Mesh & mesh)
+{
+  if (!faceindex)
+    {
+      PrintMessage (3, "Combine improve");
+
+      for (faceindex = 1; faceindex <= mesh.GetNFD(); faceindex++)
+	{
+	  CombineImprove (mesh);
+
+	  if (multithread.terminate)
+	    throw NgException ("Meshing stopped");
+	}
+      faceindex = 0;
+      return;
+    }
+
+
+  int i, j, k, l, i2, j2;
+  PointIndex pi;
+  SurfaceElementIndex sei;
+
+
+  ARRAY<SurfaceElementIndex> seia;
+  mesh.GetSurfaceElementsOfFace (faceindex, seia);
+
+
+  for (i = 0; i < seia.Size(); i++)
+    if (mesh[seia[i]].GetNP() != 3)
+      return;
+
+
+
+  int surfnr = 0;
+  if (faceindex)
+    surfnr = mesh.GetFaceDescriptor (faceindex).SurfNr();
+
+
+  int should;
+  PointIndex pi1, pi2;
+  Point3d p1, p2, pnew;
+  double bad1, bad2;
+  Vec3d nv;
+
+  int np = mesh.GetNP();
+  int nse = mesh.GetNSE();
+
+  TABLE<SurfaceElementIndex,PointIndex::BASE> elementsonnode(np); 
+  ARRAY<SurfaceElementIndex> hasonepi, hasbothpi;
+
+  for (i = 0; i < seia.Size(); i++)
+    {
+      Element2d & el = mesh[seia[i]];
+      for (j = 0; j < el.GetNP(); j++)
+	elementsonnode.Add (el[j], seia[i]);
+    }
+
+  ARRAY<int,PointIndex::BASE> fixed(np);
+  fixed = 0;
+
+  SegmentIndex si;
+  for (si = 0; si < mesh.GetNSeg(); si++)
+    {
+      INDEX_2 i2(mesh[si].p1, mesh[si].p2);
+      fixed[i2.I1()] = 1;
+      fixed[i2.I2()] = 1;
+    }
+
+
+  ARRAY<Vec3d,PointIndex::BASE> normals(np);
+
+  for (pi = PointIndex::BASE; 
+       pi < np + PointIndex::BASE; pi++)
+    {
+      if (elementsonnode[pi].Size())
+	{
+	  Element2d & hel = mesh[elementsonnode[pi][0]];
+	  for (k = 0; k < 3; k++)
+	    if (hel[k] == pi)
+	      {
+		SelectSurfaceOfPoint (mesh[pi], hel.GeomInfoPi(k+1));
+		GetNormalVector (surfnr, mesh[pi], hel.GeomInfoPi(k+1), normals[pi]);
+		break;
+	      }
+	  if (k == 3)
+	    {
+	      cerr << "Neuer Fehler von Joachim, code 17121" << endl;
+	    }
+	}
+    }
+	
+
+  for (i = 0; i < seia.Size(); i++)
+    {
+      sei = seia[i];
+      Element2d & elem = mesh[sei];
+      if (elem.IsDeleted()) continue;
+
+      for (j = 0; j < 3; j++)
+	{
+	  pi1 = elem[j];
+	  pi2 = elem[(j+1) % 3];
+
+	  if (pi1 < PointIndex::BASE || 
+	      pi2 < PointIndex::BASE)
+	    continue;
+
+	  /*
+	  INDEX_2 i2(pi1, pi2);
+	  i2.Sort();
+	  if (segmentht.Used(i2))
+	    continue;
+	  */
+
+	  bool debugflag = 0;
+
+	  if (debugflag)
+	    {
+	      (*testout) << "Combineimprove, face = " << faceindex 
+			 << "pi1 = " << pi1 << " pi2 = " << pi2 << endl;
+	    }
+
+	  /*
+	  // save version:
+	  if (fixed.Get(pi1) || fixed.Get(pi2)) 
+	    continue;
+	  if (pi2 < pi1) Swap (pi1, pi2);
+	  */
+
+	  // more general 
+	  if (fixed[pi2]) 
+	    Swap (pi1, pi2);
+
+	  if (fixed[pi2])  
+	    continue;
+
+	  double loch = mesh.GetH (mesh[pi1]);
+
+	  INDEX_2 si2 (pi1, pi2);
+	  si2.Sort();
+
+	  /*	  
+	  if (edgetested.Used (si2))
+	    continue;
+	  edgetested.Set (si2, 1);
+	  */
+
+	  hasonepi.SetSize(0);
+	  hasbothpi.SetSize(0);
+
+	  for (k = 0; k < elementsonnode[pi1].Size(); k++)
+	    {
+	      const Element2d & el2 = mesh[elementsonnode[pi1][k]];
+
+	      if (el2.IsDeleted()) continue;
+
+	      if (el2[0] == pi2 || el2[1] == pi2 || el2[2] == pi2)
+		{
+		  hasbothpi.Append (elementsonnode[pi1][k]);
+		  nv = Cross (Vec3d (mesh[el2[0]], mesh[el2[1]]),
+			      Vec3d (mesh[el2[0]], mesh[el2[2]]));
+		}
+	      else
+		{
+		  hasonepi.Append (elementsonnode[pi1][k]);
+		}
+	    } 
+
+	  Element2d & hel = mesh[hasbothpi[0]];
+	  for (k = 0; k < 3; k++)
+	    if (hel[k] == pi1)
+	      {
+		SelectSurfaceOfPoint (mesh[pi1],
+				      hel.GeomInfoPi(k+1));
+		GetNormalVector (surfnr, mesh[pi1], hel.GeomInfoPi(k+1), nv);
+		break;
+	      }
+	  if (k == 3)
+	    {
+	      cerr << "Neuer Fehler von Joachim, code 32434" << endl;
+	    }
+
+
+	  //	  nv = normals.Get(pi1);
+
+
+	  for (k = 0; k < elementsonnode[pi2].Size(); k++)
+	    {
+	      const Element2d & el2 = mesh[elementsonnode[pi2][k]];
+	      if (el2.IsDeleted()) continue;
+
+	      if (el2[0] == pi1 || el2[1] == pi1 || el2[2] == pi1)
+		;
+	      else
+		hasonepi.Append (elementsonnode[pi2][k]);
+	    } 
+
+	  bad1 = 0;
+	  int illegal1 = 0, illegal2 = 0;
+	  for (k = 0; k < hasonepi.Size(); k++)
+	    {
+	      const Element2d & el = mesh[hasonepi[k]];
+	      bad1 += CalcTriangleBadness (mesh[el[0]], mesh[el[1]], mesh[el[2]],
+					   nv, -1, loch);
+	      illegal1 += 1-mesh.LegalTrig(el);
+	    }
+	  
+	  for (k = 0; k < hasbothpi.Size(); k++)
+	    {
+	      const Element2d & el = mesh[hasbothpi[k]];
+	      bad1 += CalcTriangleBadness (mesh[el[0]], mesh[el[1]], mesh[el[2]],
+					   nv, -1, loch);
+	      illegal1 += 1-mesh.LegalTrig(el);
+	    }
+	  bad1 /= (hasonepi.Size()+hasbothpi.Size());
+
+	  p1 = mesh[pi1];
+	  p2 = mesh[pi2];
+
+	  pnew = p1;
+	  mesh[pi1] = pnew;
+	  mesh[pi2] = pnew;
+
+	  bad2 = 0;
+	  for (k = 0; k < hasonepi.Size(); k++)
+	    {
+	      Element2d & el = mesh[hasonepi[k]];
+	      double err = 
+		CalcTriangleBadness (mesh[el[0]], mesh[el[1]], mesh[el[2]],
+				     nv, -1, loch);
+	      bad2 += err;
+
+	      Vec3d hnv = Cross (Vec3d (mesh[el[0]],
+					mesh[el[1]]),
+				 Vec3d (mesh[el[0]],
+					mesh[el[2]]));
+	      if (hnv * nv < 0)
+		bad2 += 1e10;
+
+	      for (l = 0; l < 3; l++)
+		if ( (normals[el[l]] * nv) < 0.5)
+		  bad2 += 1e10;
+
+	      illegal2 += 1-mesh.LegalTrig(el);
+	    }
+	  bad2 /= hasonepi.Size();
+
+	  mesh[pi1] = p1;
+	  mesh[pi2] = p2;
+	  
+	  if (debugflag)
+	    {
+	      (*testout) << "bad1 = " << bad1 << ", bad2 = " << bad2 << endl;
+	    }
+
+
+	  bool should = (bad2 < bad1 && bad2 < 1e4);
+	  if (bad2 < 1e4)
+	    {
+	      if (illegal1 > illegal2) should = 1;
+	      if (illegal2 > illegal1) should = 0;
+	    }
+	  
+
+	  if (should)
+	    {
+	      // (*testout) << "combine !" << endl;
+	      // (*testout) << "bad1 = " << bad1 << ", bad2 = " << bad2 << endl;
+
+
+	      mesh[pi1] = pnew;
+	      PointGeomInfo gi;
+	      
+	      Element2d & el1 = mesh[elementsonnode[pi1][0]];
+	      for (l = 0; l < el1.GetNP(); l++)
+		if (el1[l] == pi1)
+		  gi = el1.GeomInfoPi (l+1);
+		  
+
+	      // (*testout) << "Connect point " << pi2 << " to " << pi1 << "\n";
+	      for (k = 0; k < elementsonnode[pi2].Size(); k++)
+		{
+		  Element2d & el = mesh[elementsonnode[pi2][k]];
+		  elementsonnode.Add (pi1, elementsonnode[pi2][k]);
+
+		  bool haspi1 = 0;
+		  for (l = 0; l < el.GetNP(); l++)
+		    if (el[l] == pi1)
+		      haspi1 = 1;
+		  if (haspi1) continue;
+
+		  for (l = 0; l < el.GetNP(); l++)
+		    {
+		      if (el[l] == pi2)
+			{
+			  el[l] = pi1;
+			  el.GeomInfoPi (l+1) = gi;
+			}
+
+		      fixed[el[l]] = 1;
+		    }
+		}
+
+	      /*
+	      for (k = 0; k < hasbothpi.Size(); k++)
+		{
+		  cout << mesh[hasbothpi[k]] << endl;
+		  for (l = 0; l < 3; l++)
+		    cout << mesh[mesh[hasbothpi[k]][l]] << " ";
+		  cout << endl;
+		}
+	      */
+
+	      for (k = 0; k < hasbothpi.Size(); k++)
+		{
+		  mesh[hasbothpi[k]].Delete();
+		  /*
+		  for (l = 0; l < 4; l++)
+		    mesh[hasbothpi[k]][l] = PointIndex::BASE-1;
+		  */
+		}
+	    }
+	}
+    }
+
+  //  mesh.Compress();
+  mesh.SetNextTimeStamp();
+}
+
+
+void MeshOptimize2d :: CheckMeshApproximation (Mesh & mesh)
+{
+  // Check angles between elements and normals at corners
+  /*
+  
+  int i, j;
+  int ne = mesh.GetNSE();
+  int surfnr;
+  
+  Vec3d n, ng;
+  ARRAY<Vec3d> ngs(3);
+
+  (*mycout) << "Check Surface Approxiamtion" << endl;
+  (*testout) << "Check Surface Approxiamtion" << endl;
+
+  for (i = 1; i <= ne; i++)
+    {
+      const Element2d & el = mesh.SurfaceElement(i);
+      surfnr = mesh.GetFaceDescriptor (el.GetIndex()).SurfNr();
+      Vec3d n = Cross (mesh.Point (el.PNum(1)) - mesh.Point (el.PNum(2)),
+		       mesh.Point (el.PNum(1)) - mesh.Point (el.PNum(3)));
+      n /= n.Length();
+
+      for (j = 1; j <= el.GetNP(); j++)
+	{
+	  SelectSurfaceOfPoint (mesh.Point(el.PNum(j)), el.GeomInfoPi(j));
+	  GetNormalVector (surfnr, mesh.Point(el.PNum(j)), ng);
+	  ng /= ng.Length();
+	  ngs.Elem(j) = ng;
+
+	  double angle =  (180.0 / M_PI) * Angle (n, ng);
+	  if (angle > 60)
+	    {
+	      (*testout) << "el " << i << " node " << el.PNum(j)
+			 << "has angle = " << angle << endl;
+	    }
+	}	
+
+      for (j = 1; j <= 3; j++)
+	{
+	  double angle =  (180.0 / M_PI) * Angle (ngs.Get(j), ngs.Get(j%3+1));
+	  if (angle > 60)
+	    {
+	      (*testout) << "el " << i << " node-node " 
+			 << ngs.Get(j) << " - " << ngs.Get(j%3+1)
+			 << " has angle = " << angle << endl;
+	    }
+	}
+    }
+  */
+}
+}
diff --git a/Netgen/libsrc/meshing/improve2.hpp b/Netgen/libsrc/meshing/improve2.hpp
new file mode 100644
index 0000000000..39cd1be018
--- /dev/null
+++ b/Netgen/libsrc/meshing/improve2.hpp
@@ -0,0 +1,91 @@
+#ifndef FILE_IMPROVE2
+#define FILE_IMPROVE2
+
+
+
+///
+class MeshOptimize2d
+{
+  int faceindex;
+  int improveedges;
+  double metricweight;
+  int writestatus;
+
+public:
+  ///
+  MeshOptimize2d ();
+  ///
+  void ImproveMesh (Mesh & mesh2d);
+  void ImproveMeshJacobian (Mesh & mesh2d);
+    
+  void EdgeSwapping (Mesh & mesh, int usemetric);
+  void CombineImprove (Mesh & mesh);
+
+  void GenericImprove (Mesh & mesh);
+
+
+  void SetFaceIndex (int fi) { faceindex = fi; }
+  void SetImproveEdges (int ie) { improveedges = ie; }
+  void SetMetricWeight (double mw) { metricweight = mw; }
+  void SetWriteStatus (int ws) { writestatus = ws; }
+
+  ///
+  virtual void SelectSurfaceOfPoint (const Point3d & p,
+				     const PointGeomInfo & gi);
+  ///
+  virtual void ProjectPoint (INDEX /* surfind */, Point3d & /* p */) const { };
+  ///
+  virtual void ProjectPoint2 (INDEX /* surfind */, INDEX /* surfind2 */, Point3d & /* p */) const { };
+  /// liefert zu einem 3d-Punkt die geominfo (Dreieck) und liefert 1, wenn erfolgreich, 
+  /// 0, wenn nicht (Punkt ausserhalb von chart)
+  virtual int CalcPointGeomInfo(PointGeomInfo& gi, const Point3d& /*p3*/) const
+    { gi.trignum = 1; return 1;};
+
+  virtual int CalcPointGeomInfo(int surfind, PointGeomInfo& gi, const Point3d& p3) const
+    { return CalcPointGeomInfo (gi, p3); }
+
+  ///
+  virtual void GetNormalVector(INDEX surfind, const Point3d & p, PointGeomInfo & gi, Vec3d & n) const;
+  virtual void GetNormalVector(INDEX surfind, const Point3d & p, Vec3d & n) const;
+
+  void CheckMeshApproximation (Mesh & mesh);
+
+
+  ///
+  friend class Opti2SurfaceMinFunction;
+  ///
+  friend class Opti2EdgeMinFunction;
+  ///
+  friend double Opti2FunctionValueGrad (const Vector & x, Vector & grad);
+  ///
+  friend double Opti2EdgeFunctionValueGrad (const Vector & x, Vector & grad);
+
+
+
+};
+
+
+extern void CalcTriangleBadness (double x2, double x3, double y3, 
+				 double metricweight,
+				 double h, double & badness, 
+				 double & g1x, double & g1y);
+
+
+
+
+extern double CalcTriangleBadness (const Point3d & p1, 
+				   const Point3d & p2, 
+				   const Point3d & p3,
+				   double metricweight,
+				   double h);
+
+extern double CalcTriangleBadness (const Point3d & p1, 
+				   const Point3d & p2, 
+				   const Point3d & p3,
+				   const Vec3d & n,
+				   double metricweight,
+				   double h);
+
+#endif
+
+
diff --git a/Netgen/libsrc/meshing/improve2gen.cpp b/Netgen/libsrc/meshing/improve2gen.cpp
new file mode 100644
index 0000000000..40291575f5
--- /dev/null
+++ b/Netgen/libsrc/meshing/improve2gen.cpp
@@ -0,0 +1,465 @@
+#include <mystdlib.h>
+
+#include "meshing.hpp"
+#include <opti.hpp>
+
+namespace netgen
+{
+
+  class ImprovementRule
+  {
+  public:
+    ARRAY<Element2d> oldels;
+    ARRAY<Element2d> newels;
+    ARRAY<int> incelsonnode;
+    ARRAY<int> reused;
+    int bonus;
+    int onp;
+  };
+
+
+  void MeshOptimize2d :: GenericImprove (Mesh & mesh)
+  {
+    if (!faceindex)
+      {
+	if (writestatus)
+	  PrintMessage (3, "Generic Improve");
+
+	for (faceindex = 1; faceindex <= mesh.GetNFD(); faceindex++)
+	  GenericImprove (mesh);
+      
+	faceindex = 0;
+      }
+
+    int j, k, l, ri;
+    int np = mesh.GetNP();
+    int ne = mesh.GetNSE();
+    SurfaceElementIndex sei;
+
+    bool ok;
+    int olddef, newdef;
+
+    ARRAY<ImprovementRule*> rules;
+    ARRAY<SurfaceElementIndex> elmap;
+    ARRAY<int> elrot;
+    ARRAY<PointIndex> pmap;
+    ARRAY<PointGeomInfo> pgi;
+
+    int surfnr = mesh.GetFaceDescriptor (faceindex).SurfNr();
+  
+    ImprovementRule * r1;
+
+    // 2 triangles to quad
+    r1 = new ImprovementRule;
+    r1->oldels.Append (Element2d (1, 2, 3));
+    r1->oldels.Append (Element2d (3, 2, 4));
+    r1->newels.Append (Element2d (1, 2, 4, 3));
+    r1->onp = 4;
+    r1->bonus = 2;
+    rules.Append (r1);
+
+    // 2 quad to 1 quad
+    r1 = new ImprovementRule;
+    r1->oldels.Append (Element2d (1, 2, 3, 4));
+    r1->oldels.Append (Element2d (4, 3, 2, 5));
+    r1->newels.Append (Element2d (1, 2, 5, 4));
+    r1->onp = 5;
+    r1->bonus = 0;
+    rules.Append (r1);
+
+    // swap quads
+    r1 = new ImprovementRule;
+    r1->oldels.Append (Element2d (1, 2, 3, 4));
+    r1->oldels.Append (Element2d (3, 2, 5, 6));
+    r1->newels.Append (Element2d (1, 6, 3, 4));
+    r1->newels.Append (Element2d (1, 2, 5, 6));
+    r1->onp = 6;
+    r1->bonus = 0;
+    rules.Append (r1);
+
+    // three quads to 2
+    r1 = new ImprovementRule;
+    r1->oldels.Append (Element2d (1, 2, 3, 4));
+    r1->oldels.Append (Element2d (2, 5, 6, 3));
+    r1->oldels.Append (Element2d (3, 6, 7, 4));
+    r1->newels.Append (Element2d (1, 2, 5, 4));
+    r1->newels.Append (Element2d (4, 5, 6, 7));
+    r1->onp = 7;
+    r1->bonus = -1;
+    rules.Append (r1);
+
+    // quad + 2 connected trigs to quad
+    r1 = new ImprovementRule;
+    r1->oldels.Append (Element2d (1, 2, 3, 4));
+    r1->oldels.Append (Element2d (2, 5, 3));
+    r1->oldels.Append (Element2d (3, 5, 4));
+    r1->newels.Append (Element2d (1, 2, 5, 4));
+    r1->onp = 5;
+    r1->bonus = 0;
+    rules.Append (r1);
+
+    // quad + 2 non-connected trigs to quad (a and b)
+    r1 = new ImprovementRule;
+    r1->oldels.Append (Element2d (1, 2, 3, 4));
+    r1->oldels.Append (Element2d (2, 6, 3));
+    r1->oldels.Append (Element2d (1, 4, 5));
+    r1->newels.Append (Element2d (1, 3, 4, 5));
+    r1->newels.Append (Element2d (1, 2, 6, 3));
+    r1->onp = 6;
+    r1->bonus = 0;
+    rules.Append (r1);
+
+    r1 = new ImprovementRule;
+    r1->oldels.Append (Element2d (1, 2, 3, 4));
+    r1->oldels.Append (Element2d (2, 6, 3));
+    r1->oldels.Append (Element2d (1, 4, 5));
+    r1->newels.Append (Element2d (1, 2, 4, 5));
+    r1->newels.Append (Element2d (4, 2, 6, 3));
+    r1->onp = 6;
+    r1->bonus = 0;
+    rules.Append (r1);
+
+    // two quad + trig -> one quad + trig
+    r1 = new ImprovementRule;
+    r1->oldels.Append (Element2d (1, 2, 3, 4));
+    r1->oldels.Append (Element2d (2, 5, 6, 3));
+    r1->oldels.Append (Element2d (4, 3, 6));
+    r1->newels.Append (Element2d (1, 2, 6, 4));
+    r1->newels.Append (Element2d (2, 5, 6));
+    r1->onp = 6;
+    r1->bonus = -1;
+    rules.Append (r1);
+
+    // swap quad + trig (a and b)
+    r1 = new ImprovementRule;
+    r1->oldels.Append (Element2d (1, 2, 3, 4));
+    r1->oldels.Append (Element2d (2, 5, 3));
+    r1->newels.Append (Element2d (2, 5, 3, 4));
+    r1->newels.Append (Element2d (1, 2, 4));
+    r1->onp = 5;
+    r1->bonus = 0;
+    rules.Append (r1);
+
+    r1 = new ImprovementRule;
+    r1->oldels.Append (Element2d (1, 2, 3, 4));
+    r1->oldels.Append (Element2d (2, 5, 3));
+    r1->newels.Append (Element2d (1, 2, 5, 3));
+    r1->newels.Append (Element2d (1, 3, 4));
+    r1->onp = 5;
+    r1->bonus = 0;
+    rules.Append (r1);
+
+
+
+
+    ARRAY<int> mapped(rules.Size());
+    ARRAY<int> used(rules.Size());
+    used = 0;
+    mapped = 0;
+
+  
+
+    for (ri = 0; ri < rules.Size(); ri++)
+      {
+	ImprovementRule & rule = *rules[ri];
+	rule.incelsonnode.SetSize (rule.onp);
+	rule.reused.SetSize (rule.onp);
+
+	for (j = 1; j <= rule.onp; j++)
+	  {
+	    rule.incelsonnode.Elem(j) = 0;
+	    rule.reused.Elem(j) = 0;
+	  }
+
+	for (j = 1; j <= rule.oldels.Size(); j++)
+	  {
+	    const Element2d & el = rule.oldels.Elem(j);
+	    for (k = 1; k <= el.GetNP(); k++)
+	      rule.incelsonnode.Elem(el.PNum(k))--;
+	  }
+
+	for (j = 1; j <= rule.newels.Size(); j++)
+	  {
+	    const Element2d & el = rule.newels.Elem(j);
+	    for (k = 1; k <= el.GetNP(); k++)
+	      {
+		rule.incelsonnode.Elem(el.PNum(k))++;
+		rule.reused.Elem(el.PNum(k)) = 1;
+	      }
+	  }
+      }
+
+
+
+  
+    TABLE<int,PointIndex::BASE> elonnode(np);
+    ARRAY<int,PointIndex::BASE> nelonnode(np);
+    TABLE<int> nbels(ne);
+
+    nelonnode = -4;
+
+    for (sei = 0; sei < ne; sei++)
+      {
+	const Element2d & el = mesh[sei];
+	if (el.GetIndex() == faceindex)
+	  {
+	    for (j = 0; j < el.GetNP(); j++)
+	      elonnode.Add (el[j], sei);
+	  }
+	for (j = 0; j < el.GetNP(); j++)
+	  nelonnode[el[j]]++;
+      }
+
+    for (sei = 0; sei < ne; sei++)
+      {
+	const Element2d & el = mesh[sei];
+	if (el.GetIndex() == faceindex)
+	  {
+	    for (j = 0; j < el.GetNP(); j++)
+	      {
+		for (k = 0; k < elonnode[el[j]].Size(); k++)
+		  {
+		    int nbel = elonnode[el[j]] [k];
+		    int used = 0;
+		    for (l = 0; l < nbels[sei].Size(); l++)
+		      if (nbels[sei][l] == nbel)
+			used = 1;
+		    if (!used)
+		      nbels.Add (sei, nbel);
+		  }
+	      }
+	  }
+      }
+
+
+    for (ri = 0; ri < rules.Size(); ri++)
+      {
+	const ImprovementRule & rule = *rules[ri];
+      
+	elmap.SetSize (rule.oldels.Size());
+	elrot.SetSize (rule.oldels.Size());
+	pmap.SetSize (rule.onp);
+	pgi.SetSize (rule.onp);
+
+
+	// loop over elements and rotations:
+	/*
+	  int nt = int (pow (ne, elmap.Size()));
+	  for (i = 1; i <= nt; i++)
+	  {
+	  int hi = i-1;
+	  for (j = 1; j <= elmap.Size(); j++)
+	  {
+	  elmap.Elem (j) = hi % ne + 1;
+	  hi /= ne;
+	  }
+	*/
+
+	for (sei = 0; sei < ne; sei++)
+	  {
+	    if (multithread.terminate)
+	      break;
+
+	    elmap[0] = sei;
+
+	    int nnb = nbels[sei].Size();
+	    int nt = int (pow (double(nnb), double(elmap.Size()-1)));
+
+	    for (int i = 1; i <= nt; i++)
+	      {
+		int hi = i-1;
+		for (j = 1; j < elmap.Size(); j++)
+		  {
+		    elmap[j] = nbels[sei][hi % nnb];
+		    hi /= nnb;
+		  }
+
+		ok = 1;
+		for (j = 0; j < elmap.Size(); j++)
+		  {
+		    const Element2d & el = mesh.SurfaceElement(elmap[j]);
+		    const Element2d & rel = rule.oldels[j];
+		   
+		    if (el.GetNP() != rel.GetNP()) { ok = 0; break; }
+		    if (el.IsDeleted()) { ok = 0; break; }
+		  }
+		
+		if (!ok) continue;
+
+
+		int nr = int (pow (4.0, elmap.Size()));
+		for (int i2 = 1; i2 <= nr; i2++)
+		  {
+		    int hi2 = i2-1;
+		    for (j = 1; j <= elmap.Size(); j++)
+		      {
+			elrot.Elem (j) = hi2 % 4 + 1;
+			hi2 /= 4;
+		      }
+		  
+		  
+		    // check applicable 
+		  
+		    ok = 1;
+
+		    // set mapped points
+		    for (j = 1; j <= elmap.Size(); j++)
+		      {
+			const Element2d & el = mesh.SurfaceElement(elmap.Get(j));
+			const Element2d & rel = rule.oldels.Get(j);
+		      
+			/*
+			if (el.GetNP() != rel.GetNP())
+			  {
+			    ok = 0; 
+			    break;
+			  }
+			*/
+
+			for (k = 1; k <= el.GetNP(); k++)
+			  {
+			    /*
+			    if (el.PNum(k) < PointIndex::BASE)
+			      {
+				ok = 0;
+				break;
+			      }
+			    */
+			    pmap.Elem(rel.PNum(k)) =
+			      el.PNumMod(k+elrot.Get(j));
+			    pgi.Elem(rel.PNum(k)) = 
+			      el.GeomInfoPiMod(k+elrot.Get(j));
+			  }
+		      }
+		    if (!ok) continue;
+
+		    /*
+		      (*testout) << "candidates found: " << endl;
+		      for (j = 1; j <= elmap.Size(); j++)
+		      {
+		      const Element2d & el = mesh.SurfaceElement(elmap.Get(j));
+		      (*testout) << "el " << elmap.Get(j) 
+		      << ", rot = " << elrot.Get(j) << " "
+		      << el << endl;
+		      }
+		    */
+		  
+	      
+		    // check consistently mapped points:
+		    for (j = 1; j <= elmap.Size(); j++)
+		      {
+			const Element2d & el = mesh.SurfaceElement(elmap.Get(j));
+			const Element2d & rel = rule.oldels.Get(j);
+		      
+			for (k = 1; k <= el.GetNP(); k++)
+			  {
+			    if (pmap.Elem(rel.PNum(k)) != el.PNumMod(k+elrot.Get(j)))
+			      ok = 0;
+			  }
+		      }  
+
+		    if (!ok) continue;
+
+		  
+		    mapped[ri]++;
+		  
+		    /*
+		      (*testout) << "application found: " << endl;
+		      for (j = 1; j <= elmap.Size(); j++)
+		      {
+		      const Element2d & el = mesh.SurfaceElement(elmap.Get(j));
+		      (*testout) << "el " << elmap.Get(j) 
+		      << ", rot = " << elrot.Get(j) << " "
+		      << el << endl;
+		      }
+		      (*testout) << "points:";
+		      for (j = 1; j <= pmap.Size(); j++)
+		      (*testout) << " " << pmap.Get(j);
+		      (*testout) << endl;
+		    */
+
+		    olddef = 0;
+		    for (j = 1; j <= pmap.Size(); j++)
+		      olddef += sqr (nelonnode[pmap.Get(j)]);
+		    olddef += rule.bonus;
+
+		    newdef = 0;
+		    for (j = 1; j <= pmap.Size(); j++)
+		      if (rule.reused.Get(j))
+			newdef += sqr (nelonnode[pmap.Get(j)] + 
+				       rule.incelsonnode.Get(j));
+
+		    if (newdef > olddef)
+		      continue;
+
+		    // calc metric badness
+		    double bad1 = 0, bad2 = 0;
+		    Vec3d n;
+
+		    SelectSurfaceOfPoint (mesh.Point(pmap.Get(1)), pgi.Get(1));
+		    GetNormalVector (surfnr, mesh.Point(pmap.Get(1)), pgi.Elem(1), n);
+		  
+		    for (j = 1; j <= rule.oldels.Size(); j++)
+		      bad1 += mesh.SurfaceElement(elmap.Get(j)).CalcJacobianBadness (mesh.Points(), n);
+		  
+		    // check new element:
+		    for (j = 1; j <= rule.newels.Size(); j++)
+		      {
+			const Element2d & rnel = rule.newels.Get(j);
+			Element2d nel(rnel.GetNP());
+			for (k = 1; k <= rnel.GetNP(); k++)
+			  nel.PNum(k) = pmap.Get(rnel.PNum(k));
+
+			bad2 += nel.CalcJacobianBadness (mesh.Points(), n);
+		      }
+
+		    if (bad2 > 1e3) continue;
+
+		    if (newdef == olddef && bad2 > bad1) continue;
+		  
+	  
+		    // generate new element:
+		    for (j = 1; j <= rule.newels.Size(); j++)
+		      {
+			const Element2d & rnel = rule.newels.Get(j);
+			Element2d nel(rnel.GetNP());
+			nel.SetIndex (faceindex);
+			for (k = 1; k <= rnel.GetNP(); k++)
+			  {
+			    nel.PNum(k) = pmap.Get(rnel.PNum(k));
+			    nel.GeomInfoPi(k) = pgi.Get(rnel.PNum(k));
+			  }
+		      
+			mesh.AddSurfaceElement(nel);
+		      }
+		  
+		    for (j = 1; j <= rule.oldels.Size(); j++)
+		      mesh.DeleteSurfaceElement (elmap.Get(j));
+
+		    for (j = 1; j <= pmap.Size(); j++)
+		      nelonnode[pmap.Get(j)] += rule.incelsonnode.Get(j);
+
+		    used[ri]++;
+		    break;
+		  }
+	      }
+	  }
+      }
+
+    mesh.Compress();
+
+    for (ri = 0; ri < rules.Size(); ri++)
+      {
+	PrintMessage (5, "rule ", ri+1, " ",
+		      mapped[ri], "/", used[ri], " mapped/used");
+      }
+
+    int sum = 0;
+    for (int i = 0; i < used.Size(); i++)
+      sum += used[i];
+  }
+
+
+
+
+}
diff --git a/Netgen/libsrc/meshing/improve3.cpp b/Netgen/libsrc/meshing/improve3.cpp
new file mode 100644
index 0000000000..625abaef65
--- /dev/null
+++ b/Netgen/libsrc/meshing/improve3.cpp
@@ -0,0 +1,1950 @@
+#include <mystdlib.h>
+
+#include "meshing.hpp"
+
+#ifdef SOLIDGEOM
+#include <csg.hpp>
+#endif
+#include <opti.hpp>
+
+namespace netgen
+{
+
+/*
+  Combine two points to one.
+  Set new point into the center, if both are
+  inner points.
+  Connect inner point to boundary point, if one
+  point is inner point.
+*/
+
+void MeshOptimize3d :: CombineImprove (Mesh & mesh,
+				       OPTIMIZEGOAL goal)
+{
+  int j, k, l;
+
+  ElementIndex ei;
+  PointIndex pi1, pi2;
+
+  Point3d p1, p2, pnew;
+
+  double bad1, bad2;
+  
+  int np = mesh.GetNP();
+  int ne = mesh.GetNE();
+
+  TABLE<ElementIndex, PointIndex::BASE> elementsonnode(np); 
+  ARRAY<Element*> hasonepoint;
+  ARRAY<Element*> hasbothpoints;
+
+  ARRAY<ElementIndex> hasonepi, hasbothpi;
+
+  ARRAY<double> oneperr;
+  ARRAY<double> elerrs (ne);
+
+  PrintMessage (3, "CombineImprove");
+  (*testout)  << "Start CombineImprove" << "\n";
+
+  //  mesh.CalcSurfacesOfNode ();
+
+  char * savetask = multithread.task;
+  multithread.task = "Combine Improve";
+
+  int cnt = 0;
+
+  bad1 = 0;
+  for (ei = 0; ei < ne; ei++)
+    {
+      double elerr = CalcBad (mesh.Points(), mesh[ei], 0);
+      bad1 += elerr;
+      elerrs[ei] = elerr;
+    }
+
+  if (goal == OPT_QUALITY)
+    {
+      bad1 = CalcTotalBad (mesh.Points(), mesh.VolumeElements());
+      (*testout) << "Total badness = " << bad1 << endl;
+      PrintMessage (5, "Total badness = ", bad1);
+    }
+
+  for (ei = 0; ei < ne; ei++)
+    for (j = 0; j < mesh[ei].GetNP(); j++)
+      elementsonnode.Add (mesh[ei][j], ei);
+  
+  INDEX_2_HASHTABLE<int> edgetested (np);
+
+
+  for (ei = 0; ei < ne; ei++)
+    {
+      if (multithread.terminate)
+	break;
+      
+      multithread.percent = 100.0 * (ei+1) / ne;
+
+      if (mesh.ElementType(ei) == FIXEDELEMENT)
+	continue;
+
+      for (j = 0; j < 6; j++)
+	{
+	  Element & elemi = mesh[ei];
+	  if (elemi.IsDeleted()) continue;
+	  
+	  static const int tetedges[6][2] =
+	    { { 0, 1 }, { 0, 2 }, { 0, 3 },
+	      { 1, 2 }, { 1, 3 }, { 2, 3 } };
+
+	  pi1 = elemi[tetedges[j][0]];
+	  pi2 = elemi[tetedges[j][1]];
+
+	  if (pi2 < pi1) Swap (pi1, pi2);
+	  
+	  INDEX_2 si2 (pi1, pi2);
+	  si2.Sort();
+	  
+	  if (edgetested.Used (si2)) continue;
+	  edgetested.Set (si2, 1);
+
+
+	  hasonepoint.SetSize(0);
+	  hasbothpoints.SetSize(0);
+	  hasonepi.SetSize(0);
+	  hasbothpi.SetSize(0);
+
+	  FlatArray<ElementIndex> row1 = elementsonnode[pi1];
+	  for (k = 0; k < row1.Size(); k++)
+	    {
+	      Element & elem = mesh[row1[k]];
+	      if (elem.IsDeleted()) continue;
+
+	      if (elem[0] == pi2 || elem[1] == pi2 ||
+		  elem[2] == pi2 || elem[3] == pi2)
+		{
+		  hasbothpoints.Append (&elem);
+		  hasbothpi.Append (row1[k]);
+		}
+	      else
+		{
+		  hasonepoint.Append (&elem);    
+		  hasonepi.Append (row1[k]);
+		}
+	    } 
+	  
+	  FlatArray<ElementIndex> row2 = elementsonnode[pi2];	  
+	  for (k = 0; k < row2.Size(); k++)
+	    {
+	      Element & elem = mesh[row2[k]];
+	      if (elem.IsDeleted()) continue;
+
+	      if (elem[0] == pi1 || elem[1] == pi1 ||
+		  elem[2] == pi1 || elem[3] == pi1)
+		;
+	      else
+		{
+		  hasonepoint.Append (&elem);    
+		  hasonepi.Append (row2[k]);
+		}
+	    } 
+	  
+	  bad1 = 0;
+	  for (k = 0; k < hasonepoint.Size(); k++)
+	    bad1 += elerrs[hasonepi[k]];
+	  
+	  for (k = 0; k < hasbothpoints.Size(); k++)
+	    bad1 += elerrs[hasbothpi[k]];
+	  
+	  p1 = mesh[pi1];
+	  p2 = mesh[pi2];
+	  
+	  if (mesh.PointType(pi2) != INNERPOINT)
+	    continue;
+	  
+	  if (mesh.PointType(pi1) != INNERPOINT)
+	    pnew = p1;
+	  else
+	    pnew = Center (p1, p2);
+	  
+	  mesh[pi1] = pnew;
+	  mesh[pi2] = pnew;
+
+	  oneperr.SetSize (hasonepoint.Size());
+	  bad2 = 0;
+	  for (k = 0; k < hasonepoint.Size(); k++)
+	    {
+	      const Element & elem = *hasonepoint[k];
+	      double err = CalcTetBadness (mesh[elem[0]], mesh[elem[1]],  
+					   mesh[elem[2]], mesh[elem[3]], 0);
+	      bad2 += err;
+	      oneperr[k] = err;
+	    }
+	  
+	  mesh[pi1] = p1;
+	  mesh[pi2] = p2;
+
+
+	  if (mesh.PointType(pi1) != INNERPOINT)
+	    {
+	      for (k = 0; k < hasonepoint.Size(); k++)
+		{
+		  Element & elem = *hasonepoint[k];
+		  for (l = 0; l < 4; l++)
+		    if (elem[l] == pi2)
+		      {
+			elem[l] = pi1;
+			break;
+		      }
+		  
+		  elem.flags.illegal_valid = 0;
+		  if (!mesh.LegalTet(elem))
+		    bad2 += 1e4;
+
+		  if (l < 4)
+		    {
+		      elem.flags.illegal_valid = 0;
+		      elem[l] = pi2;
+		    }
+		}
+	    }
+
+	  if (bad2 / hasonepoint.Size()  < 
+	      bad1 / (hasonepoint.Size()+hasbothpoints.Size())  )
+	    {
+	      mesh[pi1] = pnew;
+	      cnt++;
+
+	      FlatArray<ElementIndex> row = elementsonnode[pi2];
+	      for (k = 0; k < row.Size(); k++)
+		{
+		  Element & elem = mesh[row[k]];
+		  elementsonnode.Add (pi1, row[k]);
+		  for (l = 0; l < elem.GetNP(); l++)
+		    if (elem[l] == pi2)
+		      elem[l] = pi1;
+		  
+		  elem.flags.illegal_valid = 0;
+		  if (!mesh.LegalTet (elem))
+		    (*testout) << "illegal tet " << elementsonnode.Get (pi2, k) << endl;
+		}
+
+	      for (k = 0; k < hasonepoint.Size(); k++)
+		elerrs[hasonepi[k]] = oneperr[k];
+	      
+	      for (k = 0; k < hasbothpoints.Size(); k++)
+		{
+		  hasbothpoints[k] -> flags.illegal_valid = 0;
+		  hasbothpoints[k] -> Delete();
+		}
+	    }
+	}
+    }
+
+  mesh.Compress();
+  mesh.MarkIllegalElements();
+
+  PrintMessage (5, cnt, " elements combined");
+  (*testout) << "CombineImprove done" << "\n";
+
+  bad1 = 0;
+  for (ei = 0; ei < mesh.GetNE(); ei++)
+    bad1 += CalcBad (mesh.Points(), mesh[ei], 0);
+
+  if (goal == OPT_QUALITY)
+    {
+      bad1 = CalcTotalBad (mesh.Points(), mesh.VolumeElements());
+      (*testout) << "Total badness = " << bad1 << endl;
+
+      int cntill = 0;
+      int ne = mesh.GetNE();
+      for (ei = 0; ei < ne; ei++)
+	if (!mesh.LegalTet (mesh[ei]))
+	  cntill++;
+
+      PrintMessage (5, cntill, " illegal tets");
+    }
+  multithread.task = savetask;
+} 
+
+
+
+
+
+/*
+  Mesh improvement by edge splitting.
+  If mesh quality is improved by inserting a node into an inner edge,
+  the edge is split into two parts.
+*/
+void MeshOptimize3d :: SplitImprove (Mesh & mesh,
+				     OPTIMIZEGOAL goal)
+{
+  int j, k, l;
+  Point3d p1, p2, pnew;
+
+  ElementIndex ei;
+  SurfaceElementIndex sei;
+  PointIndex pi1, pi2;
+
+  double bad1, bad2, badmax, badlimit;
+
+
+  int cnt = 0;
+  int np = mesh.GetNP();
+  int ne = mesh.GetNE();
+
+  TABLE<ElementIndex,PointIndex::BASE> elementsonnode(np); 
+  ARRAY<ElementIndex> hasbothpoints;
+
+  BitArray origpoint(np), boundp(np);
+  origpoint.Set();
+
+  ARRAY<double> elerrs(ne);
+  BitArray illegaltet(ne);
+  illegaltet.Clear();
+
+  char * savetask = multithread.task;
+  multithread.task = "Split Improve";
+
+
+  PrintMessage (3, "SplitImprove");
+  (*testout)  << "start SplitImprove" << "\n";
+
+  ARRAY<INDEX_3> locfaces;
+
+  INDEX_2_HASHTABLE<int> edgetested (np);
+
+  bad1 = 0;
+  badmax = 0;
+  for (ei = 0; ei < ne; ei++)
+    {
+      elerrs[ei] = CalcBad (mesh.Points(), mesh[ei], 0);
+      bad1 += elerrs[ei];
+      if (elerrs[ei] > badmax) badmax = elerrs[ei];
+    }
+
+  PrintMessage (5, "badmax = ", badmax);
+  badlimit = 0.5 * badmax;
+
+
+  boundp.Clear();
+  for (sei = 0; sei < mesh.GetNSE(); sei++)
+    for (j = 0; j < 3; j++)
+      boundp.Set (mesh[sei][j]);
+
+  if (goal == OPT_QUALITY)
+    {
+      bad1 = CalcTotalBad (mesh.Points(), mesh.VolumeElements());
+      (*testout) << "Total badness = " << bad1 << endl;
+    }
+
+  for (ei = 0; ei < ne; ei++)
+    for (j = 0; j < mesh[ei].GetNP(); j++)
+      elementsonnode.Add (mesh[ei][j], ei);
+
+
+  mesh.MarkIllegalElements();
+  if (goal == OPT_QUALITY || goal == OPT_LEGAL)
+    {
+      int cntill = 0;
+      for (ei = 0; ei < ne; ei++)
+	{
+	  //	  if (!LegalTet (volelements.Get(i)))
+	  if (mesh[ei].flags.illegal)
+	    {
+	      cntill++;
+	      illegaltet.Set (ei+1);
+	    }
+	}
+      //      (*mycout) << cntill << " illegal tets" << endl;
+    }
+
+
+  for (ei = 0; ei < ne; ei++)
+    {
+      if (multithread.terminate)
+	break;
+
+      multithread.percent = 100.0 * (ei+1) / ne;
+
+      bool ltestmode = 0;
+
+
+      if (elerrs[ei] < badlimit && !illegaltet.Test(ei+1)) continue;
+
+      if ((goal == OPT_LEGAL) &&
+	  !illegaltet.Test(ei+1) &&
+	  CalcBad (mesh.Points(), mesh[ei], 0) < 1e3) 
+	continue;
+
+      
+      Element & elem = mesh[ei];
+
+      if (ltestmode)
+	{
+	  (*testout) << "test el " << ei << endl;
+	  for (j = 0; j < 4; j++)
+	    (*testout) << elem[j] << " ";
+	  (*testout) << endl;
+	}
+
+
+      for (j = 0; j < 6; j++)
+	{
+
+	  static const int tetedges[6][2] =
+	    { { 0, 1 }, { 0, 2 }, { 0, 3 },
+	      { 1, 2 }, { 1, 3 }, { 2, 3 } };
+
+	  pi1 = elem[tetedges[j][0]];
+	  pi2 = elem[tetedges[j][1]];
+
+	  if (pi2 < pi1) Swap (pi1, pi2);
+	  if (pi2 > elementsonnode.Size()) continue;
+
+	  if (!origpoint.Test(pi1) || !origpoint.Test(pi2))
+	    continue;
+
+  
+	  INDEX_2 i2(pi1, pi2);
+	  i2.Sort();
+
+	  if (mesh.BoundaryEdge (pi1, pi2)) continue;
+
+	  if (edgetested.Used (i2) && !illegaltet.Test(ei+1)) continue;
+	  edgetested.Set (i2, 1);
+
+	  hasbothpoints.SetSize (0);
+	  for (k = 1; k <= elementsonnode.EntrySize(pi1); k++)
+	    {
+	      bool has1 = 0, has2 = 0;
+
+	      ElementIndex elnr = elementsonnode.Get(pi1, k);
+	      Element & el = mesh[elnr];
+
+	      for (l = 0; l < el.GetNP(); l++)
+		{
+		  if (el[l] == pi1) has1 = 1;
+		  if (el[l] == pi2) has2 = 1;
+		}
+	      if (has1 && has2) 
+		{ // only once
+		  for (l = 0; l < hasbothpoints.Size(); l++)
+		    if (hasbothpoints[l] == elnr)
+		      has1 = 0;
+		  
+		  if (has1)
+		    hasbothpoints.Append (elnr);
+		}
+	    }
+	  
+	  bad1 = 0;
+	  for (k = 0; k < hasbothpoints.Size(); k++)
+	    bad1 += CalcBad (mesh.Points(), mesh[hasbothpoints[k]], 0);
+	  
+
+	  bool puretet = 1;
+	  for (k = 0; k < hasbothpoints.Size(); k++)
+	    if (mesh[hasbothpoints[k]].GetType() != TET)
+	      puretet = 0;
+	  if (!puretet) continue;
+
+	  p1 = mesh[pi1];
+	  p2 = mesh[pi2];
+
+	  /*
+	    pnew = Center (p1, p2);
+	  
+	    points.Elem(pi1) = pnew;
+	    bad2 = 0;
+	    for (k = 1; k <= hasbothpoints.Size(); k++)
+	    bad2 += CalcBad (points, 
+	    volelements.Get(hasbothpoints.Get(k)), 0);
+
+	    points.Elem(pi1) = p1;
+	    points.Elem(pi2) = pnew;
+	      
+	    for (k = 1; k <= hasbothpoints.Size(); k++)
+	    bad2 += CalcBad (points, 
+	    volelements.Get(hasbothpoints.Get(k)), 0);
+	    points.Elem(pi2) = p2;
+	  */
+
+
+	  locfaces.SetSize (0);
+	  for (k = 0; k < hasbothpoints.Size(); k++)
+	    {
+	      const Element & el = mesh[hasbothpoints[k]];
+
+	      for (int l = 0; l < 4; l++)
+		if (el[l] == pi1 || el[l] == pi2)
+		  {
+		    INDEX_3 i3;
+		    Element2d face;
+		    el.GetFace (l+1, face);
+		    for (int kk = 1; kk <= 3; kk++)
+		      i3.I(kk) = face.PNum(kk);
+		    locfaces.Append (i3);
+		  }
+	    }
+
+	  PointFunction1 pf (mesh.Points(), locfaces, -1);
+	  OptiParameters par;
+	  par.maxit_linsearch = 50;
+	  par.maxit_bfgs = 20;
+
+	  pnew = Center (p1, p2);
+	  Vector px(3);
+	  px.Elem(1) = pnew.X();
+	  px.Elem(2) = pnew.Y();
+	  px.Elem(3) = pnew.Z();
+
+	  if (elerrs[ei] > 0.1 * badmax)
+	    BFGS (px, pf, par);
+
+	  bad2 = pf.Func (px);
+
+	  pnew.X() = px.Get(1);
+	  pnew.Y() = px.Get(2);
+	  pnew.Z() = px.Get(3);
+
+
+	  int hpinew = mesh.AddPoint (pnew);
+	  //	  ptyps.Append (INNERPOINT);
+
+	  for (k = 0; k < hasbothpoints.Size(); k++)
+	    {
+	      Element & oldel = mesh[hasbothpoints[k]];
+	      Element newel1 = oldel;
+	      Element newel2 = oldel;
+
+	      oldel.flags.illegal_valid = 0;
+	      newel1.flags.illegal_valid = 0;
+	      newel2.flags.illegal_valid = 0;
+	      
+	      for (l = 0; l < 4; l++)
+		{
+		  if (newel1[l] == pi2) newel1[l] = hpinew;
+		  if (newel2[l] == pi1) newel2[l] = hpinew;
+		}
+	      
+	      if (!mesh.LegalTet (oldel)) bad1 += 1e6;
+	      if (!mesh.LegalTet (newel1)) bad2 += 1e6;
+	      if (!mesh.LegalTet (newel2)) bad2 += 1e6;
+	    }	  
+	  
+	  mesh.PointTypes().DeleteLast();
+	  mesh.Points().DeleteLast();
+
+	  if (bad2 < bad1) 
+	    /*	      (bad1 > 1e4 && boundp.Test(pi1) && boundp.Test(pi2)) */ 
+	    {
+	      cnt++;
+
+	      PointIndex pinew = mesh.AddPoint (pnew);
+	      
+	      for (k = 0; k < hasbothpoints.Size(); k++)
+		{
+		  Element & oldel = mesh[hasbothpoints[k]];
+		  Element newel = oldel;
+
+		  newel.flags.illegal_valid = 0;
+		  oldel.flags.illegal_valid = 0;
+
+		  for (l = 0; l < 4; l++)
+		    {
+		      origpoint.Clear (oldel[l]);
+
+		      if (oldel[l] == pi2) oldel[l] = pinew;
+		      if (newel[l] == pi1) newel[l] = pinew;
+		    }
+		  mesh.AddVolumeElement (newel);
+		}
+	      
+	      j = 10;
+	    }
+	}
+    }
+
+
+  mesh.Compress();
+  PrintMessage (5, cnt, " splits performed");
+
+  (*testout) << "Splitt - Improve done" << "\n";
+
+  if (goal == OPT_QUALITY)
+    {
+      bad1 = CalcTotalBad (mesh.Points(), mesh.VolumeElements());
+      (*testout) << "Total badness = " << bad1 << endl;
+
+      int cntill = 0;
+      ne = mesh.GetNE();
+      for (ei = 0; ei < ne; ei++)
+	{
+	  if (!mesh.LegalTet (mesh[ei]))
+	    cntill++;
+	}
+      //      cout << cntill << " illegal tets" << endl;
+    }
+
+  multithread.task = savetask;
+}
+
+
+      
+  
+
+void MeshOptimize3d :: SwapImprove (Mesh & mesh, OPTIMIZEGOAL goal)
+{
+  int j, k, l;
+
+  (*testout) << "swapimprove" << endl;
+  
+  ElementIndex ei;
+  SurfaceElementIndex sei;
+
+  int mattyp;
+  PointIndex pi1, pi2, pi3, pi4, pi5, pi6;
+  int cnt = 0;
+
+  Element el21(TET), el22(TET), el31(TET), el32(TET), el33(TET);
+  Element el1(TET), el2(TET), el3(TET), el4(TET);
+  Element el1b(TET), el2b(TET), el3b(TET), el4b(TET);
+  
+  double bad1, bad2, bad3;
+
+  int np = mesh.GetNP();
+  int ne = mesh.GetNE();
+  int nse = mesh.GetNSE();
+
+  
+  // contains at least all elements at node
+  TABLE<ElementIndex,PointIndex::BASE> elementsonnode(np);
+
+  ARRAY<ElementIndex> hasbothpoints;
+
+  PrintMessage (3, "SwapImprove ");
+  (*testout) << "\n" << "Start SwapImprove" << endl;
+
+  char * savetask = multithread.task;
+  multithread.task = "Swap Improve";
+  
+  //  mesh.CalcSurfacesOfNode ();
+  /*
+    for (i = 1; i <= GetNE(); i++)
+    if (volelements.Get(i).PNum(1))
+    if (!LegalTet (volelements.Get(i)))
+    {
+    cout << "detected illegal tet, 1" << endl;
+    (*testout) << "detected illegal tet1: " << i << endl;
+    }
+  */	
+  
+    
+  INDEX_3_HASHTABLE<int> faces(mesh.GetNOpenElements()/3 + 2);
+  if (goal == OPT_CONFORM)
+    {
+      for (int i = 1; i <= mesh.GetNOpenElements(); i++)
+	{
+	  const Element2d & hel = mesh.OpenElement(i);
+	  INDEX_3 face(hel[0], hel[1], hel[2]);
+	  face.Sort();
+	  faces.Set (face, 1);
+	}
+    }
+  
+  // Calculate total badness
+  if (goal == OPT_QUALITY)
+    {
+      bad1 = CalcTotalBad (mesh.Points(), mesh.VolumeElements());
+      (*testout) << "Total badness = " << bad1 << endl;
+    }
+  
+  // find elements on node
+  for (ei = 0; ei < ne; ei++)
+    for (j = 0; j < mesh[ei].GetNP(); j++)
+      elementsonnode.Add (mesh[ei][j], ei);
+
+  /*
+    BitArray illegaltet(GetNE());
+    MarkIllegalElements();
+    if (goal == OPT_QUALITY || goal == OPT_LEGAL)
+    {
+    int cntill = 0;
+    for (i = 1; i <= GetNE(); i++)
+    {
+    //	  if (!LegalTet (volelements.Get(i)))
+    if (VolumeElement(i).flags.illegal)
+    {
+    cntill++;
+    illegaltet.Set (i);
+    }
+    }
+    //      (*mycout) << cntill << " illegal tets" << endl;
+    }
+  */
+
+  INDEX_2_HASHTABLE<int> edgeused(2 * ne + 5);
+
+  for (ei = 0; ei < ne; ei++)
+    {
+      if (multithread.terminate)
+	break;
+      
+      multithread.percent = 100.0 * (ei+1) / ne;
+
+      if (mesh.ElementType(ei) == FIXEDELEMENT)
+	continue;
+      
+      if (mesh[ei].IsDeleted())
+	continue;
+
+      if ((goal == OPT_LEGAL) && 
+	  mesh.LegalTet (mesh[ei]) &&
+	  CalcBad (mesh.Points(), mesh[ei], 0) < 1e3)
+	continue;
+
+
+      //      int onlybedges = 1;
+
+      for (j = 0; j < 6; j++)
+	{
+	  // loop over edges
+
+	  const Element & elemi = mesh[ei];
+	  if (elemi.IsDeleted()) continue;
+
+	  mattyp = elemi.GetIndex();
+	  
+	  static const int tetedges[6][2] =
+	    { { 0, 1 }, { 0, 2 }, { 0, 3 },
+	      { 1, 2 }, { 1, 3 }, { 2, 3 } };
+
+	  pi1 = elemi[tetedges[j][0]];
+	  pi2 = elemi[tetedges[j][1]];
+	  
+	  if (pi2 < pi1) Swap (pi1, pi2);
+	 	  
+	  if (mesh.BoundaryEdge (pi1, pi2)) continue;
+
+
+	  INDEX_2 i2 (pi1, pi2);
+	  i2.Sort();
+	  if (edgeused.Used(i2)) continue;
+	  edgeused.Set (i2, 1);
+	  
+	  hasbothpoints.SetSize (0);
+	  for (k = 0; k < elementsonnode[pi1].Size(); k++)
+	    {
+	      bool has1 = 0, has2 = 0;
+	      ElementIndex elnr = elementsonnode[pi1][k];
+	      const Element & elem = mesh[elnr];
+	      
+	      if (elem.IsDeleted()) continue;
+	      
+	      for (l = 0; l < elem.GetNP(); l++)
+		{
+		  if (elem[l] == pi1) has1 = 1;
+		  if (elem[l] == pi2) has2 = 1;
+		}
+
+	      if (has1 && has2) 
+		{ // only once
+		  for (l = 0; l < hasbothpoints.Size(); l++)
+		    if (hasbothpoints[l] == elnr)
+		      has1 = 0;
+		  
+		  if (has1)
+		    hasbothpoints.Append (elnr);
+		}
+	    }
+	  
+	  bool puretet = 1;
+	  for (k = 0; k < hasbothpoints.Size(); k++)
+	    if (mesh[hasbothpoints[k]].GetType () != TET)
+	      puretet = 0;
+	  if (!puretet)
+	    continue;
+
+	  int nsuround = hasbothpoints.Size();
+
+	  if ( nsuround == 3 )
+	    {
+	      Element & elem = mesh[hasbothpoints[0]];
+	      for (l = 0; l < 4; l++)
+		if (elem[l] != pi1 && elem[l] != pi2)
+		  {
+		    pi4 = pi3;
+		    pi3 = elem[l];
+		  }
+	      
+	      el31[0] = pi1;
+	      el31[1] = pi2;
+	      el31[2] = pi3;
+	      el31[3] = pi4;
+	      el31.SetIndex (mattyp);
+	      
+	      if (WrongOrientation (mesh.Points(), el31))
+		{
+		  Swap (pi3, pi4);
+		  el31[2] = pi3;
+		  el31[3] = pi4;
+		}
+	      
+	      pi5 = 0;
+	      for (k = 1; k < 3; k++)
+		{
+		  const Element & elem = mesh[hasbothpoints[k]];
+		  bool has1 = 0;
+		  for (l = 0; l < 4; l++)
+		    if (elem[l] == pi4)
+		      has1 = 1;
+		  if (has1)
+		    {
+		      for (l = 0; l < 4; l++)
+			if (elem[l] != pi1 && elem[l] != pi2 && elem[l] != pi4)
+			  pi5 = elem[l];
+		    }
+		}
+	      
+	      el32[0] = pi1;  
+	      el32[1] = pi2;  
+	      el32[2] = pi4;  
+	      el32[3] = pi5;  
+	      el32.SetIndex (mattyp);
+	      
+	      el33[0] = pi1;  
+	      el33[1] = pi2;  
+	      el33[2] = pi5;  
+	      el33[3] = pi3;  
+	      el33.SetIndex (mattyp);
+	      
+	      elementsonnode.Add (pi4, hasbothpoints[1]);
+	      elementsonnode.Add (pi3, hasbothpoints[2]);
+	      
+	      bad1 = CalcBad (mesh.Points(), el31, 0) + 
+		CalcBad (mesh.Points(), el32, 0) +
+		CalcBad (mesh.Points(), el33, 0);
+
+	      el31.flags.illegal_valid = 0;
+	      el32.flags.illegal_valid = 0;
+	      el33.flags.illegal_valid = 0;
+
+	      if (!mesh.LegalTet(el31) ||
+		  !mesh.LegalTet(el32) ||
+		  !mesh.LegalTet(el33))
+		bad1 += 1e4;
+	      
+	      el21[0] = pi3;
+	      el21[1] = pi4;
+	      el21[2] = pi5;
+	      el21[3] = pi2;
+	      el21.SetIndex (mattyp);
+	      
+	      el22[0] = pi5;
+	      el22[1] = pi4;
+	      el22[2] = pi3;
+	      el22[3] = pi1;
+	      el22.SetIndex (mattyp);	      
+
+	      bad2 = CalcBad (mesh.Points(), el21, 0) + 
+		CalcBad (mesh.Points(), el22, 0);
+
+	      el21.flags.illegal_valid = 0;
+	      el22.flags.illegal_valid = 0;
+
+	      if (!mesh.LegalTet(el21) ||
+		  !mesh.LegalTet(el22))
+		bad2 += 1e4;
+
+
+	      if (goal == OPT_CONFORM && bad2 < 1e4)
+		{
+		  INDEX_3 face(pi3, pi4, pi5);
+		  face.Sort();
+		  if (faces.Used(face))
+		    {
+		      (*testout) << "3->2 swap, could improve conformity, bad1 = " << bad1
+				 << ", bad2 = " << bad2 << endl;
+		      if (bad2 < 1e4)
+			bad1 = 2 * bad2;
+		    }
+		  /*
+		    else
+		    {
+		    INDEX_2 hi1(pi3, pi4);
+		    hi1.Sort();
+		    INDEX_2 hi2(pi3, pi5);
+		    hi2.Sort();
+		    INDEX_2 hi3(pi4, pi5);
+		    hi3.Sort();
+
+		    if (boundaryedges->Used (hi1) ||
+		    boundaryedges->Used (hi2) ||
+		    boundaryedges->Used (hi3) )
+		    bad1 = 2 * bad2;
+		    }
+		  */
+		}
+
+	      if (bad2 < bad1)
+		{
+		  //		  (*mycout) << "3->2 " << flush;
+		  //		  (*testout) << "3->2 conversion" << endl;
+		  cnt++;
+		  
+
+		  (*testout) << "3->2 swap, old els = " << endl
+			     << mesh[hasbothpoints[0]] << endl
+			     << mesh[hasbothpoints[1]] << endl
+			     << mesh[hasbothpoints[2]] << endl
+			     << "new els = " << endl
+			     << el21 << endl
+			     << el22 << endl;
+
+
+
+		  el21.flags.illegal_valid = 0;
+		  el22.flags.illegal_valid = 0;
+		  mesh[hasbothpoints[0]] = el21;
+		  mesh[hasbothpoints[1]] = el22;
+		  for (l = 0; l < 4; l++)
+		    mesh[hasbothpoints[2]][l] = 0;
+		  mesh[hasbothpoints[2]].Delete();
+
+		  for (k = 0; k < 2; k++)
+		    for (l = 0; l < 4; l++)
+		      elementsonnode.Add (mesh[hasbothpoints[k]][l], hasbothpoints[k]);
+		}
+	    }
+	  
+
+	  if (nsuround == 4)
+	    {
+	      const Element & elem1 = mesh[hasbothpoints[0]];
+	      for (l = 0; l < 4; l++)
+		if (elem1[l] != pi1 && elem1[l] != pi2)
+		  {
+		    pi4 = pi3;
+		    pi3 = elem1[l];
+		  }
+	      
+	      el1[0] = pi1; el1[1] = pi2;
+	      el1[2] = pi3; el1[3] = pi4;
+	      el1.SetIndex (mattyp);
+
+	      if (WrongOrientation (mesh.Points(), el1))
+		{
+		  Swap (pi3, pi4);
+		  el1[2] = pi3;
+		  el1[3] = pi4;
+		}
+	      
+	      pi5 = 0;
+	      for (k = 1; k < 4; k++)
+		{
+		  const Element & elem = mesh[hasbothpoints[k]];
+		  bool has1 = 0;
+		  for (l = 0; l < 4; l++)
+		    if (elem[l] == pi4)
+		      has1 = 1;
+		  if (has1)
+		    {
+		      for (l = 0; l < 4; l++)
+			if (elem[l] != pi1 && elem[l] != pi2 && elem[l] != pi4)
+			  pi5 = elem[l];
+		    }
+		}
+	      
+	      pi6 = 0;
+	      for (k = 1; k < 4; k++)
+		{
+		  const Element & elem = mesh[hasbothpoints[k]];
+		  bool has1 = 0;
+		  for (l = 0; l < 4; l++)
+		    if (elem[l] == pi3)
+		      has1 = 1;
+		  if (has1)
+		    {
+		      for (l = 0; l < 4; l++)
+			if (elem[l] != pi1 && elem[l] != pi2 && elem[l] != pi3)
+			  pi6 = elem[l];
+		    }
+		}
+	      
+	      /*
+	      INDEX_2 i22(pi3, pi5);
+	      i22.Sort();
+	      INDEX_2 i23(pi4, pi6);
+	      i23.Sort();
+	      */
+	      
+	      el1[0] = pi1; el1[1] = pi2;  
+	      el1[2] = pi3; el1[3] = pi4; 
+	      el1.SetIndex (mattyp);
+	      
+	      el2[0] = pi1; el2[1] = pi2;  
+	      el2[2] = pi4; el2[3] = pi5;  
+	      el2.SetIndex (mattyp);
+	      
+	      el3[0] = pi1; el3[1] = pi2;  
+	      el3[2] = pi5; el3[3] = pi6;  
+	      el3.SetIndex (mattyp);
+	      
+	      el4[0] = pi1; el4[1] = pi2;  
+	      el4[2] = pi6; el4[3] = pi3;  
+	      el4.SetIndex (mattyp);
+	      
+	      //        elementsonnode.Add (pi4, hasbothpoints.Elem(2));
+	      //        elementsonnode.Add (pi3, hasbothpoints.Elem(3));
+	      
+	      bad1 = CalcBad (mesh.Points(), el1, 0) + 
+		CalcBad (mesh.Points(), el2, 0) +
+		CalcBad (mesh.Points(), el3, 0) + 
+		CalcBad (mesh.Points(), el4, 0);
+	      
+
+	      el1.flags.illegal_valid = 0;
+	      el2.flags.illegal_valid = 0;
+	      el3.flags.illegal_valid = 0;
+	      el4.flags.illegal_valid = 0;
+
+
+	      if (goal != OPT_CONFORM)
+		{
+		  if (!mesh.LegalTet(el1) ||
+		      !mesh.LegalTet(el2) ||
+		      !mesh.LegalTet(el3) ||
+		      !mesh.LegalTet(el4))
+		    bad1 += 1e4;
+		}
+	      
+	      el1[0] = pi3; el1[1] = pi5;  
+	      el1[2] = pi2; el1[3] = pi4; 
+	      el1.SetIndex (mattyp);
+	 
+	      el2[0] = pi3; el2[1] = pi5;  
+	      el2[2] = pi4; el2[3] = pi1;  
+	      el2.SetIndex (mattyp);
+	      
+	      el3[0] = pi3; el3[1] = pi5;  
+	      el3[2] = pi1; el3[3] = pi6;  
+	      el3.SetIndex (mattyp);
+	      
+	      el4[0] = pi3; el4[1] = pi5;  
+	      el4[2] = pi6; el4[3] = pi2;  	
+	      el4.SetIndex (mattyp);
+      
+	      bad2 = CalcBad (mesh.Points(), el1, 0) + 
+		CalcBad (mesh.Points(), el2, 0) +
+		CalcBad (mesh.Points(), el3, 0) + 
+		CalcBad (mesh.Points(), el4, 0);
+
+	      el1.flags.illegal_valid = 0;
+	      el2.flags.illegal_valid = 0;
+	      el3.flags.illegal_valid = 0;
+	      el4.flags.illegal_valid = 0;
+
+	      if (goal != OPT_CONFORM)
+		{
+		  if (!mesh.LegalTet(el1) ||
+		      !mesh.LegalTet(el2) ||
+		      !mesh.LegalTet(el3) ||
+		      !mesh.LegalTet(el4))
+		    bad2 += 1e4;
+		}
+
+	      
+	      el1b[0] = pi4; el1b[1] = pi6;  
+	      el1b[2] = pi3; el1b[3] = pi2; 
+	      el1b.SetIndex (mattyp);
+	      
+	      el2b[0] = pi4; el2b[1] = pi6;  
+	      el2b[2] = pi2; el2b[3] = pi5;  
+	      el2b.SetIndex (mattyp);
+	      
+	      el3b[0] = pi4; el3b[1] = pi6;  
+	      el3b[2] = pi5; el3b[3] = pi1;  
+	      el3b.SetIndex (mattyp);
+	      
+	      el4b[0] = pi4; el4b[1] = pi6;  
+	      el4b[2] = pi1; el4b[3] = pi3;  
+	      el4b.SetIndex (mattyp);
+	      
+	      bad3 = CalcBad (mesh.Points(), el1b, 0) + 
+		CalcBad (mesh.Points(), el2b, 0) +
+		CalcBad (mesh.Points(), el3b, 0) +
+		CalcBad (mesh.Points(), el4b, 0);
+	      
+	      el1b.flags.illegal_valid = 0;
+	      el2b.flags.illegal_valid = 0;
+	      el3b.flags.illegal_valid = 0;
+	      el4b.flags.illegal_valid = 0;
+
+	      if (goal != OPT_CONFORM)
+		{
+		  if (!mesh.LegalTet(el1b) ||
+		      !mesh.LegalTet(el2b) ||
+		      !mesh.LegalTet(el3b) ||
+		      !mesh.LegalTet(el4b))
+		    bad3 += 1e4;
+		}
+
+
+	      /*
+	      int swap2 = (bad2 < bad1) && (bad2 < bad3);
+	      int swap3 = !swap2 && (bad3 < bad1);
+	      
+	      if ( ((bad2 < 10 * bad1) || 
+		    (bad2 < 1e6)) && mesh.BoundaryEdge (pi3, pi5))
+		swap2 = 1;
+	      else  if ( ((bad3 < 10 * bad1) || 
+			  (bad3 < 1e6)) && mesh.BoundaryEdge (pi4, pi6))
+		{
+		  swap3 = 1;
+		  swap2 = 0;
+		}
+	      */
+	      bool swap2, swap3;
+
+	      if (goal != OPT_CONFORM)
+		{
+		  swap2 = (bad2 < bad1) && (bad2 < bad3);
+		  swap3 = !swap2 && (bad3 < bad1);
+		}
+	      else
+		{
+		  if (mesh.BoundaryEdge (pi3, pi5)) bad2 /= 1e6;
+		  if (mesh.BoundaryEdge (pi4, pi6)) bad3 /= 1e6;
+
+		  swap2 = (bad2 < bad1) && (bad2 < bad3);
+		  swap3 = !swap2 && (bad3 < bad1);
+		}
+		
+
+	      if (swap2 || swap3)
+		{
+		  // (*mycout) << "4->4 " << flush;
+		  cnt++;
+		  //		  (*testout) << "4->4 conversion" << "\n";
+		  /*
+		    (*testout) << "bad1 = " << bad1 
+		    << " bad2 = " << bad2
+		    << " bad3 = " << bad3 << "\n";
+		  
+		    (*testout) << "Points: " << pi1 << " " << pi2 << " " << pi3 
+		    << " " << pi4 << " " << pi5 << " " << pi6 << "\n";
+		    (*testout) << "Elements: " 
+		    << hasbothpoints.Get(1) << "  "
+		    << hasbothpoints.Get(2) << "  "
+		    << hasbothpoints.Get(3) << "  "
+		    << hasbothpoints.Get(4) << "  " << "\n";
+		  */
+
+		  /*
+		    {
+		    int i1, j1;
+		    for (i1 = 1; i1 <= 4; i1++)
+		    {
+		    for (j1 = 1; j1 <= 4; j1++)
+		    (*testout) << volelements.Get(hasbothpoints.Get(i1)).PNum(j1)
+		    << "  ";
+		    (*testout) << "\n";
+		    }
+		    }
+		  */
+		}
+	      
+
+	      if (swap2)
+		{
+		  //		  (*mycout) << "bad1 = " << bad1 << " bad2 = " << bad2 << "\n";
+
+
+		  (*testout) << "4->4 swap A, old els = " << endl
+			     << mesh[hasbothpoints[0]] << endl
+			     << mesh[hasbothpoints[1]] << endl
+			     << mesh[hasbothpoints[2]] << endl
+			     << mesh[hasbothpoints[3]] << endl
+			     << "new els = " << endl
+			     << el1 << endl
+			     << el2 << endl
+			     << el3 << endl
+			     << el4 << endl;
+
+
+
+
+		  el1.flags.illegal_valid = 0;
+		  el2.flags.illegal_valid = 0;
+		  el3.flags.illegal_valid = 0;
+		  el4.flags.illegal_valid = 0;
+		  
+		  mesh[hasbothpoints[0]] = el1;
+		  mesh[hasbothpoints[1]] = el2;
+		  mesh[hasbothpoints[2]] = el3;
+		  mesh[hasbothpoints[3]] = el4;
+		  
+		  for (k = 0; k < 4; k++)
+		    for (l = 0; l < 4; l++)
+		      elementsonnode.Add (mesh[hasbothpoints[k]][l], hasbothpoints[k]);
+		}
+	      else if (swap3)
+		{
+		  // (*mycout) << "bad1 = " << bad1 << " bad3 = " << bad3 << "\n";
+		  el1b.flags.illegal_valid = 0;
+		  el2b.flags.illegal_valid = 0;
+		  el3b.flags.illegal_valid = 0;
+		  el4b.flags.illegal_valid = 0;
+
+
+
+		  (*testout) << "4->4 swap A, old els = " << endl
+			     << mesh[hasbothpoints[0]] << endl
+			     << mesh[hasbothpoints[1]] << endl
+			     << mesh[hasbothpoints[2]] << endl
+			     << mesh[hasbothpoints[3]] << endl
+			     << "new els = " << endl
+			     << el1b << endl
+			     << el2b << endl
+			     << el3b << endl
+			     << el4b << endl;
+
+
+
+		  mesh[hasbothpoints[0]] = el1b;
+		  mesh[hasbothpoints[1]] = el2b;
+		  mesh[hasbothpoints[2]] = el3b;
+		  mesh[hasbothpoints[3]] = el4b;
+
+		  for (k = 0; k < 4; k++)
+		    for (l = 0; l < 4; l++)
+		      elementsonnode.Add (mesh[hasbothpoints[k]][l], hasbothpoints[k]);
+		}
+	    }
+
+	  if (nsuround >= 5) 
+	    {
+	      Element hel(TET);
+
+	      ArrayMem<PointIndex, 50> suroundpts(nsuround);
+	      ArrayMem<char, 50> tetused(nsuround);
+
+	      Element & elem = mesh[hasbothpoints[0]];
+
+	      for (l = 0; l < 4; l++)
+		if (elem[l] != pi1 && elem[l] != pi2)
+		  {
+		    pi4 = pi3;
+		    pi3 = elem[l];
+		  }
+
+	      hel[0] = pi1;
+	      hel[1] = pi2;
+	      hel[2] = pi3;
+	      hel[3] = pi4;
+	      hel.SetIndex (mattyp);
+	      
+	      if (WrongOrientation (mesh.Points(), hel))
+		{
+		  Swap (pi3, pi4);
+		  hel[2] = pi3;
+		  hel[3] = pi4;
+		}
+
+	      
+	      // suroundpts.SetSize (nsuround);
+	      suroundpts[0] = pi3;
+	      suroundpts[1] = pi4;
+
+	      tetused = 0;
+	      tetused[0] = 1;
+
+	      for (l = 2; l < nsuround; l++)
+		{
+		  int oldpi = suroundpts[l-1];
+		  int newpi = 0;
+
+		  for (k = 0; k < nsuround && !newpi; k++)
+		    if (!tetused[k])
+		      {
+			const Element & nel = mesh[hasbothpoints[k]];
+
+			for (int k2 = 0; k2 < 4 && !newpi; k2++)
+			  if (nel[k2] == oldpi)
+			    {
+			      newpi = 
+				nel[0] + nel[1] + nel[2] + nel[3] 
+				- pi1 - pi2 - oldpi;
+			      
+			      tetused[k] = 1; 
+			      suroundpts[l] = newpi;
+			    }			
+		      }
+		}
+
+	      
+	      double bad1 = 0, bad2;
+	      for (k = 0; k < nsuround; k++)
+		{
+		  hel[0] = pi1;
+		  hel[1] = pi2;
+		  hel[2] = suroundpts[k];
+		  hel[3] = suroundpts[(k+1) % nsuround];
+		  hel.SetIndex (mattyp);
+
+		  bad1 += CalcBad (mesh.Points(), hel, 0);
+		}
+
+	      //  (*testout) << "nsuround = " << nsuround << " bad1 = " << bad1 << endl;
+
+
+	      int bestl = -1;
+	      int confface = -1;
+	      int confedge = -1;
+	      double badopt = bad1;
+
+	      for (l = 0; l < nsuround; l++)
+		{
+		  bad2 = 0;
+
+		  for (k = l+1; k <= nsuround + l - 2; k++)
+		    {
+		      hel[0] = suroundpts[l];
+		      hel[1] = suroundpts[k % nsuround];
+		      hel[2] = suroundpts[(k+1) % nsuround];
+		      hel[3] = pi2;
+
+		      bad2 += CalcBad (mesh.Points(), hel, 0);
+		      hel.flags.illegal_valid = 0;
+		      if (!mesh.LegalTet(hel)) bad2 += 1e4;
+
+		      hel[2] = suroundpts[k % nsuround];
+		      hel[1] = suroundpts[(k+1) % nsuround];
+		      hel[3] = pi1;
+
+		      bad2 += CalcBad (mesh.Points(), hel, 0);
+
+		      hel.flags.illegal_valid = 0;
+		      if (!mesh.LegalTet(hel)) bad2 += 1e4;
+		    }
+		  // (*testout) << "bad2," << l << " = " << bad2 << endl;
+		  
+		  if ( bad2 < badopt )
+		    {
+		      bestl = l;
+		      badopt = bad2;
+		    }
+		  
+		  
+		  if (goal == OPT_CONFORM)
+		       // (bad2 <= 100 * bad1 || bad2 <= 1e6))
+		    {
+		      bool nottoobad =
+			(bad2 <= bad1) ||
+			(bad2 <= 100 * bad1 && bad2 <= 1e18) ||
+			(bad2 <= 1e8);
+		      
+		      for (k = l+1; k <= nsuround + l - 2; k++)
+			{
+			  INDEX_3 hi3(suroundpts[l],
+				      suroundpts[k % nsuround],
+				      suroundpts[(k+1) % nsuround]);
+			  hi3.Sort();
+			  if (faces.Used(hi3))
+			    {
+			      (*testout) << "could improve face conformity, bad1 = " << bad1
+				   << ", bad 2 = " << bad2 << ", nottoobad = " << nottoobad << endl;
+			      if (nottoobad)
+				confface = l;
+			    }
+			}
+
+		      for (k = l+2; k <= nsuround+l-2; k++)
+			{
+			  if (mesh.BoundaryEdge (suroundpts[l],
+						 suroundpts[k % nsuround]))
+			    {
+			      *testout << "could improve edge conformity, bad1 = " << bad1
+				   << ", bad 2 = " << bad2 << ", nottoobad = " << nottoobad << endl;
+			      if (nottoobad)
+				confedge = l;
+			    }
+			}
+		    }
+		}
+	      
+	      if (confedge != -1)
+		bestl = confedge;
+	      if (confface != -1)
+		bestl = confface;
+
+	      if (bestl != -1)
+		{
+		  // (*mycout) << nsuround << "->" << 2 * (nsuround-2) << " " << flush;
+		  cnt++;
+		  
+		  for (k = bestl+1; k <= nsuround + bestl - 2; k++)
+		    {
+		      int k1;
+
+		      hel[0] = suroundpts[bestl];
+		      hel[1] = suroundpts[k % nsuround];
+		      hel[2] = suroundpts[(k+1) % nsuround];
+		      hel[3] = pi2;
+		      hel.flags.illegal_valid = 0;
+
+		      (*testout) << nsuround << "-swap, new el,top = "
+				 << hel << endl;
+
+		      mesh.AddVolumeElement (hel);
+		      for (k1 = 0; k1 < 4; k1++)
+			elementsonnode.Add (hel[k1], mesh.GetNE()-1);
+		      
+
+		      hel[2] = suroundpts[k % nsuround];
+		      hel[1] = suroundpts[(k+1) % nsuround];
+		      hel[3] = pi1;
+
+
+		      (*testout) << nsuround << "-swap, new el,bot = "
+				 << hel << endl;
+
+
+		      mesh.AddVolumeElement (hel);
+		      for (k1 = 0; k1 < 4; k1++)
+			elementsonnode.Add (hel[k1], mesh.GetNE()-1);
+		    }		  
+		  
+		  for (k = 0; k < nsuround; k++)
+		    {
+		      Element & rel = mesh[hasbothpoints[k]];
+
+		      (*testout) << nsuround << "-swap, old el = "
+				 << rel << endl;
+
+		      rel.Delete();
+		      for (int k1 = 0; k1 < 4; k1++)
+			rel[k1] = 0;
+		    }
+		}
+	    }
+	}
+
+      /*
+	if (onlybedges)
+	{
+	(*testout) << "bad tet: " 
+	<< volelements.Get(i)[0] 
+	<< volelements.Get(i)[1] 
+	<< volelements.Get(i)[2] 
+	<< volelements.Get(i)[3] << "\n";
+
+	if (!mesh.LegalTet (volelements.Get(i)))
+	cerr << "Illegal tet" << "\n";
+	}
+      */
+    }
+  //  (*mycout) << endl;
+
+  /*  
+      cout << "edgeused: ";
+      edgeused.PrintMemInfo(cout);
+  */
+  PrintMessage (5, cnt, " swaps performed");
+
+  mesh.Compress ();
+
+  if (goal == OPT_QUALITY)
+    {
+      bad1 = CalcTotalBad (mesh.Points(), mesh.VolumeElements());
+      (*testout) << "Total badness = " << bad1 << endl;
+    }
+
+  /*
+    for (i = 1; i <= GetNE(); i++)
+    if (volelements.Get(i)[0])
+    if (!mesh.LegalTet (volelements.Get(i)))
+    {
+    cout << "detected illegal tet, 2" << endl;
+    (*testout) << "detected illegal tet1: " << i << endl;
+    }
+  */
+
+  multithread.task = savetask;
+}
+  
+
+
+
+
+
+
+
+/*
+  2 -> 3 conversion
+*/
+
+
+
+void MeshOptimize3d :: SwapImprove2 (Mesh & mesh, OPTIMIZEGOAL goal)
+{
+  int j, k, l;
+  //  INDEX_2 i2;
+  ElementIndex ei, eli1, eli2, elnr;
+  SurfaceElementIndex sei;
+  PointIndex pi1, pi2, pi3, pi4, pi5;
+
+  int mattyp;
+  int cnt = 0;
+
+  Element el21(TET), el22(TET), el31(TET), el32(TET), el33(TET);
+
+  double bad1, bad2;
+
+  int np = mesh.GetNP();
+  int ne = mesh.GetNE();
+  int nse = mesh.GetNSE();
+
+  if (goal == OPT_CONFORM) return;
+
+  // contains at least all elements at node
+  TABLE<ElementIndex, PointIndex::BASE> elementsonnode(np); 
+  TABLE<SurfaceElementIndex, PointIndex::BASE> belementsonnode(np);
+
+  PrintMessage (3, "SwapImprove2 ");
+  (*testout) << "\n" << "Start SwapImprove2" << "\n";
+  //  TestOk();
+
+
+
+  /*
+    CalcSurfacesOfNode ();
+    for (i = 1; i <= GetNE(); i++)
+    if (volelements.Get(i)[0])
+    if (!mesh.LegalTet (volelements.Get(i)))
+    {
+    cout << "detected illegal tet, 1" << endl;
+    (*testout) << "detected illegal tet1: " << i << endl;
+    }
+  */
+
+  
+  // Calculate total badness
+
+  bad1 = CalcTotalBad (mesh.Points(), mesh.VolumeElements());
+  (*testout) << "Total badness = " << bad1 << endl;
+
+  // find elements on node
+
+  for (ei = 0; ei < ne; ei++)
+    for (j = 0; j < mesh[ei].GetNP(); j++)
+      elementsonnode.Add (mesh[ei][j], ei);
+
+  for (sei = 0; sei < nse; sei++)
+    for (j = 0; j < 3; j++)
+      belementsonnode.Add (mesh[sei][j], sei);
+
+  // cout << "main loop" << endl;
+
+  for (eli1 = 0; eli1 < mesh.GetNE(); eli1++)
+    {
+      if (multithread.terminate)
+	break;
+
+      if (mesh.ElementType (eli1) == FIXEDELEMENT)
+	continue;
+
+      if (mesh[eli1].GetType() != TET)
+	continue;
+
+      if ((goal == OPT_LEGAL) && 
+	  mesh.LegalTet (mesh[eli1]) &&
+	  CalcBad (mesh.Points(), mesh[eli1], 0) < 1e3)
+	continue;
+
+
+
+      for (j = 0; j < 4; j++)
+	{
+	  // loop over faces
+      
+	  Element & elem = mesh[eli1];
+	  // if (elem[0] < PointIndex::BASE) continue;
+	  if (elem.IsDeleted()) continue;
+
+	  mattyp = elem.GetIndex();
+	  
+	  switch (j)
+	    {
+	    case 0:
+	      pi1 = elem.PNum(1); pi2 = elem.PNum(2); 
+	      pi3 = elem.PNum(3); pi4 = elem.PNum(4);
+	      break;
+	    case 1:
+	      pi1 = elem.PNum(1); pi2 = elem.PNum(4); 
+	      pi3 = elem.PNum(2); pi4 = elem.PNum(3);
+	      break;
+	    case 2:
+	      pi1 = elem.PNum(1); pi2 = elem.PNum(3); 
+	      pi3 = elem.PNum(4); pi4 = elem.PNum(2);
+	      break;
+	    case 3:
+	      pi1 = elem.PNum(2); pi2 = elem.PNum(4); 
+	      pi3 = elem.PNum(3); pi4 = elem.PNum(1);
+	      break;
+	    }
+	  
+
+	  bool bface = 0;
+	  for (k = 0; k < belementsonnode[pi1].Size(); k++)
+	    {
+	      const Element2d & bel = 
+		mesh[belementsonnode[pi1][k]];
+
+	      bool bface1 = 1;
+	      for (l = 0; l < 3; l++)
+		if (bel[l] != pi1 && bel[l] != pi2 && bel[l] != pi3)
+		  {
+		    bface1 = 0;
+		    break;
+		  }
+
+	      if (bface1) 
+		{
+		  bface = 1;
+		  break;
+		}
+	    }
+	  
+	  if (bface) continue;
+
+
+	  FlatArray<ElementIndex> row = elementsonnode[pi1];
+	  for (k = 0; k < row.Size(); k++)
+	    {
+	      eli2 = row[k];
+
+	      // cout << "\rei1 = " << eli1 << ", pi1 = " << pi1 << ", k = " << k << ", ei2 = " << eli2 
+	      // << ", getne = " << mesh.GetNE();
+
+	      if ( eli1 != eli2 )
+		{
+		  Element & elem2 = mesh[eli2];
+		  if (elem2.IsDeleted()) continue;
+		  if (elem2.GetType() != TET)
+		    continue;
+		  
+		  int comnodes=0;
+		  for (l = 1; l <= 4; l++)
+		    if (elem2.PNum(l) == pi1 || elem2.PNum(l) == pi2 ||
+			elem2.PNum(l) == pi3)
+		      {
+			comnodes++;
+		      }
+		    else
+		      {
+			pi5 = elem2.PNum(l);
+		      }
+		  
+		  if (comnodes == 3)
+		    {
+		      bad1 = CalcBad (mesh.Points(), elem, 0) + 
+			CalcBad (mesh.Points(), elem2, 0); 
+		      
+		      if (!mesh.LegalTet(elem) || 
+			  !mesh.LegalTet(elem2))
+			bad1 += 1e4;
+
+		      
+		      el31.PNum(1) = pi1;
+		      el31.PNum(2) = pi2;
+		      el31.PNum(3) = pi5;
+		      el31.PNum(4) = pi4;
+		      el31.SetIndex (mattyp);
+		      
+		      el32.PNum(1) = pi2;
+		      el32.PNum(2) = pi3;
+		      el32.PNum(3) = pi5;
+		      el32.PNum(4) = pi4;
+		      el32.SetIndex (mattyp);
+		      
+		      el33.PNum(1) = pi3;
+		      el33.PNum(2) = pi1;
+		      el33.PNum(3) = pi5;
+		      el33.PNum(4) = pi4;
+		      el33.SetIndex (mattyp);
+		      
+		      bad2 = CalcBad (mesh.Points(), el31, 0) + 
+			CalcBad (mesh.Points(), el32, 0) +
+			CalcBad (mesh.Points(), el33, 0); 
+		      
+
+		      el31.flags.illegal_valid = 0;
+		      el32.flags.illegal_valid = 0;
+		      el33.flags.illegal_valid = 0;
+
+		      if (!mesh.LegalTet(el31) || 
+			  !mesh.LegalTet(el32) ||
+			  !mesh.LegalTet(el33))
+			bad2 += 1e4;
+
+
+		      bool do_swap = (bad2 < bad1);
+
+		      if ( ((bad2 < 1e6) || (bad2 < 10 * bad1)) &&
+			   mesh.BoundaryEdge (pi4, pi5))
+			do_swap = 1;
+			   
+		      if (do_swap)
+			{
+			  //			  (*mycout) << "2->3 " << flush;
+			  cnt++;
+
+			  el31.flags.illegal_valid = 0;
+			  el32.flags.illegal_valid = 0;
+			  el33.flags.illegal_valid = 0;
+
+			  mesh[eli1] = el31;
+			  mesh[eli2] = el32;
+			  
+			  ElementIndex neli =
+			    mesh.AddVolumeElement (el33);
+			  
+			  /*
+			    if (!LegalTet(el31) || !LegalTet(el32) ||
+			    !LegalTet(el33))
+			    {
+			    cout << "Swap to illegal tets !!!" << endl;
+			    }
+			  */
+			  // cout << "neli = " << neli << endl;
+			  for (l = 0; l < 4; l++)
+			    {
+			      elementsonnode.Add (el31[l], eli1);
+			      elementsonnode.Add (el32[l], eli2);
+			      elementsonnode.Add (el33[l], neli);
+			    }
+
+			  break;
+			}
+		    }
+		}
+	    }
+	}
+    }
+
+  //  cout << "loop done" << endl;
+
+  PrintMessage (5, cnt, " swaps performed");
+
+
+
+  /*
+    CalcSurfacesOfNode ();
+    for (i = 1; i <= GetNE(); i++)
+    if (volelements.Get(i).PNum(1))
+    if (!LegalTet (volelements.Get(i)))
+    {
+    cout << "detected illegal tet, 2" << endl;
+    (*testout) << "detected illegal tet2: " << i << endl;
+    }
+  */
+
+
+  bad1 = CalcTotalBad (mesh.Points(), mesh.VolumeElements());
+  (*testout) << "Total badness = " << bad1 << endl;
+  (*testout) << "swapimprove2 done" << "\n";
+  //  (*mycout) << "Vol = " << CalcVolume (points, volelements) << "\n";
+}
+
+
+/*
+  void Mesh :: SwapImprove2 (OPTIMIZEGOAL goal)
+  {
+  int i, j;
+  int eli1, eli2;
+  int mattyp;
+
+  Element el31(4), el32(4), el33(4);
+  double bad1, bad2;
+
+
+  INDEX_3_HASHTABLE<INDEX_2> elsonface (GetNE());
+
+  (*mycout) << "SwapImprove2 " << endl;
+  (*testout) << "\n" << "Start SwapImprove2" << "\n";
+
+  // Calculate total badness
+
+  if (goal == OPT_QUALITY)
+  {
+  double bad1 = CalcTotalBad (points, volelements);
+  (*testout) << "Total badness = " << bad1 << endl;
+  }
+
+  // find elements on node
+
+
+  Element2d face;
+  for (i = 1; i <= GetNE(); i++)
+  if ( (i > eltyps.Size()) || (eltyps.Get(i) != FIXEDELEMENT) )
+  {
+  const Element & el = VolumeElement(i);
+  if (!el.PNum(1)) continue;
+
+  for (j = 1; j <= 4; j++)
+  {
+  el.GetFace (j, face);
+  INDEX_3 i3 (face.PNum(1), face.PNum(2), face.PNum(3));
+  i3.Sort();
+
+
+  int bnr, posnr;
+  if (!elsonface.PositionCreate (i3, bnr, posnr))
+  {
+  INDEX_2 i2;
+  elsonface.GetData (bnr, posnr, i3, i2);
+  i2.I2() = i;
+  elsonface.SetData (bnr, posnr, i3, i2);
+  }
+  else
+  {
+  INDEX_2 i2 (i, 0);
+  elsonface.SetData (bnr, posnr, i3, i2);
+  }
+
+  //  	    if (elsonface.Used (i3))
+  //  	      {
+  //  		INDEX_2 i2 = elsonface.Get(i3);
+  //  		i2.I2() = i;
+  //  		elsonface.Set (i3, i2);
+  //  	      }
+  //  	    else
+  //  	      {
+  //  		INDEX_2 i2 (i, 0);
+  //  		elsonface.Set (i3, i2);
+  //  	      }
+
+  }
+  }
+
+  BitArray original(GetNE());
+  original.Set();
+
+  for (i = 1; i <= GetNSE(); i++)
+  {
+  const Element2d & sface = SurfaceElement(i);
+  INDEX_3 i3 (sface.PNum(1), sface.PNum(2), sface.PNum(3));
+  i3.Sort();
+  INDEX_2 i2(0,0);
+  elsonface.Set (i3, i2);
+  }
+
+
+  for (i = 1; i <= elsonface.GetNBags(); i++)
+  for (j = 1; j <= elsonface.GetBagSize(i); j++)
+  {
+  INDEX_3 i3;
+  INDEX_2 i2;
+  elsonface.GetData (i, j, i3, i2);
+
+
+  int eli1 = i2.I1();
+  int eli2 = i2.I2();
+
+  if (eli1 && eli2 && original.Test(eli1) && original.Test(eli2) )
+  {
+  Element & elem = volelements.Elem(eli1);
+  Element & elem2 = volelements.Elem(eli2);
+
+  int pi1 = i3.I1();
+  int pi2 = i3.I2();
+  int pi3 = i3.I3();
+
+  int pi4 = elem.PNum(1) + elem.PNum(2) + elem.PNum(3) + elem.PNum(4) - pi1 - pi2 - pi3;
+  int pi5 = elem2.PNum(1) + elem2.PNum(2) + elem2.PNum(3) + elem2.PNum(4) - pi1 - pi2 - pi3;
+
+
+
+
+
+
+  el31.PNum(1) = pi1;
+  el31.PNum(2) = pi2;
+  el31.PNum(3) = pi3;
+  el31.PNum(4) = pi4;
+  el31.SetIndex (mattyp);
+	    
+  if (WrongOrientation (points, el31))
+  swap (pi1, pi2);
+
+
+  bad1 = CalcBad (points, elem, 0) + 
+  CalcBad (points, elem2, 0); 
+	    
+  //	    if (!LegalTet(elem) || !LegalTet(elem2))
+  //	      bad1 += 1e4;
+
+	    
+  el31.PNum(1) = pi1;
+  el31.PNum(2) = pi2;
+  el31.PNum(3) = pi5;
+  el31.PNum(4) = pi4;
+  el31.SetIndex (mattyp);
+	    
+  el32.PNum(1) = pi2;
+  el32.PNum(2) = pi3;
+  el32.PNum(3) = pi5;
+  el32.PNum(4) = pi4;
+  el32.SetIndex (mattyp);
+		      
+  el33.PNum(1) = pi3;
+  el33.PNum(2) = pi1;
+  el33.PNum(3) = pi5;
+  el33.PNum(4) = pi4;
+  el33.SetIndex (mattyp);
+	    
+  bad2 = CalcBad (points, el31, 0) + 
+  CalcBad (points, el32, 0) +
+  CalcBad (points, el33, 0); 
+	    
+  //	    if (!LegalTet(el31) || !LegalTet(el32) ||
+  //		!LegalTet(el33))
+  //	      bad2 += 1e4;
+	    
+	    
+  int swap = (bad2 < bad1);
+
+  INDEX_2 hi2b(pi4, pi5);
+  hi2b.Sort();
+	    
+  if ( ((bad2 < 1e6) || (bad2 < 10 * bad1)) &&
+  boundaryedges->Used (hi2b) )
+  swap = 1;
+	    
+  if (swap)
+  {
+  (*mycout) << "2->3 " << flush;
+		
+  volelements.Elem(eli1) = el31;
+  volelements.Elem(eli2) = el32;
+  volelements.Append (el33);
+		
+  original.Clear (eli1);
+  original.Clear (eli2);
+  }
+  }
+  }
+  
+  (*mycout) << endl;
+
+  if (goal == OPT_QUALITY)
+  {
+  bad1 = CalcTotalBad (points, volelements);
+  (*testout) << "Total badness = " << bad1 << endl;
+  }
+
+  //  FindOpenElements ();
+
+  (*testout) << "swapimprove2 done" << "\n";
+  }
+
+*/
+}
diff --git a/Netgen/libsrc/meshing/improve3.hpp b/Netgen/libsrc/meshing/improve3.hpp
new file mode 100644
index 0000000000..9b5b2c9bec
--- /dev/null
+++ b/Netgen/libsrc/meshing/improve3.hpp
@@ -0,0 +1,50 @@
+#ifndef FILE_IMPROVE3
+#define FILE_IMPROVE3
+
+
+
+
+///
+class MeshOptimize3d
+{
+public:
+  void CombineImprove (Mesh & mesh, OPTIMIZEGOAL goal = OPT_QUALITY);
+  void SplitImprove (Mesh & mesh, OPTIMIZEGOAL goal = OPT_QUALITY);
+  void SwapImprove (Mesh & mesh, OPTIMIZEGOAL goal = OPT_QUALITY);
+  void SwapImprove2 (Mesh & mesh, OPTIMIZEGOAL goal = OPT_QUALITY);
+};
+
+
+
+extern double CalcBad (const Mesh::T_POINTS & points, const Element & elem,
+		       double h);
+
+extern double CalcTotalBad (const Mesh::T_POINTS & points, 
+			    const Mesh::T_VOLELEMENTS & elements);
+
+extern int WrongOrientation (const Mesh::T_POINTS & points, const Element & el);
+
+
+/* Functional depending of inner point inside triangular surface */
+
+
+
+class PointFunction1 : public MinFunction
+{
+  Mesh::T_POINTS & points;
+  const ARRAY<INDEX_3> & faces;
+  double h;
+public:
+  PointFunction1 (Mesh::T_POINTS & apoints, 
+		  const ARRAY<INDEX_3> & afaces,
+		  double ah);
+  
+  virtual double Func (const Vector & x) const;
+  virtual double FuncDeriv (const Vector & x, const Vector & dir, double & deriv) const;
+  virtual double FuncGrad (const Vector & x, Vector & g) const;
+  virtual double GradStopping (const Vector & x) const;
+};
+
+
+
+#endif
diff --git a/Netgen/libsrc/meshing/localh.cpp b/Netgen/libsrc/meshing/localh.cpp
new file mode 100644
index 0000000000..62025737f3
--- /dev/null
+++ b/Netgen/libsrc/meshing/localh.cpp
@@ -0,0 +1,682 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+
+namespace netgen
+{
+
+GradingBox :: GradingBox (const double * ax1, const double * ax2)
+{
+  int i;
+
+  h2 = 0.5 * (ax2[0] - ax1[0]);
+  for (i = 0; i <= 2; i++)
+    {
+      /*
+      x1[i] = ax1[i];
+      x2[i] = ax2[i];
+      */
+      xmid[i] = 0.5 * (ax1[i] + ax2[i]);
+    }
+
+  /*
+  (*testout) << "new box: " << xmid[0] << "-" << xmid[1] << "-" << xmid[2] 
+	     << " h = " << (x2[0] - x1[0]) << endl;
+  */
+
+  for (i = 0; i < 8; i++)
+    childs[i] = NULL;
+  father = NULL;
+
+  flags.cutboundary = 0;
+  flags.isinner = 0;
+  flags.oldcell = 0;
+  flags.pinner = 0;
+
+  //  hopt = x2[0] - x1[0];
+  hopt = 2 * h2;
+}
+
+
+
+BlockAllocator GradingBox :: ball(sizeof (GradingBox));
+
+void * GradingBox :: operator new(size_t)
+{
+  return ball.Alloc();
+}
+
+void GradingBox :: operator delete (void * p)
+{
+  ball.Free (p);
+}
+
+
+
+
+
+
+
+void GradingBox :: DeleteChilds()
+{
+  int i;
+  for (i = 0; i < 8; i++)
+    if (childs[i])
+      {
+	childs[i]->DeleteChilds();
+	delete childs[i];
+	childs[i] = NULL;
+      }
+}
+
+
+LocalH :: LocalH (const Point3d & pmin, const Point3d & pmax, double agrading)
+{
+  double x1[3], x2[3];
+  double hmax;
+  int i;
+
+  boundingbox = Box3d (pmin, pmax);
+  grading = agrading;
+
+  // a small enlargement, non-regular points 
+  double val = 0.0879;
+  for (i = 1; i <= 3; i++)
+    {
+
+      x1[i-1] = (1 + val * i) * pmin.X(i) - val * i * pmax.X(i);
+      x2[i-1] = 1.1 * pmax.X(i) - 0.1 * pmin.X(i);
+    }
+
+  hmax = x2[0] - x1[0];
+  for (i = 1; i <= 2; i++)
+    if (x2[i] - x1[i] > hmax)
+      hmax = x2[i] - x1[i];
+
+  for (i = 0; i <= 2; i++)
+    x2[i] = x1[i] + hmax;
+
+  root = new GradingBox (x1, x2);
+  boxes.Append (root);
+}
+
+LocalH :: ~LocalH ()
+{
+  root->DeleteChilds();
+  delete root;
+}
+
+void LocalH :: Delete ()
+{
+  root->DeleteChilds();
+}
+
+void LocalH :: SetH (const Point3d & p, double h)
+{
+  /*
+  (*testout) << "Set h at " << p << " to " << h << endl;
+  if (h < 1e-8)
+    {
+      cout << "do not set h to " << h << endl;
+      return;
+    }
+  */
+
+  if (fabs (p.X() - root->xmid[0]) > root->h2 ||
+      fabs (p.Y() - root->xmid[1]) > root->h2 ||
+      fabs (p.Z() - root->xmid[2]) > root->h2)
+    return;
+
+  /*      
+  if (p.X() < root->x1[0] || p.X() > root->x2[0] ||
+      p.Y() < root->x1[1] || p.Y() > root->x2[1] ||
+      p.Z() < root->x1[2] || p.Z() > root->x2[2])
+    return;
+  */
+
+
+  if (GetH(p) <= 1.2 * h) return;
+
+
+  GradingBox * box = root;
+  GradingBox * nbox = root;
+  GradingBox * ngb;
+  int childnr;
+  double x1[3], x2[3];
+
+  while (nbox)
+    {
+      box = nbox;
+      childnr = 0;
+      if (p.X() > box->xmid[0]) childnr += 1;
+      if (p.Y() > box->xmid[1]) childnr += 2;
+      if (p.Z() > box->xmid[2]) childnr += 4;
+      nbox = box->childs[childnr];
+    };
+
+
+  while (2 * box->h2 > h)
+    {
+      childnr = 0;
+      if (p.X() > box->xmid[0]) childnr += 1;
+      if (p.Y() > box->xmid[1]) childnr += 2;
+      if (p.Z() > box->xmid[2]) childnr += 4;
+
+      double h2 = box->h2;
+      if (childnr & 1)
+	{
+	  x1[0] = box->xmid[0];
+	  x2[0] = x1[0]+h2;   // box->x2[0];
+	}
+      else
+	{
+	  x2[0] = box->xmid[0];
+	  x1[0] = x2[0]-h2;   // box->x1[0];
+	}
+
+      if (childnr & 2)
+	{
+	  x1[1] = box->xmid[1];
+	  x2[1] = x1[1]+h2;   // box->x2[1];
+	}
+      else
+	{
+	  x2[1] = box->xmid[1];
+	  x1[1] = x2[1]-h2;   // box->x1[1];
+	}
+
+      if (childnr & 4)
+	{
+	  x1[2] = box->xmid[2];
+	  x2[2] = x1[2]+h2;  // box->x2[2];
+	}
+      else
+	{
+	  x2[2] = box->xmid[2];
+	  x1[2] = x2[2]-h2;  // box->x1[2];
+	}
+
+      ngb = new GradingBox (x1, x2);
+      box->childs[childnr] = ngb;
+      ngb->father = box;
+
+      boxes.Append (ngb);
+      box = box->childs[childnr];
+    }
+
+  box->hopt = h;
+
+
+  double hbox = 2 * box->h2;  // box->x2[0] - box->x1[0];
+  double hnp = h + grading * hbox;
+
+  Point3d np;
+  int i;
+  for (i = 1; i <= 3; i++)
+    {
+      np = p;
+      np.X(i) = p.X(i) + hbox;
+      SetH (np, hnp);
+
+      np.X(i) = p.X(i) - hbox;
+      SetH (np, hnp);
+    }
+  /*
+  Point3d np;
+  int i1, i2, i3;
+  for (i1 = -1; i1 <= 1; i1++)
+    for (i2 = -1; i2 <= 1; i2++)
+      for (i3 = -1; i3 <= 1; i3++)
+	{
+	  np.X() = p.X() + hbox * i1;
+	  np.Y() = p.Y() + hbox * i2;
+	  np.Z() = p.Z() + hbox * i3;
+
+	  SetH (np, hnp);
+	}
+  */
+}
+
+
+
+double LocalH :: GetH (const Point3d & x) const
+{
+  const GradingBox * box = root;
+  const GradingBox * nbox;
+  int childnr;
+
+  while (1)
+    {
+      childnr = 0;
+      if (x.X() > box->xmid[0]) childnr += 1;
+      if (x.Y() > box->xmid[1]) childnr += 2;
+      if (x.Z() > box->xmid[2]) childnr += 4;
+      nbox = box->childs[childnr];
+      if (nbox)
+	box = nbox;
+      else
+	{
+	  //	  (*testout) << "diam = " << (box->x2[0] - box->x1[0])
+	  //		     << " h = " << box->hopt << endl;
+	  return box->hopt;
+	}
+    }
+}
+
+
+/// minimal h in box (pmin, pmax)
+double LocalH :: GetMinH (const Point3d & pmin, const Point3d & pmax) const
+{ 
+  Point3d pmin2, pmax2;
+  for (int j = 1; j <= 3; j++)
+    if (pmin.X(j) < pmax.X(j))
+      { pmin2.X(j) = pmin.X(j); pmax2.X(j) = pmax.X(j); }
+    else
+      { pmin2.X(j) = pmax.X(j); pmax2.X(j) = pmin.X(j); }
+
+  return GetMinHRec (pmin2, pmax2, root); 
+}
+
+
+double LocalH :: GetMinHRec (const Point3d & pmin, const Point3d & pmax,
+			     const GradingBox * box) const
+{
+  double h2 = box->h2;
+  if (pmax.X() < box->xmid[0]-h2 || pmin.X() > box->xmid[0]+h2 ||
+      pmax.Y() < box->xmid[1]-h2 || pmin.Y() > box->xmid[1]+h2 ||
+      pmax.Z() < box->xmid[2]-h2 || pmin.Z() > box->xmid[2]+h2)
+    return 1e8;
+  /*
+  if (pmax.X() < box->x1[0] || pmin.X() > box->x2[0] ||
+      pmax.Y() < box->x1[1] || pmin.Y() > box->x2[1] ||
+      pmax.Z() < box->x1[2] || pmin.Z() > box->x2[2])
+    return 1e8;
+  */
+
+      
+  double hmin = 2 * box->h2; // box->x2[0] - box->x1[0];
+  int i;
+  
+  for (i = 0; i <= 7; i++)
+    {
+      if (box->childs[i])
+	{
+	  double hi = GetMinHRec (pmin, pmax, box->childs[i]);
+	  if (hi < hmin)
+	    hmin = hi;
+	}	  
+    }
+
+  return hmin;
+}
+
+
+void LocalH :: CutBoundaryRec (const Point3d & pmin, const Point3d & pmax,
+			       GradingBox * box)
+{
+  double h2 = box->h2;
+  if (pmax.X() < box->xmid[0]-h2 || pmin.X() > box->xmid[0]+h2 ||
+      pmax.Y() < box->xmid[1]-h2 || pmin.Y() > box->xmid[1]+h2 ||
+      pmax.Z() < box->xmid[2]-h2 || pmin.Z() > box->xmid[2]+h2)
+    return;
+  /*
+  if (pmax.X() < box->x1[0] || pmin.X() > box->x2[0] ||
+      pmax.Y() < box->x1[1] || pmin.Y() > box->x2[1] ||
+      pmax.Z() < box->x1[2] || pmin.Z() > box->x2[2])
+    return;
+  */
+
+  box->flags.cutboundary = 1;
+  for (int i = 0; i < 8; i++)
+    if (box->childs[i])
+      CutBoundaryRec (pmin, pmax, box->childs[i]);
+}
+
+
+
+
+void LocalH :: FindInnerBoxes ( // int (*sameside)(const Point3d & p1, const Point3d & p2),
+			       AdFront3 * adfront,
+			       int (*testinner)(const Point3d & p1))
+{
+  int i, j;
+
+  int nf = adfront->GetNF();
+
+  for (i = 0; i < boxes.Size(); i++)
+    boxes[i] -> flags.isinner = 0;
+
+  root->flags.isinner = 0;
+
+  Point3d rpmid(root->xmid[0], root->xmid[1], root->xmid[2]);
+  Vec3d rv(root->h2, root->h2, root->h2);
+  Point3d rx2 = rpmid + rv;
+  Point3d rx1 = rpmid - rv;
+
+
+  root->flags.pinner = !adfront->SameSide (rpmid, rx2);
+  
+  if (testinner)
+    (*testout) << "inner = " << root->flags.pinner << " =?= " 
+	       << testinner(Point3d(root->xmid[0], root->xmid[1], root->xmid[2])) << endl;
+  
+  ARRAY<int> faceinds(nf);
+  ARRAY<Box3d> faceboxes(nf);
+
+  for (i = 1; i <= nf; i++)
+    {
+      faceinds.Elem(i) = i;
+      adfront->GetFaceBoundingBox(i, faceboxes.Elem(i));
+    }
+  
+  for (i = 0; i < 8; i++)
+    FindInnerBoxesRec2 (root->childs[i], adfront, faceboxes, faceinds, nf);
+}
+
+
+void LocalH :: 
+FindInnerBoxesRec2 (GradingBox * box,
+		    class AdFront3 * adfront, 
+		    ARRAY<Box3d> & faceboxes,
+		    ARRAY<int> & faceinds, int nfinbox)
+{
+  if (!box) return;
+  
+  int i, j;
+  
+  GradingBox * father = box -> father;
+  
+  Point3d c(box->xmid[0], box->xmid[1], box->xmid[2]);
+  Vec3d v(box->h2, box->h2, box->h2);
+  Box3d boxc(c-v, c+v);
+
+  Point3d fc(father->xmid[0], father->xmid[1], father->xmid[2]);
+  Vec3d fv(father->h2, father->h2, father->h2);
+  Box3d fboxc(fc-fv, fc+fv);
+
+  Box3d boxcfc(c,fc);
+
+
+  static ARRAY<int> faceused;
+  static ARRAY<int> faceused2;
+  static ARRAY<int> facenotused;
+
+  faceused.SetSize(0);
+  facenotused.SetSize(0);
+  faceused2.SetSize(0);
+
+  for (j = 1; j <= nfinbox; j++)
+    {
+      //      adfront->GetFaceBoundingBox (faceinds.Get(j), facebox);
+      const Box3d & facebox = faceboxes.Get(faceinds.Get(j));
+  
+      if (boxc.Intersect (facebox))
+	faceused.Append(faceinds.Get(j));
+      else
+	facenotused.Append(faceinds.Get(j));
+
+      if (boxcfc.Intersect (facebox))
+	faceused2.Append (faceinds.Get(j));
+    }
+  
+  for (j = 1; j <= faceused.Size(); j++)
+    faceinds.Elem(j) = faceused.Get(j);
+  for (j = 1; j <= facenotused.Size(); j++)
+    faceinds.Elem(j+faceused.Size()) = facenotused.Get(j);
+
+  
+  if (!father->flags.cutboundary)
+    {
+      box->flags.isinner = father->flags.isinner;
+      box->flags.pinner = father->flags.pinner;
+    }
+  else
+    {
+      Point3d cf(father->xmid[0], father->xmid[1], father->xmid[2]);
+      
+      if (father->flags.isinner)
+	box->flags.pinner = 1;
+      else
+	{
+	  if (adfront->SameSide (c, cf, &faceused2))
+	    box->flags.pinner = father->flags.pinner;
+	  else
+	    box->flags.pinner = 1 - father->flags.pinner;
+	}
+      
+      if (box->flags.cutboundary)
+	box->flags.isinner = 0;
+      else
+	box->flags.isinner = box->flags.pinner;
+    }
+
+  int nf = faceused.Size();
+  for (i = 0; i < 8; i++)
+    FindInnerBoxesRec2 (box->childs[i], adfront, faceboxes, faceinds, nf);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+/*
+void LocalH :: FindInnerBoxes ( // int (*sameside)(const Point3d & p1, const Point3d & p2),
+			       AdFront3 * adfront,
+			       int (*testinner)(const Point3d & p1))
+{
+  int i;
+  for (i = 1; i <= boxes.Size(); i++)
+    boxes.Elem(i)->flags.isinner = 0;
+
+  root->flags.isinner = 0;
+
+  Point3d rpmid(root->xmid[0], root->xmid[1], root->xmid[2]);
+  Point3d rx2 = rpmid + Vec3d (root->h2, root->h2, root->h2);
+
+  root->flags.pinner = !adfront->SameSide (rpmid, rx2);
+  
+  if (testinner)
+    (*testout) << "inner = " << root->flags.pinner << " =?= " 
+	       << testinner(Point3d(root->xmid[0], root->xmid[1], root->xmid[2])) << endl;
+  
+
+  for (i = 2; i <= boxes.Size(); i++)
+    {
+      GradingBox * box = boxes.Elem(i);
+      GradingBox * father = box -> father;
+
+      Point3d c(box->xmid[0], box->xmid[1], box->xmid[2]);
+      Vec3d v(box->h2, box->h2, box->h2);
+      Point3d x1 = c-v;
+      Point3d x2 = c+v;
+
+
+      if (!father->flags.cutboundary)
+	{
+	  box->flags.isinner = father->flags.isinner;
+	  box->flags.pinner = father->flags.pinner;
+	}
+      else
+	{
+	  Point3d cf(father->xmid[0], father->xmid[1], father->xmid[2]);
+
+	  if (father->flags.isinner)
+	    box->flags.pinner = 1;
+	  else
+	    {
+	      if (adfront->SameSide (c, cf))
+		box->flags.pinner = father->flags.pinner;
+	      else
+		box->flags.pinner = 1 - father->flags.pinner;
+	    }
+
+	  if (box->flags.cutboundary)
+	    box->flags.isinner = 0;
+	  else
+	    box->flags.isinner = box->flags.pinner;
+	}
+    }
+  //  FindInnerBoxesRec (inner, root);
+}
+*/
+
+
+void LocalH :: FindInnerBoxesRec ( int (*inner)(const Point3d & p),
+				   GradingBox * box)
+{
+  int i;
+  if (box->flags.cutboundary)
+    {
+      for (i = 0; i < 8; i++)
+	if (box->childs[i])
+	  FindInnerBoxesRec (inner, box->childs[i]);
+    }
+  else
+    {
+      if (inner (Point3d (box->xmid[0], box->xmid[1], box->xmid[2])))
+	SetInnerBoxesRec (box);
+    }
+}
+
+
+void LocalH :: SetInnerBoxesRec (GradingBox * box)
+{
+  box->flags.isinner = 1;
+  for (int i = 0; i < 8; i++)
+    if (box->childs[i])
+      ClearFlagsRec (box->childs[i]);
+}
+
+void LocalH :: ClearFlagsRec (GradingBox * box)
+{
+  box->flags.cutboundary = 0;
+  box->flags.isinner = 0;
+  for (int i = 0; i < 8; i++)
+    if (box->childs[i])
+      ClearFlagsRec (box->childs[i]);
+}
+
+
+void LocalH :: WidenRefinement ()
+{
+  int nb = boxes.Size(); 
+  int i;
+  //  (*testout) << "old boxes: " << nb << endl;
+  for (i = 1; i <= nb; i++)
+    {
+      GradingBox * box = boxes.Get(i);
+      //      double h = box->x2[0] - box->x1[0];
+      double h = box->hopt;
+      Point3d c(box->xmid[0], box->xmid[1], box->xmid[2]);
+      //      (*testout) << " i = " << i 
+      //		 << " c = " << c << " h = " << h << endl;
+
+      for (int i1 = -1; i1 <= 1; i1++)
+	for (int i2 = -1; i2 <= 1; i2++)
+	  for (int i3 = -1; i3 <= 1; i3++)
+	    SetH (Point3d (c.X() + i1 * h, 
+			   c.Y() + i2 * h,
+			   c.Z() + i3 * h), 1.001 * h);     
+    }
+}
+
+void LocalH :: GetInnerPoints (ARRAY<Point3d> & points)
+{
+  int i, nb = boxes.Size(); 
+
+  for (i = 1; i <= nb; i++)
+    {
+      GradingBox * box = boxes.Get(i);
+      /*
+      if (box->flags.pinner)
+	points.Append (box->randomip);
+      */
+      //      if (box->flags.pinner)
+      if (box->flags.isinner)
+	{
+	  Point3d c(box->xmid[0], box->xmid[1], box->xmid[2]);
+	  points.Append (c);
+	  /*
+	  cout << "add point " << c << "; h = " << box->hopt
+	       << "; max-min = " << (box->x2[0]-box->x1[0]) << endl;
+	  */
+	}
+    }
+}
+
+
+
+void LocalH :: GetOuterPoints (ARRAY<Point3d> & points)
+{
+  int i, nb = boxes.Size(); 
+
+  for (i = 1; i <= nb; i++)
+    {
+      GradingBox * box = boxes.Get(i);
+      if (!box->flags.isinner &&
+	  !box->flags.cutboundary)
+	{
+	  Point3d c(box->xmid[0], box->xmid[1], box->xmid[2]);
+	  points.Append (c);
+	}
+    }
+}
+
+
+
+void LocalH :: Convexify ()
+{
+  ConvexifyRec (root);
+}
+
+void LocalH :: ConvexifyRec (GradingBox * box)
+{
+  Point3d center(box->xmid[0], box->xmid[1], box->xmid[2]);
+  Point3d hp;
+
+  double size = 2 * box->h2; // box->x2[0] - box->x1[0];
+  double dx = 0.6 * size;
+
+  double maxh = box->hopt;
+  int i;
+
+  
+  
+  for (i = 1; i <= 6; i++)
+    {
+      hp = center;
+      switch (i)
+	{
+	case 1: hp.X() += dx; break;
+	case 2: hp.X() -= dx; break;
+	case 3: hp.Y() += dx; break;
+	case 4: hp.Y() -= dx; break;
+	case 5: hp.Z() += dx; break;
+	case 6: hp.Z() -= dx; break;
+	}
+      
+      double hh = GetH (hp);
+      if (hh > maxh) maxh = hh;
+    }
+
+  if (maxh < 0.95 * box->hopt)
+    SetH (center, maxh);
+
+  for (i = 0; i < 8; i++)
+    if (box->childs[i])
+      ConvexifyRec (box->childs[i]);  
+}
+
+void LocalH :: PrintMemInfo (ostream & ost) const
+{
+  ost << "LocalH: " << boxes.Size() << " boxes of " << sizeof(GradingBox)
+      << " bytes = " << boxes.Size()*sizeof(GradingBox) << " bytes" << endl;
+}
+}
diff --git a/Netgen/libsrc/meshing/localh.hpp b/Netgen/libsrc/meshing/localh.hpp
new file mode 100644
index 0000000000..9d6ea35a50
--- /dev/null
+++ b/Netgen/libsrc/meshing/localh.hpp
@@ -0,0 +1,143 @@
+#ifndef LOCALH
+#define LOCALH
+
+/**************************************************************************/
+/* File:   localh.hh                                                      */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   29. Jan. 97                                                    */
+/**************************************************************************/
+
+
+
+
+/// box for grading
+class GradingBox
+{
+  /*
+  /// xmin
+  float x1[3];
+  /// xmax
+  float x2[3];
+  */
+  /// xmid
+  float xmid[3];
+  /// half edgelength
+  float h2;
+  ///
+  GradingBox * childs[8];
+  ///
+  GradingBox * father;
+  ///
+  double hopt;
+  ///
+  struct 
+  {
+    unsigned int cutboundary:1;
+    unsigned int isinner:1;
+    unsigned int oldcell:1;
+    unsigned int pinner:1;
+  } flags;
+public:
+  ///
+  GradingBox (const double * ax1, const double * ax2);
+  ///
+  void DeleteChilds();
+  ///
+  friend class LocalH;
+
+
+  static BlockAllocator ball;
+  void * operator new(size_t);
+  void operator delete (void *);
+};
+
+
+
+/**
+   Control of 3D mesh grading
+ */
+class LocalH 
+{
+  ///
+  GradingBox * root;
+  ///
+  double grading;
+  ///
+  ARRAY<GradingBox*> boxes;
+  ///
+  Box3d boundingbox;
+public:
+  ///
+  LocalH (const Point3d & pmin, const Point3d & pmax, double grading);
+  ///
+  ~LocalH();
+  ///
+  void Delete();
+  ///
+  void SetH (const Point3d & x, double h);
+  ///
+  double GetH (const Point3d & x) const;
+  /// minimal h in box (pmin, pmax)
+  double GetMinH (const Point3d & pmin, const Point3d & pmax) const;
+
+  /// mark boxes intersecting with boundary-box
+  void CutBoundary (const Point3d & pmin, const Point3d & pmax)
+    { CutBoundaryRec (pmin, pmax, root); }
+
+  /// find inner boxes
+  void FindInnerBoxes ( // int (*sameside)(const Point3d & p1, const Point3d & p2),
+		       class AdFront3 * adfront,
+		       int (*testinner)(const Point3d & p1));
+
+  /// clears all flags 
+  void ClearFlags ()
+    { ClearFlagsRec(root); }
+
+  /// widen refinement zone
+  void WidenRefinement ();
+
+  /// get points in inner elements
+  void GetInnerPoints (ARRAY<Point3d> & points);
+
+  /// get points in outer closure
+  void GetOuterPoints (ARRAY<Point3d> & points);
+
+  ///
+  void Convexify ();
+  ///
+  int GetNBoxes () { return boxes.Size(); } 
+  const Box3d & GetBoundingBox () const
+  { return boundingbox; }
+  ///
+  void PrintMemInfo (ostream & ost) const;
+private:
+  /// 
+  double GetMinHRec (const Point3d & pmin, const Point3d & pmax,
+		     const GradingBox * box) const;
+  ///
+  void CutBoundaryRec (const Point3d & pmin, const Point3d & pmax,
+		       GradingBox * box);
+
+  ///
+  void FindInnerBoxesRec ( int (*inner)(const Point3d & p),
+			   GradingBox * box);
+
+  ///
+  void FindInnerBoxesRec2 (GradingBox * box,
+			   class AdFront3 * adfront,
+			   ARRAY<Box3d> & faceboxes,
+			   ARRAY<int> & finds, int nfinbox);
+
+
+  ///
+  void SetInnerBoxesRec (GradingBox * box);
+
+  ///
+  void ClearFlagsRec (GradingBox * box);
+  
+  ///
+  void ConvexifyRec (GradingBox * box);
+};
+
+
+#endif
diff --git a/Netgen/libsrc/meshing/meshclass.cpp b/Netgen/libsrc/meshing/meshclass.cpp
new file mode 100644
index 0000000000..668c1f3d6e
--- /dev/null
+++ b/Netgen/libsrc/meshing/meshclass.cpp
@@ -0,0 +1,4165 @@
+#include <mystdlib.h>
+
+#include "meshing.hpp"
+
+namespace netgen
+{
+
+Mesh :: Mesh ()
+  : ident (*this)
+
+{
+  boundaryedges = NULL;
+  surfelementht = NULL; 
+  segmentht = NULL;
+
+  lochfunc = NULL;
+  mglevels = 1;
+  elementsearchtree = NULL;
+  elementsearchtreets = NextTimeStamp();
+  majortimestamp = timestamp = NextTimeStamp();
+  hglob = 1e10;
+  numvertices = -1;
+  dimension = 3;
+  topology = new MeshTopology (*this);
+  curvedelems = new CurvedElements (*this);
+  clusters = new AnisotropicClusters (*this);
+
+  //  volelements.SetName ("Volume Elements");
+  //  surfelements.SetName ("Surface Elements");
+  //  points.SetName ("Mesh Points");
+}
+
+Mesh :: ~Mesh()
+{
+  // DeleteMesh();
+  delete lochfunc;
+  delete boundaryedges;
+  delete surfelementht;
+  delete segmentht;
+  delete curvedelems;
+  delete clusters;
+  delete topology;
+}
+
+void Mesh :: DeleteMesh()
+{
+  points.SetSize(0);
+  ptyps.SetSize(0);
+  segments.SetSize(0);
+  surfelements.SetSize(0);
+  volelements.SetSize(0);
+  lockedpoints.SetSize(0);
+  surfacesonnode.SetSize(0);
+
+  delete boundaryedges;
+  boundaryedges = NULL;
+
+  openelements.SetSize(0);
+  facedecoding.SetSize(0);
+
+  ident.Delete();
+
+  delete topology;
+  topology = new MeshTopology (*this);
+  delete curvedelems;
+  curvedelems = new CurvedElements (*this);
+  delete clusters;
+  clusters = new AnisotropicClusters (*this);
+
+  timestamp = NextTimeStamp();
+}
+
+
+
+PointIndex Mesh :: AddPoint (const Point3d & p, int layer)
+{ 
+  NgLock lock(mutex);
+  lock.Lock();
+
+  timestamp = NextTimeStamp();
+
+  if (ptyps.Size() == points.Size())
+    ptyps.Append (INNERPOINT);
+
+  PointIndex pi = points.Size() + PointIndex::BASE;
+  points.Append ( MeshPoint (p, layer) ); 
+
+  lock.UnLock();
+
+  return pi;
+}
+
+
+SegmentIndex Mesh :: AddSegment (const Segment & s)
+{ 
+  NgLock lock(mutex);	
+  lock.Lock();
+  timestamp = NextTimeStamp();
+
+  int maxn = max2 (s.p1, s.p2);
+  maxn += 1-PointIndex::BASE;
+
+  if (maxn > ptyps.Size())
+    {
+      int maxo = ptyps.Size();
+      ptyps.SetSize (maxn);
+      for (int i = maxo; i < maxn; i++)
+	ptyps[i] = INNERPOINT;
+    }
+
+  if (ptyps[s.p1] > EDGEPOINT) ptyps[s.p1] = EDGEPOINT;
+  if (ptyps[s.p2] > EDGEPOINT) ptyps[s.p2] = EDGEPOINT;
+  
+  SegmentIndex si = segments.Size();
+  segments.Append (s); 
+  
+  lock.UnLock();
+  return si;
+}
+
+SurfaceElementIndex Mesh :: AddSurfaceElement (const Element2d & el)
+{     
+  NgLock lock(mutex);
+  lock.Lock();
+  timestamp = NextTimeStamp();
+
+  int i;
+  int maxn = el[0];
+  for (i = 1; i < el.GetNP(); i++)
+    if (el[i] > maxn) maxn = el[i];
+
+  maxn += 1-PointIndex::BASE;
+
+  if (maxn > ptyps.Size())
+    {
+      int maxo = ptyps.Size();
+      ptyps.SetSize (maxn);
+      for (i = maxo+PointIndex::BASE; 
+	   i < maxn+PointIndex::BASE; i++)
+	ptyps[i] = INNERPOINT;
+    }
+
+  for (i = 0; i < el.GetNP(); i++)
+    if (ptyps[el[i]] > SURFACEPOINT)
+      ptyps[el[i]] = SURFACEPOINT;
+
+  SurfaceElementIndex si = surfelements.Size();
+  surfelements.Append (el); 
+
+  lock.UnLock();
+  return si;
+}
+
+
+ElementIndex Mesh :: AddVolumeElement (const Element & el)
+{ 
+  NgLock lock(mutex);
+  lock.Lock();
+
+  int i;
+
+  int maxn = el[0];
+  for (i = 1; i < el.GetNP(); i++)
+    if (el[i] > maxn) maxn = el[i];
+
+  maxn += 1-PointIndex::BASE;
+
+  if (maxn > ptyps.Size())
+    {
+      int maxo = ptyps.Size();
+      ptyps.SetSize (maxn);
+      for (i = maxo+PointIndex::BASE; 
+	   i < maxn+PointIndex::BASE; i++)
+	ptyps[i] = INNERPOINT;
+    }
+
+
+  int ve = volelements.Size();
+
+  volelements.Append (el); 
+  volelements.Last().flags.illegal_valid = 0;
+
+  while (volelements.Size() > eltyps.Size())
+    eltyps.Append (FREEELEMENT);
+  
+  timestamp = NextTimeStamp();
+
+  lock.UnLock();
+  return ve;
+}
+
+
+
+
+
+
+void Mesh :: Save (const char * filename) const
+{
+  int i, j;
+
+  double scale = 1;  // globflags.GetNumFlag ("scale", 1);
+  int inverttets = 0;  // globflags.GetDefineFlag ("inverttets");
+  int invertsurf = 0;  // globflags.GetDefineFlag ("invertsurfacemesh");
+
+  ofstream outfile(filename);
+
+
+  outfile << "mesh3d" << "\n";
+
+  outfile << "dimension\n" << GetDimension() << "\n";
+
+  outfile << "\n";
+  outfile << "# surfnr    bcnr   domin  domout      np      p1      p2      p3"
+	  << "\n";
+
+  outfile << "surfaceelementsgi" << "\n";
+  //  outfile << "surfaceelements" << "\n";
+  outfile << GetNSE() << "\n";
+
+  SurfaceElementIndex sei;
+  for (sei = 0; sei < GetNSE(); sei++)
+    {
+      if ((*this)[sei].GetIndex())
+	{
+	  outfile.width(8);
+	  outfile << GetFaceDescriptor((*this)[sei].GetIndex ()).SurfNr()+1;
+	  outfile.width(8);
+	  outfile << GetFaceDescriptor((*this)[sei].GetIndex ()).BCProperty();
+	  outfile.width(8);	  
+	  outfile << GetFaceDescriptor((*this)[sei].GetIndex ()).DomainIn();
+	  outfile.width(8);	  
+	  outfile << GetFaceDescriptor((*this)[sei].GetIndex ()).DomainOut();
+	}
+      else
+	outfile << "       0       0       0";
+
+
+      Element2d sel = (*this)[sei];
+      if (invertsurf)
+	sel.Invert();
+
+      outfile.width(8);
+      outfile << sel.GetNP();
+
+      for (j = 0; j < sel.GetNP(); j++)
+	{
+	  outfile.width(8);	  
+	  outfile << sel[j];
+	}
+
+      for (j = 1; j <= sel.GetNP(); j++)
+	{
+	  outfile.width(7);	  
+	  outfile << " " << sel.GeomInfoPi(j).trignum;
+	}
+      outfile << endl;
+    }
+
+  outfile << "\n" << "\n";
+  outfile << "#  matnr      np      p1      p2      p3      p4" << "\n";
+  outfile << "volumeelements" << "\n";
+  outfile << GetNE() << "\n";
+
+  for (ElementIndex ei = 0; ei < GetNE(); ei++)
+    {
+      outfile.width(8);
+      outfile << (*this)[ei].GetIndex();
+      outfile.width(8);
+      outfile << (*this)[ei].GetNP();
+
+      Element el = (*this)[ei];
+      if (inverttets)
+	el.Invert();
+
+      for (j = 0; j < el.GetNP(); j++)
+	{
+	  outfile.width(8);
+	  outfile << el[j];
+	}
+      outfile << "\n";
+    }
+
+
+  outfile << "\n" << "\n";
+  outfile << "   surf1   surf2      p1      p2" << "\n";
+  outfile << "edgesegmentsgi2" << "\n";
+  outfile << GetNSeg() << "\n";
+
+  for (i = 1; i <= GetNSeg(); i++)
+    {
+      const Segment & seg = LineSegment (i);
+      outfile.width(8);
+      outfile << seg.si;
+      outfile.width(8);
+      outfile << 0;
+      outfile.width(8);
+      outfile << seg.p1;
+      outfile.width(8);
+      outfile << seg.p2;
+      outfile << " ";
+      outfile.width(8);
+      outfile << seg.geominfo[0].trignum;
+      outfile << " ";
+      outfile.width(8);
+      outfile << seg.geominfo[1].trignum << endl;
+
+      outfile << " ";
+      outfile.width(8);
+      outfile << seg.surfnr1+1;
+      outfile << " ";
+      outfile.width(8);
+      outfile << seg.surfnr2+1;
+      outfile << " ";
+      outfile.width(8);
+      outfile << seg.edgenr;
+      //      outfile << seg.epgeominfo[0].edgenr;
+      /*
+      outfile.width(8);
+      outfile << seg.epgeominfo[0].lefttrig;
+      outfile.width(8);
+      outfile << seg.epgeominfo[0].righttrig;
+      */
+      outfile << " ";
+      outfile.width(12);
+      outfile << seg.epgeominfo[0].dist;
+      outfile << " ";
+      outfile.width(8);
+      outfile << seg.epgeominfo[1].edgenr;
+      /*
+      outfile.width(8);
+      outfile << seg.epgeominfo[1].lefttrig;
+      outfile.width(8);
+      outfile << seg.epgeominfo[1].righttrig;
+      */
+      outfile << " ";
+      outfile.width(12);
+      outfile << seg.epgeominfo[1].dist;
+
+      outfile << "\n";
+    }
+
+
+
+
+  outfile << "\n" << "\n";
+  outfile << "#          X             Y             Z" << "\n";
+  outfile << "points" << "\n";
+  outfile << GetNP() << "\n";
+  outfile.precision(16);
+  outfile.setf (ios::fixed, ios::floatfield);
+  outfile.setf (ios::showpoint);
+
+  PointIndex pi;
+  for (pi = 1; pi <= GetNP(); pi++)
+    {
+      outfile.width(22);
+      outfile << (*this)[pi].X()/scale << "  ";
+      outfile.width(22);
+      outfile << (*this)[pi].Y()/scale << "  ";
+      outfile.width(22);
+      outfile << (*this)[pi].Z()/scale << "\n";
+    }      
+
+  if (ident.GetMaxNr() > 0)
+    {
+      outfile << "identifications\n";
+      ARRAY<INDEX_2> identpairs;
+      int cnt = 0;
+      for (i = 1; i <= ident.GetMaxNr(); i++)
+	{
+	  ident.GetPairs (i, identpairs);
+	  cnt += identpairs.Size();
+	}
+      outfile << cnt << "\n";
+      for (i = 1; i <= ident.GetMaxNr(); i++)
+	{
+	  ident.GetPairs (i, identpairs);
+	  for (j = 1; j <= identpairs.Size(); j++)
+	    {
+	      outfile.width (8);
+	      outfile << identpairs.Get(j).I1();
+	      outfile.width (8);
+	      outfile << identpairs.Get(j).I2();
+	      outfile.width (8);
+	      outfile << i << "\n";
+	    }
+	}
+    }
+
+  int cntmat = 0;
+  for (i = 1; i <= materials.Size(); i++)
+    if (materials.Get(i) && strlen (materials.Get(i)))
+      cntmat++;
+
+  if (cntmat)
+    {
+      outfile << "materials" << endl;
+      outfile << cntmat << endl;
+      for (i = 1; i <= materials.Size(); i++)
+	if (materials.Get(i) && strlen (materials.Get(i)))
+	  outfile << i << " " << materials.Get(i) << endl;
+    }
+
+  //  delete houtfile;
+}
+
+
+void Mesh :: Load (const char * filename)
+{
+  char str[100];
+  int i, n;
+
+  double scale = 1;  // globflags.GetNumFlag ("scale", 1);
+  int inverttets = 0;  // globflags.GetDefineFlag ("inverttets");
+  int invertsurf = 0;  // globflags.GetDefineFlag ("invertsurfacemesh");
+
+
+  ifstream infile(filename);
+  if (!infile.good())
+    {
+      throw NgException ("mesh file not found");
+      //      cerr << "mesh file not found !!" << endl;
+      //      return;
+    }
+
+  facedecoding.SetSize(0);
+
+  while (infile.good())
+    {
+      infile >> str;
+
+      if (strcmp (str, "dimension") == 0)
+	{
+	  infile >> dimension;
+	}
+
+      if (strcmp (str, "surfaceelements") == 0)
+	{
+	  infile >> n;
+	  PrintMessage (3, n, " surface elements");
+	  for (i = 1; i <= n; i++)
+	    {
+	      int j;
+	      int surfnr, bcp, domin, domout, nep, faceind = 0;
+
+	      infile >> surfnr >> bcp >> domin >> domout;
+	      surfnr--;
+
+	      for (j = 1; j <= facedecoding.Size(); j++)
+		if (GetFaceDescriptor(j).SurfNr() == surfnr &&
+		    GetFaceDescriptor(j).BCProperty() == bcp &&
+		    GetFaceDescriptor(j).DomainIn() == domin &&
+		    GetFaceDescriptor(j).DomainOut() == domout)
+		  faceind = j;
+
+	      if (!faceind)
+		{
+		  faceind = AddFaceDescriptor (FaceDescriptor(surfnr, domin, domout, 0));
+		  GetFaceDescriptor(faceind).SetBCProperty (bcp);
+		}
+
+	      infile >> nep;
+	      if (!nep) nep = 3;
+
+	      Element2d tri(nep);
+	      tri.SetIndex(faceind);
+
+	      for (j = 1; j <= nep; j++)
+		infile >> tri.PNum(j);
+
+	      if (invertsurf)
+		tri.Invert();
+
+	      AddSurfaceElement (tri);
+	    }
+	}
+
+      if (strcmp (str, "surfaceelementsgi") == 0)
+	{
+	  infile >> n;
+	  PrintMessage (3, n, " surface elements");
+	  for (i = 1; i <= n; i++)
+	    {
+	      int j;
+	      int surfnr, bcp, domin, domout, nep, faceind = 0;
+	      infile >> surfnr >> bcp >> domin >> domout;
+	      surfnr--;
+
+	      for (j = 1; j <= facedecoding.Size(); j++)
+		if (GetFaceDescriptor(j).SurfNr() == surfnr &&
+		    GetFaceDescriptor(j).BCProperty() == bcp &&
+		    GetFaceDescriptor(j).DomainIn() == domin &&
+		    GetFaceDescriptor(j).DomainOut() == domout)
+		  faceind = j;
+
+	      if (!faceind)
+		{
+		  faceind = AddFaceDescriptor (FaceDescriptor(surfnr, domin, domout, 0));
+		  GetFaceDescriptor(faceind).SetBCProperty (bcp);
+		}
+
+	      infile >> nep;
+	      if (!nep) nep = 3;
+
+	      Element2d tri(nep);
+	      tri.SetIndex(faceind);
+
+	      for (j = 1; j <= nep; j++)
+		infile >> tri.PNum(j);
+
+	      for (j = 1; j <= nep; j++)
+		infile >> tri.GeomInfoPi(j).trignum;
+
+	      if (invertsurf)
+		tri.Invert();
+
+	      AddSurfaceElement (tri);
+	    }
+	}
+
+
+
+      if (strcmp (str, "volumeelements") == 0)
+	{
+	  infile >> n;
+	  PrintMessage (3, n, " volume elements");
+	  for (i = 1; i <= n; i++)
+	    {
+	      Element el;
+	      int hi, nep;
+	      infile >> hi;
+	      if (hi == 0) hi = 1;
+	      el.SetIndex(hi);
+	      infile >> nep;
+	      el.SetNP(nep);
+	      
+	      for (int j = 0; j < nep; j++)
+		infile >> (int&)(el[j]);
+	      
+	      if (inverttets)
+		el.Invert();
+
+	      AddVolumeElement (el);
+	      
+	    }
+	}
+
+      if (strcmp (str, "edgesegments") == 0)
+	{
+	  infile >> n;
+	  for (i = 1; i <= n; i++)
+	    {
+	      Segment seg;
+	      int hi;
+	      infile >> seg.si >> hi >> seg.p1 >> seg.p2;
+	      AddSegment (seg);
+	    }
+	}
+      
+      if (strcmp (str, "edgesegmentsgi") == 0)
+	{
+	  infile >> n;
+	  for (i = 1; i <= n; i++)
+	    {
+	      Segment seg;
+	      int hi;
+	      infile >> seg.si >> hi >> seg.p1 >> seg.p2
+		     >> seg.geominfo[0].trignum
+		     >> seg.geominfo[1].trignum;
+	      AddSegment (seg);
+	    }
+	}
+      if (strcmp (str, "edgesegmentsgi2") == 0)
+	{
+	  infile >> n;
+	  PrintMessage (3, n, " curve elements");
+
+	  for (i = 1; i <= n; i++)
+	    {
+	      Segment seg;
+	      int hi;
+	      infile >> seg.si >> hi >> seg.p1 >> seg.p2
+		     >> seg.geominfo[0].trignum
+		     >> seg.geominfo[1].trignum
+		     >> seg.surfnr1 >> seg.surfnr2
+		     >> seg.epgeominfo[0].edgenr
+		//		     >> seg.epgeominfo[0].lefttrig
+		//		     >> seg.epgeominfo[0].righttrig
+		     >> seg.epgeominfo[0].dist
+		     >> seg.epgeominfo[1].edgenr
+		//		     >> seg.epgeominfo[1].lefttrig
+		//		     >> seg.epgeominfo[1].righttrig
+		     >> seg.epgeominfo[1].dist;
+	      seg.edgenr = seg.epgeominfo[0].edgenr;
+
+	      seg.surfnr1--;
+	      seg.surfnr2--;
+	      
+	      AddSegment (seg);
+	    }
+	}
+      
+      if (strcmp (str, "points") == 0)
+	{
+	  infile >> n;
+	  PrintMessage (3, n, " points");
+	  for (i = 1; i <= n; i++)
+	    {
+	      Point3d p;
+	      infile >> p.X() >> p.Y() >> p.Z();
+	      p.X() *= scale;
+	      p.Y() *= scale;
+	      p.Z() *= scale;
+	      AddPoint (p);
+	    }
+	}
+
+      if (strcmp (str, "identifications") == 0)
+	{
+	  infile >> n;
+	  for (i = 1; i <= n; i++)
+	    {
+	      PointIndex pi1, pi2;
+	      int ind;
+	      infile >> pi1 >> pi2 >> ind;
+	      ident.Add (pi1, pi2, ind);
+	    }
+	}
+      if (strcmp (str, "materials") == 0)
+	{
+	  infile >> n;
+	  for (i = 1; i <= n; i++)
+	    {
+	      int nr;
+	      string mat;
+	      infile >> nr >> mat;
+	      SetMaterial (nr, mat.c_str());
+	    }
+	}
+
+      strcpy (str, "");
+    }
+  
+  CalcSurfacesOfNode ();
+  //  BuildConnectedNodes ();
+  topology -> Update();
+  clusters -> Update();
+  
+  SetNextMajorTimeStamp();
+  //  PrintMemInfo (cout);
+}
+  
+   
+
+bool Mesh :: TestOk () const
+{
+  for (ElementIndex ei = 0; ei < volelements.Size(); ei++)
+    {
+      for (int j = 0; j < 4; j++)
+	if ( (*this)[ei][j] <= PointIndex::BASE-1)
+	  {
+	    (*testout) << "El " << ei << " has 0 nodes: ";
+	    for (int k = 0; k < 4; k++)
+	      (*testout) << (*this)[ei][k];
+	    break;
+	  }
+    }
+  CheckMesh3D (*this);
+  return 1;
+}
+
+void Mesh :: CalcSurfacesOfNode ()
+{
+  int i, j, k;
+  SurfaceElementIndex sei;
+
+  surfacesonnode.SetSize (GetNP());
+  if (boundaryedges)
+    delete boundaryedges;
+  if (surfelementht)
+    delete surfelementht;
+  if (segmentht)
+    delete segmentht;
+
+  boundaryedges = new INDEX_2_CLOSED_HASHTABLE<int>
+    (3 * (GetNSE() + GetNOpenElements()) + GetNSeg() + 1);
+  surfelementht = new INDEX_3_HASHTABLE<int> (GetNSE()/4 + 1);
+  segmentht = new INDEX_2_HASHTABLE<int> (GetNSeg() + 1);
+
+  for (sei = 0; sei < GetNSE(); sei++)
+    {
+      const Element2d & sel = surfelements[sei];
+      if (sel.IsDeleted()) continue;
+
+      int si = sel.GetIndex();
+      
+      for (j = 0; j < sel.GetNP(); j++)
+	{
+	  PointIndex pi = sel[j];
+	  bool found = 0;
+	  for (k = 0; k < surfacesonnode[pi].Size(); k++)
+	    if (surfacesonnode[pi][k] == si)
+	      {
+		found = 1;
+		break;
+	      }
+	  
+	  if (!found)
+	    surfacesonnode.Add (pi, si);
+
+	  INDEX_2 i2;
+	  i2.I1() = sel.PNumMod(j+1);
+	  i2.I2() = sel.PNumMod(j+2);
+	  i2.Sort();
+	  if (sel.GetNP() <= 4)
+	    boundaryedges->Set (i2, 1);
+	}
+    }
+
+  for (sei = 0; sei < GetNSE(); sei++)
+    {
+      const Element2d & sel = surfelements[sei];
+      if (sel.IsDeleted()) continue;
+
+      INDEX_3 i3;
+      i3.I1() = sel.PNum(1);
+      i3.I2() = sel.PNum(2);
+      i3.I3() = sel.PNum(3);
+      i3.Sort();
+      surfelementht -> PrepareSet (i3);
+    }
+
+  surfelementht -> AllocateElements();
+  for (sei = 0; sei < GetNSE(); sei++)
+    {
+      const Element2d & sel = surfelements[sei];
+      if (sel.IsDeleted()) continue;
+
+      INDEX_3 i3;
+      i3.I1() = sel.PNum(1);
+      i3.I2() = sel.PNum(2);
+      i3.I3() = sel.PNum(3);
+      i3.Sort();
+      surfelementht -> Set (i3, sel.GetIndex());
+    }
+
+  int np = GetNP();
+  ptyps.SetSize(np);
+  ptyps = INNERPOINT;
+
+  if (GetNFD() == 0) //  || GetFaceDescriptor(1).SurfNr() == 0)
+    {
+      for (sei = 0; sei < GetNSE(); sei++)
+	{
+	  const Element2d & sel = surfelements[sei];
+	  if (sel.IsDeleted()) continue;
+	  for (j = 0;  j < sel.GetNP(); j++)
+	    {
+	      PointIndex pi = SurfaceElement(sei)[j];
+	      ptyps[pi] = FIXEDPOINT;
+	    }
+	}
+    }
+  else
+    {
+      for (sei = 0; sei < GetNSE(); sei++)
+	{
+	  const Element2d & sel = surfelements[sei];
+	  if (sel.IsDeleted()) continue;
+	  for (j = 0; j < sel.GetNP(); j++)
+	    {
+	      int pi = sel[j];
+	      int ns = surfacesonnode[pi].Size();
+	      if (ns == 1)
+		ptyps[pi] = SURFACEPOINT;
+	      if (ns == 2)
+		ptyps[pi] = EDGEPOINT;
+	      if (ns >= 3)
+		ptyps[pi] = FIXEDPOINT;
+	    }      
+	}
+    }
+
+  for (i = 0; i < segments.Size(); i++)
+    {
+      const Segment & seg = segments[i];
+      for (j = 1; j <= 2; j++)
+	{
+	  PointIndex hi = (j == 1) ? seg.p1 : seg.p2;
+	  
+	  if (ptyps[hi] == INNERPOINT ||
+	      ptyps[hi] == SURFACEPOINT)
+	    ptyps[hi] = EDGEPOINT;
+	}
+    }
+
+
+  for (i = 0; i < lockedpoints.Size(); i++)
+    ptyps[lockedpoints[i]] = FIXEDPOINT;
+  
+  for (i = 0; i < openelements.Size(); i++)
+    {
+      const Element2d & sel = openelements[i];
+      for (j = 0; j < sel.GetNP(); j++)
+	{
+	  INDEX_2 i2;
+	  i2.I1() = sel.PNumMod(j+1);
+	  i2.I2() = sel.PNumMod(j+2);
+	  i2.Sort();
+	  boundaryedges->Set (i2, 1);
+
+	  ptyps[sel[j]] = FIXEDPOINT;
+	}
+    }
+
+  eltyps.SetSize (GetNE());
+  eltyps = FREEELEMENT;
+
+  for (i = 0; i < GetNSeg(); i++)
+    {
+      const Segment & seg = segments[i];
+      INDEX_2 i2(seg.p1, seg.p2);
+      i2.Sort();
+
+      boundaryedges -> Set (i2, 2);
+      segmentht -> Set (i2, 1);
+    }
+}
+
+
+void Mesh :: FixPoints (const BitArray & fixpoints)
+{
+  if (fixpoints.Size() != GetNP())
+    {
+      cerr << "Mesh::FixPoints: sizes don´t fit" << endl;
+      return;
+    }
+  int np = GetNP();
+  for (int i = 1; i <= np; i++)
+    if (fixpoints.Test(i))
+      {
+	ptyps.Elem(i) = FIXEDPOINT;
+      }
+}
+
+
+void Mesh :: FindOpenElements (int dom)
+{
+  int i, ii, j, k, l;
+  PointIndex pi;
+  SurfaceElementIndex sei;
+  Element2d hel;
+
+
+
+  if (1)   
+    { // nodebased 
+
+      int np = GetNP();
+      int ne = GetNE();
+      int nse = GetNSE();
+
+      ARRAY<int,PointIndex::BASE> numonpoint(np);
+
+      Element2d hel;
+
+      numonpoint = 0;
+      /*
+      for (i = 1; i <= np; i++)
+	numonpoint.Elem(i) = 0;
+      */
+      ElementIndex ei;
+      for (ei = 0; ei < ne; ei++)
+	{
+	  const Element & el = (*this)[ei];
+	  if (el.GetNP() == 4)
+	    {
+	      INDEX_4 i4(el[0], el[1], el[2], el[3]);
+	      i4.Sort();
+	      numonpoint[i4.I1()]++;
+	      numonpoint[i4.I2()]++;
+	    }
+	  else
+	    for (j = 0; j < el.GetNP(); j++)
+	      numonpoint[el[j]]++;
+	}
+      TABLE<ElementIndex,PointIndex::BASE> elsonpoint(numonpoint);
+      for (ei = 0; ei < ne; ei++)
+	{
+	  const Element & el = (*this)[ei];
+	  if (el.GetNP() == 4)
+	    {
+	      INDEX_4 i4(el[0], el[1], el[2], el[3]);
+	      i4.Sort();
+	      elsonpoint.Add (i4.I1(), ei);
+	      elsonpoint.Add (i4.I2(), ei);
+	    }
+	  else
+	    for (j = 0; j < el.GetNP(); j++)
+	      elsonpoint.Add (el[j], ei);
+	}
+
+      numonpoint = 0;
+      for (i = 0; i < nse; i++)
+	{
+	  hel = surfelements[i];
+	  hel.NormalizeNumbering();	  
+	  numonpoint[hel[0]]++;
+	}
+
+      TABLE<SurfaceElementIndex,PointIndex::BASE> selsonpoint(numonpoint);
+      for (i = 0; i < nse; i++)
+	{
+	  hel = surfelements[i];
+	  hel.NormalizeNumbering();	  
+	  selsonpoint.Add (hel[0], i);
+	}
+
+
+      INDEX_3_CLOSED_HASHTABLE<INDEX_2> faceht(100);   
+      openelements.SetSize(0);
+      
+      for (pi = PointIndex::BASE; 
+	   pi < np+PointIndex::BASE; pi++)
+	{
+	  faceht.SetSize (2 * selsonpoint[pi].Size() + 4 * elsonpoint[pi].Size());
+
+
+	  FlatArray<SurfaceElementIndex> row = selsonpoint[pi];
+	  for (ii = 0; ii < row.Size(); ii++)
+	    {
+	      hel = SurfaceElement(row[ii]);
+	      int ind = hel.GetIndex();	  
+  
+	      if (GetFaceDescriptor(ind).DomainIn() && 
+		  (dom == 0 || dom == GetFaceDescriptor(ind).DomainIn()) )
+		{
+		  hel.NormalizeNumbering();
+		  if (hel.PNum(1) == pi)
+		    {
+		      INDEX_3 i3(hel[0], hel[1], hel[2]);
+		      INDEX_2 i2 (GetFaceDescriptor(ind).DomainIn(), 
+				  (hel.GetNP() == 3) 
+				  ? PointIndex (PointIndex::BASE-1)
+				  : hel.PNum(4));
+		      faceht.Set (i3, i2);
+		    }
+		}
+	      if (GetFaceDescriptor(ind).DomainOut() &&
+		  (dom == 0 || dom == GetFaceDescriptor(ind).DomainOut()) )
+		{
+		  hel.Invert();
+		  hel.NormalizeNumbering();
+		  if (hel.PNum(1) == pi)
+		    {
+		      INDEX_3 i3(hel[0], hel[1], hel[2]);
+		      INDEX_2 i2 (GetFaceDescriptor(ind).DomainOut(), 
+				  (hel.GetNP() == 3) 
+				  ? PointIndex (PointIndex::BASE-1)
+				  : hel.PNum(4));
+		      faceht.Set (i3, i2);
+		    }
+		}
+	    }
+
+	  
+	  FlatArray<ElementIndex> rowel = elsonpoint[pi];
+	  for (ii = 0; ii < rowel.Size(); ii++)
+	    {
+	      const Element & el = VolumeElement(rowel[ii]);
+
+	      if (dom == 0 || el.GetIndex() == dom)
+		{
+		  for (j = 1; j <= el.GetNFaces(); j++)
+		    {
+		      el.GetFace (j, hel);
+		      hel.Invert();
+		      hel.NormalizeNumbering();
+
+		      if (hel[0] == pi)
+			{
+			  INDEX_3 i3(hel[0], hel[1], hel[2]);
+			  
+			  if (faceht.Used (i3))
+			    {
+			      INDEX_2 i2 = faceht.Get(i3);
+			      if (i2.I1() == el.GetIndex())
+				{
+				  i2.I1() = PointIndex::BASE-1;
+				  faceht.Set (i3, i2);
+				}
+			      else
+				{
+				  if (i2.I1() == 0)
+				    {
+				      PrintSysError ("more elements on face");
+				      (*testout)  << "more elements on face!!!" << endl;
+				      (*testout) << "el = " << el << endl;
+				      (*testout) << "hel = " << hel << endl;
+				      (*testout) << "face = " << i3 << endl;
+				      (*testout) << "points = " << endl;
+				      for (int jj = 1; jj <= 3; jj++)
+					(*testout) << "p = " << Point(i3.I(jj)) << endl;
+				    }
+				}
+			    }
+			  else
+			    {
+			      hel.Invert();
+			      hel.NormalizeNumbering();
+			      INDEX_3 i3(hel[0], hel[1], hel[2]);
+			      INDEX_2 i2(el.GetIndex(), 
+					 (hel.GetNP() == 3) 
+					 ? PointIndex (PointIndex::BASE-1)
+					 : hel[3]);
+			      faceht.Set (i3, i2);
+			    }
+			}
+		    }
+		}
+	    }
+
+	  for (i = 1; i <= faceht.Size(); i++)
+	    if (faceht.UsedPos (i))
+	      {
+		INDEX_3 i3;
+		INDEX_2 i2;
+		faceht.GetData (i, i3, i2);
+		if (i2.I1() != PointIndex::BASE-1)
+		  {
+		    Element2d tri;
+		    tri.SetType ( (i2.I2() == PointIndex::BASE-1) ? TRIG : QUAD);
+		    for (l = 0; l < 3; l++)
+		      tri[l] = i3.I(l+1);
+		    tri.PNum(4) = i2.I2();
+		    tri.SetIndex (i2.I1());
+
+		    //	tri.Invert();
+		    
+		    openelements.Append (tri);
+		  }
+	      }
+	}
+    }
+
+  else if (GetNE() || 1)
+    {
+      // new version, general elemetns
+      // hash index: pnum1-3
+      // hash data : domain nr, pnum4
+
+      openelements.SetSize(0);
+      
+
+      const int steps = 4;
+
+      for (k = 0; k < steps; k++)
+	{
+	  
+	  INDEX_3_CLOSED_HASHTABLE<INDEX_2> faceht( (5 * GetNE() + 2 * GetNSE() ) / steps +1);   
+	  
+	  for (i = 1; i <= GetNSE(); i++)
+	    {
+	      hel = SurfaceElement(i);
+	      int ind = hel.GetIndex();	  
+	      
+	      
+	      if (GetFaceDescriptor(ind).DomainIn() && 
+		  (dom == 0 || dom == GetFaceDescriptor(ind).DomainIn()) )
+		{
+		  hel.Invert();
+		  hel.NormalizeNumbering();
+		  if (hel.PNum(1) % steps == k)
+		    {
+		      INDEX_3 i3(hel.PNum(1), hel.PNum(2), hel.PNum(3));
+		      INDEX_2 i2 (GetFaceDescriptor(ind).DomainIn(), 
+				  (hel.GetNP() == 3) 
+				  ? PointIndex (PointIndex::BASE-1)
+				  : hel.PNum(4));
+		      faceht.Set (i3, i2);
+		    }
+		}
+	      if (GetFaceDescriptor(ind).DomainOut() &&
+		  (dom == 0 || dom == GetFaceDescriptor(ind).DomainOut()) )
+		{
+		  hel.NormalizeNumbering();
+		  if (hel.PNum(1) % steps == k)
+		    {
+		      INDEX_3 i3(hel.PNum(1), hel.PNum(2), hel.PNum(3));
+		      INDEX_2 i2 (GetFaceDescriptor(ind).DomainOut(), 
+				  (hel.GetNP() == 3) 
+				  ? PointIndex(0)
+				  : hel.PNum(4));
+		      faceht.Set (i3, i2);
+		    }
+		}
+	    }
+
+	  for (i = 1; i <= GetNE(); i++)
+	    {
+	      const Element & el = VolumeElement(i);
+	      
+	      if (dom == 0 || el.GetIndex() == dom)
+		{
+		  for (j = 1; j <= el.GetNFaces(); j++)
+		    {
+		      el.GetFace (j, hel);
+		      
+		      hel.NormalizeNumbering();
+		      if (hel.PNum(1) % steps != k)
+			continue;
+		      
+		      INDEX_3 i3(hel.PNum(1), hel.PNum(2), hel.PNum(3));
+
+		      int pos = faceht.Position (i3);
+		      if (pos)
+			{
+			  INDEX_2 i2;
+			  faceht.GetData (pos, i2);
+			  if (i2.I1() == el.GetIndex())
+			    {
+			      i2.I1() = 0;
+			      faceht.SetData (pos, i2);
+			    }
+			  else
+			    {
+			      if (i2.I1() == 0)
+				PrintSysError ("more elements on face");
+			    }
+			}
+		      else
+			{
+			  hel.Invert();
+			  hel.NormalizeNumbering();
+			  INDEX_3 i3(hel.PNum(1), hel.PNum(2), hel.PNum(3));
+			  INDEX_2 i2(el.GetIndex(), 
+				     (hel.GetNP() == 3) 
+				     ? PointIndex(0)
+				     : hel.PNum(4));
+			  faceht.Set (i3, i2);
+			}
+		    }
+		}
+	    }  
+	  
+	  for (i = 1; i <= faceht.Size(); i++)
+	    if (faceht.UsedPos (i))
+	      {
+		INDEX_3 i3;
+		INDEX_2 i2;
+		faceht.GetData (i, i3, i2);
+		if (i2.I1() != 0)
+		  {
+		    Element2d tri;
+		    tri.SetType ( (i2.I2() == 0) ? TRIG : QUAD);
+		    for (l = 1; l <= 3; l++)
+		      tri.PNum(l) = i3.I(l);
+		    tri.PNum(4) = i2.I2();
+		    tri.SetIndex (i2.I1());
+
+		    tri.Invert();
+		    
+		    openelements.Append (tri);
+		  }
+	      }
+	  /*
+	  cout << "FindOpenElements, mem = ";
+	  faceht.PrintMemInfo (cout);
+	  */
+	}
+
+
+
+
+      /*
+	// open hashing version:
+
+	INDEX_3_HASHTABLE<INDEX_2> faceht(4 * GetNE()+GetNSE()+1);   
+ 
+      for (i = 1; i <= GetNSE(); i++)
+	{
+	  Element2d hel = SurfaceElement(i);
+	  int ind = hel.GetIndex();	  
+	  
+
+	  if (GetFaceDescriptor(ind).DomainIn() && 
+	      (dom == 0 || dom == GetFaceDescriptor(ind).DomainIn()) )
+	    {
+	      hel.NormalizeNumbering();
+	      INDEX_3 i3(hel.PNum(1), hel.PNum(2), hel.PNum(3));
+	      INDEX_2 i2 (GetFaceDescriptor(ind).DomainIn(), 
+			  (hel.GetNP() == 3) ? 0 : hel.PNum(4));
+	      faceht.Set (i3, i2);
+	    }
+	  if (GetFaceDescriptor(ind).DomainOut() &&
+	      (dom == 0 || dom == GetFaceDescriptor(ind).DomainOut()) )
+	    {
+	      hel.Invert();
+	      hel.NormalizeNumbering();
+	      INDEX_3 i3(hel.PNum(1), hel.PNum(2), hel.PNum(3));
+	      INDEX_2 i2 (GetFaceDescriptor(ind).DomainOut(), 
+			  (hel.GetNP() == 3) ? 0 : hel.PNum(4));
+	      faceht.Set (i3, i2);
+	    }
+	}
+
+      for (i = 1; i <= GetNE(); i++)
+	{
+	  const Element & el = VolumeElement(i);
+	  //	  INDEX_3 i3;
+
+	  if (dom == 0 || el.GetIndex() == dom)
+	    {
+	      for (j = 1; j <= el.GetNFaces(); j++)
+		{
+		  Element2d hel;
+		  el.GetFace (j, hel);
+		  hel.Invert();
+		  
+		  hel.NormalizeNumbering();
+		  INDEX_3 i3(hel.PNum(1), hel.PNum(2), hel.PNum(3));
+		  
+		  if (faceht.Used (i3))
+		    {
+		      INDEX_2 i2 = faceht.Get(i3);
+		      if (i2.I1() == el.GetIndex())
+			{
+			  i2.I1() = 0;
+			  faceht.Set (i3, i2);
+			}
+		      else
+			{
+			  if (i2.I1() == 0)
+			    PrintSysError ("more elements on face");
+			}
+		    }
+		  else
+		    {
+		      hel.Invert();
+		      hel.NormalizeNumbering();
+		      INDEX_3 i3(hel.PNum(1), hel.PNum(2), hel.PNum(3));
+		      INDEX_2 i2(el.GetIndex(), 
+				 (hel.GetNP() == 3) ? 0 : hel.PNum(4));
+		      faceht.Set (i3, i2);
+		    }
+		}
+	    }
+	}  
+
+      
+      openelements.SetSize(0);
+      for (i = 1; i <= faceht.GetNBags(); i++)
+	for (j = 1; j <= faceht.GetBagSize(i); j++)
+	  {
+	    INDEX_3 i3;
+	    INDEX_2 i2;
+	    faceht.GetData (i, j, i3, i2);
+	    if (i2.I1() != 0)
+	      {
+		Element2d tri;
+		tri.SetNP ( (i2.I2() == 0) ? 3 : 4);
+		for (k = 1; k <= 3; k++)
+		  tri.PNum(k) = i3.I(k);
+		tri.PNum(4) = i2.I2();
+		tri.SetIndex (i2.I1());
+
+		openelements.Append (tri);
+	      }
+	  }
+      */
+
+    }
+  else 
+    {
+      for (i = 1; i <= GetNSE(); i++)
+	{
+	  Element2d hel = SurfaceElement(i);
+	  int ind = SurfaceElement(i).GetIndex();
+
+	  if (GetFaceDescriptor(ind).DomainIn())
+	    openelements.Append (hel);
+	  if (GetFaceDescriptor(ind).DomainOut())
+	    {
+	      hel.Invert();
+	      openelements.Append (hel);
+	    }
+	}
+    }
+
+
+  int cnt3 = 0, cnt4 = 0;
+  for (i = 1; i <= openelements.Size(); i++)
+    if (openelements.Elem(i).GetNP() == 3)
+      cnt3++;
+    else
+      cnt4++;
+
+
+  MyStr treequad;
+  if (cnt4)
+    treequad = MyStr(" (") + MyStr(cnt3) + MyStr (" + ") + 
+      MyStr(cnt4) + MyStr(")");
+
+  PrintMessage (5, openelements.Size(), treequad, " open elements");
+
+
+  for (i = 1; i <= openelements.Size(); i++)
+    {
+      const Element2d & sel = openelements.Get(i);
+
+      if (boundaryedges)
+	for (j = 1; j <= sel.GetNP(); j++)
+	  {
+	    INDEX_2 i2;
+	    i2.I1() = sel.PNumMod(j);
+	    i2.I2() = sel.PNumMod(j+1);
+	    i2.Sort();
+	    boundaryedges->Set (i2, 1);
+	  }
+      
+      for (j = 1; j <= 3; j++)
+	{
+	  int pi = sel.PNum(j);
+	  if (pi < ptyps.Size()+PointIndex::BASE)
+	    ptyps[pi] = FIXEDPOINT;
+	}
+    }
+
+
+  for (i = 1; i <= GetNSeg(); i++)
+    {
+      const Segment & seg = LineSegment(i);
+      INDEX_2 i2(seg.p1, seg.p2);
+      i2.Sort();
+
+      if (!boundaryedges->Used (i2))
+	cerr << "WARNING: no boundedge, but seg edge: " << i2 << endl;
+
+      boundaryedges -> Set (i2, 2);
+      segmentht -> Set (i2, 1);
+    }
+}
+
+int Mesh :: HasOpenQuads () const
+{
+  int i;
+  int no = GetNOpenElements();
+  for (i = 1; i <= no; i++)
+    if (OpenElement(i).GetNP() == 4)
+      return 1;
+  return 0;
+}
+
+
+
+
+
+void Mesh :: FindOpenSegments (int surfnr)
+{
+  int i, j, k;
+
+  // new version, general elemetns
+  // hash index: pnum1-2
+  // hash data : surfnr,  surfel-nr (pos) or segment nr(neg)
+  INDEX_2_HASHTABLE<INDEX_2> faceht(4 * GetNSE()+GetNSeg()+1);   
+  
+  PrintMessage (5, "Test Opensegments");
+  for (i = 1; i <= GetNSeg(); i++)
+    {
+      const Segment & seg = LineSegment (i);
+
+      if (surfnr == 0 || seg.si == surfnr)
+	{
+	  INDEX_2 key(seg.p1, seg.p2);
+	  INDEX_2 data(seg.si, -i);
+
+	  if (faceht.Used (key))
+	    {
+	      cerr << "ERROR: Segment " << seg << " already used" << endl;
+	      (*testout) << "ERROR: Segment " << seg << " already used" << endl;
+	    }
+
+	  faceht.Set (key, data);
+	}
+    }
+
+
+  for (i = 1; i <= GetNSeg(); i++)
+    {
+      const Segment & seg = LineSegment (i);
+
+      if (surfnr == 0 || seg.si == surfnr)
+	{
+	  INDEX_2 key(seg.p2, seg.p1);
+	  if (!faceht.Used(key))
+	    {
+	      cerr << "ERROR: Segment " << seg << " brother not used" << endl;
+	      (*testout) << "ERROR: Segment " << seg << " brother not used" << endl;
+	    }
+	}
+    }
+
+
+
+  
+  for (i = 1; i <= GetNSE(); i++)
+    {
+      const Element2d & el = SurfaceElement(i);
+      
+      if (surfnr == 0 || el.GetIndex() == surfnr)
+	{
+	  for (j = 1; j <= el.GetNP(); j++)
+	    {
+	      INDEX_2 seg (el.PNumMod(j), el.PNumMod(j+1));
+	      INDEX_2 data;
+
+	      if (faceht.Used(seg))
+		{
+		  data = faceht.Get(seg);
+		  if (data.I1() == el.GetIndex())
+		    {
+		      data.I1() = 0;
+		      faceht.Set (seg, data);
+		    }
+		  else
+		    {
+		      PrintSysError ("hash table si not fitting for segment: ",
+				     seg.I1(), "-", seg.I2(), " other = ",
+				     data.I2());
+		    }
+		}
+	      else
+		{
+		  Swap (seg.I1(), seg.I2());
+		  data.I1() = el.GetIndex();
+		  data.I2() = i;
+
+		  faceht.Set (seg, data);
+		}
+	    }
+	}
+    }  
+  
+  (*testout) << "open segments: " << endl;
+  opensegments.SetSize(0);
+  for (i = 1; i <= faceht.GetNBags(); i++)
+    for (j = 1; j <= faceht.GetBagSize(i); j++)
+      {
+	INDEX_2 i2;
+	INDEX_2 data;
+	faceht.GetData (i, j, i2, data);
+	if (data.I1())  // surfnr
+	  {
+	    Segment seg;
+	    seg.p1 = i2.I1();
+	    seg.p2 = i2.I2();
+	    seg.si = data.I1();
+
+	    // find geomdata:
+	    if (data.I2() > 0)
+	      {
+		// segment due to triangle
+		const Element2d & el = SurfaceElement (data.I2());
+		for (k = 1; k <= el.GetNP(); k++)
+		  {
+		    if (seg.p1 == el.PNum(k))
+		      seg.geominfo[0] = el.GeomInfoPi(k);
+		    if (seg.p2 == el.PNum(k))
+		      seg.geominfo[1] = el.GeomInfoPi(k);
+		  }
+
+		(*testout) << "trig seg: ";
+	      }
+	    else
+	      {
+		// segment due to line
+		const Segment & lseg = LineSegment (-data.I2());
+		seg.geominfo[0] = lseg.geominfo[0];
+		seg.geominfo[1] = lseg.geominfo[1];
+
+		(*testout) << "line seg: ";
+	      }
+	    
+	    (*testout) << seg.p1 << " - " << seg.p2 
+		       << " len = " << Dist (Point(seg.p1), Point(seg.p2))
+		       << endl;
+
+	    opensegments.Append (seg);
+	    if (seg.geominfo[0].trignum <= 0 || seg.geominfo[1].trignum <= 0)
+	      {
+		(*testout) << "Problem with open segment: " << seg << endl;
+	      }
+
+	  }
+      }
+
+  PrintMessage (3, opensegments.Size(), " open segments found");
+  (*testout) << opensegments.Size() << " open segments found" << endl;
+  
+  ptyps.SetSize (GetNP());
+  for (i = 1; i <= ptyps.Size(); i++)
+    ptyps.Elem(i) = SURFACEPOINT;
+
+  for (i = 1; i <= GetNSeg(); i++)
+    {
+      const Segment & seg = LineSegment (i);
+      ptyps.Elem(seg.p1) = EDGEPOINT;
+      ptyps.Elem(seg.p2) = EDGEPOINT;
+    }
+  for (i = 1; i <= GetNOpenSegments(); i++)
+    {
+      const Segment & seg = GetOpenSegment (i);
+      ptyps.Elem(seg.p1) = EDGEPOINT;
+      ptyps.Elem(seg.p2) = EDGEPOINT;
+    }
+  
+  
+  /*
+
+  for (i = 1; i <= openelements.Size(); i++)
+    {
+      const Element2d & sel = openelements.Get(i);
+
+      if (boundaryedges)
+	for (j = 1; j <= sel.GetNP(); j++)
+	  {
+	    INDEX_2 i2;
+	    i2.I1() = sel.PNumMod(j);
+	    i2.I2() = sel.PNumMod(j+1);
+	    i2.Sort();
+	    boundaryedges->Set (i2, 1);
+	  }
+      
+      for (j = 1; j <= 3; j++)
+	{
+	  int pi = sel.PNum(j);
+	  if (pi <= ptyps.Size())
+	    ptyps.Elem(pi) = FIXEDPOINT;
+	}
+    }
+  */
+}
+
+
+void Mesh :: RemoveOneLayerSurfaceElements ()
+{
+  int i, j;
+  int np = GetNP();
+
+  FindOpenSegments();
+  BitArray frontpoints(np);
+
+  frontpoints.Clear();
+  for (i = 1; i <= GetNOpenSegments(); i++)
+    {
+      const Segment & seg = GetOpenSegment(i);
+      frontpoints.Set (seg.p1);
+      frontpoints.Set (seg.p2);
+    }
+
+  for (i = 1; i <= GetNSE(); i++)
+    {
+      Element2d & sel = surfelements.Elem(i);
+      int remove = 0;
+      for (j = 1; j <= sel.GetNP(); j++)
+	if (frontpoints.Test(sel.PNum(j)))
+	  remove = 1;
+      if (remove)
+	sel.PNum(1) = 0;
+    }
+
+  for (i = surfelements.Size(); i >= 1; i--)
+    {
+      if (surfelements.Elem(i).PNum(1) == 0)
+	{
+	  surfelements.Elem(i) = surfelements.Last();
+	  surfelements.DeleteLast();
+	}
+    }
+  timestamp = NextTimeStamp();
+  //  Compress();
+}
+
+
+
+
+
+void Mesh :: FreeOpenElementsEnvironment (int layers)
+{
+  int i, j, k;
+  PointIndex pi;
+  const int large = 9999;
+  ARRAY<int,PointIndex::BASE> dist(GetNP());
+
+  dist = large;
+
+  for (i = 1; i <= GetNOpenElements(); i++)
+    {
+      const Element2d & face = OpenElement(i);
+      for (j = 1; j <= face.GetNP(); j++)
+	dist[face.PNum(j)] = 1;
+    }
+
+  for (k = 1; k <= layers; k++)
+    for (i = 1; i <= GetNE(); i++)
+      {
+	const Element & el = VolumeElement(i);
+	if (el[0] == -1 || el.IsDeleted()) continue;
+
+	int elmin = large;
+	for (j = 0; j < el.GetNP(); j++)
+	  if (dist[el[j]] < elmin)
+	    elmin = dist[el[j]];
+
+	if (elmin < large)
+	  {
+	    for (j = 0; j < el.GetNP(); j++)
+	      if (dist[el[j]] > elmin+1)
+		dist[el[j]] = elmin+1;
+	  }
+      }
+
+  int cntfree = 0;
+  for (i = 1; i <= GetNE(); i++)
+    {
+      const Element & el = VolumeElement(i);
+      if (el[0] == -1 || el.IsDeleted()) continue;
+	
+      int elmin = large;
+      for (j = 0; j < el.GetNP(); j++)
+	if (dist[el[j]] < elmin)
+	  elmin = dist[el[j]];
+      
+      eltyps.Elem(i) = (elmin <= layers) ? 
+	FREEELEMENT : FIXEDELEMENT;
+      if (elmin <= layers)
+	cntfree++;
+    }
+
+  PrintMessage (5, "free: ", cntfree, ", fixed: ", GetNE()-cntfree);
+  (*testout) << "free: " << cntfree << ", fixed: " << GetNE()-cntfree << endl;
+
+  for (pi = PointIndex::BASE; 
+       pi < GetNP()+PointIndex::BASE; pi++)
+    {
+      if (dist[pi] > layers+1)
+	ptyps[pi] = FIXEDPOINT;
+    }
+}
+
+
+
+void Mesh :: SetLocalH (const Point3d & pmin, const Point3d & pmax, double grading)
+{
+  Point3d c = Center (pmin, pmax);
+  double d = max3 (pmax.X()-pmin.X(),
+		   pmax.Y()-pmin.Y(),
+		   pmax.Z()-pmin.Z());
+  d /= 2;
+  Point3d pmin2 = c - Vec3d (d, d, d);
+  Point3d pmax2 = c + Vec3d (d, d, d);
+  
+
+  delete lochfunc;
+  lochfunc = new LocalH (pmin2, pmax2, grading);
+}
+
+void Mesh :: RestrictLocalH (const Point3d & p, double hloc)
+{
+  // cout << "restrict h in " << p << " to " << hloc << endl;
+  if (!lochfunc)
+    {
+      PrintWarning("RestrictLocalH called, creating mesh-size tree");
+
+      Point3d boxmin, boxmax;
+      GetBox (boxmin, boxmax);
+      SetLocalH (boxmin, boxmax, 0.8);
+    }
+
+  lochfunc -> SetH (p, hloc);
+}
+
+void Mesh :: RestrictLocalHLine (const Point3d & p1, 
+				 const Point3d & p2,
+				 double hloc)
+{
+  // cout << "restrict h along " << p1 << " - " << p2 << " to " << hloc << endl;
+  int i;
+  int steps = int (Dist (p1, p2) / hloc) + 2;
+  Vec3d v(p1, p2);
+  
+  for (i = 0; i <= steps; i++)
+    {
+      Point3d p = p1 + (double(i)/double(steps) * v);
+      RestrictLocalH (p, hloc);
+    }
+}
+
+
+void Mesh :: SetGlobalH (double h)
+{
+  hglob = h;
+}
+
+double Mesh :: MaxHDomain (int dom) const
+{
+  if (maxhdomain.Size())
+    return maxhdomain.Get(dom);
+  else
+    return 1e10;
+}
+
+void Mesh :: SetMaxHDomain (const ARRAY<double> & mhd)
+{
+  maxhdomain.SetSize(mhd.Size());
+  for (int i = 1; i <= mhd.Size(); i++)
+    maxhdomain.Elem(i) = mhd.Get(i);
+}
+
+
+double Mesh :: GetH (const Point3d & p) const
+{
+  double hmin = hglob;
+  if (lochfunc)
+    {
+      double hl = lochfunc->GetH (p);
+      if (hl < hglob)
+	hmin = hl;
+    }
+  return hmin;
+}
+
+double Mesh :: GetMinH (const Point3d & pmin, const Point3d & pmax)
+{
+  double hmin = hglob;
+  if (lochfunc)
+    {
+      double hl = lochfunc->GetMinH (pmin, pmax);
+      if (hl < hmin)
+	hmin = hl;
+    }
+  return hmin;
+}
+
+
+
+
+
+double Mesh :: AverageH (int surfnr) const
+{
+  int i, j, n;
+  double hi, hsum;
+  double maxh = 0, minh = 1e10;
+
+  hsum = 0;
+  n = 0;
+  for (i = 1; i <= GetNSE(); i++)
+    {
+      const Element2d & el = SurfaceElement(i);
+      if (surfnr == 0 || el.GetIndex() == surfnr)
+	{
+	  for (j = 1; j <= 3; j++)
+	    {
+	      hi = Dist (Point (el.PNumMod(j)), 
+			 Point (el.PNumMod(j+1)));
+
+	      hsum += hi;
+
+	      if (hi > maxh) maxh = hi;
+	      if (hi < minh) minh = hi;
+	      n++;
+	    }
+	}
+    }
+
+  PrintMessage (5, "minh = ", minh, " avh = ", (hsum/n), " maxh = ", maxh);
+  return (hsum / n);
+}
+
+
+
+void Mesh :: CalcLocalH () 
+{
+  if (!lochfunc)
+    {
+      Point3d pmin, pmax;
+      GetBox (pmin, pmax);
+      SetLocalH (pmin, pmax, mparam.grading);
+    }
+
+  PrintMessage (3,
+		"CalcLocalH: ", 
+		GetNP(), " Points ", 
+		GetNE(), " Elements ", 
+		GetNSE(), " Surface Elements");
+
+
+  int i;
+  for (i = 0; i < GetNSE(); i++)
+    {
+      const Element2d & el = surfelements[i];
+      int j;
+
+      if (el.GetNP() == 3)
+	{
+	  double hel = -1;
+	  for (j = 1; j <= 3; j++)
+	    {
+	      const Point3d & p1 = points[el.PNumMod(j)];
+	      const Point3d & p2 = points[el.PNumMod(j+1)];
+	      
+	      /*
+	      INDEX_2 i21(el.PNumMod(j), el.PNumMod(j+1));
+	      INDEX_2 i22(el.PNumMod(j+1), el.PNumMod(j));
+	      if (! identifiedpoints->Used (i21) &&
+		  ! identifiedpoints->Used (i22) )
+	      */
+	      if (!ident.UsedSymmetric (el.PNumMod(j),
+					el.PNumMod(j+1)))
+		{
+		  double hedge = Dist (p1, p2);
+		  if (hedge > hel)
+		    hel = hedge;
+		  //		  lochfunc->SetH (Center (p1, p2), 2 * Dist (p1, p2));
+		  //		  (*testout) << "trigseth, p1,2 = " << el.PNumMod(j) << ", " << el.PNumMod(j+1) 
+		  //			     << " h = " << (2 * Dist(p1, p2)) << endl;
+		}
+	    }
+	  
+	  if (hel > 0)
+	    {
+	      const Point3d & p1 = points[el.PNum(1)];
+	      const Point3d & p2 = points[el.PNum(2)];
+	      const Point3d & p3 = points[el.PNum(3)];
+	      lochfunc->SetH (Center (p1, p2, p3), hel);
+	    }
+	}
+      else
+	  {
+	    {
+	      const Point3d & p1 = points[el.PNum(1)];
+	      const Point3d & p2 = points[el.PNum(2)];
+	      lochfunc->SetH (Center (p1, p2), 2 * Dist (p1, p2));
+	    }
+	    {
+	      const Point3d & p1 = points[el.PNum(3)];
+	      const Point3d & p2 = points[el.PNum(4)];
+	      lochfunc->SetH (Center (p1, p2), 2 * Dist (p1, p2));
+	    }
+	  }
+    }
+
+  for (i = 0; i < GetNSeg(); i++)
+    {
+      const Segment & seg = segments[i];
+      const Point3d & p1 = points[seg.p1];
+      const Point3d & p2 = points[seg.p2];
+      /*
+      INDEX_2 i21(seg.p1, seg.p2);
+      INDEX_2 i22(seg.p2, seg.p1);
+      if (identifiedpoints)
+	if (!identifiedpoints->Used (i21) && !identifiedpoints->Used (i22))
+      */
+      if (!ident.UsedSymmetric (seg.p1, seg.p2))
+	{
+	  lochfunc->SetH (Center (p1, p2), Dist (p1, p2));
+	}
+    }
+  /*
+  cerr << "do vol" << endl;
+  for (i = 1; i <= GetNE(); i++)
+    {
+      const Element & el = VolumeElement(i);
+      if (el.GetType() == TET)
+	{
+	  int j, k;
+	  for (j = 2; j <= 4; j++)
+	    for (k = 1; k < j; k++)  
+	      {
+		const Point3d & p1 = Point (el.PNum(j));
+		const Point3d & p2 = Point (el.PNum(k));
+		lochfunc->SetH (Center (p1, p2), 2 * Dist (p1, p2));
+		(*testout) << "set vol h to " << (2 * Dist (p1, p2)) << endl;
+
+	      }
+	}
+    }
+  */
+
+  /*
+  const char * meshsizefilename = 
+    globflags.GetStringFlag ("meshsize", NULL);
+  if (meshsizefilename)
+    {
+      ifstream msf(meshsizefilename);
+      if (msf)
+	{
+	  int nmsp;
+	  msf >> nmsp;
+	  for (i = 1; i <= nmsp; i++)
+	    {
+	      Point3d pi;
+	      double hi;
+	      msf >> pi.X() >> pi.Y() >> pi.Z();
+	      msf >> hi;
+	      lochfunc->SetH (pi, hi);
+	    }
+	}
+    }
+  */
+  //  lochfunc -> Convexify();
+  //  lochfunc -> PrintMemInfo (cout);
+}
+
+
+
+void Mesh :: CalcLocalHFromSurfaceCurvature (double elperr) 
+{
+  PrintMessage (3, "Calculating local h from Surface curvature");
+
+  if (!lochfunc)
+    {
+      Point3d pmin, pmax;
+      GetBox (pmin, pmax);
+      
+      SetLocalH (pmin, pmax, mparam.grading);
+    }
+
+  
+  INDEX_2_HASHTABLE<int> edges(3 * GetNP() + 2);
+  INDEX_2_HASHTABLE<int> bedges(GetNSeg() + 2);
+  int i, j;
+
+  for (i = 1; i <= GetNSeg(); i++)
+    {
+      const Segment & seg = LineSegment(i);
+      INDEX_2 i2(seg.p1, seg.p2);
+      i2.Sort();
+      bedges.Set (i2, 1);
+    }
+  for (i = 1; i <= GetNSE(); i++)
+    {
+      const Element2d & sel = SurfaceElement(i);
+      if (!sel.PNum(1))
+	continue;
+      for (j = 1; j <= 3; j++)
+	{
+	  INDEX_2 i2(sel.PNumMod(j), sel.PNumMod(j+1));
+	  i2.Sort();
+	  if (bedges.Used(i2)) continue;
+
+	  if (edges.Used(i2))
+	    {
+	      int other = edges.Get(i2);
+
+	      const Element2d & elother = SurfaceElement(other);
+
+	      int pi3 = 1;
+	      while ( (sel.PNum(pi3) == i2.I1()) || 
+		      (sel.PNum(pi3) == i2.I2()))
+		pi3++;
+	      pi3 = sel.PNum(pi3);
+
+	      int pi4 = 1;
+	      while ( (elother.PNum(pi4) == i2.I1()) || 
+		      (elother.PNum(pi4) == i2.I2()))
+		pi4++;
+	      pi4 = elother.PNum(pi4);
+
+	      double rad = ComputeCylinderRadius (Point (i2.I1()),
+						  Point (i2.I2()),
+						  Point (pi3), 
+						  Point (pi4));
+	      
+	      RestrictLocalHLine (Point(i2.I1()), Point(i2.I2()), rad/elperr);
+
+
+	      /*	      
+	      (*testout) << "pi1,2, 3, 4 = " << i2.I1() << ", " << i2.I2() << ", " << pi3 << ", " << pi4
+			 << " p1 = " << Point(i2.I1()) 
+			 << ", p2 = " << Point(i2.I2()) 
+		//			 << ", p3 = " << Point(pi3) 
+		//			 << ", p4 = " << Point(pi4) 
+			 << ", rad = " << rad << endl;
+	      */
+	    }
+	  else
+	    edges.Set (i2, i);
+	}
+    }
+
+
+  // Restrict h due to line segments
+
+  for (i = 1; i <= GetNSeg(); i++)
+    {
+      const Segment & seg = LineSegment(i);
+      const Point3d & p1 = Point(seg.p1);
+      const Point3d & p2 = Point(seg.p2);
+      RestrictLocalH (Center (p1, p2),  Dist (p1, p2));
+    }
+
+
+
+      /*
+
+
+  int i, j;
+  int np = GetNP();
+  int nseg = GetNSeg();
+  int nse = GetNSE();
+  
+  ARRAY<Vec3d> normals(np);
+  BitArray linepoint(np);
+
+  linepoint.Clear();
+  for (i = 1; i <= nseg; i++)
+    {
+      linepoint.Set (LineSegment(i).p1);
+      linepoint.Set (LineSegment(i).p2);
+    }
+
+  for (i = 1; i <= np; i++)
+    normals.Elem(i) = Vec3d(0,0,0);
+
+  for (i = 1; i <= nse; i++)
+    {
+      Element2d & el = SurfaceElement(i);
+      Vec3d nf = Cross (Vec3d (Point (el.PNum(1)), Point(el.PNum(2))),
+			Vec3d (Point (el.PNum(1)), Point(el.PNum(3))));
+      for (j = 1; j <= 3; j++)
+	normals.Elem(el.PNum(j)) += nf;
+    }
+
+  for (i = 1; i <= np; i++)
+    normals.Elem(i) /= (1e-12 + normals.Elem(i).Length());
+
+  for (i = 1; i <= nse; i++)
+    {
+      Element2d & el = SurfaceElement(i);
+      Vec3d nf = Cross (Vec3d (Point (el.PNum(1)), Point(el.PNum(2))),
+			Vec3d (Point (el.PNum(1)), Point(el.PNum(3))));
+      nf /= nf.Length();
+      Point3d c = Center (Point(el.PNum(1)),
+			  Point(el.PNum(2)),
+			  Point(el.PNum(3)));
+			  
+      for (j = 1; j <= 3; j++)
+	{
+	  if (!linepoint.Test (el.PNum(j)))
+	    {
+	      double dist = Dist (c, Point(el.PNum(j)));
+	      double dn = (nf - normals.Get(el.PNum(j))).Length();
+	  
+	      RestrictLocalH (Point(el.PNum(j)), dist / (dn+1e-12) /elperr);
+	    }
+	}
+    }
+      */
+}
+
+
+void Mesh :: RestrictLocalH (resthtype rht, int nr, double loch)
+{
+  int i;
+  switch (rht)
+    {
+    case RESTRICTH_FACE:
+      {
+	for (i = 1; i <= GetNSE(); i++)
+	  {
+	    const Element2d & sel = SurfaceElement(i);
+	    if (sel.GetIndex() == nr)
+	      RestrictLocalH (RESTRICTH_SURFACEELEMENT, i, loch);
+	  }
+	break;
+      }
+    case RESTRICTH_EDGE:
+      {
+	for (i = 1; i <= GetNSeg(); i++)
+	  {
+	    const Segment & seg = LineSegment(i);
+	    if (seg.edgenr == nr)
+	      RestrictLocalH (RESTRICTH_SEGMENT, i, loch);
+	  }
+	break;
+      }
+    case RESTRICTH_POINT:
+      {
+	RestrictLocalH (Point (nr), loch);
+	break;
+      }
+
+    case RESTRICTH_SURFACEELEMENT:
+      {
+	const Element2d & sel = SurfaceElement(nr);
+	Point3d p = Center (Point(sel.PNum(1)),
+			    Point(sel.PNum(2)),
+			    Point(sel.PNum(3)));
+	RestrictLocalH (p, loch);
+	break;
+      }
+    case RESTRICTH_SEGMENT:
+      {
+	const Segment & seg = LineSegment(nr);
+	RestrictLocalHLine (Point (seg.p1), Point(seg.p2), loch);
+	break;
+      }
+    }
+}
+
+
+void Mesh :: LoadLocalMeshSize (istream & msf)
+{
+  PrintMessage (3, "Load local mesh-size");
+  int i, nmsp, nmsl;
+  msf >> nmsp;
+  for (i = 1; i <= nmsp; i++)
+    {
+      Point3d pi;
+      double hi;
+      msf >> pi.X() >> pi.Y() >> pi.Z();
+      msf >> hi;
+      RestrictLocalH (pi, hi);
+    }
+  msf >> nmsl;
+  for (i = 1; i <= nmsl; i++)
+    {
+      Point3d p1, p2;
+      double hi;
+      msf >> p1.X() >> p1.Y() >> p1.Z();
+      msf >> p2.X() >> p2.Y() >> p2.Z();
+      msf >> hi;
+      RestrictLocalHLine (p1, p2, hi);
+    }  
+}
+
+
+
+void Mesh :: GetBox (Point3d & pmin, Point3d & pmax, int dom) const
+{
+  if (points.Size() == 0)
+    {
+      pmin = pmax = Point3d(0,0,0);
+      return;
+    }
+
+  if (dom <= 0)
+    {
+      pmin = Point3d (1e10, 1e10, 1e10);
+      pmax = Point3d (-1e10, -1e10, -1e10); 
+
+      for (PointIndex pi = PointIndex::BASE; 
+	   pi < GetNP()+PointIndex::BASE; pi++)
+	{
+	  pmin.SetToMin ( (*this) [pi] );
+	  pmax.SetToMax ( (*this) [pi] );
+	}
+    }
+  else
+    {
+      int j, nse = GetNSE();
+      SurfaceElementIndex sei;
+
+      pmin = Point3d (1e10, 1e10, 1e10);
+      pmax = Point3d (-1e10, -1e10, -1e10); 
+      for (sei = 0; sei < nse; sei++)
+	{
+	  const Element2d & el = (*this)[sei];
+	  if (el.IsDeleted() ) continue;
+
+	  if (dom == -1 || el.GetIndex() == dom)
+	    {
+	      for (j = 0; j < 3; j++)
+		{
+		  pmin.SetToMin ( (*this) [el[j]] );
+		  pmax.SetToMax ( (*this) [el[j]] );
+		}
+	    }
+	}
+    }
+
+  if (pmin.X() > 0.5e10)
+    {
+      pmin = pmax = Point3d(0,0,0);
+    }
+}
+
+
+
+
+void Mesh :: GetBox (Point3d & pmin, Point3d & pmax, POINTTYPE ptyp) const
+{
+  if (points.Size() == 0)
+    {
+      pmin = pmax = Point3d(0,0,0);
+      return;
+    }
+
+  pmin = Point3d (1e10, 1e10, 1e10);
+  pmax = Point3d (-1e10, -1e10, -1e10); 
+  
+  for (PointIndex pi = PointIndex::BASE; 
+       pi < GetNP()+PointIndex::BASE; pi++)
+    if (ptyps[pi] <= ptyp)
+      {
+	pmin.SetToMin ( (*this) [pi] );
+	pmax.SetToMax ( (*this) [pi] );
+      }
+}
+
+
+
+
+double Mesh :: ElementError (int eli) const
+{
+  const Element & el = volelements.Get(eli);
+  return CalcTetBadness (points.Get(el[0]), points.Get(el[1]),
+			 points.Get(el[2]), points.Get(el[3]), -1);
+}
+
+void Mesh :: AddLockedPoint (PointIndex pi)
+{ 
+  lockedpoints.Append (pi); 
+}
+
+void Mesh :: ClearLockedPoints ()
+{ 
+  lockedpoints.SetSize (0); 
+}
+
+
+
+void Mesh :: Compress ()
+{
+  int i, j;
+  ARRAY<int,PointIndex::BASE> op2np(GetNP());
+  ARRAY<Point3d> hpoints;
+  BitArrayChar<PointIndex::BASE> pused(GetNP());
+
+  /*
+  (*testout) << "volels: " << endl;
+  for (i = 1; i <= volelements.Size(); i++)
+    {
+      for (j = 1; j <= volelements.Get(i).GetNP(); j++)
+	(*testout) << volelements.Get(i).PNum(j) << " ";
+      (*testout) << endl;
+    }
+  (*testout) << "np: " << GetNP() << endl;
+  */
+
+
+  for (i = 0; i < volelements.Size(); i++)
+    if (volelements[i][0] <= PointIndex::BASE-1 ||
+	volelements[i].IsDeleted())
+      {
+	volelements.Delete(i);
+	i--;
+      }
+  for (i = 0; i < surfelements.Size(); i++)
+    if (surfelements[i].IsDeleted())
+      {
+	surfelements.Delete(i);
+	i--;
+      }
+  for (i = 0; i < segments.Size(); i++)
+    if (segments[i].p1 == -1)
+      {
+	segments.Delete(i);
+	i--;
+      }
+
+  
+  pused.Clear();
+  for (i = 0; i < volelements.Size(); i++)
+    {
+      const Element & el = volelements[i];
+      for (j = 0; j < el.GetNP(); j++)
+	pused.Set (el[j]);
+    }
+
+  for (i = 0; i < surfelements.Size(); i++)
+    {
+      const Element2d & el = surfelements[i];
+      for (j = 0; j < el.GetNP(); j++)
+	pused.Set (el[j]);
+    }
+
+  for (i = 0; i < segments.Size(); i++)
+    {
+      const Segment & seg = segments[i];
+      pused.Set (seg.p1);
+      pused.Set (seg.p2);
+    }
+
+  for (i = 0; i < openelements.Size(); i++)
+    {
+      const Element2d & el = openelements[i];
+      for (j = 0; j < el.GetNP(); j++)
+	pused.Set(el[j]);
+    }
+
+  for (i = 0; i < lockedpoints.Size(); i++)
+    pused.Set (lockedpoints[i]);
+
+  /*
+  // compress points doesn´t work for identified points !
+  if (identifiedpoints)
+    {
+      for (i = 1; i <= identifiedpoints->GetNBags(); i++)
+	if (identifiedpoints->GetBagSize(i))
+	  {
+	    pused.Set ();
+	    break;
+	  }
+    }
+  */
+  //  pused.Set();
+
+
+  int npi = PointIndex::BASE-1;
+
+  for (i = PointIndex::BASE; 
+       i < points.Size()+PointIndex::BASE; i++)
+    if (pused.Test(i))
+      {
+	npi++;
+	op2np[i] = npi;
+	hpoints.Append (points[i]);
+      }
+    else
+      op2np[i] = -1;
+
+
+  points.SetSize(0);
+  for (i = 0; i < hpoints.Size(); i++)
+    points.Append (hpoints[i]);
+
+
+  for (i = 1; i <= volelements.Size(); i++)
+    {
+      Element & el = VolumeElement(i);
+      for (j = 0; j < el.GetNP(); j++)
+	el[j] = op2np[el[j]];
+    }
+
+  for (i = 1; i <= surfelements.Size(); i++)
+    {
+      Element2d & el = SurfaceElement(i);
+      for (j = 0; j < el.GetNP(); j++)
+	el[j] = op2np[el[j]];
+    }
+  
+  for (i = 0; i < segments.Size(); i++)
+    {
+      Segment & seg = segments[i];
+      seg.p1 = op2np[seg.p1];
+      seg.p2 = op2np[seg.p2];
+    }
+
+  for (i = 1; i <= openelements.Size(); i++)
+    {
+      Element2d & el = openelements.Elem(i);
+      for (j = 0; j < el.GetNP(); j++)
+	el[j] = op2np[el[j]];
+    }  
+
+
+  for (i = 0; i < lockedpoints.Size(); i++)
+    lockedpoints[i] = op2np[lockedpoints[i]];
+
+
+
+  CalcSurfacesOfNode();
+  //  FindOpenElements();
+  timestamp = NextTimeStamp();
+
+  (*testout) << "compress, done" << endl
+	     << "np = " << points.Size()
+	     << "ne = " << volelements.Size() << ", type.size = " << eltyps.Size()
+	     <<  "volelements = " << volelements << endl;
+}
+
+
+int Mesh :: CheckConsistentBoundary () const
+{
+  int nf = GetNOpenElements();
+  INDEX_2_HASHTABLE<int> edges(nf+2);
+  int i, j;
+  INDEX_2 i2;
+  int err = 0;
+
+
+  for (i = 1; i <= nf; i++)
+    {
+      const Element2d & sel = OpenElement(i);
+      
+      for (j = 1; j <= sel.GetNP(); j++)
+	{
+	  i2.I1() = sel.PNumMod(j);
+	  i2.I2() = sel.PNumMod(j+1);
+
+	  int sign = (i2.I2() > i2.I1()) ? 1 : -1;
+	  i2.Sort();
+	  if (!edges.Used (i2))
+	    edges.Set (i2, 0);
+
+	  edges.Set (i2, edges.Get(i2) + sign);
+	  /*
+
+	    if (edges.Used(i2))
+	    {
+	    int hi;
+	    hi = edges.Get(i2);
+	    if (hi != 1) 
+	    err = 1;
+	    edges.Set(i2, 2);
+	    cnt2++;
+	    }
+	    else
+	    {
+	    Swap (i2.I1(), i2.I2());
+	    edges.Set(i2, 1);
+	    cnt1++;
+	    }
+	    */
+	}
+    }
+
+
+  /*
+    if (cnt1 != cnt2)
+    err = 2;
+    */
+
+  for (i = 1; i <= edges.GetNBags(); i++)
+    for (j = 1; j <= edges.GetBagSize(i); j++)
+      {
+	int cnt = 0;
+	edges.GetData (i, j, i2, cnt);
+	if (cnt)
+	  {
+	    PrintError ("Edge ", i2.I1() , " - ", i2.I2(), " multiple times in surface mesh");
+	    err = 2;
+	  }
+      }
+
+  return err;
+}
+
+
+
+int Mesh :: CheckOverlappingBoundary () 
+{
+  int i, j, k;
+
+  Point3d pmin, pmax;
+  GetBox (pmin, pmax);
+  Box3dTree setree(pmin, pmax);
+  ARRAY<int> inters;
+  int overlap = 0;
+
+  for (i = 1; i <= GetNSE(); i++)
+    SurfaceElement(i).badel = 0;
+
+
+  for (i = 1; i <= GetNSE(); i++)
+    {
+      const Element2d & tri = SurfaceElement(i);
+      
+      Point3d tpmin (Point(tri[0]));
+      Point3d tpmax (tpmin);
+
+      for (k = 1; k < tri.GetNP(); k++)
+	{
+	  tpmin.SetToMin (Point (tri[k]));
+	  tpmax.SetToMax (Point (tri[k]));
+	}
+      Vec3d diag(tpmin, tpmax);
+
+      tpmax = tpmax + 0.1 * diag;
+      tpmin = tpmin - 0.1 * diag;
+
+      setree.Insert (tpmin, tpmax, i);
+    }
+
+  for (i = 1; i <= GetNSE(); i++)
+    {
+      const Element2d & tri = SurfaceElement(i);
+      
+      Point3d tpmin (Point(tri[0]));
+      Point3d tpmax (tpmin);
+
+      for (k = 1; k < tri.GetNP(); k++)
+	{
+	  tpmin.SetToMin (Point (tri[k]));
+	  tpmax.SetToMax (Point (tri[k]));
+	}
+
+      setree.GetIntersecting (tpmin, tpmax, inters);
+
+      for (j = 1; j <= inters.Size(); j++)
+	{
+	  const Element2d & tri2 = SurfaceElement(inters.Get(j));	  
+
+	  const Point3d *trip1[3], *trip2[3];	  
+	  for (k = 1; k <= 3; k++)
+	    {
+	      trip1[k-1] = &Point (tri.PNum(k));
+	      trip2[k-1] = &Point (tri2.PNum(k));
+	    }
+
+	  if (IntersectTriangleTriangle (&trip1[0], &trip2[0]))
+	    {
+	      overlap = 1;
+	      PrintWarning ("Intersecting elements" 
+			    ,i, " and ", inters.Get(j));
+
+	      (*testout) << "Intersecting: " << endl;
+	      (*testout) << "openelement " << i << " with open element " << inters.Get(j) << endl;
+
+	      for (k = 1; k <= 3; k++)
+		(*testout) << tri.PNum(k) << "  ";
+	      (*testout) << endl;
+	      for (k = 1; k <= 3; k++)
+		(*testout) << tri2.PNum(k) << "  ";
+	      (*testout) << endl;
+
+	      for (k = 0; k <= 2; k++)
+		(*testout) << *trip1[k] << "   ";
+	      (*testout) << endl;
+	      for (k = 0; k <= 2; k++)
+		(*testout) << *trip2[k] << "   ";
+	      (*testout) << endl;
+
+
+	      /*
+	      INDEX_3 i3(tri.PNum(1), tri.PNum(2), tri.PNum(3));
+	      i3.Sort();
+	      for (k = 1; k <= GetNSE(); k++)
+		{
+		  const Element2d & el2 = SurfaceElement(k);
+		  INDEX_3 i3b(el2.PNum(1), el2.PNum(2), el2.PNum(3));
+		  i3b.Sort();
+		  if (i3 == i3b)
+		    {
+		      SurfaceElement(k).badel = 1;
+		    }
+		}
+	      */
+	      SurfaceElement(i).badel = 1;
+	      SurfaceElement(inters.Get(j)).badel = 1;
+	    }
+	}
+    }
+
+  return overlap;
+}
+
+
+int Mesh :: CheckVolumeMesh () const
+{
+  PrintMessage (3, "Checking volume mesh");
+  
+  int ne = GetNE();
+  DenseMatrix dtrans(3,3);
+  int i, j;
+
+  PrintMessage (5, "elements: ", ne);
+  for (i = 1; i <= ne; i++)
+    {
+      Element & el = (Element&) VolumeElement(i);
+      el.flags.badel = 0;
+      int nip = el.GetNIP();
+      for (j = 1; j <= nip; j++)
+	{
+	  el.GetTransformation (j, Points(), dtrans);
+	  double det = dtrans.Det();
+	  if (det > 0)
+	    {
+	      PrintError ("Element ", i , " has wrong orientation");
+	      el.flags.badel = 1;
+	    }
+	}
+    }
+
+  return 0;
+}
+
+
+bool Mesh :: LegalTrig (const Element2d & el) const
+{
+  return 1;
+  if ( /* hp */ 1)  // needed for old, simple hp-refinement
+    { 
+      // trigs with 2 or more segments are illegal
+      int i;
+      int nseg = 0;
+
+      if (!segmentht)
+	{
+	  cerr << "no segmentht allocated" << endl;
+	  return 0;
+	}
+
+      //      Point3d cp(0.5, 0.5, 0.5);
+      for (i = 1; i <= 3; i++)
+	{
+	  INDEX_2 i2(el.PNumMod (i), el.PNumMod (i+1));
+	  i2.Sort();
+	  if (segmentht -> Used (i2))
+	    nseg++;
+	}
+      if (nseg >= 2) 
+	return 0;
+    }
+  return 1;
+}
+
+///
+bool Mesh :: LegalTet2 (Element & el) const
+{
+  //  return 1;
+  // Test, whether 4 points have a common surface plus
+  // at least 4 edges at the boundary
+
+  int i, j, k;
+  
+  // non-tets are always legal
+  if (el.GetType() != TET)
+    {
+      el.SetLegal (1);
+      return 1;
+    }
+
+  // element has at least 2 inner points ---> legal
+  int cnti = 0;
+  for (j = 1; j <= 4; j++)
+    if (PointType(el.PNum(j)) == INNERPOINT)
+      cnti++;
+  if (cnti >= 2)
+    {
+      el.SetLegal (1);
+      return 1;
+    }
+
+  // which faces are boundary faces ?
+  Element2d face;
+  int bface[4];
+
+  for (i = 1; i <= 4; i++)
+    {
+      el.GetFace (i, face);
+      INDEX_3 i3 (face.PNum(1), face.PNum(2), face.PNum(3));
+      i3.Sort();
+      bface[i-1] = surfelementht->Used (i3);
+    }
+
+  int bedge[4][4];
+  int segedge[4][4];
+  for (i = 1; i <= 4; i++)
+    for (j = 1; j < i; j++)
+      {
+	INDEX_2 i2(el.PNum(i), el.PNum(j));
+	i2.Sort();
+
+	int sege = 0, be = 0;
+
+	if (boundaryedges -> Used(i2))
+	  {
+	    int val = boundaryedges -> Get(i2);
+	    be = 1;
+	    if (val == 2)
+	      sege = 1;
+	  }
+
+	segedge[j-1][i-1] =
+	  segedge[i-1][j-1] = sege;
+
+	bedge[j-1][i-1] =
+	  bedge[i-1][j-1] = be;
+      }
+
+
+  // two boundary faces and no edge is illegal
+  for (i = 0; i < 3; i++)
+    for (j = i+1; j < 4; j++)
+      {
+	if (bface[i] && bface[j])
+	  {
+	    // common nodes:
+	    int pi1 = 0, pi2;
+	    while (pi1 == i || pi1 == j)
+	      pi1++;
+	    pi2 = 6 - i - j - pi1;
+	    /*
+	    INDEX_2 i2(el.PNum(pi1+1), el.PNum(pi2+1));
+	    i2.Sort();
+	    if (!segmentht->Used (i2))
+	    */
+	    if (!segedge[pi1][pi2])
+	      {
+		// 2 boundary faces withoud edge in between
+		//		cout << "p1, p2 = " << pi1 << "," << pi2 << endl;
+		//		cout << "tet illegal due to first case" << endl;
+		el.SetLegal (0);
+		return 0;
+	      }
+	  }
+      }
+
+
+  // three boundary edges meeting in a Surface point
+  for (i = 1; i <= 4; i++)
+    {
+      int alledges = 1;
+      if (PointType(el.PNum(i)) == SURFACEPOINT)
+	{
+	  for (j = 1; j <= 4; j++)
+	    if (j != i)
+	      {
+		/*
+		INDEX_2 i2(el.PNum(i), el.PNum(j));
+		i2.Sort();
+		if (!boundaryedges->Used(i2))
+		*/
+		if (!bedge[i-1][j-1])
+		  {
+		    alledges = 0;
+		    break;
+		  }
+	      }
+	  if (alledges)
+	    {
+	      //	      cout << "tet illegal due to unmarked node" << endl;
+	      el.SetLegal (0);
+	      return 0;
+	    }
+	}
+    }
+
+
+  /*  
+  {
+    // having 3 boundary edges and 4 surface nodes ???
+    int nodehasedge[4];
+    int canbe = 1;   // can be that illegal tet
+
+    for (i = 0; i < 4; i++)
+      nodehasedge[i] = 0;
+    for (i = 1; i <= 4; i++)
+      {
+	if (PointType(el.PNum(i)) != SURFACEPOINT)
+	  canbe = 0;
+	for (j = i+1; j <= 4; j++)
+	  {
+	    INDEX_2 i2(el.PNum(i), el.PNum(j));
+	    i2.Sort();
+	    if (boundaryedges->Used(i2))
+	      {
+		nodehasedge[i-1] = 1;
+		nodehasedge[j-1] = 1;
+	      }
+
+	  }
+      }
+    for (i = 0; i < 4; i++)
+      if (!nodehasedge[i])
+	canbe = 0;
+
+    if (canbe) return 0;
+    
+  }
+  */
+
+  {
+    // two connected edges on surface, but no face
+
+    int ltestmode = 0; // (el.PNum(1) == 10516);
+
+    if (ltestmode)
+      {
+	(*testout) << "pnums: " << endl;
+	for (i = 1; i <= 4; i++)
+	  (*testout) << el.PNum(i) << " ";
+	(*testout) << endl;
+      }
+
+    for (i = 1; i <= 4; i++)
+      if (PointType(el.PNum(i)) == SURFACEPOINT)
+	for (j = 1; j <= 4; j++)
+	  if (j != i)
+	    for (k = j+1; k <= 4; k++)
+	      if (k != i)
+		{
+		  int fnr = 10 - i - j - k;
+
+		  if (!bface[fnr-1] &&
+		      bedge[i-1][j-1] &&
+		      bedge[i-1][k-1])
+		    {
+		      el.SetLegal (0);
+		      return 0;
+		    }
+		  /*
+		  INDEX_2 e1(el.PNum(i), el.PNum(j));
+		  e1.Sort();
+		  INDEX_2 e2(el.PNum(i), el.PNum(k));
+		  e2.Sort();
+		  INDEX_3 face(el.PNum(i), el.PNum(j), el.PNum(k));
+		  face.Sort();
+		  
+		  if (ltestmode)
+		    {
+		      (*testout) << "i, j, k = " << i << ", " << j << ", " << k << endl;
+		      (*testout) << "eij = " << boundaryedges->Used(e1) 
+				 << " eik = " << boundaryedges->Used(e2) 
+				 << " face = " << surfelementht->Used (face) << endl;
+		      
+		    }
+		  
+		  if (boundaryedges->Used(e1) && 
+		      boundaryedges->Used(e2) &&
+		      !surfelementht->Used (face))
+		    {
+		      //		      cout << "tet illegal due to last case" << endl;
+		      el.SetLegal (0);
+		      return 0;
+		    }
+		  */
+		}
+    
+  }
+
+
+  {
+    // connected surface edge and edge edge, but no face
+
+    for (i = 1; i <= 4; i++)
+      if (PointType(el.PNum(i)) == EDGEPOINT)
+	for (j = 1; j <= 4; j++)
+	  if (j != i)
+	    for (k = j+1; k <= 4; k++)
+	      if (k != i)
+		{
+		  int fnr = 10 - i - j - k;
+
+		  if (!bface[fnr-1] &&
+		      (bedge[i-1][j-1] && segedge[i-1][k-1] ||
+		       segedge[i-1][j-1] && bedge[i-1][k-1]))
+		    {
+		      el.SetLegal (0);
+		      return 0;
+		    }
+		}
+    
+  }
+
+
+
+
+
+    
+  el.SetLegal (1);
+  return 1;
+  
+      /*
+  int i1, i2, i3, i4, j;
+  if (PointType(el.PNum(1)) != INNERPOINT && 
+      PointType(el.PNum(2)) != INNERPOINT && 
+      PointType(el.PNum(3)) != INNERPOINT &&
+      PointType(el.PNum(4)) != INNERPOINT)
+    {      
+      for (i1 = 1; i1 <= surfacesonnode.EntrySize(el.PNum(1)); i1++)
+	for (i2 = 1; i2 <= surfacesonnode.EntrySize(el.PNum(2)); i2++)
+	  if (surfacesonnode.Get(el.PNum(1), i1) == 
+	      surfacesonnode.Get(el.PNum(2), i2))
+	    for (i3 = 1; i3 <= surfacesonnode.EntrySize(el.PNum(3)); i3++)
+	      if (surfacesonnode.Get(el.PNum(1), i1) == 
+		  surfacesonnode.Get(el.PNum(3), i3))
+		for (i4 = 1; i4 <= surfacesonnode.EntrySize(el.PNum(4)); i4++)
+		  if (surfacesonnode.Get(el.PNum(1), i1) == 
+		      surfacesonnode.Get(el.PNum(4), i4))
+		    {
+		      int j, numbe = 0;
+		      INDEX_2 i2;
+
+		      for (j = 1; j <= 6; j++)
+			{
+			  switch (j)
+			    {
+			    case 1:
+			      i2.I1() = el.PNum(1);
+			      i2.I2() = el.PNum(2); break;
+			    case 2: 
+			      i2.I1() = el.PNum(1); 
+			      i2.I2() = el.PNum(3); break;
+			    case 3: 
+			      i2.I1() = el.PNum(1); 
+			      i2.I2() = el.PNum(4); break;
+			    case 4:
+			      i2.I1() = el.PNum(2); 
+			      i2.I2() = el.PNum(3); break;
+			    case 5:
+			      i2.I1() = el.PNum(2);
+			      i2.I2() = el.PNum(4); break;
+			    case 6: 
+			      i2.I1() = el.PNum(3); 
+			      i2.I2() = el.PNum(4); break;
+			    }
+
+			  i2.Sort();
+			  if (boundaryedges->Used (i2)) numbe++;
+			}
+
+		      if (numbe >= 4)
+			{
+// 			  (*testout) 
+// 			    << "Tet illegal: " 
+// 			    << "mat = " << el.GetIndex() << " "
+// 			    << "surf = " << surfacesonnode.Get(el.PNum(1), i1) 
+// 			    << " " 
+// 			    << el.PNum(1) << " "
+// 			    << el.PNum(2) << " "
+// 			    << el.PNum(3) << " "
+// 			    << el.PNum(4) << endl;
+
+			  return 0;
+			}
+		    }
+    }
+  return 1;
+*/
+}
+
+
+int Mesh :: GetNDomains() const
+{
+  int ndom = 0;
+
+  for (int k = 0; k < facedecoding.Size(); k++)
+    {
+      if (facedecoding[k].DomainIn() > ndom)
+	ndom = facedecoding[k].DomainIn();
+      if (facedecoding[k].DomainOut() > ndom)
+	ndom = facedecoding[k].DomainOut();
+    }
+
+  return ndom;
+}
+
+
+
+void Mesh :: SurfaceMeshOrientation ()
+{
+  int i, j;
+  int nse = GetNSE();
+  
+  BitArray used(nse);
+  used.Clear();
+  INDEX_2_HASHTABLE<int> edges(nse+1);
+
+  bool haschanged = 0;
+
+
+  const Element2d & tri = SurfaceElement(1);
+  for (j = 1; j <= 3; j++)
+    {
+      INDEX_2 i2(tri.PNumMod(j), tri.PNumMod(j+1));
+      edges.Set (i2, 1);
+    }
+  used.Set(1);
+
+  bool unused;
+  do
+    {
+      bool changed;
+      do
+	{
+	  changed = 0;
+	  for (i = 1; i <= nse; i++)
+	    if (!used.Test(i))
+	      {
+		Element2d & el = surfelements.Elem(i);
+		int found = 0, foundrev = 0;
+		for (j = 1; j <= 3; j++)
+		  {
+		    INDEX_2 i2(el.PNumMod(j), el.PNumMod(j+1));
+		    if (edges.Used(i2))
+		      foundrev = 1;
+		    Swap (i2.I1(), i2.I2());
+		    if (edges.Used(i2))
+		      found = 1;
+		  }
+		
+		if (found || foundrev)
+		  {
+		    if (foundrev)
+		      Swap (el.PNum(2), el.PNum(3));
+		    
+		    changed = 1;
+		    for (j = 1; j <= 3; j++)
+		      {
+			INDEX_2 i2(el.PNumMod(j), el.PNumMod(j+1));
+			edges.Set (i2, 1);
+		      }
+		    used.Set (i);
+		  }
+	      }
+	  if (changed)
+	    haschanged = 1;
+	}
+      while (changed);
+      
+
+      unused = 0;
+      for (i = 1; i <= nse; i++)
+	if (!used.Test(i))
+	  {
+	    unused = 1;
+	    const Element2d & tri = SurfaceElement(i);
+	    for (j = 1; j <= 3; j++)
+	      {
+		INDEX_2 i2(tri.PNumMod(j), tri.PNumMod(j+1));
+		edges.Set (i2, 1);
+	      }
+	    used.Set(i);
+	    break;
+	  }
+    }
+  while (unused);
+
+  if (haschanged)
+    timestamp = NextTimeStamp();
+}
+  
+
+void Mesh :: Split2Tets()
+{
+  int oldne, oldnse;
+  int i, j, k, l;
+  
+  oldne = GetNE(); 
+  for (i = 1; i <= oldne; i++)
+    {
+      Element el = VolumeElement(i);
+      if (el.GetType() == PRISM)
+	{
+	  //	  (*testout) << "split el: " << el << " to ";
+
+	  // prism, to 3 tets
+	  
+	  // make minimal node to node 1
+	  int minpi=0;
+	  PointIndex minpnum;
+	  minpnum = GetNP() + 1;
+
+	  for (j = 1; j <= 6; j++)
+	    {
+	      if (el.PNum(j) < minpnum)
+		{
+		  minpnum = el.PNum(j);
+		  minpi = j;
+		}
+	    }
+
+	  if (minpi >= 4)
+	    {
+	      for (j = 1; j <= 3; j++)
+		Swap (el.PNum(j), el.PNum(j+3));
+	      minpi -= 3;
+	    }
+
+	  while (minpi > 1)
+	    {
+	      int hi = 0;
+	      for (j = 0; j <= 3; j+= 3)
+		{
+		  hi = el.PNum(1+j);
+		  el.PNum(1+j) = el.PNum(2+j);
+		  el.PNum(2+j) = el.PNum(3+j);
+		  el.PNum(3+j) = hi;
+		}
+	      minpi--;
+	    }
+
+	  /*
+	    version 1: edge from pi2 to pi6,
+	    version 2: edge from pi3 to pi5,
+	   */
+
+	  (*testout) << " rot el = " << el << " ";
+
+	  static const int ntets[2][12] =
+	  { { 1, 4, 5, 6, 1, 2, 3, 6, 1, 2, 5, 6 },
+	    { 1, 4, 5, 6, 1, 2, 3, 5, 3, 1, 5, 6 } };
+
+	  const int * min2pi;
+
+	  if (min2 (el.PNum(2), el.PNum(6)) <
+	      min2 (el.PNum(3), el.PNum(5)))
+	    {
+	      min2pi = &ntets[0][0];
+	      (*testout) << "version 1 ";
+	    }
+	  else
+	    {
+	      min2pi = &ntets[1][0];
+	      (*testout) << "version 2 ";
+	    }
+
+	  
+	  int firsttet = 1;
+	  for (j = 1; j <= 3; j++)
+	    {
+	      Element nel(4);
+	      for (k = 1; k <= 4; k++)
+		nel.PNum(k) = el.PNum(min2pi[4 * j + k - 5]);
+	      nel.SetIndex (el.GetIndex());
+
+	      int legal = 1;
+	      for (k = 1; k <= 3; k++)
+		for (l = k+1; l <= 4; l++)
+		  if (nel.PNum(k) == nel.PNum(l))
+		    legal = 0;
+
+	      (*testout) << nel << " ";
+
+	      if (legal)
+		{
+		  if (firsttet)
+		    {
+		      VolumeElement(i) = nel;
+		      firsttet = 0;
+		    }
+		  else
+		    {
+		      AddVolumeElement(nel);
+		    }
+		}
+	    }
+	  if (firsttet) (*testout) << "no legal";
+	  (*testout) << endl;
+	}
+      
+      
+      if (el.GetType() == PYRAMID)
+	{
+	  // pyramid, to 2 tets
+	  
+
+
+	  static const int ntets[2][8] =
+	  { { 1, 2, 3, 5, 1, 3, 4, 5 },
+	    { 1, 2, 4, 5, 4, 2, 3, 5 }};
+
+	  const int * min2pi;
+
+	  if (min2 (el.PNum(1), el.PNum(3)) <
+	      min2 (el.PNum(2), el.PNum(4)))
+	    min2pi = &ntets[0][0];
+	  else
+	    min2pi = &ntets[1][0];
+
+
+	  int firsttet = 1;
+	  for (j = 1; j <= 2; j++)
+	    {
+	      Element nel(4);
+	      for (k = 1; k <= 4; k++)
+		nel.PNum(k) = el.PNum(min2pi[4 * j + k - 5]);
+	      nel.SetIndex (el.GetIndex());
+
+
+	      int legal = 1;
+	      for (k = 1; k <= 3; k++)
+		for (l = k+1; l <= 4; l++)
+		  if (nel.PNum(k) == nel.PNum(l))
+		    legal = 0;
+
+	      if (legal)
+		{
+		  (*testout) << nel << " ";
+		  if (firsttet)
+		    {
+		      VolumeElement(i) = nel;
+		      firsttet = 0;
+		    }
+		  else
+		    {
+		      AddVolumeElement(nel);
+		    }
+		}
+	    }
+	  (*testout) << endl;
+
+
+	  
+	  
+	}
+    }
+
+  
+  oldnse = GetNSE(); 
+  for (i = 1; i <= oldnse; i++)
+    {
+      Element2d el = SurfaceElement(i);
+      if (el.GetNP() == 4)
+	{
+	  (*testout) << "split el: " << el << " to ";
+	  
+	  static const int ntris[2][6] =
+	  { { 1, 2, 3, 1, 3, 4 },
+	    { 1, 2, 4, 4, 2, 3 }};
+
+	  const int * min2pi;
+
+	  if (min2 (el.PNum(1), el.PNum(3)) <
+	      min2 (el.PNum(2), el.PNum(4)))
+	    min2pi = &ntris[0][0];
+	  else
+	    min2pi = &ntris[1][0];
+
+	  for (j = 0; j <6; j++)
+	    (*testout) << min2pi[j] << " ";
+
+
+	  int firsttri = 1;
+	  for (j = 1; j <= 2; j++)
+	    {
+	      Element2d nel(3);
+	      for (k = 1; k <= 3; k++)
+		nel.PNum(k) = el.PNum(min2pi[3 * j + k - 4]);
+	      nel.SetIndex (el.GetIndex());
+
+	      int legal = 1;
+	      for (k = 1; k <= 2; k++)
+		for (l = k+1; l <= 3; l++)
+		  if (nel.PNum(k) == nel.PNum(l))
+		    legal = 0;
+
+	      if (legal)
+		{
+		  (*testout) << nel << " ";
+		  if (firsttri)
+		    {
+		      SurfaceElement(i) = nel;
+		      firsttri = 0;
+		    }
+		  else
+		    {
+		      AddSurfaceElement(nel);
+		    }
+		}
+	    }
+	  (*testout) << endl;
+
+	}
+    }
+
+
+  for (i = 1; i <= GetNE(); i++)
+    {
+      Element & el = VolumeElement(i);
+      const Point3d & p1 = Point (el.PNum(1));
+      const Point3d & p2 = Point (el.PNum(2));
+      const Point3d & p3 = Point (el.PNum(3));
+      const Point3d & p4 = Point (el.PNum(4));
+
+      double vol = (Vec3d (p1, p2) * 
+		    Cross (Vec3d (p1, p3), Vec3d(p1, p4)));
+      if (vol > 0)
+	Swap (el.PNum(3), el.PNum(4));
+    }
+  timestamp = NextTimeStamp();
+}
+
+void Mesh :: BuildElementSearchTree ()
+{
+  if (elementsearchtreets == GetTimeStamp())
+    return;
+
+  NgLock lock(mutex);
+  lock.Lock();
+
+  PrintMessage (4, "Rebuild element searchtree");
+
+  if (elementsearchtree)
+    delete elementsearchtree;
+  elementsearchtree = NULL;
+
+  Box3d box;
+  int i, j;
+  int ne = GetNE();
+  if (!ne) 
+    {
+      lock.UnLock();
+      return;
+    }
+
+  box.SetPoint (Point (VolumeElement(1).PNum(1)));
+  for (i = 1; i <= ne; i++)
+    {
+      const Element & el = VolumeElement(i);
+      for (j = 1; j <= el.GetNP(); j++)
+	box.AddPoint (Point (el.PNum(j)));
+    }
+  
+  box.Increase (1.01 * box.CalcDiam());
+  elementsearchtree = new Box3dTree (box.PMin(), box.PMax());
+  
+
+
+  for (i = 1; i <= ne; i++)
+    {
+      const Element & el = VolumeElement(i);
+      box.SetPoint (Point (el.PNum(1)));
+      for (j = 1; j <= el.GetNP(); j++)
+	box.AddPoint (Point (el.PNum(j)));
+
+      elementsearchtree -> Insert (box.PMin(), box.PMax(), i);
+    }
+
+  elementsearchtreets = GetTimeStamp();
+
+  lock.UnLock();
+}
+
+
+int Mesh :: GetElementOfPoint (const Point3d & p,
+			       double lami[3]) const
+{
+  if (dimension == 2)
+    {
+      int i, j;
+      Vec3d col1, col2, col3;
+      Vec3d rhs, sol;
+      double eps = 1e-6;
+      int ne;
+      
+      ARRAY<int> locels;
+      if (0)
+	{
+	  elementsearchtree->GetIntersecting (p, p, locels);
+	  ne = locels.Size();
+	}
+      else
+	ne = GetNSE();
+      
+      ARRAY<Element2d> loctrigs;
+      Vec3d nv(0, 0, 1);
+
+      for (i = 1; i <= ne; i++)
+	{
+	  int ii;
+	  if (0)
+	    ii = locels.Get(i);
+	  else
+	    ii = i;
+	  
+	  //	  SurfaceElement(ii).GetTets (loctets);
+	  loctrigs.SetSize(1);
+	  loctrigs.Elem(1) = SurfaceElement(ii);
+
+	  for (j = 1; j <= loctrigs.Size(); j++)
+	    {
+	      const Element2d & el = loctrigs.Get(j);
+	      
+	      const Point3d & p1 = Point(el.PNum(1));
+	      const Point3d & p2 = Point(el.PNum(2));
+	      const Point3d & p3 = Point(el.PNum(3));
+	      
+	      /*
+	      Box3d box;
+	      box.SetPoint (p1);
+	      box.AddPoint (p2);
+	      box.AddPoint (p3);
+	      box.AddPoint (p4);
+	      if (!box.IsIn (p))
+		continue;
+	      */
+	      col1 = p2-p1;
+	      col2 = p3-p1;
+	      col3 = nv;
+	      rhs = p - p1;
+	      
+	      SolveLinearSystem (col1, col2, col3, rhs, sol);
+	      
+	      if (sol.X() >= -eps && sol.Y() >= -eps && 
+		  sol.X() + sol.Y() <= 1+eps)
+		{
+		  lami[0] = sol.X();
+		  lami[1] = sol.Y();
+		  lami[2] = sol.Z();
+		  return ii;
+		}
+	    }
+	}
+      
+      return 0;
+    }
+
+  else
+      
+    {
+      int i, j;
+      Vec3d col1, col2, col3;
+      Vec3d rhs, sol;
+      double eps = 1e-4;
+      int ne;
+      
+      ARRAY<int> locels;
+      if (elementsearchtree)
+	{
+	  // update if necessary:
+	  const_cast<Mesh&>(*this).BuildElementSearchTree (); 
+	  elementsearchtree->GetIntersecting (p, p, locels);
+	  ne = locels.Size();
+	}
+      else
+	ne = GetNE();
+      
+      ARRAY<Element> loctets;
+      for (i = 1; i <= ne; i++)
+	{
+	  int ii;
+	  if (elementsearchtree)
+	    ii = locels.Get(i);
+	  else
+	    ii = i;
+	  
+	  VolumeElement(ii).GetTets (loctets);
+	  
+	  for (j = 1; j <= loctets.Size(); j++)
+	    {
+	      const Element & el = loctets.Get(j);
+	      
+	      const Point3d & p1 = Point(el.PNum(1));
+	      const Point3d & p2 = Point(el.PNum(2));
+	      const Point3d & p3 = Point(el.PNum(3));
+	      const Point3d & p4 = Point(el.PNum(4));
+	      
+	      Box3d box;
+	      box.SetPoint (p1);
+	      box.AddPoint (p2);
+	      box.AddPoint (p3);
+	      box.AddPoint (p4);
+	      if (!box.IsIn (p))
+		continue;
+	      
+	      col1 = p2-p1;
+	      col2 = p3-p1;
+	      col3 = p4-p1;
+	      rhs = p - p1;
+	      
+	      SolveLinearSystem (col1, col2, col3, rhs, sol);
+	      
+	      if (sol.X() >= -eps && sol.Y() >= -eps && sol.Z() >= -eps &&
+		  sol.X() + sol.Y() + sol.Z() <= 1+eps)
+		{
+		  ARRAY<Element> loctetsloc;
+		  ARRAY<Point3d> pointsloc;
+
+		  VolumeElement(ii).GetTetsLocal (loctetsloc);
+		  VolumeElement(ii).GetNodesLocalNew (pointsloc);
+
+		  const Element & le = loctetsloc.Get(j);
+		  
+		  Point3d p = 
+		    pointsloc.Get(le.PNum(1)) 
+		    + sol.X() * Vec3d (pointsloc.Get(le.PNum(1)), pointsloc.Get(le.PNum(2))) 
+		    + sol.Y() * Vec3d (pointsloc.Get(le.PNum(1)), pointsloc.Get(le.PNum(3))) 
+		    + sol.Z() * Vec3d (pointsloc.Get(le.PNum(1)), pointsloc.Get(le.PNum(4))) ;
+
+
+		  lami[0] = p.X();
+		  lami[1] = p.Y();
+		  lami[2] = p.Z();
+		  return ii;
+		}
+	    }
+	}
+      
+      return 0;
+    }
+}
+
+
+void Mesh::GetIntersectingVolEls(const Point3d& p1, const Point3d& p2, 
+				 ARRAY<int> & locels) const
+{
+  elementsearchtree->GetIntersecting (p1, p2, locels);
+}
+
+void Mesh :: SplitIntoParts()
+{
+  int i, j, dom;
+  int ne = GetNE();
+  int np = GetNP();
+  int nse = GetNSE();
+
+  BitArray surfused(nse);
+  BitArray pused (np);
+
+  surfused.Clear();
+
+  dom = 0;
+  
+  while (1)
+    {
+      int cntd = 1;
+
+      dom++;
+      
+      pused.Clear();
+
+      int found = 0;
+      for (i = 1; i <= nse; i++)
+	if (!surfused.Test(i))
+	  {
+	    SurfaceElement(i).SetIndex (dom);
+	    for (j = 1; j <= 3; j++)
+	      pused.Set (SurfaceElement(i).PNum(j));
+	    found = 1;
+	    cntd = 1;
+	    surfused.Set(i);
+	    break;
+	  }
+
+      if (!found)
+	break;
+
+      int change;
+      do
+	{
+	  change = 0;
+	  for (i = 1; i <= nse; i++)
+	    {
+	      int is = 0, isnot = 0;
+	      for (j = 1; j <= 3; j++)
+		if (pused.Test(SurfaceElement(i).PNum(j)))
+		  is = 1;
+		else
+		  isnot = 1;
+	      
+	      if (is && isnot)
+		{
+		  change = 1;
+		  for (j = 1; j <= 3; j++)
+		    pused.Set (SurfaceElement(i).PNum(j));
+		}
+
+	      if (is) 
+		{
+		  if (!surfused.Test(i))
+		    {
+		      surfused.Set(i);
+		      SurfaceElement(i).SetIndex (dom);
+		      cntd++;
+		    }
+		}
+	    }
+
+
+	  for (i = 1; i <= ne; i++)
+	    {
+	      int is = 0, isnot = 0;
+	      for (j = 1; j <= 4; j++)
+		if (pused.Test(VolumeElement(i).PNum(j)))
+		  is = 1;
+		else
+		  isnot = 1;
+	      
+	      if (is && isnot)
+		{
+		  change = 1;
+		  for (j = 1; j <= 4; j++)
+		    pused.Set (VolumeElement(i).PNum(j));
+		}
+
+	      if (is)
+		{
+		  VolumeElement(i).SetIndex (dom);
+		}
+	    }
+	}
+      while (change);
+
+      PrintMessage (3, "domain ", dom, " has ", cntd, " surfaceelements");
+    }
+
+  /*
+  facedecoding.SetSize (dom);
+  for (i = 1; i <= dom; i++)
+    {
+      facedecoding.Elem(i).surfnr = 0;
+      facedecoding.Elem(i).domin = i;
+      facedecoding.Elem(i).domout = 0;
+    }
+    */
+  ClearFaceDescriptors();
+  for (i = 1; i <= dom; i++)
+    AddFaceDescriptor (FaceDescriptor (0, i, 0, 0));
+  CalcSurfacesOfNode();
+  timestamp = NextTimeStamp();
+}
+
+void Mesh :: SplitSeparatedFaces ()
+{
+  int fdi;
+  int i, j;
+  int np = GetNP();
+
+  BitArray usedp(np);
+
+  fdi = 1;
+  while (fdi <= GetNFD())
+    {
+      int firstel = 0;
+      for (i = 1; i <= GetNSE(); i++)
+	if (SurfaceElement(i).GetIndex() == fdi)
+	  {
+	    firstel = i;
+	    break;
+	  }
+      if (!firstel) continue;
+
+      usedp.Clear();
+      for (j = 1; j <= SurfaceElement(firstel).GetNP(); j++)
+	usedp.Set (SurfaceElement(firstel).PNum(j));
+
+      int changed;
+      do
+	{
+	  changed = 0;
+	  for (i = 1; i <= GetNSE(); i++)
+	    {
+	      const Element2d & el = SurfaceElement(i);
+	      if (el.GetIndex() != fdi)
+		continue;
+
+	      int has = 0;
+	      int hasno = 0;
+	      for (j = 1; j <= el.GetNP(); j++)
+		{
+		  if (usedp.Test(el.PNum(j)))
+		    has = 1;
+		  else
+		    hasno = 1;
+		}
+	      if (has && hasno)
+		changed = 1;
+
+	      if (has)
+		for (j = 1; j <= el.GetNP(); j++)
+		  usedp.Set (el.PNum(j));
+	    }
+	}
+      while (changed);
+
+      int nface = 0;
+      for (i = 1; i <= GetNSE(); i++)
+	{
+	  Element2d & el = SurfaceElement(i);
+	  if (el.GetIndex() != fdi)
+	    continue;	  
+
+	  int hasno = 0;
+	  for (j = 1; j <= el.GetNP(); j++)
+	    {
+	      if (!usedp.Test(el.PNum(j)))
+		hasno = 1;
+	    }
+	  
+	  if (hasno)
+	    {
+	      if (!nface)
+		{
+		  FaceDescriptor nfd = GetFaceDescriptor(fdi);
+		  nface = AddFaceDescriptor (nfd);
+		}
+
+	      el.SetIndex (nface);
+	    }
+	}
+      fdi++;
+    }
+}
+
+
+void Mesh :: GetSurfaceElementsOfFace (int facenr, ARRAY<SurfaceElementIndex> & sei) const
+{
+  sei.SetSize (0);
+  for (SurfaceElementIndex i = 0; i < GetNSE(); i++)
+    if ( (*this)[i].GetIndex () == facenr && (*this)[i][0] >= PointIndex::BASE )
+      sei.Append (i);
+}
+
+
+
+
+void Mesh :: CalcMinMaxAngle (double badellimit, double * retvalues) 
+{
+  int i, j;
+  int lpi1, lpi2, lpi3, lpi4;
+  double phimax = 0, phimin = 10;
+  double facephimax = 0, facephimin = 10;
+  int illegaltets = 0, negativetets = 0, badtets = 0;
+
+  for (i = 1; i <= GetNE(); i++)
+    {
+      int badel = 0;
+
+      Element & el = VolumeElement(i);
+
+      if (el.GetType() != TET)
+	{
+	  VolumeElement(i).flags.badel = 0;
+	  continue;
+	}
+
+      if (el.Volume(Points()) < 0)
+	{
+	  badel = 1;
+	  negativetets++;
+	}
+      
+
+      if (!LegalTet (el)) 
+	{
+	  badel = 1;
+	  illegaltets++;
+	  (*testout) << "illegal tet: " << i << " ";
+	  for (j = 1; j <= el.GetNP(); j++)
+	    (*testout) << el.PNum(j) << " ";
+	  (*testout) << endl;
+	}
+      
+	
+      // angles between faces
+      for (lpi1 = 1; lpi1 <= 3; lpi1++)
+	for (lpi2 = lpi1+1; lpi2 <= 4; lpi2++)
+	  {
+	    lpi3 = 1;
+	    while (lpi3 == lpi1 || lpi3 == lpi2)
+	      lpi3++;
+	    lpi4 = 10 - lpi1 - lpi2 - lpi3;
+
+	    const Point3d & p1 = Point (el.PNum(lpi1));
+	    const Point3d & p2 = Point (el.PNum(lpi2));
+	    const Point3d & p3 = Point (el.PNum(lpi3));
+	    const Point3d & p4 = Point (el.PNum(lpi4));
+
+	    Vec3d n(p1, p2);
+	    n /= n.Length();
+	    Vec3d v1(p1, p3);
+	    Vec3d v2(p1, p4);
+
+	    v1 -= (n * v1) * n;
+	    v2 -= (n * v2) * n;
+
+	    double cosphi = (v1 * v2) / (v1.Length() * v2.Length());
+	    double phi = acos (cosphi);
+	    if (phi > phimax) phimax = phi;
+	    if (phi < phimin) phimin = phi;
+
+	    if ((180/M_PI) * phi > badellimit)
+	      badel = 1;
+	  }
+
+
+      // angles in faces
+      for (j = 1; j <= 4; j++)
+	{
+	  Element2d face;
+	  el.GetFace (j, face);
+	  for (lpi1 = 1; lpi1 <= 3; lpi1++)
+	    {
+	      lpi2 = lpi1 % 3 + 1;
+	      lpi3 = lpi2 % 3 + 1;
+
+	      const Point3d & p1 = Point (el.PNum(lpi1));
+	      const Point3d & p2 = Point (el.PNum(lpi2));
+	      const Point3d & p3 = Point (el.PNum(lpi3));
+
+	      Vec3d v1(p1, p2);
+	      Vec3d v2(p1, p3);
+	      double cosphi = (v1 * v2) / (v1.Length() * v2.Length());
+	      double phi = acos (cosphi);
+	      if (phi > facephimax) facephimax = phi;
+	      if (phi < facephimin) facephimin = phi;
+
+	      if ((180/M_PI) * phi > badellimit)
+		badel = 1;
+
+	    }
+	}
+
+       
+      VolumeElement(i).flags.badel = badel;
+      if (badel) badtets++;
+    }
+
+  if (!GetNE())
+    {
+      phimin = phimax = facephimin = facephimax = 0;
+    }
+
+  if (!retvalues)
+    {
+      PrintMessage (1, "");
+      PrintMessage (1, "between planes:  phimin = ", (180/M_PI) * phimin,
+		    " phimax = ", (180/M_PI) *phimax);
+      PrintMessage (1, "inside planes:   phimin = ", (180/M_PI) * facephimin,
+		    " phimax = ", (180/M_PI) * facephimax);
+      PrintMessage (1, "");      
+    }
+  else
+    {
+      retvalues[0] = (180/M_PI) * facephimin;
+      retvalues[1] = (180/M_PI) * facephimax;
+      retvalues[2] = (180/M_PI) * phimin;
+      retvalues[3] = (180/M_PI) * phimax;
+    }
+  PrintMessage (3, "negative tets: ", negativetets);
+  PrintMessage (3, "illegal tets:  ", illegaltets);
+  PrintMessage (3, "bad tets:      ", badtets);
+}
+
+
+int Mesh :: MarkIllegalElements ()
+{
+  int cnt = 0;
+  int i;
+
+  for (i = 1; i <= GetNE(); i++)
+    {
+      LegalTet (VolumeElement(i));
+
+      /*
+      Element & el = VolumeElement(i);
+      int leg1 = LegalTet (el);
+      el.flags.illegal_valid = 0;
+      int leg2 = LegalTet (el);
+
+      if (leg1 != leg2) 
+	{
+	  cerr << "legal differs!!" << endl;
+	  (*testout) << "legal differs" << endl;
+	  (*testout) << "elnr = " << i << ", el = " << el
+		     << " leg1 = " << leg1 << ", leg2 = " << leg2 << endl;
+	}
+      
+      //      el.flags.illegal = !LegalTet (el);
+      */
+      cnt += VolumeElement(i).Illegal();
+    }
+  return cnt;
+}
+
+#ifdef NONE
+void Mesh :: AddIdentification (int pi1, int pi2, int identnr)
+{
+  INDEX_2 pair(pi1, pi2);
+  //  pair.Sort();
+  identifiedpoints->Set (pair, identnr);
+  if (identnr > maxidentnr)
+    maxidentnr = identnr;
+  timestamp = NextTimeStamp();
+}
+
+int Mesh :: GetIdentification (int pi1, int pi2) const
+{
+  INDEX_2 pair(pi1, pi2);
+  if (identifiedpoints->Used (pair))
+    return identifiedpoints->Get(pair);
+  else
+    return 0;
+}
+
+int Mesh :: GetIdentificationSym (int pi1, int pi2) const
+{
+  INDEX_2 pair(pi1, pi2);
+  if (identifiedpoints->Used (pair))
+    return identifiedpoints->Get(pair);
+
+  pair = INDEX_2 (pi2, pi1);
+  if (identifiedpoints->Used (pair))
+    return identifiedpoints->Get(pair);
+
+  return 0;
+}
+
+
+void Mesh :: GetIdentificationMap (int identnr, ARRAY<int> & identmap) const
+{
+  int i, j;
+
+  identmap.SetSize (GetNP());
+  for (i = 1; i <= identmap.Size(); i++)
+    identmap.Elem(i) = 0;
+
+  for (i = 1; i <= identifiedpoints->GetNBags(); i++)
+    for (j = 1; j <= identifiedpoints->GetBagSize(i); j++)
+      {
+	INDEX_2 i2;
+	int nr;
+	identifiedpoints->GetData (i, j, i2, nr);
+	
+	if (nr == identnr)
+	  {
+	    identmap.Elem(i2.I1()) = i2.I2();
+	  }
+      }
+}
+
+
+void Mesh :: GetIdentificationPairs (int identnr, ARRAY<INDEX_2> & identpairs) const
+{
+  int i, j;
+
+  identpairs.SetSize(0);
+
+  for (i = 1; i <= identifiedpoints->GetNBags(); i++)
+    for (j = 1; j <= identifiedpoints->GetBagSize(i); j++)
+      {
+	INDEX_2 i2;
+	int nr;
+	identifiedpoints->GetData (i, j, i2, nr);
+	
+	if (identnr == 0 || nr == identnr)
+	  identpairs.Append (i2);
+      }
+}
+#endif
+
+void Mesh :: ComputeNVertices ()
+{
+  int i, j, nv;
+  int ne = GetNE();
+  int nse = GetNSE();
+
+  numvertices = 0;
+  for (i = 1; i <= ne; i++)
+    {
+      const Element & el = VolumeElement(i);
+      nv = el.GetNV();
+      for (j = 0; j < nv; j++)
+	if (el[j] > numvertices)
+	  numvertices = el[j];
+    }
+  for (i = 1; i <= nse; i++)
+    {
+      const Element2d & el = SurfaceElement(i);
+      nv = el.GetNV();
+      for (j = 1; j <= nv; j++)
+	if (el.PNum(j) > numvertices)
+	  numvertices = el.PNum(j);
+   } 
+
+  numvertices += 1- PointIndex::BASE;
+}
+
+int Mesh :: GetNV () const
+{
+  if (numvertices < 0)
+    return GetNP();
+  else
+    return numvertices;
+}
+
+void Mesh :: SetNP (int np)
+{
+  points.SetSize(np);
+  ptyps.SetSize(np);
+
+  int mlold = mlbetweennodes.Size();
+  mlbetweennodes.SetSize(np);
+  if (np > mlold)
+    for (int i = mlold+PointIndex::BASE; 
+	 i < np+PointIndex::BASE; i++)
+      {
+	mlbetweennodes[i].I1() = PointIndex::BASE-1;
+	mlbetweennodes[i].I2() = PointIndex::BASE-1;
+      }
+}
+
+
+/*
+void Mesh :: BuildConnectedNodes ()
+{
+  if (PureTetMesh())
+    {
+      connectedtonode.SetSize(0);
+      return;
+    }
+
+
+  int i, j, k;
+  int np = GetNP();
+  int ne = GetNE();
+  TABLE<int> conto(np);
+  for (i = 1; i <= ne; i++)
+    {
+      const Element & el = VolumeElement(i);
+
+      if (el.GetType() == PRISM)
+	{
+	  for (j = 1; j <= 6; j++)
+	    {
+	      int n1 = el.PNum (j);
+	      int n2 = el.PNum ((j+2)%6+1);
+	      //	    if (n1 != n2)
+	      {
+		int found = 0;
+		for (k = 1; k <= conto.EntrySize(n1); k++)
+		  if (conto.Get(n1, k) == n2)
+		    {
+		      found = 1;
+		      break;
+		    }
+		if (!found)
+		  conto.Add (n1, n2);
+	      }
+	    }
+	}
+      else if (el.GetType() == PYRAMID)
+	{
+	  for (j = 1; j <= 4; j++)
+	    {
+	      int n1, n2;
+	      switch (j)
+		{
+		case 1: n1 = 1; n2 = 4; break;
+		case 2: n1 = 4; n2 = 1; break;
+		case 3: n1 = 2; n2 = 3; break;
+		case 4: n1 = 3; n2 = 2; break;
+		}
+
+	      int found = 0;
+	      for (k = 1; k <= conto.EntrySize(n1); k++)
+		if (conto.Get(n1, k) == n2)
+		  {
+		    found = 1;
+		    break;
+		  }
+	      if (!found)
+		conto.Add (n1, n2);
+	    }
+	}
+    }
+  
+  connectedtonode.SetSize(np);
+  for (i = 1; i <= np; i++)
+    connectedtonode.Elem(i) = 0;
+  
+  for (i = 1; i <= np; i++)
+    if (connectedtonode.Elem(i) == 0)
+      {
+	connectedtonode.Elem(i) = i;
+	ConnectToNodeRec (i, i, conto);
+      }
+  
+
+
+}
+
+void Mesh :: ConnectToNodeRec (int node, int tonode, 
+		       const TABLE<int> & conto)
+{
+  int i, n2;
+  //  (*testout) << "connect " << node << " to " << tonode << endl;
+  for (i = 1; i <= conto.EntrySize(node); i++)
+    {
+      n2 = conto.Get(node, i);
+      if (!connectedtonode.Get(n2))
+	{
+	  connectedtonode.Elem(n2) = tonode;
+	  ConnectToNodeRec (n2, tonode, conto);
+	}
+    }
+}
+*/
+
+
+bool Mesh :: PureTrigMesh (int faceindex) const
+{
+  if (!faceindex)
+    return !mparam.quad;
+
+  int i;
+  for (i = 1; i <= GetNSE(); i++)
+    if (SurfaceElement(i).GetIndex() == faceindex &&
+	SurfaceElement(i).GetNP() != 3)
+      return 0;
+  return 1;
+}
+
+bool Mesh :: PureTetMesh () const
+{
+  for (ElementIndex ei = 0; ei < GetNE(); ei++)
+    if (VolumeElement(ei).GetNP() != 4)
+      return 0;
+  return 1;
+}
+
+void Mesh :: UpdateTopology()
+{
+  topology->Update();
+  clusters->Update();
+}
+
+
+void Mesh :: SetMaterial (int domnr, const char * mat)
+{
+  if (domnr > materials.Size())
+    {
+      int olds = materials.Size();
+      materials.SetSize (domnr);
+      for (int i = olds; i < domnr; i++)
+	materials[i] = 0;
+    }
+  materials.Elem(domnr) = new char[strlen(mat+1)];
+  strcpy (materials.Elem(domnr), mat);
+}
+
+const char * Mesh :: GetMaterial (int domnr) const
+{
+  if (domnr <= materials.Size())
+    return materials.Get(domnr);
+  return 0;
+}
+
+
+
+
+
+void Mesh :: PrintMemInfo (ostream & ost) const
+{
+  ost << "Mesh Mem:" << endl;
+
+  ost << GetNP() << " Points, of size " 
+      << sizeof (Point3d) << " + " << sizeof(POINTTYPE) << " = "
+      << GetNP() * (sizeof (Point3d) + sizeof(POINTTYPE)) << endl;
+
+  ost << GetNSE() << " Surface elements, of size " 
+      << sizeof (Element2d) << " = " 
+      << GetNSE() * sizeof(Element2d) << endl;
+
+  ost << GetNE() << " Volume elements, of size " 
+      << sizeof (Element) << " = " 
+      << GetNE() * sizeof(Element) << endl;
+
+  ost << "surfs on node:";
+  surfacesonnode.PrintMemInfo (cout);
+  
+  ost << "boundaryedges: ";
+  if (boundaryedges)
+    boundaryedges->PrintMemInfo (cout);
+
+  ost << "surfelementht: ";
+  if (surfelementht)
+    surfelementht->PrintMemInfo (cout);
+}
+}
diff --git a/Netgen/libsrc/meshing/meshclass.hpp b/Netgen/libsrc/meshing/meshclass.hpp
new file mode 100644
index 0000000000..4c03a36e14
--- /dev/null
+++ b/Netgen/libsrc/meshing/meshclass.hpp
@@ -0,0 +1,591 @@
+#ifndef MESHCLASS
+#define MESHCLASS
+
+/**************************************************************************/
+/* File:   meshclass.hh                                                    */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   20. Nov. 99                                                    */
+/**************************************************************************/
+
+/*
+  The mesh class
+*/
+
+
+
+enum resthtype { RESTRICTH_FACE, RESTRICTH_EDGE, 
+		 RESTRICTH_SURFACEELEMENT, RESTRICTH_POINT, RESTRICTH_SEGMENT };
+
+/// 2d/3d mesh
+class Mesh
+{
+public:
+  //  typedef MoveableArray<MeshPoint> T_POINTS;
+  //  typedef MoveableArray<Element> T_VOLELEMENTS;
+  //  typedef MoveableArray<Element2d> T_SURFELEMENTS;
+
+  typedef ARRAY<MeshPoint,PointIndex::BASE> T_POINTS;
+  typedef ARRAY<Element> T_VOLELEMENTS;
+  typedef ARRAY<Element2d> T_SURFELEMENTS;
+
+
+private:
+  /// point coordinates
+  T_POINTS points;
+  /// type of point, is set in calcsurfacesofnode
+  ARRAY<POINTTYPE,PointIndex::BASE> ptyps;
+  /// type of element, set in calcsurfacesofnode
+  ARRAY<ELEMENTTYPE> eltyps;
+
+  /// line-segments at edges
+  ARRAY<Segment> segments;
+  /// surface elements, 2d-inner elements
+  T_SURFELEMENTS surfelements;
+  /// volume elements
+  T_VOLELEMENTS volelements;
+  /// points will be fixed forever
+  ARRAY<PointIndex> lockedpoints;
+
+
+  /// surface indices at boundary nodes
+  TABLE<int,PointIndex::BASE> surfacesonnode;
+  /// boundary edges  (1..normal bedge, 2..segment)
+  INDEX_2_CLOSED_HASHTABLE<int> * boundaryedges;
+  ///
+  INDEX_2_HASHTABLE<int> * segmentht;
+  ///
+  INDEX_3_HASHTABLE<int> * surfelementht;
+  /// faces of rest-solid
+  ARRAY<Element2d> openelements;
+  /// open segmenets for surface meshing  
+  ARRAY<Segment> opensegments;
+
+
+
+  /**
+     Representation of local mesh-size h
+  */
+  LocalH * lochfunc;
+  ///
+  double hglob;
+  ///
+  ARRAY<double> maxhdomain;
+  
+  /**
+     the face-index of the surface element maps into
+     this table.
+  */
+  ARRAY<FaceDescriptor> facedecoding;
+
+  /// sub-domain materials 
+  ARRAY<char*> materials;
+
+  /// Periodic surface, close surface, etc. identifications
+  Identifications ident;
+
+
+  /// number of vertices (if < 0, use np)
+  int numvertices;
+
+  /// geometric search tree for interval intersection search
+  Box3dTree * elementsearchtree;
+  /// time stamp for tree
+  int elementsearchtreets;
+
+  /// element -> face, element -> edge etc ...
+  class MeshTopology * topology;
+  /// methods for high order elements
+  class CurvedElements * curvedelems;
+  /// nodes identified by close points 
+  class AnisotropicClusters * clusters;
+
+  /// space dimension (2 or 3)
+  int dimension;
+  
+  /// changed by every minor modification (addpoint, ...)
+  int timestamp;
+  /// changed after finishing global algorithm (improve, ...)
+  int majortimestamp;
+
+  /// mesh access semaphor.
+  NgMutex mutex;
+
+
+public:
+  
+  
+  /// number of refinement levels
+  int mglevels;
+  /// refinement hierarchy
+  ARRAY<INDEX_2,PointIndex::BASE> mlbetweennodes;
+  /// parent element of volume element
+  ARRAY<int> mlparentelement;
+  /// parent element of surface element
+  ARRAY<int> mlparentsurfaceelement;
+
+
+
+  ///
+  Mesh();
+  ///
+  ~Mesh();
+
+  ///
+  void DeleteMesh();
+  
+  ///
+  void ClearSurfaceElements()
+  { 
+    surfelements.SetSize(0); 
+    timestamp = NextTimeStamp();
+  }
+
+  ///
+  void ClearVolumeElements()
+  {
+    volelements.SetSize(0); 
+    eltyps.SetSize(0);
+    timestamp = NextTimeStamp();
+  }
+
+  ///
+  void ClearSegments()
+  { 
+    segments.SetSize(0); 
+    timestamp = NextTimeStamp();
+  }
+  
+  ///
+  bool TestOk () const;
+
+
+  PointIndex AddPoint (const Point3d & p, int layer = 1);
+  int GetNP () const { return points.Size(); }
+
+  MeshPoint & Point(int i) { return points.Elem(i); }
+  MeshPoint & Point(PointIndex pi) { return points[pi]; }
+  const MeshPoint & Point(int i) const { return points.Get(i); }
+  const MeshPoint & Point(PointIndex pi) const { return points[pi]; }
+
+  const MeshPoint & operator[] (PointIndex pi) const { return points[pi]; }
+  MeshPoint & operator[] (PointIndex pi) { return points[pi]; }
+
+  POINTTYPE PointType (int i) const { return ptyps.Get(i); }
+  POINTTYPE PointType (PointIndex pi) const { return ptyps[pi]; }
+
+  const T_POINTS & Points() const { return points; }
+  T_POINTS & Points() { return points; }
+  ARRAY<POINTTYPE,PointIndex::BASE> & PointTypes() { return ptyps; }
+
+
+
+
+
+
+  SegmentIndex AddSegment (const Segment & s);
+  void DeleteSegment (int segnr)
+  {
+    segments.Elem(segnr).p1 = PointIndex::BASE-1;
+    segments.Elem(segnr).p2 = PointIndex::BASE-1;
+  }
+
+  int GetNSeg () const { return segments.Size(); }
+  Segment & LineSegment(int i) { return segments.Elem(i); }
+  const Segment & LineSegment(int i) const { return segments.Get(i); }
+  
+  const Segment & operator[] (SegmentIndex si) const
+  { return segments[si]; }
+  Segment & operator[] (SegmentIndex si)
+  { return segments[si]; }
+
+
+
+
+  SurfaceElementIndex AddSurfaceElement (const Element2d & el);
+  void DeleteSurfaceElement (int eli)
+  { 
+    surfelements.Elem(eli).Delete();
+    surfelements.Elem(eli).PNum(1) = -1; 
+    surfelements.Elem(eli).PNum(2) = -1; 
+    surfelements.Elem(eli).PNum(3) = -1; 
+    timestamp = NextTimeStamp();
+  }
+
+  void DeleteSurfaceElement (SurfaceElementIndex eli)
+  {
+    DeleteSurfaceElement (int(eli)+1);
+  }
+
+  int GetNSE () const { return surfelements.Size(); }
+  Element2d & SurfaceElement(int i) { return surfelements.Elem(i); }
+  const Element2d & SurfaceElement(int i) const { return surfelements.Get(i); }
+
+  Element2d & SurfaceElement(SurfaceElementIndex i)
+  { return surfelements[i]; }
+  const Element2d & SurfaceElement(SurfaceElementIndex i) const
+  { return surfelements[i]; }
+
+  const Element2d & operator[] (SurfaceElementIndex ei) const
+  { return surfelements[ei]; }
+  Element2d & operator[] (SurfaceElementIndex ei)
+  { return surfelements[ei]; }
+
+  
+  void GetSurfaceElementsOfFace (int facenr, ARRAY<SurfaceElementIndex> & sei) const;
+
+
+
+  ElementIndex AddVolumeElement (const Element & el);
+
+  int GetNE () const { return volelements.Size(); }
+
+  Element & VolumeElement(int i) { return volelements.Elem(i); }
+  const Element & VolumeElement(int i) const { return volelements.Get(i); }
+  Element & VolumeElement(ElementIndex i) { return volelements[i]; }
+  const Element & VolumeElement(ElementIndex i) const { return volelements[i]; }
+
+  const Element & operator[] (ElementIndex ei) const 
+  { return volelements[ei]; }
+  Element & operator[] (ElementIndex ei)
+  { return volelements[ei]; }
+
+
+
+
+
+  ELEMENTTYPE ElementType (int i) const { return eltyps.Get(i); }
+  ELEMENTTYPE ElementType (ElementIndex i) const { return eltyps[i]; }
+
+  const T_VOLELEMENTS & VolumeElements() const { return volelements; }
+  T_VOLELEMENTS & VolumeElements() { return volelements; }
+
+
+  ///
+  double ElementError (int eli) const;
+
+  /// 
+  void AddLockedPoint (PointIndex pi);
+  ///
+  void ClearLockedPoints ();
+
+  const ARRAY<PointIndex> & LockedPoints() const
+  { return lockedpoints; }
+
+  /// Returns number of domains
+  int GetNDomains() const;
+
+
+  ///
+  int GetDimension() const 
+  { return dimension; }
+  void SetDimension(int dim)
+  { dimension = dim; }
+
+  /// sets internal tables
+  void CalcSurfacesOfNode ();
+
+  /// additional (temporarily) fix points 
+  void FixPoints (const BitArray & fixpoints);
+
+  /**
+     finds elements without neighbour and
+     boundary elements without inner element.
+     Results are stored in openelements.
+     if dom == 0, all sub-domains, else subdomain dom */
+  void FindOpenElements (int dom = 0);
+
+  
+  /**
+     finds segments without surface element,
+     and surface elements without neighbours.
+     store in opensegmentsy
+  */
+  void FindOpenSegments (int surfnr = 0);
+  /**
+     remove one layer of surface elements
+  */
+  void RemoveOneLayerSurfaceElements ();
+
+
+  int GetNOpenSegments () { return opensegments.Size(); }
+  const Segment & GetOpenSegment (int nr) { return opensegments.Get(nr); }
+  
+  /**
+     Checks overlap of boundary
+     return == 1, iff overlap
+  */
+  int CheckOverlappingBoundary ();
+  /**
+     Checks consistent boundary
+     return == 0, everything ok
+  */
+  int CheckConsistentBoundary () const;
+
+  /*
+    checks element orientation
+  */
+  int CheckVolumeMesh () const;
+
+
+  /**
+     finds average h of surface surfnr if surfnr > 0,
+     else of all surfaces.
+  */
+  double AverageH (int surfnr = 0) const;
+  /// Calculates localh 
+  void CalcLocalH ();
+  ///
+  void SetLocalH (const Point3d & pmin, const Point3d & pmax, double grading);
+  ///
+  void RestrictLocalH (const Point3d & p, double hloc);
+  ///
+  void RestrictLocalHLine (const Point3d & p1, const Point3d & p2, 
+			   double hloc);
+  /// number of elements per radius
+  void CalcLocalHFromSurfaceCurvature(double elperr);
+  ///
+  void RestrictLocalH (resthtype rht, int nr, double loch);
+  ///
+  void LoadLocalMeshSize (istream & ist);
+  ///
+  void SetGlobalH (double h);
+  ///
+  double MaxHDomain (int dom) const;
+  ///
+  void SetMaxHDomain (const ARRAY<double> & mhd);
+  ///
+  double GetH (const Point3d & p) const;
+  ///
+  double GetMinH (const Point3d & pmin, const Point3d & pmax);
+  ///
+  LocalH & LocalHFunction () { return * lochfunc; }
+
+  /// Find bounding box
+  void GetBox (Point3d & pmin, Point3d & pmax, int dom = -1) const;
+
+  /// Find bounding box of points of typ ptyp or less
+  void GetBox (Point3d & pmin, Point3d & pmax, POINTTYPE ptyp ) const;
+
+  ///
+  int GetNOpenElements() const
+  { return openelements.Size(); }
+  ///
+  const Element2d & OpenElement(int i) const
+  { return openelements.Get(i); }
+
+
+  /// are also quads open elements
+  int HasOpenQuads () const;
+
+  /// split into connected pieces
+  void SplitIntoParts ();
+
+  /// 
+  void SplitSeparatedFaces ();
+
+  /// Refines mesh and projects points to true surface
+  // void Refine (int levels, const CSGeometry * geom);
+  
+
+  bool BoundaryEdge (PointIndex pi1, PointIndex pi2) const
+  {
+    INDEX_2 i2 (pi1, pi2);
+    i2.Sort();
+    return boundaryedges->Used (i2);
+  }
+
+  bool IsSegment (PointIndex pi1, PointIndex pi2) const
+  {
+    INDEX_2 i2 (pi1, pi2);
+    i2.Sort();
+    return segmentht->Used (i2);
+  }
+
+  /**
+     Remove unused points. etc.
+  */
+  void Compress ();
+
+  ///
+  void Save (const char * filename) const;
+  ///
+  void Load (const char * filename);
+
+
+  ///
+  void ImproveMesh (OPTIMIZEGOAL goal = OPT_QUALITY);
+
+  ///
+  void ImproveMeshJacobian (OPTIMIZEGOAL goal = OPT_QUALITY);
+  
+
+  /*
+#ifdef SOLIDGEOM
+  /// old
+  void ImproveMesh (const CSGeometry & surfaces, 
+		    OPTIMIZEGOAL goal = OPT_QUALITY);
+#endif  
+  */
+
+  /**
+     free nodes in environment of openelements 
+     for optimiztion
+  */
+  void FreeOpenElementsEnvironment (int layers);
+
+  ///
+  bool LegalTet (Element & el) const
+  {
+    if (el.IllegalValid())
+      return !el.Illegal();
+    return LegalTet2 (el);
+  }
+  ///
+  bool LegalTet2 (Element & el) const;
+
+
+  ///
+  bool LegalTrig (const Element2d & el) const;
+  /**
+     if values non-null, return values in 4-double array:
+     triangle angles min/max, tetangles min/max
+     if null, output results on cout
+  */
+  void CalcMinMaxAngle (double badellimit, double * retvalues = NULL);
+
+  /*
+    Marks elements which are dangerous to refine
+    return: number of illegal elements
+  */
+  int MarkIllegalElements ();
+
+  /// orient surface mesh, for one sub-domain only
+  void SurfaceMeshOrientation ();
+
+  /// convert mixed element mesh to tet-mesh
+  void Split2Tets();
+
+
+  /// build box-search tree
+  void BuildElementSearchTree ();
+  /// gives element of point, barycentric coordinates
+  int GetElementOfPoint (const Point3d & p,
+			 double * lami) const;
+
+  /// give list of vol elements which are int the box(p1,p2)
+  void GetIntersectingVolEls(const Point3d& p1, const Point3d& p2, 
+			     ARRAY<int> & locels) const;
+
+  ///
+  int AddFaceDescriptor(const FaceDescriptor& fd)
+  { return facedecoding.Append(fd); }
+
+
+  ///
+  void SetMaterial (int domnr, const char * mat);
+  ///
+  const char * GetMaterial (int domnr) const;
+    
+
+  ///
+  void ClearFaceDescriptors()
+  { facedecoding.SetSize(0); }
+
+  ///
+  int GetNFD () const
+  { return facedecoding.Size(); }
+
+  const FaceDescriptor & GetFaceDescriptor (int i) const
+  { return facedecoding.Get(i); }
+
+  ///
+  FaceDescriptor & GetFaceDescriptor (int i) 
+  { return facedecoding.Elem(i); }
+
+#ifdef NONE
+  /*
+    Identify points pi1 and pi2, due to
+    identification nr identnr
+  */
+  void AddIdentification (int pi1, int pi2, int identnr);
+
+  int GetIdentification (int pi1, int pi2) const;
+  int GetIdentificationSym (int pi1, int pi2) const;
+  ///
+  INDEX_2_HASHTABLE<int> & GetIdentifiedPoints () 
+  { 
+    return *identifiedpoints; 
+  }
+
+  ///
+  void GetIdentificationMap (int identnr, ARRAY<int> & identmap) const;
+  ///
+  void GetIdentificationPairs (int identnr, ARRAY<INDEX_2> & identpairs) const;
+  ///
+  int GetMaxIdentificationNr () const
+  { 
+    return maxidentnr; 
+  }
+#endif
+
+  /// return periodic, close surface etc. identifications
+  Identifications & GetIdentifications () { return ident; }
+  /// return periodic, close surface etc. identifications
+  const Identifications & GetIdentifications () const { return ident; }
+
+
+
+  /// find number of vertices
+  void ComputeNVertices ();
+  /// number of vertices (no edge-midpoints)
+  int GetNV () const;
+  /// remove edge points
+  void SetNP (int np);
+
+  /*
+ /// build connected nodes along prism stack
+ void BuildConnectedNodes ();
+ void ConnectToNodeRec (int node, int tonode, 
+ const TABLE<int> & conto);
+  */
+
+  bool PureTrigMesh (int faceindex = 0) const;
+  bool PureTetMesh () const;
+
+
+  const class MeshTopology & GetTopology () const
+  { return *topology; }
+  void UpdateTopology();
+  
+  class CurvedElements & GetCurvedElements () const
+  { return *curvedelems; }
+
+  const class AnisotropicClusters & GetClusters () const
+  { return *clusters; }
+
+
+
+  int GetTimeStamp() const { return timestamp; }
+  void SetNextTimeStamp() 
+  { timestamp = NextTimeStamp(); }
+
+  int GetMajorTimeStamp() const { return majortimestamp; }
+  void SetNextMajorTimeStamp() 
+  { majortimestamp = timestamp = NextTimeStamp(); }
+
+
+  /// return mutex
+  NgMutex & Mutex ()   { return mutex; }
+
+  ///
+  friend void OptimizeRestart (Mesh & mesh3d);
+  ///
+  void PrintMemInfo (ostream & ost) const;
+  /// 
+  friend class Meshing3;
+};
+
+
+
+
+#endif
diff --git a/Netgen/libsrc/meshing/meshfunc.cpp b/Netgen/libsrc/meshing/meshfunc.cpp
new file mode 100644
index 0000000000..a3459ae71f
--- /dev/null
+++ b/Netgen/libsrc/meshing/meshfunc.cpp
@@ -0,0 +1,745 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+namespace netgen
+{
+  extern const char * tetrules2[];
+  extern const char * prismrules2[];
+  extern const char * pyramidrules[];
+  extern const char * pyramidrules2[];
+
+
+  extern double teterrpow; 
+  MESHING3_RESULT MeshVolume (MeshingParameters & mp, Mesh& mesh3d)
+  {
+    int i, k, oldne;
+    PointIndex pi;
+
+    int meshed;
+    int cntsteps; 
+
+
+    //  PlotStatistics3d * pstat;
+    //  pstat = new TerminalPlotStatistics3d;
+
+
+    ARRAY<INDEX_2> connectednodes;
+
+    mesh3d.Compress();
+
+    //  mesh3d.PrintMemInfo (cout);
+
+    int nonconsist = 0;
+    for (k = 1; k <= mesh3d.GetNDomains(); k++)
+      {
+	PrintMessage (3, "Check subdomain ", k, " / ", mesh3d.GetNDomains());
+
+	mesh3d.FindOpenElements(k);
+
+	int res = 0; // mesh3d.CheckOverlappingBoundary();
+	if (res)
+	  {
+	    PrintError ("Surface is overlapping !!");
+	    nonconsist = 1;
+	  }
+
+	res = mesh3d.CheckConsistentBoundary();
+	if (res)
+	  {
+	    PrintError ("Surface mesh not consistent");
+	    nonconsist = 1;
+	  }
+      }
+
+    if (nonconsist)
+      {
+	PrintError ("Stop meshing since surface mesh not consistent");
+	throw NgException ("Stop meshing since surface mesh not consistent");
+      }
+
+    double globmaxh = mp.maxh;
+
+    for (k = 1; k <= mesh3d.GetNDomains(); k++)
+      {
+	if (multithread.terminate)
+	  break;
+
+	PrintMessage (2, "");
+	PrintMessage (1, "Meshing subdomain ", k, " of ", mesh3d.GetNDomains());
+ 
+	mp.maxh = min2 (globmaxh, mesh3d.MaxHDomain(k));
+
+	mesh3d.CalcSurfacesOfNode();
+	mesh3d.FindOpenElements(k);
+
+	/*
+	  if (mesh3d.CheckOverlappingBoundary())
+	  {
+	  (*mycout) << "overlapping" << endl;
+	  (*testout) << "overlapping !!!" << endl;
+	  continue;
+	  }
+	  if (mesh3d.CheckConsistentBoundary())
+	  {
+	  (*mycout) << "boundary not consistent" << endl;
+	  (*testout) << "boundary not consistent !!!" << endl;
+	  continue;
+	  }
+	*/
+
+	if (!mesh3d.GetNOpenElements())
+	  continue;
+
+	int qstep;
+	for (qstep = 1; qstep <= 3; qstep++)
+	  {
+	    if (mesh3d.HasOpenQuads())
+	      {
+		string rulefile = ngdir;
+		/*
+		  char rulefile[255];
+		  strcpy (rulefile, ngdir);
+		*/
+		const char ** rulep = NULL;
+		switch (qstep)
+		  {
+		  case 1:
+		    //		  strcat (rulefile, "/rules/prisms2.rls");
+		    rulefile += "/rules/prisms2.rls";
+		    rulep = prismrules2;
+		    break;
+		  case 2: // connect pyramid to triangle
+		    //		  strcat (rulefile, "/rules/pyramids2.rls");
+		    rulefile += "/rules/pyramids2.rls";
+		    rulep = pyramidrules2;
+		    break;
+		  case 3: // connect to vis-a-vis point
+		    //		  strcat (rulefile, "/rules/pyramids.rls");
+		    rulefile += "/rules/pyramids.rls";
+		    rulep = pyramidrules;
+		    break;
+		  }
+	      
+		//	      Meshing3 meshing(rulefile.c_str(), pstat);
+		Meshing3 meshing(NULL, rulep); 
+	      
+		MeshingParameters mpquad = mp;
+	      
+		mpquad.giveuptol = 15;
+		mpquad.baseelnp = 4;
+		mpquad.starshapeclass = 100;
+	      
+		for (pi = PointIndex::BASE; 
+		     pi < mesh3d.GetNP()+PointIndex::BASE; pi++)
+		  meshing.AddPoint (mesh3d[pi], pi);
+
+		mesh3d.GetIdentifications().GetPairs (0, connectednodes);
+		for (i = 1; i <= connectednodes.Size(); i++)
+		  meshing.AddConnectedPair (connectednodes.Get(i));
+	      
+		for (i = 1; i <= mesh3d.GetNOpenElements(); i++)
+		  {
+		    Element2d hel = mesh3d.OpenElement(i);
+		    meshing.AddBoundaryElement (hel);
+		  }
+	      
+		oldne = mesh3d.GetNE();
+	      
+		meshing.GenerateMesh (mesh3d, mpquad);
+	      
+		for (i = oldne + 1; i <= mesh3d.GetNE(); i++)
+		  mesh3d.VolumeElement(i).SetIndex (k);
+	      
+		(*testout) 
+		  << "mesh has " << mesh3d.GetNE() << " prism ? elements" << endl;
+	      
+		mesh3d.FindOpenElements(k);
+	      }
+	  }
+
+
+	if (mesh3d.HasOpenQuads())
+	  {
+	    PrintSysError ("mesh has still open quads");
+	    throw NgException ("Stop meshing since too many attempts");
+	    // return MESHING3_GIVEUP;
+	  }
+
+
+	if (mp.delaunay && mesh3d.GetNOpenElements())
+	  {
+	    Meshing3 meshing(NULL);
+	 
+	    mesh3d.FindOpenElements(k);
+	  
+
+	    for (pi = PointIndex::BASE; 
+		 pi < mesh3d.GetNP()+PointIndex::BASE; pi++)
+	      meshing.AddPoint (mesh3d[pi], pi);
+	  
+
+	    for (i = 1; i <= mesh3d.GetNOpenElements(); i++)
+	      meshing.AddBoundaryElement (mesh3d.OpenElement(i));
+	  
+	    oldne = mesh3d.GetNE();
+	    /*
+	      if (globflags.GetDefineFlag ("blockfill"))
+	      {
+	      if (!globflags.GetDefineFlag ("localh"))
+	      meshing.BlockFill 
+	      (mesh3d, mp.h * globflags.GetNumFlag ("relblockfillh", 1));
+	      else
+	      meshing.BlockFillLocalH (mesh3d);
+	      }
+	    */
+
+	  
+	    //	  mp.blockfill = globflags.GetDefineFlag ("blockfill");
+	    meshing.Delaunay (mesh3d, mp);
+	    //	  return MESHING3_OK;
+
+	    for (i = oldne + 1; i <= mesh3d.GetNE(); i++)
+	      mesh3d.VolumeElement(i).SetIndex (k);
+
+	    PrintMessage (3, mesh3d.GetNP(), " points, ",
+			  mesh3d.GetNE(), " elements");
+	  }
+
+
+	cntsteps = 0;
+	do
+	  {
+	    if (multithread.terminate)
+	      break;
+
+	    //	  mesh3d.CalcSurfacesOfNode();
+	    mesh3d.FindOpenElements(k);
+	    PrintMessage (5, mesh3d.GetNOpenElements(), " open faces");
+	    cntsteps++;
+	    if (cntsteps > mp.maxoutersteps) 
+	      throw NgException ("Stop meshing since too many attempts");
+	    // return MESHING3_OUTERSTEPSEXCEEDED;
+
+	    /*
+	      if (mesh3d.CheckOverlappingBoundary())
+	      {
+	      (*mycout) << "overlapping" << endl;
+	      (*testout) << "overlapping !!!!" << endl;
+	      break;
+	      }
+	      if (mesh3d.CheckConsistentBoundary())
+	      {
+	      (*mycout) << "boundary not consistent" << endl;
+	      (*testout) << "boundary not consistent !!!" << endl;
+	      //	      break;
+	      }
+	    */
+
+
+	    /*
+	      char rulefile[255];
+	      strcpy (rulefile, ngdir);
+	      strcat (rulefile, "/tetra.rls");
+	    */
+	    string rulefile = ngdir + "/tetra.rls";
+	    PrintMessage (1, "start tetmeshing");
+
+	    //	  Meshing3 meshing(rulefile, pstat);
+	    Meshing3 meshing(NULL);
+      
+#ifdef MYGRAPH	  
+	    Point3d pmin, pmax;
+	    mesh3d.GetBox (pmin, pmax, k);
+	    rot.SetCenter (Center (pmin, pmax));
+#endif
+
+	    for (i = 1; i <= mesh3d.GetNP(); i++)
+	      meshing.AddPoint (mesh3d.Point(i), i);
+
+	    for (i = 1; i <= mesh3d.GetNOpenElements(); i++)
+	      meshing.AddBoundaryElement (mesh3d.OpenElement(i));
+
+
+	    oldne = mesh3d.GetNE();
+
+	    mp.giveuptol = 15; // int(globflags.GetNumFlag ("giveuptol", 15));
+	    mp.sloppy = 5;
+	    meshing.GenerateMesh (mesh3d, mp);
+
+	    for (i = oldne + 1; i <= mesh3d.GetNE(); i++)
+	      mesh3d.VolumeElement(i).SetIndex (k);
+	  
+	  
+	    mesh3d.CalcSurfacesOfNode();
+	    mesh3d.FindOpenElements(k);
+	  
+	    teterrpow = 2;
+	    if (mesh3d.GetNOpenElements() != 0)
+	      {
+		meshed = 0;
+		PrintMessage (5, mesh3d.GetNOpenElements(), " open faces found");
+
+		//	      mesh3d.Save ("tmp.vol");
+
+
+		MeshOptimize3d optmesh;
+
+		const char * optstr = "mcmstmcmstmcmstmcm";
+		int j;
+		for (j = 1; j <= strlen(optstr); j++)
+		  {
+		    mesh3d.CalcSurfacesOfNode();
+		    mesh3d.FreeOpenElementsEnvironment(2);
+
+		    switch (optstr[j-1])
+		      {
+		      case 'c': optmesh.CombineImprove(mesh3d, OPT_REST); break;
+		      case 'd': optmesh.SplitImprove(mesh3d, OPT_REST); break;
+		      case 's': optmesh.SwapImprove(mesh3d, OPT_REST); break;
+		      case 't': optmesh.SwapImprove2(mesh3d, OPT_REST); break;
+		      case 'm': mesh3d.ImproveMesh(OPT_REST); break;
+		      }	  
+
+		  }
+
+		mesh3d.FindOpenElements(k);	      
+		PrintMessage (3, "Call remove problem");
+		RemoveProblem (mesh3d);
+		mesh3d.FindOpenElements(k);
+	      }
+	    else
+	      {
+		meshed = 1;
+		PrintMessage (1, "Success !");
+	      }
+	  }
+	while (!meshed);
+
+	PrintMessage (1, mesh3d.GetNP(), " points, ",
+		      mesh3d.GetNE(), " elements");
+      }
+
+    mp.maxh = globmaxh;
+
+    MeshQuality3d (mesh3d);
+
+    //  delete pstat;
+
+    return MESHING3_OK;
+  }  
+
+
+
+
+  /*
+
+
+  MESHING3_RESULT MeshVolumeOld (MeshingParameters & mp, Mesh& mesh3d)
+  {
+  int i, k, oldne;
+
+
+  int meshed;
+  int cntsteps; 
+
+
+  PlotStatistics3d * pstat;
+  if (globflags.GetNumFlag("silentflag", 1) <= 2)
+  pstat = new XPlotStatistics3d;
+  else
+  pstat = new TerminalPlotStatistics3d;
+
+  cntsteps = 0;
+  do
+  {
+  cntsteps++;
+  if (cntsteps > mp.maxoutersteps) 
+  {
+  return MESHING3_OUTERSTEPSEXCEEDED;
+  }
+
+
+  int noldp = mesh3d.GetNP();
+      
+      
+  if ( (cntsteps == 1) && globflags.GetDefineFlag ("delaunay"))
+  {
+  cntsteps ++;
+
+  mesh3d.CalcSurfacesOfNode();
+
+
+  for (k = 1; k <= mesh3d.GetNDomains(); k++)
+  {
+  Meshing3 meshing(NULL, pstat);
+
+  mesh3d.FindOpenElements(k);
+	      
+  for (i = 1; i <= noldp; i++)
+  meshing.AddPoint (mesh3d.Point(i), i);
+	      
+  for (i = 1; i <= mesh3d.GetNOpenElements(); i++)
+  {
+  if (mesh3d.OpenElement(i).GetIndex() == k)
+  meshing.AddBoundaryElement (mesh3d.OpenElement(i));
+  }
+	      
+  oldne = mesh3d.GetNE();
+  if (globflags.GetDefineFlag ("blockfill"))
+  {
+  if (!globflags.GetDefineFlag ("localh"))
+  meshing.BlockFill 
+  (mesh3d, mp.h * globflags.GetNumFlag ("relblockfillh", 1));
+  else
+  meshing.BlockFillLocalH (mesh3d);
+  }
+	      
+  MeshingParameters mpd;
+  meshing.Delaunay (mesh3d, mpd);
+
+  for (i = oldne + 1; i <= mesh3d.GetNE(); i++)
+  mesh3d.VolumeElement(i).SetIndex (k);
+  }
+  }
+
+  noldp = mesh3d.GetNP();
+
+  mesh3d.CalcSurfacesOfNode();
+  mesh3d.FindOpenElements();
+  for (k = 1; k <= mesh3d.GetNDomains(); k++)
+  {
+  Meshing3 meshing(globflags.GetStringFlag ("rules3d", NULL), pstat);
+      
+  Point3d pmin, pmax;
+  mesh3d.GetBox (pmin, pmax, k);
+	  
+  rot.SetCenter (Center (pmin, pmax));
+
+  for (i = 1; i <= noldp; i++)
+  meshing.AddPoint (mesh3d.Point(i), i);
+
+  for (i = 1; i <= mesh3d.GetNOpenElements(); i++)
+  {
+  if (mesh3d.OpenElement(i).GetIndex() == k)
+  meshing.AddBoundaryElement (mesh3d.OpenElement(i));
+  }
+
+  oldne = mesh3d.GetNE();
+
+
+  if ( (cntsteps == 1) && globflags.GetDefineFlag ("blockfill"))
+  {
+  if (!globflags.GetDefineFlag ("localh"))
+  {
+  meshing.BlockFill 
+  (mesh3d, 
+  mp.h * globflags.GetNumFlag ("relblockfillh", 1));
+  }
+  else
+  {
+  meshing.BlockFillLocalH (mesh3d);
+  }
+  }
+
+
+  mp.giveuptol = int(globflags.GetNumFlag ("giveuptol", 15));
+
+  meshing.GenerateMesh (mesh3d, mp);
+
+  for (i = oldne + 1; i <= mesh3d.GetNE(); i++)
+  mesh3d.VolumeElement(i).SetIndex (k);
+  }
+
+
+
+  mesh3d.CalcSurfacesOfNode();
+  mesh3d.FindOpenElements();
+      
+  teterrpow = 2;
+  if (mesh3d.GetNOpenElements() != 0)
+  {
+  meshed = 0;
+  (*mycout) << "Open elements found, old" << endl;
+  const char * optstr = "mcmcmcmcm";
+  int j;
+  for (j = 1; j <= strlen(optstr); j++)
+  switch (optstr[j-1])
+  {
+  case 'c': mesh3d.CombineImprove(); break;
+  case 'd': mesh3d.SplitImprove(); break;
+  case 's': mesh3d.SwapImprove(); break;
+  case 'm': mesh3d.ImproveMesh(2); break;
+  }	  
+	  
+  (*mycout) << "Call remove" << endl;
+  RemoveProblem (mesh3d);
+  (*mycout) << "Problem removed" << endl;
+  }
+  else
+  meshed = 1;
+  }
+  while (!meshed);
+
+  MeshQuality3d (mesh3d);
+
+  return MESHING3_OK;
+  }  
+
+  */
+
+
+  MESHING3_RESULT MeshMixedVolume(MeshingParameters & mp, Mesh& mesh3d)
+  {
+    int i, j;
+    MESHING3_RESULT res;
+    Point3d pmin, pmax;
+
+    mp.giveuptol = 10;
+    mp.baseelnp = 4;
+    mp.starshapeclass = 100;
+
+    //  TerminalPlotStatistics3d pstat;
+  
+    Meshing3 meshing1("pyramids.rls");
+    for (i = 1; i <= mesh3d.GetNP(); i++)
+      meshing1.AddPoint (mesh3d.Point(i), i);
+
+    mesh3d.FindOpenElements();
+    for (i = 1; i <= mesh3d.GetNOpenElements(); i++)
+      if (mesh3d.OpenElement(i).GetIndex() == 1)
+	meshing1.AddBoundaryElement (mesh3d.OpenElement(i));
+
+    res = meshing1.GenerateMesh (mesh3d, mp);
+
+    mesh3d.GetBox (pmin, pmax);
+    PrintMessage (1, "Mesh pyramids, res = ", res);
+    if (res)
+      exit (1);
+
+
+    for (i = 1; i <= mesh3d.GetNE(); i++)
+      mesh3d.VolumeElement(i).SetIndex (1);
+
+    // do delaunay
+  
+    mp.baseelnp = 0;
+    mp.starshapeclass = 5;
+
+    Meshing3 meshing2(NULL);
+    for (i = 1; i <= mesh3d.GetNP(); i++)
+      meshing2.AddPoint (mesh3d.Point(i), i);
+    
+    mesh3d.FindOpenElements();
+    for (i = 1; i <= mesh3d.GetNOpenElements(); i++)
+      if (mesh3d.OpenElement(i).GetIndex() == 1)
+	meshing2.AddBoundaryElement (mesh3d.OpenElement(i));
+
+    MeshingParameters mpd;
+    meshing2.Delaunay (mesh3d, mpd);
+
+    for (i = 1; i <= mesh3d.GetNE(); i++)
+      mesh3d.VolumeElement(i).SetIndex (1);
+
+
+    mp.baseelnp = 0;
+    mp.giveuptol = 10;
+
+    for (int trials = 1; trials <= 50; trials++)
+      {
+	if (multithread.terminate)
+	  return MESHING3_TERMINATE;
+
+	Meshing3 meshing3("tetra.rls");
+	for (i = 1; i <= mesh3d.GetNP(); i++)
+	  meshing3.AddPoint (mesh3d.Point(i), i);
+      
+	mesh3d.FindOpenElements();
+	for (i = 1; i <= mesh3d.GetNOpenElements(); i++)
+	  if (mesh3d.OpenElement(i).GetIndex() == 1)
+	    meshing3.AddBoundaryElement (mesh3d.OpenElement(i));
+      
+	if (trials > 1)
+	  CheckSurfaceMesh2 (mesh3d);
+	res = meshing3.GenerateMesh (mesh3d, mp);
+      
+	for (i = 1; i <= mesh3d.GetNE(); i++)
+	  mesh3d.VolumeElement(i).SetIndex (1);
+
+	if (res == 0) break;
+
+
+
+	for (i = 1; i <= mesh3d.GetNE(); i++)
+	  {
+	    const Element & el = mesh3d.VolumeElement(i);
+	    if (el.GetNP() != 4)
+	      {
+		for (j = 1; j <= el.GetNP(); j++)
+		  mesh3d.AddLockedPoint (el.PNum(j));
+	      }
+	  }
+
+	mesh3d.CalcSurfacesOfNode();
+	mesh3d.FindOpenElements();
+
+	MeshOptimize3d optmesh;
+
+	teterrpow = 2;
+	const char * optstr = "mcmcmcmcm";
+	for (j = 1; j <= strlen(optstr); j++)
+	  switch (optstr[j-1])
+	    {
+	    case 'c': optmesh.CombineImprove(mesh3d, OPT_REST); break;
+	    case 'd': optmesh.SplitImprove(mesh3d); break;
+	    case 's': optmesh.SwapImprove(mesh3d); break;
+	    case 'm': mesh3d.ImproveMesh(); break;
+	    }	  
+	        
+	RemoveProblem (mesh3d);
+      }
+
+
+    PrintMessage (1, "Meshing tets, res = ", res);
+    if (res)
+      {
+	mesh3d.FindOpenElements();
+	PrintSysError (1, "Open elemetns: ", mesh3d.GetNOpenElements());
+	exit (1);
+      }
+
+
+  
+    for (i = 1; i <= mesh3d.GetNE(); i++)
+      {
+	const Element & el = mesh3d.VolumeElement(i);
+	if (el.GetNP() != 4)
+	  {
+	    for (j = 1; j <= el.GetNP(); j++)
+	      mesh3d.AddLockedPoint (el.PNum(j));
+	  }
+      }
+  
+    mesh3d.CalcSurfacesOfNode();
+    mesh3d.FindOpenElements();
+  
+    MeshOptimize3d optmesh;
+
+    teterrpow = 2;
+    const char * optstr = "mcmcmcmcm";
+    for (j = 1; j <= strlen(optstr); j++)
+      switch (optstr[j-1])
+	{
+	case 'c': optmesh.CombineImprove(mesh3d, OPT_REST); break;
+	case 'd': optmesh.SplitImprove(mesh3d); break;
+	case 's': optmesh.SwapImprove(mesh3d); break;
+	case 'm': mesh3d.ImproveMesh(); break;
+	}	  
+
+
+    return MESHING3_OK;
+  }
+
+
+
+
+
+
+
+  MESHING3_RESULT OptimizeVolume (MeshingParameters & mp, 
+				  Mesh & mesh3d,
+				  const CSGeometry * geometry)
+  {
+    int i, j;
+
+    PrintMessage (1, "Volume Optimization");
+
+    /*
+      if (!mesh3d.PureTetMesh())
+      return MESHING3_OK;
+    */
+
+    // (*mycout) << "optstring = " << mp.optimize3d << endl;
+    /*
+      const char * optstr = globflags.GetStringFlag ("optimize3d", "cmh");
+      int optsteps = int (globflags.GetNumFlag ("optsteps3d", 2));
+    */
+
+    mesh3d.CalcSurfacesOfNode();
+    for (i = 1; i <= mp.optsteps3d; i++)
+      {
+	if (multithread.terminate)
+	  break;
+
+	MeshOptimize3d optmesh;
+
+	teterrpow = mp.opterrpow;
+	for (j = 1; j <= strlen(mp.optimize3d); j++)
+	  {
+	    if (multithread.terminate)
+	      break;
+
+	    switch (mp.optimize3d[j-1])
+	      {
+	      case 'c': optmesh.CombineImprove(mesh3d, OPT_REST); break;
+	      case 'd': optmesh.SplitImprove(mesh3d); break;
+	      case 's': optmesh.SwapImprove(mesh3d); break;
+	      case 't': optmesh.SwapImprove2(mesh3d); break;
+#ifdef SOLIDGEOM
+	      case 'm': mesh3d.ImproveMesh(*geometry); break;
+	      case 'M': mesh3d.ImproveMesh(*geometry); break;
+#else
+	      case 'm': mesh3d.ImproveMesh(); break;
+	      case 'M': mesh3d.ImproveMesh(); break;
+#endif
+	      
+	      case 'j': mesh3d.ImproveMeshJacobian(); break;
+	      }
+	  }
+	MeshQuality3d (mesh3d);
+      }
+  
+    return MESHING3_OK;
+  }
+
+
+
+
+  void RemoveIllegalElements (Mesh & mesh3d)
+  {
+    int it = 10;
+    int nillegal, oldn;
+    int i;
+
+    PrintMessage (1, "Remove Illegal Elements");
+    // return, if non-pure tet-mesh
+    /*
+      if (!mesh3d.PureTetMesh())
+      return;
+    */
+    mesh3d.CalcSurfacesOfNode();
+
+    nillegal = mesh3d.MarkIllegalElements();
+
+    MeshOptimize3d optmesh;
+    while (nillegal && (it--) > 0)
+      {
+	if (multithread.terminate)
+	  break;
+
+	PrintMessage (5, nillegal, " illegal tets");
+	optmesh.SplitImprove (mesh3d, OPT_LEGAL);
+
+	mesh3d.MarkIllegalElements();  // test
+	optmesh.SwapImprove (mesh3d, OPT_LEGAL);
+	mesh3d.MarkIllegalElements();  // test
+	optmesh.SwapImprove2 (mesh3d, OPT_LEGAL);
+
+	oldn = nillegal;
+	nillegal = mesh3d.MarkIllegalElements();
+
+	if (oldn != nillegal)
+	  it = 10;
+      }
+    PrintMessage (5, nillegal, " illegal tets");
+  }
+}
diff --git a/Netgen/libsrc/meshing/meshfunc.hpp b/Netgen/libsrc/meshing/meshfunc.hpp
new file mode 100644
index 0000000000..0e530ed2f0
--- /dev/null
+++ b/Netgen/libsrc/meshing/meshfunc.hpp
@@ -0,0 +1,42 @@
+#ifndef FILE_MESHFUNC
+#define FILE_MESHFUNC
+
+/**************************************************************************/
+/* File:   meshfunc.hh                                                    */
+/* Author: Johannes Gerstmayr                                             */
+/* Date:   26. Jan. 98                                                    */
+/**************************************************************************/
+
+
+/*
+  Functions for mesh-generations strategies
+ */
+
+class Mesh;
+class MeshingParameters3;
+class CSGeometry;
+
+/// Build tet-mesh
+MESHING3_RESULT MeshVolume(MeshingParameters & mp, Mesh& mesh3d);
+
+/// Build mixed-element mesh
+MESHING3_RESULT MeshMixedVolume(MeshingParameters & mp, Mesh& mesh3d);
+
+/// Optimize tet-mesh
+MESHING3_RESULT OptimizeVolume(MeshingParameters & mp, Mesh& mesh3d,
+			       const CSGeometry * geometry = NULL);
+
+void RemoveIllegalElements (Mesh & mesh3d);
+
+
+enum MESHING_STEP { 
+  MESHCONST_ANALYSE = 1,
+  MESHCONST_MESHEDGES = 2,
+  MESHCONST_MESHSURFACE = 3,
+  MESHCONST_OPTSURFACE = 4,
+  MESHCONST_MESHVOLUME = 5,
+  MESHCONST_OPTVOLUME = 6
+};
+
+
+#endif
diff --git a/Netgen/libsrc/meshing/meshfunc2d.cpp b/Netgen/libsrc/meshing/meshfunc2d.cpp
new file mode 100644
index 0000000000..f329d1df76
--- /dev/null
+++ b/Netgen/libsrc/meshing/meshfunc2d.cpp
@@ -0,0 +1,61 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+namespace netgen
+{
+
+  void Optimize2d (Mesh & mesh, MeshingParameters & mp)
+  {
+    int i, j;
+
+    double h = mp.maxh;
+  
+    mesh.CalcSurfacesOfNode();
+
+    const char * optstr = mp.optimize2d;
+    int optsteps = mp.optsteps2d;
+
+    //  cout << "optstr = " << optstr << endl;
+
+    for (i = 1; i <= optsteps; i++)
+      for (j = 1; j <= strlen(optstr); j++)
+	{
+	  if (multithread.terminate) break;
+	  switch (optstr[j-1])
+	    {
+	    case 's': 
+	      {  // topological swap
+		MeshOptimize2d meshopt;
+		meshopt.SetMetricWeight (0);
+		meshopt.EdgeSwapping (mesh, 0);
+		break;
+	      }
+	    case 'S': 
+	      {  // metric swap
+		MeshOptimize2d meshopt;
+		meshopt.SetMetricWeight (0);
+		meshopt.EdgeSwapping (mesh, 1);
+		break;
+	      }
+	    case 'm': 
+	      {
+		MeshOptimize2d meshopt;
+		meshopt.SetMetricWeight (1);
+		meshopt.ImproveMesh(mesh);
+		break;
+	      }
+	    
+	    case 'c': 
+	      {
+		MeshOptimize2d meshopt;
+		meshopt.SetMetricWeight (0.2);
+		meshopt.CombineImprove(mesh);
+		break;
+	      }
+	    default:
+	      cerr << "Optimization code " << optstr[j-1] << " not defined" << endl;
+	    }  
+	}
+  }
+
+}
diff --git a/Netgen/libsrc/meshing/meshing.hpp b/Netgen/libsrc/meshing/meshing.hpp
new file mode 100644
index 0000000000..3a60f1f7c1
--- /dev/null
+++ b/Netgen/libsrc/meshing/meshing.hpp
@@ -0,0 +1,48 @@
+#ifndef FILE_MESHING
+#define FILE_MESHING
+
+#include <myadt.hpp>
+#include <gprim.hpp>
+#include <linalg.hpp>
+#include <opti.hpp>
+
+namespace netgen
+{
+
+  class CSGeometry;
+
+
+#include "msghandler.hpp"
+
+#include "meshtype.hpp"
+#include "localh.hpp"
+#include "meshclass.hpp"
+#include "global.hpp"
+
+
+#include "meshtool.hpp"
+#include "ruler2.hpp"
+#include "adfront2.hpp"
+#include "meshing2.hpp"
+#include "improve2.hpp"
+
+
+#include "geomsearch.hpp"
+#include "adfront3.hpp"
+#include "ruler3.hpp"
+#include "meshing3.hpp"
+#include "improve3.hpp"
+#include "findip.hpp"
+
+#include "topology.hpp"
+#include "curvedelems.hpp"
+#include "clusters.hpp"
+
+#include "meshfunc.hpp"
+#include "bisect.hpp"
+#include "hprefinement.hpp"
+#include "boundarylayer.hpp"
+#include "specials.hpp"
+}
+
+#endif
diff --git a/Netgen/libsrc/meshing/meshing2.cpp b/Netgen/libsrc/meshing/meshing2.cpp
new file mode 100644
index 0000000000..efcb51346e
--- /dev/null
+++ b/Netgen/libsrc/meshing/meshing2.cpp
@@ -0,0 +1,1650 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+namespace netgen
+{
+  static void glrender (int wait);
+
+
+  // global variable for visualization
+
+  static ARRAY<Point3d> locpoints;
+  static ARRAY<int> legalpoints;
+  static ARRAY<Point2d> plainpoints;
+  static ARRAY<int> plainzones;
+  static ARRAY<INDEX_2> loclines;
+  static int geomtrig;
+  //static const char * rname;
+  static int cntelem, trials, nfaces;
+  static int oldnl;
+  static int qualclass;
+  // static const Meshing2 * meshthis;
+
+ 
+
+  Meshing2 :: Meshing2 (const Box3d & aboundingbox)
+  {
+    boundingbox = aboundingbox;
+
+    LoadRules (NULL);
+    // LoadRules ("quad.rls");
+    //  LoadRules ("triangle.rls");
+
+    adfront = new AdFront2(boundingbox);
+    starttime = GetTime();
+  }
+
+
+  Meshing2 :: ~Meshing2 ()
+  {
+    delete adfront;
+    for (int i = 0; i < rules.Size(); i++)
+      delete rules[i];
+  }
+
+  void Meshing2 :: AddPoint (const Point3d & p, PointIndex globind, 
+			     MultiPointGeomInfo * mgi)
+  {
+    // (*testout) << "add point " << globind << endl;
+    adfront ->AddPoint (p, globind, mgi);
+  }
+
+  void Meshing2 :: AddBoundaryElement (int i1, int i2,
+				       const PointGeomInfo & gi1, const PointGeomInfo & gi2)
+  {
+    //    (*testout) << "add line " << i1 << " - " << i2 << endl;
+    if (!gi1.trignum || !gi2.trignum)
+      {
+	PrintSysError ("addboundaryelement: illegal geominfo");
+      }
+    adfront -> AddLine (i1, i2, gi1, gi2);
+  }
+
+
+
+  void Meshing2 :: StartMesh ()
+  {
+    foundmap.SetSize (rules.Size());
+    canuse.SetSize (rules.Size());
+    ruleused.SetSize (rules.Size());
+
+    foundmap = 0;
+    canuse = 0;
+    ruleused = 0;
+
+    cntelem = 0;
+    trials = 0;
+  }
+
+  void Meshing2 :: EndMesh ()
+  {
+    for (int i = 0; i < ruleused.Size(); i++)
+      (*testout) << setw(4) << ruleused[i]
+		 << " times used rule " << rules[i] -> Name() << endl;
+  }
+
+  void Meshing2 :: SetStartTime (double astarttime)
+  {
+    starttime = astarttime;
+  }
+
+  double Meshing2 :: CalcLocalH (const Point3d & /* p */, double gh) const
+  {
+    return gh;
+  }
+
+
+
+  // should be class variables !!(?)
+  static Vec3d ex, ey;
+  static Point3d globp1;
+
+  void Meshing2 :: DefineTransformation (Point3d & p1, Point3d & p2,
+					 const PointGeomInfo * geominfo1,
+					 const PointGeomInfo * geominfo2)
+  {
+    globp1 = p1;
+    ex = p2 - p1;
+    ex /= ex.Length();
+    ey.X() = -ex.Y();
+    ey.Y() =  ex.X();
+    ey.Z() = 0;
+  }
+
+  void Meshing2 :: TransformToPlain (const Point3d & locpoint, 
+				     const MultiPointGeomInfo & geominf,
+				     Point2d & plainpoint, double h, int & zone)
+  {
+    Vec3d p1p;
+
+    p1p = locpoint - globp1;
+    p1p /= h;
+    plainpoint.X() = p1p * ex;
+    plainpoint.Y() = p1p * ey;
+    zone = 0;
+  }
+
+  int Meshing2 :: TransformFromPlain (Point2d & plainpoint,
+				      Point3d & locpoint, 
+				      PointGeomInfo & gi, 
+				      double h)
+  {
+    Vec3d p1p;
+    gi.trignum = 1;
+
+    p1p = plainpoint.X() * ex + plainpoint.Y() * ey;
+    p1p *= h;
+    locpoint = globp1 + p1p;
+    return 0;
+  }
+
+
+  int Meshing2 :: BelongsToActiveChart (const Point3d & p, 
+					const PointGeomInfo & gi)
+  {
+    return 1;
+  }
+
+
+  int Meshing2 :: ComputePointGeomInfo (const Point3d & p, PointGeomInfo & gi)
+  {
+    gi.trignum = 1;
+    return 0;
+  }
+
+
+  int Meshing2 :: ChooseChartPointGeomInfo (const MultiPointGeomInfo & mpgi, 
+					    PointGeomInfo & pgi)
+  {
+    pgi = mpgi.GetPGI(1);
+    return 0;
+  }
+
+
+
+  int Meshing2 :: 
+  IsLineVertexOnChart (const Point3d & p1, const Point3d & p2,
+		       int endpoint, const PointGeomInfo & geominfo)
+  {
+    return 1;
+  }
+
+  void Meshing2 ::
+  GetChartBoundary (ARRAY<Point2d> & points, 
+		    ARRAY<Point3d> & points3d, 
+		    ARRAY<INDEX_2> & lines, double h) const
+  {
+    points.SetSize (0);
+    points3d.SetSize (0);
+    lines.SetSize (0);
+  }
+
+  double Meshing2 :: Area () const
+  {
+    return -1;
+  }
+
+
+
+
+
+  MESHING2_RESULT Meshing2 :: GenerateMesh (Mesh & mesh, double gh, int facenr)
+  {
+    ARRAY<int> pindex, lindex;
+    ARRAY<int> delpoints, dellines;
+
+    ARRAY<PointGeomInfo> upgeominfo;  // unique info
+    ARRAY<MultiPointGeomInfo> mpgeominfo;  // multiple info
+
+    ARRAY<Element2d> locelements;
+
+    int i, k, z1, z2, j, oldnp;
+    SurfaceElementIndex sei;
+    int baselineindex;
+    bool found;
+    int rulenr;
+    int globind;
+    Point3d p1, p2;
+
+    const PointGeomInfo * blgeominfo1;
+    const PointGeomInfo * blgeominfo2;
+
+    bool morerisc;
+    bool debugflag;
+
+    double h, his, hshould;
+
+
+    // test for 3d overlaps
+    Box3dTree surfeltree (boundingbox.PMin(),
+			  boundingbox.PMax());
+
+    ARRAY<int> intersecttrias;
+    ARRAY<Point3d> critpoints;
+
+    // test for doubled edges
+    //INDEX_2_HASHTABLE<int> doubleedge(300000);
+
+
+    testmode = 0;
+    //  meshthis = this;
+
+    StartMesh();
+
+    ARRAY<Point2d> chartboundpoints;
+    ARRAY<Point3d> chartboundpoints3d;
+    ARRAY<INDEX_2> chartboundlines;
+
+    // illegal points: points with more then 50 elements per node
+    int maxlegalpoint, maxlegalline;
+    ARRAY<int,PointIndex::BASE> trigsonnode;
+    ARRAY<int,PointIndex::BASE> illegalpoint;
+
+    trigsonnode.SetSize (mesh.GetNP());
+    illegalpoint.SetSize (mesh.GetNP());
+
+    trigsonnode = 0;
+    illegalpoint = 0;
+  
+
+    double totalarea = Area ();
+    double meshedarea = 0;
+
+    // search tree for surface elements:
+    for (sei = 0; sei < mesh.GetNSE(); sei++)
+      {
+	const Element2d & sel = mesh[sei];
+
+	if (sel.IsDeleted())  continue;
+
+	if (sel.GetIndex() == facenr)
+	  {
+	    const Point3d & sep1 = mesh[sel.PNum(1)];
+	    const Point3d & sep2 = mesh[sel.PNum(2)];
+	    const Point3d & sep3 = mesh[sel.PNum(3)];
+	    Point3d sepmin(sep1), sepmax(sep2);
+	    sepmin.SetToMin (sep2);
+	    sepmin.SetToMin (sep3);
+	    sepmin.SetToMax (sep2);
+	    sepmin.SetToMax (sep3);
+
+	    surfeltree.Insert (sepmin, sepmax, sei);
+	  }
+
+      
+	double trigarea = Cross (Vec3d (mesh.Point (sel.PNum(1)),
+					mesh.Point (sel.PNum(2))),
+				 Vec3d (mesh.Point (sel.PNum(1)),
+					mesh.Point (sel.PNum(3)))).Length() / 2;;
+
+	if (sel.GetNP() == 4)
+	  trigarea += Cross (Vec3d (mesh.Point (sel.PNum(1)),
+				    mesh.Point (sel.PNum(3))),
+			     Vec3d (mesh.Point (sel.PNum(1)),
+				    mesh.Point (sel.PNum(4)))).Length() / 2;;
+	meshedarea += trigarea;
+
+      }
+
+
+    char * savetask = multithread.task;
+    multithread.task = "Surface meshing";
+
+    adfront ->SetStartFront ();
+
+
+    int plotnexttrial = 0;
+    //  starttime = GetTime();
+    while (!adfront ->Empty()) //  && !multithread.terminate)
+      {
+	if (multithread.terminate)
+	  throw NgException ("Meshing stopped");
+
+
+	// known for STL meshing
+	if (totalarea > 0)
+	  multithread.percent = 100 * meshedarea / totalarea;
+	/*
+	  else
+	  multithread.percent = 0;
+	*/
+
+	locpoints.SetSize(0);
+	loclines.SetSize(0);
+	pindex.SetSize(0);
+	lindex.SetSize(0);
+	delpoints.SetSize(0);
+	dellines.SetSize(0);
+	locelements.SetSize(0);
+
+
+
+	// plot statistics
+	if (trials > plotnexttrial)
+	  {
+	    PrintMessage (5, 
+			  "faces = ", nfaces,
+			  " trials = ", trials,
+			  " elements = ", mesh.GetNSE(),
+			  " els/sec = ",
+			  (mesh.GetNSE() / (GetTime() - starttime + 1)));
+	    plotnexttrial += 1000;
+	  }
+
+
+	// unique-pgi, multi-pgi
+	upgeominfo.SetSize(0);
+	mpgeominfo.SetSize(0);
+
+
+	nfaces = adfront->GetNFL();
+	trials ++;
+    
+
+	if (trials % 1000 == 0)
+	  {
+	    (*testout) << "\n";
+	    for (i = 1; i <= canuse.Size(); i++)
+	      {
+		(*testout) << foundmap.Get(i) << "/" 
+			   << canuse.Get(i) << "/"
+			   << ruleused.Get(i) << " map/can/use rule " << rules.Get(i)->Name() << "\n";
+	      }
+	    (*testout) << "\n";
+	  }
+
+
+	baselineindex = adfront -> SelectBaseLine (p1, p2, blgeominfo1, blgeominfo2);
+
+	// cout << "baseline = " << baselineindex << ", p1, p2 = " << p1 << ", " << p2 << endl;
+
+	found = 1;
+
+
+	his = Dist (p1, p2);
+
+	Point3d pmid = Center (p1, p2);
+	hshould = CalcLocalH (pmid, mesh.GetH (pmid));
+	if (gh < hshould)
+	  hshould = gh;
+
+	mesh.RestrictLocalH (pmid, hshould);
+
+	h = hshould;
+
+      
+	qualclass =
+	  adfront ->GetLocals (baselineindex, locpoints, mpgeominfo, loclines, 
+			       pindex, lindex, 5 * max2(his, hshould));
+
+
+	if (qualclass > 200)
+	  {
+	    PrintMessage (3, "give up with qualclass ", qualclass);
+	    PrintMessage (3, "number of frontlines = ", adfront->GetNFL());
+	    break;
+	  }
+
+	if (found && qualclass > 60)
+	  {
+	    found = 0;
+	  }
+
+	//      morerisc = ((qualclass > 20) && (qualclass % 2 == 1));
+	//      morerisc = 1;
+	morerisc = 0;
+
+
+	PointIndex gpi1 = adfront -> GetGlobalIndex (pindex.Get(loclines[0].I1()));
+	PointIndex gpi2 = adfront -> GetGlobalIndex (pindex.Get(loclines[0].I2()));
+
+
+	debugflag = 
+	  debugparam.haltsegment &&
+	  ( (debugparam.haltsegmentp1 == gpi1) && 
+	    (debugparam.haltsegmentp2 == gpi2) || 
+	    (debugparam.haltsegmentp1 == gpi2) && 
+	    (debugparam.haltsegmentp2 == gpi1)) ||
+	  debugparam.haltnode &&
+	  ( (debugparam.haltsegmentp1 == gpi1) ||
+	    (debugparam.haltsegmentp2 == gpi1));
+
+      
+	if (debugparam.haltface && debugparam.haltfacenr == facenr)
+	  {
+	    debugflag = 1;
+	    cout << "set debugflag" << endl;
+	  }
+	
+
+	// problem recognition !
+	if (found && 
+	    (gpi1 < illegalpoint.Size()+PointIndex::BASE) && 
+	    (gpi2 < illegalpoint.Size()+PointIndex::BASE) )
+	  {
+	    if (illegalpoint[gpi1] || illegalpoint[gpi2])
+	      found = 0;
+	  }
+
+
+	Point2d p12d, p22d;
+
+	if (found)
+	  {
+	    oldnp = locpoints.Size();
+	    oldnl = loclines.Size();
+	  
+	    DefineTransformation (p1, p2, blgeominfo1, blgeominfo2);
+	  
+	    plainpoints.SetSize (locpoints.Size());
+	    plainzones.SetSize (locpoints.Size());
+
+	    // (*testout) << endl;
+
+	    for (i = 1; i <= locpoints.Size(); i++)
+	      {
+		// (*testout) << "pindex(i) = " << pindex[i-1] << endl;
+		TransformToPlain (locpoints.Get(i), 
+				  mpgeominfo.Get(i),
+				  plainpoints.Elem(i), h, plainzones.Elem(i));
+	      }
+
+	    p12d = plainpoints.Get(1);
+	    p22d = plainpoints.Get(2);
+
+	    /*
+	    // last idea on friday
+	    plainzones.Elem(1) = 0;
+	    plainzones.Elem(2) = 0;
+	    */
+
+
+	    /*
+	    // old netgen:
+	    for (i = 2; i <= loclines.Size(); i++)  // don't remove first line
+	    {
+	    z1 = plainzones.Get(loclines.Get(i).I1());
+	    z2 = plainzones.Get(loclines.Get(i).I2());
+	      
+	    if (z1 && z2 && (z1 != z2) || (z1 == -1) || (z2 == -1) )
+	    {
+	    loclines.DeleteElement(i);
+	    lindex.DeleteElement(i);
+	    oldnl--;
+	    i--;
+	    }
+	    }
+
+	    // 	  for (i = 1; i <= plainpoints.Size(); i++)
+	    // 	    if (plainzones.Elem(i) == -1)
+	    // 	      plainpoints.Elem(i) = Point2d (1e4, 1e4);
+	    */
+	  
+
+	  
+	    for (i = 2; i <= loclines.Size(); i++)  // don't remove first line
+	      {
+		// (*testout) << "loclines(i) = " << loclines.Get(i).I1() << " - " << loclines.Get(i).I2() << endl;
+		z1 = plainzones.Get(loclines.Get(i).I1());
+		z2 = plainzones.Get(loclines.Get(i).I2());
+	      
+	      
+		// one inner point, one outer
+		if ( (z1 >= 0) != (z2 >= 0))
+		  {
+		    int innerp = (z1 >= 0) ? 1 : 2;
+		    if (IsLineVertexOnChart (locpoints.Get(loclines.Get(i).I1()),
+					     locpoints.Get(loclines.Get(i).I2()),
+					     innerp,
+					     adfront->GetLineGeomInfo (lindex.Get(i), innerp)))
+		      // pgeominfo.Get(loclines.Get(i).I(innerp))))
+		      {		
+
+			if (!morerisc)
+			  {
+			    // use one end of line
+			    int pini, pouti;
+			    Vec2d v;
+			  
+			    pini = loclines.Get(i).I(innerp);
+			    pouti = loclines.Get(i).I(3-innerp);
+			  
+			    Point2d pin (plainpoints.Get(pini));
+			    Point2d pout (plainpoints.Get(pouti));
+			    v = pout - pin;
+			    double len = v.Length();
+			    if (len <= 1e-6)
+			      (*testout) << "WARNING(js): inner-outer: short vector" << endl;
+			    else
+			      v /= len;
+			  
+			    /*
+			    // don't elongate line towards base-line !!
+			    if (Vec2d (pin, p12d) * v > 0 && 
+			    Vec2d (pin, p22d) * v > 0)
+			    v *= -1;  
+			    */
+
+			    Point2d newpout = pin + 1000 * v;
+			    newpout = pout;
+
+			  
+			    plainpoints.Append (newpout);
+			    Point3d pout3d = locpoints.Get(pouti);
+			    locpoints.Append (pout3d);
+
+			    plainzones.Append (0);
+			    pindex.Append (0);
+			    oldnp++;
+			    loclines.Elem(i).I(3-innerp) = oldnp;
+			  }
+			else
+			  plainzones.Elem(loclines.Get(i).I(3-innerp)) = 0;
+			
+
+			//		  (*testout) << "inner - outer correction" << endl;
+		      }
+		    else
+		      {
+			// remove line
+			loclines.DeleteElement(i);
+			lindex.DeleteElement(i);
+			oldnl--;
+			i--;
+		      }			
+		  }
+	      
+		else if (z1 > 0 && z2 > 0 && (z1 != z2) || (z1 < 0) && (z2 < 0) )
+		  {
+		    loclines.DeleteElement(i);
+		    lindex.DeleteElement(i);
+		    oldnl--;
+		    i--;
+		  }
+	      }
+	  
+
+
+
+
+	    legalpoints.SetSize(plainpoints.Size());
+	    for (i = 1; i <= legalpoints.Size(); i++)
+	      legalpoints.Elem(i) = 1;
+
+
+	    for (i = 1; i <= plainpoints.Size(); i++)
+	      {
+		if (plainzones.Elem(i) < 0)
+		  {
+		    plainpoints.Elem(i) = Point2d (1e4, 1e4);
+		    legalpoints.Elem(i) = 0;
+		  }
+		if (pindex.Elem(i) == 0)
+		  legalpoints.Elem(i) = 0;
+	      }
+	    /*
+	      for (i = 3; i <= plainpoints.Size(); i++)
+	      if (sqr (plainpoints.Get(i).X()) + sqr (plainpoints.Get(i).Y())
+	      > sqr (2 + 0.2 * qualclass))
+	      legalpoints.Elem(i) = 0;
+	    */  
+
+	    /*	  
+		 int clp = 0;
+		 for (i = 1; i <= plainpoints.Size(); i++)
+		 if (legalpoints.Get(i))
+		 clp++;
+		 (*testout) << "legalpts: " << clp << "/" << plainpoints.Size() << endl; 
+
+		 // sort legal/illegal lines
+		 int lastleg = 2;
+		 int firstilleg = oldnl;
+
+		 while (lastleg < firstilleg)
+		 {
+		 while (legalpoints.Get(loclines.Get(lastleg).I1()) &&
+		 legalpoints.Get(loclines.Get(lastleg).I2()) &&
+		 lastleg < firstilleg)
+		 lastleg++;
+		 while ( ( !legalpoints.Get(loclines.Get(firstilleg).I1()) ||
+		 !legalpoints.Get(loclines.Get(firstilleg).I2())) &&
+		 lastleg < firstilleg)
+		 firstilleg--;
+	      
+		 if (lastleg < firstilleg)
+		 {
+		 swap (loclines.Elem(lastleg), loclines.Elem(firstilleg));
+		 swap (lindex.Elem(lastleg), lindex.Elem(firstilleg));
+		 }
+		 }
+
+		 (*testout) << "leglines " << lastleg << "/" << oldnl << endl;
+	    */
+	
+
+	    GetChartBoundary (chartboundpoints, 
+			      chartboundpoints3d,
+			      chartboundlines, h);
+
+	    oldnp = plainpoints.Size();
+
+	    maxlegalpoint = locpoints.Size();
+	    maxlegalline = loclines.Size();
+
+
+
+	    if (mparam.checkchartboundary)
+	      {
+		for (i = 1; i <= chartboundpoints.Size(); i++)
+		  {
+		    plainpoints.Append (chartboundpoints.Get(i));
+		    locpoints.Append (chartboundpoints3d.Get(i));
+		    legalpoints.Append (0);
+		  }
+	      
+
+		for (i = 1; i <= chartboundlines.Size(); i++)
+		  {
+		    INDEX_2 line (chartboundlines.Get(i).I1()+oldnp,
+				  chartboundlines.Get(i).I2()+oldnp);
+		    loclines.Append (line);
+		    //	      (*testout) << "line: " << line.I1() << "-" << line.I2() << endl;
+		  }
+	      }
+
+	    oldnl = loclines.Size();
+	    oldnp = plainpoints.Size();
+	  }
+
+
+	/*
+	  if (qualclass > 100)
+	  {
+	  multithread.drawing = 1;
+	  glrender(1);
+	  cout << "qualclass 100, nfl = " << adfront->GetNFL() << endl;
+	  }
+	*/
+
+
+	if (found)
+	  {
+	    rulenr = ApplyRules (plainpoints, legalpoints, maxlegalpoint,
+				 loclines, maxlegalline, locelements,
+				 dellines, qualclass);
+	    if (!rulenr)
+	      {
+		found = 0;
+		if ( debugflag || debugparam.haltnosuccess )
+		  PrintWarning ("no rule found");
+	      }
+	  }
+      
+	for (i = 1; i <= locelements.Size() && found; i++)
+	  {
+	    const Element2d & el = locelements.Get(i);
+	    for (j = 1; j <= el.GetNP(); j++)
+	      if (el.PNum(j) <= oldnp && !pindex.Get(el.PNum(j)))
+		{
+		  found = 0;
+		  PrintSysError ("meshing2, index missing");
+		}
+	  }
+
+
+	if (found)
+	  {
+	    locpoints.SetSize (plainpoints.Size());
+	    upgeominfo.SetSize(locpoints.Size());
+
+	    for (i = oldnp+1; i <= plainpoints.Size(); i++)
+	      {
+		int err =
+		  TransformFromPlain (plainpoints.Elem(i), locpoints.Elem(i), 
+				      upgeominfo.Elem(i), h);
+
+		if (err)
+		  {
+		    found = 0;
+
+		    if ( debugflag || debugparam.haltnosuccess )
+		      PrintSysError ("meshing2, Backtransformation failed");
+
+		    break;
+		  }
+	      }
+	  }
+	  
+
+	//      for (i = 1; i <= oldnl; i++)
+	//        adfront -> ResetClass (lindex[i]);
+
+
+	/*
+	  double violateminh;
+	  if (qualclass <= 10)
+	  violateminh = 3;
+	  else
+	  violateminh = 3 * qualclass;
+
+	  if (uselocalh && found) //  && qualclass <= 10)
+	  {
+	  for (i = 1; i <= locelements.Size(); i++)
+	  {
+	  Point3d pmin = locpoints.Get(locelements.Get(i).PNum(1));
+	  Point3d pmax = pmin;
+	  for (j = 2; j <= 3; j++)
+	  {
+	  const Point3d & hp = 
+	  locpoints.Get(locelements.Get(i).PNum(j));
+	  pmin.SetToMin (hp);
+	  pmax.SetToMax (hp);
+	  }
+	  double minh = mesh.GetMinH (pmin, pmax);
+	  if (h > violateminh * minh)
+	  {
+	  found = 0;
+	  loclines.SetSize (oldnl);
+	  locpoints.SetSize (oldnp);
+	  }
+	  }
+	  }
+	*/
+
+
+	if (found) 
+	  {
+	    double violateminh = 3 + 0.1 * sqr (qualclass);
+	    double minh = 1e8;
+	    double newedgemaxh = 0;
+	    for (i = oldnl+1; i <= loclines.Size(); i++)
+	      {
+		double eh = Dist (locpoints.Get(loclines.Get(i).I1()),
+				  locpoints.Get(loclines.Get(i).I2()));
+		if (eh > newedgemaxh)
+		  newedgemaxh = eh;
+	      }
+
+	    for (i = 1; i <= locelements.Size(); i++)
+	      {
+		Point3d pmin = locpoints.Get(locelements.Get(i).PNum(1));
+		Point3d pmax = pmin;
+		for (j = 2; j <= locelements.Get(i).GetNP(); j++)
+		  {
+		    const Point3d & hp = 
+		      locpoints.Get(locelements.Get(i).PNum(j));
+		    pmin.SetToMin (hp);
+		    pmax.SetToMax (hp);
+		  }
+		double eh = mesh.GetMinH (pmin, pmax);
+		if (eh < minh)
+		  minh = eh;
+	      }
+
+	    //	  cout << "violate = " << newedgemaxh / minh << endl;
+	    static double maxviolate = 0;
+	    if (newedgemaxh / minh > maxviolate)
+	      {
+		maxviolate = newedgemaxh / minh;
+		//	      cout << "max minhviolate = " << maxviolate << endl;
+	      }
+
+
+	    if (newedgemaxh > violateminh * minh)
+	      {
+		found = 0;
+		loclines.SetSize (oldnl);
+		locpoints.SetSize (oldnp);
+
+		if ( debugflag || debugparam.haltnosuccess )
+		  PrintSysError ("meshing2, maxh too large");
+
+
+	      }
+	  }
+
+
+
+	/*
+	// test good ComputeLineGeoInfo
+	if (found)
+	{
+	// is line on chart ?
+	for (i = oldnl+1; i <= loclines.Size(); i++)
+	{
+	int gisize;
+	void *geominfo;
+
+	if (ComputeLineGeoInfo (locpoints.Get(loclines.Get(i).I1()),
+	locpoints.Get(loclines.Get(i).I2()),
+	gisize, geominfo))
+	found = 0;
+	}
+	}
+	*/
+
+
+	// changed for OCC meshing
+	if (found)
+	  {
+	    // take geominfo from dellines
+	    // upgeominfo.SetSize(locpoints.Size());
+
+	    /*
+	      for (i = 1; i <= dellines.Size(); i++)
+	      for (j = 1; j <= 2; j++)
+	      {
+	      upgeominfo.Elem(loclines.Get(dellines.Get(i)).I(j)) =
+	      adfront -> GetLineGeomInfo (lindex.Get(dellines.Get(i)), j);
+	      }
+	    */
+
+
+	    for (i = 1; i <= locelements.Size(); i++)
+	      for (j = 1; j <= locelements.Get(i).GetNP(); j++)
+		{
+		  int pi = locelements.Get(i).PNum(j);
+		  if (pi <= oldnp)
+		    {
+		    
+		      if (ChooseChartPointGeomInfo (mpgeominfo.Get(pi), upgeominfo.Elem(pi)))
+			{
+			  // cannot select, compute new one
+			  PrintWarning ("calc point geominfo instead of using");
+			  if (ComputePointGeomInfo (locpoints.Get(pi), upgeominfo.Elem(pi)))
+			    {
+			      found = 0;
+			      PrintSysError ("meshing2d, geominfo failed");
+			    }
+			}
+		    }
+		}
+
+	    /*
+	    // use upgeominfo from ProjectFromPlane
+	    for (i = oldnp+1; i <= locpoints.Size(); i++)
+	    {
+	    if (ComputePointGeomInfo (locpoints.Get(i), upgeominfo.Elem(i)))
+	    {
+	    found = 0;
+	    if ( debugflag || debugparam.haltnosuccess )
+	    PrintSysError ("meshing2d, compute geominfo failed");
+	    }
+	    }
+	    */
+	  }
+
+
+	if (found && mparam.checkoverlap)
+	  {
+	    // test for overlaps
+	  
+	    Point3d hullmin(1e10, 1e10, 1e10);
+	    Point3d hullmax(-1e10, -1e10, -1e10);
+	  
+	    for (i = 1; i <= locelements.Size(); i++)
+	      for (j = 1; j <= locelements.Get(i).GetNP(); j++)
+		{
+		  const Point3d & p = locpoints.Get(locelements.Get(i).PNum(j));
+		  hullmin.SetToMin (p);
+		  hullmax.SetToMax (p);
+		}
+	    hullmin += Vec3d (-his, -his, -his);
+	    hullmax += Vec3d ( his,  his,  his);
+
+	    surfeltree.GetIntersecting (hullmin, hullmax, intersecttrias);
+
+	    critpoints.SetSize (0);
+	    for (i = oldnp+1; i <= locpoints.Size(); i++)
+	      critpoints.Append (locpoints.Get(i));
+
+	    for (i = 1; i <= locelements.Size(); i++)
+	      {
+		const Element2d & tri = locelements.Get(i);
+		if (tri.GetNP() == 3)
+		  {
+		    const Point3d & tp1 = locpoints.Get(tri.PNum(1));
+		    const Point3d & tp2 = locpoints.Get(tri.PNum(2));
+		    const Point3d & tp3 = locpoints.Get(tri.PNum(3));
+		  
+		    Vec3d tv1 (tp1, tp2);
+		    Vec3d tv2 (tp1, tp3);
+		  
+		    double lam1, lam2;
+		    for (lam1 = 0.2; lam1 <= 0.8; lam1 += 0.2)
+		      for (lam2 = 0.2; lam2 + lam1 <= 0.8; lam2 += 0.2)
+			{
+			  Point3d hp = tp1 + lam1 * tv1 + lam2 * tv2;
+			  critpoints.Append (hp);
+			}
+		  }
+		else if (tri.GetNP() == 4)
+		  {
+		    const Point3d & tp1 = locpoints.Get(tri.PNum(1));
+		    const Point3d & tp2 = locpoints.Get(tri.PNum(2));
+		    const Point3d & tp3 = locpoints.Get(tri.PNum(3));
+		    const Point3d & tp4 = locpoints.Get(tri.PNum(4));
+		  
+		    double l1, l2;
+		    for (l1 = 0.1; l1 <= 0.9; l1 += 0.1)
+		      for (l2 = 0.1; l2 <= 0.9; l2 += 0.1)
+			{
+			  Point3d hp;
+			  hp.X() = 
+			    (1-l1)*(1-l2) * tp1.X() +
+			    l1*(1-l2) * tp2.X() +
+			    l1*l2 * tp3.X() +
+			    (1-l1)*l2 * tp4.X();
+			  hp.Y() = 
+			    (1-l1)*(1-l2) * tp1.Y() +
+			    l1*(1-l2) * tp2.Y() +
+			    l1*l2 * tp3.Y() +
+			    (1-l1)*l2 * tp4.Y();
+			  hp.Z() = 
+			    (1-l1)*(1-l2) * tp1.Z() +
+			    l1*(1-l2) * tp2.Z() +
+			    l1*l2 * tp3.Z() +
+			    (1-l1)*l2 * tp4.Z();
+
+
+			  critpoints.Append (hp);
+			}
+		  }
+	      }
+	    /*
+	      for (i = oldnl+1; i <= loclines.Size(); i++)
+	      {
+	      Point3d hp = locpoints.Get(loclines.Get(i).I1());
+	      Vec3d hv(hp, locpoints.Get(loclines.Get(i).I2()));
+	      int ncp = 2;
+	      for (j = 1; j <= ncp; j++)
+	      critpoints.Append ( hp + (double(j)/(ncp+1)) * hv);
+	      }
+	    */
+
+
+	    /*
+	      for (i = oldnp+1; i <= locpoints.Size(); i++)
+	      {
+	      const Point3d & p = locpoints.Get(i);
+	    */
+
+
+	    for (i = 1; i <= critpoints.Size(); i++)
+	      {
+		const Point3d & p = critpoints.Get(i);
+		 
+
+		/*
+		  for (j = 1; j <= mesh.GetNSE(); j++)
+		  {
+		*/
+		int jj;
+		for (jj = 1; jj <= intersecttrias.Size(); jj++)
+		  {
+		    j = intersecttrias.Get(jj);
+		    const Element2d & el = mesh.SurfaceElement(j);
+		  
+		    int ntrig = (el.GetNP() == 3) ? 1 : 2;
+
+		    int jl;
+		    for (jl = 1; jl <= ntrig; jl++)
+		      {
+			Point3d tp1, tp2, tp3;
+
+			if (jl == 1)
+			  {
+			    tp1 = mesh.Point(el.PNum(1));
+			    tp2 = mesh.Point(el.PNum(2));
+			    tp3 = mesh.Point(el.PNum(3));
+			  }
+			else
+			  {
+			    tp1 = mesh.Point(el.PNum(1));
+			    tp2 = mesh.Point(el.PNum(3));
+			    tp3 = mesh.Point(el.PNum(4));
+			  }
+
+			int onchart = 0;
+			for (k = 1; k <= el.GetNP(); k++)
+			  if (BelongsToActiveChart (mesh.Point(el.PNum(k)),
+						    el.GeomInfoPi(k)))
+			    onchart = 1;
+			if (!onchart)
+			  continue;
+		      
+			Vec3d e1(tp1, tp2);
+			Vec3d e2(tp1, tp3);
+			Vec3d n = Cross (e1, e2);
+			n /= n.Length();
+			double lam1, lam2, lam3;
+			lam3 = n * Vec3d (tp1, p);
+			LocalCoordinates (e1, e2, Vec3d (tp1, p), lam1, lam2);
+		      
+			if (fabs (lam3) < 0.1 * hshould && 
+			    lam1 > 0 && lam2 > 0 && (lam1 + lam2) < 1)
+			  {
+#ifdef DEVELOP
+			    cout << "overlap" << endl;
+			    (*testout) << "overlap:" << endl
+				       << "tri = " << tp1 << "-" << tp2 << "-" << tp3 << endl
+				       << "point = " << p << endl
+				       << "lam1, 2 = " << lam1 << ", " << lam2 << endl
+				       << "lam3 = " << lam3 << endl;
+			  
+			    //		      cout << "overlap !!!" << endl;
+#endif
+			    for (int k = 1; k <= 5; k++)
+			      adfront -> IncrementClass (lindex.Get(1));
+
+			    found = 0;
+			  
+			    if ( debugflag || debugparam.haltnosuccess )
+			      PrintWarning ("overlapping");
+			  
+			  
+			    if (debugparam.haltoverlap)
+			      {
+				debugflag = 1;
+			      }
+			  
+			    /*
+			      multithread.drawing = 1;
+			      glrender(1);
+			    */
+			  }
+		      }
+		  }
+	      }
+	  }
+
+
+	if (found)
+	  {
+	    // check, whether new front line already exists
+
+	    for (i = oldnl+1; i <= loclines.Size(); i++)
+	      {
+		int nlgpi1 = loclines.Get(i).I1();
+		int nlgpi2 = loclines.Get(i).I2();
+		if (nlgpi1 <= pindex.Size() && nlgpi2 <= pindex.Size())
+		  {
+		    nlgpi1 = adfront->GetGlobalIndex (pindex.Get(nlgpi1));
+		    nlgpi2 = adfront->GetGlobalIndex (pindex.Get(nlgpi2));
+
+		    int exval = adfront->ExistsLine (nlgpi1, nlgpi2);
+		    if (exval)
+		      {
+			cout << "ERROR: new line exits, val = " << exval << endl;
+			(*testout) << "ERROR: new line exits, val = " << exval << endl;
+			found = 0;
+
+
+			if (debugparam.haltexistingline)
+			  debugflag = 1;
+
+		      }
+		  }
+	      }
+	  
+	  }
+
+
+	/*
+	  if (found)
+	  {
+	  // check, whether new triangles insert edges twice
+	  for (i = 1; i <= locelements.Size(); i++)
+	  for (j = 1; j <= 3; j++)
+	  {
+	  int tpi1 = locelements.Get(i).PNumMod (j);
+	  int tpi2 = locelements.Get(i).PNumMod (j+1);
+	  if (tpi1 <= pindex.Size() && tpi2 <= pindex.Size())
+	  {
+	  tpi1 = adfront->GetGlobalIndex (pindex.Get(tpi1));
+	  tpi2 = adfront->GetGlobalIndex (pindex.Get(tpi2));
+
+	  if (doubleedge.Used (INDEX_2(tpi1, tpi2)))
+	  {
+	  if (debugparam.haltexistingline)
+	  debugflag = 1;
+	  cerr << "ERROR Insert edge "
+	  << tpi1 << " - " << tpi2 << " twice !!!" << endl;
+	  found = 0;
+	  }
+	  doubleedge.Set (INDEX_2(tpi1, tpi2), 1);
+	  }
+	  }
+	  }
+	*/
+
+
+	if (found)
+	  {
+	    // everything is ok, perform mesh update
+
+	    ruleused.Elem(rulenr)++;
+
+
+	    pindex.SetSize(locpoints.Size());
+	      
+	    for (i = oldnp+1; i <= locpoints.Size(); i++)
+	      {
+		globind = mesh.AddPoint (locpoints.Get(i));
+		pindex.Elem(i) = adfront -> AddPoint (locpoints.Get(i), globind);
+	      }
+	      
+	    for (i = oldnl+1; i <= loclines.Size(); i++)
+	      {
+		/*
+		  for (j = 1; j <= locpoints.Size(); j++)
+		  {
+		  (*testout) << j << ": " << locpoints.Get(j) << endl;
+		  }
+		*/
+	      
+		/*
+		  ComputeLineGeoInfo (locpoints.Get(loclines.Get(i).I1()),
+		  locpoints.Get(loclines.Get(i).I2()),
+		  gisize, geominfo);
+		*/		  
+
+		if (pindex.Get(loclines.Get(i).I1()) == 0 || 
+		    pindex.Get(loclines.Get(i).I2()) == 0)
+		  {
+		    (*testout) << "pindex is 0" << endl;
+		  }
+
+		if (!upgeominfo.Get(loclines.Get(i).I1()).trignum || 
+		    !upgeominfo.Get(loclines.Get(i).I2()).trignum)
+		  {
+		    cout << "new el: illegal geominfo" << endl;
+		  }
+
+		adfront -> AddLine (pindex.Get(loclines.Get(i).I1()),
+				    pindex.Get(loclines.Get(i).I2()),
+				    upgeominfo.Get(loclines.Get(i).I1()),
+				    upgeominfo.Get(loclines.Get(i).I2()));
+	      }
+	    for (i = 1; i <= locelements.Size(); i++)
+	      {
+		Element2d mtri(locelements.Get(i).GetNP());
+		mtri = locelements.Get(i);
+		mtri.SetIndex (facenr);
+
+
+		// compute triangle geominfo:
+		//	      (*testout) << "triggeominfo: ";
+		for (j = 1; j <= locelements.Get(i).GetNP(); j++)
+		  {
+		    mtri.GeomInfoPi(j) = upgeominfo.Get(locelements.Get(i).PNum(j));
+		    //		  (*testout) << mtri.GeomInfoPi(j).trignum << " ";
+		  }
+		//	      (*testout) << endl;
+
+		for (j = 1; j <= locelements.Get(i).GetNP(); j++)
+		  {
+		    mtri.PNum(j) = 
+		      locelements.Elem(i).PNum(j) =
+		      adfront -> GetGlobalIndex (pindex.Get(locelements.Get(i).PNum(j)));
+		  }
+	      
+		
+	      
+	      
+		mesh.AddSurfaceElement (mtri);
+		cntelem++;
+		//	      cout << "elements: " << cntelem << endl;
+
+
+	      
+
+		const Point3d & sep1 = mesh.Point (mtri.PNum(1));
+		const Point3d & sep2 = mesh.Point (mtri.PNum(2));
+		const Point3d & sep3 = mesh.Point (mtri.PNum(3));
+
+		Point3d sepmin(sep1), sepmax(sep1);
+		for (j = 2; j <= mtri.GetNP(); j++)
+		  {
+		    sepmin.SetToMin (mesh.Point (mtri.PNum(j)));
+		    sepmax.SetToMax (mesh.Point (mtri.PNum(j)));
+		  }
+
+		surfeltree.Insert (sepmin, sepmax, mesh.GetNSE());
+
+
+		double trigarea = Cross (Vec3d (sep1, sep2), 
+					 Vec3d (sep1, sep3)).Length() / 2;
+
+		if (mtri.GetNP() == 4)
+		  {
+		    const Point3d & sep4 = mesh.Point (mtri.PNum(4));
+		    trigarea += Cross (Vec3d (sep1, sep3), 
+				       Vec3d (sep1, sep4)).Length() / 2;
+		  }
+
+		meshedarea += trigarea;
+
+	      
+
+
+		for (j = 1; j <= locelements.Get(i).GetNP(); j++)
+		  {
+		    int gpi = locelements.Get(i).PNum(j);
+
+		    int oldts = trigsonnode.Size();
+		    if (gpi >= oldts+PointIndex::BASE)
+		      {
+			trigsonnode.SetSize (gpi+1-PointIndex::BASE);
+			illegalpoint.SetSize (gpi+1-PointIndex::BASE);
+			for (k = oldts+PointIndex::BASE; 
+			     k <= gpi; k++)
+			  {
+			    trigsonnode[k] = 0;
+			    illegalpoint[k] = 0;
+			  }
+		      }
+
+		    trigsonnode[gpi]++;
+		  
+		    if (trigsonnode[gpi] > 20)
+		      {
+			illegalpoint[gpi] = 1;
+			//		      cout << "illegal point: " << gpi << endl;
+			(*testout) << "illegal point: " << gpi << endl;
+		      }
+
+		    static int mtonnode = 0;
+		    if (trigsonnode[gpi] > mtonnode)
+		      mtonnode = trigsonnode[gpi];
+		  }
+		//	      cout << "els = " << cntelem << " trials = " << trials << endl;
+		//	      if (trials > 100)		return;
+	      }
+	      
+	    for (i = 1; i <= dellines.Size(); i++)
+	      adfront -> DeleteLine (lindex.Get(dellines.Get(i)));
+	      
+	    //	  rname = rules[found]->Name();
+#ifdef MYGRAPH
+	    if (silentflag<3) 
+	      {
+		plotsurf.DrawPnL(locpoints, loclines);
+		plotsurf.Plot(testmode, testmode);
+	      }
+#endif
+
+	    if (morerisc)
+	      {
+		cout << "generated due to morerisc" << endl;
+		//	      multithread.drawing = 1;
+		//	      glrender(1);
+	      }
+
+
+
+	  
+	    if ( debugparam.haltsuccess || debugflag )
+	      {
+		cout << "success" << endl;
+		multithread.drawing = 1;
+		multithread.testmode = 1;
+		multithread.pause = 1;
+
+
+		/*
+		  extern STLGeometry * stlgeometry;
+		  stlgeometry->ClearMarkedSegs();
+		  for (i = 1; i <= loclines.Size(); i++)
+		  {
+		  stlgeometry->AddMarkedSeg(locpoints.Get(loclines.Get(i).I1()),
+		  locpoints.Get(loclines.Get(i).I2()));
+		  }
+		*/
+
+
+		glrender(1);
+	      }
+	  }
+	else
+	  {
+	    adfront -> IncrementClass (lindex.Get(1));
+
+	    if ( debugparam.haltnosuccess || debugflag )
+	      {
+		cout << "Problem with seg " << gpi1 << " - " << gpi2
+		     << ", class = " << qualclass << endl;
+		multithread.drawing = 1;
+		multithread.testmode = 1;
+		multithread.pause = 1;
+
+
+		/*
+		  extern STLGeometry * stlgeometry;
+		  stlgeometry->ClearMarkedSegs();
+		  for (i = 1; i <= loclines.Size(); i++)
+		  {
+		  stlgeometry->AddMarkedSeg(locpoints.Get(loclines.Get(i).I1()),
+		  locpoints.Get(loclines.Get(i).I2()));
+		  }
+		*/
+
+		for (i = 1; i <= loclines.Size(); i++)
+		  {
+		    (*testout) << "line ";
+		    for (j = 1; j <= 2; j++)
+		      {
+			int hi = 0;
+			if (loclines.Get(i).I(j) >= 1 &&
+			    loclines.Get(i).I(j) <= pindex.Size())
+			  hi = adfront->GetGlobalIndex (pindex.Get(loclines.Get(i).I(j)));
+
+			(*testout) << hi << " ";
+		      }
+		    (*testout) << " : " 
+			       << plainpoints.Get(loclines.Get(i).I1()) << " - "
+			       << plainpoints.Get(loclines.Get(i).I2()) << " 3d: "
+			       << locpoints.Get(loclines.Get(i).I1()) << " - "
+			       << locpoints.Get(loclines.Get(i).I2()) 
+			       << endl;
+		  }
+
+
+		/*
+		  cout << "p1gi = " << blgeominfo[0].trignum 
+		  << ", p2gi = " << blgeominfo[1].trignum << endl;
+		*/
+
+		glrender(1);
+	      }
+
+	  
+#ifdef MYGRAPH      
+	    if (silentflag<3)
+	      {
+		if (testmode || trials%2 == 0)
+		  {
+		    plotsurf.DrawPnL(locpoints, loclines);
+		    plotsurf.Plot(testmode, testmode);
+		  }
+	      }
+#endif
+	  }
+
+      }
+
+    PrintMessage (3, "Surface meshing done");
+
+    adfront->PrintOpenSegments (*testout);
+
+    multithread.task = savetask;
+
+
+    //  cout << "surfeltree.depth = " << surfeltree.Tree().Depth() << endl;
+    EndMesh ();
+
+    if (!adfront->Empty())
+      return MESHING2_GIVEUP;
+    
+    return MESHING2_OK;
+  }
+
+
+
+
+
+
+
+
+
+}
+
+
+
+
+
+
+
+#ifdef OPENGL
+
+/* *********************** Draw Surface Meshing **************** */
+
+
+#include <visual.hpp>
+#include <stlgeom.hpp>
+
+namespace netgen 
+{
+
+  extern STLGeometry * stlgeometry;
+  extern Mesh * mesh;
+  VisualSceneSurfaceMeshing vssurfacemeshing;
+
+
+
+  void glrender (int wait)
+  {
+    //  cout << "plot adfront" << endl;
+
+    if (multithread.drawing)
+      {
+	//      vssurfacemeshing.Render();
+	Render ();
+      
+	if (wait || multithread.testmode)
+	  {
+	    multithread.pause = 1;
+	  }
+	while (multithread.pause);
+      }
+  }
+
+
+
+  VisualSceneSurfaceMeshing :: VisualSceneSurfaceMeshing ()
+    : VisualScene()
+  {
+    ;
+  }
+
+  VisualSceneSurfaceMeshing :: ~VisualSceneSurfaceMeshing ()
+  {
+    ;
+  }
+
+  void VisualSceneSurfaceMeshing :: DrawScene ()
+  {
+    int i, j, k;
+
+    //  cout << "draw surfacemeshing" << endl;
+    /*
+      if (changeval != stlgeometry->GetNT())
+      BuildScene();
+      changeval = stlgeometry->GetNT();
+    */
+
+    glClearColor(backcolor, backcolor, backcolor, 1.0);
+    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+    SetLight();
+
+    glPushMatrix();
+    glLoadMatrixf (transmat);
+    glMultMatrixf (rotmat);
+
+
+    glShadeModel (GL_SMOOTH);
+    glDisable (GL_COLOR_MATERIAL);
+    glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
+
+    glEnable (GL_BLEND);
+    glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+    float mat_spec_col[] = { 1, 1, 1, 1 };
+    glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, mat_spec_col);
+
+    double shine = vispar.shininess;
+    double transp = vispar.transp;
+
+    glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, shine);
+    glLogicOp (GL_COPY);
+
+
+    float mat_col[] = { 0.2, 0.2, 0.8, transp };
+    float mat_colrt[] = { 0.2, 0.8, 0.8, transp };
+    glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_col);
+
+    glPolygonOffset (1, 1);
+    glEnable (GL_POLYGON_OFFSET_FILL);
+
+    glColor3f (1.0f, 1.0f, 1.0f);
+
+    glEnable (GL_NORMALIZE);
+    /*
+      glBegin (GL_TRIANGLES);
+      for (j = 1; j <= stlgeometry -> GetNT(); j++)
+      {
+      glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_col);
+      if (j == geomtrig)
+      glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colrt);
+	
+
+      const STLReadTriangle & tria = stlgeometry -> GetReadTriangle(j);
+      glNormal3f (tria.normal.X(),
+      tria.normal.Y(),
+      tria.normal.Z());
+		  
+      for (k = 0; k < 3; k++)
+      {
+      glVertex3f (tria.pts[k].X(),
+      tria.pts[k].Y(),
+      tria.pts[k].Z());
+      }
+      }    
+      glEnd ();
+    */
+
+
+    glDisable (GL_POLYGON_OFFSET_FILL);
+
+    float mat_colbl[] = { 0.8, 0.2, 0.2, 1 };
+    float mat_cololdl[] = { 0.2, 0.8, 0.2, 1 };
+    float mat_colnewl[] = { 0.8, 0.8, 0.2, 1 };
+
+
+    glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
+    glPolygonOffset (1, -1);
+    glLineWidth (3);
+
+    for (i = 1; i <= loclines.Size(); i++)
+      {
+	if (i == 1)
+	  {
+	    glEnable (GL_POLYGON_OFFSET_FILL);
+	    glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colbl);
+	  }
+	else if (i <= oldnl) 
+	  glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_cololdl);
+	else 
+	  glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colnewl);
+
+	int pi1 = loclines.Get(i).I1();
+	int pi2 = loclines.Get(i).I2();
+
+	if (pi1 >= 1 && pi2 >= 1)
+	  {
+	    Point3d p1 = locpoints.Get(pi1);
+	    Point3d p2 = locpoints.Get(pi2);
+	  
+	    glBegin (GL_LINES);
+	    glVertex3f (p1.X(), p1.Y(), p1.Z());
+	    glVertex3f (p2.X(), p2.Y(), p2.Z());
+	    glEnd();
+	  }
+
+	glDisable (GL_POLYGON_OFFSET_FILL);
+      }
+
+
+    glLineWidth (1);
+
+
+    glPointSize (5);
+    float mat_colp[] = { 1, 0, 0, 1 };
+    glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colp);
+    glBegin (GL_POINTS);
+    for (i = 1; i <= locpoints.Size(); i++)
+      {
+	Point3d p = locpoints.Get(i);
+	glVertex3f (p.X(), p.Y(), p.Z());
+      }
+    glEnd();
+
+
+    glPopMatrix();
+
+
+    float mat_col2d1[] = { 1, 0.5, 0.5, 1 };
+    float mat_col2d[] = { 1, 1, 1, 1 };
+    glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_col2d);
+  
+    double scalex = 0.1, scaley = 0.1;
+
+    glBegin (GL_LINES);
+    for (i = 1; i <= loclines.Size(); i++)
+      {
+	glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_col2d);
+	if (i == 1)
+	  glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_col2d1);
+
+	int pi1 = loclines.Get(i).I1();
+	int pi2 = loclines.Get(i).I2();
+
+	if (pi1 >= 1 && pi2 >= 1)
+	  {
+	    Point2d p1 = plainpoints.Get(pi1);
+	    Point2d p2 = plainpoints.Get(pi2);
+	  
+	    glBegin (GL_LINES);
+	    glVertex3f (scalex * p1.X(), scaley * p1.Y(), -5);
+	    glVertex3f (scalex * p2.X(), scaley * p2.Y(), -5);
+	    glEnd();
+	  }
+      }
+    glEnd ();
+
+
+    glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colp);
+    glBegin (GL_POINTS);
+    for (i = 1; i <= plainpoints.Size(); i++)
+      {
+	Point2d p = plainpoints.Get(i);
+	glVertex3f (scalex * p.X(), scaley * p.Y(), -5);
+      }
+    glEnd();
+
+    glFinish();  
+  }
+
+
+  void VisualSceneSurfaceMeshing :: BuildScene (int zoomall)
+  {
+    int i, j, k;
+    /*
+      center = stlgeometry -> GetBoundingBox().Center();
+      rad = stlgeometry -> GetBoundingBox().Diam() / 2;
+
+      CalcTransformationMatrices();
+    */
+  }
+
+}
+
+
+#else
+namespace netgen
+{
+  void glrender (int wait)
+  { ; }
+}
+#endif
diff --git a/Netgen/libsrc/meshing/meshing2.hpp b/Netgen/libsrc/meshing/meshing2.hpp
new file mode 100644
index 0000000000..e827a5419b
--- /dev/null
+++ b/Netgen/libsrc/meshing/meshing2.hpp
@@ -0,0 +1,149 @@
+#ifndef FILE_MESHING2
+#define FILE_MESHING2
+
+/**************************************************************************/
+/* File:   meshing2.hpp                                                   */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Okt. 95                                                    */
+/**************************************************************************/
+
+
+
+enum MESHING2_RESULT
+{
+  MESHING2_OK = 0,
+  MESHING2_GIVEUP = 1,
+};
+
+
+/*
+   
+The basis class for 2D mesh generation. 
+Has the method GenerateMesh
+
+For surface mesh generation, or non-Euklidean meshing,
+derive from Meshing2, and replace transformation.
+
+*/
+
+class Meshing2
+{
+  /// the current advancing front
+  AdFront2 * adfront;
+  /// rules for mesh generation
+  ARRAY<netrule*> rules;
+  /// statistics
+  ARRAY<int> ruleused, canuse, foundmap;
+  /// 
+  Box3d boundingbox;
+  ///
+  double starttime;
+public:
+  ///
+  Meshing2 (const Box3d & aboundingbox);
+
+  ///
+  virtual ~Meshing2 ();
+
+  /// Load rules, either from file, or compiled rules
+  void LoadRules (const char * filename);
+
+  /// 
+  MESHING2_RESULT GenerateMesh (Mesh & mesh, double gh, int facenr);
+
+  ///
+  void AddPoint (const Point3d & p, PointIndex globind, MultiPointGeomInfo * mgi = NULL);
+
+  ///
+  void AddBoundaryElement (INDEX i1, INDEX i2,
+			   const PointGeomInfo & gi1, const PointGeomInfo & gi2);
+  
+  ///
+  void SetStartTime (double astarttime);
+
+protected:
+  ///
+  virtual void StartMesh ();
+  ///
+  virtual void EndMesh ();
+  ///
+  virtual double CalcLocalH (const Point3d & p, double gh) const;
+
+  ///
+  virtual void DefineTransformation (Point3d & p1, Point3d & p2,
+				     const PointGeomInfo * geominfo1,
+				     const PointGeomInfo * geominfo2);
+  ///
+  virtual void TransformToPlain (const Point3d & locpoint, const MultiPointGeomInfo &  geominfo,
+				 Point2d & plainpoint, double h, int & zone);
+  /// return 0 .. ok
+  /// return >0 .. cannot transform point to true surface
+  virtual int TransformFromPlain (Point2d & plainpoint,
+				  Point3d & locpoint, 
+				  PointGeomInfo & geominfo, 
+				  double h);
+  
+  /// projects to surface
+  /// return 0 .. ok
+  virtual int BelongsToActiveChart (const Point3d & p, 
+				    const PointGeomInfo & gi);
+
+  /// computes geoinfo data for line with respect to
+  /// selected chart
+  virtual int ComputePointGeomInfo (const Point3d & p, 
+				    PointGeomInfo & gi);
+
+  /// Tries to select unique geominfo on active chart
+  /// return 0: success
+  /// return 1: failed
+  virtual int ChooseChartPointGeomInfo (const MultiPointGeomInfo & mpgi, 
+					PointGeomInfo & pgi);
+
+
+
+  /*
+    tests, whether endpoint (= 1 or 2) of line segment p1-p2
+    is inside of the selected chart. The endpoint must be on the
+    chart
+   */
+  virtual int IsLineVertexOnChart (const Point3d & p1, const Point3d & p2,
+				   int endpoint, const PointGeomInfo & geominfo);
+
+  /*
+    get (projected) boundary of current chart
+   */
+  virtual void GetChartBoundary (ARRAY<Point2d> & points, 
+				 ARRAY<Point3d> & points3d,
+				 ARRAY<INDEX_2> & lines, double p) const;
+
+  virtual double Area () const;
+
+
+/** Applies 2D rules.
+ Tests all 2D rules */
+  int ApplyRules (ARRAY<Point2d> & lpoints, 
+		  ARRAY<int> & legalpoints,
+		  int maxlegalpoint,
+		  ARRAY<INDEX_2> & llines,
+		  int maxlegelline,
+		  ARRAY<Element2d> & elements, ARRAY<INDEX> & dellines,
+		  int tolerance);
+  
+
+};
+
+
+
+
+
+
+
+
+#endif
+
+
+
+
+
+
+
diff --git a/Netgen/libsrc/meshing/meshing3.cpp b/Netgen/libsrc/meshing/meshing3.cpp
new file mode 100644
index 0000000000..46b89b28cd
--- /dev/null
+++ b/Netgen/libsrc/meshing/meshing3.cpp
@@ -0,0 +1,1303 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+namespace netgen
+{
+
+double minother;
+double minwithoutother;
+
+
+
+
+
+
+
+/*
+MeshingParameters3 ::   MeshingParameters3()
+{
+  h = 1;
+  giveuptol = 10;
+  maxoutersteps = 5;
+  baseelnp = 0;
+  starshapeclass = 5;
+  blockfill = 0;
+  sloppy = 1;
+  optsteps = 2;
+  optstr = "cmsmdm";
+}
+*/
+
+
+
+
+  
+MeshingStat3d :: MeshingStat3d ()
+{
+  cntsucc = cnttrials = cntelem = qualclass = 0;
+  vol0 = h = 1;
+  problemindex = 1;
+}  
+  
+
+ 
+
+
+Meshing3 :: Meshing3 (const char * rulefilename) //, const PlotStatistics3d * aplotstat)
+  //  : plotstat(aplotstat)
+{
+  int i;
+  tolfak = 1;
+
+  LoadRules (rulefilename, NULL);
+  adfront = new AdFront3;
+
+  problems.SetSize (rules.Size());
+  foundmap.SetSize (rules.Size());
+  canuse.SetSize (rules.Size());
+  ruleused.SetSize (rules.Size());
+
+  for (i = 1; i <= rules.Size(); i++)
+    {
+      problems.Elem(i) = new char[255];
+      foundmap.Elem(i) = 0;
+      canuse.Elem(i) = 0;
+      ruleused.Elem(i) = 0;
+    }
+}
+
+Meshing3 :: Meshing3 (const char * rulefilename, const char ** rulep)
+  //		      const PlotStatistics3d * aplotstat)
+  //  : plotstat(aplotstat)
+{
+  tolfak = 1;
+
+  LoadRules (NULL, rulep);
+  adfront = new AdFront3;
+
+  problems.SetSize (rules.Size());
+  foundmap.SetSize (rules.Size());
+  canuse.SetSize (rules.Size());
+  ruleused.SetSize (rules.Size());
+
+  for (int i = 0; i < rules.Size(); i++)
+    {
+      problems[i] = new char[255];
+      foundmap[i] = 0;
+      canuse[i]   = 0;
+      ruleused[i] = 0;
+    }
+}
+
+Meshing3 :: ~Meshing3 ()
+{
+  delete adfront;
+  for (int i = 0; i < rules.Size(); i++)
+    {
+      delete problems[i];
+      delete rules[i];
+    }
+}
+
+
+#ifdef ABC
+TerminalPlotStatistics3d :: TerminalPlotStatistics3d()
+{
+  oldne = -1;
+}
+
+void TerminalPlotStatistics3d :: Plot (const MeshingStat3d & stat) const
+{
+  if (stat.cntelem == oldne)
+    return;
+  
+  ((int&)oldne) = stat.cntelem;
+
+  PrintMessageCR (5, "El: ", stat.cntelem,
+		//	    << " trials: " << stat.cnttrials
+		" faces: ", stat.nff,
+		" vol = ", float(100 * stat.vol / stat.vol0));
+  
+  multithread.percent = 100 -  100.0 * stat.vol / stat.vol0;
+}
+
+#endif
+
+
+static double CalcLocH (const ARRAY<Point3d> & locpoints,
+			const ARRAY<Element2d> & locfaces,
+			double h)
+{
+  return h;
+
+  // was war das ????
+  
+  int i, j;
+  double hi, h1, d, dn, sum, weight, wi;
+  Point3d p0, pc;
+  Vec3d n, v1, v2;
+
+  p0.X() = p0.Y() = p0.Z() = 0;
+  for (j = 1; j <= 3; j++)
+    {
+      p0.X() += locpoints.Get(locfaces.Get(1).PNum(j)).X();
+      p0.Y() += locpoints.Get(locfaces.Get(1).PNum(j)).Y();
+      p0.Z() += locpoints.Get(locfaces.Get(1).PNum(j)).Z();
+    }
+  p0.X() /= 3; p0.Y() /= 3; p0.Z() /= 3;
+  
+  v1 = locpoints.Get(locfaces.Get(1).PNum(2)) -
+    locpoints.Get(locfaces.Get(1).PNum(1));
+  v2 = locpoints.Get(locfaces.Get(1).PNum(3)) -
+    locpoints.Get(locfaces.Get(1).PNum(1));
+
+  h1 = v1.Length();
+  n = Cross (v2, v1);
+  n /= n.Length();
+
+  sum = 0;
+  weight = 0;
+
+  for (i = 1; i <= locfaces.Size(); i++)
+    {
+      pc.X() = pc.Y() = pc.Z() = 0;
+      for (j = 1; j <= 3; j++)
+	{
+	  pc.X() += locpoints.Get(locfaces.Get(i).PNum(j)).X();
+	  pc.Y() += locpoints.Get(locfaces.Get(i).PNum(j)).Y();
+	  pc.Z() += locpoints.Get(locfaces.Get(i).PNum(j)).Z();
+	}
+      pc.X() /= 3; pc.Y() /= 3; pc.Z() /= 3;
+
+      d = Dist (p0, pc);
+      dn = n * (pc - p0);
+      hi = Dist (locpoints.Get(locfaces.Get(i).PNum(1)),
+		 locpoints.Get(locfaces.Get(i).PNum(2)));
+		 
+      if (dn > -0.2 * h1)
+	{
+	  wi = 1 / (h1 + d);
+	  wi *= wi;
+	}
+      else
+	wi = 0;
+
+      sum += hi * wi;
+      weight += wi;
+    }
+
+  return sum/weight;
+}
+
+
+int Meshing3 :: AddPoint (const Point3d & p, INDEX globind)
+{
+  return adfront -> AddPoint (p, globind);  
+}  
+
+void Meshing3 :: AddBoundaryElement (const Element2d & elem)
+{
+  adfront -> AddFace(elem);
+}  
+
+int Meshing3 :: AddConnectedPair (const INDEX_2 & apair)
+{
+  return adfront -> AddConnectedPair (apair);
+}
+
+MESHING3_RESULT Meshing3 :: 
+GenerateMesh (Mesh & mesh, const MeshingParameters & mp)
+{
+  ARRAY<Point3d> locpoints;      // local points
+  ARRAY<Element2d> locfaces;    // local faces
+  ARRAY<PointIndex> pindex;           // mapping from local to front point numbering
+  ARRAY<int> allowpoint;         // point is allowd ?
+  ARRAY<INDEX> findex;           // mapping from local to front face numbering
+  INDEX_2_HASHTABLE<int> connectedpairs(100);  // connecgted pairs for prism meshing
+
+  ARRAY<Point3d> plainpoints;       // points in reference coordinates
+  ARRAY<int> delpoints, delfaces;   // points and lines to be deleted
+  ARRAY<Element> locelements;       // new generated elements
+
+  int i, j, oldnp, oldnf;
+  int found;
+  referencetransform trans;
+  int rotind;
+  INDEX globind;
+  Point3d inp;
+  float err;
+
+  INDEX locfacesplit;             //index for faces in outer area
+  
+  int loktestmode = 0;
+
+  int uselocalh = mparam.uselocalh;
+
+  int giveuptol = mp.giveuptol; // 
+  MeshingStat3d stat;      // statistics
+  int plotstat_oldne = -1;
+
+  
+  // for star-shaped domain meshing
+  ARRAY<MeshPoint> grouppoints;      
+  ARRAY<Element2d> groupfaces;
+  ARRAY<PointIndex> grouppindex;
+  ARRAY<INDEX> groupfindex;
+  
+  
+  float minerr;
+  int hasfound;
+  double tetvol;
+  int giveup = 0;
+
+  
+  ARRAY<Point3d> tempnewpoints;
+  ARRAY<Element2d> tempnewfaces;
+  ARRAY<int> tempdelfaces;
+  ARRAY<Element> templocelements;
+
+
+  stat.h = mp.maxh;
+
+  adfront->SetStartFront (mp.baseelnp);
+
+
+  found = 0;
+  stat.vol0 = adfront -> Volume();
+  tetvol = 0;
+
+  stat.qualclass = 1;
+
+  while (1)
+    {
+      if (multithread.terminate)
+	throw NgException ("Meshing stopped");
+      /*
+      if (multithread.terminate)
+	break;
+      */
+      if (giveup)
+	break;
+
+      // break if advancing front is empty
+      if (!mp.baseelnp && adfront->Empty())
+	break;
+
+      // break, if advancing front has no elements with
+      // mp.baseelnp nodes  
+      if (mp.baseelnp && adfront->Empty (mp.baseelnp))
+	break;
+
+
+      locpoints.SetSize(0);
+      locfaces.SetSize(0);
+      locelements.SetSize(0);
+      pindex.SetSize(0);
+      findex.SetSize(0);
+
+      INDEX_2_HASHTABLE<int> connectedpairs(100);  // connecgted pairs for prism meshing
+      
+      // select base-element (will be locface[1])
+      // and get local environment of radius (safety * h)
+
+
+      int baseelem = adfront -> SelectBaseElement ();
+      if (mp.baseelnp && adfront->GetFace (baseelem).GetNP() != mp.baseelnp)
+	{
+	  adfront->IncrementClass (baseelem);	  
+	  continue;
+	}
+
+      const Element2d & bel = adfront->GetFace (baseelem);
+      const Point3d & p1 = adfront->GetPoint (bel.PNum(1));
+      const Point3d & p2 = adfront->GetPoint (bel.PNum(2));
+      const Point3d & p3 = adfront->GetPoint (bel.PNum(3));
+
+      Point3d pmid = Center (p1, p2, p3);
+
+      double his = (Dist (p1, p2) + Dist(p1, p3) + Dist(p2, p3)) / 3;
+      double hshould;
+
+      hshould = mesh.GetH (pmid);
+
+      if (adfront->GetFace (baseelem).GetNP() == 4)
+	hshould = max2 (his, hshould);
+
+      double hmax = (his > hshould) ? his : hshould;
+      
+      // qualclass should come from baseelem !!!!!
+      double hinner = hmax * (1 + stat.qualclass);
+      double houter = hmax * (1 + 2 * stat.qualclass);
+      
+      stat.qualclass =
+        adfront -> GetLocals (baseelem, locpoints, locfaces, 
+			      pindex, findex, connectedpairs,
+			      houter, hinner,
+			      locfacesplit);
+
+
+      int pi1 = pindex.Get(locfaces.Elem(1).PNum(1));
+      int pi2 = pindex.Get(locfaces.Elem(1).PNum(2));
+      int pi3 = pindex.Get(locfaces.Elem(1).PNum(3));
+
+      /*      
+      (*testout) << "baseel = " << baseelem << ", ind = " << findex.Get(1) << endl;
+      (*testout) << "pi = " << pi1 << ", " << pi2 << ", " << pi3 << endl;
+      */
+
+      loktestmode = 0;
+      /*
+      // 1085, 1084, 1491 
+      if ( (pi1 == 1085 || pi1 == 1084 || pi1 == 1491) &&
+	   (pi2 == 1085 || pi2 == 1084 || pi2 == 1491) &&
+	   (pi3 == 1085 || pi3 == 1084 || pi3 == 1491) )
+	//      if (findex.Get(1) == 7551)
+	{
+	  (*testout) << "baseel = " << findex.Get(1) << ", points: ";
+	  for (i = 1; i <= pindex.Size(); i++)
+	    (*testout) << pindex.Get(i) << " ";
+	  (*testout) << endl;
+	  loktestmode = 1;
+	}
+      */
+      //      testmode = loktestmode;
+
+      //      cout << "baseelem = " << baseelem << " qualclass = " << stat.qualclass << endl;
+
+      // loch = CalcLocH (locpoints, locfaces, h);
+      
+      stat.nff = adfront->GetNF();
+      stat.vol = adfront->Volume();
+      if (stat.vol < 0) break;
+
+      oldnp = locpoints.Size();
+      oldnf = locfaces.Size();
+
+
+      allowpoint.SetSize(locpoints.Size());
+      if (uselocalh && stat.qualclass <= 3)
+	for (i = 1; i <= allowpoint.Size(); i++)
+	  {
+	    allowpoint.Elem(i) =
+	      mesh.GetH (locpoints.Get(i)) > 0.4 * hshould / mp.sloppy;
+	  }
+      else
+	for (i = 1; i <= allowpoint.Size(); i++)	
+	  allowpoint.Elem(i) = 1;
+
+
+      
+      if (stat.qualclass >= mp.starshapeclass)   
+	{
+	  // star-shaped domain removing
+
+	  grouppoints.SetSize (0);
+	  groupfaces.SetSize (0);
+	  grouppindex.SetSize (0);
+	  groupfindex.SetSize (0);
+	  
+	  adfront -> GetGroup (findex.Get(1), grouppoints, groupfaces, 
+			       grouppindex, groupfindex);
+
+	  int onlytri = 1;
+	  for (i = 1; i <= groupfaces.Size(); i++)
+	    if (groupfaces.Get(i).GetNP() != 3) 
+	      onlytri = 0;
+
+	  if (onlytri && groupfaces.Size() <= 20 &&
+	      FindInnerPoint (grouppoints, groupfaces, inp))
+	    {
+	      (*testout) << "inner point found" << endl;
+
+	      for (i = 1; i <= groupfaces.Size(); i++)
+		adfront -> DeleteFace (groupfindex.Get(i));
+	      
+	      for (i = 1; i <= groupfaces.Size(); i++)
+		for (j = 1; j <= locfaces.Size(); j++)
+		  if (findex.Get(j) == groupfindex.Get(i))
+		    delfaces.Append (j);
+	      
+	      
+	      delfaces.SetSize (0);
+	      
+	      INDEX npi;
+	      Element newel;
+	      
+	      npi = mesh.AddPoint (inp);
+	      newel.SetNP(4);
+	      newel.PNum(4) = npi;
+	      
+	      
+	      for (i = 1; i <= groupfaces.Size(); i++)
+		{
+		  for (j = 1; j <= 3; j++)
+		    {
+		      newel.PNum(j) = 
+			adfront->GetGlobalIndex 
+			(grouppindex.Get(groupfaces.Get(i).PNum(j)));
+		    }
+		  mesh.AddVolumeElement (newel);
+		}
+	      continue;
+	    }
+	}
+      
+
+
+      found = 0;
+      hasfound = 0;
+      minerr = 1e6;
+
+
+      //      int optother = 0;
+
+      /*
+      for (i = 1; i <= locfaces.Size(); i++)
+	{
+	  (*testout) << "Face " << i << ": ";
+	  for (j = 1; j <= locfaces.Get(i).GetNP(); j++)
+	    (*testout) << pindex.Get(locfaces.Get(i).PNum(j)) << " ";
+	  (*testout) << endl;
+	}
+      for (i = 1; i <= locpoints.Size(); i++)
+	{
+	  (*testout) << "p" << i 
+		     << ", gi = " << pindex.Get(i) 
+		     << " = " << locpoints.Get(i) << endl;
+	}
+	*/
+
+      minother = 1e10;
+      minwithoutother = 1e10;
+
+      for (rotind = 1; rotind <= locfaces.Get(1).GetNP(); rotind++)
+	{
+	  // set transformatino to reference coordinates
+
+	  if (locfaces.Get(1).GetNP() == 3)
+	    {
+	      trans.Set (locpoints.Get(locfaces.Get(1).PNumMod(1+rotind)),
+			 locpoints.Get(locfaces.Get(1).PNumMod(2+rotind)),
+			 locpoints.Get(locfaces.Get(1).PNumMod(3+rotind)), hshould);
+	    }
+	  else
+	    {
+	      trans.Set (locpoints.Get(locfaces.Get(1).PNumMod(1+rotind)),
+			 locpoints.Get(locfaces.Get(1).PNumMod(2+rotind)),
+			 locpoints.Get(locfaces.Get(1).PNumMod(4+rotind)), hshould);
+	    }
+
+	  trans.ToPlain (locpoints, plainpoints);
+	  
+	  stat.cnttrials++;
+
+
+	  if (stat.cnttrials % 100 == 0)
+	    {
+	      (*testout) << "\n";
+	      for (i = 1; i <= canuse.Size(); i++)
+	      {
+		(*testout) << foundmap.Get(i) << "/" 
+			   << canuse.Get(i) << "/"
+			   << ruleused.Get(i) << " map/can/use rule " << rules.Get(i)->Name() << "\n";
+	      }
+	      (*testout) << endl;
+	    }
+	  
+	  found = ApplyRules (plainpoints, allowpoint, 
+			      locfaces, locfacesplit, connectedpairs,
+			      locelements, delfaces, 
+			      stat.qualclass, mp.sloppy, rotind, err);
+	  
+	  if (loktestmode)
+	    {
+	      (*testout) << "Applyrules found " << found << endl;
+	    }
+
+	  if (found) stat.cntsucc++;
+
+	  locpoints.SetSize (plainpoints.Size());
+	  for (i = oldnp+1; i <= plainpoints.Size(); i++)
+	    trans.FromPlain (plainpoints.Elem(i), locpoints.Elem(i));
+	  
+
+
+	  // avoid meshing from large to small mesh-size
+
+	  if (uselocalh && found && stat.qualclass <= 3)
+	    {
+	      for (i = 1; i <= locelements.Size(); i++)
+		{
+		  Point3d pmin = locpoints.Get(locelements.Get(i).PNum(1));
+		  Point3d pmax = pmin;
+		  for (j = 2; j <= 4; j++)
+		    {
+		      const Point3d & hp = locpoints.Get(locelements.Get(i).PNum(j));
+		      pmin.SetToMin (hp);
+		      pmax.SetToMax (hp);
+		    }
+
+		  if (mesh.GetMinH (pmin, pmax) < 0.4 * hshould / mp.sloppy)
+		    found = 0;
+		}
+	    }
+	  if (found)
+	    {
+	      for (i = 1; i <= locelements.Size(); i++)
+		for (j = 1; j <= 4; j++)
+		  {
+		    const Point3d & hp = locpoints.Get(locelements.Get(i).PNum(j));
+		    if (Dist (hp, pmid) > hinner)
+		      found = 0;
+		  }
+	    }
+
+
+	  if (found)
+	    ruleused.Elem(found)++;
+
+
+	  if (stat.qualclass > 80)
+	    {
+	      cerr << "Sorry, I failed" << endl;
+	      mesh.Save ("tempvol.out");
+	      exit (1);
+	    }
+	  
+	  
+	  // plotstat->Plot(stat);
+	  
+	  if (stat.cntelem != plotstat_oldne)
+	    {
+	      plotstat_oldne = stat.cntelem;
+
+	      PrintMessageCR (5, "El: ", stat.cntelem,
+			      //	    << " trials: " << stat.cnttrials
+			      " faces: ", stat.nff,
+			      " vol = ", float(100 * stat.vol / stat.vol0));
+  
+	      multithread.percent = 100 -  100.0 * stat.vol / stat.vol0;
+	    }
+
+
+	  if (found && (!hasfound || err < minerr) )
+	    {
+	      
+	      if (testmode)
+		{
+		  (*testout) << "testmode found" << endl;
+		  for (i = 1; i <= plainpoints.Size(); i++)
+		    {
+		      (*testout) << "p";
+		      if (i <= pindex.Size())
+			(*testout) << pindex.Get(i) << ": ";
+		      else
+			(*testout) << "new: ";
+		      (*testout) << plainpoints.Get(i) << endl;
+		    }
+		}
+	      
+	      
+	      
+	      hasfound = found;
+	      minerr = err;
+	      
+	      tempnewpoints.SetSize (0);
+	      for (i = oldnp+1; i <= locpoints.Size(); i++)
+		tempnewpoints.Append (locpoints.Get(i));
+	      
+	      tempnewfaces.SetSize (0);
+	      for (i = oldnf+1; i <= locfaces.Size(); i++)
+		tempnewfaces.Append (locfaces.Get(i));
+	      
+	      tempdelfaces.SetSize (0);
+	      for (i = 1; i <= delfaces.Size(); i++)
+		tempdelfaces.Append (delfaces.Get(i));
+	      
+	      templocelements.SetSize (0);
+	      for (i = 1; i <= locelements.Size(); i++)
+		templocelements.Append (locelements.Get(i));
+
+	      /*
+	      optother =
+		strcmp (problems[found], "other") == 0;
+	      */
+	    }
+	  
+	  locpoints.SetSize (oldnp);
+	  locfaces.SetSize (oldnf);
+	  delfaces.SetSize (0);
+	  locelements.SetSize (0);
+	}
+      
+      
+
+      if (hasfound)
+	{
+
+	  /*
+	  if (optother)
+	    (*testout) << "Other is optimal" << endl;
+
+	  if (minother < minwithoutother)
+	    {
+	      (*testout) << "Other is better, " << minother << " less " << minwithoutother << endl;
+	    }
+	    */
+
+	  for (i = 1; i <= tempnewpoints.Size(); i++)
+	    locpoints.Append (tempnewpoints.Get(i));
+	  for (i = 1; i <= tempnewfaces.Size(); i++)
+	    locfaces.Append (tempnewfaces.Get(i));
+	  for (i = 1; i <= tempdelfaces.Size(); i++)
+	    delfaces.Append (tempdelfaces.Get(i));
+	  for (i = 1; i <= templocelements.Size(); i++)
+	    locelements.Append (templocelements.Get(i));
+
+
+	  if (testmode)
+	    {
+	      (*testout) << "testmode locpoints" << endl;
+	      for (i = 1; i <= locpoints.Size(); i++)
+		{
+		  (*testout) << "p";
+		  if (i <= pindex.Size())
+		    (*testout) << pindex.Get(i) << ": ";
+		  else
+		    (*testout) << "new: ";
+		  (*testout) << locpoints.Get(i) << endl;
+		}
+	    }
+
+
+
+	  pindex.SetSize(locpoints.Size());
+
+	  for (i = oldnp+1; i <= locpoints.Size(); i++)
+	    {
+	      globind = mesh.AddPoint (locpoints.Get(i));
+	      pindex.Elem(i) = adfront -> AddPoint (locpoints.Get(i), globind);
+	    }
+
+	  for (i = 1; i <= locelements.Size(); i++)
+	    {
+	      Point3d * hp1, * hp2, * hp3, * hp4;
+	      hp1 = &locpoints.Elem(locelements.Get(i).PNum(1));
+	      hp2 = &locpoints.Elem(locelements.Get(i).PNum(2));
+	      hp3 = &locpoints.Elem(locelements.Get(i).PNum(3));
+	      hp4 = &locpoints.Elem(locelements.Get(i).PNum(4));
+	      
+	      tetvol += (1.0 / 6.0) * ( Cross ( *hp2 - *hp1, *hp3 - *hp1) * (*hp4 - *hp1) );
+
+	      for (j = 1; j <= locelements.Get(i).NP(); j++)
+		locelements.Elem(i).PNum(j) =
+		  adfront -> GetGlobalIndex (pindex.Get(locelements.Get(i).PNum(j)));
+
+	      mesh.AddVolumeElement (locelements.Get(i));
+	      stat.cntelem++;
+	    }
+
+	  for (i = oldnf+1; i <= locfaces.Size(); i++)
+	    {
+	      for (j = 1; j <= locfaces.Get(i).GetNP(); j++)
+		locfaces.Elem(i).PNum(j) = 
+		  pindex.Get(locfaces.Get(i).PNum(j));
+	      (*testout) << "add face " << locfaces.Get(i) << endl;
+	      adfront->AddFace (locfaces.Get(i));
+	    }
+	  
+	  for (i = 1; i <= delfaces.Size(); i++)
+	    {
+	      adfront->DeleteFace (findex.Get(delfaces.Get(i)));
+	    }
+	}
+      else
+	{
+	  adfront->IncrementClass (findex.Get(1));
+	}
+
+      locelements.SetSize (0);
+      delpoints.SetSize(0);
+      delfaces.SetSize(0);
+
+      if (stat.qualclass >= giveuptol)
+	giveup = 1;
+#ifdef MYGRAPH
+      if (plotvolmesh && plotvolmesh->GiveUp())
+	giveup = 1;
+#endif
+    }
+  
+
+
+  for (i = 1; i <= ruleused.Size(); i++)
+    (*testout) << setw(4) << ruleused.Get(i)
+	       << " times used rule " << rules.Get(i) -> Name() << endl;
+
+
+  if (!mp.baseelnp && adfront->Empty())
+    return MESHING3_OK;
+
+  if (mp.baseelnp && adfront->Empty (mp.baseelnp))
+    return MESHING3_OK;
+
+  if (stat.vol < -1e-15)
+    return MESHING3_NEGVOL;
+
+  return MESHING3_NEGVOL;
+}
+
+
+
+
+enum blocktyp { BLOCKUNDEF, BLOCKINNER, BLOCKBOUND, BLOCKOUTER };
+
+void Meshing3 :: BlockFill (Mesh & mesh, double gh)
+{
+  PrintMessage (3, "Block-filling called (obsolete) ");
+
+  int i, j, i1, i2, i3, j1, j2, j3;
+  int n1, n2, n3, n, min1, min2, min3, max1, max2, max3;
+  int changed, filled;
+  double xmin, xmax, ymin, ymax, zmin, zmax;
+  double xminb, xmaxb, yminb, ymaxb, zminb, zmaxb;
+  double rad = 0.7 * gh;
+  
+  for (i = 1; i <= adfront->GetNP(); i++)
+    {
+      const Point3d & p = adfront->GetPoint(i);
+      if (i == 1)
+	{
+	  xmin = xmax = p.X();
+	  ymin = ymax = p.Y();
+	  zmin = zmax = p.Z();
+	}
+      else
+	{
+	  if (p.X() < xmin) xmin = p.X();
+	  if (p.X() > xmax) xmax = p.X();
+	  if (p.Y() < ymin) ymin = p.Y();
+	  if (p.Y() > ymax) ymax = p.Y();
+	  if (p.Z() < zmin) zmin = p.Z();
+	  if (p.Z() > zmax) zmax = p.Z();
+	}
+    }
+  
+  xmin -= 5 * gh;
+  ymin -= 5 * gh;
+  zmin -= 5 * gh;
+  
+  n1 = int ((xmax-xmin) / gh + 5);
+  n2 = int ((ymax-ymin) / gh + 5);
+  n3 = int ((zmax-zmin) / gh + 5);
+  n = n1 * n2 * n3;
+  
+  PrintMessage (5, "n1 = ", n1, " n2 = ", n2, " n3 = ", n3);
+
+  ARRAY<blocktyp> inner(n);
+  ARRAY<int> pointnr(n), frontpointnr(n);
+
+
+  // initialize inner to 1
+
+  for (i = 1; i <= n; i++)
+    inner.Elem(i) = BLOCKUNDEF;
+
+
+  // set blocks cutting surfaces to 0
+
+  for (i = 1; i <= adfront->GetNF(); i++)
+    {
+      const Element2d & el = adfront->GetFace(i);
+      xminb = xmax; xmaxb = xmin;
+      yminb = ymax; ymaxb = ymin;
+      zminb = zmax; zmaxb = zmin;
+
+      for (j = 1; j <= 3; j++)
+	{
+	  const Point3d & p = adfront->GetPoint (el.PNum(j));
+	  if (p.X() < xminb) xminb = p.X();
+	  if (p.X() > xmaxb) xmaxb = p.X();
+	  if (p.Y() < yminb) yminb = p.Y();
+	  if (p.Y() > ymaxb) ymaxb = p.Y();
+	  if (p.Z() < zminb) zminb = p.Z();
+	  if (p.Z() > zmaxb) zmaxb = p.Z();
+	}
+
+	
+
+      double filldist = 0.2; // globflags.GetNumFlag ("filldist", 0.4);
+      xminb -= filldist * gh;
+      xmaxb += filldist * gh;
+      yminb -= filldist * gh;
+      ymaxb += filldist * gh;
+      zminb -= filldist * gh;
+      zmaxb += filldist * gh;
+
+      min1 = int ((xminb - xmin) / gh) + 1;
+      max1 = int ((xmaxb - xmin) / gh) + 1;
+      min2 = int ((yminb - ymin) / gh) + 1;
+      max2 = int ((ymaxb - ymin) / gh) + 1;
+      min3 = int ((zminb - zmin) / gh) + 1;
+      max3 = int ((zmaxb - zmin) / gh) + 1;
+
+
+      for (i1 = min1; i1 <= max1; i1++)
+	for (i2 = min2; i2 <= max2; i2++)
+	  for (i3 = min3; i3 <= max3; i3++)
+	    inner.Elem(i3 + (i2-1) * n3 + (i1-1) * n2 * n3) = BLOCKBOUND;      
+    }
+
+  
+
+
+  while (1)
+    {
+      int undefi = 0;
+      Point3d undefp;
+
+      for (i1 = 1; i1 <= n1 && !undefi; i1++)
+	for (i2 = 1; i2 <= n2 && !undefi; i2++)
+	  for (i3 = 1; i3 <= n3 && !undefi; i3++)
+	    {
+	      i = i3 + (i2-1) * n3 + (i1-1) * n2 * n3;
+	      if (inner.Elem(i) == BLOCKUNDEF)
+		{
+		  undefi = i;
+		  undefp.X() = xmin + (i1-0.5) * gh;
+		  undefp.Y() = ymin + (i2-0.5) * gh;
+		  undefp.Z() = zmin + (i3-0.5) * gh;
+		}
+	    }
+	      
+      if (!undefi)
+	break;
+
+      //      PrintMessage (5, "Test point: ", undefp);
+      
+      if (adfront -> Inside (undefp))
+	{
+	  //	  (*mycout) << "inner" << endl;
+	  inner.Elem(undefi) = BLOCKINNER;
+	}
+      else
+	{
+	  //	  (*mycout) << "outer" << endl;
+	  inner.Elem(undefi) = BLOCKOUTER;
+	}
+
+      do
+	{
+	  changed = 0;
+	  for (i1 = 1; i1 <= n1; i1++)
+	    for (i2 = 1; i2 <= n2; i2++)
+	      for (i3 = 1; i3 <= n3; i3++)
+		{
+		  i = i3 + (i2-1) * n3 + (i1-1) * n2 * n3;
+
+		  for (int k = 1; k <= 3; k++)
+		    {
+		      switch (k)
+			{
+			case 1: j = i + n2 * n3; break;
+			case 2: j = i + n3; break;
+			case 3: j = i + 1; break;
+			}
+		  
+		      if (j > n1 * n2 * n3) continue;
+
+		      if (inner.Elem(i) == BLOCKOUTER && inner.Elem(j) == BLOCKUNDEF)
+			{
+			  changed = 1;
+			  inner.Elem(j) = BLOCKOUTER;
+			}
+		      if (inner.Elem(j) == BLOCKOUTER && inner.Elem(i) == BLOCKUNDEF)
+			{
+			  changed = 1;
+			  inner.Elem(i) = BLOCKOUTER;
+			}
+		      if (inner.Elem(i) == BLOCKINNER && inner.Elem(j) == BLOCKUNDEF)
+			{
+			  changed = 1;
+			  inner.Elem(j) = BLOCKINNER;
+			}
+		      if (inner.Elem(j) == BLOCKINNER && inner.Elem(i) == BLOCKUNDEF)
+			{
+			  changed = 1;
+			  inner.Elem(i) = BLOCKINNER;
+			}
+		    }
+		}
+	}
+      while (changed); 
+
+    }
+
+
+
+  filled = 0;
+  for (i = 1; i <= n; i++)
+    if (inner.Elem(i) == BLOCKINNER)
+      {
+	filled++;
+      }
+  PrintMessage (5, "Filled blocks: ", filled);
+
+  for (i = 1; i <= n; i++)
+    {
+      pointnr.Elem(i) = 0;
+      frontpointnr.Elem(i) = 0;
+    }
+  
+  for (i1 = 1; i1 <= n1-1; i1++)
+    for (i2 = 1; i2 <= n2-1; i2++)
+      for (i3 = 1; i3 <= n3-1; i3++)
+	{
+	  i = i3 + (i2-1) * n3 + (i1-1) * n2 * n3;
+	  if (inner.Elem(i) == BLOCKINNER)
+	    {
+	      for (j1 = i1; j1 <= i1+1; j1++)
+		for (j2 = i2; j2 <= i2+1; j2++)
+		  for (j3 = i3; j3 <= i3+1; j3++)
+		    {
+		      j = j3 + (j2-1) * n3 + (j1-1) * n2 * n3;
+		      if (pointnr.Get(j) == 0)
+			{
+			  Point3d hp(xmin + (j1-1) * gh, 
+				     ymin + (j2-1) * gh, 
+				     zmin + (j3-1) * gh);
+			  pointnr.Elem(j) = mesh.AddPoint (hp);
+			  frontpointnr.Elem(j) =
+			    AddPoint (hp, pointnr.Elem(j));
+
+			}
+		    }
+	    }
+	}
+
+
+  for (i1 = 2; i1 <= n1-1; i1++)
+    for (i2 = 2; i2 <= n2-1; i2++)
+      for (i3 = 2; i3 <= n3-1; i3++)
+	{
+	  i = i3 + (i2-1) * n3 + (i1-1) * n2 * n3;
+	  if (inner.Elem(i) == BLOCKINNER)
+	    {
+	      int pn[9];
+	      pn[1] = pointnr.Get(i);
+	      pn[2] = pointnr.Get(i+1);
+	      pn[3] = pointnr.Get(i+n3);
+	      pn[4] = pointnr.Get(i+n3+1);
+	      pn[5] = pointnr.Get(i+n2*n3);
+	      pn[6] = pointnr.Get(i+n2*n3+1);
+	      pn[7] = pointnr.Get(i+n2*n3+n3);
+	      pn[8] = pointnr.Get(i+n2*n3+n3+1);
+	      static int elind[][4] =
+	      {
+		{ 1, 8, 2, 4 },
+		{ 1, 8, 4, 3 },
+		{ 1, 8, 3, 7 },
+		{ 1, 8, 7, 5 },
+		{ 1, 8, 5, 6 },
+		{ 1, 8, 6, 2 }
+	      };
+	      for (j = 1; j <= 6; j++)
+		{
+		  Element el(4);
+		  for (int k = 1; k <= 4;  k++)
+		    el.PNum(k) = pn[elind[j-1][k-1]];
+
+		  mesh.AddVolumeElement (el);
+		}
+	    }
+	}
+
+
+
+  for (i1 = 2; i1 <= n1-1; i1++)
+    for (i2 = 2; i2 <= n2-1; i2++)
+      for (i3 = 2; i3 <= n3-1; i3++)
+	{
+	  i = i3 + (i2-1) * n3 + (i1-1) * n2 * n3;
+	  if (inner.Elem(i) == BLOCKINNER)
+	    {    
+	      int pi1, pi2, pi3, pi4;
+
+	      int pn1 = frontpointnr.Get(i);
+	      int pn2 = frontpointnr.Get(i+1);
+	      int pn3 = frontpointnr.Get(i+n3);
+	      int pn4 = frontpointnr.Get(i+n3+1);
+	      int pn5 = frontpointnr.Get(i+n2*n3);
+	      int pn6 = frontpointnr.Get(i+n2*n3+1);
+	      int pn7 = frontpointnr.Get(i+n2*n3+n3);
+	      int pn8 = frontpointnr.Get(i+n2*n3+n3+1);
+
+	      for (int k = 1; k <= 6; k++)
+		{
+		  switch (k)
+		    {
+		    case 1: // j3 = i3+1
+		      j = i + 1;
+		      pi1 = pn2;
+		      pi2 = pn6;
+		      pi3 = pn4;
+		      pi4 = pn8;
+		      break;
+		    case 2: // j3 = i3-1
+		      j = i - 1;
+		      pi1 = pn1;
+		      pi2 = pn3;
+		      pi3 = pn5;
+		      pi4 = pn7;
+		      break;
+		    case 3: // j2 = i2+1
+		      j = i + n3;
+		      pi1 = pn3;
+		      pi2 = pn4;
+		      pi3 = pn7;
+		      pi4 = pn8;
+		      break;
+		    case 4: // j2 = i2-1
+		      j = i - n3;
+		      pi1 = pn1;
+		      pi2 = pn5;
+		      pi3 = pn2;
+		      pi4 = pn6;
+		      break;
+		    case 5: // j1 = i1+1
+		      j = i + n3*n2;
+		      pi1 = pn5;
+		      pi2 = pn7;
+		      pi3 = pn6;
+		      pi4 = pn8;
+		      break;
+		    case 6: // j1 = i1-1
+		      j = i - n3*n2;
+		      pi1 = pn1;
+		      pi2 = pn2;
+		      pi3 = pn3;
+		      pi4 = pn4;
+		      break;
+		    }
+
+		  if (inner.Get(j) == BLOCKBOUND)
+		    {
+		      Element2d face;
+		      face.PNum(1) = pi4;
+		      face.PNum(2) = pi1;
+		      face.PNum(3) = pi3;
+		      AddBoundaryElement (face);
+
+		      face.PNum(1) = pi1;
+		      face.PNum(2) = pi4;
+		      face.PNum(3) = pi2;
+		      AddBoundaryElement (face);
+
+		    }
+		}
+	    }
+	}
+}
+
+
+
+static const AdFront3 * locadfront;
+static int TestInner (const Point3d & p)
+{
+  return locadfront->Inside (p);
+}
+static int TestSameSide (const Point3d & p1, const Point3d & p2)
+{
+  return locadfront->SameSide (p1, p2);
+}
+
+
+
+
+void Meshing3 :: BlockFillLocalH (Mesh & mesh, 
+				  const MeshingParameters & mp)
+{
+  int i, j;
+  
+  double filldist = mp.filldist;
+
+  (*testout) << "blockfill local h" << endl;
+  (*testout) << "rel filldist = " << filldist << endl;
+  PrintMessage (3, "blockfill local h");
+
+  /*  
+  (*mycout) << "boxes: " << mesh.LocalHFunction().GetNBoxes() << endl
+	    << "filldist = " << filldist << endl;
+  */
+  ARRAY<Point3d> npoints;
+  
+  adfront -> CreateTrees();
+
+  Point3d mpmin, mpmax;
+  // mesh.GetBox (mpmin, mpmax);
+  bool firstp = 1;
+
+  double maxh = 0;
+  for (i = 1; i <= adfront->GetNF(); i++)
+    {
+      const Element2d & el = adfront->GetFace(i);
+      for (j = 1; j <= 3; j++)
+	{
+	  const Point3d & p1 = adfront->GetPoint (el.PNumMod(j));
+	  const Point3d & p2 = adfront->GetPoint (el.PNumMod(j+1));
+	  double hi = Dist (p1, p2);
+	  if (hi > maxh) maxh = hi;
+
+	  if (firstp)
+	    {
+	      mpmin = p1;
+	      mpmax = p1;
+	      firstp = 0;
+	    }
+	  else
+	    {
+	      mpmin.SetToMin  (p1);
+	      mpmax.SetToMax  (p1);
+	    }
+	}
+    }
+
+  Point3d mpc = Center (mpmin, mpmax);
+  double d = max3(mpmax.X()-mpmin.X(), 
+		  mpmax.Y()-mpmin.Y(), 
+		  mpmax.Z()-mpmin.Z()) / 2;
+  mpmin = mpc - Vec3d (d, d, d);
+  mpmax = mpc + Vec3d (d, d, d);
+  Box3d meshbox (mpmin, mpmax);
+
+  LocalH loch2 (mpmin, mpmax, 1);
+
+
+  if (mp.maxh < maxh) maxh = mp.maxh;
+
+  int changed;
+  do 
+    {
+      mesh.LocalHFunction().ClearFlags();
+
+      for (i = 1; i <= adfront->GetNF(); i++)
+	{
+	  const Element2d & el = adfront->GetFace(i);
+	  Point3d pmin = adfront->GetPoint (el.PNum(1));
+	  Point3d pmax = pmin;
+	  
+	  for (j = 2; j <= 3; j++)
+	    {
+	      const Point3d & p = adfront->GetPoint (el.PNum(j));
+	      pmin.SetToMin (p);
+	      pmax.SetToMax (p);
+	    }
+	  
+
+	  double filld = filldist * Dist (pmin, pmax);
+	  
+	  pmin = pmin - Vec3d (filld, filld, filld);
+	  pmax = pmax + Vec3d (filld, filld, filld);
+	  //	  (*testout) << "cut : " << pmin << " - " << pmax << endl;
+	  mesh.LocalHFunction().CutBoundary (pmin, pmax);
+	}
+
+      locadfront = adfront;
+      mesh.LocalHFunction().FindInnerBoxes (adfront, NULL);
+
+      npoints.SetSize(0);
+      mesh.LocalHFunction().GetInnerPoints (npoints);
+
+      changed = 0;
+      for (i = 1; i <= npoints.Size(); i++)
+	{
+	  if (mesh.LocalHFunction().GetH(npoints.Get(i)) > 1.5 * maxh)
+	    {
+	      mesh.LocalHFunction().SetH (npoints.Get(i), 
+maxh);
+	      changed = 1;
+	    }
+	}
+    }
+  while (changed);
+
+  if (debugparam.slowchecks)
+    (*testout) << "Blockfill with points: " << endl;
+  for (i = 1; i <= npoints.Size(); i++)
+    {
+      if (meshbox.IsIn (npoints.Get(i)))
+	{
+	  int gpnum = mesh.AddPoint (npoints.Get(i));
+	  adfront->AddPoint (npoints.Get(i), gpnum);
+
+	  if (debugparam.slowchecks)
+	    {
+	      (*testout) << npoints.Get(i) << endl;
+	      if (!adfront->Inside(npoints.Get(i)))
+		{
+		  cout << "add outside point" << endl;
+		  (*testout) << "outside" << endl;
+		}
+	    }
+
+	}
+    }
+
+  
+
+  // find outer points
+  
+  loch2.ClearFlags();
+
+  for (i = 1; i <= adfront->GetNF(); i++)
+    {
+      const Element2d & el = adfront->GetFace(i);
+      Point3d pmin = adfront->GetPoint (el.PNum(1));
+      Point3d pmax = pmin;
+      
+      for (j = 2; j <= 3; j++)
+	{
+	  const Point3d & p = adfront->GetPoint (el.PNum(j));
+	  pmin.SetToMin (p);
+	  pmax.SetToMax (p);
+	}
+      
+      loch2.SetH (Center (pmin, pmax), Dist (pmin, pmax));
+    }
+
+  for (i = 1; i <= adfront->GetNF(); i++)
+    {
+      const Element2d & el = adfront->GetFace(i);
+      Point3d pmin = adfront->GetPoint (el.PNum(1));
+      Point3d pmax = pmin;
+      
+      for (j = 2; j <= 3; j++)
+	{
+	  const Point3d & p = adfront->GetPoint (el.PNum(j));
+	  pmin.SetToMin (p);
+	  pmax.SetToMax (p);
+	}
+      
+      double filld = filldist * Dist (pmin, pmax);
+      pmin = pmin - Vec3d (filld, filld, filld);
+      pmax = pmax + Vec3d (filld, filld, filld);
+      loch2.CutBoundary (pmin, pmax);
+    }
+
+  locadfront = adfront;
+  loch2.FindInnerBoxes (adfront, NULL);
+
+  npoints.SetSize(0);
+  loch2.GetOuterPoints (npoints);
+  
+  for (i = 1; i <= npoints.Size(); i++)
+    {
+      if (meshbox.IsIn (npoints.Get(i)))
+	{
+	  int gpnum = mesh.AddPoint (npoints.Get(i));
+	  adfront->AddPoint (npoints.Get(i), gpnum);
+	}
+    }  
+}
+
+}
diff --git a/Netgen/libsrc/meshing/meshing3.hpp b/Netgen/libsrc/meshing/meshing3.hpp
new file mode 100644
index 0000000000..e6829554fa
--- /dev/null
+++ b/Netgen/libsrc/meshing/meshing3.hpp
@@ -0,0 +1,192 @@
+#ifndef FILE_MESHING3
+#define FILE_MESHING3
+
+
+
+
+// class PlotStatistics3d;
+
+
+/*
+///
+class MeshingParameters3
+{
+public:
+  /// global h
+  double h;
+
+  /// give up quality class
+  int giveuptol;
+
+  /// maximal outer steps
+  int maxoutersteps;   
+
+  /// if non-zero, baseelement must have baseelnp points
+  int baseelnp;        
+
+  /// class starting star-shape filling
+  int starshapeclass;
+
+  /// call blockfill function
+  int blockfill;
+
+  /// quality tolerances are handled less careful
+  double sloppy;
+
+  /// number of optimizationsteps
+  int optsteps;
+
+  ///
+  char * optstr;
+
+  ///
+  MeshingParameters3();
+};
+*/
+
+
+enum MESHING3_RESULT
+{
+  MESHING3_OK = 0,
+  MESHING3_GIVEUP = 1,
+  MESHING3_NEGVOL = 2,
+  MESHING3_OUTERSTEPSEXCEEDED = 3,
+  MESHING3_TERMINATE = 4,
+  MESHING3_BADSURFACEMESH = 5
+};
+
+
+/// 3d volume mesh generation
+class Meshing3
+{
+  /// current state of front
+  AdFront3 * adfront;
+  /// 3d generation rules
+  ARRAY<vnetrule*> rules;
+  /// counts how often a rule is used
+  ARRAY<int> ruleused, canuse, foundmap;
+  /// describes, why a rule is not applied
+  ARRAY<char*> problems;
+  /// tolerance criterion
+  double tolfak;
+public:
+  /// 
+  Meshing3 (const char * rulefilename); 
+  /// 
+  Meshing3 (const char * rulefilename, const char ** rulep);
+  ///
+  virtual ~Meshing3 ();
+  
+  ///
+  void LoadRules (const char * filename, const char ** prules);
+  ///
+  MESHING3_RESULT GenerateMesh (Mesh & mesh, const MeshingParameters & mp);
+  
+  ///
+  int ApplyRules (ARRAY<Point3d> & lpoints, ARRAY<int> & allowpoint,
+		  ARRAY<Element2d> & lfaces, INDEX lfacesplit,
+		  INDEX_2_HASHTABLE<int> & connectedpairs,
+		  ARRAY<Element> & elements,
+		  ARRAY<INDEX> & delfaces, int tolerance, 
+		  double sloppy, int rotind1,
+		  float & retminerr);
+  
+  ///
+  int AddPoint (const Point3d & p, INDEX globind);
+  ///
+  void AddBoundaryElement (const Element2d & elem);
+  ///
+  int AddConnectedPair (const INDEX_2 & pair);
+  
+  ///
+  void BlockFill (Mesh & mesh, double gh);
+  ///
+  void BlockFillLocalH (Mesh & mesh, const MeshingParameters & mp);
+
+  /// uses points of adfront, and puts new elements into mesh
+  void Delaunay (Mesh & mesh, const MeshingParameters & mp);
+  ///
+  friend class PlotVolMesh;
+  ///
+  friend void TestRules ();
+};
+
+
+
+
+/// status of mesh generation
+class MeshingStat3d
+{
+public:
+  ///
+  MeshingStat3d ();
+  ///
+  int cntsucc;
+  ///
+  int cnttrials;
+  ///
+  int cntelem;
+  ///
+  int nff;
+  ///
+  int qualclass;
+  ///
+  double vol0;
+  ///
+  double vol;
+  ///
+  double h;
+  ///
+  int problemindex;
+};
+
+
+/*
+///
+class PlotStatistics3d
+{
+public:
+  ///
+  PlotStatistics3d () { }
+  ///
+  virtual void Plot (const MeshingStat3d & stat) const = 0;
+};
+
+
+///
+class TerminalPlotStatistics3d : public PlotStatistics3d
+{
+  int oldne;
+public:
+  ///
+  TerminalPlotStatistics3d ();
+  ///
+  virtual void Plot (const MeshingStat3d & stat) const;
+};
+*/
+
+
+
+/*
+template <typename POINTARRAY, typename FACEARRAY>
+extern int FindInnerPoint (POINTARRAY & grouppoints,
+			   FACEARRAY & groupfaces,
+			   Point3d & p);
+
+*/
+
+
+
+
+
+#endif
+
+
+
+
+
+
+
+
+
+
diff --git a/Netgen/libsrc/meshing/meshtool.cpp b/Netgen/libsrc/meshing/meshtool.cpp
new file mode 100644
index 0000000000..127d047820
--- /dev/null
+++ b/Netgen/libsrc/meshing/meshtool.cpp
@@ -0,0 +1,865 @@
+#include <mystdlib.h>
+
+#include "meshing.hpp"
+#include <csg.hpp>
+#include <geometry2d.hpp>
+
+namespace netgen
+{
+
+int CheckSurfaceMesh (const Mesh & mesh)
+{
+  PrintMessage (3, "Check Surface mesh");
+
+  int nf = mesh.GetNSE();
+  INDEX_2_HASHTABLE<int> edges(nf+2);
+  int i, j;
+  INDEX_2 i2;
+  int cnt1 = 0, cnt2 = 0;
+  
+  std::cout<<"MeshTool"<<std::endl;
+
+  for (i = 1; i <= nf; i++)
+    for (j = 1; j <= 3; j++)
+      {
+	i2.I1() = mesh.SurfaceElement(i).PNumMod(j);
+ 	i2.I2() = mesh.SurfaceElement(i).PNumMod(j+1);
+        if (edges.Used(i2))
+          {
+            int hi;
+	    hi = edges.Get(i2);
+	    if (hi != 1) 
+	      PrintSysError ("CheckSurfaceMesh, hi = ", hi);
+            edges.Set(i2, 2);
+	    cnt2++;
+          }
+        else
+          {
+	    Swap (i2.I1(), i2.I2());
+            edges.Set(i2, 1);
+	    cnt1++;
+          }
+      }
+  
+
+  if (cnt1 != cnt2)
+    {
+      PrintUserError ("Surface mesh not consistent");
+      //      MyBeep(2);
+      //      (*mycout) << "cnt1 = " << cnt1 << " cnt2 = " << cnt2 << endl;
+      return 0;
+    }
+  return 1;
+}
+
+
+
+int CheckSurfaceMesh2 (const Mesh & mesh)
+{
+  int i, j, k;
+  const Point3d *tri1[3], *tri2[3];
+
+  for (i = 1; i <= mesh.GetNOpenElements(); i++)
+    {
+      PrintDot ();
+      for (j = 1; j < i; j++)
+	{
+	  for (k = 1; k <= 3; k++)
+	    {
+	      tri1[k-1] = &mesh.Point (mesh.OpenElement(i).PNum(k));
+	      tri2[k-1] = &mesh.Point (mesh.OpenElement(j).PNum(k));
+	    }
+	  if (IntersectTriangleTriangle (&tri1[0], &tri2[0]))
+	    {
+	      PrintSysError ("Surface elements are intersecting");
+	      (*testout) << "Intersecting: " << endl;
+	      for (k = 0; k <= 2; k++)
+		(*testout) << *tri1[k] << "   ";
+	      (*testout) << endl;
+	      for (k = 0; k <= 2; k++)
+		(*testout) << *tri2[k] << "   ";
+	      (*testout) << endl;
+	    }
+
+	}
+    }
+  return 0;
+}
+
+
+
+
+
+static double TriangleQualityInst (const Point3d & p1, const Point3d & p2,
+				   const Point3d & p3)
+{
+  // quality 0 (worst) .. 1 (optimal)
+
+  Vec3d v1, v2, v3;
+  double s1, s2, s3;
+  double an1, an2, an3;
+
+  v1 = p2 - p1;
+  v2 = p3 - p1;
+  v3 = p3 - p2;
+
+  an1 = Angle (v1, v2);
+  v1 *= -1;
+  an2 = Angle (v1, v3);
+  an3 = Angle (v2, v3);
+
+  s1 = sin (an1/2);
+  s2 = sin (an2/2);
+  s3 = sin (an3/2);
+
+  return 8 * s1 * s2 * s3;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+void MeshQuality2d (const Mesh & mesh)
+{
+  int ncl = 20, cl;
+  ARRAY<INDEX> incl(ncl);
+  INDEX i;
+  SurfaceElementIndex sei;
+  double qual;
+
+  incl = 0;
+
+  for (sei = 0; sei < mesh.GetNSE(); sei++)
+    {
+      qual = TriangleQualityInst (mesh[mesh[sei][0]],
+				  mesh[mesh[sei][1]],
+				  mesh[mesh[sei][2]]);
+
+      cl = int ( (ncl-1e-3) * qual ) + 1;
+      incl.Elem(cl)++;
+    }
+
+
+  (*testout) << endl << endl;
+
+  (*testout) << "Points:           " << mesh.GetNP() << endl;
+  (*testout) << "Surface Elements: " << mesh.GetNSE() << endl;
+
+  (*testout) << endl;
+  (*testout) << "Elements in qualityclasses:" << endl;
+  (*testout).precision(2);
+  for (i = 1; i <= ncl; i++)
+    {
+      (*testout) << setw(4) << double (i-1)/ncl << " - "
+		 << setw(4) << double (i) / ncl << ": "
+		 << incl.Get(i) << endl;
+    }
+}
+
+
+static double TetElementQuality (const Point3d & p1, const Point3d & p2,
+				 const Point3d & p3, const Point3d & p4)
+{
+  double vol, l, l4, l5, l6;
+
+
+  Vec3d v1 = p2 - p1;
+  Vec3d v2 = p3 - p1;
+  Vec3d v3 = p4 - p1;
+
+  vol = fabs ((Cross (v1, v2) * v3)) / 6;
+  l4 = Dist (p2, p3);
+  l5 = Dist (p2, p4);
+  l6 = Dist (p3, p4);
+
+  l = v1.Length() + v2.Length() + v3.Length() + l4 + l5 + l6;
+
+  if (vol <= 1e-8 * l * l * l) return 1e-10;
+
+  return vol/(l*l*l) * 1832.82;    // 6^4 * sqrt(2)
+}
+
+
+
+
+
+double teterrpow = 2;
+
+
+double CalcTetBadnessNew (const Point3d & p1, const Point3d & p2,
+			  const Point3d & p3, const Point3d & p4, double h)
+{
+  double vol, l, ll, lll, ll1, ll2, ll3, ll4, ll5, ll6;
+  double err;
+
+  Vec3d v1 (p1, p2);
+  Vec3d v2 (p1, p3);
+  Vec3d v3 (p1, p4);
+
+  vol = Determinant (v1, v2, v3) / 6;
+
+  ll1 = v1.Length2();
+  ll2 = v2.Length2();
+  ll3 = v3.Length2();
+  ll4 = Dist2 (p2, p3);
+  ll5 = Dist2 (p2, p4);
+  ll6 = Dist2 (p3, p4);
+
+  ll = ll1 + ll2 + ll3 + ll4 + ll5 + ll6;
+  l = sqrt (ll);
+  lll = l * ll;
+
+  if (vol <= 1e-24 * lll)
+    return 1e24;
+
+  err = (lll) / (1832.82 * vol);    // 6^4 * sqrt(2)
+
+  if (h > 0)
+    err += ll / (h * h) + 
+      h * h * ( 1 / ll1 + 1 / ll2 + 1 / ll3 + 
+		1 / ll4 + 1 / ll5 + 1 / ll6 ) - 12;
+
+  return pow (err, teterrpow);
+}
+
+
+
+
+
+double CalcTetBadness (const Point3d & p1, const Point3d & p2,
+		       const Point3d & p3, const Point3d & p4, double h)
+{
+  double vol, l;
+  double err;
+
+
+  Vec3d v1 (p1, p2);
+  Vec3d v2 (p1, p3);
+  Vec3d v3 (p1, p4);
+
+  vol = -Determinant (v1, v2, v3) / 6;
+
+  double l1 = v1.Length();
+  double l2 = v2.Length();
+  double l3 = v3.Length();
+  double l4 = Dist (p2, p3);
+  double l5 = Dist (p2, p4);
+  double l6 = Dist (p3, p4);
+
+  l = l1 + l2 + l3 + l4 + l5 + l6;
+
+  if (vol <= 1e-24 * l * l * l)
+    { 
+      return 1e24;
+    }
+
+  err = (l*l*l) / (1832.82 * vol);    // 6^4 * sqrt(2)
+  
+  if (h > 0)
+    err += l / h + 
+      h * (1 / l1 + 1/l2 + 1/l3 + 1/l4 + 1/l5 + 1/l6) - 12;
+
+  return pow (err, teterrpow);
+}
+
+
+  
+double CalcTetBadnessGrad (const Point3d & p1, const Point3d & p2,
+			   const Point3d & p3, const Point3d & p4, double h,
+			   int pi, Vec3d & grad)
+{
+  double vol, l;
+  double err;
+
+  const Point3d *pp1, *pp2, *pp3, *pp4;
+
+  pp1 = &p1;
+  pp2 = &p2;
+  pp3 = &p3;
+  pp4 = &p4;
+  
+  switch (pi)
+    {
+    case 2:
+      {
+	Swap (pp1, pp2);
+	Swap (pp3, pp4);
+	break;
+      }
+    case 3:
+      {
+	Swap (pp1, pp3);
+	Swap (pp2, pp4);
+	break;
+      }
+    case 4:
+      {
+	Swap (pp1, pp4);
+	Swap (pp3, pp2);
+	break;
+      }
+    }
+  
+
+  Vec3d v1 (*pp1, *pp2);
+  Vec3d v2 (*pp1, *pp3);
+  Vec3d v3 (*pp1, *pp4);
+
+  Vec3d v4 (*pp2, *pp3);
+  Vec3d v5 (*pp2, *pp4);
+  Vec3d v6 (*pp3, *pp4);
+
+  /*
+  Vec3d n;
+  Cross (v1, v2, n);
+  vol = - (n * v3) / 6;
+  */
+
+  vol = -Determinant (v1, v2, v3) / 6;  
+
+  Vec3d gradvol;
+  Cross (v5, v4, gradvol);
+  gradvol *= (-1.0/6.0);
+
+
+  double l1 = v1.Length();
+  double l2 = v2.Length();
+  double l3 = v3.Length();
+  double l4 = v4.Length();
+  double l5 = v5.Length();
+  double l6 = v6.Length();
+
+  l = l1 + l2 + l3 +l4 + l5 + l6;
+
+  Vec3d gradl1 (*pp2, *pp1);
+  Vec3d gradl2 (*pp3, *pp1);
+  Vec3d gradl3 (*pp4, *pp1);
+  gradl1 /= l1;
+  gradl2 /= l2;
+  gradl3 /= l3;
+
+  Vec3d gradl (gradl1);
+  gradl += gradl2;
+  gradl += gradl3;
+
+
+  if (vol <= 1e-24 * l * l * l)
+    { 
+      grad = Vec3d (0, 0, 0);
+      return 1e24;
+    }
+
+
+  double c1 = 1.0 / 1832.82;      // 6^4 * sqrt(2)
+  err = c1 * (l*l*l) / vol; 
+
+
+  gradl *= (c1 * 3 * l * l / vol);
+  Vec3d graderr(gradl);
+  gradvol *= ( -c1 * l * l * l / (vol * vol) );
+  graderr+= gradvol;
+  
+  if (h > 0)
+    {
+      err += l / h + 
+	h * ( 1 / l1 + 1 / l2 + 1 / l3 + 
+	      1 / l4 + 1 / l5 + 1 / l6 ) - 12;
+
+      graderr += (1/h - h/(l1*l1)) * gradl1;
+      graderr += (1/h - h/(l2*l2)) * gradl2;
+      graderr += (1/h - h/(l3*l3)) * gradl3;
+      cout << "?";
+    }
+
+  double errpow = pow (err, teterrpow);
+  grad = (teterrpow * errpow / err) * graderr;
+  
+  return errpow;
+}
+  
+
+
+
+
+  
+/*
+double CalcVolume (const ARRAY<Point3d> & points,
+        const Element & el)
+  {
+  Vec3d v1 = points.Get(el.PNum(2)) - 
+             points.Get(el.PNum(1));
+  Vec3d v2 = points.Get(el.PNum(3)) - 
+             points.Get(el.PNum(1));
+  Vec3d v3 = points.Get(el.PNum(4)) - 
+             points.Get(el.PNum(1)); 
+         
+  return -(Cross (v1, v2) * v3) / 6;	 
+  }  
+  */
+
+double CalcVolume (const ARRAY<Point3d> & points, 
+		   const ARRAY<Element> & elements)
+{
+  double vol;
+  Vec3d v1, v2, v3;
+  
+  vol = 0;
+  for (int i = 0; i < elements.Size(); i++)
+    {
+      v1 = points.Get(elements[i][1]) - points.Get(elements[i][0]);
+      v2 = points.Get(elements[i][2]) - points.Get(elements[i][0]);
+      v3 = points.Get(elements[i][3]) - points.Get(elements[i][0]);
+      vol -= (Cross (v1, v2) * v3) / 6;	 
+    }
+  return vol;
+}
+
+  
+  
+
+void MeshQuality3d (const Mesh & mesh, ARRAY<int> * inclass)
+{ 
+  int ncl = 20;
+  signed int cl;
+  ARRAY<INDEX> incl(ncl);
+  INDEX i;
+  double qual;
+  double sum = 0;
+  int nontet  = 0;
+
+  for (i = 1; i <= incl.Size(); i++)
+    incl.Elem(i) = 0;
+
+  for (ElementIndex ei = 0; ei < mesh.GetNE(); ei++)
+    {
+      if (mesh[ei].GetType() != TET)
+	{
+	  nontet++;
+	  continue;
+	}
+
+      qual = TetElementQuality (mesh.Point(mesh[ei][0]),
+				mesh.Point(mesh[ei][1]),
+				mesh.Point(mesh[ei][2]),
+				mesh.Point(mesh[ei][3]));
+
+      if (qual > 1) qual = 1;
+      cl = int (ncl * qual ) + 1;
+     
+      if (cl < 1) cl = 1; 
+      if (cl > ncl) cl = ncl;
+
+      incl.Elem(cl)++;
+      if (inclass) (*inclass)[ei] = cl;
+      sum += 1/qual;
+    }
+
+  (*testout) << endl << endl;
+  (*testout) << "Points:           " << mesh.GetNP() << endl;
+  (*testout) << "Volume Elements:  " << mesh.GetNE() << endl;
+  if (nontet)
+    (*testout) << nontet << " non tetrahedral elements" << endl;
+  (*testout) << endl;
+
+  (*testout) << "Volume elements in qualityclasses:" << endl;
+  (*testout).precision(2);
+  for (i = 1; i <= ncl; i++)
+    {
+      (*testout) << setw(4) << double (i-1)/ncl << " - "
+		 << setw(4) << double (i) / ncl << ": "
+		 << incl.Get(i) << endl;
+    }
+  (*testout) << "total error: " << sum << endl;
+}
+
+
+void SaveEdges (const Mesh & mesh, const char * geomfile, double h, char * filename)
+{
+  ofstream of (filename);
+  int i;
+  const Segment * seg;
+  
+  of << "edges" << endl;
+  of << geomfile << endl;
+  of << h << endl;
+
+  of << mesh.GetNP() << endl;
+  for (i = 1; i <= mesh.GetNP(); i++)
+    of << mesh.Point(i).X() << " "
+       << mesh.Point(i).Y() << " "
+       << mesh.Point(i).Z() << "\n";
+    
+  of << 2 * mesh.GetNSeg() << endl;
+  for (i = 1; i <= mesh.GetNSeg(); i++)
+    {
+      seg = &mesh.LineSegment(i);
+
+      of << seg->p2 << " " << seg->p1 << " " << seg->si << "\n";
+    }
+   
+}
+
+
+void SaveSurfaceMesh (const Mesh & mesh,
+		      double h,
+		      char * filename)
+
+{
+  INDEX i;
+
+  ofstream outfile(filename);
+
+  outfile << "surfacemesh" << endl;
+  outfile << h << endl;
+
+  outfile << mesh.GetNP() << endl;
+  for (i = 1; i <= mesh.GetNP(); i++)
+    outfile << mesh.Point(i).X() << " "
+            << mesh.Point(i).Y() << " "
+            << mesh.Point(i).Z() << endl;
+
+  
+
+  outfile << mesh.GetNSE() << endl;
+  for (i = 1; i <= mesh.GetNSE(); i++)
+    {
+      const Element2d & el = mesh.SurfaceElement(i);
+
+      if (mesh.GetFaceDescriptor(el.GetIndex()).DomainOut() == 0)
+	outfile << mesh.SurfaceElement(i).PNum(1) << " "
+		<< mesh.SurfaceElement(i).PNum(2) << " "
+		<< mesh.SurfaceElement(i).PNum(3) << endl;
+      if (mesh.GetFaceDescriptor(el.GetIndex()).DomainIn() == 0)
+	outfile << mesh.SurfaceElement(i).PNum(1) << " "
+		<< mesh.SurfaceElement(i).PNum(3) << " "
+		<< mesh.SurfaceElement(i).PNum(2) << endl;
+    }
+}
+
+
+#ifdef OLD
+void Save2DMesh (
+		 const Mesh & mesh2d,
+		 const ARRAY<SplineSegment *> * splines,
+		 ostream & outfile)
+
+{
+  int i, j;
+  outfile.precision (6);
+  
+  outfile << "areamesh2" << endl;
+
+
+  outfile << endl;
+  outfile << mesh2d.GetNSeg() << endl;
+  for (i = 1; i <= mesh2d.GetNSeg(); i++)
+    outfile << mesh2d.LineSegment(i).si << "        "
+	    << mesh2d.LineSegment(i).p1 << " "
+	    << mesh2d.LineSegment(i).p2 << "  " << endl;
+  
+
+  outfile << mesh2d.GetNSE() << endl;
+  for (i = 1; i <= mesh2d.GetNSE(); i++)
+    {
+      outfile << mesh2d.SurfaceElement(i).GetIndex() << "         ";
+      outfile << mesh2d.SurfaceElement(i).GetNP() << " ";
+      for (j = 1; j <= mesh2d.SurfaceElement(i).GetNP(); j++)
+	outfile << mesh2d.SurfaceElement(i).PNum(j) << " ";
+      outfile << endl;
+    }
+
+  outfile << mesh2d.GetNP() << endl;
+  for (i = 1; i <= mesh2d.GetNP(); i++)
+    outfile << mesh2d.Point(i).X() << " "
+            << mesh2d.Point(i).Y() << endl;
+
+  if (splines)
+    {
+      outfile << splines->Size() << endl;
+      for (i = 1; i <= splines->Size(); i++)
+	splines->Get(i) -> PrintCoeff (outfile);
+    }
+  else
+    outfile << "0" << endl;
+}
+#endif
+
+
+
+
+
+
+
+
+void SaveVolumeMesh (const Mesh & mesh, 
+		     const CSGeometry & geometry,
+		     char * filename)
+{
+  INDEX i;
+
+  ofstream outfile(filename);
+  outfile << "volumemesh" << endl;
+
+  outfile << mesh.GetNSE() << endl;
+  for (i = 1; i <= mesh.GetNSE(); i++)
+    {
+      if (mesh.SurfaceElement(i).GetIndex())
+	outfile << mesh.GetFaceDescriptor(mesh.SurfaceElement(i).GetIndex ()).SurfNr()
+		<< "\t";
+      else
+	outfile << "0" << "\t";
+      outfile << mesh.SurfaceElement(i)[0] << " "
+	      << mesh.SurfaceElement(i)[1] << " "
+	      << mesh.SurfaceElement(i)[2] << endl;
+    }
+  outfile << mesh.GetNE() << endl;
+  for (ElementIndex ei = 0; ei < mesh.GetNE(); ei++)
+    outfile << mesh[ei].GetIndex() << "\t"
+	    << mesh[ei][0] << " " << mesh[ei][1] << " "
+            << mesh[ei][2] << " " << mesh[ei][3] << endl;
+
+  outfile << mesh.GetNP() << endl;
+  for (i = 1; i <= mesh.GetNP(); i++)
+    outfile << mesh.Point(i).X() << " "
+            << mesh.Point(i).Y() << " "
+            << mesh.Point(i).Z() << endl;
+
+#ifdef SOLIDGEOM
+  outfile << geometry.GetNSurf() << endl;
+  for (i = 1; i <= geometry.GetNSurf(); i++)
+    geometry.GetSurface(i) -> Print (outfile);
+#endif
+}
+
+
+
+
+int CheckCode ()
+{
+  return 1;
+
+  /*
+    char st[100];
+    ifstream ist("pw");
+
+    if (!ist.good()) return 0;
+    ist >> st;
+    if (strcmp (st, "JKULinz") == 0) return 1;
+    return 0;
+    */
+}
+
+
+
+/* ******************** CheckMesh ******************************* */
+
+/// Checks, whether mesh contains a valid 3d mesh
+int CheckMesh3D (const Mesh & mesh)
+{
+  INDEX_3_HASHTABLE<int> faceused(mesh.GetNE()/3);
+  INDEX i;
+  int j, k, l;
+  INDEX_3 i3;
+  int ok = 1;
+  ElementIndex ei;
+
+  for (i = 1; i <= mesh.GetNSE(); i++)
+    {
+      const Element2d & el = mesh.SurfaceElement(i);
+      
+      if (mesh.GetFaceDescriptor(el.GetIndex()).DomainIn() == 0 ||
+	  mesh.GetFaceDescriptor(el.GetIndex()).DomainOut() == 0)
+	{
+	  for (j = 1; j <= 3; j++)
+	    i3.I(j) = el.PNum(j);
+	  
+	  i3.Sort();
+	  faceused.Set (i3, 1);
+	}
+    }
+  
+  for (ei = 0; ei < mesh.GetNE(); ei++)
+    {
+      const Element & el = mesh[ei];
+
+      for (j = 1; j <= 4; j++)
+	{
+	  l = 0;
+	  for (k = 1; k <= 4; k++)
+	    {
+	      if (j != k)
+		{
+		  l++;
+		  i3.I(l) = el.PNum(k);
+		}
+	    }
+
+	  i3.Sort();
+	  if (faceused.Used(i3))
+	    faceused.Set(i3, faceused.Get(i3)+1);
+	  else
+	    faceused.Set (i3, 1);
+	}
+    }
+
+
+  for (i = 1; i <= mesh.GetNSE(); i++)
+    {
+      const Element2d & el = mesh.SurfaceElement(i);
+
+      for (j = 1; j <= 3; j++)
+	i3.I(j) = el.PNum(j);
+      
+      i3.Sort();
+      k = faceused.Get (i3);
+      if (k != 2)
+	{
+	  ok = 0;
+	  (*testout) << "face " << i << " with points " 
+		     << i3.I1() << "-" << i3.I2() << "-" << i3.I3() 
+		     << " has " << k << " elements" << endl;
+	}
+    }
+  
+  for (ei = 0; ei < mesh.GetNE(); ei++)
+    {
+      const Element & el = mesh[ei];
+
+      for (j = 1; j <= 4; j++)
+	{
+	  l = 0;
+	  for (k = 1; k <= 4; k++)
+	    {
+	      if (j != k)
+		{
+		  l++;
+		  i3.I(l) = el.PNum(k);
+		}
+	    }
+
+	  i3.Sort();
+	  k = faceused.Get(i3);
+	  if (k != 2)
+	    {
+	      ok = 0;
+	      (*testout) << "element " << ei << " with face " 
+			 << i3.I1() << "-" << i3.I2() << "-"
+			 << i3.I3() 
+			 << " has " << k << " elements" << endl;
+	    }
+	}
+    }
+
+
+
+
+
+  /*
+    for (i = 1; i <= faceused.GetNBags(); i++)
+    for (j = 1; j <= faceused.GetBagSize(i); j++)
+    {
+    faceused.GetData(i, j, i3, k);
+    if (k != 2)
+    {
+    (*testout) << "Face: " << i3.I1() << "-" 
+    << i3.I2() << "-" << i3.I3() << " has " 
+    << k << " Faces " << endl;
+    cerr << "Face Error" << endl;
+    ok = 0;
+    }
+    }
+    */
+
+
+  if (!ok)
+    {
+      (*testout) << "surfelements: " << endl;
+      for (i = 1; i <= mesh.GetNSE(); i++)
+	{
+	  const Element2d & el = mesh.SurfaceElement(i);
+	  (*testout) << setw(5) << i << ":" 
+		     << setw(6) << el.GetIndex() 
+		     << setw(6) << el.PNum(1) 
+		     << setw(4) << el.PNum(2) 
+		     << setw(4) << el.PNum(3)  << endl;
+	}
+      (*testout) << "volelements: " << endl;
+      for (ElementIndex ei = 0; ei < mesh.GetNE(); ei++)
+	{
+	  const Element & el = mesh[ei];
+	  (*testout) << setw(5) << i << ":" 
+		     << setw(6) << el.GetIndex() 
+		     << setw(6) << el[0] << setw(4) << el[1]
+		     << setw(4) << el[2] << setw(4) << el[3] << endl;
+	}
+    }
+
+
+  return ok;
+}
+
+
+
+void RemoveProblem (Mesh & mesh)
+{
+  int i, j, k;
+  
+  mesh.FindOpenElements();
+  int np = mesh.GetNP();
+
+  BitArrayChar<PointIndex::BASE> ppoints(np);
+  
+  int ndom = mesh.GetNDomains();
+
+  PrintMessage (3, "Elements before Remove: ", mesh.GetNE());
+  for (k = 1; k <= ndom; k++)
+    {
+      ppoints.Clear();
+      
+      for (i = 1; i <= mesh.GetNOpenElements(); i++)
+	{
+	  const Element2d & sel = mesh.OpenElement(i);
+	  if (sel.GetIndex() == k)
+	    {
+	      for (j = 1; j <= sel.GetNP(); j++)
+		ppoints.Set (sel.PNum(j));
+	    }
+	}
+
+      for (ElementIndex ei = 0; ei < mesh.GetNE(); ei++)
+	{
+	  const Element & el = mesh[ei];
+	  if (el.GetIndex() == k)
+	    {
+	      int todel = 0;
+	      for (j = 0; j < el.GetNP(); j++)
+		if (ppoints.Test (el[j]))
+		  todel = 1;
+	      
+	      if (el.GetNP() != 4)
+		todel = 0;
+	      
+	      if (todel)
+		{
+		  mesh[ei].Delete();
+		  // ei--;
+		}
+	    }
+	}
+    }
+  
+  mesh.Compress();
+  PrintMessage (3, "Elements after Remove: ", mesh.GetNE());
+}
+
+
+}
diff --git a/Netgen/libsrc/meshing/meshtool.hpp b/Netgen/libsrc/meshing/meshtool.hpp
new file mode 100644
index 0000000000..397528876f
--- /dev/null
+++ b/Netgen/libsrc/meshing/meshtool.hpp
@@ -0,0 +1,82 @@
+#ifndef FILE_MESHTOOL
+#define FILE_MESHTOOL
+
+
+///
+extern void MeshQuality2d (const Mesh & mesh);
+
+///
+extern void MeshQuality3d (const Mesh & mesh,
+			   ARRAY<int> * inclass = NULL);
+
+///
+extern void SaveEdges (const Mesh & mesh, 
+		       const char * geomfile, 
+		       double h, 
+		       char * filename);
+
+///
+extern void SaveSurfaceMesh (const Mesh & mesh,
+			     double h,
+			     char * filename);
+/*
+///
+extern void Save2DMesh (
+         const Mesh & mesh2d,
+	 const ARRAY<class SplineSegment*> * splines,
+         ostream & outfile);
+*/
+
+class Surface;
+///
+extern void SaveVolumeMesh (
+         const ARRAY<Point3d> & points,
+         const ARRAY<Element> & elements,
+         const ARRAY<Element> & volelements,
+         const ARRAY<Surface*> & surfaces,
+         char * filename);
+
+///
+void SaveVolumeMesh (const Mesh & mesh, 
+		     const class CSGeometry & geometry,
+		     char * filename);
+
+///
+extern int CheckCode ();
+
+///
+extern double CalcTetBadness (const Point3d & p1, 
+			      const Point3d & p2,
+			      const Point3d & p3, 
+			      const Point3d & p4, 
+			      double h);
+///
+extern double CalcTetBadnessGrad (const Point3d & p1, 
+				const Point3d & p2,
+				const Point3d & p3, 
+				const Point3d & p4, 
+				double h, int pi,
+				Vec3d & grad);
+
+
+/** Calculates volume of an element.
+  The volume of the tetrahedron el is computed
+ */
+// extern double CalcVolume (const ARRAY<Point3d> & points,
+//        const Element & el);  
+
+/** The total volume of all elements is computed.
+  This function calculates the volume of the mesh */
+extern double CalcVolume (const ARRAY<Point3d> & points, 
+	const ARRAY<Element> & elements);
+
+///
+extern int CheckSurfaceMesh (const Mesh & mesh);
+
+///
+extern int CheckSurfaceMesh2 (const Mesh & mesh);
+///
+extern int CheckMesh3D (const Mesh & mesh);
+///
+extern void RemoveProblem (Mesh & mesh);
+#endif
diff --git a/Netgen/libsrc/meshing/meshtype.cpp b/Netgen/libsrc/meshing/meshtype.cpp
new file mode 100644
index 0000000000..7a8bcb513c
--- /dev/null
+++ b/Netgen/libsrc/meshing/meshtype.cpp
@@ -0,0 +1,1880 @@
+#include <mystdlib.h>
+
+#include "meshing.hpp"
+
+
+namespace netgen
+{
+
+  MultiPointGeomInfo :: MultiPointGeomInfo()
+  {
+    cnt = 0;
+  }
+
+  int MultiPointGeomInfo :: 
+  AddPointGeomInfo (const PointGeomInfo & gi)
+  {
+    int k;
+
+    for (k = 0; k < cnt; k++)
+      if (mgi[k].trignum == gi.trignum)
+	return 0;
+  
+    if (cnt < MULTIPOINTGEOMINFO_MAX)
+      {
+	mgi[cnt] = gi;
+	cnt++;
+	return 0;
+      }
+    // #ifdef DEVELOP
+    cout << "Please Increase MPGI - Size" << endl;
+    // #endif
+    return 1;
+  }
+
+
+  void MultiPointGeomInfo :: 
+  Init ()
+  {
+    cnt = 0;
+  }
+
+  void MultiPointGeomInfo :: 
+  DeleteAll ()
+  {
+    cnt = 0;
+  }
+
+
+
+
+  Segment :: Segment() 
+  {
+    p1 = p2 = 0; 
+    geominfo[0].trignum=0; 
+    geominfo[1].trignum=0; 
+    surfnr1 = surfnr2 = 0;
+    edgenr = 0;
+
+    singedge = 0;
+
+    epgeominfo[0].edgenr = 1;
+    epgeominfo[0].dist = 0;
+    epgeominfo[1].edgenr = 1;
+    epgeominfo[1].dist = 0;
+
+    pmid = 0;
+  }
+
+  ostream & operator<<(ostream  & s, const Segment & seg)
+  {
+    s << seg.p1 << "(gi=" << seg.geominfo[0].trignum << ") - "
+      << seg.p2 << "(gi=" << seg.geominfo[1].trignum << ")";
+    return s;
+  }
+
+  Element2d :: Element2d (int anp)
+  { 
+    int i;
+    for (i = 0; i < 6; i++)
+      {
+	pnum[i] = 0;
+	geominfo[i].trignum = 0;
+      }
+    np = anp;
+    index = 0;
+    badel = 0;
+    deleted = 0;
+    switch (np)
+      {
+      case 3: typ = TRIG; break;
+      case 4: typ = QUAD; break;
+      case 6: typ = TRIG6; break;
+      }
+    order = 1;
+  } 
+
+
+  Element2d :: Element2d (ELEMENT_TYPE atyp)
+  { 
+    int i;
+    for (i = 0; i < 6; i++)
+      {
+	pnum[i] = 0;
+	geominfo[i].trignum = 0;
+      }
+
+    SetType (atyp);
+
+    index = 0;
+    badel = 0;
+    deleted = 0;
+    order = 1;
+  } 
+
+
+
+
+  Element2d :: Element2d (int pi1, int pi2, int pi3)
+{
+  pnum[0] = pi1;
+  pnum[1] = pi2;
+  pnum[2] = pi3;
+  np = 3;
+  typ = TRIG;
+  pnum[3] = 0;
+  pnum[4] = 0;
+  pnum[5] = 0;
+  
+  for (int i = 0; i < 6; i++)
+    geominfo[i].trignum = 0;
+  index = 0;
+  badel = 0;
+  refflag = 1;
+  deleted = 0;
+  order = 1;
+}
+
+Element2d :: Element2d (int pi1, int pi2, int pi3, int pi4)
+{
+  pnum[0] = pi1;
+  pnum[1] = pi2;
+  pnum[2] = pi3;
+  pnum[3] = pi4;
+  np = 4;
+  typ = QUAD;
+
+  pnum[4] = 0;
+  pnum[5] = 0;
+  
+  for (int i = 0; i < 6; i++)
+    geominfo[i].trignum = 0;
+  index = 0;
+  badel = 0;
+  refflag = 1;
+  deleted = 0;
+  order = 1;
+}
+
+
+void Element2d :: SetType (ELEMENT_TYPE atyp)
+{
+  typ = atyp;
+  switch (typ)
+    {
+    case TRIG: np = 3; break;
+    case QUAD: np = 4; break;
+    case TRIG6: np = 6; break;
+    case QUAD6: np = 6; break;
+    default:
+      PrintSysError ("Element2d::SetType, illegal type ", typ);
+    }
+}
+
+
+
+void Element2d :: GetBox (const T_POINTS & points, Box3d & box) const
+{
+  box.SetPoint (points.Get(pnum[0]));
+  for (unsigned i = 1; i < np; i++)
+    box.AddPoint (points.Get(pnum[i]));
+}
+
+void Element2d :: Invert2()
+{
+  switch (typ)
+    {
+    case TRIG:
+      {
+	Swap (pnum[1], pnum[2]);
+	break;
+      }
+    case QUAD:
+      {
+	Swap (pnum[0], pnum[3]);
+	Swap (pnum[1], pnum[2]);
+	break;
+      }
+    default:
+      {
+	cerr << "Element2d::Invert2, illegal element type " << int(typ) << endl;
+      }
+    }
+}
+
+int Element2d::HasFace(const Element2d& el) const
+{
+  //nur für tets!!! hannes
+  for (int i = 1; i <= 3; i++)
+    {
+      if (PNumMod(i)   == el[0] && 
+	  PNumMod(i+1) == el[1] && 
+	  PNumMod(i+2) == el[2])
+	{
+	  return 1;
+	}
+    }
+  return 0;
+}
+
+void Element2d :: NormalizeNumbering2 ()
+{
+  if (GetNP() == 3)
+    {
+      PointIndex pi1;
+      if (PNum(1) < PNum(2) && PNum(1) < PNum(3))
+	return;
+      else
+	{
+	  if (PNum(2) < PNum(3))
+	    {
+	      pi1 = PNum(2);
+	      PNum(2) = PNum(3);
+	      PNum(3) = PNum(1);
+	      PNum(1) = pi1;
+	    }
+	  else
+	    {
+	      pi1 = PNum(3);
+	      PNum(3) = PNum(2);
+	      PNum(2) = PNum(1);
+	      PNum(1) = pi1;
+	    }
+	}
+    }
+  else
+    {
+      int i;
+      int mini = 1;
+      for (i = 2; i <= GetNP(); i++)
+	if (PNum(i) < PNum(mini)) mini = i;
+      
+      Element2d hel = (*this);
+      for (i = 1; i <= GetNP(); i++)
+	PNum(i) = hel.PNumMod (i+mini-1);
+    }
+}
+
+
+
+
+ARRAY<IntegrationPointData*> ipdtrig;
+ARRAY<IntegrationPointData*> ipdquad;
+
+
+int Element2d :: GetNIP () const
+{
+  int nip;
+  switch (np)
+    {
+    case 3: nip = 1; break;
+    case 4: nip = 4; break;
+    default: nip = 0; break;
+    }
+  return nip;
+}
+
+void Element2d :: 
+GetIntegrationPoint (int ip, Point2d & p, double & weight) const
+{
+  static double eltriqp[1][3] =
+  {
+    { 1.0/3.0, 1.0/3.0, 0.5 }
+  };
+
+  static double elquadqp[4][3] =
+  { 
+    { 0, 0, 0.25 },
+    { 0, 1, 0.25 },
+    { 1, 0, 0.25 },
+    { 1, 1, 0.25 }
+  };
+  
+  double * pp = 0;
+  switch (typ)
+    {
+    case TRIG: pp = &eltriqp[0][0]; break;
+    case QUAD: pp = &elquadqp[ip-1][0]; break;
+    default:
+      PrintSysError ("Element2d::GetIntegrationPoint, illegal type ", typ);
+    }
+
+  p.X() = pp[0];
+  p.Y() = pp[1];
+  weight = pp[2];
+}
+
+void Element2d :: 
+GetTransformation (int ip, const ARRAY<Point2d> & points,
+		   DenseMatrix & trans) const
+{
+  int np = GetNP();
+  static DenseMatrix pmat(2, np), dshape(2, np);
+  pmat.SetSize (2, np);
+  dshape.SetSize (2, np);
+
+  Point2d p;
+  double w;
+
+  GetPointMatrix (points, pmat);
+  GetIntegrationPoint (ip, p, w);
+  GetDShape (p, dshape);
+  
+  CalcABt (pmat, dshape, trans);
+
+  /*
+  (*testout) << "p = " << p  << endl
+	     << "pmat = " << pmat << endl
+	     << "dshape = " << dshape << endl
+	     << "tans = " << trans << endl;
+  */
+}
+
+void Element2d :: 
+GetTransformation (int ip, class DenseMatrix & pmat,
+		   class DenseMatrix & trans) const
+{
+  int np = GetNP();
+
+  if (pmat.Width() != np || pmat.Height() != 2)
+    {
+      (*testout) << "GetTransofrmation: pmat doesn't fit" << endl;
+      return;
+    }
+
+  ComputeIntegrationPointData ();
+  DenseMatrix * dshapep = 0;
+  switch (typ)
+    {
+    case TRIG: dshapep = &ipdtrig.Get(ip)->dshape; break;
+    case QUAD: dshapep = &ipdquad.Get(ip)->dshape; break;
+    default:
+      PrintSysError ("Element2d::GetTransformation, illegal type ", typ);
+    }
+  
+  CalcABt (pmat, *dshapep, trans);
+}
+
+
+
+void Element2d :: GetShape (const Point2d & p, Vector & shape) const
+{
+  if (shape.Size() != GetNP())
+    {
+      cerr << "Element::GetShape: Length not fitting" << endl;
+      return;
+    }
+
+  switch (typ)
+    {
+    case TRIG:
+      shape.Elem(1) = 1 - p.X() - p.Y();
+      shape.Elem(2) = p.X();
+      shape.Elem(3) = p.Y();
+      break;
+    case QUAD:
+      shape.Elem(1) = (1-p.X()) * (1-p.Y());
+      shape.Elem(2) = p.X() * (1-p.Y());
+      shape.Elem(3) = p.X() * p.Y();
+      shape.Elem(4) = (1-p.X()) * p.Y();
+      break;
+    default:
+      PrintSysError ("Element2d::GetShape, illegal type ", typ);
+    }
+}
+
+void Element2d :: 
+GetDShape (const Point2d & p, DenseMatrix & dshape) const
+{
+#ifdef DEBUG
+  if (dshape.Height() != 2 || dshape.Width() != np)
+    {
+      PrintSysError ("Element::DShape: Sizes don't fit");
+      return;
+    }
+#endif
+
+  switch (typ)
+    {
+    case TRIG:
+      dshape.Elem(1, 1) = -1;
+      dshape.Elem(1, 2) = 1;
+      dshape.Elem(1, 3) = 0;
+      dshape.Elem(2, 1) = -1;
+      dshape.Elem(2, 2) = 0;
+      dshape.Elem(2, 3) = 1;
+      break;
+    case QUAD:
+      dshape.Elem(1, 1) = -(1-p.Y());
+      dshape.Elem(1, 2) = (1-p.Y());
+      dshape.Elem(1, 3) = p.Y();
+      dshape.Elem(1, 4) = -p.Y();
+      dshape.Elem(2, 1) = -(1-p.X());
+      dshape.Elem(2, 2) = -p.X();
+      dshape.Elem(2, 3) = p.X();
+      dshape.Elem(2, 4) = (1-p.X());
+      break;
+
+    default:
+      PrintSysError ("Element2d::GetDShape, illegal type ", typ);
+    }
+}
+
+
+void Element2d :: 
+GetPointMatrix (const ARRAY<Point2d> & points,
+		DenseMatrix & pmat) const
+{
+  int i;
+  int np = GetNP();
+  if (pmat.Width() != np || pmat.Height() != 2)
+    {
+      cerr << "Element::GetPointMatrix: sizes don't fit" << endl;
+      return;
+    }
+  
+  for (i = 1; i <= np; i++)
+    {
+      const Point2d & p = points.Get(PNum(i));
+      pmat.Elem(1, i) = p.X();
+      pmat.Elem(2, i) = p.Y();
+    }
+}
+
+
+
+
+
+double Element2d :: CalcJacobianBadness (const ARRAY<Point2d> & points) const
+{
+  int i, j;
+  int nip = GetNIP();
+  static DenseMatrix trans(2,2);
+  static DenseMatrix pmat;
+  
+  pmat.SetSize (2, GetNP());
+  GetPointMatrix (points, pmat);
+
+  double err = 0;
+  for (i = 1; i <= nip; i++)
+    {
+      GetTransformation (i, pmat, trans);
+
+      // Frobenius norm
+      double frob = 0;
+      for (j = 1; j <= 4; j++)
+	frob += sqr (trans.Get(j));
+      frob = sqrt (frob);
+      frob /= 2;
+
+      double det = trans.Det();
+
+      if (det <= 0)
+	err += 1e12;
+      else
+	err += frob * frob / det;
+    }
+
+  err /= nip;
+  return err;
+}
+
+
+double Element2d :: 
+CalcJacobianBadnessDirDeriv (const ARRAY<Point2d> & points,
+			     int pi, Vec2d & dir, double & dd) const
+{
+  int i, j, k, l;
+  int nip = GetNIP();
+  static DenseMatrix trans(2,2), dtrans(2,2), hmat(2,2);
+  static DenseMatrix pmat, vmat;
+  
+  pmat.SetSize (2, GetNP());
+  vmat.SetSize (2, GetNP());
+
+  GetPointMatrix (points, pmat);
+  
+  for (i = 1; i <= np; i++)
+    for (j = 1; j <= 2; j++)
+      vmat.Elem(j, i) = 0;
+  //  for (j = 1; j <= 2; j++)
+  vmat.Elem(1, pi) = dir.X();
+  vmat.Elem(2, pi) = dir.Y();
+
+
+
+  double err = 0;
+  dd = 0;
+
+  for (i = 1; i <= nip; i++)
+    {
+      GetTransformation (i, pmat, trans);
+      GetTransformation (i, vmat, dtrans);
+
+
+      // Frobenius norm
+      double frob = 0;
+      for (j = 1; j <= 4; j++)
+	frob += sqr (trans.Get(j));
+      frob = sqrt (frob);
+      
+      double dfrob = 0;
+      for (j = 1; j <= 4; j++)
+	dfrob += trans.Get(j) * dtrans.Get(j);
+      dfrob = dfrob / frob;
+      
+      frob /= 2;      
+      dfrob /= 2;
+
+      
+      double det = trans.Det();
+      double ddet = 0;
+      
+      for (j = 1; j <= 2; j++)
+	{
+	  hmat = trans;
+	  for (k = 1; k <= 2; k++)
+	    hmat.Elem(k, j) = dtrans.Get(k, j);
+	  ddet += hmat.Det();
+	}
+
+
+      if (det <= 0)
+	err += 1e12;
+      else
+	{
+	  err += frob * frob / det;
+	  dd += (2 * frob * dfrob * det - frob * frob * ddet) / (det * det);
+	}
+    }
+
+  err /= nip;
+  dd /= nip;
+  return err;
+}
+
+
+
+double Element2d :: 
+CalcJacobianBadness (const T_POINTS & points, const Vec3d & n) const
+{
+  int i, j;
+  int nip = GetNIP();
+  static DenseMatrix trans(2,2);
+  static DenseMatrix pmat;
+  
+  pmat.SetSize (2, GetNP());
+
+  Vec3d t1, t2;
+  n.GetNormal(t1);
+  Cross (n, t1, t2);
+
+  for (i = 1; i <= nip; i++)
+    {
+      const Point3d & p = points.Get(PNum(i));
+      pmat.Elem(1, i) = p.X() * t1.X() + p.Y() * t1.Y() + p.Z() * t1.Z();
+      pmat.Elem(2, i) = p.X() * t2.X() + p.Y() * t2.Y() + p.Z() * t2.Z();
+    }
+
+  double err = 0;
+  for (i = 1; i <= nip; i++)
+    {
+      GetTransformation (i, pmat, trans);
+
+      // Frobenius norm
+      double frob = 0;
+      for (j = 1; j <= 4; j++)
+	frob += sqr (trans.Get(j));
+      frob = sqrt (frob);
+      frob /= 2;
+
+      double det = trans.Det();
+      if (det <= 0)
+	err += 1e12;
+      else
+	err += frob * frob / det;
+    }
+
+  err /= nip;
+  return err;
+}
+
+
+
+void Element2d :: ComputeIntegrationPointData () const
+{
+  switch (np)
+    {
+    case 3: if (ipdtrig.Size()) return; break;
+    case 4: if (ipdquad.Size()) return; break;
+    }
+
+  int i;
+  for (i = 1; i <= GetNIP(); i++)
+    {
+      IntegrationPointData * ipd = new IntegrationPointData;
+      Point2d hp;
+      GetIntegrationPoint (i, hp, ipd->weight);
+      ipd->p.X() = hp.X();
+      ipd->p.Y() = hp.Y();
+      ipd->p.Z() = 0;
+
+      ipd->shape.SetSize(GetNP());
+      ipd->dshape.SetSize(2, GetNP());
+
+      GetShape (hp, ipd->shape);
+      GetDShape (hp, ipd->dshape);
+
+      switch (np)
+	{
+	case 3: ipdtrig.Append (ipd); break;
+	case 4: ipdquad.Append (ipd); break;
+	}
+    }
+}
+
+
+
+
+
+
+
+
+
+
+ostream & operator<<(ostream  & s, const Element2d & el)
+{
+  s << "np = " << el.GetNP();
+  for (int j = 1; j <= el.GetNP(); j++)
+    s << " " << el.PNum(j);
+  return s;
+}
+
+
+ostream & operator<<(ostream  & s, const Element & el)
+{
+  s << "np = " << el.GetNP();
+  for (int j = 0; j < el.GetNP(); j++)
+    s << " " << int(el[j]);
+  return s;
+}
+
+
+Element :: Element ()
+{
+  typ = TET;
+  np = 4;
+  for (int i = 0; i < ELEMENT_MAXPOINTS; i++)
+    pnum[i] = 0;
+  index = 0;
+  flags.marked = 1;
+  flags.badel = 0;
+  flags.reverse = 0;
+  flags.illegal = 0;
+  flags.illegal_valid = 0;
+  flags.refflag = 1;
+  flags.deleted = 0;
+  order = 1;
+}
+
+
+Element :: Element (int anp)
+{
+  np = anp;
+  int i;
+  for (i = 0; i < ELEMENT_MAXPOINTS; i++)
+    pnum[i] = 0;
+  index = 0;
+  flags.marked = 1;
+  flags.badel = 0;
+  flags.reverse = 0;
+  flags.illegal = 0;
+  flags.illegal_valid = 0;
+  flags.refflag = 1;
+  flags.deleted = 0;
+  switch (np)
+    {
+    case 4: typ = TET; break;
+    case 5: typ = PYRAMID; break;
+    case 6: typ = PRISM; break;
+    case 8: typ = HEX; break;
+    case 10: typ = TET10; break;
+    default: cerr << "Element::Element: unknown element with " << np << " points" << endl;
+    }
+  order = 1;
+}
+
+
+Element :: Element (ELEMENT_TYPE type)
+{
+  SetType (type);
+
+  int i;
+  for (i = 0; i < ELEMENT_MAXPOINTS; i++)
+    pnum[i] = 0;
+  index = 0;
+  flags.marked = 1;
+  flags.badel = 0;
+  flags.reverse = 0;
+  flags.illegal = 0;
+  flags.illegal_valid = 0;
+  flags.refflag = 1;
+  flags.deleted = 0;
+  order = 1;
+}
+
+
+
+
+
+Element & Element :: operator= (const Element & el2)
+{
+  int i;
+  typ = el2.typ;
+  np = el2.np;
+  for (i = 0; i < ELEMENT_MAXPOINTS; i++)
+    pnum[i] = el2.pnum[i];
+  index = el2.index;
+  flags = el2.flags;
+  order = el2.order;
+  return *this;
+}
+
+
+
+void Element :: SetNP (int anp)
+{
+  np = anp; 
+  switch (np)
+    {
+    case 4: typ = TET; break;
+    case 5: typ = PYRAMID; break;
+    case 6: typ = PRISM; break;
+    case 8: typ = HEX; break;
+    case 10: typ = TET10; break;
+      // 
+    default: break;
+      cerr << "Element::SetNP unknown element with " << np << " points" << endl;
+    }
+}
+
+
+
+void Element :: SetType (ELEMENT_TYPE atyp)
+{
+  typ = atyp;
+  switch (atyp)
+    {
+    case TET: np = 4; break;
+    case PYRAMID: np = 5; break;
+    case PRISM: np = 6; break;
+    case HEX: np = 8; break;
+    case TET10: np = 10; break;
+    case PRISM12: np = 12; break;
+    }
+}
+
+
+
+void Element :: Invert()
+{
+  switch (GetNP())
+    {
+    case 4:
+      {
+	Swap (PNum(3), PNum(4));
+	break;
+      }
+    case 5:
+      {
+	Swap (PNum(1), PNum(4));
+	Swap (PNum(2), PNum(3));
+	break;
+      }
+    case 6:
+      {
+	Swap (PNum(1), PNum(4));
+	Swap (PNum(2), PNum(5));
+	Swap (PNum(3), PNum(6));
+	break;
+      }
+    }
+}
+
+
+void Element :: Print (ostream & ost) const
+{
+  ost << np << " Points: ";
+  for (int i = 1; i <= np; i++)
+    ost << pnum[i-1] << " " << endl;
+}
+
+void Element :: GetBox (const T_POINTS & points, Box3d & box) const
+{
+  box.SetPoint (points.Get(PNum(1)));
+  box.AddPoint (points.Get(PNum(2)));
+  box.AddPoint (points.Get(PNum(3)));
+  box.AddPoint (points.Get(PNum(4)));
+}
+
+double Element :: Volume (const T_POINTS & points) const
+{
+  Vec3d v1 = points.Get(PNum(2)) - 
+    points.Get(PNum(1));
+  Vec3d v2 = points.Get(PNum(3)) - 
+    points.Get(PNum(1));
+  Vec3d v3 = points.Get(PNum(4)) - 
+    points.Get(PNum(1)); 
+         
+  return -(Cross (v1, v2) * v3) / 6;	 
+}  
+
+
+void Element :: GetFace2 (int i, Element2d & face) const
+{
+  static const int tetfaces[][5] = 
+  { { 3, 2, 3, 4, 0 },
+    { 3, 3, 1, 4, 0 },
+    { 3, 1, 2, 4, 0 },
+    { 3, 2, 1, 3, 0 } };
+
+  static const int pyramidfaces[][5] =
+  { { 4, 1, 4, 3, 2 },
+    { 3, 1, 2, 5, 0 },
+    { 3, 2, 3, 5, 0 },
+    { 3, 3, 4, 5, 0 },
+    { 3, 4, 1, 5, 0 } };
+
+  static const int prismfaces[][5] =
+  {
+    { 3, 1, 3, 2, 0 },
+    { 3, 4, 5, 6, 0 },
+    { 4, 1, 2, 5, 4 },
+    { 4, 2, 3, 6, 5 },
+    { 4, 3, 1, 4, 6 }
+  };
+
+  switch (np)
+    {
+    case 4: // tet
+    case 10: // tet
+      {
+	face.SetType(TRIG);
+	for (int j = 1; j <= 3; j++)
+	  face.PNum(j) = PNum(tetfaces[i-1][j]);
+	break;
+      }
+    case 5: // pyramid
+      {
+	// face.SetNP(pyramidfaces[i-1][0]);
+	face.SetType ( (i == 1) ? QUAD : TRIG);
+	for (int j = 1; j <= face.GetNP(); j++)
+	  face.PNum(j) = PNum(pyramidfaces[i-1][j]);
+	break;
+      }
+    case 6: // prism
+      {
+	//	face.SetNP(prismfaces[i-1][0]);
+	face.SetType ( (i >= 3) ? QUAD : TRIG);
+	for (int j = 1; j <= face.GetNP(); j++)
+	  face.PNum(j) = PNum(prismfaces[i-1][j]);
+	break;
+      }
+    }
+}
+
+
+
+void Element :: GetTets (ARRAY<Element> & locels) const
+{
+  GetTetsLocal (locels);
+  int i, j;
+  for (i = 1; i <= locels.Size(); i++)
+    for (j = 1; j <= 4; j++)
+      locels.Elem(i).PNum(j) = PNum ( locels.Elem(i).PNum(j) );
+}
+
+void Element :: GetTetsLocal (ARRAY<Element> & locels) const
+{
+  int i, j;
+  locels.SetSize(0);
+  switch (GetType())
+    {
+    case TET:
+      {
+	int linels[1][4] = 
+	{ { 1, 2, 3, 4 },
+	};
+	for (i = 0; i < 1; i++)
+	  {
+	    Element tet(4);
+	    for (j = 1; j <= 4; j++)
+	      tet.PNum(j) = linels[i][j-1];
+	    locels.Append (tet);
+	  }
+	break;
+      }
+    case TET10:
+      {
+	int linels[8][4] = 
+	{ { 1, 5, 6, 7 },
+	  { 5, 2, 8, 9 },
+	  { 6, 8, 3, 10 },
+	  { 7, 9, 10, 4 },
+	  { 5, 6, 7, 9 },
+	  { 5, 6, 9, 8 },
+	  { 6, 7, 9, 10 },
+	  { 6, 8, 10, 9 } };
+	for (i = 0; i < 8; i++)
+	  {
+	    Element tet(4);
+	    for (j = 1; j <= 4; j++)
+	      tet.PNum(j) = linels[i][j-1];
+	    locels.Append (tet);
+	  }
+	break;
+      }
+    case PYRAMID:
+      {
+	int linels[2][4] = 
+	{ { 1, 2, 3, 5 },
+	  { 1, 3, 4, 5 } };
+	for (i = 0; i < 2; i++)
+	  {
+	    Element tet(4);
+	    for (j = 1; j <= 4; j++)
+	      tet.PNum(j) = linels[i][j-1];
+	    locels.Append (tet);
+	  }
+	break;
+      }
+    case PRISM:
+    case PRISM12:
+      {
+	int linels[3][4] = 
+	{ { 1, 2, 3, 4 },
+	  { 4, 2, 3, 5 },
+	  { 6, 5, 4, 3 }
+	};
+	for (i = 0; i < 3; i++)
+	  {
+	    Element tet(4);
+	    for (j = 0; j < 4; j++)
+	      tet[j] = linels[i][j];
+	    locels.Append (tet);
+	  }
+	break;
+      }
+    case HEX:
+      {
+	int linels[6][4] = 
+	{ { 1, 7, 2, 3 },
+	  { 1, 7, 3, 4 },
+	  { 1, 7, 4, 8 },
+	  { 1, 7, 8, 5 },
+	  { 1, 7, 5, 6 },
+	  { 1, 7, 6, 2 }
+	};
+	for (i = 0; i < 6; i++)
+	  {
+	    Element tet(4);
+	    for (j = 0; j < 4; j++)
+	      tet[j] = linels[i][j];
+	    locels.Append (tet);
+	  }
+	break;
+      }
+    default:
+      {
+	cerr << "GetTetsLocal not implemented for el with " << GetNP() << " nodes" << endl;
+      }
+    }
+}
+
+void Element :: GetNodesLocal (ARRAY<Point3d> & points) const
+{
+  const static double tetpoints[4][3] =
+    { { 0, 0, 0 },
+      { 1, 0, 0 },
+      { 0, 1, 0 },
+      { 0, 0, 1 }};
+  
+  const static double prismpoints[6][3] =
+    { { 0, 0, 0 },
+      { 1, 0, 0 },
+      { 0, 1, 0 },
+      { 0, 0, 1 },
+      { 1, 0, 1 },
+      { 0, 1, 1 } };
+  
+  const static double pyramidpoints[6][3] =
+    { { 0, 0, 0 },
+      { 1, 0, 0 },
+      { 1, 1, 0 },
+      { 0, 1, 0 },
+      { 0, 0, 1 } };
+  
+  const static double tet10points[10][3] =
+    { { 0, 0, 0 },
+      { 1, 0, 0 },
+      { 0, 1, 0 },
+      { 0, 0, 1 },
+      { 0.5, 0, 0 },
+      { 0, 0.5, 0 },
+      { 0, 0, 0.5 },
+      { 0.5, 0.5, 0 },
+      { 0.5, 0, 0.5 },
+      { 0, 0.5, 0.5 } };
+
+  const static double hexpoints[8][3] =
+    { 
+      { 0, 0, 0 },
+      { 1, 0, 0 },
+      { 1, 1, 0 },
+      { 1, 0, 0 },
+      { 0, 0, 1 },
+      { 1, 0, 1 },
+      { 1, 1, 1 },
+      { 1, 0, 1 }
+    };
+  
+  int np, i;
+  const double (*pp)[3];
+  switch (GetType())
+    {
+    case TET:
+      {
+	np = 4;
+	pp = tetpoints;
+	break;
+      }
+    case PRISM:
+    case PRISM12:
+      {
+	np = 6;
+	pp = prismpoints;
+	break;
+      }
+    case TET10:
+      {
+	np = 10;
+	pp = tet10points;
+	break;
+      }
+    case PYRAMID:
+      {
+	np = 5;
+	pp = pyramidpoints;
+	break;
+      }
+    case HEX:
+      {
+	np = 8;
+	pp = hexpoints;
+	break;
+      }
+    default:
+      {
+	cout << "GetNodesLocal not impelemented for element " << GetType() << endl;
+	np = 0;
+      }
+    }
+  
+  points.SetSize(0);
+  for (i = 0; i < np; i++)
+    points.Append (Point3d (pp[i][0], pp[i][1], pp[i][2]));
+}
+
+
+
+
+
+
+
+void Element :: GetNodesLocalNew (ARRAY<Point3d> & points) const
+{
+  const static double tetpoints[4][3] =
+    {      
+      { 1, 0, 0 },
+      { 0, 1, 0 },
+      { 0, 0, 1 },
+      { 0, 0, 0 }
+    };
+  
+  const static double prismpoints[6][3] =
+    {
+      { 1, 0, 0 },
+      { 0, 1, 0 },
+      { 0, 0, 0 },
+      { 1, 0, 1 },
+      { 0, 1, 1 },
+      { 0, 0, 1 }
+    };
+  
+  const static double pyramidpoints[6][3] =
+    { { 0, 0, 0 },
+      { 1, 0, 0 },
+      { 1, 1, 0 },
+      { 0, 1, 0 },
+      { 0, 0, 1 } };
+  
+  const static double tet10points[10][3] =
+    { { 0, 0, 0 },
+      { 1, 0, 0 },
+      { 0, 1, 0 },
+      { 0, 0, 1 },
+      { 0.5, 0, 0 },
+      { 0, 0.5, 0 },
+      { 0, 0, 0.5 },
+      { 0.5, 0.5, 0 },
+      { 0.5, 0, 0.5 },
+      { 0, 0.5, 0.5 } };
+
+  const static double hexpoints[8][3] =
+    { 
+      { 0, 0, 0 },
+      { 1, 0, 0 },
+      { 1, 1, 0 },
+      { 0, 1, 0 },
+      { 0, 0, 1 },
+      { 1, 0, 1 },
+      { 1, 1, 1 },
+      { 0, 1, 1 }
+    };
+  
+
+  
+  int np, i;
+  const double (*pp)[3];
+  switch (GetType())
+    {
+    case TET:
+      {
+	np = 4;
+	pp = tetpoints;
+	break;
+      }
+    case PRISM:
+    case PRISM12:
+      {
+	np = 6;
+	pp = prismpoints;
+	break;
+      }
+    case TET10:
+      {
+	np = 10;
+	pp = tet10points;
+	break;
+      }
+    case PYRAMID:
+      {
+	np = 5;
+	pp = pyramidpoints;
+	break;
+      }
+    case HEX:
+      {
+	np = 8;
+	pp = hexpoints;
+	break;
+      }
+    default:
+      {
+	cout << "GetNodesLocal not impelemented for element " << GetType() << endl;
+	np = 0;
+      }
+    }
+  
+  points.SetSize(0);
+  for (i = 0; i < np; i++)
+    points.Append (Point3d (pp[i][0], pp[i][1], pp[i][2]));
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+void Element :: GetSurfaceTriangles (ARRAY<Element2d> & surftrigs) const
+{
+  static int tet4trigs[][3] = 
+  { { 2, 3, 4 },
+    { 3, 1, 4 },
+    { 1, 2, 4 },
+    { 2, 1, 3 } };
+
+  // just a few:
+  static int tet10trigs[][3] = 
+  { { 2, 8, 9 },
+    { 3, 10, 8},
+    { 4, 9, 10 },
+    { 9, 8, 10 },
+    { 3, 1, 4 },
+    { 1, 2, 4 },
+    { 2, 1, 3 } };
+
+  static int pyramidtrigs[][3] =
+  {
+    { 1, 3, 2 },
+    { 1, 4, 3 },
+    { 1, 2, 5 },
+    { 2, 3, 5 },
+    { 3, 4, 5 },
+    { 4, 1, 5 }
+  };
+
+  static int prismtrigs[][3] =
+    {
+      { 1, 3, 2 },
+      { 4, 5, 6 },
+      { 1, 2, 4 },
+      { 4, 2, 5 },
+      { 2, 3, 5 },
+      { 5, 3, 6 },
+      { 3, 1, 6 },
+      { 6, 1, 4 }
+    };
+  
+  static int hextrigs[][3] = 
+    {
+      { 1, 3, 2 },
+      { 1, 4, 3 }, 
+      { 5, 6, 7 },
+      { 5, 7, 8 },
+      { 1, 2, 6 },
+      { 1, 6, 5 },
+      { 2, 3, 7 },
+      { 2, 7, 6 },
+      { 3, 4, 8 },
+      { 3, 8, 7 },
+      { 4, 1, 8 },
+      { 1, 5, 8 }
+    };
+
+  int j;
+
+  int nf;
+  int (*fp)[3];
+
+  switch (GetType())
+    {
+    case TET:
+      {
+	nf = 4;
+	fp = tet4trigs;
+	break;
+      }
+    case PYRAMID:
+      {
+	nf = 6;
+	fp = pyramidtrigs;
+	break;
+      }
+    case PRISM:
+    case PRISM12:
+      {
+	nf = 8;
+	fp = prismtrigs;
+	break;
+      }
+    case TET10:
+      {
+	nf = 7;
+	fp = tet10trigs;
+	break;
+      }
+    case HEX:
+      {
+	nf = 12;
+	fp = hextrigs;
+	break;
+      }
+    default:
+      {
+	nf = 0;
+	fp = NULL;
+      }
+    }
+
+  
+  surftrigs.SetSize (nf);
+  for (j = 0; j < nf; j++)
+    {
+      surftrigs.Elem(j+1) = Element2d(3);
+      surftrigs.Elem(j+1).PNum(1) = fp[j][0];
+      surftrigs.Elem(j+1).PNum(2) = fp[j][1];
+      surftrigs.Elem(j+1).PNum(3) = fp[j][2];
+    }
+}
+
+
+
+
+
+ARRAY<IntegrationPointData*> ipdtet;
+ARRAY<IntegrationPointData*> ipdtet10;
+
+
+int Element :: GetNIP () const
+{
+  int nip;
+  switch (typ)
+    {
+    case TET: nip = 1; break;
+    case TET10: nip = 8; break;
+    default: nip = 0; break;
+    }
+  return nip;
+}
+
+void Element :: 
+GetIntegrationPoint (int ip, Point3d & p, double & weight) const
+{
+  static double eltetqp[1][4] =
+  {
+    { 0.25, 0.25, 0.25, 1.0/6.0 }
+  };
+
+  static double eltet10qp[8][4] =
+  {
+    { 0.585410196624969, 0.138196601125011, 0.138196601125011, 1.0/24.0 },
+    { 0.138196601125011, 0.585410196624969, 0.138196601125011, 1.0/24.0 },
+    { 0.138196601125011, 0.138196601125011, 0.585410196624969, 1.0/24.0 },
+    { 0.138196601125011, 0.138196601125011, 0.138196601125011, 1.0/24.0 },
+    { 1, 0, 0, 1 },
+    { 0, 1, 0, 1 },
+    { 0, 0, 1, 1 },
+    { 0, 0, 0, 1 },
+  };
+  
+  double * pp;
+  switch (typ)
+    {
+    case TET: pp = &eltetqp[0][0]; break;
+    case TET10: pp = &eltet10qp[ip-1][0]; break;
+    }
+
+  p.X() = pp[0];
+  p.Y() = pp[1];
+  p.Z() = pp[2];
+  weight = pp[3];
+}
+
+void Element :: 
+GetTransformation (int ip, const T_POINTS & points,
+		   DenseMatrix & trans) const
+{
+  int np = GetNP();
+  static DenseMatrix pmat(3, np), dshape(3, np);
+  pmat.SetSize (3, np);
+  dshape.SetSize (3, np);
+
+  Point3d p;
+  double w;
+
+  GetPointMatrix (points, pmat);
+  GetIntegrationPoint (ip, p, w);
+  GetDShape (p, dshape);
+  
+  CalcABt (pmat, dshape, trans);
+
+  /*
+  (*testout) << "p = " << p  << endl
+	     << "pmat = " << pmat << endl
+	     << "dshape = " << dshape << endl
+	     << "tans = " << trans << endl;
+  */
+}
+
+void Element :: 
+GetTransformation (int ip, class DenseMatrix & pmat,
+		   class DenseMatrix & trans) const
+{
+  int np = GetNP();
+
+  if (pmat.Width() != np || pmat.Height() != 3)
+    {
+      (*testout) << "GetTransofrmation: pmat doesn't fit" << endl;
+      return;
+    }
+
+  ComputeIntegrationPointData ();
+  DenseMatrix * dshapep;
+  switch (GetType())
+    {
+    case TET: dshapep = &ipdtet.Get(ip)->dshape; break;
+    case TET10: dshapep = &ipdtet10.Get(ip)->dshape; break;
+    }
+  
+  CalcABt (pmat, *dshapep, trans);
+}
+
+
+
+void Element :: GetShape (const Point3d & p, Vector & shape) const
+{
+  if (shape.Size() != GetNP())
+    {
+      cerr << "Element::GetShape: Length not fitting" << endl;
+      return;
+    }
+
+  switch (typ)
+    {
+    case TET:
+      shape.Elem(1) = 1 - p.X() - p.Y() - p.Z(); 
+      shape.Elem(2) = p.X();
+      shape.Elem(3) = p.Y();
+      shape.Elem(4) = p.Z();
+      break;
+    case TET10:
+      double lam1 = 1 - p.X() - p.Y() - p.Z();
+      double lam2 = p.X();
+      double lam3 = p.Y();
+      double lam4 = p.Z();
+      
+      shape.Elem(5) = 4 * lam1 * lam2;
+      shape.Elem(6) = 4 * lam1 * lam3;
+      shape.Elem(7) = 4 * lam1 * lam4;
+      shape.Elem(8) = 4 * lam2 * lam3;
+      shape.Elem(9) = 4 * lam2 * lam4;
+      shape.Elem(10) = 4 * lam3 * lam4;
+
+      shape.Elem(1) = lam1 - 
+	0.5 * (shape.Elem(5) + shape.Elem(6) + shape.Elem(7));
+      shape.Elem(2) = lam2 - 
+	0.5 * (shape.Elem(5) + shape.Elem(8) + shape.Elem(9));
+      shape.Elem(3) = lam3 - 
+	0.5 * (shape.Elem(6) + shape.Elem(8) + shape.Elem(10));
+      shape.Elem(4) = lam4 - 
+	0.5 * (shape.Elem(7) + shape.Elem(9) + shape.Elem(10));
+      break;
+    }
+}
+
+void Element :: 
+GetDShape (const Point3d & p, DenseMatrix & dshape) const
+{
+  int np = GetNP();
+  if (dshape.Height() != 3 || dshape.Width() != np)
+    {
+      cerr << "Element::DShape: Sizes don't fit" << endl;
+      return;
+    }
+
+  int i, j;
+  double eps = 1e-6;
+  Vector shaper(np), shapel(np);
+
+  for (i = 1; i <= 3; i++)
+    {
+      Point3d pr(p), pl(p);
+      pr.X(i) += eps;
+      pl.X(i) -= eps;
+      
+      GetShape (pr, shaper);
+      GetShape (pl, shapel);
+      for (j = 1; j <= np; j++)
+	dshape.Elem(i, j) = (shaper.Get(j) - shapel.Get(j)) / (2 * eps);
+    }
+}
+
+
+void Element :: 
+GetPointMatrix (const T_POINTS & points,
+		DenseMatrix & pmat) const
+{
+  int i;
+  int np = GetNP();
+  if (pmat.Width() != np || pmat.Height() != 3)
+    {
+      cerr << "Element::GetPointMatrix: sizes don't fit" << endl;
+      return;
+    }
+  
+  for (i = 1; i <= np; i++)
+    {
+      const Point3d & p = points.Get(PNum(i));
+      pmat.Elem(1, i) = p.X();
+      pmat.Elem(2, i) = p.Y();
+      pmat.Elem(3, i) = p.Z();
+    }
+}
+
+
+
+
+
+
+double Element :: CalcJacobianBadness (const T_POINTS & points) const
+{
+  int i, j;
+  int nip = GetNIP();
+  static DenseMatrix trans(3,3);
+  static DenseMatrix pmat;
+  
+  pmat.SetSize (3, GetNP());
+  GetPointMatrix (points, pmat);
+
+  double err = 0;
+  for (i = 1; i <= nip; i++)
+    {
+      GetTransformation (i, pmat, trans);
+
+      // Frobenius norm
+      double frob = 0;
+      for (j = 1; j <= 9; j++)
+	frob += sqr (trans.Get(j));
+      frob = sqrt (frob);
+      frob /= 3;
+
+      double det = -trans.Det();
+      
+      if (det <= 0)
+	err += 1e12;
+      else
+	err += frob * frob * frob / det;
+    }
+
+  err /= nip;
+  return err;
+}
+
+double Element :: 
+CalcJacobianBadnessDirDeriv (const T_POINTS & points,
+			     int pi, Vec3d & dir, double & dd) const
+{
+  int i, j, k, l;
+  int nip = GetNIP();
+  static DenseMatrix trans(3,3), dtrans(3,3), hmat(3,3);
+  static DenseMatrix pmat, vmat;
+  
+  pmat.SetSize (3, GetNP());
+  vmat.SetSize (3, GetNP());
+
+  GetPointMatrix (points, pmat);
+  
+  for (i = 1; i <= np; i++)
+    for (j = 1; j <= 3; j++)
+      vmat.Elem(j, i) = 0;
+  for (j = 1; j <= 3; j++)
+    vmat.Elem(j, pi) = dir.X(j);
+
+
+
+  double err = 0;
+  dd = 0;
+
+  for (i = 1; i <= nip; i++)
+    {
+      GetTransformation (i, pmat, trans);
+      GetTransformation (i, vmat, dtrans);
+
+
+      // Frobenius norm
+      double frob = 0;
+      for (j = 1; j <= 9; j++)
+	frob += sqr (trans.Get(j));
+      frob = sqrt (frob);
+      
+      double dfrob = 0;
+      for (j = 1; j <= 9; j++)
+	dfrob += trans.Get(j) * dtrans.Get(j);
+      dfrob = dfrob / frob;
+      
+      frob /= 3;      
+      dfrob /= 3;
+
+      
+      double det = trans.Det();
+      double ddet = 0;
+      
+      for (j = 1; j <= 3; j++)
+	{
+	  hmat = trans;
+	  for (k = 1; k <= 3; k++)
+	    hmat.Elem(k, j) = dtrans.Get(k, j);
+	  ddet += hmat.Det();
+	}
+
+
+      det *= -1;
+      ddet *= -1;
+
+      
+      if (det <= 0)
+	err += 1e12;
+      else
+	{
+	  err += frob * frob * frob / det;
+	  dd += (3 * frob * frob * dfrob * det - frob * frob * frob * ddet) / (det * det);
+	}
+    }
+
+  err /= nip;
+  dd /= nip;
+  return err;
+}
+
+
+
+
+
+void Element :: ComputeIntegrationPointData () const
+{
+  switch (GetType())
+    {
+    case TET: if (ipdtet.Size()) return; break;
+    case TET10: if (ipdtet10.Size()) return; break;
+    default:
+      PrintSysError ("Element::ComputeIntegrationPoint, illegal type ", int(typ));
+    }
+
+  int i;
+  for (i = 1; i <= GetNIP(); i++)
+    {
+      IntegrationPointData * ipd = new IntegrationPointData;
+      GetIntegrationPoint (i, ipd->p, ipd->weight);
+      ipd->shape.SetSize(GetNP());
+      ipd->dshape.SetSize(3, GetNP());
+
+      GetShape (ipd->p, ipd->shape);
+      GetDShape (ipd->p, ipd->dshape);
+
+      switch (GetType())
+	{
+	case TET: ipdtet.Append (ipd); break;
+	case TET10: ipdtet10.Append (ipd); break;
+	default:
+	  PrintSysError ("Element::ComputeIntegrationPoint(2), illegal type ", int(typ));
+	}
+    }
+}
+
+
+
+
+
+
+
+
+FaceDescriptor ::  FaceDescriptor()
+{ 
+  surfnr = domin = 
+    domout  = bcprop = 0; 
+  tlosurf = -1;
+}
+
+FaceDescriptor :: 
+FaceDescriptor(int surfnri, int domini, int domouti, int tlosurfi)
+{ 
+  surfnr = surfnri; 
+  domin = domini; 
+  domout = domouti;
+  tlosurf = tlosurfi; 
+  bcprop = surfnri;
+}
+
+FaceDescriptor :: FaceDescriptor(const Segment & seg)
+{ 
+  surfnr = seg.si; 
+  domin = seg.domin+1;
+  domout = seg.domout+1;
+  tlosurf = seg.tlosurf+1;
+  bcprop = 0;
+}
+
+int FaceDescriptor ::  SegmentFits (const Segment & seg)
+{
+  return
+    surfnr == seg.si &&
+    domin == seg.domin+1 &&
+    domout == seg.domout+1  &&
+    tlosurf == seg.tlosurf+1;
+}
+
+
+ostream & operator<<(ostream  & s, const FaceDescriptor & fd)
+{
+  s << "surfnr = " << fd.surfnr 
+    << ", domin = " << fd.domin
+    << ", domout = " << fd.domout
+    << ", tlosurf = " << fd.tlosurf
+    << ", bcprop = " << fd.bcprop;
+  return s;
+}
+
+
+
+
+
+
+Identifications :: Identifications (Mesh & amesh)
+  : mesh(amesh)
+{
+  identifiedpoints = new INDEX_2_HASHTABLE<int>(100);
+  maxidentnr = 0;
+}
+
+Identifications :: ~Identifications ()
+{
+  delete identifiedpoints;
+}
+
+void Identifications :: Delete ()
+{
+  delete identifiedpoints;
+  identifiedpoints = new INDEX_2_HASHTABLE<int>(100);
+  maxidentnr = 0;
+}
+
+void Identifications :: Add (PointIndex pi1, PointIndex pi2, int identnr)
+{
+  INDEX_2 pair (pi1, pi2);
+  identifiedpoints->Set (pair, identnr);
+  if (identnr > maxidentnr) maxidentnr = identnr;
+  //  timestamp = NextTimeStamp();
+}
+
+int Identifications :: Get (PointIndex pi1, PointIndex pi2) const
+{
+  INDEX_2 pair(pi1, pi2);
+  if (identifiedpoints->Used (pair))
+    return identifiedpoints->Get(pair);
+  else
+    return 0;
+}
+
+int Identifications :: GetSymmetric (PointIndex pi1, PointIndex pi2) const
+{
+  INDEX_2 pair(pi1, pi2);
+  if (identifiedpoints->Used (pair))
+    return identifiedpoints->Get(pair);
+
+  pair = INDEX_2 (pi2, pi1);
+  if (identifiedpoints->Used (pair))
+    return identifiedpoints->Get(pair);
+
+  return 0;
+}
+
+
+void Identifications :: GetMap (int identnr, 
+				ARRAY<int,PointIndex::BASE> & identmap) const
+{
+  int i, j;
+  
+  identmap.SetSize (mesh.GetNP());
+  for (i = 1; i <= identmap.Size(); i++)
+    identmap.Elem(i) = 0;
+
+  for (i = 1; i <= identifiedpoints->GetNBags(); i++)
+    for (j = 1; j <= identifiedpoints->GetBagSize(i); j++)
+      {
+	INDEX_2 i2;
+	int nr;
+	identifiedpoints->GetData (i, j, i2, nr);
+	
+	if (nr == identnr)
+	  {
+	    identmap.Elem(i2.I1()) = i2.I2();
+	  }
+      }  
+}
+ 
+
+void Identifications :: GetPairs (int identnr, 
+				  ARRAY<INDEX_2> & identpairs) const
+{
+  int i, j;
+  
+  identpairs.SetSize(0);
+  
+  for (i = 1; i <= identifiedpoints->GetNBags(); i++)
+    for (j = 1; j <= identifiedpoints->GetBagSize(i); j++)
+      {
+	INDEX_2 i2;
+	int nr;
+	identifiedpoints->GetData (i, j, i2, nr);
+	
+	if (identnr == 0 || nr == identnr)
+	  identpairs.Append (i2);
+      }  
+}
+
+
+
+
+
+
+
+MeshingParameters :: MeshingParameters ()
+{
+  optimize3d = "cmdmstm";
+  optsteps3d = 3;
+  optimize2d = "smsmsmSmSmSm";
+  optsteps2d = 1;
+  opterrpow = 2;
+  blockfill = 1;
+  filldist = 0.1;
+  safety = 5;
+  relinnersafety = 3;
+  uselocalh = 1;
+  grading = 0.5;
+  delaunay = 1;
+  maxh = 1e10;
+  meshsizefilename = NULL;
+  startinsurface = 0;
+  checkoverlap = 1;
+  checkchartboundary = 1;
+  curvaturesafety = 2;
+  parthread = 0;
+  
+  elsizeweight = 0;
+  giveuptol = 10;
+  maxoutersteps = 5;
+  starshapeclass = 5;
+  baseelnp = 0;
+  sloppy = 1;
+
+  badellimit = 175;
+  secondorder = 0;
+}
+
+void MeshingParameters :: Print (ostream & ost) const
+{
+  ost << "Meshing parameters: " << endl
+      << "maxh = " << maxh << endl
+      << "grading = " << grading << endl
+      << "startinsurface = " << startinsurface << endl
+      << "checkoverlap = " << checkoverlap << endl
+      << "curvaturesafety = " << curvaturesafety << endl;
+}
+
+
+
+DebugParameters :: DebugParameters ()
+{
+  slowchecks = 0;
+  haltsuccess = 0;
+  haltnosuccess = 0;
+  haltsegment = 0;
+  haltsegmentp1 = 0;
+  haltsegmentp2 = 0;
+};
+
+
+
+}
diff --git a/Netgen/libsrc/meshing/meshtype.hpp b/Netgen/libsrc/meshing/meshtype.hpp
new file mode 100644
index 0000000000..25a131114a
--- /dev/null
+++ b/Netgen/libsrc/meshing/meshtype.hpp
@@ -0,0 +1,919 @@
+#ifndef MESHTYPE
+#define MESHTYPE
+
+/**************************************************************************/
+/* File:   meshtype.hpp                                                   */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Okt. 95                                                    */
+/**************************************************************************/
+
+/*
+    Classes for NETGEN
+*/
+
+
+enum ELEMENT_TYPE { 
+  SEGMENT = 1, SEGMENT3 = 2,
+  TRIG = 10, QUAD=11, TRIG6 = 12, QUAD6 = 13, QUAD8 = 14,
+  TET = 20, TET10 = 21, 
+  PYRAMID = 22, PRISM = 23, PRISM12 = 24,
+  HEX = 25
+};
+
+typedef int ELEMENT_EDGE[2];      // initial point, end point
+typedef int ELEMENT_FACE[4];      // points, last one is -1 for trig
+
+
+#define ELEMENT_MAXPOINTS 12
+#define ELEMENT2D_MAXPOINTS 6
+
+
+enum POINTTYPE { FIXEDPOINT = 1, EDGEPOINT = 2, SURFACEPOINT = 3, INNERPOINT = 4 };
+enum ELEMENTTYPE { FREEELEMENT, FIXEDELEMENT };
+enum OPTIMIZEGOAL { OPT_QUALITY, OPT_CONFORM, OPT_REST, OPT_WORSTCASE, OPT_LEGAL };
+
+
+
+
+// class CSGeometry;
+
+extern int GetTimeStamp();
+extern int NextTimeStamp();
+
+struct PointGeomInfo
+{
+  int trignum;   // for STL Meshing
+  double u, v;   // for OCC Meshing
+};
+
+inline ostream & operator<< (ostream & ost, const PointGeomInfo & gi)
+{
+  return (ost << gi.trignum);
+}
+
+
+
+#define MULTIPOINTGEOMINFO_MAX 100
+class MultiPointGeomInfo
+{
+  int cnt;
+  PointGeomInfo mgi[MULTIPOINTGEOMINFO_MAX];
+public:
+  MultiPointGeomInfo ();
+  int AddPointGeomInfo (const PointGeomInfo & gi);
+  void Init ();
+  void DeleteAll ();
+
+  int GetNPGI () const { return cnt; }
+  const PointGeomInfo & GetPGI (int i) const { return mgi[i-1]; }
+};
+
+
+struct EdgePointGeomInfo
+{
+public:
+  int edgenr;
+  double dist; 
+  double u, v; // for OCC Meshing
+
+  EdgePointGeomInfo ()
+  { edgenr = 0; dist = 0; u = v = 0; }
+};
+
+inline ostream & operator<< (ostream & ost, const EdgePointGeomInfo & gi)
+{
+  return (ost << gi.edgenr);
+}
+
+
+
+
+
+
+class PointIndex
+{
+  int i;
+public:
+  PointIndex () { ; }
+  PointIndex (int ai) : i(ai) { ; }
+  PointIndex & operator= (const PointIndex &ai) { i = ai.i; return *this; }
+  PointIndex & operator= (int ai) { i = ai; return *this; }
+  operator int () const { return i; }
+  int GetInt () const { return i; }
+  PointIndex operator++ (int) { int hi = i; i++; return hi; }
+  PointIndex operator-- (int) { int hi = i; i--; return hi; }
+
+  enum { BASE = 1 };
+};
+
+inline istream & operator>> (istream & ist, PointIndex & pi)
+{
+  int i; ist >> i; pi = i; return ist;
+}
+
+inline ostream & operator<< (ostream & ost, const PointIndex & pi)
+{
+  return (ost << pi.GetInt());
+}
+
+
+
+
+class ElementIndex
+{
+  int i;
+public:
+  ElementIndex () { ; }
+  ElementIndex (int ai) : i(ai) { ; }
+  ElementIndex & operator= (const ElementIndex & ai) { i = ai.i; return *this; }
+  ElementIndex & operator= (int ai) { i = ai; return *this; }
+  operator int () const { return i; }
+  ElementIndex & operator++ (int) { i++; return *this; }
+  ElementIndex & operator-- (int) { i--; return *this; }
+};
+
+
+
+
+class SurfaceElementIndex
+{
+  int i;
+public:
+  SurfaceElementIndex () { ; }
+  SurfaceElementIndex (int ai) : i(ai) { ; }
+  SurfaceElementIndex & operator= (const SurfaceElementIndex & ai) 
+    { i = ai.i; return *this; }
+  SurfaceElementIndex & operator= (int ai) { i = ai; return *this; }
+  operator int () const { return i; }
+  SurfaceElementIndex & operator++ (int) { i++; return *this; }
+  SurfaceElementIndex & operator-- (int) { i--; return *this; }
+};
+
+
+
+class SegmentIndex
+{
+  int i;
+public:
+  SegmentIndex () { ; }
+  SegmentIndex (int ai) : i(ai) { ; }
+  SegmentIndex & operator= (const SegmentIndex & ai) 
+    { i = ai.i; return *this; }
+  SegmentIndex & operator= (int ai) { i = ai; return *this; }
+  operator int () const { return i; }
+  SegmentIndex & operator++ (int) { i++; return *this; }
+  SegmentIndex & operator-- (int) { i--; return *this; }
+};
+
+
+
+
+
+
+/**
+   Point in the mesh.
+   Contains layer (a new feature in 4.3 for overlapping meshes.
+   will contain pointtype
+ */
+class MeshPoint : public Point3d
+{
+  int layer;
+public:
+  MeshPoint () { ; }
+  MeshPoint (const Point3d & ap, int alayer = 1)
+    : Point3d (ap), layer(alayer) { ; }
+  
+  void SetPoint (const Point3d & ap)
+  { Point3d::operator= (ap); }
+  int GetLayer() const { return layer; }
+};
+
+
+
+// typedef MoveableArray<MeshPoint> T_POINTS;
+typedef ARRAY<MeshPoint,PointIndex::BASE> T_POINTS;
+
+
+class Element2d;
+ostream & operator<<(ostream  & s, const Element2d & el);
+
+/**
+  Triangle element for surface mesh generation.
+ */
+class Element2d
+{ 
+  /// point numbers
+  PointIndex pnum[ELEMENT2D_MAXPOINTS];
+  /// geom info of corner points
+  PointGeomInfo geominfo[ELEMENT2D_MAXPOINTS];
+
+  /// surface nr
+  int index:16;
+  ///
+  ELEMENT_TYPE typ:6;
+  /// number of points
+  unsigned int np:3;
+  bool badel:1;
+  bool refflag:1;  // marked for refinement
+  bool deleted:1;  // element is deleted
+
+  /// order for hp-FEM
+  unsigned int order:6;
+public:
+  ///
+  Element2d (int anp = 3);
+  ///
+  Element2d (ELEMENT_TYPE type);
+  ///
+  Element2d (int pi1, int pi2, int pi3);
+  ///
+  Element2d (int pi1, int pi2, int pi3, int pi4);
+  ///
+  ELEMENT_TYPE GetType () const { return typ; }
+  /// 
+  void SetType (ELEMENT_TYPE atyp);
+  ///
+  int GetNP() const { return np; }
+  ///
+  int GetNV() const
+  {
+    switch (typ)
+      {
+      case TRIG:
+      case TRIG6: return 3;
+
+      case QUAD:
+      case QUAD8:
+      case QUAD6: return 4;
+      default:
+#ifdef DEBUG
+	PrintSysError ("element2d::GetNV not implemented for typ", typ)
+#endif
+	;
+      }
+    return np;
+  }
+
+  ///
+  PointIndex & operator[] (int i) { return pnum[i]; }
+  ///
+  const PointIndex & operator[] (int i) const { return pnum[i]; }
+
+  ///
+  PointIndex & PNum (int i) { return pnum[i-1]; }
+  ///
+  const PointIndex & PNum (int i) const { return pnum[i-1]; }
+  ///
+  PointIndex & PNumMod (int i) { return pnum[(i-1) % np]; }
+  ///
+  const PointIndex & PNumMod (int i) const { return pnum[(i-1) % np]; }
+  ///
+
+  ///
+  PointGeomInfo & GeomInfoPi (int i) { return geominfo[i-1]; }
+  ///
+  const PointGeomInfo & GeomInfoPi (int i) const { return geominfo[i-1]; }
+  ///
+  PointGeomInfo & GeomInfoPiMod (int i) { return geominfo[(i-1) % np]; }
+  ///
+  const PointGeomInfo & GeomInfoPiMod (int i) const { return geominfo[(i-1) % np]; }
+
+
+  void SetIndex (int si) { index = si; }
+  ///
+  int GetIndex () const { return index; }
+
+  int GetOrder () const { return order; }
+  void SetOrder (int aorder) { order = aorder; }
+
+  ///
+  void GetBox (const T_POINTS & points, Box3d & box) const;
+  /// invert orientation
+  inline void Invert ();
+  ///
+  void Invert2 ();
+  /// first point number is smallest
+  inline void NormalizeNumbering ();
+  ///
+  void NormalizeNumbering2 ();
+
+  bool BadElement() const { return badel; }
+
+  friend ostream & operator<<(ostream  & s, const Element2d & el);
+  friend class Mesh;
+
+
+  /// get number of 'integration points'
+  int GetNIP () const;
+  void GetIntegrationPoint (int ip, Point2d & p, double & weight) const;
+  void GetTransformation (int ip, const ARRAY<Point2d> & points,
+			  class DenseMatrix & trans) const;
+  void GetTransformation (int ip, class DenseMatrix & pmat,
+			  class DenseMatrix & trans) const;
+
+  void GetShape (const Point2d & p, class Vector & shape) const;
+  /// matrix 2 * np
+  void GetDShape (const Point2d & p, class DenseMatrix & dshape) const;
+  /// matrix 2 * np
+  void GetPointMatrix (const ARRAY<Point2d> & points,
+		       class DenseMatrix & pmat) const; 
+
+  void ComputeIntegrationPointData () const;
+  
+
+  double CalcJacobianBadness (const ARRAY<Point2d> & points) const;
+  double CalcJacobianBadness (const T_POINTS & points, 
+			      const Vec3d & n) const;
+  double CalcJacobianBadnessDirDeriv (const ARRAY<Point2d> & points,
+				      int pi, Vec2d & dir, double & dd) const;
+
+
+
+  void Delete () { deleted = 1; pnum[0] = pnum[1] = pnum[2] = pnum[3] = PointIndex::BASE-1; }
+  bool IsDeleted () const 
+  {
+#ifdef DEBUG
+    if (pnum[0] < PointIndex::BASE && !deleted)
+      cerr << "Surfelement has illegal pnum, but not marked as deleted" << endl;
+#endif    
+    return deleted; 
+  }
+
+  void SetRefinementFlag (int rflag = 1) 
+  { refflag = rflag; }
+  bool TestRefinementFlag () const
+  { return refflag; }
+
+  int HasFace(const Element2d& el) const;
+  ///
+  int meshdocval;
+};
+
+
+
+
+class IntegrationPointData
+{
+public:
+  Point3d p;
+  double weight;
+  Vector shape;
+  DenseMatrix dshape;
+};
+
+
+
+
+class Element;
+ostream & operator<<(ostream  & s, const Element & el);
+
+
+
+/**
+  Volume element
+ */
+class Element
+{
+private:
+  /// point numbers
+  PointIndex pnum[ELEMENT_MAXPOINTS];
+  ///
+  ELEMENT_TYPE typ:6;
+  /// number of points (4..tet, 5..pyramid, 6..prism, 8..hex, 10..quad tet, 12..quad prism)
+  int np:5;
+  ///
+  struct flagstruct {
+    bool marked:1;  // marked for refinement
+    bool badel:1;   // angles worse then limit
+    bool reverse:1; // for refinement a la Bey
+    bool illegal:1; // illegal, will be split or swaped 
+    bool illegal_valid:1; // is illegal-flag valid ?
+    bool badness_valid:1; // is badness valid ?
+    bool refflag:1;     // mark element for refinement
+    bool deleted:1;   // element is deleted, will be removed from array
+  };
+  /// surface or sub-domain index
+  short int index;
+  /// order for hp-FEM
+  unsigned int order:6;
+  /// stored shape-badness of element
+  float badness;
+  
+public:
+  flagstruct flags;
+
+  ///
+  Element ();
+  ///
+  Element (int anp);
+  ///
+  Element (ELEMENT_TYPE type);
+  ///
+  Element & operator= (const Element & el2);
+  
+  ///
+  void SetNP (int anp);
+  ///
+  void SetType (ELEMENT_TYPE atyp);
+  ///
+  int GetNP () const { return np; }
+  ///
+  int GetNV() const
+  {
+    switch (typ)
+      {
+      case TET: return 4;
+      case TET10: return 4;
+      case PRISM12: return 6;
+      default:
+#ifdef DEBUG
+	PrintSysError ("Element3d::GetNV not implemented for typ", typ)
+#endif
+	  ;
+      }
+    return np;
+  }
+  // old style:
+  int NP () const { return np; }
+
+  ///
+  ELEMENT_TYPE GetType () const { return typ; }
+
+  ///
+  PointIndex & operator[] (int i) { return pnum[i]; }
+  ///
+  const PointIndex & operator[] (int i) const { return pnum[i]; }
+
+  ///
+  PointIndex & PNum (int i) { return pnum[i-1]; }
+  ///
+  const PointIndex & PNum (int i) const { return pnum[i-1]; }
+  ///
+  PointIndex & PNumMod (int i) { return pnum[(i-1) % np]; }
+  ///
+  const PointIndex & PNumMod (int i) const { return pnum[(i-1) % np]; }
+  
+  ///
+  void SetIndex (int si) { index = si; }
+  ///
+  int GetIndex () const { return index; }
+
+  int GetOrder () const { return order; }
+  void SetOrder (int aorder) { order = aorder; }
+
+  ///
+  void GetBox (const T_POINTS & points, Box3d & box) const;
+  /// Calculates Volume of elemenet
+  double Volume (const T_POINTS & points) const;
+  ///
+  virtual void Print (ostream & ost) const;
+  ///
+  int GetNFaces () const
+    {
+      switch (typ)
+	{
+	case TET: 
+	case TET10: return 4;
+	case PYRAMID: return 5;
+	case PRISM: 
+	case PRISM12: return 5;
+	default:
+#ifdef DEBUG
+	  PrintSysError ("element3d::GetNFaces not implemented for typ", typ)
+#endif
+	    ;
+	}
+      return 0;
+    }
+  ///
+  inline void GetFace (int i, Element2d & face) const;
+  ///
+  void GetFace2 (int i, Element2d & face) const;
+  ///
+  void Invert ();
+
+  /// split into 4 node tets
+  void GetTets (ARRAY<Element> & locels) const;
+  /// split into 4 node tets, local point nrs
+  void GetTetsLocal (ARRAY<Element> & locels) const;
+  /// returns coordinates of nodes
+  void GetNodesLocal (ARRAY<Point3d> & points) const;
+  void GetNodesLocalNew (ARRAY<Point3d> & points) const;
+
+  /// split surface into 3 node trigs
+  void GetSurfaceTriangles (ARRAY<Element2d> & surftrigs) const;
+
+
+  /// get number of 'integration points'
+  int GetNIP () const;
+  void GetIntegrationPoint (int ip, Point3d & p, double & weight) const;
+  void GetTransformation (int ip, const T_POINTS & points,
+			  class DenseMatrix & trans) const;
+  void GetTransformation (int ip, class DenseMatrix & pmat,
+			  class DenseMatrix & trans) const;
+
+  void GetShape (const Point3d & p, class Vector & shape) const;
+  /// matrix 2 * np
+  void GetDShape (const Point3d & p, class DenseMatrix & dshape) const;
+  /// matrix 3 * np
+  void GetPointMatrix (const T_POINTS & points,
+		       class DenseMatrix & pmat) const; 
+
+  void ComputeIntegrationPointData () const;
+  
+
+  double CalcJacobianBadness (const T_POINTS & points) const;
+  double CalcJacobianBadnessDirDeriv (const T_POINTS & points,
+				      int pi, Vec3d & dir, double & dd) const;
+
+  ///
+  friend ostream & operator<<(ostream  & s, const Element & el);
+
+  void SetRefinementFlag (int rflag = 1) 
+  { flags.refflag = rflag; }
+  int TestRefinementFlag () const
+  { return flags.refflag; }
+
+  int Illegal () const
+    { return flags.illegal; }
+  int IllegalValid () const
+    { return flags.illegal_valid; }
+  void SetIllegal (int aillegal)
+  {
+    flags.illegal = aillegal ? 1 : 0;
+    flags.illegal_valid = 1;
+  }
+  void SetLegal (int alegal)
+  {
+    flags.illegal = alegal ? 0 : 1;
+    flags.illegal_valid = 1;
+  }
+  
+  void Delete () { flags.deleted = 1; }
+  bool IsDeleted () const 
+  { 
+#ifdef DEBUG
+    if (pnum[0] < PointIndex::BASE && !flags.deleted)
+      cerr << "Volelement has illegal pnum, but not marked as deleted" << endl;
+#endif    
+
+    return flags.deleted; 
+  }
+};
+
+
+class Segment;
+ostream & operator<<(ostream  & s, const Segment & seg);
+
+
+/**
+  Edge segment.
+  */
+class Segment
+{
+public:
+  ///
+  Segment();
+
+  friend ostream & operator<<(ostream  & s, const Segment & seg);
+
+  /// point index 1
+  PointIndex p1;
+  /// point index 2
+  PointIndex p2;    
+  /// edge nr
+  int edgenr;
+  ///
+  unsigned int singedge:1;
+  /// 0.. not first segment of segs, 1..first of class, 2..first of class, inverse
+  unsigned int seginfo:2;
+  /// surface decoding index
+  int si;          
+  /// domain number inner side
+  int domin;
+  /// domain number outer side
+  int domout;  
+  /// top-level object number of surface
+  int tlosurf;
+  ///
+  PointGeomInfo geominfo[2];
+  /// surfaces describing edge
+  int surfnr1, surfnr2;
+  ///
+  EdgePointGeomInfo epgeominfo[2];
+  ///
+  int pmid; // for second order
+  ///
+  int meshdocval;
+};
+
+
+// class Surface;  
+class FaceDescriptor;
+ostream & operator<< (ostream  & s, const FaceDescriptor & fd);
+
+///
+class FaceDescriptor
+{
+  /// which surface, 0 if not available
+  int surfnr;
+  /// domain nr inside
+  int domin;
+  /// domain nr outside
+  int domout;
+  /// top level object number of surface
+  int tlosurf;
+  /// boundary condition property
+  int bcprop;
+
+public:
+  FaceDescriptor();
+  FaceDescriptor(int surfnri, int domini, int domouti, int tlosurfi);
+  FaceDescriptor(const Segment & seg);
+
+  int SegmentFits (const Segment & seg);
+
+  int SurfNr () const { return surfnr; }
+  int DomainIn () const { return domin; }
+  int DomainOut () const { return domout; }
+  int TLOSurface () const { return tlosurf; }
+  int BCProperty () const { return bcprop; }
+  void SetSurfNr (int sn) { surfnr = sn; }
+  void SetDomainIn (int di) { domin = di; }
+  void SetDomainOut (int dom) { domout = dom; }
+  void SetBCProperty (int bc) { bcprop = bc; }
+
+  friend ostream & operator<<(ostream  & s, const FaceDescriptor & fd);
+};
+
+ 
+
+
+
+
+class MeshingParameters
+{
+public:
+  /**
+     3d optimization strategy:
+     // m .. move nodes
+     // M .. move nodes, cheap functional
+     // s .. swap faces
+     // c .. combine elements
+     // d .. divide elements
+     // p .. plot, no pause
+     // P .. plot, Pause
+     // h .. Histogramm, no pause
+     // H .. Histogramm, pause
+  */
+  char * optimize3d;
+  /// number of 3d optimization steps
+  int optsteps3d;
+  /**
+     2d optimization strategy:
+     // s .. swap, opt 6 lines/node
+     // S .. swap, optimal elements
+     // m .. move nodes
+     // p .. plot, no pause
+     // P .. plot, pause
+     // c .. combine
+  **/
+  char * optimize2d;
+  /// number of 2d optimization steps
+  int optsteps2d;
+  /// power of error (to approximate max err optimization)
+  double opterrpow;
+  /// do block filling ?
+  int blockfill;
+  /// block filling up to distance
+  double filldist;
+  /// radius of local environment (times h)
+  double safety;
+  /// radius of active environment (times h)
+  double relinnersafety;
+  /// use local h ?
+  int uselocalh;
+  /// grading for local h
+  double grading;
+  /// use delaunay meshing
+  int delaunay;
+  /// maximal mesh size
+  double maxh;
+  /// file for meshsize
+  const char * meshsizefilename;
+  /// start surfacemeshing from everywhere in surface
+  int startinsurface;
+  /// check overlapping surfaces (debug)
+  int checkoverlap;
+  /// check chart boundary (sometimes too restrictive)
+  int checkchartboundary;
+  /// safty factor for curvatures (elemetns per radius)
+  double curvaturesafety;
+  /// minimal number of segments per edge
+  double segmentsperedge;
+  /// use parallel threads
+  int parthread;
+  /// weight of element size w.r.t element shape
+  double elsizeweight;
+  /// init with default values
+
+
+  /// from mp3:
+  /// give up quality class
+  int giveuptol;
+  /// maximal outer steps
+  int maxoutersteps;
+  /// class starting star-shape filling
+  int starshapeclass;
+  /// if non-zero, baseelement must have baseelnp points
+  int baseelnp;        
+  /// quality tolerances are handled less careful
+  int sloppy;
+  
+  /// limit for max element angle (150-180)
+  double badellimit;
+
+  ///
+  int secondorder;
+  /// high order element curvature
+  int elementorder;
+  /// quad-dominated surface meshing
+  int quad;
+  ///
+  int inverttets;
+  ///
+  int inverttrigs;
+  ///
+  MeshingParameters ();
+  ///
+  void Print (ostream & ost) const;
+};
+
+class DebugParameters 
+{
+public:
+  ///
+  int debugoutput;
+  /// use slow checks
+  int slowchecks;
+  ///
+  int haltsuccess;
+  ///
+  int haltnosuccess;
+  ///
+  int haltsegment;
+  ///
+  int haltnode;
+  ///
+  int haltsegmentp1;
+  ///
+  int haltsegmentp2;
+  ///
+  int haltexistingline;
+  ///
+  int haltoverlap;
+  ///
+  int haltface;
+  ///
+  int haltfacenr;
+  ///
+  DebugParameters ();
+};
+
+
+
+
+
+
+
+inline void Element2d :: Invert()
+{
+  if (typ == TRIG)
+    Swap (PNum(2), PNum(3));
+  else
+    Invert2();
+}
+
+
+
+
+inline void Element2d :: NormalizeNumbering ()
+{
+  if (GetNP() == 3)
+    {
+      if (PNum(1) < PNum(2) && PNum(1) < PNum(3))
+	return;
+      else
+	{
+	  if (PNum(2) < PNum(3))
+	    {
+	      PointIndex pi1 = PNum(2);
+	      PNum(2) = PNum(3);
+	      PNum(3) = PNum(1);
+	      PNum(1) = pi1;
+	    }
+	  else
+	    {
+	      PointIndex pi1 = PNum(3);
+	      PNum(3) = PNum(2);
+	      PNum(2) = PNum(1);
+	      PNum(1) = pi1;
+	    }
+	}
+    }
+  else
+    NormalizeNumbering2();
+}
+
+
+
+static const int gftetfacesa[4][3] = 
+  { { 1, 2, 3 },
+    { 2, 0, 3 },
+    { 0, 1, 3 },
+    { 1, 0, 2 } };
+
+inline void Element :: GetFace (int i, Element2d & face) const
+{
+  if (typ == TET)
+    {
+      face.SetType(TRIG);
+      face[0] = pnum[gftetfacesa[i-1][0]];
+      face[1] = pnum[gftetfacesa[i-1][1]];
+      face[2] = pnum[gftetfacesa[i-1][2]];
+    }
+  else
+    GetFace2 (i, face);
+}
+
+
+
+
+
+
+
+/**
+   Identification of periodic surfaces, close surfaces, etc. 
+ */
+class Identifications
+{
+private:
+  Mesh & mesh;
+
+  /// identify points (thin layers, periodic b.c.)  
+  INDEX_2_HASHTABLE<int> * identifiedpoints;
+
+  /// number of identifications (or, actually used identifications ?)
+  int maxidentnr;
+
+public:
+  ///
+  Identifications (Mesh & amesh);
+  ///
+  ~Identifications ();
+
+  void Delete ();
+
+  /*
+    Identify points pi1 and pi2, due to
+    identification nr identnr
+  */
+  void Add (PointIndex pi1, PointIndex pi2, int identnr);
+
+
+  int Get (PointIndex pi1, PointIndex pi2) const;
+  int GetSymmetric (PointIndex pi1, PointIndex pi2) const;
+  ///
+  INDEX_2_HASHTABLE<int> & GetIdentifiedPoints () 
+  { 
+    return *identifiedpoints; 
+  }
+
+  bool Used (PointIndex pi1, PointIndex pi2)
+  {
+    return identifiedpoints->Used (INDEX_2 (pi1, pi2));
+  }
+
+  bool UsedSymmetric (PointIndex pi1, PointIndex pi2)
+  {
+    return 
+      identifiedpoints->Used (INDEX_2 (pi1, pi2)) ||
+      identifiedpoints->Used (INDEX_2 (pi2, pi1));
+  }
+
+  ///
+  void GetMap (int identnr, ARRAY<int,PointIndex::BASE> & identmap) const;
+  ///
+  void GetPairs (int identnr, ARRAY<INDEX_2> & identpairs) const;
+  ///
+  int GetMaxNr () const { return maxidentnr; }  
+
+};
+
+
+
+
+
+
+
+#endif
diff --git a/Netgen/libsrc/meshing/msghandler.cpp b/Netgen/libsrc/meshing/msghandler.cpp
new file mode 100644
index 0000000000..8d2bb429ee
--- /dev/null
+++ b/Netgen/libsrc/meshing/msghandler.cpp
@@ -0,0 +1,186 @@
+//File for handling warnings, errors, messages
+#include <meshing.hpp>
+
+namespace netgen
+{
+
+int printmessage_importance = 5;
+int printwarnings = 1;
+int printerrors = 1;
+int printdots = 1;
+int printfnstart = 0;
+
+// extern void Ng_PrintDest(const MyStr& s);
+extern void Ng_PrintDest(const char * s);
+
+//the dots for progression of program
+void PrintDot(char ch)
+{
+  if (printdots)
+    {
+      char st[2];
+      st[0] = ch;
+      st[1] = 0;
+      Ng_PrintDest(st);
+    }
+}
+
+void PrintMessage(int importance, 
+		  const MyStr& s1, const MyStr& s2, const MyStr& s3, const MyStr& s4, 
+		  const MyStr& s5, const MyStr& s6, const MyStr& s7, const MyStr& s8)
+{
+  if (importance <= printmessage_importance)
+    {
+      Ng_PrintDest(MyStr(" ")+s1+s2+s3+s4+s5+s6+s7+s8+MyStr("\n"));
+    }
+}
+
+void PrintMessageCR(int importance, 
+		    const MyStr& s1, const MyStr& s2, const MyStr& s3, const MyStr& s4, 
+		    const MyStr& s5, const MyStr& s6, const MyStr& s7, const MyStr& s8)
+{
+  if (importance <= printmessage_importance)
+    {
+      Ng_PrintDest(MyStr(" ")+s1+s2+s3+s4+s5+s6+s7+s8+MyStr("\r"));
+    }
+}
+
+void PrintFnStart(const MyStr& s1, const MyStr& s2, const MyStr& s3, const MyStr& s4, 
+		  const MyStr& s5, const MyStr& s6, const MyStr& s7, const MyStr& s8)
+{
+  if (printfnstart)
+    Ng_PrintDest(MyStr(" Start Function: ")+s1+s2+s3+s4+s5+s6+s7+s8+MyStr("\n"));
+}
+
+void PrintWarning(const MyStr& s1, const MyStr& s2, const MyStr& s3, const MyStr& s4, 
+		  const MyStr& s5, const MyStr& s6, const MyStr& s7, const MyStr& s8)
+{
+  if (printwarnings)
+    Ng_PrintDest(MyStr(" WARNING: ")+s1+s2+s3+s4+s5+s6+s7+s8+MyStr("\n"));
+}
+
+void PrintError(const MyStr& s1, const MyStr& s2, const MyStr& s3, const MyStr& s4, 
+		const MyStr& s5, const MyStr& s6, const MyStr& s7, const MyStr& s8)
+{
+  if (printerrors)
+    Ng_PrintDest(MyStr(" ERROR: ")+s1+s2+s3+s4+s5+s6+s7+s8+MyStr("\n"));
+}
+
+void PrintFileError(const MyStr& s1, const MyStr& s2, const MyStr& s3, const MyStr& s4, 
+		    const MyStr& s5, const MyStr& s6, const MyStr& s7, const MyStr& s8)
+{
+  if (printerrors)
+    Ng_PrintDest(MyStr(" FILE ERROR: ")+s1+s2+s3+s4+s5+s6+s7+s8+MyStr("\n"));
+}
+
+void PrintUserError(const MyStr& s1, const MyStr& s2, const MyStr& s3, const MyStr& s4, 
+		const MyStr& s5, const MyStr& s6, const MyStr& s7, const MyStr& s8)
+{
+  Ng_PrintDest(MyStr(" USER ERROR: ")+s1+s2+s3+s4+s5+s6+s7+s8+MyStr("\n"));
+}
+
+void PrintSysError(const MyStr& s1, const MyStr& s2, const MyStr& s3, const MyStr& s4, 
+		const MyStr& s5, const MyStr& s6, const MyStr& s7, const MyStr& s8)
+{
+  if (printerrors)
+    Ng_PrintDest(MyStr(" SYSTEM ERROR: ")+s1+s2+s3+s4+s5+s6+s7+s8+MyStr("\n"));
+}
+
+void PrintTime(const MyStr& s1, const MyStr& s2, const MyStr& s3, const MyStr& s4, 
+	       const MyStr& s5, const MyStr& s6, const MyStr& s7, const MyStr& s8)
+{
+  if (printmessage_importance >= 3)
+    Ng_PrintDest(MyStr(" Time = ")+s1+s2+s3+s4+s5+s6+s7+s8+MyStr("\n"));
+}
+
+ARRAY<MyStr*> msgstatus_stack(0);
+MyStr* msgstatus = NULL;
+
+void ResetStatus()
+{
+  SetStatMsg("idle");
+
+  if (msgstatus != NULL)
+    {
+      delete msgstatus;
+    } 
+  int i;
+  for (i = 1; i <= msgstatus_stack.Size(); i++)
+    {
+      delete msgstatus_stack.Get(i);
+    }
+  
+  msgstatus_stack.SetSize(0);
+  msgstatus = NULL;
+  multithread.task = "";
+  multithread.percent = 100.;
+}
+
+void PushStatus(const MyStr& s)
+{
+  if (msgstatus == NULL)
+    {
+      SetStatMsg("idle");
+    } 
+  msgstatus_stack.Append(msgstatus);
+  msgstatus = NULL;
+
+  SetStatMsg(s);
+  //  multithread.task = "";
+}
+void PushStatusF(const MyStr& s)
+{
+  if (msgstatus == NULL)
+    {
+      SetStatMsg("idle");
+    } 
+  msgstatus_stack.Append(msgstatus);
+  msgstatus = NULL;
+
+  SetStatMsg(s);
+  //  multithread.task = "";
+  PrintFnStart(s);
+}
+
+void PopStatus()
+{
+  SetThreadPercent(100.);
+  if (msgstatus_stack.Size())
+    {
+      if (msgstatus != NULL) 
+	{
+	  delete msgstatus;
+	}
+      msgstatus = msgstatus_stack.Get(msgstatus_stack.Size());
+      msgstatus_stack.SetSize(msgstatus_stack.Size()-1);
+      multithread.task = msgstatus->c_str();
+    }
+  else
+    {
+      PrintSysError("PopStatus failed");
+    }
+}
+/*
+void SetStatMsgF(const MyStr& s)
+{
+  PrintFnStart(s);
+  SetStatMsg(s);
+}
+*/
+void SetStatMsg(const MyStr& s)
+{
+  if (msgstatus != NULL)
+    {
+      delete msgstatus;
+    }
+  msgstatus = new MyStr(s);
+  multithread.task = msgstatus->c_str();  
+}
+
+void SetThreadPercent(double percent)
+{
+  multithread.percent = percent;
+}
+
+
+}
diff --git a/Netgen/libsrc/meshing/msghandler.hpp b/Netgen/libsrc/meshing/msghandler.hpp
new file mode 100644
index 0000000000..b7d4481866
--- /dev/null
+++ b/Netgen/libsrc/meshing/msghandler.hpp
@@ -0,0 +1,47 @@
+#ifndef FILE_MSGHANDLER
+#define FILE_MSGHANDLER
+
+/**************************************************************************/
+/* File:   msghandler.hh                                                  */
+/* Author: Johannes Gerstmayr                                             */
+/* Date:   20. Nov. 99                                                    */
+/**************************************************************************/
+
+
+extern void PrintDot(char ch = '.');
+
+
+//Message Pipeline:
+
+//importance: importance of message: 1=very important, 3=middle, 5=low, 7=unimportant
+extern void PrintMessage(int importance, 
+			 const MyStr& s1, const MyStr& s2="", const MyStr& s3="", const MyStr& s4="", 
+			 const MyStr& s5="", const MyStr& s6="", const MyStr& s7="", const MyStr& s8="");
+// CR without line-feed
+extern void PrintMessageCR(int importance, 
+			   const MyStr& s1, const MyStr& s2="", const MyStr& s3="", const MyStr& s4="", 
+			   const MyStr& s5="", const MyStr& s6="", const MyStr& s7="", const MyStr& s8="");
+extern void PrintFnStart(const MyStr& s1, const MyStr& s2="", const MyStr& s3="", const MyStr& s4="", 
+			 const MyStr& s5="", const MyStr& s6="", const MyStr& s7="", const MyStr& s8="");
+extern void PrintWarning(const MyStr& s1, const MyStr& s2="", const MyStr& s3="", const MyStr& s4="", 
+			 const MyStr& s5="", const MyStr& s6="", const MyStr& s7="", const MyStr& s8="");
+extern void PrintError(const MyStr& s1, const MyStr& s2="", const MyStr& s3="", const MyStr& s4="", 
+		       const MyStr& s5="", const MyStr& s6="", const MyStr& s7="", const MyStr& s8="");
+extern void PrintFileError(const MyStr& s1, const MyStr& s2="", const MyStr& s3="", const MyStr& s4="", 
+		       const MyStr& s5="", const MyStr& s6="", const MyStr& s7="", const MyStr& s8="");
+extern void PrintSysError(const MyStr& s1, const MyStr& s2="", const MyStr& s3="", const MyStr& s4="", 
+		       const MyStr& s5="", const MyStr& s6="", const MyStr& s7="", const MyStr& s8="");
+extern void PrintUserError(const MyStr& s1, const MyStr& s2="", const MyStr& s3="", const MyStr& s4="", 
+		       const MyStr& s5="", const MyStr& s6="", const MyStr& s7="", const MyStr& s8="");
+extern void PrintTime(const MyStr& s1="", const MyStr& s2="", const MyStr& s3="", const MyStr& s4="", 
+		      const MyStr& s5="", const MyStr& s6="", const MyStr& s7="", const MyStr& s8="");
+extern void SetStatMsg(const MyStr& s);
+
+extern void PushStatus(const MyStr& s);
+extern void PushStatusF(const MyStr& s);
+extern void PopStatus();
+extern void SetThreadPercent(double percent);
+
+
+#endif
+
diff --git a/Netgen/libsrc/meshing/netrule2.cpp b/Netgen/libsrc/meshing/netrule2.cpp
new file mode 100644
index 0000000000..c0acd4938d
--- /dev/null
+++ b/Netgen/libsrc/meshing/netrule2.cpp
@@ -0,0 +1,212 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+namespace netgen
+{
+
+netrule :: netrule ()
+{
+  name = new char[1];
+  name[0] = char(0);
+  quality = 0;
+}
+
+netrule ::  ~netrule()
+{
+  delete name;
+}
+
+
+/*
+void netrule :: GetFreeArea (ARRAY<Point2d> & afreearea)
+  {
+  int i;
+
+  afreearea.SetSize (freearea.Size());
+  for (i = 1; i <= freearea.Size(); i++)
+    afreearea[i] = freearea[i];
+  }
+*/
+
+
+void netrule :: SetFreeZoneTransformation (const Vector & devp, int tolclass)
+{
+  int i;
+  double lam1 = 1.0/tolclass;
+  double lam2 = 1-lam1;
+
+  double mem1[100], mem2[100], mem3[100];
+
+  int vs = oldutofreearea.Height();
+  FlatVector devfree(vs, mem1);
+  FlatVector devfree1(vs, mem2);
+  FlatVector devfree2(vs, mem3);
+
+  oldutofreearea.Mult (devp, devfree1);
+  oldutofreearealimit.Mult (devp, devfree2);
+  devfree.Set2 (lam1, devfree1, lam2, devfree2);
+
+  transfreezone.SetSize (freezone.Size());
+
+
+  int fzs = transfreezone.Size();
+
+  if (fzs > 0)
+    {
+      transfreezone[0].X() = lam1 * freezone[0].X() + lam2 * freezonelimit[0].X() + devfree[0];
+      transfreezone[0].Y() = lam1 * freezone[0].Y() + lam2 * freezonelimit[0].Y() + devfree[1];
+      fzmaxx = fzminx = transfreezone[0].X();
+      fzmaxy = fzminy = transfreezone[0].Y();
+    }
+
+  for (i = 1; i < fzs; i++)
+    {
+      transfreezone[i].X() = lam1 * freezone[i].X() + lam2 * freezonelimit[i].X() + devfree[2*i];
+      transfreezone[i].Y() = lam1 * freezone[i].Y() + lam2 * freezonelimit[i].Y() + devfree[2*i+1];
+
+      if (transfreezone[i].X() > fzmaxx) fzmaxx = transfreezone[i].X();
+      if (transfreezone[i].X() < fzminx) fzminx = transfreezone[i].X();
+      if (transfreezone[i].Y() > fzmaxy) fzmaxy = transfreezone[i].Y();
+      if (transfreezone[i].Y() < fzminy) fzminy = transfreezone[i].Y();
+    }
+
+  for (i = 0; i < fzs; i++)
+    {
+      Point2d p1 = transfreezone[i];
+      Point2d p2 = transfreezone[(i+1) % fzs];
+
+      Vec2d vn (p2.Y() - p1.Y(), p1.X() - p2.X());
+      double len2 = vn.Length2();
+
+      if (len2 < 1e-10)
+	{
+	  freesetinequ(i, 0) = 0;
+	  freesetinequ(i, 1) = 0;
+	  freesetinequ(i, 2) = -1;
+	}
+      else
+	{
+	  vn *= 1/sqrt (len2);
+
+	  freesetinequ(i,0) = vn.X(); 
+	  freesetinequ(i,1) = vn.Y(); 
+	  freesetinequ(i,2) = -(p1.X() * vn.X() + p1.Y() * vn.Y());
+	}
+    }
+}
+
+
+int netrule :: IsInFreeZone2 (const Point2d & p) const
+{
+  int i;
+
+  for (i = 1; i <= transfreezone.Size(); i++)
+    {
+      if (freesetinequ.Get(i, 1) * p.X() + freesetinequ.Get(i, 2) * p.Y() +
+	  freesetinequ.Get(i, 3) > 0) return 0;
+    }
+  return 1;
+}
+
+int netrule :: IsLineInFreeZone2 (const Point2d & p1, const Point2d & p2) const
+{
+  int i;
+  int left, right, allleft, allright;
+  double nx, ny, nl, c;
+
+  if (p1.X() > fzmaxx && p2.X() > fzmaxx ||
+      p1.X() < fzminx && p2.X() < fzminx ||
+      p1.Y() > fzmaxy && p2.Y() > fzmaxy ||
+      p1.Y() < fzminy && p2.Y() < fzminy) return 0;
+
+  for (i = 1; i <= transfreezone.Size(); i++)
+    {
+      if (freesetinequ.Get(i, 1) * p1.X() + freesetinequ.Get(i, 2) * p1.Y() +
+	  freesetinequ.Get(i, 3) > -1e-5 &&
+	  freesetinequ.Get(i, 1) * p2.X() + freesetinequ.Get(i, 2) * p2.Y() +
+	  freesetinequ.Get(i, 3) > -1e-5
+	  ) return 0;
+    }
+
+  nx =  (p2.Y() - p1.Y());
+  ny = -(p2.X() - p1.X());
+  nl = sqrt (nx * nx + ny * ny);
+  if (nl > 1e-8)
+    {
+      nx /= nl;
+      ny /= nl;
+      c = - (p1.X() * nx + p1.Y() * ny);
+
+      allleft = 1;
+      allright = 1;
+
+      for (i = 1; i <= transfreezone.Size(); i++)
+	{
+	  left  = transfreezone.Get(i).X() * nx + transfreezone.Get(i).Y() + c <  1e-7;
+	  right = transfreezone.Get(i).X() * nx + transfreezone.Get(i).Y() + c > -1e-7;
+
+	  if (!left) allleft = 0;
+	  if (!right) allright = 0;
+	}
+      if (allleft || allright) return 0;
+    }
+
+  return 1;
+}
+
+int netrule :: ConvexFreeZone () const
+{
+  int i, n;
+  n = transfreezone.Size();
+  for (i = 1; i <= n; i++)
+    {
+      if (! CCW (transfreezone.Get(i), 
+		 transfreezone.Get(i % n + 1),
+		 transfreezone.Get( (i+1) % n + 1 ) ) )
+	return 0;
+    }
+  return 1;
+}
+
+
+
+float netrule :: CalcPointDist (int pi, const Point2d & p) const
+{
+  float dx = p.X() - points.Get(pi).X();
+  float dy = p.Y() - points.Get(pi).Y();
+  const threefloat * tf = &tolerances.Get(pi);
+
+  return tf->f1 * dx * dx + tf->f2 * dx * dy + tf->f3 * dy * dy;
+}
+
+
+float netrule :: CalcLineError (int li, const Vec2d & v) const
+{
+  float dx = v.X() - linevecs.Get(li).X();
+  float dy = v.Y() - linevecs.Get(li).Y();
+
+  const threefloat * tf = &linetolerances.Get(li);
+  return tf->f1 * dx * dx + tf->f2 * dx * dy + tf->f3 * dy * dy;
+}
+
+
+
+
+/*
+int GetNRules ()
+  {
+  return rules.Size();
+  }
+*/
+
+
+
+
+
+
+
+
+
+
+
+}
diff --git a/Netgen/libsrc/meshing/netrule3.cpp b/Netgen/libsrc/meshing/netrule3.cpp
new file mode 100644
index 0000000000..b6c5967058
--- /dev/null
+++ b/Netgen/libsrc/meshing/netrule3.cpp
@@ -0,0 +1,1143 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+// #define MARK
+// #include <prof.h>
+
+
+namespace netgen
+{
+
+
+vnetrule :: vnetrule ()
+{
+  name = "";
+  quality = 0;
+}
+
+vnetrule :: ~vnetrule ()
+{
+  int i;
+  if (strlen(name))
+    delete name;
+  for (i = 1; i <= freefaces.Size(); i++)
+    delete freefaces.Elem(i);
+  for (i = 1; i <= freesets.Size(); i++)
+    delete freesets.Elem(i);
+  for (i = 1; i <= freeedges.Size(); i++)
+    delete freeedges.Elem(i);
+  for (i = 1; i <= freefaceinequ.Size(); i++)
+    delete freefaceinequ.Elem(i);
+  delete oldutofreezone;
+  delete oldutofreezonelimit;
+}
+
+int vnetrule :: TestFlag (char flag) const
+{
+  int i;
+  for (i = 1; i <= flags.Size(); i++)
+    if (flags.Get(i) == flag) return 1;
+  return 0;
+}
+
+
+void vnetrule :: SetFreeZoneTransformation (const Vector & allp, int tolclass)
+{
+  int i, j;
+  // double nx, ny, nz, v1x, v1y, v1z, v2x, v2y, v2z;
+  double nl;
+  const threeint * ti;
+  int fs;
+
+  double lam1 = 1.0/(2 * tolclass - 1);
+  double lam2 = 1-lam1;
+
+  //  MARK (setfz1);
+
+  transfreezone.SetSize (freezone.Size());
+  
+  int np = points.Size();
+  int nfp = freezone.Size();
+  Vector vp(np), vfp1(nfp), vfp2(nfp);
+
+
+  for (i = 1; i <= 3; i++)
+    {
+      for (j = 1; j <= np; j++)
+	vp.Elem(j) = allp.Get(i+3*j-3);
+
+      oldutofreezone->Mult (vp, vfp1);
+      oldutofreezonelimit->Mult (vp, vfp2);
+
+      vfp1 *= lam1;
+      vfp1.Add (lam2, vfp2);
+
+      for (j = 1; j <= nfp; j++)
+	transfreezone.Elem(j).X(i) = vfp1.Elem(j);
+    }
+
+  // MARK(setfz2);
+
+
+  fzbox.SetPoint (transfreezone.Elem(1));
+  for (i = 2; i <= freezone.Size(); i++)
+    fzbox.AddPoint (transfreezone.Elem(i));
+  
+  
+  // MARK(setfz3);
+
+
+  for (fs = 1; fs <= freesets.Size(); fs++)
+    {
+      ARRAY<threeint> & freesetfaces = *freefaces.Get(fs);
+      DenseMatrix & freesetinequ = *freefaceinequ.Get(fs);
+      
+      for (i = 1; i <= freesetfaces.Size(); i++)
+	{
+	  ti = &freesetfaces.Get(i);
+	  const Point3d & p1 = transfreezone.Get(ti->i1);
+	  const Point3d & p2 = transfreezone.Get(ti->i2);
+	  const Point3d & p3 = transfreezone.Get(ti->i3);
+
+	  Vec3d v1(p1, p2);   
+	  Vec3d v2(p1, p3);   
+	  Vec3d n;
+	  Cross (v1, v2, n);
+
+	  nl = n.Length();
+
+	  if (nl < 1e-10)
+	    {
+	      freesetinequ.Set(1, 1, 0);
+	      freesetinequ.Set(1, 2, 0);
+	      freesetinequ.Set(1, 3, 0);
+	      freesetinequ.Set(1, 4, -1);
+	    }
+	  else
+	    {
+	      //	      n /= nl;
+	      
+	      freesetinequ.Set(i, 1, n.X()/nl);
+	      freesetinequ.Set(i, 2, n.Y()/nl);
+	      freesetinequ.Set(i, 3, n.Z()/nl);
+	      freesetinequ.Set(i, 4,
+			       -(p1.X() * n.X() + p1.Y() * n.Y() + p1.Z() * n.Z()) / nl);
+	    }
+	}
+    }
+
+  /*
+  (*testout) << "Transformed freezone: " << endl;
+  for (i = 1; i <= transfreezone.Size(); i++)
+    (*testout) << transfreezone.Get(i) << " ";
+  (*testout) << endl;
+  */
+}
+
+int vnetrule :: ConvexFreeZone () const
+{
+  int i, j, k, fs;
+
+  // (*mycout) << "Convex free zone...\n";
+  
+  int ret1=1;
+  // int ret2=1;
+
+  for (fs = 1; fs <= freesets.Size(); fs++)
+    {
+      const DenseMatrix & freesetinequ = *freefaceinequ.Get(fs);
+
+      // const ARRAY<int> & freeset = *freesets.Get(fs);
+      const ARRAY<twoint> & freesetedges = *freeedges.Get(fs);
+      // const ARRAY<threeint> & freesetfaces = *freefaces.Get(fs);
+      
+      for (i = 1; i <= freesetedges.Size(); i++)
+	{
+	  j = freesetedges.Get(i).i1;    //triangle j with opposite point k
+	  k = freesetedges.Get(i).i2;
+	  
+	  if ( freesetinequ.Get(j, 1) * transfreezone.Get(k).X() +
+	       freesetinequ.Get(j, 2) * transfreezone.Get(k).Y() +
+	       freesetinequ.Get(j, 3) * transfreezone.Get(k).Z() +
+	       freesetinequ.Get(j, 4) > 0 )
+	    {
+	      ret1=0;
+	    }
+	}
+      
+    }
+
+  return ret1;
+}
+
+
+int vnetrule :: IsInFreeZone (const Point3d & p) const
+{
+  int i, fs;
+  char inthis;
+  
+  
+  for (fs = 1; fs <= freesets.Size(); fs++)
+    {
+      inthis = 1;
+      ARRAY<threeint> & freesetfaces = *freefaces.Get(fs);
+      DenseMatrix & freesetinequ = *freefaceinequ.Get(fs);
+      
+      for (i = 1; i <= freesetfaces.Size() && inthis; i++)
+	{
+	  if (freesetinequ.Get(i, 1) * p.X() + freesetinequ.Get(i, 2) * p.Y() +
+	      freesetinequ.Get(i, 3) * p.Z() + freesetinequ.Get(i, 4) > 0)
+	    inthis = 0;
+	}
+      
+      if (inthis) return 1;
+    }
+  
+  return 0;
+}
+
+
+int vnetrule :: IsTriangleInFreeZone (const Point3d & p1, 
+				      const Point3d & p2,
+				      const Point3d & p3, 
+				      const ARRAY<int> & pi, int newone)
+{
+  int fs;
+  int infreeset, cannot = 0;
+
+
+  static ARRAY<int> pfi(3), pfi2(3);
+
+  // convert from local index to freeset index
+  int i, j;
+  for (i = 1; i <= 3; i++)
+    {
+      pfi.Elem(i) = 0;
+      if (pi.Get(i))
+	{
+	  for (j = 1; j <= freezonepi.Size(); j++)
+	    if (freezonepi.Get(j) == pi.Get(i))
+	      pfi.Elem(i) = j;
+	}
+    }
+
+  for (fs = 1; fs <= freesets.Size(); fs++)
+    {
+      const ARRAY<int> & freeseti = *freesets.Get(fs);
+      for (i = 1; i <= 3; i++)
+	{
+	  pfi2.Elem(i) = 0;
+	  for (j = 1; j <= freeseti.Size(); j++)
+	    if (pfi.Get(i) == freeseti.Get(j))
+	      pfi2.Elem(i) = pfi.Get(i);
+	}
+
+      infreeset = IsTriangleInFreeSet(p1, p2, p3, fs, pfi2, newone);
+      if (infreeset == 1) return 1;
+      if (infreeset == -1) cannot = -1;
+    }
+  
+  return cannot;
+}
+
+
+
+int vnetrule :: IsTriangleInFreeSet (const Point3d & p1, const Point3d & p2,
+                                     const Point3d & p3, int fs,
+				     const ARRAY<int> & pi, int newone)
+{
+  int i, ii;
+  Vec3d n;
+  int allleft, allright;
+  int hos1, hos2, hos3, os1, os2, os3;
+  double hf, lam1, lam2, f, c1, c2, alpha;
+  double v1n, v2n, h11, h12, h22, dflam1, dflam2;
+  double lam1old, lam2old, fold;
+  double hpx, hpy, hpz, v1x, v1y, v1z, v2x, v2y, v2z;
+  int act1, act2, act3, it;
+  int cntout;
+  static ARRAY<int> activefaces;
+  int isin;
+  
+
+  // MARK(triinfz);
+  
+  ARRAY<threeint> & freesetfaces = *freefaces.Get(fs);
+  DenseMatrix & freesetinequ = *freefaceinequ.Get(fs);
+  
+
+  int cnt = 0;
+  for (i = 1; i <= 3; i++)
+    if (pi.Get(i)) cnt++;
+
+  /*
+  (*testout) << "trig in free set : " << p1 << " - " << p2 << " - " << p3 << endl;
+  (*testout) << "common points: " << cnt << endl;
+  */
+  if (!newone)
+    cnt = 0;
+
+  if (cnt == 1)
+    {
+      // MARK(triinfz1);
+
+      int upi = 0, lpiu = 0;
+      for (i = 1; i <= 3; i++)
+	if (pi.Get(i))
+	  {
+	    upi = i;
+	    lpiu = pi.Get(i);
+	  }
+
+      Vec3d v1, v2;
+      switch (upi)
+	{
+	case 1:
+	  {
+	    v1 = p2 - p1;
+	    v2 = p3 - p1;
+	    break;
+	  }
+	case 2:
+	  {
+	    v1 = p3 - p2;
+	    v2 = p1 - p2;
+	    break;
+	  }
+	case 3:
+	  {
+	    v1 = p1 - p3;
+	    v2 = p2 - p3;
+	    break;
+	  }
+	}
+
+      v1 /= v1.Length();
+      v2 /= v2.Length();
+      Cross (v1, v2, n);
+      n /= n.Length();
+
+      //      (*testout) << "Test new: " << endl;
+      for (i = 1; i <= freesetfaces.Size(); i++)
+	{
+	  if ( (freesetfaces.Get(i).i1 == lpiu) || 
+	       (freesetfaces.Get(i).i2 == lpiu) ||
+	       (freesetfaces.Get(i).i3 == lpiu) )
+	    {
+	      // freeface has point
+
+
+	      Vec3d a (freesetinequ.Get(i, 1),
+		       freesetinequ.Get(i, 2),
+		       freesetinequ.Get(i, 3));
+	      
+	      //	      if (1 - fabs (a * n) < 1e-8 ) 
+	      //		continue;
+
+	      Vec3d an;
+	      Cross (a, n, an);
+	      double lan = an.Length();
+	      if (lan < 1e-10)
+		continue;
+
+	      an /= lan;
+	      
+	      int out1 = (a * v1) > 0;
+	      int out2 = (a * v2) > 0;
+	      //	      (*testout) << "out1, out2 = " << out1 << ", " << out2 << endl;
+	      if (out1 && out2)
+		return 0;
+
+	      if (!out1 && !out2) 
+		continue;
+
+
+	      //	      if ( ( (an * v1) < 0) &&  ( (an * v2) < 0) )   // falsch !!!!
+	      //		an *= -1;
+
+	      // solve  an = lam1 v1 + lam2 v2
+	      double vii11 = v1 * v1;
+	      double vii12 = v1 * v2;
+	      double vii22 = v2 * v2;
+	      double det = vii11 * vii22 - vii12 * vii12;
+	      if ( fabs (det) < 1e-10 )
+		continue;
+	      double rs1 = an * v1;
+	      double rs2 = an * v2;
+	      
+	      double lam1 = rs1 * vii22 - rs2 * vii12;
+	      double lam2 = rs2 * vii11 - rs1 * vii12;
+
+	      if (fabs (lam1) > fabs (lam2))
+		{
+		  if (lam1 < 0)
+		    an *= -1;
+		}
+	      else
+		{
+		  if (lam2 < 0)
+		    an *= -1;
+		}
+
+
+	      if (lam1 * lam2 < 0 && 0)
+		{
+		  if (fabs (lam1) > 1e-14 && fabs (lam2) > 1e-14)
+		    {
+		      //		      (*mycout) << "lam1 lam2 < 0" << endl;
+		      (*testout) << "lami different" << endl;
+		      (*testout) << "v1 = " << v1 << endl;
+		      (*testout) << "v2 = " << v2 << endl;
+		      (*testout) << "n = " << n << endl;
+		      (*testout) << "a = " << a << endl;
+		      (*testout) << "an = " << an << endl;
+		      (*testout) << "a * v1 = " << (a * v1) << endl;
+		      (*testout) << "a * v2 = " << (a * v2) << endl;
+		      (*testout) << "an * v1 = " << (an * v1) << endl;
+		      (*testout) << "an * v2 = " << (an * v2) << endl;
+		      
+		      (*testout) << "vii = " << vii11 << ", " << vii12 << ", " << vii22 << endl;
+		      (*testout) << "lami = " << lam1 << ", " << lam2 << endl;
+		      (*testout) << "rs = " << rs1 << ", " << rs2 << endl;
+		      continue;
+		    }
+		}
+
+	      if (out1)
+		v1 = an;
+	      else
+		v2 = an;
+	    }
+	}
+      
+      return 1;
+
+      /*
+      (*testout) << "overlap trig " << p1 << p2 << p3 << endl;
+      (*testout) << "upi = " << upi << endl;
+      (*testout) << "v1 = " << v1 << " v2 = " << v2 << endl;
+      */
+
+      switch (upi)
+	{
+	case 1:
+	  {
+	    v1 = p2 - p1;
+	    v2 = p3 - p1;
+	    break;
+	  }
+	case 2:
+	  {
+	    v1 = p3 - p2;
+	    v2 = p1 - p2;
+	    break;
+	  }
+	case 3:
+	  {
+	    v1 = p1 - p3;
+	    v2 = p2 - p3;
+	    break;
+	  }
+	}
+
+      v1 /= v1.Length();
+      v2 /= v2.Length();
+      Cross (v1, v2, n);
+      n /= n.Length();
+
+      //      (*testout) << "orig v1, v2 = " << v1 << ", " << v2 << endl;
+
+      
+      for (i = 1; i <= freesetfaces.Size(); i++)
+	{
+	  if ( (freesetfaces.Get(i).i1 == lpiu) || 
+	       (freesetfaces.Get(i).i2 == lpiu) ||
+	       (freesetfaces.Get(i).i3 == lpiu) )
+	    {
+	      /*
+	      (*testout) << "v1, v2, now = " << v1 << ", " << v2 << endl;
+
+	      // freeface has point
+	      (*testout) << "freesetface: "
+			 << freesetfaces.Get(i).i1 << " "
+			 << freesetfaces.Get(i).i2 << " "
+			 << freesetfaces.Get(i).i3 << " ";
+	      */
+
+	      Vec3d a (freesetinequ.Get(i, 1),
+		       freesetinequ.Get(i, 2),
+		       freesetinequ.Get(i, 3));
+	      //	      (*testout) << "a = " <<  a << endl;
+
+
+	      Vec3d an;
+	      Cross (a, n, an);
+	      double lan = an.Length();
+	      
+	      //	      (*testout) << "an = " << an << endl;
+
+	      if (lan < 1e-10)
+		continue;
+
+	      an /= lan;
+
+	      //	      (*testout) << "a*v1 = " << (a*v1) << " a*v2 = " << (a*v2) << endl;
+	      
+	      int out1 = (a * v1) > 0;
+	      // int out2 = (a * v2) > 0;
+
+
+	      //	      (*testout) << "out1, 2 = " << out1 << ", " << out2 << endl;
+
+	      
+	      double vii11 = v1 * v1;
+	      double vii12 = v1 * v2;
+	      double vii22 = v2 * v2;
+	      double det = vii11 * vii22 - vii12 * vii12;
+	      if ( fabs (det) < 1e-10 )
+		continue;
+	      double rs1 = an * v1;
+	      double rs2 = an * v2;
+	      
+	      double lam1 = rs1 * vii22 - rs2 * vii12;
+	      double lam2 = rs2 * vii11 - rs1 * vii12;
+
+	      //	      (*testout) << "lam1, lam2 = " << lam1 << ", " << lam2 << endl;
+
+
+	      if (fabs (lam1) > fabs (lam2))
+		{
+		  if (lam1 < 0)
+		    an *= -1;
+		}
+	      else
+		{
+		  if (lam2 < 0)
+		    an *= -1;
+		}
+
+
+	      if (lam1 * lam2 < 0)
+		{
+		  if (fabs (lam1) > 1e-14 && fabs (lam2) > 1e-14)
+		    {
+		      //		      (*mycout) << "lam1 lam2 < 0" << endl;
+		      (*testout) << "lami different" << endl;
+		      (*testout) << "v1 = " << v1 << endl;
+		      (*testout) << "v2 = " << v2 << endl;
+		      (*testout) << "n = " << n << endl;
+		      (*testout) << "a = " << a << endl;
+		      (*testout) << "an = " << an << endl;
+		      (*testout) << "a * v1 = " << (a * v1) << endl;
+		      (*testout) << "a * v2 = " << (a * v2) << endl;
+		      (*testout) << "an * v1 = " << (an * v1) << endl;
+		      (*testout) << "an * v2 = " << (an * v2) << endl;
+		      
+		      (*testout) << "vii = " << vii11 << ", " << vii12 << ", " << vii22 << endl;
+		      (*testout) << "lami = " << lam1 << ", " << lam2 << endl;
+		      (*testout) << "rs = " << rs1 << ", " << rs2 << endl;
+		      continue;
+		    }
+		}
+
+	      if (out1)
+		v1 = an;
+	      else
+		v2 = an;
+
+
+
+	    }
+	}
+
+      return 1;
+    }
+
+
+
+  if (cnt == 2)
+    {
+      //      (*testout) << "tripoitns: " << p1 << " " << p2 << " " << p3 << endl;
+
+      // MARK(triinfz2);
+
+      int pi1 = 0, pi2 = 0, pi3 = 0;
+      Vec3d a1, a2;  // outer normals
+      Vec3d trivec;  // vector from common edge to third point of triangle
+      for (i = 1; i <= 3; i++)
+	if (pi.Get(i))
+	  {
+	    pi2 = pi1;
+	    pi1 = pi.Get(i);
+	  }
+	else
+	  pi3 = i;
+
+      switch (pi3)
+	{
+	case 1: trivec = (p1 - p2); break;
+	case 2: trivec = (p2 - p3); break;
+	case 3: trivec = (p3 - p2); break;
+	}
+
+      ARRAY<int> lpi(freezonepi.Size());
+      for (i = 1; i <= lpi.Size(); i++)
+	lpi.Elem(i) = 0;
+      lpi.Elem(pi1) = 1;
+      lpi.Elem(pi2) = 1;
+      
+      int ff1 = 0, ff2 = 0;
+      for (i = 1; i <= freesetfaces.Size(); i++)
+	{
+	  if (lpi.Get(freesetfaces.Get(i).i1) + 
+	      lpi.Get(freesetfaces.Get(i).i2) + 
+	      lpi.Get(freesetfaces.Get(i).i3) == 2)
+	    {
+	      ff2 = ff1;
+	      ff1 = i;
+	    }
+	}
+
+      if (ff2 == 0)
+	return 1;
+
+      a1 = Vec3d (freesetinequ.Get(ff1, 1),
+		  freesetinequ.Get(ff1, 2),
+		  freesetinequ.Get(ff1, 3));
+      a2 = Vec3d (freesetinequ.Get(ff2, 1),
+		  freesetinequ.Get(ff2, 2),
+		  freesetinequ.Get(ff2, 3));
+
+      if ( ( (a1 * trivec) > 0) || ( (a2 * trivec) > 0))
+	return 0;
+
+      return 1;
+    }
+
+
+  if (cnt == 3)
+    {
+      // MARK(triinfz3);  
+
+      ARRAY<int> lpi(freezonepi.Size());
+      for (i = 1; i <= lpi.Size(); i++)
+	lpi.Elem(i) = 0;
+
+      for (i = 1; i <= 3; i++)
+	lpi.Elem(pi.Get(i)) = 1;
+      
+      for (i = 1; i <= freesetfaces.Size(); i++)
+	{
+	  if (lpi.Get(freesetfaces.Get(i).i1) + 
+	      lpi.Get(freesetfaces.Get(i).i2) + 
+	      lpi.Get(freesetfaces.Get(i).i3) == 3)
+	    {
+	      return 0;
+	    }
+	}
+      return 1;
+    }
+
+  // MARK(triinfz0);  
+
+  
+  os1 = os2 = os3 = 0;
+  activefaces.SetSize(0);
+
+  // is point inside ?
+
+  for (i = 1; i <= freesetfaces.Size(); i++)
+    {
+      hos1 = freesetinequ.Get(i, 1) * p1.X() +
+	freesetinequ.Get(i, 2) * p1.Y() +
+	freesetinequ.Get(i, 3) * p1.Z() +
+	freesetinequ.Get(i, 4) > -1E-5;
+      
+      hos2 = freesetinequ.Get(i, 1) * p2.X() +
+	freesetinequ.Get(i, 2) * p2.Y() +
+	freesetinequ.Get(i, 3) * p2.Z() +
+	freesetinequ.Get(i, 4) > -1E-5;
+      
+      hos3 = freesetinequ.Get(i, 1) * p3.X() +
+	freesetinequ.Get(i, 2) * p3.Y() +
+	freesetinequ.Get(i, 3) * p3.Z() +
+	freesetinequ.Get(i, 4) > -1E-5;
+      
+      if (hos1 && hos2 && hos3) return 0;
+      
+      if (hos1) os1 = 1;
+      if (hos2) os2 = 1;
+      if (hos3) os3 = 1;
+      
+      if (hos1 || hos2 || hos3) activefaces.Append (i);
+    }
+  
+  if (!os1 || !os2 || !os3) return 1;
+
+  v1x = p2.X() - p1.X();
+  v1y = p2.Y() - p1.Y();
+  v1z = p2.Z() - p1.Z();
+
+  v2x = p3.X() - p1.X();
+  v2y = p3.Y() - p1.Y();
+  v2z = p3.Z() - p1.Z();
+
+  n.X() = v1y * v2z - v1z * v2y;
+  n.Y() = v1z * v2x - v1x * v2z;
+  n.Z() = v1x * v2y - v1y * v2x;
+  n /= n.Length();
+
+  allleft = allright = 1;
+  for (i = 1; i <= transfreezone.Size() && (allleft || allright); i++)
+    {
+      const Point3d & p = transfreezone.Get(i);
+      float scal = (p.X() - p1.X()) * n.X() +
+	(p.Y() - p1.Y()) * n.Y() +
+	(p.Z() - p1.Z()) * n.Z();
+
+      if ( scal >  1E-8 ) allleft = 0;
+      if ( scal < -1E-8 ) allright = 0;
+    }
+
+  if (allleft || allright) return 0;
+
+
+  lam1old = lam2old = lam1 = lam2 = 1.0 / 3.0;
+
+
+  //  testout << endl << endl << "Start minimizing" << endl;
+
+  it = 0;
+  int minit;
+  minit = 1000;
+  fold = 1E10;
+
+
+
+  while (1)
+    {
+      it++;
+
+      if (it > 1000) return -1;
+
+      if (lam1 < 0) lam1 = 0;
+      if (lam2 < 0) lam2 = 0;
+      if (lam1 + lam2 > 1) lam1 = 1 - lam2;
+
+      if (it > minit)
+	{
+	  (*testout) << "it = " << it << endl;
+	  (*testout) << "lam1/2 = " << lam1 << "  " << lam2 << endl;
+	}
+
+      hpx = p1.X() + lam1 * v1x + lam2 * v2x;
+      hpy = p1.Y() + lam1 * v1y + lam2 * v2y;
+      hpz = p1.Z() + lam1 * v1z + lam2 * v2z;
+
+      f = 0;
+
+      h11 = h12 = h22 = dflam1 = dflam2 = 0;
+      cntout = 0;
+
+      isin = 1;
+
+      for (i = 1; i <= activefaces.Size(); i++)
+	{
+	  ii = activefaces.Get(i);
+
+	  hf = freesetinequ.Get(ii, 1) * hpx +
+	    freesetinequ.Get(ii, 2) * hpy +
+	    freesetinequ.Get(ii, 3) * hpz +
+	    freesetinequ.Get(ii, 4);
+
+	  if (hf > -1E-7) isin = 0;
+
+	  hf += 1E-4;
+	  if (hf > 0)
+	    {
+	      f += hf * hf;
+
+	      v1n = freesetinequ.Get(ii, 1) * v1x +
+		freesetinequ.Get(ii, 2) * v1y +
+		freesetinequ.Get(ii, 3) * v1z;
+	      v2n = freesetinequ.Get(ii, 1) * v2x +
+		freesetinequ.Get(ii, 2) * v2y +
+		freesetinequ.Get(ii, 3) * v2z;
+
+	      h11 += 2 * v1n * v1n;
+	      h12 += 2 * v1n * v2n;
+	      h22 += 2 * v2n * v2n;
+	      dflam1 += 2 * hf * v1n;
+	      dflam2 += 2 * hf * v2n;
+	      cntout++;
+	    }
+	}
+
+      if (isin) return 1;
+
+      if (it > minit)
+	{
+	  (*testout) << "f = " << f
+		     << "  dfdlam = " << dflam1 << "  " << dflam2 << endl;
+	  (*testout) << "h = " << h11 << "  " << h12 << "  " << h22 << endl;
+	  (*testout) << "active: " << cntout << endl;
+	  (*testout) << "lam1-lam1old = " << (lam1 - lam1old) << endl;
+	  (*testout) << "lam2-lam2old = " << (lam2 - lam2old) << endl;
+	}
+
+
+      if (f >= fold)
+	{
+	  lam1 = 0.100000000000000 * lam1 + 0.9000000000000000 * lam1old;
+	  lam2 = 0.100000000000000 * lam2 + 0.9000000000000000 * lam2old;
+	}
+      else
+	{
+	  lam1old = lam1;
+	  lam2old = lam2;
+	  fold = f;
+
+
+	  if (f < 1E-9) return 1;
+
+	  h11 += 1E-10;
+	  h22 += 1E-10;
+	  c1 = - ( h22 * dflam1 - h12 * dflam2) / (h11 * h22 - h12 * h12);
+	  c2 = - (-h12 * dflam1 + h11 * dflam2) / (h11 * h22 - h12 * h12);
+	  alpha = 1;
+
+
+	  if (it > minit)
+	    (*testout) << "c1/2 = " << c1 << "  " << c2 << endl;
+
+	  act1 = lam1 <= 1E-6 && c1 <= 0;
+	  act2 = lam2 <= 1E-6 && c2 <= 0;
+	  act3 = lam1 + lam2 >= 1 - 1E-6 && c1 + c2 >= 0;
+
+	  if (it > minit)
+	    (*testout) << "act1,2,3 = " << act1 << act2 << act3 << endl;
+
+	  if (act1 && act2 || act1 && act3 || act2 && act3) return 0;
+
+	  if (act1)
+	    {
+	      c1 = 0;
+	      c2 = - dflam2 / h22;
+	    }
+
+	  if (act2)
+	    {
+	      c1 = - dflam1 / h11;
+	      c2 = 0;
+	    }
+
+	  if (act3)
+	    {
+	      c1 = - (dflam1 - dflam2) / (h11 + h22 - 2 * h12);
+	      c2 = -c1;
+	    }
+
+	  if (it > minit)
+	    (*testout) << "c1/2 now = " << c1 << "  " << c2 << endl;
+
+
+	  if (f > 100 * sqrt (sqr (c1) + sqr (c2))) return 0;
+
+
+	  if (lam1 + alpha * c1 < 0 && !act1)
+	    alpha = -lam1 / c1;
+	  if (lam2 + alpha * c2 < 0 && !act2)
+	    alpha = -lam2 / c2;
+	  if (lam1 + lam2 + alpha * (c1 + c2) > 1 && !act3)
+	    alpha = (1 - lam1 - lam2) / (c1 + c2);
+
+	  if (it > minit)
+	    (*testout) << "alpha = " << alpha << endl;
+
+	  lam1 += alpha * c1;
+	  lam2 += alpha * c2;
+	}
+    }
+}
+
+
+
+
+int vnetrule :: IsQuadInFreeZone (const Point3d & p1, 
+				  const Point3d & p2,
+				  const Point3d & p3, 
+				  const Point3d & p4, 
+				  const ARRAY<int> & pi, int newone)
+{
+  int fs;
+  int infreeset, cannot = 0;
+
+
+  static ARRAY<int> pfi(4), pfi2(4);
+
+  // convert from local index to freeset index
+  int i, j;
+  for (i = 1; i <= 4; i++)
+    {
+      pfi.Elem(i) = 0;
+      if (pi.Get(i))
+	{
+	  for (j = 1; j <= freezonepi.Size(); j++)
+	    if (freezonepi.Get(j) == pi.Get(i))
+	      pfi.Elem(i) = j;
+	}
+    }
+
+  for (fs = 1; fs <= freesets.Size(); fs++)
+    {
+      const ARRAY<int> & freeseti = *freesets.Get(fs);
+      for (i = 1; i <= 4; i++)
+	{
+	  pfi2.Elem(i) = 0;
+	  for (j = 1; j <= freeseti.Size(); j++)
+	    if (pfi.Get(i) == freeseti.Get(j))
+	      pfi2.Elem(i) = pfi.Get(i);
+	}
+
+      infreeset = IsQuadInFreeSet(p1, p2, p3, p4, fs, pfi2, newone);
+      if (infreeset == 1) return 1;
+      if (infreeset == -1) cannot = -1;
+    }
+  
+  return cannot;
+}
+
+
+int vnetrule :: IsQuadInFreeSet (const Point3d & p1, const Point3d & p2,
+				 const Point3d & p3, const Point3d & p4, 
+				 int fs, const ARRAY<int> & pi, int newone)
+{
+  int i;
+  
+  int cnt = 0;
+  for (i = 1; i <= 4; i++)
+    if (pi.Get(i)) cnt++;
+  
+  /*
+  (*testout) << "test quad in freeset: " << p1 << " - " << p2 << " - " << p3 << " - " << p4 << endl;
+  (*testout) << "pi = ";
+  for (i = 1; i <= pi.Size(); i++)
+    (*testout) << pi.Get(i) << " ";
+  (*testout) << endl;
+  (*testout) << "cnt = " << cnt  << endl;
+  */
+  if (cnt == 4)
+    {
+      return 1;
+    }
+
+  if (cnt == 3)
+    {
+      return 1;
+    }
+
+  static ARRAY<int> pi3(3);
+  int res;
+
+  pi3.Elem(1) = pi.Get(1);
+  pi3.Elem(2) = pi.Get(2);
+  pi3.Elem(3) = pi.Get(3);
+  res = IsTriangleInFreeSet (p1, p2, p3, fs, pi3, newone);
+  if (res) return res;
+
+
+  pi3.Elem(1) = pi.Get(2);
+  pi3.Elem(2) = pi.Get(3);
+  pi3.Elem(3) = pi.Get(4);
+  res = IsTriangleInFreeSet (p2, p3, p4, fs, pi3, newone);
+  if (res) return res;
+
+  pi3.Elem(1) = pi.Get(3);
+  pi3.Elem(2) = pi.Get(4);
+  pi3.Elem(3) = pi.Get(1);
+  res = IsTriangleInFreeSet (p3, p4, p1, fs, pi3, newone);
+  if (res) return res;
+
+  pi3.Elem(1) = pi.Get(4);
+  pi3.Elem(2) = pi.Get(1);
+  pi3.Elem(3) = pi.Get(2);
+  res = IsTriangleInFreeSet (p4, p1, p2, fs, pi3, newone);
+  return res;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+float vnetrule :: CalcPointDist (int pi, const Point3d & p) const
+{
+  float dx = p.X() - points.Get(pi).X();
+  float dy = p.Y() - points.Get(pi).Y();
+  float dz = p.Z() - points.Get(pi).Z();
+  
+  //  const threefloat * tf = &tolerances.Get(pi);
+  //  return tf->f1 * dx * dx + tf->f2 * dx * dy + tf->f3 * dy * dy;
+  return tolerances.Get(pi) * (dx * dx + dy * dy + dz * dz);
+}
+
+
+int vnetrule :: TestOk () const
+{
+  ARRAY<int> cntpused(points.Size());
+  ARRAY<int> edge1, edge2;
+  ARRAY<int> delf(faces.Size());
+  int i, j, k;
+  int pi1, pi2;
+  int found;
+
+  for (i = 1; i <= cntpused.Size(); i++)
+    cntpused.Elem(i) = 0;
+  for (i = 1; i <= faces.Size(); i++)
+    delf.Elem(i) = 0;
+  for (i = 1; i <= delfaces.Size(); i++)
+    delf.Elem(delfaces.Get(i)) = 1;
+
+
+  for (i = 1; i <= faces.Size(); i++)
+    if (delf.Get(i) || i > noldf)
+      for (j = 1; j <= faces.Get(i).GetNP(); j++)
+        cntpused.Elem(faces.Get(i).PNum(j))++;
+
+  for (i = 1; i <= cntpused.Size(); i++)
+    if (cntpused.Get(i) > 0 && cntpused.Get(i) < 2)
+      {
+	return 0;
+      }
+
+
+  //  (*testout) << endl;
+  for (i = 1; i <= faces.Size(); i++)
+    {
+      //      (*testout) << "face " << i << endl;
+      for (j = 1; j <= faces.Get(i).GetNP(); j++)
+	{
+	  pi1 = 0; pi2 = 0;
+	  if (delf.Get(i))
+	    {
+	      pi1 = faces.Get(i).PNumMod(j);
+	      pi2 = faces.Get(i).PNumMod(j+1);
+	    }
+	  if (i > noldf)
+	    {
+	      pi1 = faces.Get(i).PNumMod(j+1);
+	      pi2 = faces.Get(i).PNumMod(j);
+	    }
+
+	  found = 0;
+	  if (pi1)
+	    {
+	      for (k = 1; k <= edge1.Size(); k++)
+		if (edge1.Get(k) == pi1 && edge2.Get(k) == pi2)
+		  {
+		    found = 1;
+		    edge1.DeleteElement(k);
+		    edge2.DeleteElement(k);
+		    k--;
+		    //		    (*testout) << "Del edge " << pi1 << "-" << pi2 << endl;
+		  }
+	      if (!found)
+		{
+		  edge1.Append (pi2);
+		  edge2.Append (pi1);
+		  //		  (*testout) << "Add edge " << pi1 << "-" << pi2 << endl;
+		}
+	    }
+	}
+    }
+
+
+  if (edge1.Size() > 0)
+    {
+      return 0;
+    }
+
+  /*
+    cntpused.SetSize(freezone.Size());
+    for (i = 1; i <= cntpused.Size(); i++)
+    cntpused[i] = 0;
+
+    for (i = 1; i <= freefaces.Size(); i++)
+    {
+    cntpused[freefaces[i].i1]++;
+    cntpused[freefaces[i].i2]++;
+    cntpused[freefaces[i].i3]++;
+    }
+
+    for (i = 1; i <= cntpused.Size(); i++)
+    if (cntpused[i] < 3)
+    {
+    (*mycout) << "Fall 3" << endl;
+    return 0;
+    }
+
+
+
+    for (i = 1; i <= freefaces.Size(); i++)
+    {
+    for (j = 1; j <= 3; j++)
+    {
+    if (j == 1)
+    {
+    pi1 = freefaces[i].i1;
+    pi2 = freefaces[i].i2;
+    }
+    if (j == 2)
+    {
+    pi1 = freefaces[i].i2;
+    pi2 = freefaces[i].i3;
+    }
+    if (j == 3)
+    {
+    pi1 = freefaces[i].i3;
+    pi2 = freefaces[i].i1;
+    }
+
+    found = 0;
+    for (k = 1; k <= edge1.Size(); k++)
+    if (edge1[k] == pi1 && edge2[k] == pi2)
+    {
+    found = 1;
+    edge1.DeleteElement(k);
+    edge2.DeleteElement(k);
+    k--;
+    }
+
+    if (!found)
+    {
+    edge1.Append (pi2);
+    edge2.Append (pi1);
+    }
+    }
+    }
+
+    if (edge1.Size() > 0)
+    {
+    (*mycout) << "Fall 4" << endl;
+    return 0;
+    }
+    */
+  return 1;
+}
+
+
+int vnetrule :: IsDelFace (int fn) const
+{
+  int i;
+  for (i = 1; i <= GetNDelF(); i++)
+    if (GetDelFace(i) == fn) return 1;
+  return 0;
+}
+
+}
diff --git a/Netgen/libsrc/meshing/parser2.cpp b/Netgen/libsrc/meshing/parser2.cpp
new file mode 100644
index 0000000000..402207c259
--- /dev/null
+++ b/Netgen/libsrc/meshing/parser2.cpp
@@ -0,0 +1,550 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+namespace netgen
+{
+
+
+void LoadMatrixLine (istream & ist, DenseMatrix & m, int line)
+{
+  char ch;
+  int pnum;
+  float f;
+
+  ist >> ch;
+  while (ch != '}')
+    {
+      ist.putback (ch);
+      ist >> f;
+      ist >> ch;
+      ist >> pnum;
+
+      if (ch == 'x' || ch == 'X')
+	m.Elem(line, 2 * pnum - 1) = f;
+      if (ch == 'y' || ch == 'Y')
+	m.Elem(line, 2 * pnum) = f;
+
+      ist >> ch;
+      if (ch == ',')
+	ist >> ch;
+    }
+}
+
+
+void netrule :: LoadRule (istream & ist)
+{
+  char buf[256];
+  char ch;
+  Point2d p;
+  INDEX_2 lin;
+  int i, j;
+  DenseMatrix tempoldutonewu(20, 20), tempoldutofreearea(20, 20),
+    tempoldutofreearealimit(20, 20);
+
+  tempoldutonewu = 0;
+  tempoldutofreearea = 0;
+  tempoldutofreearealimit = 0;
+
+  noldp = 0;
+  noldl = 0;
+
+  ist.get (buf, sizeof(buf), '"');
+  ist.get (ch);
+  ist.get (buf, sizeof(buf), '"');
+  ist.get (ch);
+
+  delete name;
+  name = new char[strlen (buf) + 1];
+  strcpy (name, buf);
+  //  (*mycout) << "Rule " << name << " found." << endl;
+
+  do
+    {
+      ist >> buf;
+
+      if (strcmp (buf, "quality") == 0)
+
+	{
+	  ist >> quality;
+	}
+
+      else if (strcmp (buf, "mappoints") == 0)
+	{
+	  ist >> ch;
+
+	  while (ch == '(')
+	    {
+	      ist >> p.X();
+	      ist >> ch;    // ','
+	      ist >> p.Y();
+	      ist >> ch;    // ')'
+
+	      points.Append (p);
+	      noldp++;
+
+	      tolerances.SetSize (noldp);
+	      tolerances.Elem(noldp).f1 = 0;
+	      tolerances.Elem(noldp).f2 = 0;
+	      tolerances.Elem(noldp).f3 = 0;
+
+	      ist >> ch;
+	      while (ch != ';')
+		{
+		  if (ch == '{')
+		    {
+		      ist >> tolerances.Elem(noldp).f1;
+		      ist >> ch;  // ','
+		      ist >> tolerances.Elem(noldp).f2;
+		      ist >> ch;  // ','
+		      ist >> tolerances.Elem(noldp).f3;
+		      ist >> ch;  // '}'
+		    }
+		  else if (ch == 'd')
+		    {
+		      //            delpoints.Append (noldp);
+		      ist >> ch; // 'e'
+		      ist >> ch; // 'l'
+		    }
+
+		  ist >> ch;
+		}
+
+	      ist >> ch;
+	    }
+
+	  ist.putback (ch);
+	}
+
+
+      else if (strcmp (buf, "maplines") == 0)
+	{
+	  ist >> ch;
+
+	  while (ch == '(')
+	    {
+	      ist >> lin.I1();
+	      ist >> ch;    // ','
+	      ist >> lin.I2();
+	      ist >> ch;    // ')'
+
+	      lines.Append (lin);
+	      linevecs.Append (points.Get(lin.I2()) - points.Get(lin.I1()));
+	      noldl++;
+	      linetolerances.SetSize (noldl);
+	      linetolerances.Elem(noldl).f1 = 0;
+	      linetolerances.Elem(noldl).f2 = 0;
+	      linetolerances.Elem(noldl).f3 = 0;
+
+	      ist >> ch;
+	      while (ch != ';')
+		{
+		  if (ch == '{')
+		    {
+		      ist >> linetolerances.Elem(noldl).f1;
+		      ist >> ch;  // ','
+		      ist >> linetolerances.Elem(noldl).f2;
+		      ist >> ch;  // ','
+		      ist >> linetolerances.Elem(noldl).f3;
+		      ist >> ch;  // '}'
+		    }
+		  else if (ch == 'd')
+		    {
+		      dellines.Append (noldl);
+		      ist >> ch; // 'e'
+		      ist >> ch; // 'l'
+		    }
+
+		  ist >> ch;
+		}
+
+	      ist >> ch;
+	    }
+
+	  ist.putback (ch);
+	}
+
+      else if (strcmp (buf, "newpoints") == 0)
+	{
+	  ist >> ch;
+
+	  while (ch == '(')
+	    {
+	      ist >> p.X();
+	      ist >> ch;    // ','
+	      ist >> p.Y();
+	      ist >> ch;    // ')'
+
+	      points.Append (p);
+
+	      ist >> ch;
+	      while (ch != ';')
+		{
+		  if (ch == '{')
+		    {
+		      LoadMatrixLine (ist, tempoldutonewu,
+				      2 * (points.Size()-noldp) - 1);
+
+		      ist >> ch; // '{'
+		      LoadMatrixLine (ist, tempoldutonewu,
+				      2 * (points.Size()-noldp));
+		    }
+
+		  ist >> ch;
+		}
+
+	      ist >> ch;
+	    }
+
+	  ist.putback (ch);
+	}
+
+      else if (strcmp (buf, "newlines") == 0)
+	{
+	  ist >> ch;
+
+	  while (ch == '(')
+	    {
+	      ist >> lin.I1();
+	      ist >> ch;    // ','
+	      ist >> lin.I2();
+	      ist >> ch;    // ')'
+
+	      lines.Append (lin);
+	      linevecs.Append (points.Get(lin.I2()) - points.Get(lin.I1()));
+
+	      ist >> ch;
+	      while (ch != ';')
+		{
+		  ist >> ch;
+		}
+
+	      ist >> ch;
+	    }
+
+	  ist.putback (ch);
+	}
+
+      else if (strcmp (buf, "freearea") == 0)
+	{
+	  ist >> ch;
+
+	  while (ch == '(')
+	    {
+	      ist >> p.X();
+	      ist >> ch;    // ','
+	      ist >> p.Y();
+	      ist >> ch;    // ')'
+
+	      freezone.Append (p);
+	      freezonelimit.Append (p);
+
+	      ist >> ch;
+	      while (ch != ';')
+		{
+		  if (ch == '{')
+		    {
+		      LoadMatrixLine (ist, tempoldutofreearea,
+				      2 * freezone.Size() - 1);
+
+		      ist >> ch; // '{'
+		      LoadMatrixLine (ist, tempoldutofreearea,
+				      2 * freezone.Size());
+		    }
+
+		  ist >> ch;
+		}
+
+	      ist >> ch;
+	    }
+
+	  for (i = 1; i <= tempoldutofreearealimit.Height(); i++)
+	    for (j = 1; j <= tempoldutofreearealimit.Width(); j++)
+	      tempoldutofreearealimit.Elem(i,j) =
+		tempoldutofreearea.Elem(i,j);
+
+
+	  ist.putback (ch);
+	}    
+      else if (strcmp (buf, "freearea2") == 0)
+	{
+	  ist >> ch;
+	  int freepi = 0;
+	  tempoldutofreearealimit = 0;
+
+	  while (ch == '(')
+	    {
+	      freepi++;
+
+	      ist >> p.X();
+	      ist >> ch;    // ','
+	      ist >> p.Y();
+	      ist >> ch;    // ')'
+
+	      freezonelimit.Elem(freepi) = p;
+	  
+	      ist >> ch;
+	      while (ch != ';')
+		{
+		  if (ch == '{')
+		    {
+		      LoadMatrixLine (ist, tempoldutofreearealimit,
+				      2 * freepi - 1);
+
+		      ist >> ch; // '{'
+		      LoadMatrixLine (ist, tempoldutofreearealimit,
+				      2 * freepi);
+		    }
+
+		  ist >> ch;
+		}
+	  
+	      ist >> ch;
+	    }
+
+	  ist.putback (ch);
+	}
+
+      else if (strcmp (buf, "elements") == 0)
+	{
+	  ist >> ch;
+
+	  while (ch == '(')
+	    {
+	      elements.Append (Element2d());
+
+	      ist >> elements.Last().PNum(1);
+	      ist >> ch;    // ','
+	  
+	      if (ch == ',')
+		{
+		  ist >> elements.Last().PNum(2);
+		  ist >> ch;    // ','
+		}
+	      if (ch == ',')
+		{
+		  ist >> elements.Last().PNum(3);
+		  ist >> ch;    // ','
+		}
+	      if (ch == ',')
+		{
+		  elements.Last().SetType (QUAD);
+		  ist >> elements.Last().PNum(4);
+		  ist >> ch;    // ','
+		  
+		  // const Element2d & el = elements.Last();
+		  /*
+		  orientations.Append (threeint(el.PNum(1), el.PNum(2), el.PNum(3)));
+		  orientations.Append (threeint(el.PNum(2), el.PNum(3), el.PNum(4)));
+		  orientations.Append (threeint(el.PNum(3), el.PNum(4), el.PNum(1)));
+		  orientations.Append (threeint(el.PNum(4), el.PNum(1), el.PNum(2)));
+		  */
+		}
+
+	      ist >> ch;
+	      while (ch != ';')
+		{
+		  ist >> ch;
+		}
+
+	      ist >> ch;
+	    }
+
+	  ist.putback (ch);
+	}
+
+      else if (strcmp (buf, "orientations") == 0)
+
+	{
+	  ist >> ch;
+
+	  while (ch == '(')
+	    {
+	      //        threeint a = threeint();
+	      orientations.Append (threeint());
+
+	      ist >> orientations.Last().i1;
+	      ist >> ch;    // ','
+	      ist >> orientations.Last().i2;
+	      ist >> ch;    // ','
+	      ist >> orientations.Last().i3;
+	      ist >> ch;    // ','
+
+	      ist >> ch;
+	      while (ch != ';')
+		{
+		  ist >> ch;
+		}
+
+	      ist >> ch;
+	    }
+
+	  ist.putback (ch);
+	}
+
+      else if (strcmp (buf, "endrule") != 0)
+	{
+	  PrintSysError ("Parser error, unknown token ", buf);
+	}
+    }
+  while (!ist.eof() && strcmp (buf, "endrule") != 0);
+
+  oldutonewu.SetSize (2 * (points.Size() - noldp), 2 * noldp);
+  oldutofreearea.SetSize (2 * freezone.Size(), 2 * noldp);
+  oldutofreearealimit.SetSize (2 * freezone.Size(), 2 * noldp);
+
+  for (i = 1; i <= oldutonewu.Height(); i++)
+    for (j = 1; j <= oldutonewu.Width(); j++)
+      oldutonewu.Elem(i, j) = tempoldutonewu.Elem(i, j);
+
+  for (i = 1; i <= oldutofreearea.Height(); i++)
+    for (j = 1; j <= oldutofreearea.Width(); j++)
+      oldutofreearea.Elem(i, j) = tempoldutofreearea.Elem(i, j);
+
+  for (i = 1; i <= oldutofreearea.Height(); i++)
+    for (j = 1; j <= oldutofreearea.Width(); j++)
+      oldutofreearealimit.Elem(i, j) = tempoldutofreearealimit.Elem(i, j);
+
+  freesetinequ.SetSize (freezone.Size());
+
+
+
+  {
+    char ok;
+    int minn;
+    ARRAY<int> pnearness (noldp);
+
+    for (i = 1; i <= pnearness.Size(); i++)
+      pnearness.Elem(i) = 1000;
+
+    for (j = 1; j <= 2; j++)
+      pnearness.Elem(GetPointNr (1, j)) = 0;
+
+    do
+      {
+	ok = 1;
+
+	for (i = 1; i <= noldl; i++)
+	  {
+	    minn = 1000;
+	    for (j = 1; j <= 2; j++)
+	      minn = min2 (minn, pnearness.Get(GetPointNr (i, j)));
+
+	    for (j = 1; j <= 2; j++)
+	      if (pnearness.Get(GetPointNr (i, j)) > minn+1)
+		{
+		  ok = 0;
+		  pnearness.Elem(GetPointNr (i, j)) = minn+1;
+		}
+	  }
+      }
+    while (!ok);
+
+    lnearness.SetSize (noldl);
+
+    for (i = 1; i <= noldl; i++)
+      {
+	lnearness.Elem(i) = 0;
+	for (j = 1; j <= 2; j++)
+	  lnearness.Elem(i) += pnearness.Get(GetPointNr (i, j));
+      }
+  }
+
+}
+
+
+
+
+extern const char * triarules[];
+extern const char * quadrules[];
+
+void Meshing2 :: LoadRules (const char * filename)
+{
+  char buf[256];
+  istream * ist;
+  char *tr1 = NULL;
+
+  /*
+  ifstream ist (filename);
+  if (!ist.good())
+    {
+      cerr << "Rule description file " << filename << " not found" << endl;
+      exit (1);
+    }
+  */
+
+
+  if (filename)
+    {
+      //      (*mycout) << "rule-filename = " << filename << endl;
+      ist = new ifstream (filename);
+    }
+  else 
+    {
+      /* connect tetrules to one string */
+      const char ** hcp;
+
+      if (!mparam.quad)
+	{
+	  hcp = triarules;
+	  PrintMessage (3, "load internal triangle rules");
+	}
+      else
+	{
+	  hcp = quadrules;
+	  PrintMessage (3, "load internal quad rules");
+	  // LoadRules ("rules/quad.rls");
+	}
+
+      int len = 0;
+      while (*hcp)
+	{
+	  len += strlen (*hcp);
+	  hcp++;
+	}
+      tr1 = new char[len+1];
+      tr1[0] = 0;
+
+
+      if (!mparam.quad)
+	hcp = triarules;
+      else
+	hcp = quadrules;
+
+
+      char * tt1 = tr1;
+      while (*hcp)
+	{
+	  strcat (tt1, *hcp);
+	  tt1 += strlen (*hcp);
+	  hcp++;
+	}
+
+      ist = new istringstream (tr1);
+    }
+
+
+  if (!ist->good())
+    {
+      cerr << "Rule description file " << filename << " not found" << endl;
+      delete ist;
+      exit (1);
+    }
+    
+  while (!ist->eof())
+    {
+      buf[0] = 0;
+      (*ist) >> buf;
+
+      if (strcmp (buf, "rule") == 0)
+	{
+	  netrule * rule = new netrule;
+	  rule -> LoadRule(*ist);
+	  rules.Append (rule);
+	}
+    }
+
+  delete ist;
+  delete [] tr1;
+}
+
+}
diff --git a/Netgen/libsrc/meshing/parser3.cpp b/Netgen/libsrc/meshing/parser3.cpp
new file mode 100644
index 0000000000..7bf6e513ac
--- /dev/null
+++ b/Netgen/libsrc/meshing/parser3.cpp
@@ -0,0 +1,987 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+namespace netgen
+{
+
+extern const char * tetrules[];
+
+void LoadVMatrixLine (istream & ist, DenseMatrix & m, int line)
+{
+  char ch;
+  int pnum;
+  float f;
+  
+  ist >> ch;
+  while (ch != '}')
+    {
+      ist.putback (ch);
+      ist >> f;
+      ist >> ch;
+      ist >> pnum;
+      
+      if (ch == 'x' || ch == 'X')
+	m.Elem(line, 3 * pnum - 2) = f;
+      if (ch == 'y' || ch == 'Y')
+	m.Elem(line, 3 * pnum - 1) = f;
+      if (ch == 'z' || ch == 'Z')
+	m.Elem(line, 3 * pnum    ) = f;
+
+      if (ch == 'p' || ch == 'P')
+	{
+	  m.Elem(line  , 3 * pnum-2) = f;
+	  m.Elem(line+1, 3 * pnum-1) = f;
+	  m.Elem(line+2, 3 * pnum  ) = f;
+	}
+
+      ist >> ch;
+      if (ch == ',')
+	ist >> ch;
+    }
+}
+
+
+
+
+
+int vnetrule :: NeighbourTrianglePoint (const threeint & t1, const threeint & t2) const
+{
+  ARRAY<int> tr1(3);
+  ARRAY<int> tr2(3);
+  tr1.Elem(1)=t1.i1;
+  tr1.Elem(2)=t1.i2;
+  tr1.Elem(3)=t1.i3;
+  tr2.Elem(1)=t2.i1;
+  tr2.Elem(2)=t2.i2;
+  tr2.Elem(3)=t2.i3;
+
+
+  int ret=0;
+
+  for (int i=1; i<=3; i++)
+    {
+      for (int j=1; j<=3; j++)
+	{
+	  if ((tr1.Get(i)==tr2.Get(j) && tr1.Get((i%3)+1)==tr2.Get((j%3)+1)) ||
+              (tr1.Get(i)==tr2.Get((j%3)+1) && tr1.Get((i%3)+1)==tr2.Get(j)))
+	    {ret = tr2.Get((j+1)%3+1);}
+	}      
+    }
+
+  return ret;
+
+}
+
+void vnetrule :: LoadRule (istream & ist)
+{
+  char buf[256];
+  char ch, ok;
+  Point3d p;
+  Element2d face;
+  int i, j, i1, i2, i3, fs, ii, ii1, ii2, ii3;
+  twoint edge;
+  DenseMatrix tempoldutonewu(30, 20), 
+    tempoldutofreezone(30, 20),
+    tempoldutofreezonelimit(30, 20),
+    tfz(20, 20),
+    tfzl(20, 20);
+
+  tempoldutonewu = 0;
+  tempoldutofreezone = 0;
+  tfz = 0;
+  tfzl = 0;
+
+
+  noldp = 0;
+  noldf = 0;
+
+  ist.get (buf, sizeof(buf), '"');
+  ist.get (ch);
+  ist.get (buf, sizeof(buf), '"');
+  ist.get (ch);
+
+  name = new char[strlen (buf) + 1];
+  strcpy (name, buf);
+  //  (*mycout) << "Rule " << name << " found." << endl;
+
+  do
+    {
+      ist >> buf;
+
+      if (strcmp (buf, "quality") == 0)
+
+	{
+	  ist >> quality;
+	}
+
+      else if (strcmp (buf, "flags") == 0)
+	{
+	  ist >> ch;
+	  while (ch != ';')
+	    {
+	      flags.Append (ch);
+	      ist >> ch;
+	    }
+	}
+
+      else if (strcmp (buf, "mappoints") == 0)
+	{
+	  ist >> ch;
+
+	  while (ch == '(')
+	    {
+	      ist >> p.X();
+	      ist >> ch;    // ','
+	      ist >> p.Y();
+	      ist >> ch;    // ','
+	      ist >> p.Z();
+	      ist >> ch;    // ')'
+
+	      points.Append (p);
+	      noldp++;
+
+	      tolerances.SetSize (noldp);
+	      tolerances.Elem(noldp) = 1;
+
+	      ist >> ch;
+	      while (ch != ';')
+		{
+		  if (ch == '{')
+		    {
+		      ist >> tolerances.Elem(noldp);
+		      ist >> ch;  // '}'
+		    }
+
+		  ist >> ch;
+		}
+
+	      ist >> ch;
+	    }
+
+	  ist.putback (ch);
+	}
+
+
+      else if (strcmp (buf, "mapfaces") == 0)
+	{
+	  ist >> ch;
+
+	  while (ch == '(')
+	    {
+	      face.SetType(TRIG);
+	      ist >> face.PNum(1);
+	      ist >> ch;    // ','
+	      ist >> face.PNum(2);
+	      ist >> ch;    // ','
+	      ist >> face.PNum(3);
+	      ist >> ch;    // ')' or ','
+	      if (ch == ',')
+		{
+		  face.SetType(QUAD);
+		  ist >> face.PNum(4);
+		  ist >> ch;    // ')' 
+		}
+	      faces.Append (face);
+	      noldf++;
+
+	      ist >> ch;
+	      while (ch != ';')
+		{
+		  if (ch == 'd')
+		    {
+		      delfaces.Append (noldf);
+		      ist >> ch; // 'e'
+		      ist >> ch; // 'l'
+		    }
+
+		  ist >> ch;
+		}
+
+	      ist >> ch;
+	    }
+
+	  ist.putback (ch);
+	}
+
+      else if (strcmp (buf, "mapedges") == 0)
+	{
+	  ist >> ch;
+
+	  while (ch == '(')
+	    {
+	      ist >> edge.i1;
+	      ist >> ch;    // ','
+	      ist >> edge.i2;
+	      ist >> ch;    // ')'
+
+	      edges.Append (edge);
+
+	      ist >> ch;
+	      while (ch != ';')
+		{
+		  ist >> ch;
+		}
+
+	      ist >> ch;
+	    }
+
+	  ist.putback (ch);
+	}
+
+
+      else if (strcmp (buf, "newpoints") == 0)
+	{
+	  ist >> ch;
+
+	  while (ch == '(')
+	    {
+	      ist >> p.X();
+	      ist >> ch;    // ','
+	      ist >> p.Y();
+	      ist >> ch;    // ','
+	      ist >> p.Z();
+	      ist >> ch;    // ')'
+
+	      points.Append (p);
+
+	      ist >> ch;
+	      while (ch != ';')
+		{
+		  if (ch == '{')
+		    {
+		      LoadVMatrixLine (ist, tempoldutonewu,
+				       3 * (points.Size()-noldp) - 2);
+
+		      ist >> ch; // '{'
+		      LoadVMatrixLine (ist, tempoldutonewu,
+				       3 * (points.Size()-noldp) - 1);
+
+		      ist >> ch; // '{'
+		      LoadVMatrixLine (ist, tempoldutonewu,
+				       3 * (points.Size()-noldp)    );
+		    }
+
+		  ist >> ch;
+		}
+
+	      ist >> ch;
+	    }
+
+	  ist.putback (ch);
+	}
+
+      else if (strcmp (buf, "newfaces") == 0)
+	{
+	  ist >> ch;
+
+	  while (ch == '(')
+	    {
+	      face.SetType(TRIG);
+	      ist >> face.PNum(1);
+	      ist >> ch;    // ','
+	      ist >> face.PNum(2);
+	      ist >> ch;    // ','
+	      ist >> face.PNum(3);
+	      ist >> ch;    // ')' or ','
+	      if (ch == ',')
+		{
+		  face.SetType(QUAD);
+		  ist >> face.PNum(4);
+		  ist >> ch;    // ')' 
+		}
+	      faces.Append (face);
+
+	      ist >> ch;
+	      while (ch != ';')
+		{
+		  ist >> ch;
+		}
+
+	      ist >> ch;
+	    }
+
+	  ist.putback (ch);
+	}
+
+      else if (strcmp (buf, "freezone") == 0)
+	{
+	  ist >> ch;
+	
+	  while (ch == '(')
+	    {
+	      ist >> p.X();
+	      ist >> ch;    // ','
+	      ist >> p.Y();
+	      ist >> ch;    // ','
+	      ist >> p.Z();
+	      ist >> ch;    // ')'
+	    
+	      freezone.Append (p);
+	    
+	      ist >> ch;
+	      while (ch != ';')
+		{
+		  if (ch == '{')
+		    {
+		      LoadVMatrixLine (ist, tempoldutofreezone,
+				       3 * freezone.Size() - 2);
+		    
+		      ist >> ch; // '{'
+		      LoadVMatrixLine (ist, tempoldutofreezone,
+				       3 * freezone.Size() - 1);
+		    
+		      ist >> ch; // '{'
+		      LoadVMatrixLine (ist, tempoldutofreezone,
+				       3 * freezone.Size()    );
+		    }
+		
+		  ist >> ch;
+		}
+	    
+	      ist >> ch;
+	    }
+	
+	  ist.putback (ch);
+	}
+      else if (strcmp (buf, "freezone2") == 0)
+	{
+	  int i, j, k, nfp;
+	  Point3d p;
+
+	  nfp = 0;
+	  ist >> ch;
+
+	  DenseMatrix hm1(3, 50), hm2(50, 50), hm3(50, 50);
+	  hm3 = 0;
+
+	  while (ch == '{')
+	    {
+	      hm1 = 0;
+	      nfp++;
+	      LoadVMatrixLine (ist, hm1, 1);
+
+	      for (i = 1; i <= points.Size(); i++)
+		tfz.Elem(nfp, i) = hm1.Get(1, 3*i-2);
+
+
+	      p.X() = p.Y() = p.Z() = 0;
+	      for (i = 1; i <= points.Size(); i++)
+		{
+		  p.X() += hm1.Get(1, 3*i-2) * points.Get(i).X();
+		  p.Y() += hm1.Get(1, 3*i-2) * points.Get(i).Y();
+		  p.Z() += hm1.Get(1, 3*i-2) * points.Get(i).Z();
+		}
+	      freezone.Append (p);
+	      freezonelimit.Append (p);
+	    
+	      hm2 = 0;
+	      for (i = 1; i <= 3 * noldp; i++)
+		hm2.Elem(i, i) = 1;
+	      for (i = 1; i <= 3 * noldp; i++)
+		for (j = 1; j <= 3 * (points.Size() - noldp); j++)
+		  hm2.Elem(j + 3 * noldp, i) = tempoldutonewu.Get(j, i);
+		  
+	      for (i = 1; i <= 3; i++)
+		for (j = 1; j <= 3 * noldp; j++)
+		  {
+		    double sum = 0;
+		    for (k = 1; k <= 3 * points.Size(); k++)
+		      sum += hm1.Get(i, k) * hm2.Get(k, j);
+		  
+		    hm3.Elem(i + 3 * (nfp-1), j) = sum;
+		  }
+
+	      //	    (*testout) << "freepoint: " << p << endl;
+
+	      while (ch != ';')
+		ist >> ch; 
+
+	      ist >> ch;
+	    }
+
+	  tfzl = tfz;
+
+	  tempoldutofreezone = hm3;
+	  tempoldutofreezonelimit = hm3;
+	  ist.putback(ch);
+	}
+
+      else if (strcmp (buf, "freezonelimit") == 0)
+	{
+	  int i, j, k, nfp;
+	  Point3d p;
+
+	  nfp = 0;
+	  ist >> ch;
+
+	  DenseMatrix hm1(3, 50), hm2(50, 50), hm3(50, 50);
+	  hm3 = 0;
+
+	  while (ch == '{')
+	    {
+	      hm1 = 0;
+	      nfp++;
+	      LoadVMatrixLine (ist, hm1, 1);
+
+	      for (i = 1; i <= points.Size(); i++)
+		tfzl.Elem(nfp, i) = hm1.Get(1, 3*i-2);
+
+
+	      p.X() = p.Y() = p.Z() = 0;
+	      for (i = 1; i <= points.Size(); i++)
+		{
+		  p.X() += hm1.Get(1, 3*i-2) * points.Get(i).X();
+		  p.Y() += hm1.Get(1, 3*i-2) * points.Get(i).Y();
+		  p.Z() += hm1.Get(1, 3*i-2) * points.Get(i).Z();
+		}
+	      freezonelimit.Elem(nfp) = p;
+	    
+	      hm2 = 0;
+	      for (i = 1; i <= 3 * noldp; i++)
+		hm2.Elem(i, i) = 1;
+	      for (i = 1; i <= 3 * noldp; i++)
+		for (j = 1; j <= 3 * (points.Size() - noldp); j++)
+		  hm2.Elem(j + 3 * noldp, i) = tempoldutonewu.Get(j, i);
+		  
+	      for (i = 1; i <= 3; i++)
+		for (j = 1; j <= 3 * noldp; j++)
+		  {
+		    double sum = 0;
+		    for (k = 1; k <= 3 * points.Size(); k++)
+		      sum += hm1.Get(i, k) * hm2.Get(k, j);
+		  
+		    hm3.Elem(i + 3 * (nfp-1), j) = sum;
+		  }
+
+	      //	    (*testout) << "freepoint: " << p << endl;
+
+	      while (ch != ';')
+		ist >> ch; 
+
+	      ist >> ch;
+	    }
+
+	  tempoldutofreezonelimit = hm3;
+	  ist.putback(ch);
+	}
+
+      else if (strcmp (buf, "freeset") == 0)
+	{
+	  freesets.Append (new ARRAY<int>);
+
+	  ist >> ch;
+
+	  while (ch != ';')
+	    {
+	      ist.putback (ch);
+	      ist >> i;
+	      freesets.Last()->Append(i);
+	      ist >> ch;
+	    }
+	}
+
+      else if (strcmp (buf, "elements") == 0)
+	{
+	  ist >> ch;
+
+	  while (ch == '(')
+	    {
+	      elements.Append (Element(TET));
+
+	      //	      elements.Last().SetNP(1);
+	      ist >> elements.Last().PNum(1);
+	      ist >> ch;    // ','
+
+	      if (ch == ',')
+		{
+		  //		  elements.Last().SetNP(2);
+		  ist >> elements.Last().PNum(2);
+		  ist >> ch;    // ','
+		}
+	      if (ch == ',')
+		{
+		  //		  elements.Last().SetNP(3);
+		  ist >> elements.Last().PNum(3);
+		  ist >> ch;    // ','
+		}
+	      if (ch == ',')
+		{
+		  //		  elements.Last().SetNP(4);
+		  elements.Last().SetType(TET);
+		  ist >> elements.Last().PNum(4);
+		  ist >> ch;    // ','
+		}
+	      if (ch == ',')
+		{
+		  //		  elements.Last().SetNP(5);
+		  elements.Last().SetType(PYRAMID);
+		  ist >> elements.Last().PNum(5);
+		  ist >> ch;    // ','
+		}
+	      if (ch == ',')
+		{
+		  //		  elements.Last().SetNP(6);
+		  elements.Last().SetType(PRISM);
+		  ist >> elements.Last().PNum(6);
+		  ist >> ch;    // ','
+		}
+
+	      /*
+	      orientations.Append (fourint());
+	      orientations.Last().i1 = elements.Last().PNum(1);
+	      orientations.Last().i2 = elements.Last().PNum(2);
+	      orientations.Last().i3 = elements.Last().PNum(3);
+	      orientations.Last().i4 = elements.Last().PNum(4);
+	      */
+
+	      ist >> ch;
+	      while (ch != ';')
+		{
+		  ist >> ch;
+		}
+
+	      ist >> ch;
+	    }
+
+	  ist.putback (ch);
+	}
+
+      else if (strcmp (buf, "orientations") == 0)
+
+	{
+	  ist >> ch;
+
+	  while (ch == '(')
+	    {
+	      //        fourint a = fourint();
+	      orientations.Append (fourint());
+
+	      ist >> orientations.Last().i1;
+	      ist >> ch;    // ','
+	      ist >> orientations.Last().i2;
+	      ist >> ch;    // ','
+	      ist >> orientations.Last().i3;
+	      ist >> ch;    // ','
+	      ist >> orientations.Last().i4;
+	      ist >> ch;    // ','
+
+
+	      ist >> ch;
+	      while (ch != ';')
+		{
+		  ist >> ch;
+		}
+
+	      ist >> ch;
+	    }
+
+	  ist.putback (ch);
+	}
+
+
+      else if (strcmp (buf, "endrule") != 0)
+	{
+	  PrintSysError ("Parser3d, unknown token " , buf);
+	}
+    }
+  while (!ist.eof() && strcmp (buf, "endrule") != 0);
+
+
+  //  (*testout) << endl;
+  //  (*testout) << Name() << endl;
+  //  (*testout) << "no1 = " << GetNO() << endl;
+
+  oldutonewu.SetSize (3 * (points.Size() - noldp), 3 * noldp);
+  oldutonewu = 0;
+
+  for (i = 1; i <= oldutonewu.Height(); i++)
+    for (j = 1; j <= oldutonewu.Width(); j++)
+      oldutonewu.Elem(i, j) = tempoldutonewu.Elem(i, j);
+
+
+  /*
+    oldutofreezone = new SparseMatrixFlex (3 * freezone.Size(), 3 * noldp);
+    oldutofreezonelimit = new SparseMatrixFlex (3 * freezone.Size(), 3 * noldp);
+
+    oldutofreezone -> SetSymmetric(0);
+    oldutofreezonelimit -> SetSymmetric(0);
+    */
+
+  /*
+    oldutofreezone = new DenseMatrix (3 * freezone.Size(), 3 * noldp);
+    oldutofreezonelimit = new DenseMatrix (3 * freezone.Size(), 3 * noldp);
+  
+    for (i = 1; i <= oldutofreezone->Height(); i++)
+    for (j = 1; j <= oldutofreezone->Width(); j++)
+    //      if (j == 4 || j >= 7)
+    {
+    if (tempoldutofreezone.Elem(i, j))
+    (*oldutofreezone)(i, j) = tempoldutofreezone(i, j);
+    if (tempoldutofreezonelimit.Elem(i, j))
+    (*oldutofreezonelimit)(i, j) = tempoldutofreezonelimit(i, j);
+    }
+    */
+
+
+
+
+  oldutofreezone = new DenseMatrix (freezone.Size(), points.Size());
+  oldutofreezonelimit = new DenseMatrix (freezone.Size(), points.Size());
+  //  oldutofreezone = new SparseMatrixFlex (freezone.Size(), points.Size());
+  //  oldutofreezonelimit = new SparseMatrixFlex (freezone.Size(), points.Size());
+
+  for (i = 1; i <= freezone.Size(); i++)
+    for (j = 1; j <= points.Size(); j++)
+      {
+	if (tfz.Elem(i, j))
+	  (*oldutofreezone).Elem(i, j) = tfz.Elem(i, j);
+	if (tfzl.Elem(i, j))
+	  (*oldutofreezonelimit).Elem(i, j) = tfzl.Elem(i, j);
+      }
+  
+  /*
+  (*testout) << "Rule " << Name() << endl;
+  (*testout) << "oldutofreezone = " << (*oldutofreezone) << endl;
+  (*testout) << "oldutofreezonelimit = " << (*oldutofreezonelimit) << endl;
+  */
+
+  freezonepi.SetSize (freezone.Size());
+  for (i = 1; i <= freezonepi.Size(); i++)
+    freezonepi.Elem(i) = 0;
+  for (i = 1; i <= freezone.Size(); i++)
+    for (j = 1; j <= noldp; j++)
+      if (Dist (freezone.Get(i), points.Get(j)) < 1e-8)
+	freezonepi.Elem(i) = j;
+
+
+
+  
+  for (i = 1; i <= elements.Size(); i++)
+    {
+      if (elements.Elem(i).GetNP() == 4)
+	{
+	  orientations.Append (fourint());
+	  orientations.Last().i1 = elements.Get(i).PNum(1);
+	  orientations.Last().i2 = elements.Get(i).PNum(2);
+	  orientations.Last().i3 = elements.Get(i).PNum(3);
+	  orientations.Last().i4 = elements.Get(i).PNum(4);
+	}
+      if (elements.Elem(i).GetNP() == 5)
+	{
+	  orientations.Append (fourint());
+	  orientations.Last().i1 = elements.Get(i).PNum(1);
+	  orientations.Last().i2 = elements.Get(i).PNum(2);
+	  orientations.Last().i3 = elements.Get(i).PNum(3);
+	  orientations.Last().i4 = elements.Get(i).PNum(5);
+
+	  orientations.Append (fourint());
+	  orientations.Last().i1 = elements.Get(i).PNum(1);
+	  orientations.Last().i2 = elements.Get(i).PNum(3);
+	  orientations.Last().i3 = elements.Get(i).PNum(4);
+	  orientations.Last().i4 = elements.Get(i).PNum(5);
+	}
+    }
+
+
+
+  if (freesets.Size() == 0)
+    {
+      freesets.Append (new ARRAY<int>);
+      for (i = 1; i <= freezone.Size(); i++)
+	freesets.Elem(1)->Append(i);
+    }
+
+
+  //  testout << "Freezone: " << endl;
+
+  //  for (i = 1; i <= freezone.Size(); i++)
+  //    (*testout) << "freepoint: " << freezone.Get(i) << endl;
+  Vector vp(points.Size()), vfp(freezone.Size());
+
+
+  if (quality < 100)
+    {
+      for (i = 1; i <= 3; i++)
+	{
+	  for (j = 1; j <= points.Size(); j++)
+	    vp.Elem(j) = points.Get(j).X(i);
+	  oldutofreezone->Mult(vp, vfp);
+	  for (j = 1; j <= freezone.Size(); j++)
+	    freezone.Elem(j).X(i) = vfp.Get(j);
+	}
+      //      for (i = 1; i <= freezone.Size(); i++)
+      //	(*testout) << "freepoint: " << freezone.Get(i) << endl;
+    }
+
+
+  for (fs = 1; fs <= freesets.Size(); fs++)
+    {
+      freefaces.Append (new ARRAY<threeint>);
+
+      ARRAY<int> & freeset = *freesets.Elem(fs);
+      ARRAY<threeint> & freesetfaces = *freefaces.Last();
+
+      for (ii1 = 1; ii1 <= freeset.Size(); ii1++)
+	for (ii2 = 1; ii2 <= freeset.Size(); ii2++)
+	  for (ii3 = 1; ii3 <= freeset.Size(); ii3++)
+	    if (ii1 < ii2 && ii1 < ii3 && ii2 != ii3)
+	      {
+		i1 = freeset.Get(ii1);
+		i2 = freeset.Get(ii2);
+		i3 = freeset.Get(ii3);
+
+		Vec3d v1, v2, n;
+
+		v1 = freezone.Get(i3) - freezone.Get(i1);
+		v2 = freezone.Get(i2) - freezone.Get(i1);
+		n = Cross (v1, v2);
+		n /= n.Length();
+		//		(*testout) << "i1,2,3 = " << i1 << ", " << i2 << ", " << i3 << endl;
+		//		(*testout) << "v1 = " << v1 << " v2 = " << v2 << " n = " << n << endl;
+		ok = 1;
+		for (ii = 1; ii <= freeset.Size(); ii++)
+		  {
+		    i = freeset.Get(ii);
+		    //		    (*testout) << "i = " << i << endl;
+		    if (i != i1 && i != i2 && i != i3)
+		      if ( (freezone.Get(i) - freezone.Get(i1)) * n < 0 ) ok = 0;
+		  }
+
+		if (ok)
+		  {
+		    freesetfaces.Append (threeint());
+		    freesetfaces.Last().i1 = i1;
+		    freesetfaces.Last().i2 = i2;
+		    freesetfaces.Last().i3 = i3;
+		  }
+	      }
+    }
+
+  for (fs = 1; fs <= freesets.Size(); fs++)
+    {
+      freefaceinequ.Append (new DenseMatrix (freefaces.Get(fs)->Size(), 4));
+    }
+
+
+  {
+    char ok;
+    int minn;
+    //    ARRAY<int> pnearness (noldp);
+    pnearness.SetSize (noldp);
+
+    for (i = 1; i <= pnearness.Size(); i++)
+      pnearness.Elem(i) = INT_MAX/10;
+
+    for (j = 1; j <= GetNP(1); j++)
+      pnearness.Elem(GetPointNr (1, j)) = 0;
+
+    do
+      {
+	ok = 1;
+
+	for (i = 1; i <= noldf; i++)
+	  {
+	    minn = INT_MAX/10;
+	    for (j = 1; j <= GetNP(i); j++)
+	      minn = min2 (minn, pnearness.Get(GetPointNr (i, j)));
+
+	    for (j = 1; j <= GetNP(i); j++)
+	      if (pnearness.Get(GetPointNr (i, j)) > minn+1)
+		{
+		  ok = 0;
+		  pnearness.Elem(GetPointNr (i, j)) = minn+1;
+		}
+	  }
+
+	for (i = 1; i <= elements.Size(); i++)
+	  if (elements.Get(i).GetNP() == 6)
+	    {
+	      for (j = 1; j <= 3; j++)
+		{
+		  int pi1 = elements.Get(i).PNum(j);
+		  int pi2 = elements.Get(i).PNum(j+3);
+
+		  if (pnearness.Get(pi1) > pnearness.Get(pi2)+1)
+		    {
+		      ok = 0;
+		      pnearness.Elem(pi1) = pnearness.Get(pi2)+1;
+		    }
+		  if (pnearness.Get(pi2) > pnearness.Get(pi1)+1)
+		    {
+		      ok = 0;
+		      pnearness.Elem(pi2) = pnearness.Get(pi1)+1;
+		    }
+		}
+	    }
+      }
+    while (!ok);
+
+    int maxpnearness = 0;
+    for (i = 1; i <= pnearness.Size(); i++)
+      maxpnearness = max2 (maxpnearness, pnearness.Get(i));
+
+
+    fnearness.SetSize (noldf);
+
+    for (i = 1; i <= noldf; i++)
+      {
+	fnearness.Elem(i) = 0;
+	for (j = 1; j <= GetNP(i); j++)
+	  fnearness.Elem(i) += pnearness.Get(GetPointNr (i, j));
+      }
+  }
+
+  
+  //Table of edges:
+  for (fs = 1; fs <= freesets.Size(); fs++)
+    {
+      freeedges.Append (new ARRAY<twoint>);
+      
+      //      ARRAY<int> & freeset = *freesets.Get(fs);
+      ARRAY<twoint> & freesetedges = *freeedges.Last();
+      ARRAY<threeint> & freesetfaces = *freefaces.Get(fs);
+      int k,l;
+      INDEX ind;
+      
+      for (k = 1; k <= freesetfaces.Size(); k++)
+	{
+          threeint tr = freesetfaces.Get(k);
+
+	  for (l = k+1; l <= freesetfaces.Size(); l++)
+	    {
+	      ind = NeighbourTrianglePoint(freesetfaces.Get(k), freesetfaces.Get(l));
+	      if (!ind) continue;
+
+	      INDEX_3 f1(freesetfaces.Get(k).i1, 
+			 freesetfaces.Get(k).i2, 
+			 freesetfaces.Get(k).i3);
+	      INDEX_3 f2(freesetfaces.Get(l).i1, 
+			 freesetfaces.Get(l).i2, 
+			 freesetfaces.Get(l).i3);
+	      INDEX_2 edge(0, 0);
+	      for (int f11 = 1; f11 <= 3; f11++)
+		for (int f12 = 1; f12 <= 3; f12++)
+		  if (f11 != f12)
+		    for (int f21 = 1; f21 <= 3; f21++)
+		      for (int f22 = 1; f22 <= 3; f22++)		    
+			if (f1.I(f11) == f2.I(f21) && f1.I(f12) == f2.I(f22))
+			{
+			  edge.I(1) = f1.I(f11);
+			  edge.I(2) = f1.I(f12);
+			}
+	      //	      (*testout) << "edge = " << edge.I(1) << "-" << edge.I(2) << endl;
+	      //	      (*testout) << "ind = " << ind << " edge = " << edge << endl;
+	      for (int eli = 1; eli <= GetNOldF(); eli++)
+		{
+		  if (GetNP(eli) == 4)
+		    {
+		      for (int elr = 1; elr <= 4; elr++)
+			{
+			  if (GetPointNrMod (eli, elr) == edge.I(1) &&
+			      GetPointNrMod (eli, elr+2) == edge.I(2))
+			    {
+			      /*
+			      (*testout) << "edge is diagonal of rectangle" << endl;
+			      (*testout) << "edge = " << edge.I(1) << "-" << edge.I(2) << endl;
+			      (*testout) << "ind = " << ind << endl;
+			      */
+			      ind = 0;
+			    }
+
+			}
+		    }
+		}
+
+	      if (ind)
+		{
+		  /*
+		  (*testout) << "new edge from face " << k 
+			     << " = (" << freesetfaces.Get(k).i1 
+			     << ", " << freesetfaces.Get(k).i2 
+			     << ", " << freesetfaces.Get(k).i3
+			     << "), point " << ind << endl;
+			     */
+		  freesetedges.Append(twoint(k,ind));
+		}
+	    }	
+	}
+    }
+    
+}
+
+
+
+
+
+void Meshing3 :: LoadRules (const char * filename, const char ** prules)
+{
+  char buf[256];
+  istream * ist;
+  char *tr1 = NULL;
+
+  if (filename)
+    {
+      PrintMessage (3, "rule-filename = ", filename);
+      ist = new ifstream (filename);
+    }
+  else 
+    {
+      /* connect tetrules to one string */
+      PrintMessage (3, "Use internal rules");
+      if (!prules) prules = tetrules;
+
+      const char ** hcp = prules; 
+      int len = 0;
+      while (*hcp)
+	{
+	  len += strlen (*hcp);
+	  hcp++;
+	}
+      tr1 = new char[len+1];
+      tr1[0] = 0;
+      hcp = prules; //  tetrules;
+
+
+      char * tt1 = tr1;
+      while (*hcp)
+	{
+	  strcat (tt1, *hcp);
+	  tt1 += strlen (*hcp);	  
+	  hcp++;
+	}
+
+      ist = new istringstream (tr1);
+    }
+  
+  if (!ist->good())
+    {
+      cerr << "Rule description file " << filename << " not found" << endl;
+      delete ist;
+      exit (1);
+    }
+    
+  while (!ist->eof())
+    {
+      buf[0] = 0;
+      (*ist) >> buf;
+	
+      if (strcmp (buf, "rule") == 0)
+	{
+	  vnetrule * rule = new vnetrule;
+	  rule -> LoadRule(*ist);
+	  rules.Append (rule);
+	  if (!rule->TestOk())
+	    {
+	      PrintSysError ("Parser3d: Rule ", rules.Size(), " not ok");
+	      exit (1);
+	    }
+	}
+      else if (strcmp (buf, "tolfak") == 0)
+	{
+	  (*ist) >> tolfak;
+	}
+    }
+  delete ist;
+  delete tr1;
+}
+}
diff --git a/Netgen/libsrc/meshing/prism2rls.cpp b/Netgen/libsrc/meshing/prism2rls.cpp
new file mode 100644
index 0000000000..baf0bef388
--- /dev/null
+++ b/Netgen/libsrc/meshing/prism2rls.cpp
@@ -0,0 +1,446 @@
+namespace netgen
+{
+const char * prismrules2[] = {
+"tolfak 0.5\n",\
+"\n",\
+"rule \"prism on quad\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0);\n",\
+"(1, 1, 0);\n",\
+"(0, 1, 0);\n",\
+"(0.5, 0, -0.86);\n",\
+"(0.5, 1, -0.86);\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3, 4) del;\n",\
+"(1, 5, 2) del;\n",\
+"(4, 3, 6) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newfaces\n",\
+"(5, 2, 3, 6);\n",\
+"(1, 5, 6, 4);\n",\
+"\n",\
+"elements\n",\
+"(1, 5, 2, 4, 6, 3);\n",\
+"\n",\
+"orientations\n",\
+"(1, 2, 3, 5);\n",\
+"(1, 3, 4, 6);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"{ 1 P6 };\n",\
+"{ 0.3 P1, -0.1 P2, -0.1 P3, 0.3 P4, 0.3 P5, 0.3 P6 };\n",\
+"{ -0.1 P1, 0.3 P2, 0.3 P3, -0.1 P4, 0.3 P5, 0.3 P6 };\n",\
+"\n",\
+"freezonelimit\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"{ 1 P6 };\n",\
+"{ 0.25 P1, 0 P2, 0 P3, 0.25 P4, 0.25 P5, 0.25 P6 };\n",\
+"{ 0 P1, 0.25 P2, 0.25 P3, 0 P4, 0.25 P5, 0.25 P6 };\n",\
+"\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"prism on quad, one trig\"\n",\
+"\n",\
+"quality 2\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0);\n",\
+"(1, 1, 0);\n",\
+"(0, 1, 0);\n",\
+"(0.5, 0, -0.86);\n",\
+"(0.5, 1, -0.86);\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3, 4) del;\n",\
+"(1, 5, 2) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newfaces\n",\
+"(5, 2, 3, 6);\n",\
+"(1, 5, 6, 4);\n",\
+"(4, 6, 3);\n",\
+"\n",\
+"elements\n",\
+"(1, 5, 2, 4, 6, 3);\n",\
+"\n",\
+"orientations\n",\
+"(1, 2, 3, 5);\n",\
+"(1, 3, 4, 6);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"{ 1 P6 };\n",\
+"{ 0.3 P1, -0.1 P2, -0.1 P3, 0.3 P4, 0.3 P5, 0.3 P6 };\n",\
+"{ -0.1 P1, 0.3 P2, 0.3 P3, -0.1 P4, 0.3 P5, 0.3 P6 };\n",\
+"\n",\
+"freezonelimit\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"{ 1 P6 };\n",\
+"{ 0.25 P1, 0 P2, 0 P3, 0.25 P4, 0.25 P5, 0.25 P6 };\n",\
+"{ 0 P1, 0.25 P2, 0.25 P3, 0 P4, 0.25 P5, 0.25 P6 };\n",\
+"\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"prism on 2 quad\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0);\n",\
+"(1, 1, 0);\n",\
+"(0, 1, 0);\n",\
+"(0.5, 0, -0.86);\n",\
+"(0.5, 1, -0.86);\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3, 4) del;\n",\
+"(2, 5, 6, 3) del;\n",\
+"(1, 5, 2) del;\n",\
+"(4, 3, 6) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newfaces\n",\
+"(1, 5, 6, 4);\n",\
+"\n",\
+"elements\n",\
+"(1, 5, 2, 4, 6, 3);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"{ 1 P6 };\n",\
+"{ 0.3 P1, -0.1 P2, -0.1 P3, 0.3 P4, 0.3 P5, 0.3 P6 };\n",\
+"\n",\
+"freezonelimit\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"{ 1 P6 };\n",\
+"{ 0.25 P1, 0 P2, 0 P3, 0.25 P4, 0.25 P5, 0.25 P6 };\n",\
+"\n",\
+"freeset\n",\
+"1 2 4 5 6 7;\n",\
+"\n",\
+"freeset\n",\
+"2 3 4 6;\n",\
+"\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"prism on 2 quad, one trig\"\n",\
+"\n",\
+"quality 2\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0);\n",\
+"(1, 1, 0);\n",\
+"(0, 1, 0);\n",\
+"(0.5, 0, -0.86);\n",\
+"(0.5, 1, -0.86);\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3, 4) del;\n",\
+"(2, 5, 6, 3) del;\n",\
+"(1, 5, 2) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newfaces\n",\
+"(1, 5, 6, 4);\n",\
+"(4, 6, 3);\n",\
+"\n",\
+"elements\n",\
+"(1, 5, 2, 4, 6, 3);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"{ 1 P6 };\n",\
+"{ 0.3 P1, -0.1 P2, -0.1 P3, 0.3 P4, 0.3 P5, 0.3 P6 };\n",\
+"\n",\
+"freezonelimit\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"{ 1 P6 };\n",\
+"{ 0.25 P1, 0 P2, 0 P3, 0.25 P4, 0.25 P5, 0.25 P6 };\n",\
+"\n",\
+"freeset\n",\
+"1 2 4 5 6 7;\n",\
+"\n",\
+"freeset\n",\
+"2 3 4 6;\n",\
+"\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"prism on 2 quada\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0);\n",\
+"(1, 1, 0);\n",\
+"(0, 1, 0);\n",\
+"(0.5, 0, -0.86);\n",\
+"(0.5, 1, -0.86);\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3, 4) del;\n",\
+"(5, 1, 4, 6) del;\n",\
+"(1, 5, 2) del;\n",\
+"(4, 3, 6) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newfaces\n",\
+"(5, 2, 3, 6);\n",\
+"\n",\
+"elements\n",\
+"(1, 5, 2, 4, 6, 3);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"{ 1 P6 };\n",\
+"{ -0.1 P1, 0.3 P2, 0.3 P3, -0.1 P4, 0.3 P5, 0.3 P6 };\n",\
+"\n",\
+"freezonelimit\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"{ 1 P6 };\n",\
+"{ 0 P1, 0.25 P2, 0.25 P3, 0 P4, 0.25 P5, 0.25 P6 };\n",\
+"\n",\
+"freeset\n",\
+"1 2 3 5 6 7;\n",\
+"\n",\
+"freeset\n",\
+"1 3 4 6;\n",\
+"\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"fill prism\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0);\n",\
+"(1, 1, 0);\n",\
+"(0, 1, 0);\n",\
+"(0.5, 0, -0.86);\n",\
+"(0.5, 1, -0.86);\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3, 4) del;\n",\
+"(2, 5, 6, 3) del;\n",\
+"(5, 1, 4, 6) del;\n",\
+"(1, 5, 2) del;\n",\
+"(4, 3, 6) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newfaces\n",\
+"\n",\
+"\n",\
+"elements\n",\
+"(1, 5, 2, 4, 6, 3);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"{ 1 P6 };\n",\
+"\n",\
+"freeset\n",\
+"1 2 4 5;\n",\
+"\n",\
+"freeset\n",\
+"2 3 4 6;\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"prism on 3 quad, one trig\"\n",\
+"\n",\
+"quality 2\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0);\n",\
+"(1, 1, 0);\n",\
+"(0, 1, 0);\n",\
+"(0.5, 0, -0.86);\n",\
+"(0.5, 1, -0.86);\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3, 4) del;\n",\
+"(2, 5, 6, 3) del;\n",\
+"(5, 1, 4, 6) del;\n",\
+"(1, 5, 2) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newfaces\n",\
+"(4, 6, 3);\n",\
+"\n",\
+"\n",\
+"elements\n",\
+"(1, 5, 2, 4, 6, 3);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"{ 1 P6 };\n",\
+"\n",\
+"freeset\n",\
+"1 2 4 5;\n",\
+"\n",\
+"freeset\n",\
+"2 3 4 6;\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"flat prism\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0);\n",\
+"(0.5, 0.866, 0);\n",\
+"(0, 0, -1);\n",\
+"(1, 0, -1);\n",\
+"(0.5, 0.866, -1);\n",\
+"\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3) del;\n",\
+"(5, 4, 6) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newfaces\n",\
+"(1, 2, 4);\n",\
+"(4, 2, 5);\n",\
+"(2, 3, 5);\n",\
+"(5, 3, 6);\n",\
+"(3, 1, 6);\n",\
+"(6, 1, 4);\n",\
+"\n",\
+"\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 5, 4, 6);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P5 };\n",\
+"{ 1 P6 };\n",\
+"endrule\n",\
+"\n",\
+0};
+}
diff --git a/Netgen/libsrc/meshing/pyramid2rls.cpp b/Netgen/libsrc/meshing/pyramid2rls.cpp
new file mode 100644
index 0000000000..a97e7f13e5
--- /dev/null
+++ b/Netgen/libsrc/meshing/pyramid2rls.cpp
@@ -0,0 +1,309 @@
+namespace netgen
+{
+const char * pyramidrules2[] = {
+"tolfak 0.5\n",\
+"\n",\
+"rule \"Pyramid on quad\"\n",\
+"\n",\
+"quality 100\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0);\n",\
+"(1, 1, 0);\n",\
+"(0, 1, 0);\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3, 4) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0.5, 0.5, -0.5) \n",\
+"	{ 0.25 X1, 0.25 X2, 0.25 X3, 0.25 X4 } 	\n",\
+"	{ 0.25 Y1, 0.25 Y2, 0.25 Y3, 0.25 Y4 } { };\n",\
+"\n",\
+"newfaces\n",\
+"(1, 2, 5);\n",\
+"(2, 3, 5);\n",\
+"(3, 4, 5);\n",\
+"(4, 1, 5);\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4, 5);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1.4 P5, -0.1 P1, -0.1 P2, -0.1 P3, -0.1 P4 };\n",\
+"\n",\
+"freezonelimit\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"\n",\
+"freeset\n",\
+"1 2 3 5;\n",\
+"\n",\
+"freeset\n",\
+"1 3 4 5;\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"rule \"small Pyramid on quad\"\n",\
+"\n",\
+"quality 100\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0);\n",\
+"(1, 1, 0);\n",\
+"(0, 1, 0);\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3, 4) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0.5, 0.5, -0.1 )\n",\
+"	{ 0.25 X1, 0.25 X2, 0.25 X3, 0.25 X4 } \n",\
+"	{ 0.25 Y1, 0.25 Y2, 0.25 Y3, 0.25 Y4 } { };\n",\
+"\n",\
+"newfaces\n",\
+"(1, 2, 5);\n",\
+"(2, 3, 5);\n",\
+"(3, 4, 5);\n",\
+"(4, 1, 5);\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4, 5);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1.4 P5, -0.1 P1, -0.1 P2, -0.1 P3, -0.1 P4 };\n",\
+"\n",\
+"freezonelimit\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"\n",\
+"freeset\n",\
+"1 2 3 5;\n",\
+"\n",\
+"freeset\n",\
+"1 3 4 5;\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"connect pyramid\"\n",\
+"\n",\
+"quality 100\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0);\n",\
+"(1, 1, 0);\n",\
+"(0, 1, 0);\n",\
+"(0.5, 0.5, -0.5);\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3, 4) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newfaces\n",\
+"(1, 2, 5);\n",\
+"(2, 3, 5);\n",\
+"(3, 4, 5);\n",\
+"(4, 1, 5);\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4, 5);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"\n",\
+"freeset\n",\
+"1 2 3 5;\n",\
+"\n",\
+"freeset\n",\
+"1 3 4 5;\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"pyramid with one trig\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0);\n",\
+"(1, 1, 0);\n",\
+"(0, 1, 0);\n",\
+"(0.5, 0.5, -0.5);\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3, 4) del;\n",\
+"(2, 1, 5) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newfaces\n",\
+"(2, 3, 5);\n",\
+"(3, 4, 5);\n",\
+"(4, 1, 5);\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4, 5);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"{ 0.34 P2, 0.34 P3, 0.34 P5, -0.02 P1 };\n",\
+"{ 0.34 P3, 0.34 P4, 0.34 P5, -0.02 P1 };\n",\
+"{ 0.34 P1, 0.34 P4, 0.34 P5, -0.02 P2 };\n",\
+"\n",\
+"freezonelimit\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"{ 0.333 P2, 0.333 P3, 0.334 P5, 0 P1 };\n",\
+"{ 0.333 P3, 0.333 P4, 0.334 P5, 0 P1 };\n",\
+"{ 0.333 P1, 0.333 P4, 0.334 P5, 0 P2 };\n",\
+"\n",\
+"orientations\n",\
+"(1, 2, 3, 5);\n",\
+"(1, 3, 4, 5);\n",\
+"\n",\
+"\n",\
+"freeset\n",\
+"1 2 3 5;\n",\
+"freeset\n",\
+"1 3 4 5;\n",\
+"freeset\n",\
+"2 3 5 6;\n",\
+"freeset\n",\
+"3 4 5 7;\n",\
+"freeset \n",\
+"1 4 5 8;\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"pyramid with two trig\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0);\n",\
+"(1, 1, 0);\n",\
+"(0, 1, 0);\n",\
+"(0.5, 0.5, -0.5);\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3, 4) del;\n",\
+"(2, 1, 5) del;\n",\
+"(3, 2, 5) del;\n",\
+"newpoints\n",\
+"\n",\
+"newfaces\n",\
+"(3, 4, 5);\n",\
+"(4, 1, 5);\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4, 5);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"\n",\
+"freeset\n",\
+"1 2 3 5;\n",\
+"\n",\
+"freeset\n",\
+"1 3 4 5;\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"pyramid with two trig, left\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0);\n",\
+"(1, 1, 0);\n",\
+"(0, 1, 0);\n",\
+"(0.5, 0.5, -0.5);\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3, 4) del;\n",\
+"(2, 1, 5) del;\n",\
+"(1, 4, 5) del;\n",\
+"newpoints\n",\
+"\n",\
+"newfaces\n",\
+"(3, 4, 5);\n",\
+"(2, 3, 5);\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4, 5);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"\n",\
+"freeset\n",\
+"1 2 3 5;\n",\
+"\n",\
+"freeset\n",\
+"1 3 4 5;\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+0};
+}
diff --git a/Netgen/libsrc/meshing/pyramidrls.cpp b/Netgen/libsrc/meshing/pyramidrls.cpp
new file mode 100644
index 0000000000..d4e997c1fe
--- /dev/null
+++ b/Netgen/libsrc/meshing/pyramidrls.cpp
@@ -0,0 +1,263 @@
+namespace netgen
+{
+const char * pyramidrules[] = {
+"tolfak 0.5\n",\
+"\n",\
+"rule \"Pyramid on quad\"\n",\
+"\n",\
+"quality 100\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0);\n",\
+"(1, 1, 0);\n",\
+"(0, 1, 0);\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3, 4) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0.5, 0.5, -0.5) \n",\
+"	{ 0.25 X1, 0.25 X2, 0.25 X3, 0.25 X4 } 	\n",\
+"	{ 0.25 Y1, 0.25 Y2, 0.25 Y3, 0.25 Y4 } { };\n",\
+"\n",\
+"newfaces\n",\
+"(1, 2, 5);\n",\
+"(2, 3, 5);\n",\
+"(3, 4, 5);\n",\
+"(4, 1, 5);\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4, 5);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1.4 P5, -0.1 P1, -0.1 P2, -0.1 P3, -0.1 P4 };\n",\
+"\n",\
+"freezonelimit\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"\n",\
+"freeset\n",\
+"1 2 3 5;\n",\
+"\n",\
+"freeset\n",\
+"1 3 4 5;\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"rule \"small Pyramid on quad\"\n",\
+"\n",\
+"quality 100\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0);\n",\
+"(1, 1, 0);\n",\
+"(0, 1, 0);\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3, 4) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0.5, 0.5, -0.1 )\n",\
+"	{ 0.25 X1, 0.25 X2, 0.25 X3, 0.25 X4 } \n",\
+"	{ 0.25 Y1, 0.25 Y2, 0.25 Y3, 0.25 Y4 } { };\n",\
+"\n",\
+"newfaces\n",\
+"(1, 2, 5);\n",\
+"(2, 3, 5);\n",\
+"(3, 4, 5);\n",\
+"(4, 1, 5);\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4, 5);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1.4 P5, -0.1 P1, -0.1 P2, -0.1 P3, -0.1 P4 };\n",\
+"\n",\
+"freezonelimit\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"\n",\
+"freeset\n",\
+"1 2 3 5;\n",\
+"\n",\
+"freeset\n",\
+"1 3 4 5;\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"connect pyramid\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0);\n",\
+"(1, 1, 0);\n",\
+"(0, 1, 0);\n",\
+"(0.5, 0.5, -0.5);\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3, 4) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newfaces\n",\
+"(1, 2, 5);\n",\
+"(2, 3, 5);\n",\
+"(3, 4, 5);\n",\
+"(4, 1, 5);\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4, 5);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"\n",\
+"freeset\n",\
+"1 2 3 5;\n",\
+"\n",\
+"freeset\n",\
+"1 3 4 5;\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"pyramid with one trig\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0);\n",\
+"(1, 1, 0);\n",\
+"(0, 1, 0);\n",\
+"(0.5, 0.5, -0.5);\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3, 4) del;\n",\
+"(2, 1, 5) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newfaces\n",\
+"(2, 3, 5);\n",\
+"(3, 4, 5);\n",\
+"(4, 1, 5);\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4, 5);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"{ 0.34 P2, 0.34 P3, 0.34 P5, -0.02 P1 };\n",\
+"{ 0.34 P3, 0.34 P4, 0.34 P5, -0.02 P1 };\n",\
+"{ 0.34 P1, 0.34 P4, 0.34 P5, -0.02 P3 };\n",\
+"\n",\
+"freezonelimit\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"{ 0.333 P2, 0.333 P3, 0.334 P5, 0 P1 };\n",\
+"{ 0.333 P3, 0.333 P4, 0.334 P5, 0 P1 };\n",\
+"{ 0.333 P1, 0.333 P4, 0.334 P5, 0 P3 };\n",\
+"\n",\
+"orientations\n",\
+"(1, 2, 3, 5);\n",\
+"(1, 3, 4, 5);\n",\
+"\n",\
+"\n",\
+"freeset\n",\
+"1 2 3 5;\n",\
+"freeset\n",\
+"1 3 4 5;\n",\
+"freeset\n",\
+"2 3 5 6;\n",\
+"freeset\n",\
+"3 4 5 7;\n",\
+"freeset \n",\
+"1 4 5 8;\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"pyramid with two trig\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0);\n",\
+"(1, 1, 0);\n",\
+"(0, 1, 0);\n",\
+"(0.5, 0.5, -0.5);\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3, 4) del;\n",\
+"(2, 1, 5) del;\n",\
+"(3, 2, 5) del;\n",\
+"newpoints\n",\
+"\n",\
+"newfaces\n",\
+"(3, 4, 5);\n",\
+"(4, 1, 5);\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4, 5);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"\n",\
+"freeset\n",\
+"1 2 3 5;\n",\
+"\n",\
+"freeset\n",\
+"1 3 4 5;\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+0};
+}
diff --git a/Netgen/libsrc/meshing/quadrls.cpp b/Netgen/libsrc/meshing/quadrls.cpp
new file mode 100644
index 0000000000..01555b72ea
--- /dev/null
+++ b/Netgen/libsrc/meshing/quadrls.cpp
@@ -0,0 +1,743 @@
+namespace netgen
+{
+const char * quadrules[] = {
+"rule \"Free Quad (1)\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0);\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"\n",\
+"newpoints\n",\
+"(1, 1) { 1 X2 } { };\n",\
+"(0, 1) { } { };\n",\
+"\n",\
+"newlines\n",\
+"(3, 2);\n",\
+"(4, 3);\n",\
+"(1, 4);\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1.5, 1.5) { 1.5 X2 } { };\n",\
+"(-0.5, 1.5) { -0.5 X2 } { };\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Free Quad (5)\"\n",\
+"\n",\
+"quality 5\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0);\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"\n",\
+"newpoints\n",\
+"(1, 1) { 1 X2 } { };\n",\
+"(0, 1) { } { };\n",\
+"\n",\
+"newlines\n",\
+"(3, 2);\n",\
+"(4, 3);\n",\
+"(1, 4);\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1.5, 1.5) { 1.5 X2 } { };\n",\
+"(-0.5, 1.5) { -0.5 X2 } { };\n",\
+"\n",\
+"freearea2\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1, 1) { 1 X2 } { };\n",\
+"(0, 1) { } { };\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Quad Right (1)\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0);\n",\
+"(1, 1);\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"(2, 3) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0, 1) { } { 1 y3 };\n",\
+"\n",\
+"newlines\n",\
+"(1, 4);\n",\
+"(4, 3);\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1, 1) { 1 X3 } { 1 Y3 };\n",\
+"(-0.5, 1.5) { } { 1.5 Y3 };\n",\
+"\n",\
+"freearea2\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1, 1) { 1 X3 } { 1 Y3 };\n",\
+"(0, 1) { } { 1 Y3 };\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Quad P Right (1)\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0);\n",\
+"(1, 1);\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0, 1) { } { 1 y3 };\n",\
+"\n",\
+"newlines\n",\
+"(1, 4);\n",\
+"(4, 3);\n",\
+"(3, 2);\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1.2, 0.6) { 0.6 X2, 0.6 Y2 } { 0.6 Y3 };\n",\
+"(1, 1) { 1 X3 } { 1 Y3 };\n",\
+"(-0.5, 1.5) { } { 1.5 Y3 };\n",\
+"\n",\
+"freearea2\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1, 0.5) { 0.5 X2, 0.5 Y2 } { 0.5 Y3 };\n",\
+"(1, 1) { 1 X3 } { 1 Y3 };\n",\
+"(0, 1) { } { 1 Y3 };\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"rule \"Quad Right PL (1)\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0);\n",\
+"(1, 1);\n",\
+"(0, 1);\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"(2, 3) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newlines\n",\
+"(1, 4);\n",\
+"(4, 3);\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1, 1) { 1 X3 } { 1 Y3 };\n",\
+"(0.5, 1.2) { -0.2 X2, 0.6 X3, 0.6 X4 } { -0.2 Y2, 0.6 Y3, 0.6 Y4 };\n",\
+"(0, 1) { 1 X4 } { 1 Y4 };\n",\
+"(-0.2, 0.5) { -0.2 X2, -0.2 X3, 0.6 X4 } { -0.2 Y2, -0.2 Y3, 0.6 Y4 };\n",\
+"\n",\
+"freearea2\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1, 1) { 1 X3 } { 1 Y3 };\n",\
+"(0.5, 1) { 0.5 X3, 0.5 X4 } { 0.5 Y3, 0.5 Y4 };\n",\
+"(0, 1) { 1 X4 } { 1 Y4 };\n",\
+"(0, 0.5) { 0.5 X4 } { 0.5 Y4 };\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Left Quad (1)\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0);\n",\
+"(0, 1);\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"(3, 1) del;\n",\
+"\n",\
+"newpoints\n",\
+"(1, 1) { 1 X2, 1 X3 } { 1 Y3 };\n",\
+"\n",\
+"newlines\n",\
+"(3, 4);\n",\
+"(4, 2);\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1.5, 1.5) { 1.5 X2, 1.5 X3 } { 1.5 Y3 };\n",\
+"(0, 1) { 1 X3 } { 1 Y3 };\n",\
+"\n",\
+"freearea2\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1, 1) { 1 X2, 1 X3 } { 1 Y3 };\n",\
+"(0, 1) { 1 X3 } { 1 Y3 };\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 4, 3);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Left P Quad (1)\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0);\n",\
+"(0, 1);\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"\n",\
+"newpoints\n",\
+"(1, 1) { 1 X2, 1 X3 } { 1 Y3 };\n",\
+"\n",\
+"newlines\n",\
+"(1, 3);\n",\
+"(3, 4);\n",\
+"(4, 2);\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1.5, 1.5) { 1.5 X2, 1.5 X3 } { 1.5 Y3 };\n",\
+"(0, 1) { 1 X3 } { 1 Y3 };\n",\
+"(-0.2, 0.6) { -0.2 X2, 0.6 X3 } { 0.6 Y3 };\n",\
+"\n",\
+"freearea2\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1, 1) { 1 X2, 1 X3 } { 1 Y3 };\n",\
+"(0, 1) { 1 X3 } { 1 Y3 };\n",\
+"(0, 0.5) { 0.5 X3 } { 0.5 Y3 };\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 4, 3);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Left Quad RP (1)\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0);\n",\
+"(0, 1);\n",\
+"(1, 1);\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"(3, 1) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newlines\n",\
+"(3, 4);\n",\
+"(4, 2);\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1.2, 0.5) { 0.6 X2, 0.6 X4, -0.2 X3 } { 0.6 Y2, 0.6 Y4, -0.2 Y3 };\n",\
+"(1, 1) { 1 X4 } { 1 Y4 };\n",\
+"(0.5, 1.2) { -0.2 X2, 0.6 X3, 0.6 X4 } { -0.2 Y2, 0.6 Y3, 0.6 Y4 };\n",\
+"(0, 1) { 1 X3 } { 1 Y3 };\n",\
+"\n",\
+"freearea2\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1, 0.5) { 0.5 X2, 0.5 X4 } { 0.5 Y2, 0.5 Y4 };\n",\
+"(1, 1) { 1 X4 } { 1 Y4 };\n",\
+"(0.5, 1) { 0.5 X3, 0.5 X4 } { 0.5 Y3, 0.5 Y4 };\n",\
+"(0, 1) { 1 X3 } { 1 Y3 };\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 4, 3);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Two left (1)\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0);\n",\
+"(1, 1);\n",\
+"(0, 1);\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"(3, 4) del;\n",\
+"(4, 1) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newlines\n",\
+"(3, 2);\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1.5, 0.5) { 0.75 X2, 0.75 X3, -0.25 X4 } { 0.75 Y3, -0.25 Y4 };\n",\
+"(1, 1) { 1 X3 } { 1 Y3 };\n",\
+"(0, 1) { 1 X4 } { 1 Y4 };\n",\
+"\n",\
+"\n",\
+"freearea2\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1, 0.5) { 0.5 X2, 0.5 X3 } { 0.5 Y3 };\n",\
+"(1, 1) { 1 X3 } { 1 Y3 };\n",\
+"(0, 1) { 1 X4 } { 1 Y4 };\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Two Right (1)\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0);\n",\
+"(1, 1);\n",\
+"(0, 1);\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"(2, 3) del;\n",\
+"(3, 4) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newlines\n",\
+"(1, 4);\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1, 1) { 1 X3 } { 1 Y3 };\n",\
+"(0, 1) { 1 X4 } { 1 Y4 };\n",\
+"(-0.5, 0.5) { -0.25 X2, -0.25 X3, 0.75 X4 } { -0.25 Y3, 0.75 Y4 };\n",\
+"\n",\
+"freearea2\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1, 1) { 1 X3 } { 1 Y3 };\n",\
+"(0, 1) { 1 X4 } { 1 Y4 };\n",\
+"(0, 0.5) { 0.5 X4 } { 0.5 Y4 };\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Right 120 (1)\"\n",\
+"\n",\
+"quality 1000\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0);\n",\
+"(1.5, 0.866);\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"(2, 3) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0.5, 0.866) { 1 X3, -1 X2 } { 1 Y3 };\n",\
+"\n",\
+"newlines\n",\
+"(1, 4);\n",\
+"(4, 3);\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1.5, 0.866) { 1 X3 } { 1 Y3 };\n",\
+"(1, 1.732) { -2 X2, 2 X3 } { 2 Y3 };\n",\
+"(0, 1.732) { -3 X2, 2 X3 } { 2 Y3 };\n",\
+"(-0.5, 0.866) { -2 X2, 1 X3 } {1 Y3 };\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 4);\n",\
+"(2, 3, 4);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Left 120 (1)\"\n",\
+"\n",\
+"quality 1000\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0);\n",\
+"(-0.5, 0.866);\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"(3, 1) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0.5, 0.866) { 1 X3, 1 X2 } { 1 Y3 };\n",\
+"\n",\
+"newlines\n",\
+"(3, 4);\n",\
+"(4, 2);\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1.5, 0.866) { 2 X2, 1 X3 } { 1 Y3 };\n",\
+"(1, 1.732) { 2 X2, 2 X3 } { 2 Y3 };\n",\
+"(0, 1.732) { -1 X2, 2 X3 } { 2 Y3 };\n",\
+"(-0.5, 0.866) { 1 X3 } {1 Y3 };\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 4);\n",\
+"(2, 3, 4);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Left Right (1)\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0);\n",\
+"(1, 1);\n",\
+"(0, 1);\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"(2, 3) del;\n",\
+"(4, 1) del;\n",\
+"\n",\
+"\n",\
+"newlines\n",\
+"(4, 3);\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1, 1) { 1 X3 } { 1 Y3 };\n",\
+"(0.5, 1.5) { -0.25 X2, 0.75 X3, 0.75 X4 } { 0.75 Y3, 0.75 Y4 };\n",\
+"(0, 1) { 1 X4 } { 1 Y4 };\n",\
+"\n",\
+"freearea2\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1, 1) { 1 X3 } { 1 Y3 };\n",\
+"(0.5, 1) { 0.5 X3, 0.5 X4 } { 0.5 Y3, 0.5 Y4 };\n",\
+"(0, 1) { 1 X4 } { 1 Y4 };\n",\
+"\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Fill Quad\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0);\n",\
+"(1, 1);\n",\
+"(0, 1);\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"(2, 3) del;\n",\
+"(3, 4) del;\n",\
+"(4, 1) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newlines\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { 1 Y2 };\n",\
+"(1, 1) { 1 X3 } { 1 Y3 };\n",\
+"(0, 1) { 1 X4 } { 1 Y4 };\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Fill Triangle\"\n",\
+"\n",\
+"quality 10\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0);\n",\
+"(0.5, 0.86);\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"(2, 3) del;\n",\
+"(3, 1) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newlines\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { 1 Y2 };\n",\
+"(0.5, 0.86) { 1 X3 } { 1 Y3 };\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Right 60 (1)\"\n",\
+"\n",\
+"quality 10\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0) { 0.5, 0, 1.0 };\n",\
+"(0.5, 0.866) { 0.6, 0, 0.8 };\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"(2, 3) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newlines\n",\
+"(1, 3);\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(0.5, 0.866) { 1 X3 } { 1 Y3 };\n",\
+"(-0.125, 0.6495) { -0.5 X2, 0.75 X3 } { -0.5 Y2, 0.75 Y3 };\n",\
+"\n",\
+"freearea2\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(0.5, 0.866) { 1 X3 } { 1 Y3 };\n",\
+"(0.25, 0.433) { 0.5 X3 } { 0.5 Y3 };\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Vis A Vis (1)\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0);\n",\
+"(1, 1);\n",\
+"(0, 1);\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"(3, 4) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newlines\n",\
+"(1, 4);\n",\
+"(3, 2);\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1.5, 0.5) { 0.75 X2, 0.75 X3, -0.25 X4 } { 0.75 Y3, -0.25 Y4 };\n",\
+"(1, 1) { 1 X3 } { 1 Y3 };\n",\
+"(0, 1) { 1 X4 } { 1 Y4 };\n",\
+"(-0.5, 0.5) { -0.25 X2, -0.25 X3, 0.75 X4 } { -0.25 Y3, 0.75 Y4 };\n",\
+"\n",\
+"freearea2\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1, 0.5) { 0.5 X2, 0.5 X3 } { 0.5 Y3 };\n",\
+"(1, 1) { 1 X3 } { 1 Y3 };\n",\
+"(0, 1) { 1 X4 } { 1 Y4 };\n",\
+"(0, 0.5) { 0.5 X4 } { 0.5 Y4 };\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"2 h Vis A Vis (1)\"\n",\
+"\n",\
+"quality 3000\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0);\n",\
+"(1, 1.732);\n",\
+"(0, 1.732);\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"(3, 4) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0.5, 0.866) { 0.25 X3, 0.25 X4 } { 0.25 Y2, 0.25 Y3, 0.25 Y4 };\n",\
+"\n",\
+"newlines\n",\
+"(1, 5);\n",\
+"(5, 4);\n",\
+"(3, 5);\n",\
+"(5, 2);\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { 1 Y2 };\n",\
+"(1.5, 0.866) { 0.75 X2, 0.75 X3, -0.25 X4 } { 0.75 Y2, 0.75 Y3, -0.25 Y4 };\n",\
+"(1, 1.732) { 1 X3 } { 1 Y3 };\n",\
+"(0, 1.732) { 1 X4 } { 1 Y4 };\n",\
+"(-0.5, 0.866) { 0.75 X4, -0.25 X2, -0.25 X3 } { 0.75 Y4, -0.25 Y3 };\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 5);\n",\
+"(3, 4, 5);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+0};
+}
diff --git a/Netgen/libsrc/meshing/refine.cpp b/Netgen/libsrc/meshing/refine.cpp
new file mode 100644
index 0000000000..c14979693e
--- /dev/null
+++ b/Netgen/libsrc/meshing/refine.cpp
@@ -0,0 +1,549 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+
+namespace netgen
+{
+  void Refinement :: Refine (Mesh & mesh, int /* levels */)
+  {
+    int i, j, k;
+
+
+    // reduce 2nd order
+    mesh.ComputeNVertices();
+    mesh.SetNP(mesh.GetNV());
+
+
+
+    //  for (l = 1; l <= levels; l++)
+    //    {
+    INDEX_2_HASHTABLE<int> between(mesh.GetNP() + 5);
+      
+    int oldne, oldns, oldnf;
+
+    // refine edges
+
+
+    ARRAY<EdgePointGeomInfo> epgi;
+
+    oldns = mesh.GetNSeg();
+
+    for (i = 1; i <= oldns; i++)
+      {
+	const Segment & el = mesh.LineSegment(i);
+
+	INDEX_2 i2(el.p1, el.p2);
+	i2.Sort();
+
+	int pnew;
+	EdgePointGeomInfo ngi;
+
+	if (between.Used(i2))
+	  {
+	    pnew = between.Get(i2);
+	    ngi = epgi.Get(pnew);
+	  }
+	else
+	  {
+	    Point3d pb;
+	    pb = Center (mesh.Point (el.p1),
+			 mesh.Point (el.p2));
+
+	    PointBetween (mesh.Point (el.p1),
+			  mesh.Point (el.p2), 0.5,
+			  el.surfnr1, el.surfnr2,
+			  el.epgeominfo[0], el.epgeominfo[1],
+			  pb, ngi);
+
+	    pnew = mesh.AddPoint (pb);
+
+	    between.Set (i2, pnew);
+
+	    if (pnew > epgi.Size())
+	      epgi.SetSize (pnew);
+	    epgi.Elem(pnew) = ngi;
+
+	    (*testout) << "ref edge, oldgi = " 
+		       << el.epgeominfo[0] << " - " << el.epgeominfo[1] 
+		       << ", new gi = " << ngi << endl;
+	    
+	  }
+
+	Segment ns1 = el;
+	Segment ns2 = el;
+	ns1.p2 = pnew;
+	ns1.epgeominfo[1] = ngi;
+	ns2.p1 = pnew;
+	ns2.epgeominfo[0] = ngi;
+
+	mesh.LineSegment(i) = ns1;
+	mesh.AddSegment (ns2);
+      }
+
+
+
+    (*testout) << "refine surfaces" << endl;
+    // refine surface elements
+
+    ARRAY<PointGeomInfo> surfgi (8*mesh.GetNP());
+    for (i = 1; i <= surfgi.Size(); i++)
+      surfgi.Elem(i).trignum = -1;
+
+    oldnf = mesh.GetNSE();
+    for (i = 1; i <= oldnf; i++)
+      {
+	int j, k;
+	const Element2d & el = mesh.SurfaceElement(i);
+
+	switch (el.GetType())
+	  {
+	  case TRIG:
+	  case TRIG6:
+	    {
+	      ArrayMem<int,6> pnums(6);
+	      ArrayMem<PointGeomInfo,6> pgis(6);
+	      
+	      static int betw[3][3] =
+		{ { 2, 3, 4 },
+		  { 1, 3, 5 },
+		  { 1, 2, 6 } };
+	      
+	      for (j = 1; j <= 3; j++)
+		{
+		  pnums.Elem(j) = el.PNum(j);
+		  pgis.Elem(j) = el.GeomInfoPi(j);
+		}
+	      
+	      for (j = 0; j < 3; j++)
+		{
+		  int pi1 = pnums.Elem(betw[j][0]);
+		  int pi2 = pnums.Elem(betw[j][1]);
+		  
+		  INDEX_2 i2 (pi1, pi2);
+		  i2.Sort();
+		  
+
+
+		  Point3d pb;
+		  PointGeomInfo pgi;
+		  PointBetween (mesh.Point (pi1),
+				mesh.Point (pi2), 0.5,
+				mesh.GetFaceDescriptor(el.GetIndex ()).SurfNr(),
+				el.GeomInfoPi (betw[j][0]),
+				el.GeomInfoPi (betw[j][1]),
+				pb, pgi);
+
+
+		  pgis.Elem(4+j) = pgi;
+		  if (between.Used(i2))
+		    pnums.Elem(4+j) = between.Get(i2);
+		  else
+		    {
+		      pnums.Elem(4+j) = mesh.AddPoint (pb);
+		      between.Set (i2, pnums.Get(4+j));
+		    }
+
+		  if (surfgi.Size() < pnums.Elem(4+j))
+		    surfgi.SetSize (pnums.Elem(4+j));
+		  surfgi.Elem(pnums.Elem(4+j)) = pgis.Elem(4+j);
+		      
+
+		  /*
+		  if (between.Used(i2))
+		    {
+		      pnums.Elem(4+j) = between.Get(i2);
+		      pgis.Elem(4+j) = surfgi.Get(pnums.Elem(4+j));
+		    }
+		  else
+		    {
+		      Point3d pb;
+		      PointBetween (mesh.Point (pi1),
+				    mesh.Point (pi2), 0.5,
+				    mesh.GetFaceDescriptor(el.GetIndex ()).SurfNr(),
+				    el.GeomInfoPi (betw[j][0]),
+				    el.GeomInfoPi (betw[j][1]),
+				    pb, pgis.Elem(4+j));
+		    
+		      pnums.Elem(4+j) = mesh.AddPoint (pb);
+		    
+		      between.Set (i2, pnums.Get(4+j));
+		    
+		      if (surfgi.Size() < pnums.Elem(4+j))
+			surfgi.SetSize (pnums.Elem(4+j));
+		      surfgi.Elem(pnums.Elem(4+j)) = pgis.Elem(4+j);
+
+		      (*testout) << "ref face, oldgi = " 
+				 << el.GeomInfoPi (betw[j][0]) << " - " 
+				 << el.GeomInfoPi (betw[j][1])
+				 << ", new gi = " << pgis.Elem(4+j) << endl;
+
+		    }
+		  */
+		}
+
+	      static int reftab[4][3] = 
+		{ { 1, 6, 5 },
+		  { 2, 4, 6 },
+		  { 3, 5, 4 },
+		  { 6, 4, 5 } };
+	    
+	      int ind = el.GetIndex();
+	      for (j = 0; j < 4; j++)
+		{
+		  Element2d nel(TRIG);
+		  for (k = 1; k <= 3; k++)
+		    {
+		      nel.PNum(k) = pnums.Get(reftab[j][k-1]);
+		      nel.GeomInfoPi(k) = pgis.Get(reftab[j][k-1]);
+		    }
+		  nel.SetIndex(ind);
+		
+		  if (j == 0)
+		    mesh.SurfaceElement(i) = nel;
+		  else
+		    mesh.AddSurfaceElement(nel);
+		}
+	      break;
+	    }
+	  case QUAD:
+	  case QUAD6:
+	    {
+	      ArrayMem<int,9> pnums(9);
+	      ArrayMem<PointGeomInfo,9> pgis(9);
+	    
+	      static int betw[5][3] =
+		{ { 1, 2, 5 },
+		  { 2, 3, 6 },
+		  { 3, 4, 7 },
+		  { 1, 4, 8 },
+		  { 1, 3, 9 } };
+	    
+	      for (j = 1; j <= 4; j++)
+		{
+		  pnums.Elem(j) = el.PNum(j);
+		  pgis.Elem(j) = el.GeomInfoPi(j);
+		}
+	    
+	      for (j = 0; j < 5; j++)
+		{
+		  int pi1 = pnums.Elem(betw[j][0]);
+		  int pi2 = pnums.Elem(betw[j][1]);
+		
+		  INDEX_2 i2 (pi1, pi2);
+		  i2.Sort();
+		
+		  if (between.Used(i2))
+		    {
+		      pnums.Elem(5+j) = between.Get(i2);
+		      pgis.Elem(5+j) = surfgi.Get(pnums.Elem(4+j));
+		    }
+		  else
+		    {
+		      Point3d pb;
+		      PointBetween (mesh.Point (pi1),
+				    mesh.Point (pi2), 0.5,
+				    mesh.GetFaceDescriptor(el.GetIndex ()).SurfNr(),
+				    el.GeomInfoPi (betw[j][0]),
+				    el.GeomInfoPi (betw[j][1]),
+				    pb, pgis.Elem(5+j));
+		    
+		      pnums.Elem(5+j) = mesh.AddPoint (pb);
+		    
+		      between.Set (i2, pnums.Get(5+j));
+		    
+		      if (surfgi.Size() < pnums.Elem(5+j))
+			surfgi.SetSize (pnums.Elem(5+j));
+		      surfgi.Elem(pnums.Elem(5+j)) = pgis.Elem(5+j);
+		    }
+		}
+
+	      static int reftab[4][4] = 
+		{ 
+		  { 1, 5, 9, 8 },
+		  { 5, 2, 6, 9 },
+		  { 8, 9, 7, 4 },
+		  { 9, 6, 3, 7 } };
+
+	      int ind = el.GetIndex();
+	      for (j = 0; j < 4; j++)
+		{
+		  Element2d nel(QUAD);
+		  for (k = 1; k <= 4; k++)
+		    {
+		      nel.PNum(k) = pnums.Get(reftab[j][k-1]);
+		      nel.GeomInfoPi(k) = pgis.Get(reftab[j][k-1]);
+		    }
+		  nel.SetIndex(ind);
+		
+		  if (j == 0)
+		    mesh.SurfaceElement(i) = nel;
+		  else
+		    mesh.AddSurfaceElement(nel);
+		}
+	      break;
+	    }
+	  default:
+	    PrintSysError ("Refine: undefined surface element type ", int(el.GetType()));
+	  }
+      }
+    
+    (*testout) << "refine volume" << endl;
+
+    // refine volume elements
+    oldne = mesh.GetNE();
+    for (i = 1; i <= oldne; i++)
+      {
+	int j, k;
+	const Element & el = mesh.VolumeElement(i);
+	ArrayMem<int,10> pnums(10);
+	static int betw[6][3] =
+	  { { 1, 2, 5 },
+	    { 1, 3, 6 },
+	    { 1, 4, 7 },
+	    { 2, 3, 8 },
+	    { 2, 4, 9 },
+	    { 3, 4, 10 } };
+	  
+	int elrev = el.flags.reverse;
+
+	for (j = 1; j <= 4; j++)
+	  pnums.Elem(j) = el.PNum(j);
+	if (elrev)
+	  Swap (pnums.Elem(3), pnums.Elem(4));
+
+	for (j = 0; j < 6; j++)
+	  {
+	    INDEX_2 i2;
+	    i2.I1() = pnums.Get(betw[j][0]);
+	    i2.I2() = pnums.Get(betw[j][1]);
+	    i2.Sort();
+
+	    if (between.Used(i2))
+	      pnums.Elem(5+j) = between.Get(i2);
+	    else
+	      {
+		pnums.Elem(5+j) = mesh.AddPoint
+		  (Center (mesh.Point(i2.I1()),
+			   mesh.Point(i2.I2())));
+		between.Set (i2, pnums.Elem(5+j));
+	      }
+	  }
+
+	static int reftab[8][4] = 
+	  { { 1, 5, 6, 7 },
+	    { 5, 2, 8, 9 },
+	    { 6, 8, 3, 10 },
+	    { 7, 9, 10, 4 },
+	    { 5, 6, 7, 9 },
+	    { 5, 6, 9, 8 },
+	    { 6, 7, 9, 10 },
+	    { 6, 8, 10, 9 } };
+	/*
+	  { { 1, 5, 6, 7 },
+	  { 5, 2, 8, 9 },
+	  { 6, 8, 3, 10 },
+	  { 7, 9, 10, 4 },
+	  { 5, 6, 7, 9 },
+	  { 5, 6, 8, 9 },
+	  { 6, 7, 9, 10 },
+	  { 6, 8, 9, 10 } };
+	*/
+	static int reverse[8] =
+	  {
+	    0, 0, 0, 0, 0, 1, 0, 1
+	  };
+
+	int ind = el.GetIndex();
+	for (j = 0; j < 8; j++)
+	  {
+	    Element nel;
+	    for (k = 1; k <= 4; k++)
+	      nel.PNum(k) = pnums.Get(reftab[j][k-1]);
+	    nel.SetIndex(ind);
+	    nel.flags.reverse = reverse[j];
+	    if (elrev)
+	      {
+		nel.flags.reverse = 1 - nel.flags.reverse;
+		Swap (nel.PNum(3), nel.PNum(4));
+	      }
+
+	    if (j == 0)
+	      mesh.VolumeElement(i) = nel;
+	    else
+	      mesh.AddVolumeElement (nel);
+	  }
+      }
+      
+    // update identification tables
+    for (i = 1; i <= mesh.GetIdentifications().GetMaxNr(); i++)
+      {
+	ARRAY<int,PointIndex::BASE> identmap;
+	mesh.GetIdentifications().GetMap (i, identmap);
+
+	for (j = 1; j <= between.GetNBags(); j++)
+	  for (k = 1; k <= between.GetBagSize(j); k++)
+	    {
+	      INDEX_2 i2;
+	      int newpi;
+	      between.GetData (j, k, i2, newpi);
+	      INDEX_2 oi2(identmap.Get(i2.I1()),
+			  identmap.Get(i2.I2()));
+	      oi2.Sort();
+	      if (between.Used (oi2))
+		{
+		  int onewpi = between.Get(oi2);
+		  mesh.GetIdentifications().Add (newpi, onewpi, i);
+		}
+	    }
+
+      }
+
+
+    
+      
+
+    int cnttrials = 10;
+    int wrongels = 0;
+    for (i = 1; i <= mesh.GetNE(); i++)
+      if (mesh.VolumeElement(i).Volume(mesh.Points()) < 0)
+	{
+	  wrongels++;
+	  mesh.VolumeElement(i).flags.badel = 1;
+	}
+      else
+	mesh.VolumeElement(i).flags.badel = 0;
+
+      
+    if (wrongels)
+      {
+	cout << "WARNING: " << wrongels << " with wrong orientation found" << endl;
+
+	int np = mesh.GetNP();
+	ARRAY<Point3d> should(np);
+	ARRAY<Point3d> can(np);
+	for (i = 1; i <= np; i++)
+	  {
+	    should.Elem(i) = can.Elem(i) = mesh.Point(i);
+	  }
+	for (i = 1; i <= between.GetNBags(); i++)
+	  for (j = 1; j <= between.GetBagSize(i); j++)
+	    {
+	      INDEX_2 parent;
+	      int child;
+	      between.GetData (i, j, parent, child);
+	      can.Elem(child) = Center (can.Elem(parent.I1()),
+					can.Elem(parent.I2()));
+	    }
+
+	BitArray boundp(np);
+	boundp.Clear();
+	for (i = 1; i <= mesh.GetNSE(); i++)
+	  {
+	    const Element2d & sel = mesh.SurfaceElement(i);
+	    for (j = 1; j <= sel.GetNP(); j++)
+	      boundp.Set(sel.PNum(j));
+	  }
+
+
+	double lam = 0.5;
+
+	while (lam < 0.9 && cnttrials > 0)
+	  {
+	    lam = 2;
+	    do
+	      {
+		lam *= 0.5;
+		cnttrials--;
+
+		cout << "lam = " << lam << endl;
+
+		for (i = 1; i <= np; i++)
+		  if (boundp.Test(i))
+		    {
+		      for (j = 1; j <= 3; j++)
+			mesh.Point(i).X(j) = 
+			  lam * should.Get(i).X(j) +
+			  (1-lam) * can.Get(i).X(j);
+		    }
+		  else
+		    mesh.Point(i) = can.Get(i);
+	      
+
+		BitArray free (mesh.GetNP()), fhelp(mesh.GetNP());
+		free.Clear();
+		for (i = 1; i <= mesh.GetNE(); i++)
+		  {
+		    const Element & el = mesh.VolumeElement(i);
+		    if (el.Volume(mesh.Points()) < 0)
+		      for (j = 1; j <= el.GetNP(); j++)
+			free.Set (el.PNum(j));
+		  }
+		for (k = 1; k <= 3; k++)
+		  {
+		    fhelp.Clear();
+		    for (i = 1; i <= mesh.GetNE(); i++)
+		      {
+			const Element & el = mesh.VolumeElement(i);
+			int freeel = 0;
+			for (j = 1; j <= el.GetNP(); j++)
+			  if (free.Test(el.PNum(j)))
+			    freeel = 1;
+			if (freeel)
+			  for (j = 1; j <= el.GetNP(); j++)
+			    fhelp.Set (el.PNum(j));
+		      }
+		    free.Or (fhelp);
+		  }
+
+		(*testout) << "smooth points: " << endl;
+		for (i = 1; i <= free.Size(); i++)
+		  if (free.Test(i))
+		    (*testout) << "p " << i << endl;
+
+		(*testout) << "surf points: " << endl;
+		for (i = 1; i <= mesh.GetNSE(); i++)
+		  for (j = 1; j <= 3; j++)
+		    (*testout) << mesh.SurfaceElement(i).PNum(j) << endl;
+		  
+
+
+		mesh.CalcSurfacesOfNode();
+		free.Invert();
+		mesh.FixPoints (free);
+		mesh.ImproveMesh (OPT_REST);
+
+
+		wrongels = 0;
+		for (i = 1; i <= mesh.GetNE(); i++)
+		  {
+		    if (mesh.VolumeElement(i).Volume(mesh.Points()) < 0)
+		      {
+			wrongels++;
+			mesh.VolumeElement(i).flags.badel = 1;
+			(*testout) << "wrong el: ";
+			for (j = 1; j <= 4; j++)
+			  (*testout) << mesh.VolumeElement(i).PNum(j) << " ";
+			(*testout) << endl;
+		      }
+		    else
+		      mesh.VolumeElement(i).flags.badel = 0;
+		  }
+		cout << "wrongels = " << wrongels << endl;
+	      }
+	    while (wrongels && cnttrials > 0);
+	  
+	    for (i = 1; i <= np; i++)
+	      can.Elem(i) = mesh.Point(i);
+	  }
+      }
+
+    if (cnttrials <= 0)
+      {
+	cerr << "ERROR: Sorry, reverted elements" << endl;
+      }
+ 
+    mesh.ComputeNVertices();
+    (*testout) << "refine done" << endl;
+
+  }
+}
diff --git a/Netgen/libsrc/meshing/ruler2.cpp b/Netgen/libsrc/meshing/ruler2.cpp
new file mode 100644
index 0000000000..700a3c4f70
--- /dev/null
+++ b/Netgen/libsrc/meshing/ruler2.cpp
@@ -0,0 +1,642 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+namespace netgen
+{
+static double CalcElementBadness (const ARRAY<Point2d> & points,
+				  const Element2d & elem)
+{
+  // badness = sqrt(3) /36 * circumference^2 / area - 1 +
+  //           h / li + li / h - 2
+
+  Vec2d v12, v13, v23;
+  double l12, l13, l23, cir, area;
+  static const double c = sqrt(3.0) / 36;
+
+  v12 = points.Get(elem.PNum(2)) - points.Get(elem.PNum(1));
+  v13 = points.Get(elem.PNum(3)) - points.Get(elem.PNum(1));
+  v23 = points.Get(elem.PNum(3)) - points.Get(elem.PNum(2));
+
+  l12 = v12.Length();
+  l13 = v13.Length();
+  l23 = v23.Length();
+
+  cir = l12 + l13 + l23;
+  area = 0.5 * (v12.X() * v13.Y() - v12.Y() * v13.X());
+  if (area < 1e-6)
+    {
+      return 1e8;
+    }
+
+  if (testmode)
+    {
+      (*testout) << "l = " << l12 << " + " << l13 << " + " << l23 << " = " 
+		 << cir << ", area = " << area << endl;
+      (*testout) << "shapeerr = " << 10 * (c * cir * cir / area - 1) << endl
+		 << "sizeerr = " << 1/l12 + l12 + 1/l13 + l13 + 1/l23 + l23 - 6
+		 << endl;
+    }
+
+  return 10 * (c * cir * cir / area - 1)
+    + 1/l12 + l12 + 1/l13 + l13 + 1/l23 + l23 - 6;
+}
+
+
+
+int Meshing2 ::ApplyRules (ARRAY<Point2d> & lpoints, 
+			   ARRAY<int> & legalpoints,
+			   int maxlegalpoint,
+			   ARRAY<INDEX_2> & llines,
+			   int maxlegalline,
+			   ARRAY<Element2d> & elements,
+			   ARRAY<INDEX> & dellines, int tolerance)
+{
+  int i, j, ri, nlok, npok, incnpok, refpi, locli = 0;
+
+  double maxerr = 0.5 + 0.3 * tolerance;
+  double minelerr = 2 + 0.5 * tolerance * tolerance;
+
+
+  int ok, found;
+  netrule * rule;
+  Vector oldu, newu;
+  Point2d np;
+  Vec2d linevec;
+  int oldnp;
+  INDEX_2 loclin;
+  double hf, elerr;
+  int noldlp, noldll;
+  int loctestmode;
+
+  static ARRAY<int> pused, lused;
+  static ARRAY<int> pmap, lmap, pfixed;
+  static ARRAY<int> pnearness, lnearness;
+  
+  static ARRAY<Point2d> tempnewpoints;
+  static ARRAY<INDEX_2> tempnewlines;
+  static ARRAY<int> tempdellines;
+  static ARRAY<Element2d> tempelements;
+
+
+
+  elements.SetSize (0);
+  dellines.SetSize (0);
+
+  noldlp = lpoints.Size();
+  noldll = llines.Size();
+
+  pused.SetSize (maxlegalpoint);
+  lused.SetSize (maxlegalline);
+  pnearness.SetSize (noldlp);
+  lnearness.SetSize (llines.Size());
+
+
+  testmode = debugparam.debugoutput;
+  loctestmode = testmode;
+
+  if (loctestmode)
+    {
+      (*testout) << endl << endl << "Check new environment" << endl;
+      (*testout) << "tolerance = " << tolerance << endl;
+      for (i = 1; i <= lpoints.Size(); i++)
+	(*testout) << "P" << i << " = " << lpoints.Get(i) << endl;
+      (*testout) << endl;
+      for (i = 1; i <= llines.Size(); i++)
+	(*testout) << "(" << llines.Get(i).I1() << "-" << llines.Get(i).I2() << ")" << endl;
+    }
+
+  // check every rule
+
+  found = 0;
+
+  
+  for (i = 1; i <= noldlp; i++)
+    pnearness.Set(i, 1000);
+  
+  for (j = 1; j <= 2; j++)
+    pnearness.Set(llines.Get(1).I(j), 0);
+    
+
+  do
+    {
+      ok = 1;
+      for (i = 1; i <= maxlegalline; i++)
+	{
+	  const INDEX_2 & hline = llines.Get(i);
+
+	  /*
+	  int minn = INT_MAX-1;
+	  for (j = 1; j <= 2; j++)
+	    {
+	      int hi = pnearness.Get(hline.I(j));
+	      if (hi < minn) minn = hi;
+	    }
+	  */
+	  int minn = pnearness.Get(hline.I1());
+	  int minn2 = pnearness.Get(hline.I2());
+	  if (minn2 < minn)
+	    minn = minn2;
+
+	  /*
+	  for (j = 1; j <= 2; j++)
+	    {
+	      int hpi = hline.I(j);
+	      if (pnearness.Get(hpi) > minn+1)
+		{
+		  ok = 0;
+		  pnearness.Set(hpi, minn+1);
+		}
+	    }
+	  */
+	  int hpi = hline.I1();
+	  if (pnearness.Get(hpi) > minn+1)
+	    {
+	      ok = 0;
+	      pnearness.Set(hpi, minn+1);
+	    }
+	  hpi = hline.I2();
+	  if (pnearness.Get(hpi) > minn+1)
+	    {
+	      ok = 0;
+	      pnearness.Set(hpi, minn+1);
+	    }
+	}
+    }
+  while (!ok);
+  
+  for (i = 1; i <= maxlegalline /* lnearness.Size() */; i++)
+    {
+      lnearness.Set(i, 0);
+      for (j = 1; j <= 2; j++)
+	lnearness.Elem(i) += pnearness.Get(llines.Get(i).I(j));
+    }
+
+
+
+#ifdef MARK
+  MARK (applyrules2m1);
+#endif
+
+  for (ri = 1; ri <= rules.Size(); ri++)
+    {
+#ifdef MARK
+      MARK (applyrules2m1a);
+#endif
+
+      rule = rules.Get(ri);
+
+      if (loctestmode)
+	(*testout) << "Rule " << rule->Name() << endl;
+
+      if (rule->GetQuality() > tolerance) continue;
+
+      pmap.SetSize (rule->GetNP());
+      lmap.SetSize (rule->GetNL());
+
+      for (i = 1; i <= lused.Size(); i++)
+	lused.Set (i, 0);
+      for (i = 1; i <= pused.Size(); i++)
+	pused.Set (i, 0);
+      for (i = 1; i <= pmap.Size(); i++)
+	pmap.Set(i, 0);
+      for (i = 1; i <= lmap.Size(); i++)
+	lmap.Set(i, 0);
+
+      lused.Set (1, 1);
+      lmap.Set (1, 1);
+
+      for (j = 1; j <= 2; j++)
+	{
+	  pmap.Elem(rule->GetPointNr (1, j)) = llines.Get(1).I(j);
+	  pused.Elem(llines.Get(1).I(j))++;
+	}
+
+
+      nlok = 2;
+
+      while (nlok >= 2)
+	{
+
+#ifdef MARK
+      MARK (applyrules2m2b);
+#endif
+
+
+	  if (nlok <= rule->GetNOldL())
+
+	    {
+	      ok = 0;
+	      while (!ok && lmap.Get(nlok) < maxlegalline  /* llines.Size() */)
+		{
+		  lmap.Elem(nlok)++;
+		  locli = lmap.Get(nlok);
+
+		  if (!lused.Get(locli) && 
+		      lnearness.Get(locli) <= rule->GetLNearness (nlok) )
+		    {
+		      ok = 1;
+
+		      loclin = llines.Get(locli);
+
+		      linevec.X() = lpoints.Get (loclin.I2()).X() -
+			lpoints.Get (loclin.I1()).X();
+		      linevec.Y() = lpoints.Get (loclin.I2()).Y() -
+			lpoints.Get (loclin.I1()).Y();
+
+		      if (rule->CalcLineError (nlok, linevec) > maxerr)
+			ok = 0;
+
+		      for (j = 1; j <= 2 && ok; j++)
+			{
+			  refpi = rule->GetPointNr (nlok, j);
+
+			  if (pmap.Get(refpi) != 0)
+			    {
+			      if (pmap.Get(refpi) != loclin.I(j))
+				ok = 0;
+			    }
+			  else
+			    {
+			      if (rule->CalcPointDist (refpi, lpoints.Get(loclin.I(j))) > maxerr
+				  || !legalpoints.Get(loclin.I(j))
+				  || pused.Get(loclin.I(j)))
+				ok = 0;
+			    }
+			}
+		    }
+		}
+
+	      if (ok)
+		{
+		  lused.Set (locli, 1);
+		  for (j = 1; j <= 2; j++)
+		    {
+		      pmap.Set(rule->GetPointNr (nlok, j), loclin.I(j));
+		      pused.Elem(loclin.I(j))++;
+		    }
+
+		  nlok++;
+		}
+	      else
+		{
+		  lmap.Elem(nlok) = 0;
+		  nlok--;
+
+		  lused.Set (lmap.Get(nlok), 0);
+		  for (j = 1; j <= 2; j++)
+		    {
+		      pused.Elem(llines.Get(lmap.Get(nlok)).I(j)) --;
+		      if (! pused.Get (llines.Get (lmap.Get (nlok)).I(j)))
+			pmap.Set (rule->GetPointNr (nlok, j), 0);
+		    }
+		}
+	    }
+
+	  else
+
+	    {
+
+#ifdef MARK
+      MARK (applyrules2mc);
+#endif
+
+
+	      // all lines are mapped !!
+
+	      // map also all points:
+
+	      npok = 1;
+	      incnpok = 1;
+
+	      pfixed.SetSize (pmap.Size());
+	      for (i = 1; i <= pmap.Size(); i++)
+		pfixed.Elem(i) = (pmap.Get(i) >= 1);
+
+	      while (npok >= 1)
+		{
+
+		  if (npok <= rule->GetNOldP())
+
+		    {
+		      if (pfixed.Get(npok))
+
+			{
+			  if (incnpok)
+			    npok++;
+			  else
+			    npok--;
+			}
+
+		      else
+
+			{
+			  ok = 0;
+
+			  if (pmap.Get(npok))
+			    pused.Elem(pmap.Get(npok))--;
+
+			  while (!ok && pmap.Get(npok) < maxlegalpoint /* lpoints.Size() */)
+			    {
+			      ok = 1;
+
+			      pmap.Elem(npok)++;
+
+			      if (pused.Get(pmap.Get(npok)))
+				{
+				  ok = 0;
+				}
+			      else
+				{
+				  if (rule->CalcPointDist (npok, lpoints.Get(pmap.Get(npok))) > maxerr 
+				      || !legalpoints.Get(pmap.Get(npok)) 
+				      )
+				    ok = 0;
+				}
+			    }
+
+			  if (ok)
+			    {
+			      pused.Elem(pmap.Get(npok))++;
+			      npok++;
+			      incnpok = 1;
+			    }
+
+			  else
+
+			    {
+			      pmap.Elem(npok) = 0;
+			      npok--;
+			      incnpok = 0;
+			    }
+			}
+		    }
+
+		  else
+
+		    {
+#ifdef MARK
+      MARK (applyrules2m2d);
+#endif
+
+		      if (ok)
+			{
+			  foundmap.Elem(ri)++;
+			}
+
+		      if (loctestmode)
+			(*testout) << "lines and points mapped" << endl;
+
+		      oldu.SetSize (2 * rule->GetNOldP());
+
+		      for (i = 1; i <= rule->GetNOldP(); i++)
+			{
+			  //			  ui = lpoints.Get(pmap.Get(i)) - rule->GetPoint(i);
+			  Vec2d ui(rule->GetPoint(i), lpoints.Get(pmap.Get(i)));
+			  oldu.Set (2*i-1, ui.X());
+			  oldu.Set (2*i  , ui.Y());
+			}
+
+		      rule -> SetFreeZoneTransformation (oldu, tolerance);
+
+		      ok = 1;
+
+		      if (!rule->ConvexFreeZone())
+			{
+			  ok = 0;
+			  if (loctestmode) (*testout) << "freezone not convex" << endl;
+			}
+
+		      // check freezone:
+
+		      for (i = 1; i <= maxlegalpoint && ok; i++)
+			{
+			  if ( !pused.Get(i) &&
+			       rule->IsInFreeZone (lpoints.Get(i)) )
+			    {
+			      ok = 0;
+			      if (loctestmode)
+				(*testout) << "Point " << i << " in freezone" << endl;
+			    }
+			}
+
+
+		      for (i = maxlegalpoint+1; i <= lpoints.Size() && ok; i++)
+			{
+			  if ( rule->IsInFreeZone (lpoints.Get(i)) )
+			    {
+			      ok = 0;
+			      if (loctestmode)
+				(*testout) << "Point " << i << " in freezone" << endl;
+			    }
+			}
+
+		      for (i = 1; i <= maxlegalline && ok; i++)
+			{
+			  if (!lused.Get(i) && 
+			      rule->IsLineInFreeZone (lpoints.Get(llines.Get(i).I1()),
+						      lpoints.Get(llines.Get(i).I2())))
+			    {
+			      ok = 0;
+			      if (loctestmode)
+				(*testout) << "line " << llines.Get(i).I1() << "-"
+					   << llines.Get(i).I2() << " in freezone" << endl;
+			    }
+			}
+		      for (i = maxlegalline+1; i <= llines.Size() && ok; i++)
+			{
+			  if (rule->IsLineInFreeZone (lpoints.Get(llines.Get(i).I1()),
+						      lpoints.Get(llines.Get(i).I2())))
+			    {
+			      ok = 0;
+			      if (loctestmode)
+				(*testout) << "line " << llines.Get(i).I1() << "-"
+					   << llines.Get(i).I2() << " in freezone" << endl;
+			    }
+			}
+
+
+
+		      // check orientations
+
+		      for (i = 1; i <= rule->GetNOrientations() && ok; i++)
+			{
+			  if (CW (lpoints.Get(pmap.Get(rule->GetOrientation(i).i1)),
+				  lpoints.Get(pmap.Get(rule->GetOrientation(i).i2)),
+				  lpoints.Get(pmap.Get(rule->GetOrientation(i).i3))) )
+			    {
+			      ok = 0;
+			      if (loctestmode)
+				(*testout) << "Orientation " << i << " not ok" << endl;
+			    }
+			}
+
+
+
+		      if (ok)
+			{
+			  if (loctestmode)
+			    (*testout) << "rule ok" << endl;
+
+			  //			  newu = rule->GetOldUToNewU() * oldu;
+			  if (rule->GetNOldP() < rule->GetNP())
+			    {
+			      newu.SetSize (rule->GetOldUToNewU().Height());
+			      rule->GetOldUToNewU().Mult (oldu, newu);
+			    }
+
+			  // Setze neue Punkte:
+
+			  oldnp = rule->GetNOldP();
+
+			  for (i = oldnp + 1; i <= rule->GetNP(); i++)
+			    {
+			      np = rule->GetPoint(i);
+			      np.X() += newu.Elem (2 * (i-oldnp) - 1);
+			      np.Y() += newu.Elem (2 * (i-oldnp));
+
+			      pmap.Elem(i) = lpoints.Append (np);
+			    }
+
+			  // Setze neue Linien:
+
+			  for (i = rule->GetNOldL() + 1; i <= rule->GetNL(); i++)
+			    {
+			      llines.Append (INDEX_2 (pmap.Get(rule->GetPointNr (i, 1)),
+						      pmap.Get(rule->GetPointNr (i, 2))));
+			    }
+
+
+			  // delete old lines:
+
+			  for (i = 1; i <= rule->GetNDelL(); i++)
+			    dellines.Append (lmap.Get(rule->GetDelLine(i)));
+
+			  // insert new elements:
+
+			  for (i = 1; i <= rule->GetNE(); i++)
+			    {
+			      elements.Append (rule->GetElement(i));
+			      for (j = 1; j <= elements.Get(i).GetNP(); j++)
+				elements.Elem(i).PNum(j) = pmap.Get(elements.Get(i).PNum(j));
+			    }
+
+
+			  elerr = 0;
+			  for (i = 1; i <= elements.Size(); i++)
+			    {
+			      if (!mparam.quad)
+				hf = CalcElementBadness (lpoints, elements.Get(i));
+			      else
+				hf = elements.Get(i).CalcJacobianBadness (lpoints) * 5;
+			      if (loctestmode)
+				(*testout) << "r " << rule->Name() << "bad = " << hf << endl;
+			      if (hf > elerr) elerr = hf;
+			    }
+
+			  if (loctestmode)
+			    (*testout) << "error = " << elerr;
+
+
+			  canuse.Elem(ri) ++;
+
+			  if (elerr < minelerr)
+			    {
+
+			      if (testmode)
+				{
+				  (*testout) << "rule = " << rule->Name() << endl;
+				  (*testout) << "class = " << tolerance << endl;
+				  (*testout) << "lpoints: " << endl;
+				  for (i = 1; i <= lpoints.Size(); i++)
+				    (*testout) << lpoints.Get(i) << endl;
+				  (*testout) << "llines: " << endl;
+				  for (i = 1; i <= llines.Size(); i++)
+				    (*testout) << llines.Get(i).I1() << " " << llines.Get(i).I2() << endl;
+
+				  (*testout) << "Freezone: ";
+				  for (i = 1; i <= rule -> GetTransFreeZone().Size(); i++)
+				    (*testout) << rule->GetTransFreeZone().Get(i) << endl;
+				}
+
+
+
+			      minelerr = elerr;
+			      found = ri;
+
+			      tempnewpoints.SetSize (0);
+			      for (i = noldlp+1; i <= lpoints.Size(); i++)
+				tempnewpoints.Append (lpoints.Get(i));
+
+			      tempnewlines.SetSize (0);
+			      for (i = noldll+1; i <= llines.Size(); i++)
+				tempnewlines.Append (llines.Get(i));
+
+			      tempdellines.SetSize (0);
+			      for (i = 1; i <= dellines.Size(); i++)
+				tempdellines.Append (dellines.Get(i));
+
+			      tempelements.SetSize (0);
+			      for (i = 1; i <= elements.Size(); i++)
+				tempelements.Append (elements.Get(i));
+			    }
+
+			  lpoints.SetSize (noldlp);
+			  llines.SetSize (noldll);
+			  dellines.SetSize (0);
+			  elements.SetSize (0);
+			  ok = 0;
+
+			}
+
+
+		      npok = rule->GetNOldP();
+		      incnpok = 0;
+		    }
+		}
+
+	      nlok = rule->GetNOldL();
+
+	      lused.Set (lmap.Get(nlok), 0);
+
+	      for (j = 1; j <= 2; j++)
+		{
+		  refpi = rule->GetPointNr (nlok, j);
+		  pused.Elem(pmap.Get(refpi))--;
+
+		  if (pused.Get(pmap.Get(refpi)) == 0)
+		    {
+		      pmap.Set(refpi, 0);
+		    }
+		}
+	    }
+	}
+    }
+
+
+#ifdef MARK
+  MARK (applyrules2m3);
+#endif
+
+
+  if (found)
+    {
+      for (i = 1; i <= tempnewpoints.Size(); i++)
+	lpoints.Append (tempnewpoints.Get(i));
+      for (i = 1; i <= tempnewlines.Size(); i++)
+	llines.Append (tempnewlines.Get(i));
+      for (i = 1; i <= tempdellines.Size(); i++)
+	dellines.Append (tempdellines.Get(i));
+      for (i = 1; i <= tempelements.Size(); i++)
+	elements.Append (tempelements.Get(i));
+
+      //    (*testout) << "minelerr = " << minelerr << endl;
+    }
+
+  return found;
+}
+
+
+
+
+
+}
diff --git a/Netgen/libsrc/meshing/ruler2.hpp b/Netgen/libsrc/meshing/ruler2.hpp
new file mode 100644
index 0000000000..3627df521e
--- /dev/null
+++ b/Netgen/libsrc/meshing/ruler2.hpp
@@ -0,0 +1,149 @@
+#ifndef FILE_NETRULE
+#define FILE_NETRULE
+
+///
+class netrule
+{
+private:
+  ///
+  typedef struct tf 
+  { float f1, f2, f3; }   threefloat;
+  
+  class threeint 
+  { 
+  public: int i1, i2, i3; 
+    threeint() { } 
+    threeint(int ai1, int ai2, int ai3) 
+    { i1 = ai1; i2 = ai2; i3 = ai3; } 
+  };
+
+
+  ///
+  int quality;
+  ///
+  char * name;
+  ///
+  ARRAY<Point2d> points;
+  ///
+  ARRAY<INDEX_2> lines;
+  ///
+  ARRAY<Point2d> freezone, freezonelimit;
+  ///
+  ARRAY<Point2d> transfreezone;
+
+  ///
+  ARRAY<int> dellines;
+  ///
+  ARRAY<Element2d> elements;
+  ///
+  ARRAY<threefloat> tolerances, linetolerances;
+  ///
+  ARRAY<threeint> orientations;
+  ///
+  DenseMatrix oldutonewu, oldutofreearea, oldutofreearealimit;
+  ///
+  MatrixFixWidth<3> freesetinequ;
+
+  ///
+  ARRAY<Vec2d> linevecs;
+
+  ///
+  int noldp, noldl;
+  ///
+  float fzminx, fzmaxx, fzminy, fzmaxy;
+
+  /// topological distance of line to base element
+  ARRAY<int> lnearness;
+
+public:
+
+  ///
+  netrule ();
+  ///
+  ~netrule();
+
+  ///
+  int GetNP () const { return points.Size(); }
+  ///
+  int GetNL () const { return lines.Size(); }
+  ///
+  int GetNE () const { return elements.Size(); }
+  ///
+  int GetNOldP () const { return noldp; }
+  ///
+  int GetNOldL () const { return noldl; }
+  ///
+  int GetNDelL () const { return dellines.Size(); }
+  ///
+  int GetNOrientations () const { return orientations.Size(); }
+  ///
+  int GetQuality () const { return quality; }
+  ///
+  int GetLNearness (int li) const { return lnearness.Get(li); }
+
+  ///
+  const Point2d & GetPoint (int i) const { return points.Get(i); }
+  ///
+  const INDEX_2 & GetLine (int i) const { return lines.Get(i); }
+  ///
+  const Element2d & GetElement (int i) const { return elements.Get(i); }
+  ///
+  const threeint & GetOrientation (int i) const { return orientations.Get(i); }
+  ///
+  int GetDelLine (int i) const { return dellines.Get(i); }
+
+  ///
+  void GetFreeZone (ARRAY<Point2d> & afreearea);
+  ///
+  float CalcPointDist (int pi, const Point2d & p) const;
+  ///
+  float CalcLineError (int li, const Vec2d & v) const;
+
+  ///
+  void SetFreeZoneTransformation (const Vector & u, int tolclass);
+  ///
+  int IsInFreeZone (const Point2d & p) const
+  {
+    if (p.X() < fzminx || p.X() > fzmaxx ||
+	p.Y() < fzminy || p.Y() > fzmaxy) return 0;
+    return IsInFreeZone2 (p);
+  }
+  ///
+  int IsInFreeZone2 (const Point2d & p) const;
+  ///
+  int IsLineInFreeZone (const Point2d & p1, const Point2d & p2) const
+  {
+    if (p1.X() > fzmaxx && p2.X() > fzmaxx ||
+	p1.X() < fzminx && p2.X() < fzminx ||
+	p1.Y() > fzmaxy && p2.Y() > fzmaxy ||
+	p1.Y() < fzminy && p2.Y() < fzminy) return 0;
+    return IsLineInFreeZone2 (p1, p2);
+  }
+  ///
+  int IsLineInFreeZone2 (const Point2d & p1, const Point2d & p2) const;
+  ///
+  int ConvexFreeZone () const;
+  ///
+  const ARRAY<Point2d> & GetTransFreeZone () { return transfreezone; }
+
+  ///
+  int GetPointNr (int ln, int endp) const { return lines.Get(ln).I(endp); }
+
+  ///
+  const DenseMatrix & GetOldUToNewU () const { return oldutonewu; }
+  ///
+  const DenseMatrix & GetOldUToFreeArea () const { return oldutofreearea; }
+  ///
+  const char * Name () const { return name; }
+
+  ///
+  void LoadRule (istream & ist);
+};
+
+
+
+/** Draws 2D rules.
+    Visual testing of 2D meshing rules */
+extern void DrawRules ();
+#endif
+
diff --git a/Netgen/libsrc/meshing/ruler3.cpp b/Netgen/libsrc/meshing/ruler3.cpp
new file mode 100644
index 0000000000..0d6c2dab1f
--- /dev/null
+++ b/Netgen/libsrc/meshing/ruler3.cpp
@@ -0,0 +1,1177 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+// #define MARK
+// #include <prof.h>
+
+namespace netgen
+{
+extern double minother;
+extern double minwithoutother;
+
+
+static double CalcElementBadness (const ARRAY<Point3d> & points,
+				  const Element & elem)
+{
+  double vol, l, l4, l5, l6;
+  if (elem.GetNP() != 4) 
+    {
+      if (elem.GetNP() == 5)
+	{
+	  double z = points.Get(elem.PNum(5)).Z();
+	  if (z > -1e-8) return 1e8;
+	  return (-1 / z) - z; //  - 2;
+	}
+      return 0;
+    }
+  
+  Vec3d v1 = points.Get(elem.PNum(2)) - points.Get(elem.PNum(1));
+  Vec3d v2 = points.Get(elem.PNum(3)) - points.Get(elem.PNum(1));
+  Vec3d v3 = points.Get(elem.PNum(4)) - points.Get(elem.PNum(1));
+  
+  vol = - (Cross (v1, v2) * v3);
+  l4 = Dist (points.Get(elem.PNum(2)), points.Get(elem.PNum(3)));
+  l5 = Dist (points.Get(elem.PNum(2)), points.Get(elem.PNum(4)));
+  l6 = Dist (points.Get(elem.PNum(3)), points.Get(elem.PNum(4)));
+
+  l = v1.Length() + v2.Length() + v3.Length() + l4 + l5 + l6;
+  
+  //  testout << "vol = " << vol << " l = " << l << endl;
+  if (vol < 1e-8) return 1e10;
+  //  (*testout) << "l^3/vol = " << (l*l*l / vol) << endl;
+  
+  double err = pow (l*l*l/vol, 1.0/3.0) / 12;
+  return err;
+}
+
+
+
+
+
+
+int Meshing3 :: ApplyRules 
+(
+ ARRAY<Point3d> & lpoints,     // in: local points, out: old+new local points
+ ARRAY<int> & allowpoint,      // in: 1 .. it is allowed to use pointi
+ ARRAY<Element2d> & lfaces,    // in: local faces, out: old+new local faces
+ INDEX lfacesplit,	       // for local faces in outer radius
+ INDEX_2_HASHTABLE<int> & connectedpairs,  // connected pairs for prism-meshing
+ ARRAY<Element> & elements,    // out: new elements
+ ARRAY<INDEX> & delfaces,      // out: face indices of faces to delete
+ int tolerance,                // quality class: 1 best 
+ double sloppy,                // quality strength
+ int rotind1,                  // how to rotate base element
+ float & retminerr             // element error 
+ )
+
+{
+  //  const int rotsym = 3;
+  int i, j, k, ri, nfok, npok, incnpok, refpi, locpi, locfi, locfr;
+  int hi, minn, hpi;
+  float hf, err, minerr, teterr, minteterr;
+  char ok, found, hc;
+  vnetrule * rule;
+  Vector oldu, newu, newu1, newu2, allp;
+  Vec3d ui;
+  Point3d np;
+  int oldnp, noldlp, noldlf;
+  const Element2d * locface = NULL;
+  int loktestmode;
+  
+  static ARRAY<int> pused;       // point is already mapped
+  static ARRAY<int> fused;       // face is already mapped
+  static ARRAY<int> pmap;        // map of reference point to local point
+  static ARRAY<int> pfixed;      // ???
+  static ARRAY<int> fmapi;       // face in reference is mapped to face nr ...
+  static ARRAY<int> fmapr;       // face in reference is rotated to map 
+  static ARRAY<Point3d> transfreezone;  // transformed free-zone
+  static INDEX cnt = 0;
+  INDEX_2_HASHTABLE<int> ledges(lfaces.Size());  // edges in local environment
+  
+  static ARRAY<Point3d> tempnewpoints;
+  static ARRAY<Element2d> tempnewfaces;
+  static ARRAY<int> tempdelfaces;
+  static ARRAY<Element> tempelements;
+  static ARRAY<Box3d> triboxes;         // bounding boxes of local faces
+
+
+  static ARRAY<int> pnearness;
+  static ARRAY<int> fnearness;
+  
+  cnt++;
+  
+  delfaces.SetSize (0);
+  elements.SetSize (0);
+
+
+  // determine topological distance of faces and points to
+  // base element
+
+
+  pnearness.SetSize (lpoints.Size());
+  fnearness.SetSize (lfacesplit);
+
+  for (i = 1; i <= pnearness.Size(); i++)
+    pnearness.Set(i, INT_MAX/10);
+
+  for (j = 1; j <= lfaces.Get(1).GetNP(); j++)
+    pnearness.Set(lfaces.Get(1).PNum(j), 0);
+
+
+  // MARK(appl1);
+  do
+    {
+      ok = 1;
+      
+      for (i = 1; i <= lfacesplit; i++)
+	{
+	  const Element2d & hface = lfaces.Get(i);
+
+	  minn = INT_MAX-1;
+	  for (j = 1; j <= hface.GetNP(); j++)
+	    {
+	      hi = pnearness.Get(hface.PNum(j));
+	      if (hi < minn) minn = hi;
+	    }
+	  
+	  for (j = 1; j <= hface.GetNP(); j++)
+	    {
+	      hpi = hface.PNum(j);
+	      if (pnearness.Get(hpi) > minn+1)
+		{
+		  ok = 0;
+		  pnearness.Set(hpi, minn+1);
+		}
+	    }
+	}
+
+      for (i = 1; i <= connectedpairs.GetNBags(); i++)
+	for (j = 1; j <= connectedpairs.GetBagSize(i); j++)
+	  {
+	    INDEX_2 edge;
+	    int val;
+	    connectedpairs.GetData (i, j, edge, val);
+
+	    
+	    if (edge.I1() > pnearness.Size() ||
+		edge.I2() > pnearness.Size() ||
+		edge.I1() < 1 ||
+		edge.I2() < 1)
+	      {
+		cerr << "pair out of range" << endl;
+		exit (1);
+	      }
+		
+	    if (pnearness.Get(edge.I1()) >
+		pnearness.Get(edge.I2()) + 1)
+	      {
+		;
+		ok = 0;
+		pnearness.Elem(edge.I1()) = 
+		  pnearness.Get(edge.I2()) + 1;
+	      }
+	    if (pnearness.Get(edge.I2()) >
+		pnearness.Get(edge.I1()) + 1)
+	      {
+		;
+		ok = 0;
+		pnearness.Elem(edge.I2()) = 
+		  pnearness.Get(edge.I1()) + 1;
+	      }
+	  }
+    }
+  while (!ok);
+
+  
+  for (i = 1; i <= fnearness.Size(); i++)
+    {
+      fnearness.Set(i, 0);
+      for (j = 1; j <= lfaces.Get(i).GetNP(); j++)
+	fnearness.Elem(i) += pnearness.Get(lfaces.Get(i).PNum(j));
+    }
+
+
+  // MARK(appl2);
+
+  // find bounding boxes of faces
+
+  triboxes.SetSize (lfaces.Size());
+  for (i = 1; i <= lfaces.Size(); i++)
+    {
+      const Element2d & face = lfaces.Get(i);
+      triboxes.Elem(i).SetPoint (lpoints.Get(face.PNum(1)));
+      for (j = 2; j <= face.GetNP(); j++)
+	triboxes.Elem(i).AddPoint (lpoints.Get(face.PNum(j)));
+    }
+
+  // MARK(appl3);  
+
+  /*
+  for (j = 1; j <= lfacesplit; j++)
+    for (k = 1; k <= lfaces.Get(j).GetNP(); k++)
+      {
+	INDEX_2 i2;
+	i2.I1() = lfaces.Get(j).PNumMod(k);
+	i2.I2() = lfaces.Get(j).PNumMod(k+1);
+	i2.Sort();
+	ledges.Set (i2, 1);
+      }
+  */  
+  
+  for (j = 1; j <= lfacesplit; j++)
+    {
+      const Element2d & face = lfaces.Get(j);
+      int newp, oldp;
+
+      newp = face.PNum(face.GetNP());
+      for (k = 1; k <= face.GetNP(); k++)
+	{
+	  oldp = newp;
+	  newp = face.PNum(k);
+	  
+	  INDEX_2 i2(oldp, newp);
+	  i2.Sort();
+	  ledges.Set (i2, 1);
+	}
+    }
+
+
+  pused.SetSize (lpoints.Size());
+  fused.SetSize (lfaces.Size());
+  
+
+
+  found = 0;
+  minerr = tolfak * tolerance * tolerance;
+  minteterr = sloppy * tolerance;
+
+  if (testmode)
+    (*testout) << "cnt = " << cnt << " class = " << tolerance << endl;
+
+
+  // check each rule:
+
+  // MARK(applyml);
+
+  for (ri = 1; ri <= rules.Size(); ri++)
+    { 
+      sprintf (problems.Elem(ri), "");
+
+      rule = rules.Get(ri);
+      
+      if (rule->GetNP(1) != lfaces.Get(1).GetNP())
+	continue;
+
+      if (rule->GetQuality() > tolerance)
+	{
+	  if (testmode)
+	    sprintf (problems.Elem(ri), "Quality not ok");
+	  continue;
+	}
+      
+      if (testmode)
+	sprintf (problems.Elem(ri), "no mapping found");
+      
+      loktestmode = testmode || rule->TestFlag ('t');
+      /*
+      if (tolerance > 8)
+	loktestmode = 1;
+      */
+
+      if (loktestmode)
+	(*testout) << "Rule " << ri << " = " << rule->Name() << endl;
+      
+      pmap.SetSize (rule->GetNP());
+      fmapi.SetSize (rule->GetNF());
+      fmapr.SetSize (rule->GetNF());
+      
+      for (i = 1; i <= lfaces.Size(); i++)
+	fused.Set (i, 0);
+      for (i = 1; i <= lpoints.Size(); i++)
+	pused.Set (i, 0);
+      for (i = 1; i <= pmap.Size(); i++)
+	pmap.Set(i, 0);
+      for (i = 1; i <= fmapi.Size(); i++)
+	fmapi.Set(i, 0);
+      for (i = 1; i <= fmapr.Size(); i++)
+	fmapr.Set(i, rule->GetNP(i));
+      
+      fused.Set (1, 1);
+      
+      fmapi.Set (1, 1);
+      fmapr.Set (1, rotind1);
+
+      
+      for (j = 1; j <= lfaces.Get(1).GetNP(); j++)
+	{
+	  locpi = lfaces.Get(1).PNumMod (j+rotind1);
+	  pmap.Set (rule->GetPointNr (1, j), locpi);
+	  pused.Elem(locpi)++;
+	}
+
+
+
+      /*
+	map all faces
+	nfok .. first nfok-1 faces are mapped properly
+	*/
+
+      nfok = 2;
+      while (nfok >= 2)
+	{
+	  
+	  if (nfok <= rule->GetNOldF())
+	    {
+	      // not all faces mapped
+
+	      ok = 0;
+	      locfi = fmapi.Get(nfok);
+	      locfr = fmapr.Get(nfok);
+
+	      int actfnp = rule->GetNP(nfok);
+
+	      while (!ok)
+		{
+		  locfr++;
+		  if (locfr == actfnp + 1)
+		    {
+		      locfr = 1;
+		      locfi++;
+		      if (locfi > lfacesplit) break;
+		    }
+		  
+		  
+		  if (fnearness.Get(locfi) > rule->GetFNearness (nfok) ||
+		      fused.Get(locfi) ||
+		      actfnp != lfaces.Get(locfi).GetNP() )
+		    {
+		      // face not feasible in any rotation
+
+		      locfr = actfnp;
+		    }
+		  else
+		    {
+		      
+		      ok = 1;
+		      
+		      locface = &lfaces.Get(locfi);
+
+		      
+		      // reference point already mapped differently ?
+		      for (j = 1; j <= actfnp && ok; j++)
+			{
+			  locpi = pmap.Get(rule->GetPointNr (nfok, j));
+			  
+			  if (locpi && locpi != locface->PNumMod(j+locfr))
+			    ok = 0;
+			}
+		      
+		      // local point already used or point outside tolerance ?
+		      for (j = 1; j <= actfnp && ok; j++)
+			{
+			  refpi = rule->GetPointNr (nfok, j);
+			  
+			  if (pmap.Get(refpi) == 0)
+			    {
+			      locpi = locface->PNumMod (j + locfr);
+
+			      if (pused.Get(locpi))
+				ok = 0;
+			      else
+				{
+				  const Point3d & lp = lpoints.Get(locpi);
+				  const Point3d & rp = rule->GetPoint(refpi);
+
+				  if ( Dist2 (lp, rp) * rule->PointDistFactor(refpi) > minerr)
+				    ok = 0;
+				}
+			    }
+			}
+		    }
+		}
+	      
+	      
+	      if (ok)
+		{
+		  // map face nfok
+
+		  fmapi.Set (nfok, locfi);
+		  fmapr.Set (nfok, locfr);
+		  fused.Set (locfi, 1);
+		  
+		  for (j = 1; j <= rule->GetNP (nfok); j++)
+		    {
+		      locpi = locface->PNumMod(j+locfr);
+		      
+		      if (rule->GetPointNr (nfok, j) <= 3 &&
+			  pmap.Get(rule->GetPointNr(nfok, j)) != locpi)
+			(*testout) << "change face1 point, mark1" << endl;
+		      
+		      pmap.Set(rule->GetPointNr (nfok, j), locpi);
+		      pused.Elem(locpi)++;
+		    }
+		  
+		  nfok++;
+		}
+	      else
+		{
+		  // backtrack one face
+		  fmapi.Set (nfok, 0);
+		  fmapr.Set (nfok, rule->GetNP(nfok));
+		  nfok--;
+		  
+		  fused.Set (fmapi.Get(nfok), 0);
+		  for (j = 1; j <= rule->GetNP (nfok); j++)
+		    {
+		      refpi = rule->GetPointNr (nfok, j);
+		      pused.Elem(pmap.Get(refpi))--;
+		      
+		      if (pused.Get(pmap.Get(refpi)) == 0)
+			{
+			  pmap.Set(refpi, 0);
+			}
+		    }
+		}
+	    }
+	  
+	  else
+	    
+	    { 
+
+	      // all faces are mapped
+	      // now map all isolated points:
+	      
+	      if (loktestmode)
+		{
+		  (*testout) << "Faces Ok" << endl;
+		  sprintf (problems.Elem(ri), "Faces Ok");
+		}
+	      
+	      npok = 1;
+	      incnpok = 1;
+	      
+	      pfixed.SetSize (pmap.Size());
+	      for (i = 1; i <= pmap.Size(); i++)
+		pfixed.Set(i, (pmap.Get(i) != 0) );
+	      
+	      while (npok >= 1)
+		{
+		  
+		  if (npok <= rule->GetNOldP())
+		    {
+		      
+		      if (pfixed.Get(npok))
+			
+			{
+			  if (incnpok)
+			    npok++;
+			  else
+			    npok--;
+			}
+		      
+		      else
+			
+			{
+			  locpi = pmap.Elem(npok);
+			  ok = 0;
+			  
+			  if (locpi)
+			    pused.Elem(locpi)--;
+			  
+			  while (!ok && locpi < lpoints.Size())
+			    {
+			      ok = 1;
+			      locpi++;
+			      
+			      if (pused.Get(locpi) || !allowpoint.Get(locpi) ||
+				  pnearness.Get(locpi) > rule->GetPNearness(npok))
+				{
+				  ok = 0;
+				}
+			      else
+				{
+				  const Point3d & lp = lpoints.Get(locpi);
+				  const Point3d & rp = rule->GetPoint(npok);
+
+				  if ( Dist2 (lp, rp) * rule->PointDistFactor(npok) > minerr)
+				    ok = 0;
+				}
+			    }
+			  
+			  
+			  if (ok)
+			    {
+			      pmap.Set (npok, locpi);
+			      
+			      if (npok <= 3)
+				(*testout) << "set face1 point, mark3" << endl;
+			      
+			      pused.Elem(locpi)++;
+			      npok++;
+			      incnpok = 1;
+			    }
+			  
+			  else
+			    
+			    {
+			      pmap.Set (npok, 0);
+			      
+			      if (npok <= 3)
+				(*testout) << "set face1 point, mark4" << endl;
+			      
+			      npok--;
+			      incnpok = 0;
+			    }
+			}
+		    }
+		  
+		  else
+		    
+		    {
+		      
+		      // all points are mapped
+		      
+		      if (loktestmode)
+			{
+			  (*testout) << "Mapping found!!: Rule " << rule->Name() << endl;
+			  for (i = 1; i <= pmap.Size(); i++)
+			    (*testout) << pmap.Get(i) << " ";
+			  (*testout) << endl;
+			  sprintf (problems.Elem(ri), "mapping found");
+			  (*testout) << rule->GetNP(1) << " = " << lfaces.Get(1).GetNP() << endl;
+			}
+		      
+		      ok = 1;
+		      
+		      
+		      // check mapedges:
+		      
+		      for (i = 1; i <= rule->GetNEd(); i++)
+			{
+			  int i1, i2;
+			  i1 = pmap.Get(rule->GetEdge(i).i1);
+			  i2 = pmap.Get(rule->GetEdge(i).i2);
+
+			  INDEX_2 in2(i1, i2);
+			  in2.Sort();
+			  if (!ledges.Used (in2)) ok = 0;
+			}
+
+
+		      // check prism edges:
+		      for (i = 1; i <= rule->GetNE(); i++)
+			{
+			  const Element & el = rule->GetElement (i);
+			  if (el.GetType() == PRISM) 
+			    { 
+			      for (j = 1; j <= 3; j++)
+				{
+				  int i1, i2;
+				  i1 = pmap.Get(el.PNum(j));
+				  i2 = pmap.Get(el.PNum(j+3));
+				  
+				  INDEX_2 in2(i1, i2);
+				  in2.Sort();
+				  if (!connectedpairs.Used (in2)) ok = 0;
+				}
+			    }
+			  if (el.GetType() == PYRAMID) 
+			    { 
+			      if (loktestmode)
+				(*testout) << "map pyramid, rule = " << rule->Name() << endl;
+			      for (j = 1; j <= 2; j++)
+				{
+				  INDEX_2 in2;
+				  if (j == 1)
+				    {
+				      in2.I1() = pmap.Get(el.PNum(2));
+				      in2.I2() = pmap.Get(el.PNum(3));
+				    }
+				  else
+				    {
+				      in2.I1() = pmap.Get(el.PNum(1));
+				      in2.I2() = pmap.Get(el.PNum(4));
+				    }
+				  in2.Sort();
+				  if (!connectedpairs.Used (in2)) 
+				    {
+				      ok = 0;
+				      if (loktestmode)
+					(*testout) << "no pair" << endl;
+				    }
+				}
+			    }
+
+			}
+		      
+
+		      
+		      for (i = rule->GetNOldF() + 1; i <= rule->GetNF(); i++)
+			fmapi.Set(i, 0);
+		      
+
+		      if (ok)
+			{
+			  foundmap.Elem(ri)++;
+			}
+
+		      
+
+
+		      // deviation of existing points
+
+		      oldu.SetSize (3 * rule->GetNOldP());
+		      newu.SetSize (3 * (rule->GetNP() - rule->GetNOldP()));
+		      allp.SetSize (3 * rule->GetNP());
+		      
+		      for (i = 1; i <= rule->GetNOldP(); i++)
+			{
+			  const Point3d & lp = lpoints.Get(pmap.Get(i));
+			  const Point3d & rp = rule->GetPoint(i);
+			  oldu.Set (3*i-2, lp.X()-rp.X());
+			  oldu.Set (3*i-1, lp.Y()-rp.Y());
+			  oldu.Set (3*i  , lp.Z()-rp.Z());
+			  
+			  allp.Set (3*i-2, lp.X());
+			  allp.Set (3*i-1, lp.Y());
+			  allp.Set (3*i  , lp.Z());
+			}
+
+		      if (rule->GetNP() > rule->GetNOldP())
+			{
+			  newu.SetSize (rule->GetOldUToNewU().Height());
+			  rule->GetOldUToNewU().Mult (oldu, newu);
+			}
+
+		      //		      int idiff = 3 * (rule->GetNP()-rule->GetNOldP());
+		      int idiff = 3 * rule->GetNOldP();
+		      for (i = rule->GetNOldP()+1; i <= rule->GetNP(); i++)
+			{
+			  const Point3d & rp = rule->GetPoint(i);
+			  allp.Set (3*i-2, rp.X() + newu.Get(3*i-2 - idiff));
+			  allp.Set (3*i-1, rp.Y() + newu.Get(3*i-1 - idiff));
+			  allp.Set (3*i  , rp.Z() + newu.Get(3*i   - idiff));
+			}
+		      
+		      rule->SetFreeZoneTransformation (allp, 
+						       tolerance + int(sloppy));
+
+		      if (!rule->ConvexFreeZone())
+			{
+			  ok = 0;
+			  sprintf (problems.Elem(ri), "Freezone not convex");
+
+			  if (loktestmode)
+			    (*testout) << "Freezone not convex" << endl;
+			}
+
+		      if (loktestmode)
+			{
+			  const ARRAY<Point3d> & fz = rule->GetTransFreeZone();
+			  (*testout) << "Freezone: " << endl;
+			  for (i = 1; i <= fz.Size(); i++)
+			    (*testout) << fz.Get(i) << endl;
+			}
+		      
+
+		      // check freezone:
+		      
+		      for (i = 1; i <= lpoints.Size(); i++)
+			{
+			  if ( !pused.Get(i) )
+			    {
+			      const Point3d & lp = lpoints.Get(i);
+
+			      if (rule->fzbox.IsIn (lp))
+				{
+				  if (rule->IsInFreeZone(lp))
+				    {
+				      if (loktestmode)
+					{
+					  (*testout) << "Point " << i 
+						     << " in Freezone" << endl;
+					  sprintf (problems.Elem(ri), 
+						   "locpoint %d in Freezone", i);
+					}
+				      ok = 0;
+				      break;
+				    }
+				}
+			    }
+			}
+
+		      for (i = 1; i <= lfaces.Size() && ok; i++)
+			{
+			  static ARRAY<int> lpi(4);
+
+			  if (!fused.Get(i))
+			    { 
+			      int triin;
+			      const Element2d & lfacei = lfaces.Get(i);
+
+			      if (!triboxes.Elem(i).Intersect (rule->fzbox))
+				triin = 0;
+			      else
+				{
+				  int li, lj;
+				  for (li = 1; li <= lfacei.GetNP(); li++)
+				    {
+				      int lpii = 0;
+				      int pi = lfacei.PNum(li);
+				      for (lj = 1; lj <= rule->GetNOldP(); lj++)
+					if (pmap.Get(lj) == pi)
+					  lpii = lj;
+				      lpi.Elem(li) = lpii;
+				    }
+
+
+				  if (lfacei.GetNP() == 3)
+				    {
+				      triin = rule->IsTriangleInFreeZone 
+					(
+					 lpoints.Get(lfacei.PNum(1)),
+					 lpoints.Get(lfacei.PNum(2)),
+					 lpoints.Get(lfacei.PNum(3)), lpi, 1
+					 );
+				    }
+				  else
+				    {
+				      triin = rule->IsQuadInFreeZone 
+					(
+					 lpoints.Get(lfacei.PNum(1)),
+					 lpoints.Get(lfacei.PNum(2)),
+					 lpoints.Get(lfacei.PNum(3)), 
+					 lpoints.Get(lfacei.PNum(4)), 
+					 lpi, 1
+					 );
+				    }
+				}
+
+
+			      if (triin == -1)
+				{
+				  ok = 0;
+				}
+			      
+			      if (triin == 1)
+				{
+#ifdef TEST_JS
+				  ok = 0;
+
+				  if (loktestmode)
+				    {
+				      (*testout) << "El with " << lfaces.Get(i).GetNP() << " points in freezone: "
+						 << lfaces.Get(i).PNum(1) << " - " 
+						 << lfaces.Get(i).PNum(2) << " - "
+						 << lfaces.Get(i).PNum(3) << " - "
+						 << lfaces.Get(i).PNum(4) << endl;
+				      for (int lj = 1; lj <= lfaces.Get(i).GetNP(); lj++)
+					(*testout) << lpoints.Get(lfaces.Get(i).PNum(lj)) << " ";
+
+				      (*testout) << endl;
+
+				      sprintf (problems.Elem(ri), "triangle (%d, %d, %d) in Freezone",
+					       lfaces.Get(i).PNum(1), lfaces.Get(i).PNum(2),
+					       lfaces.Get(i).PNum(3));
+				    }
+#else
+				  if (loktestmode)
+				    {
+				      if (lfacei.GetNP() == 3)
+					{
+					  (*testout) << "Triangle in freezone: "
+						     << lfacei.PNum(1) << " - " 
+						     << lfacei.PNum(2) << " - "
+						     << lfacei.PNum(3) 
+						     << ", or "
+						     << lpoints.Get(lfacei.PNum(1)) << " - " 
+						     << lpoints.Get(lfacei.PNum(2)) << " - "
+						     << lpoints.Get(lfacei.PNum(3)) 
+						     << endl;
+					  (*testout) << "lpi = " << lpi.Get(1) << ", " 
+						     << lpi.Get(2) << ", " << lpi.Get(3) << endl;
+					}
+				      else
+					  (*testout) << "Quad in freezone: "
+						     << lfacei.PNum(1) << " - " 
+						     << lfacei.PNum(2) << " - "
+						     << lfacei.PNum(3) << " - "
+						     << lfacei.PNum(4) 
+						     << ", or "
+						     << lpoints.Get(lfacei.PNum(1)) << " - " 
+						     << lpoints.Get(lfacei.PNum(2)) << " - "
+						     << lpoints.Get(lfacei.PNum(3)) << " - "
+						     << lpoints.Get(lfacei.PNum(4)) 
+						     << endl;
+
+				      sprintf (problems.Elem(ri), "triangle (%d, %d, %d) in Freezone",
+					       int(lfaces.Get(i).PNum(1)), 
+					       int(lfaces.Get(i).PNum(2)),
+					       int(lfaces.Get(i).PNum(3)));
+				    }	
+
+				  hc = 0;
+				  for (k = rule->GetNOldF() + 1; k <= rule->GetNF(); k++)
+				    {
+				      if (rule->GetPointNr(k, 1) <= rule->GetNOldP() &&
+					  rule->GetPointNr(k, 2) <= rule->GetNOldP() &&
+					  rule->GetPointNr(k, 3) <= rule->GetNOldP())
+					{
+					  for (j = 1; j <= 3; j++)
+					    if (lfaces.Get(i).PNumMod(j  ) == pmap.Get(rule->GetPointNr(k, 1)) &&
+						lfaces.Get(i).PNumMod(j+1) == pmap.Get(rule->GetPointNr(k, 3)) &&
+						lfaces.Get(i).PNumMod(j+2) == pmap.Get(rule->GetPointNr(k, 2)))
+					      {
+						fmapi.Elem(k) = i;
+						hc = 1;
+
+						
+ // 						(*testout) << "found from other side: " 
+//  							   << rule->Name() 
+//  							   << " ( " << pmap.Get (rule->GetPointNr(k, 1))
+//  							   << " - " << pmap.Get (rule->GetPointNr(k, 2))
+//  							   << " - " << pmap.Get (rule->GetPointNr(k, 3)) << " ) "
+//  							   << endl;
+
+						strcpy (problems.Elem(ri), "other");
+					      }
+					}
+				    }
+				  
+				  if (!hc)
+				    {
+				      if (loktestmode)
+					{
+					  (*testout) << "Triangle in freezone: "
+						     << lfaces.Get(i).PNum(1) << " - " 
+						     << lfaces.Get(i).PNum(2) << " - "
+						     << lfaces.Get(i).PNum(3) << endl;
+
+					  sprintf (problems.Elem(ri), "triangle (%d, %d, %d) in Freezone",
+						   int (lfaces.Get(i).PNum(1)), 
+						   int (lfaces.Get(i).PNum(2)),
+						   int (lfaces.Get(i).PNum(3)));
+					}
+				      ok = 0;
+				    }
+#endif
+				}
+			    }
+			   
+			}
+
+		      
+		      if (ok)
+			{
+			  err = 0;
+			  for (i = 1; i <= rule->GetNOldP(); i++)
+			    {
+			      hf = rule->CalcPointDist (i, lpoints.Get(pmap.Get(i)));
+			      if (hf > err) err = hf;
+			    }
+			  
+			  
+			  if (loktestmode)
+			    {
+			      (*testout) << "Rule ok" << endl;
+			      sprintf (problems.Elem(ri), "Rule ok, err = %f", err);
+			    }
+
+
+			  // MARK(m2);			  
+			  //			  newu = rule->GetOldUToNewU() * oldu;
+
+			  // set new points:
+			  
+			  oldnp = rule->GetNOldP();
+			  noldlp = lpoints.Size();
+			  noldlf = lfaces.Size();
+			  
+			  
+			  for (i = oldnp + 1; i <= rule->GetNP(); i++)
+			    {
+			      np = rule->GetPoint(i);
+			      np.X() += newu.Elem (3 * (i-oldnp) - 2);
+			      np.Y() += newu.Elem (3 * (i-oldnp) - 1);
+			      np.Z() += newu.Elem (3 * (i-oldnp));
+			      
+			      pmap.Elem(i) = lpoints.Append (np);
+			    }
+			  
+			  // Set new Faces:
+			  
+			  for (i = rule->GetNOldF() + 1; i <= rule->GetNF(); i++)
+			    if (!fmapi.Get(i))
+			      {
+				Element2d nface(rule->GetNP(i));
+				for (j = 1; j <= nface.GetNP(); j++)
+				  nface.PNum(j) = pmap.Get(rule->GetPointNr (i, j));
+				
+				lfaces.Append (nface);
+			      }
+			  
+			  
+			  // Delete old Faces:
+
+			  for (i = 1; i <= rule->GetNDelF(); i++)
+			    delfaces.Append (fmapi.Get(rule->GetDelFace(i)));
+			  for (i = rule->GetNOldF()+1; i <= rule->GetNF(); i++)
+			    if (fmapi.Get(i))
+			      {
+				delfaces.Append (fmapi.Get(i));
+				fmapi.Elem(i) = 0;
+			      }
+			  
+
+			  // check orientation
+			  for (i = 1; i <= rule->GetNO() && ok; i++)
+			    {
+			      const fourint * fouri;
+			      
+			      fouri = &rule->GetOrientation(i);
+			      Vec3d v1 (lpoints.Get(pmap.Get(fouri->i1)), 
+					lpoints.Get(pmap.Get(fouri->i2)));
+			      Vec3d v2 (lpoints.Get(pmap.Get(fouri->i1)), 
+					lpoints.Get(pmap.Get(fouri->i3)));
+			      Vec3d v3 (lpoints.Get(pmap.Get(fouri->i1)), 
+					lpoints.Get(pmap.Get(fouri->i4)));
+
+			      Vec3d n;
+			      Cross (v1, v2, n);
+			      if (n * v3 > -1e-7)
+				{
+				  if (loktestmode)
+				    {
+				      sprintf (problems.Elem(ri), "Orientation wrong");
+				      (*testout) << "Orientation wrong" << endl;
+				    }
+				  ok = 0;
+				}
+			    }
+
+			  
+
+			  // new points in free-zone ?
+			  for (i = rule->GetNOldP() + 1; i <= rule->GetNP() && ok; i++)
+			    if (!rule->IsInFreeZone (lpoints.Get(pmap.Get(i))))
+			      {
+				if (loktestmode)
+				  {
+				    (*testout) << "Newpoint " << lpoints.Get(pmap.Get(i))
+					       << " outside convex hull" << endl;
+				    sprintf (problems.Elem(ri), "newpoint outside convex hull");
+				  }
+				ok = 0;
+				
+			      }
+			  
+			  // insert new elements
+			  
+			  for (i = 1; i <= rule->GetNE(); i++)
+			    {
+			      elements.Append (rule->GetElement(i));
+			      for (j = 1; j <= elements.Get(i).NP(); j++)
+				elements.Elem(i).PNum(j) = pmap.Get(elements.Get(i).PNum(j));
+			    }
+			  
+
+			  // Calculate Element badness
+			  
+			  teterr = 0;
+			  for (i = 1; i <= elements.Size(); i++)
+			    {
+			      hf = CalcElementBadness (lpoints, elements.Get(i));
+			      if (hf > teterr) teterr = hf;
+			    }
+
+			  /*
+			    // keine gute Erfahrung am 25.1.2000, js
+			  if (ok && teterr < 100 &&
+			      (rule->TestFlag('b') || tolerance > 10) )
+			    {
+			      (*mycout) << "Reset teterr " 
+				   << rule->Name() 
+				   << " err = " << teterr 
+				   << endl;
+			      teterr = 1;
+			    }
+			  */
+
+			  // compare edgelength
+			  if (rule->TestFlag('l'))
+			    {
+			      double oldlen = 0;
+			      double newlen = 0;
+
+			      for (i = 1; i <= rule->GetNDelF(); i++)
+				{
+				  const Element2d & face = 
+				    rule->GetFace (rule->GetDelFace(i));
+				  for (j = 1; j <= 3; j++)
+				    {
+				      const Point3d & p1 =
+					lpoints.Get(pmap.Get(face.PNumMod(j)));
+				      const Point3d & p2 =
+					lpoints.Get(pmap.Get(face.PNumMod(j+1)));
+				      oldlen += Dist(p1, p2);
+				    }
+				}
+
+			      for (i = rule->GetNOldF()+1; i <= rule->GetNF(); i++)
+				{
+				  const Element2d & face = rule->GetFace (i);
+				  for (j = 1; j <= 3; j++)
+				    {
+				      const Point3d & p1 =
+					lpoints.Get(pmap.Get(face.PNumMod(j)));
+				      const Point3d & p2 =
+					lpoints.Get(pmap.Get(face.PNumMod(j+1)));
+				      newlen += Dist(p1, p2);
+				    }
+				}
+
+			      if (oldlen < newlen) 
+				{
+				  ok = 0;
+				  if (loktestmode)
+				    sprintf (problems.Elem(ri), "oldlen < newlen");
+				}
+			    }
+			  
+
+			  if (loktestmode)
+			    (*testout) << "ok = " << int(ok) 
+				       << "teterr = " << teterr 
+				       << "minteterr = " << minteterr << endl;
+
+
+			  if (ok && teterr < tolerance)
+			    {
+			      canuse.Elem(ri) ++;
+			      /*
+			      (*testout) << "can use rule " << rule->Name() 
+					 << ", err = " << teterr << endl;
+			      for (i = 1; i <= pmap.Size(); i++)
+				(*testout) << pmap.Get(i) << " ";
+			      (*testout) << endl;
+			      */
+
+			      if (strcmp (problems.Elem(ri), "other") == 0)
+				{
+				  if (teterr < minother)
+				    minother = teterr;
+				}
+			      else
+				{
+				  if (teterr < minwithoutother)
+				    minwithoutother = teterr;
+				}
+			    }
+
+			  if (ok && teterr < minteterr)
+			    {
+
+			      if (loktestmode)
+				(*testout) << "use rule" << endl;
+
+			      found = ri;
+			      minteterr = teterr;
+			      
+			      if (testmode)
+				{
+				  for (i = 1; i <= rule->GetNOldP(); i++)
+				    {
+				      (*testout) << "P" << i << ": Ref: "
+						 << rule->GetPoint (i) << "  is: "
+						 << lpoints.Get(pmap.Get(i)) << endl;
+				    }
+				}
+			      
+			      tempnewpoints.SetSize (0);
+			      for (i = noldlp+1; i <= lpoints.Size(); i++)
+				tempnewpoints.Append (lpoints.Get(i));
+			      
+			      tempnewfaces.SetSize (0);
+			      for (i = noldlf+1; i <= lfaces.Size(); i++)
+				tempnewfaces.Append (lfaces.Get(i));
+
+			      tempdelfaces.SetSize (0);
+			      for (i = 1; i <= delfaces.Size(); i++)
+				tempdelfaces.Append (delfaces.Get(i));
+			      
+			      tempelements.SetSize (0);
+			      for (i = 1; i <= elements.Size(); i++)
+				tempelements.Append (elements.Get(i));
+			    }
+			  
+			  lpoints.SetSize (noldlp);
+			  lfaces.SetSize (noldlf);
+			  delfaces.SetSize (0);
+			  elements.SetSize (0);
+			}
+		      
+		      npok = rule->GetNOldP();
+		      incnpok = 0;
+		    }
+		}
+	      
+	      nfok = rule->GetNOldF();
+	      
+	      for (j = 1; j <= rule->GetNP (nfok); j++)
+		{
+		  refpi = rule->GetPointNr (nfok, j);
+		  pused.Elem(pmap.Get(refpi))--;
+		  
+		  if (pused.Get(pmap.Get(refpi)) == 0)
+		    {
+		      pmap.Set(refpi, 0);
+		    }
+		}
+	      
+	    }
+	}
+      if (loktestmode)
+	(*testout) << "end rule" << endl;
+    }
+
+  //  (*testout) << "end" << endl;
+
+  // if successfull, reload best choice
+  
+  if (found)
+    {
+
+#ifdef debug
+      // if face in advancing front ???
+      for (i = 1; i <= tempnewfaces.Size(); i++)
+	{
+	  hc = 1;
+	  for (k = 1; k <= lfaces.Size() && hc; k++)
+	    for (j = 1; j <= 3 && hc; j++)
+	      if (tempnewfaces.Elem(i).PNumMod(j  ) == lfaces.Get(k).PNum(1) &&
+		  tempnewfaces.Elem(i).PNumMod(j+1) == lfaces.Get(k).PNum(3) &&
+		  tempnewfaces.Elem(i).PNumMod(j+2) == lfaces.Get(k).PNum(2))
+		{
+		  tempdelfaces.Append(k);
+		  tempnewfaces.Elem(i).PNum(1) = 0;
+		  hc = 0;
+		  cerr << "Ruler-reload necessary" << endl;
+		}
+	}
+#endif
+      
+      for (i = 1; i <= tempnewpoints.Size(); i++)
+	lpoints.Append (tempnewpoints.Get(i));
+      for (i = 1; i <= tempnewfaces.Size(); i++)
+	if (tempnewfaces.Get(i).PNum(1))
+	  lfaces.Append (tempnewfaces.Get(i));
+      for (i = 1; i <= tempdelfaces.Size(); i++)
+	delfaces.Append (tempdelfaces.Get(i));
+      for (i = 1; i <= tempelements.Size(); i++)
+	elements.Append (tempelements.Get(i));
+    }
+  
+  retminerr = minerr;
+  return found;
+}
+}
diff --git a/Netgen/libsrc/meshing/ruler3.hpp b/Netgen/libsrc/meshing/ruler3.hpp
new file mode 100644
index 0000000000..483d83ed4e
--- /dev/null
+++ b/Netgen/libsrc/meshing/ruler3.hpp
@@ -0,0 +1,210 @@
+#ifndef FILE_RULER3
+#define FILE_RULER3
+
+
+/**
+  3D element generation rule.
+ */
+class vnetrule
+{
+private:
+  /// rule is applicable for quality classes above this value
+  int quality;
+  /// name of rule
+  char * name;
+  /// point coordinates in reference position
+  ARRAY<Point3d> points;
+  /// old and new faces in reference numbering
+  ARRAY<Element2d> faces;
+  /// additional edges of rule
+  ARRAY<twoint> edges;
+
+  /// points of freezone in reference coordinates
+  ARRAY<Point3d> freezone;
+  /// points of freezone in reference coordinates if tolcalss to infty
+  ARRAY<Point3d> freezonelimit;
+  /// point index, if point equal to mappoint, otherwise 0
+  ARRAY<int> freezonepi;
+  /// faces of each convex part of freezone
+  ARRAY<ARRAY<threeint>*> freefaces;
+  /// set of points of each convex part of freezone
+  ARRAY<ARRAY<int>*> freesets;
+  /// points of transformed freezone
+  ARRAY<Point3d> transfreezone;
+  /// edges of each convex part of freezone
+  ARRAY<ARRAY<twoint>*> freeedges;
+
+  /// face numbers to be deleted
+  ARRAY<int> delfaces;
+  /// elements to be generated
+  ARRAY<Element> elements;
+  /// tolerances for points and faces (used ??)
+  ARRAY<double> tolerances, linetolerances;
+  /// transformation matrix 
+  DenseMatrix oldutonewu;
+  /// transformation matrix: deviation old point to dev. freezone
+  DenseMatrix * oldutofreezone;
+  /** transformation matrix: deviation old point to dev. freezone, 
+    quality class to infinity */
+  DenseMatrix * oldutofreezonelimit;
+
+  // can be deleted:
+  // BaseMatrix *outf, *outfl;
+
+  /**
+    a point is outside of convex part of freezone, 
+    iff mat * (point, 1) >= 0 for each component (correct ?)
+    */
+  ARRAY<DenseMatrix*> freefaceinequ;
+  /// 
+  ARRAY<fourint> orientations;
+  /**
+    flags specified in rule-description file:
+    t .. test rule
+    */
+  ARRAY<char> flags;
+
+  /**
+    topological distance of face to base element
+    non-connected: > 100  (??) 
+    */
+  ARRAY<int> fnearness;
+  ARRAY<int> pnearness;
+  int maxpnearness;
+
+  /// number of old points in rule
+  int noldp;
+  /// number of new poitns in rule
+  int noldf;
+  /// box containing free-zone
+public:  
+  // double fzminx, fzmaxx, fzminy, fzmaxy, fzminz, fzmaxz;
+  Box3d fzbox;
+
+public:
+  
+  ///
+  vnetrule ();
+  ///
+  ~vnetrule ();
+  ///
+  int GetNP () const { return points.Size(); }
+  ///
+  int GetNF () const { return faces.Size(); }
+  ///
+  int GetNE () const { return elements.Size(); }
+  ///
+  int GetNO () const { return orientations.Size(); }
+  ///
+  int GetNEd () const { return edges.Size(); }
+  ///
+  int GetNOldP () const { return noldp; }
+  ///
+  int GetNOldF () const { return noldf; }
+  ///
+  int GetNDelF () const { return delfaces.Size(); }
+  ///
+  int GetQuality () const { return quality; }
+  ///
+  int GetFNearness (int fi) const { return fnearness.Get(fi); }
+  ///
+  int GetPNearness (int pi) const { return pnearness.Get(pi); }
+  ///
+  int GetMaxPNearness () const { return maxpnearness; }
+
+
+  ///
+  const Point3d & GetPoint (int i) const { return points.Get(i); }
+  ///
+  const Element2d & GetFace (int i) const { return faces.Get(i); }
+  ///
+  const Element & GetElement (int i) const { return elements.Get(i); }
+  ///
+  const twoint & GetEdge (int i) const { return edges.Get(i); }
+  ///
+  int GetDelFace (int i) const { return delfaces.Get(i); }
+  ///
+  int IsDelFace (int fn) const;
+  
+  ///
+  float CalcPointDist (int pi, const Point3d & p) const;
+  ///
+  double PointDistFactor (int pi) const
+    {
+      return tolerances.Get(pi);
+    }
+  ///
+  void SetFreeZoneTransformation (const Vector & allp,
+				  int tolclass);
+  ///
+  int IsInFreeZone (const Point3d & p) const;
+  /**
+    0 not in free-zone
+    1 in free-zone
+    -1 maybe 
+   */
+  int IsTriangleInFreeZone (const Point3d & p1, const Point3d & p2,
+                            const Point3d & p3, const ARRAY<int> & pi, int newone);
+  ///
+  int IsQuadInFreeZone (const Point3d & p1, const Point3d & p2,
+			const Point3d & p3, const Point3d & p4,
+			const ARRAY<int> & pi, int newone);
+  ///
+  int IsTriangleInFreeSet (const Point3d & p1, const Point3d & p2,
+                           const Point3d & p3, int fs, const ARRAY<int> & pi, int newone);
+
+  ///
+  int IsQuadInFreeSet (const Point3d & p1, const Point3d & p2,
+		       const Point3d & p3, const Point3d & p4,
+		       int fs, const ARRAY<int> & pi, int newone);
+  
+  ///
+  int ConvexFreeZone () const;
+  
+  /// if t1 and t2 are neighbourtriangles, NTP returns the opposite Point of t1 in t2
+  int NeighbourTrianglePoint (const threeint & t1, const threeint & t2) const;
+  ///
+  const Point3d & GetTransFreeZone (int i) { return transfreezone.Get(i); }
+
+  ///
+  int GetNP (int fn) const
+  { return faces.Get(fn).GetNP(); }
+  ///
+  int GetPointNr (int fn, int endp) const
+  { return faces.Get(fn).PNum(endp); }
+  ///
+  int GetPointNrMod (int fn, int endp) const
+  { return faces.Get(fn).PNumMod(endp); }
+  ///
+  const fourint & GetOrientation (int i) { return orientations.Get(i); }
+
+  ///
+  int TestFlag (char flag) const;
+
+  ///
+  const DenseMatrix & GetOldUToNewU () const { return oldutonewu; }
+  //
+  //  const DenseMatrix & GetOldUToFreeZone () const { return oldutofreezone; }
+  //
+  //  const DenseMatrix & GetOldUToFreeZoneLimit () const 
+  //    { return oldutofreezonelimit; }
+  ///
+  const char * Name () const { return name; }
+  ///
+  void LoadRule (istream & ist);
+
+  ///
+  const ARRAY<Point3d> & GetTransFreeZone () { return transfreezone; }
+  ///
+  int TestOk () const;
+
+  ///
+  friend void TestRules ();
+  ///
+  //  friend void Plot3DRule (const ROT3D & r, char key);
+};
+
+
+
+#endif
+
diff --git a/Netgen/libsrc/meshing/secondorder.cpp b/Netgen/libsrc/meshing/secondorder.cpp
new file mode 100644
index 0000000000..120ff024f1
--- /dev/null
+++ b/Netgen/libsrc/meshing/secondorder.cpp
@@ -0,0 +1,454 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+
+namespace netgen
+{
+
+
+
+  Refinement :: Refinement ()
+  {
+    ;
+  }
+
+  Refinement :: ~Refinement ()
+  {
+    ;
+  }
+  
+  void Refinement :: MakeSecondOrder (Mesh & mesh)
+  {
+    int i, j;
+  
+    INDEX_2_HASHTABLE<int> between(mesh.GetNP() + 5);
+
+    int nseg, nse, ne;
+
+
+    nseg = mesh.GetNSeg();
+    for (i = 1; i <= nseg; i++)
+      {
+	Segment & el = mesh.LineSegment(i);
+      
+	INDEX_2 i2 (el.p1, el.p2);
+	i2.Sort();
+      
+	int pnew;
+	if (between.Used(i2))
+	  pnew = between.Get(i2);
+	else
+	  {
+	    Point3d pb;
+	    EdgePointGeomInfo ngi;
+	    PointBetween (mesh.Point (el.p1),
+			  mesh.Point (el.p2), 0.5,
+			  el.surfnr1, el.surfnr2,
+			  el.epgeominfo[0], el.epgeominfo[1],
+			  pb, ngi);
+	  
+	    pnew = mesh.AddPoint (pb);
+	    between.Set (i2, pnew);
+	  }
+	el.pmid = pnew;
+      }
+
+    // refine surface elements
+    nse = mesh.GetNSE();
+    for (i = 1; i <= nse; i++)
+      {
+	int j;
+	const Element2d & el = mesh.SurfaceElement(i);
+
+	int onp = el.GetNP();
+      
+	Element2d newel;
+	newel.SetIndex (el.GetIndex());
+
+	static int betw_trig[3][3] =
+	  { { 2, 3, 4 },
+	    { 1, 3, 5 },
+	    { 1, 2, 6 } };
+	static int betw_quad6[2][3] =
+	  { { 1, 2, 5 },
+	    { 4, 3, 6 } };
+	int (*betw)[3];
+      
+	switch (el.GetType())
+	  {
+	  case TRIG:
+	  case TRIG6:
+	    {
+	      betw = betw_trig;
+	      newel.SetType (TRIG6);
+	      break;
+	    }
+	  case QUAD:
+	  case QUAD6:
+	  case QUAD8:
+	    {
+	      betw = betw_quad6;
+	      newel.SetType (QUAD6);
+	      break;
+	    }
+	  default:
+	    PrintSysError ("Unhandled element in secondorder:", int(el.GetType()));
+	  }
+
+	for (j = 1; j <= onp; j++)
+	  newel.PNum(j) = el.PNum(j);
+      
+	int nnp = newel.GetNP();
+	for (j = 0; j < nnp-onp; j++)
+	  {
+	    int pi1 = newel.PNum(betw[j][0]);
+	    int pi2 = newel.PNum(betw[j][1]);
+	  
+	    INDEX_2 i2 (pi1, pi2);
+	    i2.Sort();
+	  
+	    if (between.Used(i2))
+	      newel.PNum(onp+1+j) = between.Get(i2);
+	    else
+	      {
+		Point3d pb;
+		PointGeomInfo newgi;
+		PointBetween (mesh.Point (pi1),
+			      mesh.Point (pi2), 0.5, 
+			      mesh.GetFaceDescriptor(el.GetIndex ()).SurfNr(),
+			      el.GeomInfoPi (betw[j][0]),
+			      el.GeomInfoPi (betw[j][1]),
+			      pb, newgi);
+
+		newel.PNum(onp+1+j) = mesh.AddPoint (pb);
+		between.Set (i2, newel.PNum(onp+1+j));
+	      }
+	  }
+      
+	mesh.SurfaceElement(i) = newel;
+      }
+
+ 
+
+
+    // refine volume elements
+    ne = mesh.GetNE();
+    for (i = 1; i <= ne; i++)
+      {
+	int j;
+	const Element & el = mesh.VolumeElement(i);
+
+	if (el.GetType() != TET && el.GetType() != PRISM)
+	  continue;
+
+	int onp = el.GetNP();
+
+	Element newel;
+	newel.SetIndex (el.GetIndex());
+
+	static int betw_tet[6][3] =
+	  { { 1, 2, 5 },
+	    { 1, 3, 6 },
+	    { 1, 4, 7 },
+	    { 2, 3, 8 },
+	    { 2, 4, 9 },
+	    { 3, 4, 10 } };
+	static int betw_prism[6][3] =
+	  {
+	    { 1, 3, 7 },
+	    { 1, 2, 8 },
+	    { 2, 3, 9 },
+	    { 4, 6, 10 },
+	    { 4, 5, 11 },
+	    { 5, 6, 12 },
+	  };
+	int (*betw)[3];
+
+	switch (el.GetType())
+	  {
+	  case TET:
+	  case TET10:
+	    {
+	      betw = betw_tet;
+	      newel.SetType (TET10);
+	      break;
+	    }
+	  case PRISM:
+	  case PRISM12:
+	    {
+	      betw = betw_prism;
+	      newel.SetType (PRISM12);
+	      break;
+	    }
+	  default:
+	    PrintSysError ("MakeSecondOrder, illegal vol type ", el.GetType());
+	  }
+
+
+	for (j = 1; j <= onp; j++)
+	  newel.PNum(j) = el.PNum(j);
+	int nnp = newel.GetNP();
+
+	for (j = 0; j < nnp-onp; j++)
+	  {
+	    INDEX_2 i2(newel.PNum(betw[j][0]),
+		       newel.PNum(betw[j][1]));
+	    i2.Sort();
+	  
+	    if (between.Used(i2))
+	      newel.PNum(onp+1+j) = between.Get(i2);
+	    else
+	      {
+		newel.PNum(onp+1+j) = mesh.AddPoint
+		  (Center (mesh.Point(i2.I1()),
+			   mesh.Point(i2.I2())));
+		between.Set (i2, newel.PNum(onp+1+j));
+	      }
+	  }
+
+	mesh.VolumeElement (i) = newel;
+      }
+
+    /*
+    // makes problems after linear mesh refinement, since
+    // 2nd order identifications are not removed
+    // update identification tables
+    for (i = 1; i <= mesh.GetIdentifications().GetMaxNr(); i++)
+    {
+    ARRAY<int> identmap;
+    mesh.GetIdentifications().GetMap (i, identmap);
+
+    for (j = 1; j <= between.GetNBags(); j++)
+    for (k = 1; k <= between.GetBagSize(j); k++)
+    {
+    INDEX_2 i2;
+    int newpi;
+    between.GetData (j, k, i2, newpi);
+    INDEX_2 oi2(identmap.Get(i2.I1()),
+    identmap.Get(i2.I2()));
+    oi2.Sort();
+    if (between.Used (oi2))
+    {
+    int onewpi = between.Get(oi2);
+    mesh.GetIdentifications().Add (newpi, onewpi, i);
+    }
+    }
+
+    }
+    */
+
+    //  mesh.mglevels++;
+    int oldsize = mesh.mlbetweennodes.Size();
+    mesh.mlbetweennodes.SetSize(mesh.GetNP());
+    for (i = oldsize+1; i <= mesh.GetNP(); i++)
+      {
+	mesh.mlbetweennodes.Elem(i).I1() = 0;
+	mesh.mlbetweennodes.Elem(i).I2() = 0;
+      }
+    for (i = 1; i <= between.GetNBags(); i++)
+      for (j = 1; j <= between.GetBagSize(i); j++)
+	{
+	  INDEX_2 oldp;
+	  int newp;
+	  between.GetData (i, j, oldp, newp);
+	  mesh.mlbetweennodes.Elem(newp) = oldp;
+	}
+
+    mesh.ComputeNVertices();
+  
+    //  ValidateSecondOrder (mesh);
+  }
+
+
+  void Refinement :: ValidateSecondOrder (Mesh & mesh)
+  {
+    PrintMessage (3, "Validate mesh");
+    int np = mesh.GetNP();
+    int ne = mesh.GetNE();
+    int i, j;
+    ARRAY<INDEX_2> parents(np);
+  
+    for (i = 1; i <= np; i++)
+      parents.Elem(i) = INDEX_2(0,0);
+
+    for (i = 1; i <= ne; i++)
+      {
+	const Element & el = mesh.VolumeElement(i);
+	if (el.GetType() == TET10)
+	  {
+	    static int betweentab[6][3] =
+	      { { 1, 2, 5 },
+		{ 1, 3, 6 },
+		{ 1, 4, 7 },
+		{ 2, 3, 8 },
+		{ 2, 4, 9 },
+		{ 3, 4, 10 } };
+	    for (j = 0; j < 6; j++)
+	      {
+		int f1 = el.PNum (betweentab[j][0]);
+		int f2 = el.PNum (betweentab[j][1]);
+		int son = el.PNum (betweentab[j][2]);
+		parents.Elem(son).I1() = f1;
+		parents.Elem(son).I2() = f2;
+	      }
+	  }
+      }
+
+    ValidateRefinedMesh (mesh, parents);
+  }
+
+
+  void Refinement ::
+  ValidateRefinedMesh (Mesh & mesh, 
+		       ARRAY<INDEX_2> & parents)
+  {
+    int i, j, k;
+  
+    // homotopy method
+
+    int ne = mesh.GetNE();
+
+    int cnttrials = 100;
+    int wrongels = 0;
+    for (i = 1; i <= ne; i++)
+      if (mesh.VolumeElement(i).CalcJacobianBadness (mesh.Points()) > 1e10)
+	{
+	  wrongels++;
+	  mesh.VolumeElement(i).flags.badel = 1;
+	}
+      else
+	mesh.VolumeElement(i).flags.badel = 0;
+
+    double facok = 0;
+    double factry;
+
+    BitArray illegalels(ne);
+    illegalels.Clear();
+
+      
+    if (wrongels)
+      {
+	cout << "WARNING: " << wrongels << " illegal element(s) found" << endl;
+
+	int np = mesh.GetNP();
+	ARRAY<Point3d> should(np);
+	ARRAY<Point3d> can(np);
+
+	for (i = 1; i <= np; i++)
+	  {
+	    should.Elem(i) = can.Elem(i) = mesh.Point(i);
+	  }
+
+	for (i = 1; i <= parents.Size(); i++)
+	  {
+	    if (parents.Get(i).I1())
+	      can.Elem(i) = Center (can.Elem(parents.Get(i).I1()),
+				    can.Elem(parents.Get(i).I2()));
+	  }
+
+	BitArray boundp(np);
+	boundp.Clear();
+	for (i = 1; i <= mesh.GetNSE(); i++)
+	  {
+	    const Element2d & sel = mesh.SurfaceElement(i);
+	    for (j = 1; j <= sel.GetNP(); j++)
+	      boundp.Set(sel.PNum(j));
+	  }
+
+
+	(*testout) << "bpoints:" << endl;
+	for (i = 1; i <= np; i++)
+	  if (boundp.Test(i))
+	    (*testout) << i << endl;
+
+	double lam = 0.5;
+
+	while (facok < 1-1e-8 && cnttrials > 0)
+	  {
+	    lam *= 4;
+	    if (lam > 2) lam = 2;
+
+	    do
+	      {
+		//	      cout << "trials: " << cnttrials << endl;
+		lam *= 0.5;
+		cnttrials--;
+
+		cout << "lam = " << lam << endl;
+
+		factry = lam + (1-lam) * facok;
+		cout << "trying: " << factry << endl;
+
+		for (i = 1; i <= np; i++)
+		  if (boundp.Test(i))
+		    {
+		      for (j = 1; j <= 3; j++)
+			mesh.Point(i).X(j) = 
+			  lam * should.Get(i).X(j) +
+			  (1-lam) * can.Get(i).X(j);
+		    }
+		  else
+		    mesh.Point(i) = can.Get(i);
+	      
+		//	      (*testout) << "bad els: " << endl;
+		wrongels = 0;
+		for (i = 1; i <= ne; i++)
+		  {
+		    if (!illegalels.Test(i) && 
+			mesh.VolumeElement(i).
+			CalcJacobianBadness(mesh.Points()) > 1e10)
+		      {
+			wrongels++;
+			Element & el = mesh.VolumeElement(i);
+			el.flags.badel = 1;
+		     
+		      
+			if (lam < 1e-4)
+			  illegalels.Set(i);
+ 
+
+			/*
+			  (*testout) << i << ": ";
+			  for (j = 1; j <= el.GetNP(); j++)
+			  (*testout) << el.PNum(j) << " ";
+			  (*testout) << endl;
+			*/
+		      }
+		    else
+		      mesh.VolumeElement(i).flags.badel = 0;
+		  }
+		cout << "wrongels = " << wrongels << endl;
+	      }
+	    while (wrongels && cnttrials > 0);
+
+	    mesh.CalcSurfacesOfNode();
+	    mesh.ImproveMeshJacobian (OPT_WORSTCASE);	      
+	  
+	    facok = factry;
+	    for (i = 1; i <= np; i++)
+	      can.Elem(i) = mesh.Point(i);
+	  }
+      }
+
+
+      
+    for (i = 1; i <= ne; i++)
+      {
+	if (illegalels.Test(i))
+	  {
+	    cout << "illegal element: " << i << endl;
+	    mesh.VolumeElement(i).flags.badel = 1;	
+	  }
+	else
+	  mesh.VolumeElement(i).flags.badel = 0;	
+      }
+  
+    /*
+      if (cnttrials <= 0)
+      {
+      cerr << "ERROR: Sorry, illegal elements:" << endl;
+      }
+    */
+  }
+
+}
diff --git a/Netgen/libsrc/meshing/smoothing2.cpp b/Netgen/libsrc/meshing/smoothing2.cpp
new file mode 100644
index 0000000000..32e44b256d
--- /dev/null
+++ b/Netgen/libsrc/meshing/smoothing2.cpp
@@ -0,0 +1,790 @@
+#include <mystdlib.h>
+
+#include "meshing.hpp"
+#include <opti.hpp>
+
+namespace netgen
+{
+
+static const MeshOptimize2d * meshthis;
+
+
+
+
+inline void CalcTriangleBadness (double x2, double x3, double y3, double metricweight,
+			  double h, double & badness, double & g1x, double & g1y)
+{
+  // badness = sqrt(3.0) /36 * circumference^2 / area - 1 
+  // p1 = (0, 0), p2 = (x2, 0), p3 = (x3, y3);
+
+  Vec2d v23;
+  double l12, l13, l23, cir, area;
+  static const double c = sqrt(3.0) / 36;
+  double c1, c2, c3, c4;
+
+  v23.X() = x3 - x2;
+  v23.Y() = y3;
+
+  l12 = x2;
+  l13 = sqrt (x3*x3 + y3*y3);
+  l23 = v23.Length();
+
+  cir = l12 + l13 + l23;
+  area = 0.5 * x2 * y3;
+
+  if (area <= 1e-24 * cir * cir)
+    {
+      g1x = 0;
+      g1y = 0;
+      badness = 1e10;
+      return;
+    }
+
+  badness = c * cir * cir / area - 1;
+
+  c1 = 2 * c * cir / area;
+  c2 = 0.5 * c * cir * cir / (area * area);
+
+  g1x = c1 * ( - 1 - x3 / l13) - c2 * (-v23.Y());
+  g1y = c1 * (     - y3 / l13) - c2 * ( v23.X());
+  
+  //  metricweight = 0.1;
+  if (metricweight > 0)
+    {
+      // area = (x2 - x1) * (y3 - y1) - (x3 - x1) * (y2 - y1);
+      // add:  metricweight * (area / h^2 + h^2 / area - 2)
+      
+      const double area = x2 * y3;
+      const double dareax1 = -y3; 
+      const double dareay1 = x3 - x2; 
+
+      const double areahh = area / (h * h);
+      const double fac = metricweight * (areahh - 1 / areahh) / area;
+
+      badness += metricweight * (areahh + 1 / areahh - 2);
+      g1x += fac * dareax1;
+      g1y += fac * dareay1; 
+      
+      /*
+      // add: metricweight * (l1^2/h^2 + l2^2/h^2 + l3^2/h2 + h^2/l1^2 + h^2/l2^2 + h^2/l3^2 - 6)
+      double h2 = h*h;
+      double l1 = x2*x2;
+      double l2 = x3*x3+y3*y3;
+      double l3 = (x2-x3)*(x2-x3)+y3*y3;
+      double dl1dx = 2*(-x2);
+      double dl1dy = 0;
+      double dl2dx = -2*x3;
+      double dl2dy = -2*y3;
+
+      badness += (l1/h2 + l2/h2 + l3/h2 +h2/l1 + h2/l2 + h2/l3-6) * metricweight;
+
+      g1x += metricweight * (dl1dx/h2-h2/(l1*l1)*dl1dx + dl2dx/h2-h2/(l2*l2)*dl2dx);
+      g1y += metricweight * (dl1dy/h2-h2/(l1*l1)*dl1dy + dl2dy/h2-h2/(l2*l2)*dl2dy);
+      */
+    }
+}
+
+
+  double CalcTriangleBadness (const Point3d & p1, 
+			      const Point3d & p2, 
+			      const Point3d & p3,
+			      double metricweight,
+			      double h)
+  {
+  double badness;
+  double g1x, g1y;
+  
+  Vec3d e1 (p1, p2);
+  Vec3d e2 (p1, p3);
+  
+  double e1l = e1.Length() + 1e-24;
+  e1 /= e1l;
+  double e1e2 = (e1 * e2);
+  e2.Add (-e1e2, e1);
+  double e2l = e2.Length();
+  
+  CalcTriangleBadness ( e1l, e1e2, e2l,
+			metricweight, h, badness, g1x, g1y);
+  return badness;
+}
+
+
+double CalcTriangleBadness (const Point3d & p1, 
+			    const Point3d & p2, 
+			    const Point3d & p3,
+			    const Vec3d & n,
+			    double metricweight,
+			    double h)
+{
+  double badness;
+  double g1x, g1y;
+  
+  Vec3d v1 (p1, p2);
+  Vec3d v2 (p1, p3);
+
+  Vec3d e1 = v1;
+  Vec3d e2 = v2;
+
+  e1 -= (e1 * n) * n;
+  e1 /= (e1.Length() + 1e-12);
+  e2 = Cross (n, e1);
+
+  CalcTriangleBadness ( (e1 * v1), (e1 * v2), (e2 * v2), 
+			metricweight, h, badness, g1x, g1y);
+  return badness;
+}
+
+
+
+
+static Point3d sp1; 
+static PointGeomInfo gi1;
+static Vec3d n, t1, t2;
+static ARRAY<SurfaceElementIndex> locelements(0);
+static ARRAY<int> locrots(0);
+static ARRAY<double> lochs(0);
+// static int locerr2;
+static double locmetricweight = 0;
+static double loch;
+static int surfi, surfi2;
+static int uselocalh;
+
+
+class Opti2SurfaceMinFunction : public MinFunction
+{
+  const Mesh & mesh;
+public:
+  Opti2SurfaceMinFunction (const Mesh & amesh)
+    : mesh(amesh)
+    { } ;
+  virtual double FuncGrad (const Vector & x, Vector & g) const;
+  virtual double Func (const Vector & x) const;
+};
+  
+double Opti2SurfaceMinFunction :: 
+Func (const Vector & x) const
+{
+  Vector g(x.Size());
+  return FuncGrad (x, g);
+}
+
+
+double Opti2SurfaceMinFunction :: 
+FuncGrad (const Vector & x, Vector & grad) const
+{
+  int j, roti;
+  Vec3d n, vgrad;
+  Point3d pp1;
+  Vec2d g1;
+  double badness, hbadness;
+
+  vgrad = 0;
+  badness = 0;
+
+
+  meshthis -> GetNormalVector (surfi, sp1, gi1, n);
+
+  pp1 = sp1;
+  pp1.Add2 (x.Get(1), t1, x.Get(2), t2);
+
+  //  meshthis -> ProjectPoint (surfi, pp1);
+  // meshthis -> GetNormalVector (surfi, pp1, n);
+
+
+  for (j = 0; j < locelements.Size(); j++)
+    {
+      roti = locrots[j];
+      const Element2d & bel = mesh[locelements[j]];
+
+      Vec3d e1(pp1, mesh[bel.PNumMod(roti + 1)]);
+      Vec3d e2(pp1, mesh[bel.PNumMod(roti + 2)]);
+
+      if (uselocalh) loch = lochs[j];
+
+      double e1l = e1.Length();
+      if (Determinant(e1, e2, n) > 1e-8 * e1l * e2.Length())
+	{
+	  e1 /= e1l;
+	  double e1e2 = e1 * e2;
+	  e2.Add (-e1e2, e1);
+	  double e2l = e2.Length();
+
+	  CalcTriangleBadness ( e1l, e1e2, e2l, locmetricweight, loch,
+				hbadness, g1.X(), g1.Y());
+
+	  badness += hbadness;
+	  vgrad.Add2 (g1.X(), e1, g1.Y() / e2l, e2);
+	}
+      else
+	badness += 1e8;
+    }
+
+  vgrad.Add (-(vgrad * n), n);
+
+  grad.Elem(1) = vgrad * t1;
+  grad.Elem(2) = vgrad * t2;
+  return badness;
+}
+
+
+class Opti2EdgeMinFunction : public MinFunction
+{
+  const Mesh & mesh;
+public:
+  Opti2EdgeMinFunction (const Mesh & amesh)
+    : mesh(amesh) { } ;
+
+  virtual double FuncGrad (const Vector & x, Vector & g) const;
+  virtual double Func (const Vector & x) const;
+};
+
+double Opti2EdgeMinFunction :: Func (const Vector & x) const
+{
+  Vector g(x.Size());
+  return FuncGrad (x, g);
+}
+
+double Opti2EdgeMinFunction :: FuncGrad (const Vector & x, Vector & grad) const
+{
+  int j, rot;
+  Vec3d n1, n2, v1, v2, e1, e2, vgrad;
+  Point3d pp1;
+  Vec2d g1;
+  double badness, hbadness;
+
+  vgrad.X() = 0;
+  vgrad.Y() = 0;
+  vgrad.Z() = 0;
+  badness = 0;
+
+  pp1 = sp1 + x.Get(1) * t1;
+  meshthis -> ProjectPoint2 (surfi, surfi2, pp1);
+
+  for (j = 0; j < locelements.Size(); j++)
+    {
+      rot = locrots[j];
+      const Element2d & bel = mesh[locelements[j]];
+
+      v1 = mesh[bel.PNumMod(rot + 1)] - pp1;
+      v2 = mesh[bel.PNumMod(rot + 2)] - pp1;
+
+      e1 = v1;
+      e2 = v2;
+      e1 /= e1.Length();
+      e2 -= (e1 * e2) * e1;
+      e2 /= e2.Length();
+
+      if (uselocalh) loch = lochs[j];
+      CalcTriangleBadness ( (e1 * v1), (e1 * v2), (e2 * v2), locmetricweight, loch,
+			    hbadness, g1.X(), g1.Y());
+
+      badness += hbadness;
+
+      vgrad.X() += g1.X() * e1.X() + g1.Y() * e2.X();
+      vgrad.Y() += g1.X() * e1.Y() + g1.Y() * e2.Y();
+      vgrad.Z() += g1.X() * e1.Z() + g1.Y() * e2.Z();
+    }
+
+  meshthis -> GetNormalVector (surfi, pp1, n1);
+  meshthis -> GetNormalVector (surfi2, pp1, n2);
+
+  v1 = Cross (n1, n2);
+  v1 /= v1.Length();
+
+  grad.Elem(1) = (vgrad * v1) * (t1 * v1);
+
+  return badness;
+}
+
+
+
+
+class Opti2SurfaceMinFunctionJacobian : public MinFunction
+{
+  const Mesh & mesh;
+public:
+  Opti2SurfaceMinFunctionJacobian (const Mesh & amesh)
+    : mesh(amesh)
+    { } ;
+  virtual double FuncGrad (const Vector & x, Vector & g) const;
+  virtual double Func (const Vector & x) const;
+};
+  
+double Opti2SurfaceMinFunctionJacobian :: 
+Func (const Vector & x) const
+{
+  Vector g(x.Size());
+  return FuncGrad (x, g);
+}
+
+
+double Opti2SurfaceMinFunctionJacobian :: 
+FuncGrad (const Vector & x, Vector & grad) const
+{
+  // from 2d:
+
+  int j, k, lpi, gpi;
+  Vec3d n, vgrad;
+  Point3d pp1;
+  Vec2d g1, vdir;
+  double badness, hbadness, hbad, hderiv;
+
+  vgrad = 0;
+  badness = 0;
+
+  meshthis -> GetNormalVector (surfi, sp1, gi1, n);
+
+  pp1 = sp1;
+  pp1.Add2 (x.Get(1), t1, x.Get(2), t2);
+
+  //  meshthis -> ProjectPoint (surfi, pp1);
+  //  meshthis -> GetNormalVector (surfi, pp1, n);
+
+  static ARRAY<Point2d> pts2d;
+  pts2d.SetSize(mesh.GetNP());
+
+  grad = 0;
+
+  for (j = 1; j <= locelements.Size(); j++)
+    {
+      lpi = locrots.Get(j);
+      const Element2d & bel = 
+	mesh[locelements.Get(j)];
+      
+      gpi = bel.PNum(lpi);
+
+      for (k = 1; k <= bel.GetNP(); k++)
+	{
+	  PointIndex pi = bel.PNum(k);
+	  pts2d.Elem(pi) = Point2d (t1 * (mesh.Point(pi) - sp1), 
+				    t2 * (mesh.Point(pi) - sp1)); 
+	}				    
+      pts2d.Elem(gpi) = Point2d (x.Get(1), x.Get(2));
+      
+
+      for (k = 1; k <= 2; k++)
+	{
+	  if (k == 1)
+	    vdir = Vec2d (1, 0);
+	  else
+	    vdir = Vec2d (0, 1);
+	  
+	  hbad = bel.
+	    CalcJacobianBadnessDirDeriv (pts2d, lpi, vdir, hderiv);
+
+	  grad.Elem(k) += hderiv;
+	  if (k == 1)
+	    badness += hbad;
+	}
+	  
+	  
+      /*
+      Vec3d e1(pp1, mesh.Point(bel.PNumMod(lpi + 1)));
+      Vec3d e2(pp1, mesh.Point(bel.PNumMod(lpi + 2)));
+
+      if (uselocalh)
+	loch = lochs.Get(j);
+
+      double e1l = e1.Length();
+      if (Determinant(e1, e2, n) > 1e-8 * e1l * e2.Length())
+	{
+	  e1 /= e1l;
+	  double e1e2 = e1 * e2;
+	  e2.Add (-e1e2, e1);
+	  double e2l = e2.Length();
+
+	  CalcTriangleBadness ( e1l, e1e2, e2l, locmetricweight, loch,
+				hbadness, g1.X(), g1.Y());
+
+	  badness += hbadness;
+	  vgrad.Add2 (g1.X(), e1, g1.Y() / e2l, e2);
+	}
+      else
+	badness += 1e8;
+      */
+    }
+
+
+  /*
+  vgrad.Add (-(vgrad * n), n);
+
+  grad.Elem(1) = vgrad * t1;
+  grad.Elem(2) = vgrad * t2;
+  */
+  return badness;
+
+  /*
+
+  // from 3d:
+
+  int j, k;
+  int lpi;
+  double badness = 0, hbad;
+
+  Point3d hp = points.Elem(actpind);
+  points.Elem(actpind) = hp + Vec3d (x.Get(1), x.Get(2), x.Get(3));
+
+  double hderiv;
+  Vec3d vdir;
+  g.SetSize(3);
+  g = 0;
+
+  for (j = 1; j <= elementsonpoint.EntrySize(actpind); j++)
+    {
+      int eli = elementsonpoint.Get(actpind, j);
+      const Element & el = elements.Get(eli);
+
+      lpi = 0;
+      for (k = 1; k <= el.GetNP(); k++)
+	if (el.PNum(k) == actpind)
+	  lpi = k;
+      if (!lpi) cerr << "loc point not found" << endl;
+
+      for (k = 1; k <= 3; k++)
+	{
+	  vdir = Vec3d(0,0,0);
+	  vdir.X(k) = 1;
+
+	  hbad = elements.Get(eli).
+	    CalcJacobianBadnessDirDeriv (points, lpi, vdir, hderiv);
+	  g.Elem(k) += hderiv;
+	  if (k == 1)
+	    badness += hbad;
+	}
+    }
+  
+  points.Elem(actpind) = hp; 
+
+  return badness;
+
+  */
+
+}
+
+
+
+
+
+
+
+MeshOptimize2d dummy;
+
+MeshOptimize2d :: MeshOptimize2d ()
+{
+  SetFaceIndex (0);
+  SetImproveEdges (0);
+  SetMetricWeight (0);
+  SetWriteStatus (1);
+}
+
+
+void MeshOptimize2d :: SelectSurfaceOfPoint (const Point3d & p,
+					     const PointGeomInfo & gi)
+{
+  ;
+}
+
+void MeshOptimize2d :: ImproveMesh (Mesh & mesh)
+{
+  if (!faceindex)
+    {
+      PrintMessage (3, "Smoothing");
+
+      for (faceindex = 1; faceindex <= mesh.GetNFD(); faceindex++)
+	{
+	  ImproveMesh (mesh);
+	  if (multithread.terminate)
+	    throw NgException ("Meshing stopped");
+	}
+      faceindex = 0;
+      return;
+    }
+ 
+  CheckMeshApproximation (mesh);
+
+  int i, j, k, surfi3;
+  SurfaceElementIndex sei;
+
+  ARRAY<SurfaceElementIndex> seia;
+  mesh.GetSurfaceElementsOfFace (faceindex, seia);
+
+  bool mixed = 0;
+  for (i = 0; i < seia.Size(); i++)
+    if (mesh[seia[i]].GetNP() != 3)
+      {
+	mixed = 1;
+	break;
+      }
+
+
+  int loci;
+  double fact;
+  int moveisok;
+
+  PointGeomInfo ngi;
+  Point3d origp;
+
+  Vec3d n1, n2;
+  Vector x(2), xedge(1);
+
+  ARRAY<Point3d, PointIndex::BASE> savepoints(mesh.GetNP());
+  uselocalh = mparam.uselocalh;
+
+  ARRAY<int, PointIndex::BASE> nelementsonpoint(mesh.GetNP());
+  nelementsonpoint = 0;
+
+  for (i = 0; i < seia.Size(); i++)
+    {
+      const Element2d & el = mesh[seia[i]];
+      for (j = 0; j < el.GetNP(); j++)
+	nelementsonpoint[el[j]]++;
+    }
+
+
+  TABLE<SurfaceElementIndex,PointIndex::BASE> elementsonpoint(nelementsonpoint);
+  for (i = 0; i < seia.Size(); i++)
+    {
+      const Element2d & el = mesh[seia[i]];
+      for (j = 0; j < el.GetNP(); j++)
+	elementsonpoint.Add (el[j], seia[i]);
+    }
+
+  loch = mparam.maxh;
+  locmetricweight = metricweight;
+  meshthis = this;
+
+  Opti2SurfaceMinFunction surfminf(mesh);
+  Opti2EdgeMinFunction edgeminf(mesh);
+  Opti2SurfaceMinFunctionJacobian surfminfj(mesh);
+
+  OptiParameters par;
+  par.maxit_linsearch = 8;
+  par.maxit_bfgs = 5;
+
+  /*
+  if (improveedges)
+    for (i = 1; i <= mesh.GetNP(); i++)
+      if (mesh.PointType(i) == EDGEPOINT)
+	{
+	  continue;
+	  PrintDot ();
+	  sp1 = mesh.Point(i);
+	  
+	  locelements.SetSize(0);
+	  locrots.SetSize (0);
+	  lochs.SetSize (0);
+	  surfi = surfi2 = surfi3 = 0;
+	  
+	  for (j = 0; j < elementsonpoint[i].Size(); j++)
+	    {
+	      sei = elementsonpoint[i][j];
+	      const Element2d * bel = &mesh[sei];
+	      
+	      if (!surfi)
+		surfi = mesh.GetFaceDescriptor(bel->GetIndex()).SurfNr();
+	      else if (surfi != mesh.GetFaceDescriptor(bel->GetIndex()).SurfNr())
+		{
+		  if (surfi2 != 0 && surfi2 != 
+		      mesh.GetFaceDescriptor(bel->GetIndex()).SurfNr())
+		    surfi3 = mesh.GetFaceDescriptor(bel->GetIndex()).SurfNr();
+		  else
+		    surfi2 = mesh.GetFaceDescriptor(bel->GetIndex()).SurfNr();
+		}
+	      
+	      locelements.Append (sei);
+	      
+	      if (bel->PNum(1) == i)
+		locrots.Append (1);
+	      else if (bel->PNum(2) == i)
+		locrots.Append (2);
+	      else
+		locrots.Append (3);
+
+	      if (uselocalh)
+		{
+		  Point3d pmid = Center (mesh.Point(bel->PNum(1)),
+					 mesh.Point(bel->PNum(2)),
+					 mesh.Point(bel->PNum(3)));
+		  lochs.Append (mesh.GetH(pmid));
+		}
+	    }
+	  
+	  if (surfi2 && !surfi3)
+	    {
+	      GetNormalVector (surfi, sp1, n1);
+	      GetNormalVector (surfi2, sp1, n2);
+	      t1 = Cross (n1, n2);
+	      
+	      xedge = 0;
+	      BFGS (xedge, edgeminf, par, 1e-6);
+	      
+	      mesh.Point(i).X() += xedge.Get(1) * t1.X();
+	      mesh.Point(i).Y() += xedge.Get(1) * t1.Y();
+	      mesh.Point(i).Z() += xedge.Get(1) * t1.Z();
+	      ProjectPoint2 (surfi, surfi2, mesh.Point(i));
+	    }
+	}
+  */
+
+  bool printeddot = 0;
+  char plotchar = '.';
+  int modplot = 1;
+  if (mesh.GetNP() > 1000)
+    {
+      plotchar = '+';
+      modplot = 10;
+    }
+  int cnt = 0;
+
+  for (PointIndex pi = PointIndex::BASE; 
+       pi < mesh.GetNP()+PointIndex::BASE; pi++)
+
+    if (mesh.PointType(pi) == SURFACEPOINT)
+      {
+	if (multithread.terminate)
+	  throw NgException ("Meshing stopped");
+	
+	cnt++;
+	if (cnt % modplot == 0 && writestatus)
+	  {
+	    printeddot = 1;
+	    PrintDot (plotchar);
+	  }
+	
+	if (elementsonpoint[pi].Size() == 0)
+	  continue;
+	
+	sp1 = mesh[pi];
+
+	Element2d & hel = mesh[elementsonpoint[pi][0]];
+
+	int hpi = 0;
+	for (j = 1; j <= hel.GetNP(); j++)
+	  if (hel.PNum(j) == pi)
+	    {
+	      hpi = j;
+	      break;
+	    }
+
+	gi1 = hel.GeomInfoPi(hpi);
+	SelectSurfaceOfPoint (sp1, gi1);
+	  
+	locelements.SetSize(0);
+	locrots.SetSize (0);
+	lochs.SetSize (0);
+	
+	for (j = 0; j < elementsonpoint[pi].Size(); j++)
+	  {
+	    sei = elementsonpoint[pi][j];
+	    const Element2d & bel = mesh[sei];
+	    surfi = mesh.GetFaceDescriptor(bel.GetIndex()).SurfNr();
+	    
+	    locelements.Append (sei);
+	    
+	    for (k = 1; k <= bel.GetNP(); k++)
+	      if (bel.PNum(k) == pi)
+		{
+		  locrots.Append (k);
+		  break;
+		}
+	      
+	    if (uselocalh)
+	      {
+		Point3d pmid = Center (mesh[bel[0]], mesh[bel[1]], mesh[bel[2]]);
+		lochs.Append (mesh.GetH(pmid));
+	      }
+	  }
+
+	  
+	GetNormalVector (surfi, sp1, gi1, n);
+	n.GetNormal (t1);
+	t2 = Cross (n, t1);
+	  
+	// save points, and project to tangential plane
+	for (j = 0; j < locelements.Size(); j++)
+	  {
+	    const Element2d & el = mesh[locelements[j]];
+	    for (k = 0; k < el.GetNP(); k++)
+	      savepoints[el[k]] = mesh[el[k]];
+	  }
+
+	for (j = 0; j < locelements.Size(); j++)
+	  {
+	    const Element2d & el = mesh[locelements[j]];
+	    for (k = 0; k < el.GetNP(); k++)
+	      {
+		PointIndex hpi = el[k];
+		double lam = n * (mesh[hpi] - sp1);
+		mesh[hpi] -= lam * n;
+	      }
+	  }
+	  
+	x = 0;
+
+	if (mixed)
+	  BFGS (x, surfminfj, par, 1e-6);
+	else
+	  BFGS (x, surfminf, par, 1e-6);
+
+	origp = mesh[pi];
+	loci = 1;
+	fact = 1;
+	moveisok = 0;
+
+	// restore other points
+	for (j = 0; j < locelements.Size(); j++)
+	  {
+	    const Element2d & el = mesh[locelements[j]];
+	    for (k = 0; k < el.GetNP(); k++)
+	      {
+		PointIndex hpi = el[k];
+		if (hpi != pi) mesh[hpi] = savepoints[hpi];
+	      }
+	  }
+	  
+	  
+	//optimizer loop (if not whole distance is not possible, move only a bit!!!!)
+	while (loci <= 5 && !moveisok)
+	  {
+	    loci ++;
+	    mesh[pi].X() = origp.X() + (x.Get(1) * t1.X() + x.Get(2) * t2.X())*fact;
+	    mesh[pi].Y() = origp.Y() + (x.Get(1) * t1.Y() + x.Get(2) * t2.Y())*fact;
+	    mesh[pi].Z() = origp.Z() + (x.Get(1) * t1.Z() + x.Get(2) * t2.Z())*fact;
+	    fact = fact/2.;
+	    ProjectPoint (surfi, mesh[pi]);
+	    
+	    moveisok = CalcPointGeomInfo(surfi, ngi, mesh[pi]); 
+	    // point lies on same chart in stlsurface
+	    
+	    if (moveisok)
+	      {
+		for (j = 0; j < locelements.Size(); j++)
+		  mesh[locelements[j]].GeomInfoPi(locrots[j]) = ngi;
+	      }
+	    else
+	      {
+		mesh[pi] = origp;
+	      }
+	    
+	  }
+	  //	(*testout) << " new: " << mesh.Point(i) << endl;
+      }
+  
+  if (printeddot)
+    PrintDot ('\n');
+  
+  CheckMeshApproximation (mesh);
+  mesh.SetNextTimeStamp();
+}
+
+void MeshOptimize2d :: GetNormalVector(INDEX /* surfind */, const Point3d & p, Vec3d & nv) const
+{
+  nv = Vec3d (0, 0, 1);
+}
+
+void MeshOptimize2d :: GetNormalVector(INDEX surfind, const Point3d & p, PointGeomInfo & gi, Vec3d & n) const
+{
+  GetNormalVector (surfind, p, n);
+}
+
+}
diff --git a/Netgen/libsrc/meshing/smoothing3.cpp b/Netgen/libsrc/meshing/smoothing3.cpp
new file mode 100644
index 0000000000..6fcb2b8e70
--- /dev/null
+++ b/Netgen/libsrc/meshing/smoothing3.cpp
@@ -0,0 +1,1557 @@
+#include <mystdlib.h>
+
+#include "meshing.hpp"
+#ifdef SOLIDGEOM
+#include <csg.hpp>
+#endif
+#include <opti.hpp>
+
+
+namespace netgen
+{
+  
+
+  PointFunction1 :: PointFunction1 (Mesh::T_POINTS & apoints, 
+				    const ARRAY<INDEX_3> & afaces,
+				    double ah)
+    : points(apoints), faces(afaces)
+  {
+    h = ah;
+  }
+  
+
+  double PointFunction1 :: Func (const Vector & vp) const
+  {
+    int j;
+    double badness = 0;
+    Point3d pp(vp.Get(1), vp.Get(2), vp.Get(3));
+
+    for (j = 0; j < faces.Size(); j++)
+      {
+	const INDEX_3 & el = faces[j];
+
+	double bad = CalcTetBadness (points.Get(el.I1()), 
+				     points.Get(el.I3()), 
+				     points.Get(el.I2()), 
+				     pp, 0);
+	badness += bad;
+      }
+ 
+    return badness;
+  }
+
+
+
+  double PointFunction1 :: FuncDeriv (const Vector & x, const Vector & dir, double & deriv) const
+  {
+    static Vector hx(3);
+    static double eps = 1e-6;
+
+    double dirlen = dir.L2Norm();
+    if (dirlen < 1e-14)
+      {
+	deriv = 0;
+	return Func(x);
+      }
+
+    hx.Set(1, x);
+    hx.Add(eps * h / dirlen, dir);
+    double fr = Func (hx);
+    hx.Set(1, x);
+    hx.Add(-eps * h / dirlen, dir);
+    double fl = Func (hx);
+
+    deriv = (fr - fl) / (2 * eps * h) * dirlen;
+
+    return Func(x);
+  }
+
+
+  double PointFunction1 :: FuncGrad (const Vector & x, Vector & g) const
+  {
+    static Vector hx(3);
+    static double eps = 1e-6;
+
+    hx = x;
+    for (int i = 1; i <= 3; i++)
+      {
+	hx.Elem(i) = x.Get(i) + eps * h;
+	double fr = Func (hx);
+	hx.Elem(i) = x.Get(i) - eps * h;
+	double fl = Func (hx);
+	hx.Elem(i) = x.Get(i);
+
+	g.Elem(i) = (fr - fl) / (2 * eps * h);
+      }
+
+    return Func(x);
+  }
+
+  double PointFunction1 :: GradStopping (const Vector & x) const
+  {
+    double f = Func(x);
+    return 1e-8 * f * f;
+  }
+
+
+
+
+  /* Cheap Functional depending of inner point inside triangular surface */
+
+  class CheapPointFunction1 : public MinFunction
+  {
+    Mesh::T_POINTS & points;
+    const ARRAY<INDEX_3> & faces;
+    DenseMatrix m;
+    double h;
+  public:
+    CheapPointFunction1 (Mesh::T_POINTS & apoints, 
+			 const ARRAY<INDEX_3> & afaces,
+			 double ah);
+  
+    virtual double Func (const Vector & x) const;
+    virtual double FuncGrad (const Vector & x, Vector & g) const;
+  };
+
+  CheapPointFunction1 :: CheapPointFunction1 (Mesh::T_POINTS & apoints, 
+					      const ARRAY<INDEX_3> & afaces,
+					      double ah)
+    : points(apoints), faces(afaces)
+  {
+    h = ah;
+  
+
+    int i, nf = faces.Size();
+
+    m.SetSize (nf, 4);
+  
+    for (i = 1; i <= nf; i++)
+      {
+	const Point3d & p1 = points.Get(faces.Get(i).I1());
+	const Point3d & p2 = points.Get(faces.Get(i).I2());
+	const Point3d & p3 = points.Get(faces.Get(i).I3());
+	Vec3d v1 (p1, p2);
+	Vec3d v2 (p1, p3);
+	Vec3d n;
+	Cross (v1, v2, n);
+	n /= n.Length();
+
+	m.Elem(i, 1) = n.X();
+	m.Elem(i, 2) = n.Y();
+	m.Elem(i, 3) = n.Z();
+	m.Elem(i, 4) = - (n.X() * p1.X() + n.Y() * p1.Y() + n.Z() * p1.Z());
+      } 
+  }
+  
+
+  double CheapPointFunction1 :: Func (const Vector & vp) const
+  {
+
+    /*
+      int j;
+      double badness = 0;
+      Point3d pp(vp.Get(1), vp.Get(2), vp.Get(3));
+
+      for (j = 1; j <= faces.Size(); j++)
+      {
+      const INDEX_3 & el = faces.Get(j);
+
+      double bad = CalcTetBadness (points.Get(el.I1()), 
+      points.Get(el.I3()), 
+      points.Get(el.I2()), 
+      pp, 0);
+      badness += bad;
+      }
+    */
+
+    int i;
+    double badness = 0;
+    static Vector hv(4);
+    static Vector res;
+    res.SetSize (m.Height());
+
+    for (i = 1;i <= 3; i++)
+      hv.Elem(i) = vp.Get(i);
+    hv.Elem(4) = 1;
+    m.Mult (hv, res);
+
+    for (i = 1; i <= res.Size(); i++)
+      {
+	if (res.Get(i) < 1e-10)
+	  badness += 1e24;
+	else
+	  badness += 1 / res.Get(i);
+      }
+ 
+    return badness;
+  }
+
+
+  double CheapPointFunction1 :: FuncGrad (const Vector & x, Vector & g) const
+  {
+    static Vector hx(3);
+    static double eps = 1e-6;
+
+    hx = x;
+    for (int i = 1; i <= 3; i++)
+      {
+	hx.Elem(i) = x.Get(i) + eps * h;
+	double fr = Func (hx);
+	hx.Elem(i) = x.Get(i) - eps * h;
+	double fl = Func (hx);
+	hx.Elem(i) = x.Get(i);
+
+	g.Elem(i) = (fr - fl) / (2 * eps * h);
+      }
+
+    return Func(x);
+  }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  /* ************* PointFunction **************************** */
+
+
+  class PointFunction 
+  {
+  public:
+    Mesh::T_POINTS & points;
+    const Mesh::T_VOLELEMENTS & elements;
+    TABLE<INDEX> elementsonpoint;
+    int actpind;
+    double h;
+  
+  public:
+    PointFunction (Mesh::T_POINTS & apoints, 
+		   const Mesh::T_VOLELEMENTS & aelements);
+  
+    virtual void SetPointIndex (int aactpind);
+    void SetLocalH (double ah) { h = ah; }
+    double GetLocalH () const { return h; }
+    virtual double PointFunctionValue (const Point3d & pp) const;
+    virtual double PointFunctionValueGrad (const Point3d & pp, Vector & grad) const;
+    virtual double PointFunctionValueDeriv (const Point3d & pp, const Vec3d & dir, double & deriv) const;
+
+    int MovePointToInner ();
+  };
+
+
+  PointFunction :: PointFunction (Mesh::T_POINTS & apoints, 
+				  const Mesh::T_VOLELEMENTS & aelements)
+    : points(apoints), elements(aelements), elementsonpoint(apoints.Size())
+  {
+    INDEX i;
+    int j;
+  
+    for (i = 1; i <= elements.Size(); i++)
+      {
+	if (elements.Get(i).NP() == 4)
+	  for (j = 1; j <= elements.Get(i).NP(); j++)
+	    elementsonpoint.Add1 (elements.Get(i).PNum(j), i);  
+      }
+  }
+
+  void PointFunction :: SetPointIndex (int aactpind)
+  {
+    actpind = aactpind; 
+  }  
+
+  double PointFunction :: PointFunctionValue (const Point3d & pp) const
+  {
+    int j;
+    INDEX eli;
+    const Element * el;
+    double badness;
+    //  ARRAY<const Point3d*> p(4);
+    Point3d hp;
+
+    badness = 0;
+
+    hp = points.Elem(actpind);
+    points.Elem(actpind) = pp;
+
+    for (j = 1; j <= elementsonpoint.EntrySize(actpind); j++)
+      {
+	eli = elementsonpoint.Get(actpind, j);
+	el = &elements.Get(eli);
+	badness += CalcTetBadness (points.Get(el->PNum(1)), 
+				   points.Get(el->PNum(2)), 
+				   points.Get(el->PNum(3)), 
+				   points.Get(el->PNum(4)), -1);
+      }
+  
+    points.Elem(actpind) = hp; 
+    return badness;
+  }
+
+
+  double PointFunction :: PointFunctionValueGrad (const Point3d & pp, Vector & grad) const
+  {
+    double f, delta = h * 1e-6;
+    Point3d hpp;
+
+    f = PointFunctionValue (pp);
+
+    /*
+      hpp = pp;
+      hpp.X() = pp.X() + delta;
+      fr = PointFunctionValue (hpp);
+      hpp.X() = pp.X() - delta;
+      fl = PointFunctionValue (hpp);
+      grad.Elem(1) = (fr - fl) / (2 * delta);
+
+      hpp = pp;
+      hpp.Y() = pp.Y() + delta;
+      fr = PointFunctionValue (hpp);
+      hpp.Y() = pp.Y() - delta;
+      fl = PointFunctionValue (hpp);
+      grad.Elem(2) = (fr - fl) / (2 * delta);
+
+      hpp = pp;
+      hpp.Z() = pp.Z() + delta;
+      fr = PointFunctionValue (hpp);
+      hpp.Z() = pp.Z() - delta;
+      fl = PointFunctionValue (hpp);
+      grad.Elem(3) = (fr - fl) / (2 * delta);
+    */
+
+
+
+    // new gradient calculation
+    int j, k;
+    INDEX eli;
+    //  double badness;
+    Point3d hp;
+    Vec3d vgradi, vgrad(0,0,0);
+
+    //  badness = 0;
+
+    hp = points.Elem(actpind);
+    points.Elem(actpind) = pp;
+
+    for (j = 1; j <= elementsonpoint.EntrySize(actpind); j++)
+      {
+	eli = elementsonpoint.Get(actpind, j);
+	const Element & el = elements.Get(eli);
+
+	for (k = 1; k <= 4; k++)
+	  if (el.PNum(k) == actpind)
+	    {
+	      CalcTetBadnessGrad (points.Get(el.PNum(1)), 
+				  points.Get(el.PNum(2)), 
+				  points.Get(el.PNum(3)), 
+				  points.Get(el.PNum(4)), -1, k, vgradi);
+	      vgrad += vgradi;
+	    }
+      }
+    points.Elem(actpind) = hp; 
+
+    for (j = 1; j <= 3; j++)
+      grad.Elem(j) = vgrad.X(j);
+
+    return f;
+  }
+
+
+  double PointFunction :: PointFunctionValueDeriv (const Point3d & pp, const Vec3d & dir,
+						   double & deriv) const
+  {
+    double f;
+    Point3d hpp;
+
+    Vec3d dirn (dir);
+    double ldir = dir.Length();
+
+    int j, k;
+    INDEX eli;
+    //  double badness;
+    Point3d hp;
+    Vec3d vgradi, vgrad(0,0,0);
+
+    //  badness = 0;
+
+    hp = points.Elem(actpind);
+    points.Elem(actpind) = pp;
+    f = 0;
+
+    for (j = 1; j <= elementsonpoint.EntrySize(actpind); j++)
+      {
+	eli = elementsonpoint.Get(actpind, j);
+	const Element & el = elements.Get(eli);
+
+	for (k = 1; k <= 4; k++)
+	  if (el.PNum(k) == actpind)
+	    {
+	      f += CalcTetBadnessGrad (points.Get(el.PNum(1)), 
+				       points.Get(el.PNum(2)), 
+				       points.Get(el.PNum(3)), 
+				       points.Get(el.PNum(4)), -1, k, vgradi);
+
+	      vgrad += vgradi;
+	    }
+      }
+
+    points.Elem(actpind) = hp; 
+    deriv = dir * vgrad;
+    return f;
+  }
+
+  int PointFunction :: MovePointToInner ()
+  {
+    int j, k;
+
+    // try point movement 
+    ARRAY<Element2d> faces;
+  
+    for (j = 1; j <= elementsonpoint.EntrySize(actpind); j++)
+      {
+	const Element & el = 
+	  elements.Get(elementsonpoint.Get (actpind, j));
+      
+	for (k = 1; k <= 4; k++)
+	  if (el.PNum(k) == actpind)
+	    {
+	      Element2d face;
+	      el.GetFace (k, face);
+	      Swap (face.PNum(2), face.PNum(3));
+	      faces.Append (face);
+	    }
+      }
+  
+    Point3d hp;
+    int hi = FindInnerPoint (points, faces, hp);
+    if (hi)
+      {
+	cout << "inner point found" << endl;
+	points.Elem(actpind) = hp;
+      }
+    else
+      cout << "no inner point found" << endl;
+
+
+  
+    return hi;
+  }
+
+
+
+
+
+
+  class CheapPointFunction : public PointFunction
+  {
+    DenseMatrix m;
+  public:
+    CheapPointFunction (Mesh::T_POINTS & apoints, 
+			const Mesh::T_VOLELEMENTS & aelements);
+    virtual void SetPointIndex (int aactpind);
+    virtual double PointFunctionValue (const Point3d & pp) const;
+    virtual double PointFunctionValueGrad (const Point3d & pp, Vector & grad) const;
+  };
+
+
+  CheapPointFunction :: CheapPointFunction (Mesh::T_POINTS & apoints, 
+					    const Mesh::T_VOLELEMENTS & aelements)
+    : PointFunction (apoints, aelements)
+  {
+    ;
+  }
+
+
+  void CheapPointFunction :: SetPointIndex (int aactpind)
+  {
+    actpind = aactpind; 
+
+    int n = elementsonpoint.EntrySize(actpind);
+    int i, j;
+    int pi1, pi2, pi3;
+
+    m.SetSize (n, 4);
+
+    for (i = 1; i <= n; i++)
+      {
+	pi1 = 0;
+	pi2 = 0;
+	pi3 = 0;
+
+	const Element & el = elements.Get (elementsonpoint.Get(actpind, i));
+	for (j = 1; j <= 4; j++)
+	  if (el.PNum(j) != actpind)
+	    {
+	      pi3 = pi2;
+	      pi2 = pi1;
+	      pi1 = el.PNum(j);
+	    }
+
+	const Point3d & p1 = points.Get(pi1);
+	Vec3d v1 (p1, points.Get(pi2));
+	Vec3d v2 (p1, points.Get(pi3));
+	Vec3d n;
+	Cross (v1, v2, n);
+	n /= n.Length();
+
+	Vec3d v (p1, points.Get(actpind));
+	double c = v * n;
+      
+	if (c < 0)
+	  n *= -1;    
+      
+	// n is inner normal
+
+	m.Elem(i, 1) = n.X();
+	m.Elem(i, 2) = n.Y();
+	m.Elem(i, 3) = n.Z();
+	m.Elem(i, 4) = - (n.X() * p1.X() + n.Y() * p1.Y() + n.Z() * p1.Z());
+      }
+  }
+
+  double CheapPointFunction :: PointFunctionValue (const Point3d & pp) const
+  {
+    static Vector p4(4);
+    static Vector di;
+    int n = m.Height();
+
+    p4.Elem(1) = pp.X();
+    p4.Elem(2) = pp.Y();
+    p4.Elem(3) = pp.Z();
+    p4.Elem(4) = 1;
+
+    di.SetSize (n);
+    m.Mult (p4, di);
+  
+    double sum = 0;
+    for (int i = 1; i <= n; i++)
+      {
+	if (di.Get(i) > 0)
+	  sum += 1 / di.Get(i);
+	else
+	  return 1e16;
+      }
+    return sum;
+  }
+
+
+
+
+  double CheapPointFunction :: PointFunctionValueGrad (const Point3d & pp, Vector & grad) const
+  {
+    static Vector p4(4);
+    static Vector di;
+
+    grad.SetSize (3);
+    int n = m.Height();
+
+    p4.Elem(1) = pp.X();
+    p4.Elem(2) = pp.Y();
+    p4.Elem(3) = pp.Z();
+    p4.Elem(4) = 1;
+
+    di.SetSize (n);
+    m.Mult (p4, di);
+  
+    double sum = 0;
+    grad = 0;
+    for (int i = 1; i <= n; i++)
+      {
+	if (di.Get(i) > 0)
+	  {
+	    double idi = 1 / di.Get(i);
+	    sum += idi;
+	    grad.Elem(1) -= idi * idi * m.Get(i, 1);
+	    grad.Elem(2) -= idi * idi * m.Get(i, 2);
+	    grad.Elem(3) -= idi * idi * m.Get(i, 3);
+	  }
+	else
+	  {
+	    return 1e16;
+	  }
+      }
+    return sum;
+  }
+
+
+
+
+
+
+
+
+  class Opti3FreeMinFunction : public MinFunction
+  { 
+    const PointFunction & pf;
+    Point3d sp1;
+  
+  public:
+    Opti3FreeMinFunction (const PointFunction & apf);
+    void SetPoint (const Point3d & asp1) { sp1 = asp1; }
+    virtual double Func (const Vector & x) const;
+    virtual double FuncGrad (const Vector & x, Vector & g) const;
+    virtual double FuncDeriv (const Vector & x, const Vector & dir, double & deriv) const;  
+    virtual double GradStopping (const Vector & x) const;
+    virtual void ApproximateHesse (const Vector & x,
+				   DenseMatrix & hesse) const;
+  };
+
+
+
+  Opti3FreeMinFunction :: Opti3FreeMinFunction (const PointFunction & apf)
+    : pf(apf)
+  {
+    ;
+  }
+
+
+  double Opti3FreeMinFunction :: Func (const Vector & x) const
+  {
+    Point3d pp;
+    pp.X() = sp1.X() + x.Get(1);
+    pp.Y() = sp1.Y() + x.Get(2);
+    pp.Z() = sp1.Z() + x.Get(3);
+
+    return pf.PointFunctionValue (pp);
+  }
+  
+  double Opti3FreeMinFunction :: FuncGrad (const Vector & x, Vector & grad) const
+  {
+    Point3d pp;
+    pp.X() = sp1.X() + x.Get(1);
+    pp.Y() = sp1.Y() + x.Get(2);
+    pp.Z() = sp1.Z() + x.Get(3);
+
+    return pf.PointFunctionValueGrad (pp, grad);
+  }
+
+  double Opti3FreeMinFunction :: FuncDeriv (const Vector & x, const Vector & dir, double & deriv) const
+  {
+    Point3d pp;
+    pp.X() = sp1.X() + x.Get(1);
+    pp.Y() = sp1.Y() + x.Get(2);
+    pp.Z() = sp1.Z() + x.Get(3);
+
+    Vec3d vdir;
+    vdir.X() = dir.Get(1);
+    vdir.Y() = dir.Get(2);
+    vdir.Z() = dir.Get(3);
+
+    return pf.PointFunctionValueDeriv (pp, vdir, deriv);
+  }
+
+  double Opti3FreeMinFunction :: GradStopping (const Vector & x) const
+  {
+    double f = Func(x);
+    return 1e-3 * f / pf.GetLocalH();
+  }
+
+
+  void Opti3FreeMinFunction :: ApproximateHesse (const Vector & x,
+						 DenseMatrix & hesse) const
+  {
+    int n = x.Size();
+    int i, j;
+
+    static Vector hx;
+    hx.SetSize(n);
+
+    double eps = 1e-8;
+    double f, f11, f12, f21, f22;
+
+    f = Func(x);
+
+  
+    for (i = 1; i <= n; i++)
+      {
+	for (j = 1; j < i; j++)
+	  {
+	    /*
+	      hx = x;
+	      hx.Elem(i) = x.Get(i) + eps;
+	      hx.Elem(j) = x.Get(j) + eps;
+	      f11 = Func(hx);
+	      hx.Elem(i) = x.Get(i) + eps;
+	      hx.Elem(j) = x.Get(j) - eps;
+	      f12 = Func(hx);
+	      hx.Elem(i) = x.Get(i) - eps;
+	      hx.Elem(j) = x.Get(j) + eps;
+	      f21 = Func(hx);
+	      hx.Elem(i) = x.Get(i) - eps;
+	      hx.Elem(j) = x.Get(j) - eps;
+	      f22 = Func(hx);
+	    */
+	    hesse.Elem(i, j) = hesse.Elem(j, i) = 0;
+	    //	    (f11 + f22 - f12 - f21) / (2 * eps * eps);
+	  }
+
+	hx = x;
+	hx.Elem(i) = x.Get(i) + eps;
+	f11 = Func(hx);
+	hx.Elem(i) = x.Get(i) - eps;
+	f22 = Func(hx);
+
+	hesse.Elem(i, i) = (f11 + f22 - 2 * f) / (eps * eps) + 1e-12;
+      }
+  }
+
+
+
+
+
+
+#ifdef SOLIDGEOM
+  class Opti3SurfaceMinFunction : public MinFunction
+  {
+    const PointFunction & pf;
+    Point3d sp1;
+    const Surface * surf;
+    Vec3d t1, t2;
+  
+  public:
+    Opti3SurfaceMinFunction (const PointFunction & apf);
+  
+    void SetPoint (const Surface * asurf, const Point3d & asp1);
+
+    void CalcNewPoint (const Vector & x, Point3d & np) const; 
+    virtual double Func (const Vector & x) const;
+    virtual double FuncGrad (const Vector & x, Vector & g) const;
+  };
+
+
+  Opti3SurfaceMinFunction :: Opti3SurfaceMinFunction (const PointFunction & apf)
+    : MinFunction(), pf(apf)
+  {
+    ;
+  }
+
+  void Opti3SurfaceMinFunction :: SetPoint (const Surface * asurf, const Point3d & asp1)
+  { 
+    Vec3d n;
+    sp1 = asp1; 
+    surf = asurf;
+  
+    Vec<3> hn;
+    surf -> GetNormalVector (sp1, hn);
+    n = hn;
+
+    n.GetNormal (t1);
+    t1 /= t1.Length();
+    t2 = Cross (n, t1);
+  }
+
+  
+  void Opti3SurfaceMinFunction :: CalcNewPoint (const Vector & x, 
+						Point3d & np) const
+  {
+    np.X() = sp1.X() + x.Get(1) * t1.X() + x.Get(2) * t2.X();
+    np.Y() = sp1.Y() + x.Get(1) * t1.Y() + x.Get(2) * t2.Y();
+    np.Z() = sp1.Z() + x.Get(1) * t1.Z() + x.Get(2) * t2.Z();
+
+    Point<3> hnp = np;
+    surf -> Project (hnp);
+    np = hnp;
+  }
+
+
+  double Opti3SurfaceMinFunction :: Func (const Vector & x) const
+  {
+    Point3d pp1;
+
+    CalcNewPoint (x, pp1);
+    return pf.PointFunctionValue (pp1);
+  }
+
+
+
+  double Opti3SurfaceMinFunction :: FuncGrad (const Vector & x, Vector & grad) const
+  {
+    Vec3d n, vgrad;
+    Point3d pp1;
+    double badness;
+    static Vector freegrad(3);
+
+    CalcNewPoint (x, pp1);
+
+    badness = pf.PointFunctionValueGrad (pp1, freegrad);
+    vgrad.X() = freegrad.Get(1);
+    vgrad.Y() = freegrad.Get(2);
+    vgrad.Z() = freegrad.Get(3);
+
+    Vec<3> hn;
+    surf -> GetNormalVector (pp1, hn);
+    n = hn;
+
+    vgrad -= (vgrad * n) * n;
+
+    grad.Elem(1) = vgrad * t1;
+    grad.Elem(2) = vgrad * t2;
+    
+    return badness;
+  }
+#endif
+  
+  
+  
+
+
+  
+  
+  
+#ifdef SOLIDGEOM
+  class Opti3EdgeMinFunction : public MinFunction
+  {
+    const PointFunction & pf;
+    Point3d sp1;
+    const Surface *surf1, *surf2;
+    Vec3d t1;
+  
+  public:
+    Opti3EdgeMinFunction (const PointFunction & apf);
+  
+    void SetPoint (const Surface * asurf1, const Surface * asurf2,
+		   const Point3d & asp1);
+    void CalcNewPoint (const Vector & x, Point3d & np) const; 
+    virtual double FuncGrad (const Vector & x, Vector & g) const;
+    virtual double Func (const Vector & x) const;
+  };
+
+  Opti3EdgeMinFunction :: Opti3EdgeMinFunction (const PointFunction & apf)
+    : MinFunction(), pf(apf)
+  {
+    ;
+  }
+  
+  void Opti3EdgeMinFunction :: SetPoint (const Surface * asurf1, 
+					 const Surface * asurf2, 
+					 const Point3d & asp1) 
+  { 
+    Vec3d n1, n2;
+    sp1 = asp1; 
+    surf1 = asurf1;
+    surf2 = asurf2;
+
+    Vec<3> hn1, hn2;
+    surf1 -> GetNormalVector (sp1, hn1);
+    surf2 -> GetNormalVector (sp1, hn2);
+    n1 = hn1;
+    n2 = hn2;
+    t1 = Cross (n1, n2);
+  }
+
+  void Opti3EdgeMinFunction :: CalcNewPoint (const Vector & x,
+					     Point3d & np) const
+{
+  np.X() = sp1.X() + x.Get(1) * t1.X();
+  np.Y() = sp1.Y() + x.Get(1) * t1.Y();
+  np.Z() = sp1.Z() + x.Get(1) * t1.Z();
+  Point<3> hnp = np;
+  ProjectToEdge (surf1, surf2, hnp);
+  np = hnp;
+}   
+
+double Opti3EdgeMinFunction :: Func (const Vector & x) const
+{
+  Vector g(x.Size());
+  return FuncGrad (x, g);
+}
+
+
+double Opti3EdgeMinFunction :: FuncGrad (const Vector & x, Vector & grad) const
+{
+  Vec3d n1, n2, v1, vgrad;
+  Point3d pp1;
+  double badness;
+  static Vector freegrad(3);
+
+  CalcNewPoint (x, pp1);
+
+
+  badness = pf.PointFunctionValueGrad (pp1, freegrad);
+
+  vgrad.X() = freegrad.Get(1);
+  vgrad.Y() = freegrad.Get(2);
+  vgrad.Z() = freegrad.Get(3);
+
+  Vec<3> hn1, hn2;
+  surf1 -> GetNormalVector (pp1, hn1);
+  surf2 -> GetNormalVector (pp1, hn2);
+  n1 = hn1;
+  n2 = hn2;
+
+  v1 = Cross (n1, n2);
+  v1 /= v1.Length();
+
+  grad.Elem(1) = (vgrad * v1) * (t1 * v1);
+  return badness;
+}
+#endif
+
+
+
+
+double CalcBad (const Mesh::T_POINTS & points, const Element & elem,
+		double h)
+{
+  if (elem.GetType() == TET)
+    return CalcTetBadness (points[elem.PNum(1)], 
+			   points[elem.PNum(2)],  
+			   points[elem.PNum(3)],  
+			   points[elem.PNum(4)], h);  
+  return 0;
+}
+
+
+extern double teterrpow;
+double CalcTotalBad (const Mesh::T_POINTS & points, 
+		     const Mesh::T_VOLELEMENTS & elements)
+{
+  int i;
+  double sum = 0;
+  double elbad;
+  
+  tets_in_qualclass.SetSize(20);
+  for (i = 1; i <= 20; i++)
+    tets_in_qualclass.Elem(i) = 0;
+
+
+  for (i = 1; i <= elements.Size(); i++)
+    {
+      elbad = pow (CalcBad (points, elements.Get(i), 0), 1/teterrpow);
+
+      int qualclass = int (20 / elbad + 1);
+      if (qualclass < 1) qualclass = 1;
+      if (qualclass > 20) qualclass = 20;
+      tets_in_qualclass.Elem(qualclass)++;
+
+      sum += elbad;
+    }
+  return sum;
+}
+
+int WrongOrientation (const Mesh::T_POINTS & points, const Element & el)
+{
+  const Point3d & p1 = points[el.PNum(1)];
+  const Point3d & p2 = points[el.PNum(2)];
+  const Point3d & p3 = points[el.PNum(3)];
+  const Point3d & p4 = points[el.PNum(4)];
+
+  Vec3d v1(p1, p2);
+  Vec3d v2(p1, p3);
+  Vec3d v3(p1, p4);
+  Vec3d n;
+
+  Cross (v1, v2, n);
+  double vol = n * v3;
+
+  return (vol > 0);
+}
+
+
+
+
+
+
+
+
+
+
+
+/* ************* JacobianPointFunction **************************** */
+
+
+
+
+class JacobianPointFunction : public MinFunction
+{
+public:
+  Mesh::T_POINTS & points;
+  const Mesh::T_VOLELEMENTS & elements;
+  TABLE<INDEX> elementsonpoint;
+  int actpind;
+  
+public:
+  JacobianPointFunction (Mesh::T_POINTS & apoints, 
+			 const Mesh::T_VOLELEMENTS & aelements);
+  
+  virtual void SetPointIndex (int aactpind);
+  virtual double Func (const Vector & x) const;
+  virtual double FuncGrad (const Vector & x, Vector & g) const;
+  virtual double FuncDeriv (const Vector & x, const Vector & dir, double & deriv) const;
+};
+
+
+JacobianPointFunction :: 
+JacobianPointFunction (Mesh::T_POINTS & apoints, 
+		       const Mesh::T_VOLELEMENTS & aelements)
+  : points(apoints), elements(aelements), elementsonpoint(apoints.Size())
+{
+  INDEX i;
+  int j;
+  
+  for (i = 1; i <= elements.Size(); i++)
+    {
+      for (j = 1; j <= elements.Get(i).NP(); j++)
+	elementsonpoint.Add1 (elements.Get(i).PNum(j), i);  
+    }
+}
+
+void JacobianPointFunction :: SetPointIndex (int aactpind)
+{
+  actpind = aactpind; 
+}  
+
+
+double JacobianPointFunction :: Func (const Vector & v) const
+{
+  int j;
+  double badness = 0;
+
+  Point3d hp = points.Elem(actpind);
+  points.Elem(actpind) = hp + Vec3d (v.Get(1), v.Get(2), v.Get(3));
+
+  for (j = 1; j <= elementsonpoint.EntrySize(actpind); j++)
+    {
+      int eli = elementsonpoint.Get(actpind, j);
+      badness += elements.Get(eli).CalcJacobianBadness (points);
+    }
+  
+  points.Elem(actpind) = hp; 
+
+  return badness;
+}
+
+
+
+
+
+double JacobianPointFunction :: 
+FuncGrad (const Vector & x, Vector & g) const
+{
+  int j, k;
+  int lpi;
+  double badness = 0, hbad;
+
+  Point3d hp = points.Elem(actpind);
+  points.Elem(actpind) = hp + Vec3d (x.Get(1), x.Get(2), x.Get(3));
+
+  double hderiv;
+  Vec3d vdir;
+  g.SetSize(3);
+  g = 0;
+
+  for (j = 1; j <= elementsonpoint.EntrySize(actpind); j++)
+    {
+      int eli = elementsonpoint.Get(actpind, j);
+      const Element & el = elements.Get(eli);
+
+      lpi = 0;
+      for (k = 1; k <= el.GetNP(); k++)
+	if (el.PNum(k) == actpind)
+	  lpi = k;
+      if (!lpi) cerr << "loc point not found" << endl;
+
+      for (k = 1; k <= 3; k++)
+	{
+	  vdir = Vec3d(0,0,0);
+	  vdir.X(k) = 1;
+
+	  hbad = elements.Get(eli).
+	    CalcJacobianBadnessDirDeriv (points, lpi, vdir, hderiv);
+	  g.Elem(k) += hderiv;
+	  if (k == 1)
+	    badness += hbad;
+	}
+    }
+  
+  points.Elem(actpind) = hp; 
+
+  return badness;
+}
+
+
+double JacobianPointFunction :: 
+FuncDeriv (const Vector & x, const Vector & dir, double & deriv) const
+{
+  int j, k;
+  int lpi;
+  double badness = 0;
+
+  Point3d hp = points.Elem(actpind);
+  points.Elem(actpind) = hp + Vec3d (x.Get(1), x.Get(2), x.Get(3));
+
+  double hderiv;
+  deriv = 0;
+  Vec3d vdir(dir.Get(1), dir.Get(2), dir.Get(3));
+
+  for (j = 1; j <= elementsonpoint.EntrySize(actpind); j++)
+    {
+      int eli = elementsonpoint.Get(actpind, j);
+      const Element & el = elements.Get(eli);
+
+      lpi = 0;
+      for (k = 1; k <= el.GetNP(); k++)
+	if (el.PNum(k) == actpind)
+	  lpi = k;
+      if (!lpi) cerr << "loc point not found" << endl;
+
+      badness += elements.Get(eli).
+	CalcJacobianBadnessDirDeriv (points, lpi, vdir, hderiv);
+      deriv += hderiv;
+    }
+  
+  points.Elem(actpind) = hp; 
+
+  return badness;
+  
+  /*
+    (*testout) << "bad1 = " << badness << " der = " << deriv << endl;
+
+
+
+    static Vector hx(3);
+    static double eps = 1e-6;
+
+    double dirlen = dir.L2Norm();
+    if (dirlen < 1e-14)
+    {
+    deriv = 0;
+    return Func(x);
+    }
+
+    hx.Set(1, x);
+    hx.Add(eps / dirlen, dir);
+    double fr = Func (hx);
+    hx.Set(1, x);
+    hx.Add(-eps / dirlen, dir);
+    double fl = Func (hx);
+
+    deriv = (fr - fl) / (2 * eps) * dirlen;
+
+
+    (*testout) << "bad2 = " << Func(x) << " der = " << deriv << endl;
+
+
+    return Func(x);
+  */
+}
+
+
+
+
+
+
+
+
+
+
+#ifdef SOLIDGEOMxxxx
+void Mesh :: ImproveMesh (const CSGeometry & geometry, OPTIMIZEGOAL goal)
+{
+  INDEX i, eli;
+  int j;
+  int typ = 1;
+
+  if (!&geometry || geometry.GetNSurf() == 0)
+    {
+      ImproveMesh (goal);
+      return;
+    }
+
+  char * savetask = multithread.task;
+  multithread.task = "Smooth Mesh";
+
+
+  TABLE<INDEX> surfelementsonpoint(points.Size());
+  Vector x(3), xsurf(2), xedge(1);
+  int surf, surf1, surf2, surf3;
+
+  int uselocalh = mparam.uselocalh;
+
+  (*testout).precision(8);
+  (*testout) << "Improve Mesh" << "\n";
+  PrintMessage (3, "ImproveMesh");
+  //  (*mycout) << "Vol = " << CalcVolume (points, volelements) << endl;
+
+
+  for (i = 1; i <= surfelements.Size(); i++)
+    for (j = 1; j <= 3; j++)
+      surfelementsonpoint.Add1 (surfelements.Get(i).PNum(j), i);
+
+
+  PointFunction * pf;
+  if (typ == 1)
+    pf = new PointFunction(points, volelements);
+  else
+    pf = new CheapPointFunction(points, volelements);
+
+  //  pf->SetLocalH (h);
+  
+  Opti3FreeMinFunction freeminf(*pf);
+  Opti3SurfaceMinFunction surfminf(*pf);
+  Opti3EdgeMinFunction edgeminf(*pf);
+  
+  OptiParameters par;
+  par.maxit_linsearch = 20;
+  par.maxit_bfgs = 20;
+
+
+
+  for (i = 1; i <= points.Size(); i++)
+    {
+      //      if (ptyps.Get(i) == FIXEDPOINT) continue;
+      if (ptyps.Get(i) != INNERPOINT) continue;
+
+      if (multithread.terminate)
+	throw NgException ("Meshing stopped");
+      /*
+      if (multithread.terminate)
+	break;
+      */
+      multithread.percent = 100.0 * i /points.Size();
+
+      if (points.Size() < 1000)
+	PrintDot ();
+      else
+	if (i % 10 == 0)
+	  PrintDot ('+');
+      
+      //    (*testout) << "Now point " << i << "\n";
+      //    (*testout) << "Old: " << points.Get(i) << "\n";
+
+      pf->SetPointIndex (i);
+
+      //      if (uselocalh)
+      {
+	double lh = GetH (points.Get(i));
+	pf->SetLocalH (GetH (points.Get(i)));
+	par.typx = lh / 10;
+	//	  (*testout) << "lh(" << points.Get(i) << ") = " << lh << "\n";
+      }
+
+      surf1 = surf2 = surf3 = 0;
+
+      for (j = 1; j <= surfelementsonpoint.EntrySize(i); j++)
+	{
+	  eli = surfelementsonpoint.Get(i, j);
+	  int surfi = surfelements.Get(eli).GetIndex();
+
+	  if (surfi)
+	    {
+	      surf = GetFaceDescriptor(surfi).SurfNr();
+	    
+	      if (!surf1)
+		surf1 = surf;
+	      else if (surf1 != surf)
+		{
+		  if (!surf2)
+		    surf2 = surf;
+		  else if (surf2 != surf)
+		    surf3 = surf;
+		}
+	    }
+	  else
+	    {
+	      surf1 = surf2 = surf3 = 1;   // simulates corner point
+	    }
+	}
+
+
+      if (surf2 && !surf3)
+	{
+	  //      (*testout) << "On Edge" << "\n";
+	  /*
+	    xedge = 0;
+	    edgeminf.SetPoint (geometry.GetSurface(surf1),
+	    geometry.GetSurface(surf2), 
+	    points.Elem(i));
+	    BFGS (xedge, edgeminf, par);
+
+	    edgeminf.CalcNewPoint (xedge, points.Elem(i));
+	  */
+	}
+
+      if (surf1 && !surf2)
+	{
+	  //      (*testout) << "In Surface" << "\n";
+	  /*
+	    xsurf = 0;
+	    surfminf.SetPoint (geometry.GetSurface(surf1),
+	    points.Get(i));
+	    BFGS (xsurf, surfminf, par);
+   
+	    surfminf.CalcNewPoint (xsurf, points.Elem(i));
+	  */
+	}
+ 
+      if (!surf1)
+	{
+	  //      (*testout) << "In Volume" << "\n";
+	  x = 0;
+	  freeminf.SetPoint (points.Elem(i));
+	  //	  par.typx = 
+	  BFGS (x, freeminf, par);
+
+	  points.Elem(i).X() += x.Get(1);
+	  points.Elem(i).Y() += x.Get(2);
+	  points.Elem(i).Z() += x.Get(3);
+	}
+      
+      //    (*testout) << "New Point: " << points.Elem(i) << "\n" << "\n";
+    
+    }
+  PrintDot ('\n');
+  //  (*mycout) << "Vol = " << CalcVolume (points, volelements) << endl;
+
+  multithread.task = savetask;
+
+}
+#endif
+
+  
+void Mesh :: ImproveMesh (OPTIMIZEGOAL goal)
+{
+  int typ = 1;
+  int i, j;
+  
+  (*testout) << "Improve Mesh2" << "\n";
+  PrintMessage (3, "ImproveMesh2");
+
+  int np = GetNP();
+  int ne = GetNE();
+
+
+  ARRAY<double> perrs(np);
+  for (i = 1; i <= np; i++)
+    perrs.Elem(i) = 1;
+
+  double bad1 = 0;
+  double badmax = 0;
+
+  if (goal == OPT_QUALITY)
+    {
+      for (i = 1; i <= ne; i++)
+	{
+	  const Element & el = VolumeElement(i);
+	  if (el.GetType() != TET)
+	    continue;
+	  
+	  double hbad = CalcBad (points, el, 0);
+	  for (j = 1; j <= 4; j++)
+	    perrs.Elem(el.PNum(j)) += hbad;
+	  
+	  bad1 += hbad;
+	}
+      
+      for (i = 1; i <= np; i++)
+	if (perrs.Get(i) > badmax)
+	  badmax = perrs.Get(i);
+      badmax = 0;
+    }
+
+  if (goal == OPT_QUALITY)
+    {
+      bad1 = CalcTotalBad (points, volelements);
+      (*testout) << "Total badness = " << bad1 << endl;
+      PrintMessage (5, "Total badness = ", bad1);
+    }
+  
+  Vector x(3);
+  
+  (*testout).precision(8);
+  
+  int uselocalh = mparam.uselocalh;
+
+
+  PointFunction * pf;
+
+  if (typ == 1)
+    pf = new PointFunction(points, volelements);
+  else
+    pf = new CheapPointFunction(points, volelements);
+
+  //  pf->SetLocalH (h);
+  
+  Opti3FreeMinFunction freeminf(*pf);
+
+  OptiParameters par;
+  par.maxit_linsearch = 20;
+  par.maxit_bfgs = 20;
+
+
+  char * savetask = multithread.task;
+  multithread.task = "Smooth Mesh";
+  
+  for (i = 1; i <= points.Size(); i++)
+    if (PointType(i) == INNERPOINT && perrs.Get(i) > 0.01 * badmax)
+      {
+	if (multithread.terminate)
+	  throw NgException ("Meshing stopped");
+	/*
+	if (multithread.terminate)
+	  break;
+	*/
+
+	multithread.percent = 100.0 * i / points.Size();
+
+	if (points.Size() < 1000)
+	  PrintDot ();
+	else
+	  if (i % 10 == 0)
+	    PrintDot ('+');
+
+	//	if (uselocalh)
+	{
+	  double lh = GetH(points.Get(i));
+	  pf->SetLocalH (lh);
+	  par.typx = lh;
+	  //	    (*mycout) << "lh = " << lh << "\n";
+	}
+
+	//    if (elementsonpoint.EntrySize(i) == 0) continue;
+	
+	freeminf.SetPoint (points.Elem(i));
+	pf->SetPointIndex (i);
+
+	x = 0;
+	int pok;
+	pok = freeminf.Func (x) < 1e10; 
+
+	if (!pok)
+	  {
+	    pok = pf->MovePointToInner ();
+
+	    freeminf.SetPoint (points.Elem(i));
+	    pf->SetPointIndex (i);
+	  }
+
+	if (pok)
+	  {
+	    BFGS (x, freeminf, par);
+	    
+	    points.Elem(i).X() += x.Get(1);
+	    points.Elem(i).Y() += x.Get(2);
+	    points.Elem(i).Z() += x.Get(3);
+	  }
+      }
+  PrintDot ('\n');
+  
+  
+  delete pf;
+
+  multithread.task = savetask;
+
+  if (goal == OPT_QUALITY)
+    {
+      bad1 = CalcTotalBad (points, volelements);
+      (*testout) << "Total badness = " << bad1 << endl;
+      PrintMessage (5, "Total badness = ", bad1);
+    }
+}
+
+
+
+
+// Improve Condition number of Jacobian, any elements  
+void Mesh :: ImproveMeshJacobian (OPTIMIZEGOAL goal)
+{
+  int i, j;
+  
+  (*testout) << "Improve Mesh Jacobian" << "\n";
+  PrintMessage (3, "ImproveMesh Jacobian");
+
+  int np = GetNP();
+  int ne = GetNE();
+
+  
+  Vector x(3);
+  
+  (*testout).precision(8);
+  
+  JacobianPointFunction pf(points, volelements);
+  
+
+  OptiParameters par;
+  par.maxit_linsearch = 20;
+  par.maxit_bfgs = 20;
+  
+  BitArray badnodes(np);
+  badnodes.Clear();
+
+  for (i = 1; i <= ne; i++)
+    {
+      const Element & el = VolumeElement(i);
+      double bad = el.CalcJacobianBadness (Points());
+      if (bad > 1)
+	for (j = 1; j <= el.GetNP(); j++)
+	  badnodes.Set (el.PNum(j));
+    }
+
+
+  char * savetask = multithread.task;
+  multithread.task = "Smooth Mesh Jacobian";
+  
+  for (i = 1; i <= points.Size(); i++)
+    if (PointType(i) == INNERPOINT)
+      {
+
+	(*testout) << "improvejac, p = " << i << endl;
+
+	if (goal == OPT_WORSTCASE && !badnodes.Test(i))
+	  continue;
+	//	(*testout) << "smoot p " << i << endl;
+
+	/*
+	if (multithread.terminate)
+	  break;
+	*/
+	if (multithread.terminate)
+	  throw NgException ("Meshing stopped");
+
+	multithread.percent = 100.0 * i / points.Size();
+
+	if (points.Size() < 1000)
+	  PrintDot ();
+	else
+	  if (i % 10 == 0)
+	    PrintDot ('+');
+
+	double lh = GetH(points.Get(i));
+	par.typx = lh;
+
+	pf.SetPointIndex (i);
+
+	x = 0;
+	int pok = (pf.Func (x) < 1e10); 
+
+	if (pok)
+	  {
+	    BFGS (x, pf, par);
+
+	    points.Elem(i).X() += x.Get(1);
+	    points.Elem(i).Y() += x.Get(2);
+	    points.Elem(i).Z() += x.Get(3);
+	  }
+	else
+	  {
+	    cout << "el not ok" << endl;
+	  }
+      }
+  PrintDot ('\n');
+  
+
+  multithread.task = savetask;
+}
+
+
+
+
+}
diff --git a/Netgen/libsrc/meshing/specials.cpp b/Netgen/libsrc/meshing/specials.cpp
new file mode 100644
index 0000000000..ae9877cc2e
--- /dev/null
+++ b/Netgen/libsrc/meshing/specials.cpp
@@ -0,0 +1,193 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+
+namespace netgen
+{
+
+// A special function for Hermann Landes, Erlangen
+
+
+void CutOffAndCombine (Mesh & mesh, const Mesh & othermesh)
+{
+  int i, j;
+  int nse = othermesh.GetNSE();
+  int onp = othermesh.GetNP();
+
+  int ne = mesh.GetNE();
+
+  PrintMessage (1, "other mesh has ",
+		othermesh.GetNP(), " points, ",
+		othermesh.GetNSE(), " surface elements.");
+
+  ARRAY<Box3d> otherbounds(nse);  
+  Box3d otherbox;
+
+  double maxh = 0;
+  for (i = 1; i <= nse; i++)
+    {
+      const Element2d & sel = othermesh.SurfaceElement(i);
+      sel.GetBox(othermesh.Points(), otherbounds.Elem(i));
+
+      double loch = othermesh.GetH (othermesh.Point (sel.PNum(1)));
+      otherbounds.Elem(i).Increase(loch);
+      if (loch > maxh) maxh = loch;
+    }
+
+  otherbox.SetPoint (othermesh.Point(1));
+  for (i = 1; i <= othermesh.GetNP(); i++)
+    otherbox.AddPoint (othermesh.Point(i));
+  otherbox.Increase (maxh);
+
+  for (i = 1; i <= ne; i++)
+    {
+      Box3d box;
+      int remove = 0;
+
+      const Element & el = mesh.VolumeElement(i);
+      el.GetBox(mesh.Points(), box);
+
+      if (i % 10000 == 0)
+	cout << "+" << flush;
+
+      if (box.Intersect(otherbox))
+	{
+	  for (j = 1; j <= nse && !remove; j++)
+	    if (box.Intersect(otherbounds.Get(j)))
+	      remove = 1;
+	}
+
+      if (remove)
+	mesh.VolumeElement(i).Delete();
+    }
+  cout << endl;
+
+  BitArray connected(mesh.GetNP());
+  connected.Clear();
+  for (i = 1; i <= mesh.GetNSE(); i++)
+    {
+      const Element2d & el = mesh.SurfaceElement(i);
+      for (j = 1; j <= 3; j++)
+	connected.Set(el.PNum(j));
+    }
+  
+  bool changed;
+  do
+    {
+      changed = 0;
+      for (i = 1; i <= mesh.GetNE(); i++)
+	{
+	  const Element & el = mesh.VolumeElement(i);
+	  int has = 0, hasnot = 0;
+	  if (el[0])
+	    {
+	      for (j = 0; j < 4; j++)
+		{
+		  if (connected.Test(el[j]))
+		    has = 1;
+		  else
+		    hasnot = 1;
+		}
+	      if (has && hasnot)
+		{
+		  changed = 1;
+		  for (j = 0; j < 4; j++)
+		    connected.Set (el[j]);
+		}
+	    }
+	}
+      cout << "." << flush;
+    }
+  while (changed);
+  cout << endl;
+
+  for (i = 1; i <= mesh.GetNE(); i++)
+    {
+      const Element & el = mesh.VolumeElement(i);
+      int hasnot = 0;
+      if (el[0])
+	{
+	  for (j = 0; j < 4; j++)
+	    {
+	      if (!connected.Test(el[j]))
+		hasnot = 1;
+	    }
+	  if (hasnot)
+	    mesh.VolumeElement(i).Delete();
+	}
+    }
+
+  mesh.Compress();
+  
+  mesh.FindOpenElements();
+  BitArray locked(mesh.GetNP());
+  locked.Set();
+  for (i = 1; i <= mesh.GetNOpenElements(); i++)
+    for (j = 1; j <= 3; j++)
+      locked.Clear (mesh.OpenElement(i).PNum(j));
+
+  for (i = 1; i <= locked.Size(); i++)
+    if (locked.Test(i))
+      {
+	mesh.AddLockedPoint (i);
+      }
+
+
+
+  
+  ARRAY<int> pmat(onp);
+
+  for (i = 1; i <= onp; i++)
+    pmat.Elem(i) = mesh.AddPoint (othermesh.Point(i));
+
+  int fnum = 
+    mesh.AddFaceDescriptor (FaceDescriptor(0,0,1,0));
+
+  for (i = 1; i <= othermesh.GetNSE(); i++)
+    {
+      Element2d tri = othermesh.SurfaceElement(i);
+      for (j = 1; j <= 3; j++)
+	tri.PNum(j) = pmat.Get(tri.PNum(j));
+      tri.SetIndex(fnum);
+      mesh.AddSurfaceElement (tri);
+    }
+
+  for (i = 1; i <= onp; i++)
+    mesh.AddLockedPoint (pmat.Elem(i));
+
+  mesh.CalcSurfacesOfNode();
+  mesh.CalcLocalH();
+}
+
+
+
+
+void HelmholtzMesh (Mesh & mesh)
+{
+  int i, j;
+  double ri, ra, rinf;
+
+  cout << "ri = ";
+  cin >> ri;
+  cout << "ra = ";
+  cin >> ra;
+  cout << "rinf = ";
+  cin >> rinf;
+
+  double det = ri * ra * rinf - ri * ri * rinf;
+  double a = (ri - rinf) / det;
+  double b = (ri*ri - ra * rinf) / det;
+  for (i = 1; i <= mesh.GetNP(); i++)
+    {
+      Point3d & p = mesh.Point(i);
+      double rold = sqrt (sqr(p.X()) + sqr(p.Y()) + sqr(p.Z()));
+      if (rold < ri) continue;
+
+      double rnew = 1 / (a * rold - b);
+      double fac = rnew / rold;
+      p.X() *= fac;
+      p.Y() *= fac;
+      p.Z() *= fac;
+    }
+}
+}
diff --git a/Netgen/libsrc/meshing/specials.hpp b/Netgen/libsrc/meshing/specials.hpp
new file mode 100644
index 0000000000..700ba4596b
--- /dev/null
+++ b/Netgen/libsrc/meshing/specials.hpp
@@ -0,0 +1,16 @@
+#ifndef FILE_SPECIALS
+#define FILE_SPECIALS
+
+/*
+
+  Very special implementations ..
+  
+ */
+
+
+///
+extern void CutOffAndCombine (Mesh & mesh, const Mesh & othermesh);
+
+extern void HelmholtzMesh (Mesh & mesh);
+
+#endif
diff --git a/Netgen/libsrc/meshing/tetrarls.cpp b/Netgen/libsrc/meshing/tetrarls.cpp
new file mode 100644
index 0000000000..cb28648b6a
--- /dev/null
+++ b/Netgen/libsrc/meshing/tetrarls.cpp
@@ -0,0 +1,1466 @@
+namespace netgen
+{
+const char * tetrules[] = {
+"tolfak 0.5\n",\
+"\n",\
+"rule \"Free Tetrahedron\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0);\n",\
+"(0.5, 0.866, 0);\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0.5, 0.288, -0.816)\n",\
+"	{ 0.333 X1, 0.333 X2, 0.333 X3 }\n",\
+"	{ 0.333 Y1, 0.333 Y2, 0.333 Y3 } { };\n",\
+"\n",\
+"newfaces\n",\
+"(4, 1, 2);\n",\
+"(4, 2, 3);\n",\
+"(4, 3, 1);\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1.6 P4, -0.2 P1, -0.2 P2, -0.2 P3 };\n",\
+"{ -0.5 P1, 0.5 P2, 0.5 P3, 0.5 P4 };\n",\
+"{ 0.5 P1, -0.5 P2, 0.5 P3, 0.5 P4 };\n",\
+"{ 0.5 P1, 0.5 P2, -0.5 P3, 0.5 P4 };\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Tetrahedron 60\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"flags c;\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 0.5 } ;\n",\
+"(0.5, 0.866, 0) { 0.5 };\n",\
+"(0.5, 0.288, -0.816) { 0.5 };\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3) del;\n",\
+"(1, 4, 2) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newfaces\n",\
+"(1, 4, 3);\n",\
+"(4, 2, 3);\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ -0.35 P1, 0.45 P2, 0.45 P3, 0.45 P4 };\n",\
+"{ 0.45 P1, -0.35 P2, 0.45 P3, 0.45 P4 };\n",\
+"{ -0.05 P1, -0.05 P2, 0.7 P3, 0.4 P4 };\n",\
+"\n",\
+"\n",\
+"freezonelimit\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 0.3333 P2, 0.3333 P3, 0.3334 P4 };\n",\
+"{ 0.3333 P1, 0.3333 P3, 0.3334 P4 };\n",\
+"{ 0.65 P3, 0.35 P4 };\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Tetrahedron 60 with edge(1)\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"flags c;\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 0.8 };\n",\
+"(0.5, 0.866, 0) { 0.8 };\n",\
+"(0.5, 0.288, -0.816) { 0.8 };\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3) del;\n",\
+"(1, 4, 2) del;\n",\
+"\n",\
+"mapedges\n",\
+"(3, 4);\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newfaces\n",\
+"(1, 4, 3);\n",\
+"(4, 2, 3);\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4);\n",\
+"\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 0.4 P1, 0.4 P4, 0.4 P3, -0.2 P2 };\n",\
+"{ 0.4 P2, 0.4 P4, 0.4 P3, -0.2 P1 };\n",\
+"\n",\
+"freezonelimit\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 0.3333 P1, 0.3333 P4, 0.3334 P3 };\n",\
+"{ 0.3333 P2, 0.3333 P4, 0.3334 P3 };\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Tetrahedron Vis a Vis Point (1)\"\n",\
+"\n",\
+"quality 100\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 0.5 };\n",\
+"(0.5, 0.866, 0) { 0.5 };\n",\
+"(0.5, 0.288, -0.816) { 0.5 };\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newfaces\n",\
+"(4, 3, 1);\n",\
+"(4, 2, 3);\n",\
+"(4, 1, 2);\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ -0.5 P1, 0.5 P2, 0.5 P3, 0.5 P4 };\n",\
+"{ 0.5 P1, -0.5 P2, 0.5 P3, 0.5 P4 };\n",\
+"{ 0.5 P1, 0.5 P2, -0.5 P3, 0.5 P4 };\n",\
+"{ 0.8 P1, -0.1 P2, -0.1 P3, 0.4 P4 };\n",\
+"{ -0.1 P1, 0.8 P2, -0.1 P3, 0.4 P4 };\n",\
+"{ -0.1 P1, -0.1 P2, 0.8 P3, 0.4 P4 };\n",\
+"\n",\
+"freezonelimit\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 0.3333 P2, 0.3333 P3, 0.3334 P4 };\n",\
+"{ 0.3333 P1, 0.3333 P3, 0.3334 P4 };\n",\
+"{ 0.3333 P1, 0.3333 P2, 0.3334 P4 };\n",\
+"{ 0.7 P1, 0.3 P4 };\n",\
+"{ 0.7 P2, 0.3 P4 };\n",\
+"{ 0.7 P3, 0.3 P4 };\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Tetrahedron Vis a Vis Point with edge(1)\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 0.5 };\n",\
+"(0.5, 0.866, 0) { 0.5 };\n",\
+"(0.5, 0.288, -0.816) { 0.5 };\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3) del;\n",\
+"\n",\
+"mapedges\n",\
+"(1, 4);\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newfaces\n",\
+"(4, 3, 1);\n",\
+"(4, 2, 3);\n",\
+"(4, 1, 2);\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4);\n",\
+"\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ -0.35 P1, 0.45 P2, 0.45 P3, 0.45 P4 };\n",\
+"{ 0.45 P1, -0.35 P2, 0.45 P3, 0.45 P4 };\n",\
+"{ 0.45 P1, 0.45 P2, -0.35 P3, 0.45 P4 };\n",\
+"{ -0.05 P1, 0.7 P2, -0.05 P3, 0.4 P4 };\n",\
+"{ -0.05 P1, -0.05 P2, 0.7 P3, 0.4 P4 };\n",\
+"\n",\
+"freezonelimit\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 0.3333 P2, 0.3333 P3, 0.3334 P4 };\n",\
+"{ 0.3333 P1, 0.3333 P3, 0.3334 P4 };\n",\
+"{ 0.3333 P1, 0.3333 P2, 0.3334 P4 };\n",\
+"{ 0.65 P2, 0.35 P4 };\n",\
+"{ 0.65 P3, 0.35 P4 };\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Tetrahedron Vis a Vis Point with 2 edges (1)\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 0.5 };\n",\
+"(0.5, 0.866, 0) { 0.5 };\n",\
+"(0.5, 0.288, -0.816) { 0.5 };\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3) del;\n",\
+"\n",\
+"mapedges\n",\
+"(1, 4);\n",\
+"(2, 4);\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newfaces\n",\
+"(4, 3, 1);\n",\
+"(4, 2, 3);\n",\
+"(4, 1, 2);\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4);\n",\
+"\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ -0.35 P1, 0.45 P2, 0.45 P3, 0.45 P4 };\n",\
+"{ 0.45 P1, -0.35 P2, 0.45 P3, 0.45 P4 };\n",\
+"{ 0.45 P1, 0.45 P2, -0.35 P3, 0.45 P4 };\n",\
+"{ -0.05 P1, -0.05 P2, 0.7 P3, 0.4 P4 };\n",\
+"\n",\
+"freezonelimit\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 0.3333 P2, 0.3333 P3, 0.3334 P4 };\n",\
+"{ 0.3333 P1, 0.3333 P3, 0.3334 P4 };\n",\
+"{ 0.3333 P1, 0.3333 P2, 0.3334 P4 };\n",\
+"{ 0.65 P3, 0.35 P4 };\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Tetrahedron Vis a Vis Point with 3 edges (1)\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 0.5 };\n",\
+"(0.5, 0.866, 0) { 0.5 };\n",\
+"(0.5, 0.288, -0.816) { 0.5 };\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3) del;\n",\
+"\n",\
+"mapedges\n",\
+"(1, 4);\n",\
+"(2, 4);\n",\
+"(3, 4);\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newfaces\n",\
+"(4, 3, 1);\n",\
+"(4, 2, 3);\n",\
+"(4, 1, 2);\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4);\n",\
+"\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ -0.35 P1, 0.45 P2, 0.45 P3, 0.45 P4 };\n",\
+"{ 0.45 P1, -0.35 P2, 0.45 P3, 0.45 P4 };\n",\
+"{ 0.45 P1, 0.45 P2, -0.35 P3, 0.45 P4 };\n",\
+"\n",\
+"freezonelimit\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 0.3333 P2, 0.3333 P3, 0.3334 P4 };\n",\
+"{ 0.3333 P1, 0.3333 P3, 0.3334 P4 };\n",\
+"{ 0.3333 P1, 0.3333 P2, 0.3334 P4 };\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Tetrahedron Vis a Vis Triangle (1)\"\n",\
+"\n",\
+"quality 100\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 0.5 };\n",\
+"(0.5, 0.866, 0) { 0.5 };\n",\
+"(0, 0, -0.816) { 0.5 };\n",\
+"(1, 0, -0.816) { 0.5 };\n",\
+"(0.5, 0.866, -0.816) { 0.5 };\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3) del;\n",\
+"(4, 6, 5) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newfaces\n",\
+"(1, 2, 4);\n",\
+"(2, 5, 4);\n",\
+"(2, 3, 6);\n",\
+"(2, 6, 5);\n",\
+"(3, 1, 4);\n",\
+"(3, 4, 6);\n",\
+"\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4);\n",\
+"(4, 2, 3, 6);\n",\
+"(4, 2, 6, 5);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"{ 1 P6 };\n",\
+"{ -0.2 P1, 0.35 P2, 0.35 P3, -0.2 P4, 0.35 P5, 0.35 P6 };\n",\
+"{ 0.35 P1, -0.2 P2, 0.35 P3, 0.35 P4, -0.2 P5, 0.35 P6 };\n",\
+"{ 0.35 P1, 0.35 P2, -0.2 P3, 0.35 P4, 0.35 P5, -0.2 P6 };\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Octaeder 1\"\n",\
+"\n",\
+"quality 100\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 0.95 };\n",\
+"(0.5, 0.866, 0) { 0.95 };\n",\
+"(0.5, -0.288, -0.816) { 0.5 };\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3) del;\n",\
+"(1, 4, 2) del;\n",\
+"\n",\
+"newpoints\n",\
+"(1, 0.578, -0.816) { 0.5 X3, 0.5 X4 } { 0.5 Y3, 0.5 Y4} { 0.5 Z3, 0.5 Z4 };\n",\
+"(0, 0.578, -0.816) { 0.5 X3, 0.5 X4 } { 0.5 Y3, 0.5 Y4} { 0.5 Z3, 0.5 Z4 };\n",\
+"\n",\
+"newfaces\n",\
+"(2, 3, 5);\n",\
+"(3, 1, 6);\n",\
+"(3, 6, 5);\n",\
+"(2, 5, 4);\n",\
+"(1, 4, 6);\n",\
+"(4, 5, 6);\n",\
+"\n",\
+"elements\n",\
+"(3, 4, 1, 2);\n",\
+"(3, 4, 2, 5);\n",\
+"(3, 4, 5, 6);\n",\
+"(3, 4, 6, 1);\n",\
+"\n",\
+"freezone\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 1 X2 } { } { };\n",\
+"(0.5, 0.866, 0) { 1 X3 } { 1 Y3 } { };\n",\
+"(0.5, -0.288, -0.816) { 1 X4 } { 1 Y4 } { 1 Z4 };\n",\
+"(-0.5, 1, -1.5) { 0.5 X3, 0.5 X4 } { 0.5 Y3, 0.5 Y4 } { 1 Z4 };\n",\
+"( 1.5, 1, -1.5) { 0.5 X3, 0.5 X4 } { 0.5 Y3, 0.5 Y4 } { 1 Z4 };\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Octaeder 2\"\n",\
+"\n",\
+"quality 100\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 0.95 };\n",\
+"(0.5, 0.866, 0) { 0.95 };\n",\
+"(0.5, -0.288, -0.816) { 0.5 };\n",\
+"(1, 0.578, -0.816) { 0.5 };\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3) del;\n",\
+"(1, 4, 2) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0, 0.578, -0.816) { 0.5 X3, 0.5 X4 } { 0.5 Y3, 0.5 Y4} { 0.5 Z3, 0.5 Z4 };\n",\
+"\n",\
+"newfaces\n",\
+"(2, 3, 5);\n",\
+"(3, 1, 6);\n",\
+"(3, 6, 5);\n",\
+"(2, 5, 4);\n",\
+"(1, 4, 6);\n",\
+"(4, 5, 6);\n",\
+"\n",\
+"elements\n",\
+"(3, 4, 1, 2);\n",\
+"(3, 4, 2, 5);\n",\
+"(3, 4, 5, 6);\n",\
+"(3, 4, 6, 1);\n",\
+"\n",\
+"freezone\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 1 X2 } { } { };\n",\
+"(0.5, 0.866, 0) { 1 X3 } { 1 Y3 } { };\n",\
+"(0.5, -0.288, -0.816) { 1 X4 } { 1 Y4 } { 1 Z4 };\n",\
+"(1, 0.578, -0.816) { 1 X5 } { 1 Y5 } { 1 Z5 };\n",\
+"\n",\
+"(0.9, 0.097, -0.544) { 0.333 X2, 0.333 X4, 0.333 X5 }\n",\
+"                     { 0.333 Y2, 0.333 Y4, 0.333 Y5 }\n",\
+"                     { 0.333 Z2, 0.333 Z4, 0.333 Z5 };\n",\
+"(0.9, 0.481, -0.272) { 0.333 X2, 0.333 X3, 0.333 X5 }\n",\
+"                     { 0.333 Y2, 0.333 Y3, 0.333 Y5 }\n",\
+"                     { 0.333 Z2, 0.333 Z3, 0.333 Z5 };\n",\
+"\n",\
+"(-0.5, 1, -1.5) { 0.5 X3, 0.5 X4 } { 0.5 Y3, 0.5 Y4 } { 0.5 Z4, 0.5 Z5 };\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"rule \"Octaeder 2a\"\n",\
+"\n",\
+"\n",\
+"quality 100\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 0.95 };\n",\
+"(0.5, 0.866, 0) { 0.95 };\n",\
+"(0.5, -0.288, -0.816) { 0.5 };\n",\
+"(1, 0.578, -0.816) { 0.5 };\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3) del;\n",\
+"(3, 2, 5) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0, 0.578, -0.816)\n",\
+"	{ -1 X2, 1 X3, 1 X4 }\n",\
+"	{ -1 Y2, 1 Y3, 1 Y4 }\n",\
+"	{ -1 Z2, 1 Z3, 1 Z4 };\n",\
+"\n",\
+"newfaces\n",\
+"(1, 2, 4);\n",\
+"(3, 1, 6);\n",\
+"(3, 6, 5);\n",\
+"(2, 5, 4);\n",\
+"(1, 4, 6);\n",\
+"(4, 5, 6);\n",\
+"\n",\
+"elements\n",\
+"(3, 4, 1, 2);\n",\
+"(3, 4, 2, 5);\n",\
+"(3, 4, 5, 6);\n",\
+"(3, 4, 6, 1);\n",\
+"\n",\
+"freezone\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 1 X2 } { } { };\n",\
+"(0.5, 0.866, 0) { 1 X3 } { 1 Y3 } { };\n",\
+"(0.5, -0.288, -0.816) { 1 X4 } { 1 Y4 } { 1 Z4 };\n",\
+"(1, 0.578, -0.816) { 1 X5 } { 1 Y5 } { 1 Z5 };\n",\
+"\n",\
+"(0.9, 0.097, -0.544) { 0.333 X2, 0.333 X4, 0.333 X5 }\n",\
+"                     { 0.333 Y2, 0.333 Y4, 0.333 Y5 }\n",\
+"                     { 0.333 Z2, 0.333 Z4, 0.333 Z5 };\n",\
+"\n",\
+"(0.5, -0.097, -0.272) { 0.333 X2, 0.333 X4, 0.333 X1 }\n",\
+"                     { 0.333 Y2, 0.333 Y4, 0.333 Y1 }\n",\
+"                     { 0.333 Z2, 0.333 Z4, 0.333 Z1 };\n",\
+"\n",\
+"(-0.5, 1, -1.5) { 0.5 X3, 0.5 X4 } { 0.5 Y3, 0.5 Y4 } { 0.5 Z4, 0.5 Z5 };\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Pyramid 1\"\n",\
+"\n",\
+"quality 100\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 1 };\n",\
+"(0.5, 0.866, 0) { 1 };\n",\
+"(0.5, -0.288, -0.816) { 1 };\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3) del;\n",\
+"(1, 4, 2) del;\n",\
+"\n",\
+"newpoints\n",\
+"(1, 0.578, -0.816) { 0.5 X3, 0.5 X4 } { 0.5 Y3, 0.5 Y4} { 0.5 Z3, 0.5 Z4 };\n",\
+"\n",\
+"newfaces\n",\
+"(1, 4, 3);\n",\
+"(2, 3, 5);\n",\
+"(2, 5, 4);\n",\
+"(4, 5, 3);\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4);\n",\
+"(4, 2, 3, 5);\n",\
+"\n",\
+"\n",\
+"freezone\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 1 X2 } { } { };\n",\
+"(0.5, 0.866, 0) { 1 X3 } { 1 Y3 } { };\n",\
+"(0.5, -0.288, -0.816) { 1 X4 } { 1 Y4 } { 1 Z4 };\n",\
+"(0, 1, -1) { 0.5 X3, 0.5 X4 } { 1 Y3 } { 1 Z4 };\n",\
+"(1.5, 1, -1.5) { 0.5 X3, 0.5 X4 } { 0.5 Y3, 0.5 Y4} { 0.5 Z3, 0.5 Z4 };\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Tetrahedron 2 times 60\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 0.3 };\n",\
+"(0.5, 0.866, 0) { 0.3 };\n",\
+"(0.5, 0.288, -0.816) { 0.3 };\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3) del;\n",\
+"(1, 4, 2) del;\n",\
+"(2, 4, 3) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newfaces\n",\
+"(1, 4, 3);\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 0.4 P1, 0.4 P4, 0.4 P3, -0.2 P2 };\n",\
+"\n",\
+"freezonelimit\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 0.3333 P1, 0.3333 P3, 0.3334 P4 };\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Fill Tetrahedron (1)\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 0.2 };\n",\
+"(0.5, 0.866, 0) { 0.2 };\n",\
+"(0.5, 0.288, -0.816) { 0.2 };\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3) del;\n",\
+"(1, 4, 2) del;\n",\
+"(2, 4, 3) del;\n",\
+"(3, 4, 1) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newfaces\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Tetrahedron 120 (1)\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 1 };\n",\
+"(0.5, 0.866, 0) { 1 };\n",\
+"(0.5, -0.674, -0.544) { 1 };\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3) del;\n",\
+"(1, 4, 2) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0.5, 0.288, -0.816)\n",\
+"	{ -0.5 X1, -0.5 X2, 1 X3, 1 X4 }\n",\
+"	{ -0.5 Y1, -0.5 Y2, 1 Y3, 1 Y4}\n",\
+"	{ -0.5 Z1, -0.5 Z2, 1 Z3, 1 Z4};\n",\
+"\n",\
+"newfaces\n",\
+"(1, 5, 3);\n",\
+"(3, 5, 2);\n",\
+"(1, 4, 5);\n",\
+"(2, 5, 4);\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 5);\n",\
+"(1, 4, 2, 5);\n",\
+"\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1.3 P5, -0.3 P1 };\n",\
+"{ 1.3 P5, -0.3 P2 };\n",\
+"\n",\
+"freezonelimit\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"{ 1 P5 };\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Tetrahedron 2 times 120 (1)\"\n",\
+"\n",\
+"quality 100\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 1 };\n",\
+"(0.5, 0.866, 0) { 1 };\n",\
+"(0.5, -0.674, -0.544) { 0.8 };\n",\
+"(1.334, 0.77, -0.544) { 0.8 };\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3) del;\n",\
+"(1, 4, 2) del;\n",\
+"(3, 2, 5) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0.5, 0.288, -0.816) { 0.25 X1, -0.5 X2, 0.25 X3, 0.5 X4, 0.5 X5 }\n",\
+"		 { 0.25 Y1, -0.5 Y2, 0.25 Y3, 0.5 Y4, 0.5 Y5 }\n",\
+"		 { 0.25 Z1, -0.5 Z2, 0.25 Z3, 0.5 Z4, 0.5 Z5 };\n",\
+"\n",\
+"newfaces\n",\
+"(6, 3, 1);\n",\
+"(6, 1, 4);\n",\
+"(6, 4, 2);\n",\
+"(6, 2, 5);\n",\
+"(6, 5, 3);\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 6);\n",\
+"(1, 4, 2, 6);\n",\
+"(2, 5, 3, 6);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"{ 1.4 P6, -0.4 P2 };\n",\
+"{ 1.4 P6, -0.4 P1 };\n",\
+"{ 1.4 P6, -0.4 P3 };\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"four Tetrahedron non convex (4)\"\n",\
+"\n",\
+"quality 4\n",\
+"flags l;\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 0.1 };\n",\
+"(0.5, 1, 0) { 0.1 };\n",\
+"(0.5, 0, -1) { 0.1 };\n",\
+"(0.5, 0.3, -0.3) { 0.1 };\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3) del;\n",\
+"(1, 4, 2) del;\n",\
+"(1, 5, 4) del;\n",\
+"(1, 3, 5) del;\n",\
+"\n",\
+"\n",\
+"newpoints\n",\
+"(0.5, 0.1, -0.1)\n",\
+"	 { 0.333 X1, 0.333 X2, 0.334 X5 }\n",\
+"	 { 0.333 Y1, 0.333 Y2, 0.334 Y5 }\n",\
+"	 { 0.333 Z1, 0.333 Z2, 0.334 Z5 };\n",\
+"\n",\
+"newfaces\n",\
+"(6, 2, 3) del;\n",\
+"(6, 4, 2) del;\n",\
+"(6, 5, 4) del;\n",\
+"(6, 3, 5) del;\n",\
+"\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 6);\n",\
+"(1, 4, 2, 6);\n",\
+"(1, 5, 4, 6);\n",\
+"(1, 3, 5, 6);\n",\
+"\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"{ 1.5 P6, -0.5 P1 };\n",\
+"\n",\
+"freezonelimit\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"{ 1 P6 };\n",\
+"\n",\
+"\n",\
+"\n",\
+"freeset\n",\
+"1 6 2 3;\n",\
+"\n",\
+"freeset\n",\
+"1 6 3 5;\n",\
+"\n",\
+"freeset\n",\
+"1 6 5 4;\n",\
+"\n",\
+"freeset\n",\
+"1 6 4 2;\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"five Tetrahedron non convex (4)\"\n",\
+"\n",\
+"quality 4\n",\
+"flags l;\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 0.5 };\n",\
+"(0.5, 1, 0) { 0.5 };\n",\
+"(0, 0.8, -0.2) { 0.5 };\n",\
+"(0, 0.2, -0.8) { 0.5 };\n",\
+"(0.5, 0, -1) { 0.5 };\n",\
+"\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3) del;\n",\
+"(1, 3, 4) del;\n",\
+"(1, 4, 5) del;\n",\
+"(1, 5, 6) del;\n",\
+"(1, 6, 2) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0.1, 0.1, -0.1)\n",\
+"	 { 0.75 X1, 0.05 X2, 0.05 X3, 0.05 X4, 0.05 X5, 0.05 X6 }\n",\
+"	 { 0.75 Y1, 0.05 Y2, 0.05 Y3, 0.05 Y4, 0.05 Y5, 0.05 Y6 }\n",\
+"	 { 0.75 Z1, 0.05 Z2, 0.05 Z3, 0.05 Z4, 0.05 Z5, 0.05 Z6 };\n",\
+"\n",\
+"newfaces\n",\
+"(7, 2, 3);\n",\
+"(7, 3, 4);\n",\
+"(7, 4, 5);\n",\
+"(7, 5, 6);\n",\
+"(7, 6, 2);\n",\
+"\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 7);\n",\
+"(1, 3, 4, 7);\n",\
+"(1, 4, 5, 7);\n",\
+"(1, 5, 6, 7);\n",\
+"(1, 6, 2, 7);\n",\
+"\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"{ 1 P6 };\n",\
+"{ 1.5 P7, -0.5 P1 };\n",\
+"\n",\
+"freezonelimit\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"{ 1 P6 };\n",\
+"{ 1 P7 };\n",\
+"\n",\
+"\n",\
+"\n",\
+"freeset\n",\
+"1 7 2 3;\n",\
+"\n",\
+"freeset\n",\
+"1 7 3 4;\n",\
+"\n",\
+"freeset\n",\
+"1 7 4 5;\n",\
+"\n",\
+"freeset\n",\
+"1 7 5 6;\n",\
+"\n",\
+"freeset\n",\
+"1 7 6 2;\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"four Tetrahedron non convex (6)\"\n",\
+"\n",\
+"quality 6\n",\
+"flags l;\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 0.5 };\n",\
+"(0.5, 1, 0) { 0.5 };\n",\
+"(0.5, 0, -1) { 0.5 };\n",\
+"(0.5, 0.3, -0.3) { 0.5 };\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3) del;\n",\
+"(1, 4, 2) del;\n",\
+"(1, 5, 4) del;\n",\
+"(1, 3, 5) del;\n",\
+"\n",\
+"\n",\
+"newpoints\n",\
+"(0.095, 0.003, -0.003)\n",\
+"	 { 0.9 X1, 0.09 X2, 0.01 X5 }\n",\
+"	 { 0.9 Y1, 0.09 Y2, 0.01 Y5 }\n",\
+"	 { 0.9 Z1, 0.09 Z2, 0.01 Z5 };\n",\
+"\n",\
+"newfaces\n",\
+"(6, 2, 3) del;\n",\
+"(6, 4, 2) del;\n",\
+"(6, 5, 4) del;\n",\
+"(6, 3, 5) del;\n",\
+"\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 6);\n",\
+"(1, 4, 2, 6);\n",\
+"(1, 5, 4, 6);\n",\
+"(1, 3, 5, 6);\n",\
+"\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"{ 1.499 P6, -0.5 P1, 0.001 P2 };\n",\
+"\n",\
+"freezonelimit\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"{ 1 P6 };\n",\
+"\n",\
+"\n",\
+"\n",\
+"freeset\n",\
+"1 6 2 3;\n",\
+"\n",\
+"freeset\n",\
+"1 6 3 5;\n",\
+"\n",\
+"freeset\n",\
+"1 6 5 4;\n",\
+"\n",\
+"freeset\n",\
+"1 6 4 2;\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"four Tetrahedron non convex (6)\"\n",\
+"\n",\
+"quality 100\n",\
+"\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 0.5 };\n",\
+"(0.5, 1, 0) { 0.5 };\n",\
+"(0.5, 0, -1) { 0.5 };\n",\
+"(0.5, 0.4, -0.4) { 0.5 };\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3) del;\n",\
+"(1, 4, 2) del;\n",\
+"(4, 5, 2) del;\n",\
+"(5, 3, 2) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0.925, 0.02, -0.02)\n",\
+"	 { 0.05 X1, 0.9 X2, 0.05 X5 }\n",\
+"	 { 0.05 Y1, 0.9 Y2, 0.05 Y5 }\n",\
+"	 { 0.05 Z1, 0.9 Z2, 0.05 Z5 };\n",\
+"\n",\
+"newfaces\n",\
+"(3, 1, 6);\n",\
+"(1, 4, 6);\n",\
+"(4, 5, 6);\n",\
+"(5, 3, 6);\n",\
+"\n",\
+"elements\n",\
+"(3, 1, 2, 6);\n",\
+"(1, 4, 2, 6);\n",\
+"(4, 5, 2, 6);\n",\
+"(5, 3, 2, 6);\n",\
+"\n",\
+"orientations\n",\
+"(3, 1, 2, 5);\n",\
+"(1, 4, 2, 5);\n",\
+"(2, 4, 5, 1);\n",\
+"(3, 2, 5, 1);\n",\
+"(5, 4, 2, 3);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"{ 1.5 P6, -0.5 P2 };\n",\
+"\n",\
+"freezonelimit\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"{ 1 P6 };\n",\
+"\n",\
+"freeset\n",\
+"3 1 2 6;\n",\
+"\n",\
+"freeset\n",\
+"1 4 2 6;\n",\
+"\n",\
+"freeset\n",\
+"4 5 2 6;\n",\
+"\n",\
+"freeset\n",\
+"5 3 2 6;\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"three Tetrahedron non convex (4)\"\n",\
+"\n",\
+"quality 4\n",\
+"flags l;\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 0.5 };\n",\
+"(0.5, 1, 0) { 0.5 };\n",\
+"(0.5, 0, -1) { 0.5 };\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3) del;\n",\
+"(1, 4, 2) del;\n",\
+"(1, 3, 4) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0.5, 0.25, -0.25)\n",\
+"	 { 0.25 X1, 0.25 X2, 0.25 X3, 0.25 X4 }\n",\
+"	 { 0.25 Y1, 0.25 Y2, 0.25 Y3, 0.25 Y4 }\n",\
+"	 { 0.25 Z1, 0.25 Z2, 0.25 Z3, 0.25 Z4 };\n",\
+"\n",\
+"newfaces\n",\
+"(5, 2, 3);\n",\
+"(5, 4, 2);\n",\
+"(5, 3, 4);\n",\
+"\n",\
+"elements\n",\
+"(2, 3, 1, 5);\n",\
+"(3, 4, 1, 5);\n",\
+"(4, 2, 1, 5;\n",\
+"\n",\
+"orientations\n",\
+"(1, 2, 4, 3);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1.5 P5, -0.5 P1 };\n",\
+"\n",\
+"freezonelimit\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"\n",\
+"freeset\n",\
+"1 2 3 5;\n",\
+"\n",\
+"freeset\n",\
+"1 3 4 5;\n",\
+"\n",\
+"freeset\n",\
+"1 4 2 5;\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"three Tetrahedron non convex (6)\"\n",\
+"\n",\
+"quality 100\n",\
+"\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 0.5 };\n",\
+"(0.5, 1, 0) { 0.5 };\n",\
+"(0.5, 0, -1) { 0.5 };\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3) del;\n",\
+"(1, 4, 2) del;\n",\
+"(1, 3, 4) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0.2, 0.1, -0.1)\n",\
+"	 { 0.7 X1, 0.1 X2, 0.1 X3, 0.1 X4 }\n",\
+"	 { 0.7 Y1, 0.1 Y2, 0.1 Y3, 0.1 Y4 }\n",\
+"	 { 0.7 Z1, 0.1 Z2, 0.1 Z3, 0.1 Z4 };\n",\
+"\n",\
+"newfaces\n",\
+"(5, 2, 3);\n",\
+"(5, 4, 2);\n",\
+"(5, 3, 4);\n",\
+"\n",\
+"elements\n",\
+"(2, 3, 1, 5);\n",\
+"(3, 4, 1, 5);\n",\
+"(4, 2, 1, 5;\n",\
+"\n",\
+"orientations\n",\
+"(1, 2, 3, 4);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1.5 P5, -0.5 P1 };\n",\
+"\n",\
+"freezonelimit\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"\n",\
+"freeset\n",\
+"1 2 3 5;\n",\
+"\n",\
+"freeset\n",\
+"1 3 4 5;\n",\
+"\n",\
+"freeset\n",\
+"1 4 2 5;\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"four Tetrahedron non convex (6)\"\n",\
+"\n",\
+"quality 100\n",\
+"\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 0.5 };\n",\
+"(0.5, 1, 0) { 0.5 };\n",\
+"(0.5, 0, -1) { 0.5 };\n",\
+"(0.5, 0.4, -0.4) { 0.5 };\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3) del;\n",\
+"(1, 4, 2) del;\n",\
+"(4, 5, 2) del;\n",\
+"(5, 3, 2) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0.7, 0.08, -0.08) { 0.6 X2, 0.2 X5 } { 0.2 Y5 } { 0.2 Z5 };\n",\
+"\n",\
+"newfaces\n",\
+"(3, 1, 6);\n",\
+"(1, 4, 6);\n",\
+"(4, 5, 6);\n",\
+"(5, 3, 6);\n",\
+"\n",\
+"elements\n",\
+"(3, 1, 2, 6);\n",\
+"(1, 4, 2, 6);\n",\
+"(4, 5, 2, 6);\n",\
+"(5, 3, 2, 6);\n",\
+"\n",\
+"\n",\
+"orientations\n",\
+"(3, 1, 2, 5);\n",\
+"(5, 1, 2, 4);\n",\
+"\n",\
+"freezone\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 1 X2 } { } { };\n",\
+"(0.5, 1, 0) { 1 X3 } { 1 Y3 } { };\n",\
+"(0.5, 0, -1) { 1 X4 } { 1 Y4 } { 1 Z4 };\n",\
+"(0.5, 0.4, -0.4) { 1 X5 } { 1 Y5 } { 1 Z5 };\n",\
+"(0.55, 0.12, -0.12) { 0.4 X2, 0.3 X5 } { 0.3 Y5 } { 0.3 Z5 };\n",\
+"\n",\
+"freeset\n",\
+"3 1 2 6;\n",\
+"\n",\
+"freeset\n",\
+"1 4 2 6;\n",\
+"\n",\
+"freeset\n",\
+"4 5 2 6;\n",\
+"\n",\
+"freeset\n",\
+"5 3 2 6;\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Tetrahedron 2 in 60 (12)\"\n",\
+"\n",\
+"quality 100\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 0.5 };\n",\
+"(0.5, 1, 0) { 0.5 };\n",\
+"(0.5, 0, -1) { 0.5 };\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3) del;\n",\
+"(1, 4, 2) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0.5, 0.1, -0.1)\n",\
+"	{ 0.4 X1, 0.4 X2, 0.1 X3, 0.1 X4 }\n",\
+"	{ 0.4 Y1, 0.4 Y2, 0.1 Y3, 0.1 Y4 }\n",\
+"	{ 0.4 Z1, 0.4 Z2, 0.1 Z3, 0.1 Z4 };\n",\
+"\n",\
+"newfaces\n",\
+"(5, 2, 3);\n",\
+"(5, 3, 1);\n",\
+"(5, 4, 2);\n",\
+"(5, 1, 4);\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 5);\n",\
+"(1, 2, 5, 4);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1.5 P5, -0.25 P1, -0.25 P2 };\n",\
+"\n",\
+"freezonelimit\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"\n",\
+"freeset\n",\
+"1 2 3 5;\n",\
+"\n",\
+"freeset\n",\
+"1 2 4 5;\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Tetrahedron 120, but more than 180 (13)\"\n",\
+"\n",\
+"quality 100\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 1 };\n",\
+"(0.5, 0.866, 0) { 1 };\n",\
+"(0.5, -0.866, 0) { 1 };\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3) del;\n",\
+"(1, 4, 2);\n",\
+"\n",\
+"newpoints\n",\
+"(0.5, 0, -0.3) { 0.5 X3, 0.5 X4 } { 0.5 Y3, 0.5 Y4} { 0.5 Z3, 0.5 Z4 };\n",\
+"\n",\
+"newfaces\n",\
+"(1, 5, 3);\n",\
+"(3, 5, 2);\n",\
+"(2, 5, 1);\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 5);\n",\
+"\n",\
+"\n",\
+"freezone\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 1 X2 } { } { };\n",\
+"(0.5, 0.866, 0) { 1 X3 } { 1 Y3 } { };\n",\
+"(0.5, -0.1, -0.4)  { 0.5 X3, 0.5 X4 } { 0.5 Y3, 0.5 Y4} { 0.5 Z3, 0.5 Z4 };\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Free Tetrahedron (14)\"\n",\
+"\n",\
+"quality 100\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 1.0 };\n",\
+"(0.5, 0.866, 0) { 1.0 };\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0.5, 0.288, -0.2) { 0.333 X2, 0.333 X3 } { 0.333 Y3 } { };\n",\
+"\n",\
+"newfaces\n",\
+"(4, 1, 2);\n",\
+"(4, 2, 3);\n",\
+"(4, 3, 1);\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4);\n",\
+"\n",\
+"freezone\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 1 X2 } { } { };\n",\
+"(0.5, 0.866, 0) { 1 X3 } { 1 Y3 } { };\n",\
+"(0.5, 0.288, -0.25) { 0.333 X2, 0.333 X3 } { 0.333 Y3 } { };\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Free Tetrahedron (15)\"\n",\
+"\n",\
+"quality 100\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 1.0 };\n",\
+"(0.5, 0.866, 0) { 1.0 };\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0.5, 0.288, -0.1) { 0.333 X2, 0.333 X3 } { 0.333 Y3 } { };\n",\
+"\n",\
+"newfaces\n",\
+"(4, 1, 2);\n",\
+"(4, 2, 3);\n",\
+"(4, 3, 1);\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4);\n",\
+"\n",\
+"freezone\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 1 X2 } { } { };\n",\
+"(0.5, 0.866, 0) { 1 X3 } { 1 Y3 } { };\n",\
+"(0.5, 0.288, -0.15) { 0.333 X2, 0.333 X3 } { 0.333 Y3 } { };\n",\
+"\n",\
+"endrule\n",
+0};
+}
diff --git a/Netgen/libsrc/meshing/topology.cpp b/Netgen/libsrc/meshing/topology.cpp
new file mode 100644
index 0000000000..9b91a464dc
--- /dev/null
+++ b/Netgen/libsrc/meshing/topology.cpp
@@ -0,0 +1,1523 @@
+#include <mystdlib.h>
+
+#include "meshing.hpp"
+
+namespace netgen
+{
+
+MeshTopology ::  MeshTopology (const Mesh & amesh)
+  : mesh(amesh)
+{
+  buildedges = 1;
+  buildfaces = 1;
+  vert2element = 0;
+  vert2surfelement = 0;
+  vert2segment = 0;
+  timestamp = -1;
+
+  edge2vert.SetName ("edge2vert");
+  face2vert.SetName ("face2vert");
+  edges.SetName ("el2edge");
+  faces.SetName ("el2face");
+  surfedges.SetName ("surfel2edge");
+  segedges.SetName ("segment2edge");
+  surffaces.SetName ("surfel2face");
+  surf2volelement.SetName ("surfel2el");
+  face2surfel.SetName ("face2surfel");
+}
+
+void MeshTopology :: Update()
+{
+  int i, j, k;
+
+  if (timestamp > mesh.GetTimeStamp()) return;
+
+  int ne = mesh.GetNE();
+  int nse = mesh.GetNSE();
+  int nseg = mesh.GetNSeg();
+  int np = mesh.GetNP();
+  int nv = mesh.GetNV();
+  int nfa = 0;
+  int ned = edge2vert.Size();
+
+  PrintMessage (3, "Update mesh topology");
+
+  (*testout) << "ne   = " << ne << endl;
+  (*testout) << "nse  = " << nse << endl;
+  (*testout) << "nseg = " << nseg << endl;
+  (*testout) << "np   = " << np << endl;
+  (*testout) << "nv   = " << nv << endl;
+ 
+  delete vert2element;
+  delete vert2surfelement;
+  delete vert2segment;
+  ARRAY<int> cnt(nv);
+  ARRAY<int> vnums;
+
+  (*testout) << "tables deleted" << endl;
+
+  /*
+    generate:
+    vertex to element 
+    vertex to surface element
+    vertex to segment 
+   */
+
+  cnt = 0;
+  for (i = 1; i <= ne; i++)
+    {
+      const Element & el = mesh.VolumeElement(i);
+      int nelv = el.GetNV();
+      for (j = 1; j <= nelv; j++)
+	cnt.Elem(el.PNum(j))++;
+    }
+  vert2element = new TABLE<int> (cnt);
+  for (i = 1; i <= ne; i++)
+    {
+      const Element & el = mesh.VolumeElement(i);
+      int nelv = el.GetNV();
+      for (j = 1; j <= nelv; j++)
+	vert2element->AddSave (el.PNum(j), i);
+    }
+
+  cnt = 0;
+  for (i = 1; i <= nse; i++)
+    {
+      const Element2d & el = mesh.SurfaceElement(i);
+      int nelv = el.GetNV();
+      for (j = 1; j <= nelv; j++)
+	cnt.Elem(el.PNum(j))++;
+    }
+
+  vert2surfelement = new TABLE<int> (cnt);
+  for (i = 1; i <= nse; i++)
+    {
+      const Element2d & el = mesh.SurfaceElement(i);
+      int nelv = el.GetNV();
+      for (j = 1; j <= nelv; j++)
+	vert2surfelement->AddSave (el.PNum(j), i);
+    }
+
+
+  cnt = 0;
+  for (i = 1; i <= nseg; i++)
+    {
+      const Segment & seg = mesh.LineSegment(i);
+      cnt.Elem (seg.p1)++;
+      cnt.Elem (seg.p2)++;
+    }
+
+  vert2segment = new TABLE<int> (cnt);
+  for (i = 1; i <= nseg; i++)
+    {
+      const Segment & seg = mesh.LineSegment(i);
+      vert2segment->AddSave (seg.p1, i);
+      vert2segment->AddSave (seg.p2, i);
+    }
+
+
+
+  (*testout) << "before buildedges" << endl;
+
+
+  if (buildedges)
+    {
+      PrintMessage (5, "Update edges ");
+      
+      edges.SetSize(ne);
+      surfedges.SetSize(nse); 
+      segedges.SetSize(nseg);
+
+      for (i = 1; i <= ne; i++)
+	for (j = 0; j < 12; j++)
+	  edges.Elem(i)[j] = 0;
+      for (i = 1; i <= nse; i++)
+	for (j = 0; j < 4; j++)
+	  surfedges.Elem(i)[j] = 0;
+
+      // keep existing edges
+      cnt = 0;
+      for (i = 1; i <= edge2vert.Size(); i++)
+	cnt.Elem(edge2vert.Get(i)[0])++;
+      TABLE<int> vert2edge (cnt);
+      for (i = 1; i <= edge2vert.Size(); i++)
+	vert2edge.AddSave (edge2vert.Get(i)[0], i);
+
+      // ensure all coarse grid and intermediate level edges
+      cnt = 0;
+      for (i = 1; i <= mesh.mlbetweennodes.Size(); i++)
+	{
+	  int pa[2];
+	  pa[0] = mesh.mlbetweennodes.Get(i).I1();
+	  pa[1] = mesh.mlbetweennodes.Get(i).I2();
+	  if (pa[0] > pa[1]) Swap (pa[0], pa[1]);
+	  if (pa[0] > 0)
+	    cnt.Elem(pa[0])++;
+	}
+      TABLE<int> vert2vertcoarse (cnt);
+      for (i = 1; i <= mesh.mlbetweennodes.Size(); i++)
+	{
+	  int pa[2];
+	  pa[0] = mesh.mlbetweennodes.Get(i).I1();
+	  pa[1] = mesh.mlbetweennodes.Get(i).I2();
+	  if (pa[0] > pa[1]) Swap (pa[0], pa[1]);
+	  if (pa[0] > 0)
+	    vert2vertcoarse.AddSave (pa[0], pa[1]);
+	}
+
+
+      ARRAY<int> edgenr(nv), edgeflag(nv);
+      for (i = 1; i <= nv; i++)
+	edgeflag.Elem(i) = 0;
+      ned = edge2vert.Size();
+      ARRAY<INDEX_3> missing;
+
+      for (i = 1; i <= nv; i++)
+	{
+	  for (j = 1; j <= vert2edge.EntrySize(i); j++)
+	    {
+	      int ednr = vert2edge.Get(i,j);
+	      int i2 = edge2vert.Get(ednr)[1];
+	      edgeflag.Elem(i2) = i;
+	      edgenr.Elem(i2) = ednr;
+	    }
+	  for (j = 1; j <= vert2vertcoarse.EntrySize(i); j++)
+	    {
+	      int v2 = vert2vertcoarse.Get(i,j);
+	      if (edgeflag.Get(v2) < i)
+		{
+		  ned++;
+		  edgenr.Elem(v2) = ned;
+		  edgeflag.Elem(v2) = i;
+		  missing.Append (INDEX_3(i,v2,ned));
+		}
+	    }
+
+	  for (j = 1; j <= vert2element->EntrySize(i); j++)
+	    {
+	      int elnr = vert2element->Get(i,j);
+	      const Element & el = mesh.VolumeElement (elnr);
+
+	      int neledges = GetNEdges (el.GetType());
+	      const ELEMENT_EDGE * eledges = GetEdges (el.GetType());
+	  
+	      for (k = 0; k < neledges; k++)
+		{
+		  INDEX_2 edge(el.PNum(eledges[k][0]),
+			       el.PNum(eledges[k][1]));
+	      
+		  int edgedir = (edge.I1() > edge.I2());
+		  if (edgedir) Swap (edge.I1(), edge.I2());
+	     
+		  if (edge.I1() != i)
+		    continue;
+	     
+		  if (edgeflag.Get (edge.I2()) < i)
+		    {
+		      ned++;
+		      edgenr.Elem(edge.I2()) = ned;
+		      edgeflag.Elem(edge.I2()) = i;
+		    }
+
+		  int edgenum = edgenr.Elem(edge.I2());
+		  if (edgedir) edgenum *= -1;
+		  edges.Elem(elnr)[k] = edgenum;
+		}
+	    }
+
+	  for (j = 1; j <= vert2surfelement->EntrySize(i); j++)
+	    {
+	      int elnr = vert2surfelement->Get(i,j);
+	      const Element2d & el = mesh.SurfaceElement (elnr);
+
+	      int neledges = GetNEdges (el.GetType());
+	      const ELEMENT_EDGE * eledges = GetEdges (el.GetType());
+	  
+	      for (k = 0; k < neledges; k++)
+		{
+		  INDEX_2 edge(el.PNum(eledges[k][0]),
+			       el.PNum(eledges[k][1]));
+	      
+		  int edgedir = (edge.I1() > edge.I2());
+		  if (edgedir) Swap (edge.I1(), edge.I2());
+	     
+		  if (edge.I1() != i)
+		    continue;
+	     
+		  if (edgeflag.Get (edge.I2()) < i)
+		    {
+		      ned++;
+		      edgenr.Elem(edge.I2()) = ned;
+		      edgeflag.Elem(edge.I2()) = i;
+		    }
+	      
+		  int edgenum = edgenr.Elem(edge.I2());
+		  if (edgedir) edgenum *= -1;
+		  surfedges.Elem(elnr)[k] = edgenum;
+		}
+	    }
+
+	  for (j = 1; j <= vert2segment->EntrySize(i); j++)
+	    {
+	      int elnr = vert2segment->Get(i,j);
+	      const Segment & el = mesh.LineSegment (elnr);
+
+	      INDEX_2 edge(el.p1, el.p2);
+	      
+	      int edgedir = (edge.I1() > edge.I2());
+	      if (edgedir) Swap (edge.I1(), edge.I2());
+	      
+	      if (edge.I1() != i)
+		continue;
+	     
+	      if (edgeflag.Get (edge.I2()) < i)
+		{
+		  ned++;
+		  edgenr.Elem(edge.I2()) = ned;
+		  edgeflag.Elem(edge.I2()) = i;
+		}   
+ 	      int edgenum = edgenr.Elem(edge.I2());
+
+	      if (edgedir) edgenum *= -1;
+	      segedges.Elem(elnr) = edgenum;
+	    }
+	}
+
+
+      edge2vert.SetSize (ned);
+      for (i = 1; i <= ne; i++)
+	{
+	  const Element & el = mesh.VolumeElement (i);
+      
+	  int neledges = GetNEdges (el.GetType());
+	  const ELEMENT_EDGE * eledges = GetEdges (el.GetType());
+	  
+	  for (k = 0; k < neledges; k++)
+	    {
+	      INDEX_2 edge(el.PNum(eledges[k][0]),
+			   el.PNum(eledges[k][1]));
+	  
+	      int edgedir = (edge.I1() > edge.I2());
+	      if (edgedir) Swap (edge.I1(), edge.I2());
+
+	      int edgenum = abs (edges.Elem(i)[k]);
+
+	      edge2vert.Elem(edgenum)[0] = edge.I1();
+	      edge2vert.Elem(edgenum)[1] = edge.I2();
+	    }
+	}
+      for (i = 1; i <= nse; i++)
+	{
+	  const Element2d & el = mesh.SurfaceElement (i);
+      
+	  int neledges = GetNEdges (el.GetType());
+	  const ELEMENT_EDGE * eledges = GetEdges (el.GetType());
+	  
+	  for (k = 0; k < neledges; k++)
+	    {
+	      INDEX_2 edge(el.PNum(eledges[k][0]),
+			   el.PNum(eledges[k][1]));
+	  
+	      int edgedir = (edge.I1() > edge.I2());
+	      if (edgedir) Swap (edge.I1(), edge.I2());
+
+	      int edgenum = abs (surfedges.Elem(i)[k]);
+
+	      edge2vert.Elem(edgenum)[0] = edge.I1();
+	      edge2vert.Elem(edgenum)[1] = edge.I2();
+	    }
+	}
+
+      for (i = 1; i <= nseg; i++)
+	{
+	  const Segment & el = mesh.LineSegment (i);
+      
+	  INDEX_2 edge(el.p1, el.p2);
+	  int edgedir = (edge.I1() > edge.I2());
+	  if (edgedir) Swap (edge.I1(), edge.I2());
+	  
+	  int edgenum = abs (segedges.Elem(i));
+	  
+	  edge2vert.Elem(edgenum)[0] = edge.I1();
+	  edge2vert.Elem(edgenum)[1] = edge.I2();
+	}
+
+      for (i = 1; i <= missing.Size(); i++)
+	{
+	  INDEX_3 i3 = missing.Get(i);
+	  edge2vert.Elem(i3.I3())[0] = i3.I1();
+	  edge2vert.Elem(i3.I3())[1] = i3.I2();
+	}
+	
+      /*
+      (*testout) << "edge table:" << endl;
+      (*testout) << "edge2vert:" << endl;
+      for (i = 1; i <= edge2vert.Size(); i++)
+	  (*testout) << "edge " << i << ", v1,2 = " << edge2vert.Elem(i)[0] << ", " << edge2vert.Elem(i)[1] << endl;
+      (*testout) << "surfedges:" << endl;
+      for (i = 1; i <= surfedges.Size(); i++)
+	  (*testout) << "el " << i << ", edges = " 
+		     << surfedges.Elem(i)[0] << ", "
+		     << surfedges.Elem(i)[1] << ", "
+		     << surfedges.Elem(i)[2] << endl;
+      */
+    }
+
+#ifdef OLD
+  if (buildedges == 2)
+    { // old style with hash-table
+      edges.SetSize(ne);
+      surfedges.SetSize(nse); 
+      INDEX_2_HASHTABLE<int> vert2edge(ne+nse+1);
+      
+      // keep coarse grid edges
+      for (i = 1; i <= ned; i++)
+	{
+	  INDEX_2 edge (edge2vert.Get(i)[0],
+			edge2vert.Get(i)[1]);
+	  edge.Sort ();
+	  vert2edge.Set (edge, i);
+	}
+      
+      
+      
+      for (i = 1; i <= ne; i++)
+	{
+	  const Element & el = mesh.VolumeElement(i);
+	  
+	  int neledges = GetNEdges (el.GetType());
+	  const ELEMENT_EDGE * eledges = GetEdges (el.GetType());
+	  
+	  for (j = 0; j < 12; j++)
+	    edges.Elem(i)[j] = 0;
+	  for (j = 0; j < neledges; j++)
+	    {
+	      int edgenum;
+	      int edgedir;
+	      
+	      INDEX_2 edge(el.PNum(eledges[j][0]),
+			   el.PNum(eledges[j][1]));
+	      
+	      edgedir = (edge.I1() > edge.I2());
+	      if (edgedir) Swap (edge.I1(), edge.I2());
+	      
+	      if (vert2edge.Used (edge))
+		edgenum = vert2edge.Get(edge);
+	      else
+		{
+		  ned++;
+		  vert2edge.Set (edge, ned);
+		  edgenum = ned;
+		  /*
+		  edge2vert.SetSize(edge2vert.Size()+1);
+		  edge2vert.Last()[0] = edge.I1();
+		  edge2vert.Last()[1] = edge.I2();
+		  */
+		  edge2vert.Append (edge);
+		}
+	      
+	      if (edgedir) edgenum *= -1;
+	      edges.Elem(i)[j] = edgenum;
+	    }
+	}
+      
+      for (i = 1; i <= nse; i++)
+	{
+	  const Element2d & el = mesh.SurfaceElement(i);
+	  
+	  int neledges = GetNEdges (el.GetType());
+	  const ELEMENT_EDGE * eledges = GetEdges (el.GetType());
+	  
+	  for (j = 0; j < 4; j++)
+	    surfedges.Elem(i)[j] = 0;
+	  for (j = 0; j < neledges; j++)
+	    {
+	      int edgenum;
+	      int edgedir;
+	      
+	      INDEX_2 edge(el.PNum(eledges[j][0]),
+			   el.PNum(eledges[j][1]));
+	      
+	      edgedir = (edge.I1() > edge.I2());
+	      if (edgedir) Swap (edge.I1(), edge.I2());
+	      
+	      if (vert2edge.Used (edge))
+		edgenum = vert2edge.Get(edge);
+	      else
+		{
+		  ned++;
+		  vert2edge.Set (edge, ned);
+		  edgenum = ned;
+		  
+		  /*
+		  edge2vert.SetSize(edge2vert.Size()+1);
+		  edge2vert.Last()[0] = edge.I1();
+		  edge2vert.Last()[1] = edge.I2();
+		  */
+		  edge2vert.Append (edge);
+		  if (mesh.GetDimension() == 3 && mesh.GetNE())
+		    cerr << "surface edge: should be in use: "
+			 << edge.I1() << "-" << edge.I2() << endl;
+		}
+	      
+	      if (edgedir) edgenum *= -1;
+	      surfedges.Elem(i)[j] = edgenum;
+	    }
+	}
+      
+      
+      // find edges only in intermediate level
+      
+      for (i = 1; i <= np; i++)
+	{
+	  int parents[2];
+	  
+	  if (i <= mesh.mlbetweennodes.Size())
+	    {
+	      parents[0] = mesh.mlbetweennodes.Get(i).I1();
+	      parents[1] = mesh.mlbetweennodes.Get(i).I2();
+	    }
+	  else
+	    parents[0] = parents[1] = 0;
+	  
+	  if (parents[0] && parents[1])
+	    {
+	      INDEX_2 edge(parents[0], parents[1]);
+	      int edgedir = (edge.I1() > edge.I2());
+	      if (edgedir) Swap (edge.I1(), edge.I2());
+	      
+	      if (!vert2edge.Used (edge))
+		{
+		  ned++;
+		  vert2edge.Set (edge, ned);
+		  /*
+		  edge2vert.SetSize(edge2vert.Size()+1);
+		  edge2vert.Last()[0] = edge.I1();
+		  edge2vert.Last()[1] = edge.I2();
+		  */
+		  edge2vert.Append (edge);
+		}
+	    }
+	}
+      
+      /*
+	cout << "edge2vert: ";
+	edge2vert.PrintMemInfo(cout);
+	cout << "edges: ";
+	edges.PrintMemInfo(cout);
+	cout << "hashtable: ";
+	vert2edge.PrintMemInfo(cout);
+      */
+
+      if (mesh.GetDimension() == 2)
+	{
+	  surffaces.SetSize(mesh.GetNSeg());
+	  for (i = 1; i <= mesh.GetNSeg(); i++)
+	    {
+	      const Segment & seg = mesh.LineSegment (i);
+
+	      INDEX_2 edge(seg.p1, seg.p2);
+	      int edgenum;
+	      int edgedir = (edge.I1() > edge.I2());
+	      if (edgedir) Swap (edge.I1(), edge.I2());
+	      
+	      if (vert2edge.Used (edge))
+		edgenum = vert2edge.Get(edge);
+	      else
+		{
+		  ned++;
+		  vert2edge.Set (edge, ned);
+		  edgenum = ned;
+		  
+		  /*
+		  edge2vert.SetSize(edge2vert.Size()+1);
+		  edge2vert.Last()[0] = edge.I1();
+		  edge2vert.Last()[1] = edge.I2();
+		  */
+		  edge2vert.Append (edge);
+		}
+	      
+
+	      if (edgedir) edgenum *= -1;
+	      surffaces.Elem(i) = edgenum;
+	    }
+	}
+    }
+
+#endif  
+  
+
+  // generate faces
+  if (buildfaces) //  && mesh.GetDimension() == 3)
+    {
+      PrintMessage (5, "Update faces ");
+
+      faces.SetSize(ne);
+      surffaces.SetSize(nse);
+      
+      // face2vert.SetSize(0);  // keep old faces
+      nfa = face2vert.Size();
+      // INDEX_3_HASHTABLE<int> vert2face(ne+nse+1);
+      INDEX_3_CLOSED_HASHTABLE<int> vert2face(8*ne+2*nse+nfa+2);
+
+      for (i = 1; i <= face2vert.Size(); i++)
+	{
+	  INDEX_3 f;
+	  f.I1() = face2vert.Get(i)[0];
+	  f.I2() = face2vert.Get(i)[1];
+	  f.I3() = face2vert.Get(i)[2];
+	  vert2face.Set (f, i);
+	}
+      
+      for (i = 1; i <= ne; i++)
+	{
+	  const Element & el = mesh.VolumeElement (i);
+	  
+	  int nelfaces = GetNFaces (el.GetType());
+	  const ELEMENT_FACE * elfaces = GetFaces (el.GetType());
+	  
+	  for (j = 0; j < 6; j++)
+	    faces.Elem(i)[j] = 0;
+	  for (j = 0; j < nelfaces; j++)
+	    if (elfaces[j][3] == 0)
+	      
+	      { // triangle
+		
+		int facenum;
+		int facedir;
+		
+		INDEX_3 face(el.PNum(elfaces[j][0]),
+			     el.PNum(elfaces[j][1]),
+			     el.PNum(elfaces[j][2]));
+		
+		facedir = 0;
+		if (face.I1() > face.I2())
+		  {
+		    Swap (face.I1(), face.I2());
+		    facedir += 1;
+		  }
+		if (face.I2() > face.I3())
+		  {
+		    Swap (face.I2(), face.I3());
+		    facedir += 2;
+		  }
+		if (face.I1() > face.I2())
+		  {
+		    Swap (face.I1(), face.I2());
+		    facedir += 4;
+		  }
+		
+		if (vert2face.Used (face))
+		  facenum = vert2face.Get(face);
+		else
+		  {
+		    nfa++;
+		    vert2face.Set (face, nfa);
+		    facenum = nfa;
+		    
+		    INDEX_4 hface;
+		    face2vert.Append (hface);
+		    // face2vert.SetSize(face2vert.Size()+1);
+		    face2vert.Last()[0] = face.I1();
+		    face2vert.Last()[1] = face.I2();
+		    face2vert.Last()[2] = face.I3();
+		    face2vert.Last()[3] = 0;
+
+		  }
+		
+		faces.Elem(i)[j] = 8*(facenum-1)+facedir+1;
+	      }
+	  
+	    else
+	      
+	      {
+		// quad
+		int facenum;
+		int facedir;
+		INDEX_4Q face4(el.PNum(elfaces[j][0]),
+			       el.PNum(elfaces[j][1]),
+			       el.PNum(elfaces[j][2]),
+			       el.PNum(elfaces[j][3]));
+		
+		facedir = 0;
+		if (min2 (face4.I1(), face4.I2()) > 
+		    min2 (face4.I4(), face4.I3())) 
+		  {  // z - flip
+		    facedir += 1; 
+		    Swap (face4.I1(), face4.I4());
+		    Swap (face4.I2(), face4.I3());
+		  }
+		if (min2 (face4.I1(), face4.I4()) >
+		    min2 (face4.I2(), face4.I3())) 
+		  {  // x - flip
+		    facedir += 2; 
+		    Swap (face4.I1(), face4.I2());
+		    Swap (face4.I3(), face4.I4());
+		  }
+		if (face4.I2() > face4.I4())
+		  {  // diagonal flip
+		    facedir += 4; 
+		    Swap (face4.I2(), face4.I4());
+		  }
+		//		face4.Sort();
+		
+		INDEX_3 face(face4.I1(), face4.I2(), face4.I3());
+		
+		if (vert2face.Used (face))
+		  {
+		    facenum = vert2face.Get(face);
+		  }
+		else
+		  {
+		    nfa++;
+		    vert2face.Set (face, nfa);
+		    facenum = nfa;
+
+		    // face2vert.SetSize(face2vert.Size()+1);
+
+		    INDEX_4 hface;
+		    face2vert.Append (hface);
+		    face2vert.Last()[0] = face4.I1();
+		    face2vert.Last()[1] = face4.I2();
+		    face2vert.Last()[2] = face4.I3();
+		    face2vert.Last()[3] = face4.I4();
+
+		  }
+		
+		faces.Elem(i)[j] = 8*(facenum-1)+facedir+1;
+	      }
+	}
+
+      face2surfel.SetSize(nfa+nse);
+      for (i = 1; i <= face2surfel.Size(); i++)
+	face2surfel.Elem(i) = 0;
+
+      for (i = 1; i <= nse; i++)
+	{
+	  const Element2d & el = mesh.SurfaceElement (i);
+	  
+	  const ELEMENT_FACE * elfaces = GetFaces (el.GetType());
+	  
+	  if (elfaces[0][3] == 0)
+	    
+	    { // triangle
+	      
+	      int facenum;
+	      int facedir;
+	      
+	      INDEX_3 face(el.PNum(elfaces[0][0]),
+			   el.PNum(elfaces[0][1]),
+			   el.PNum(elfaces[0][2]));
+	      
+	      facedir = 0;
+	      if (face.I1() > face.I2())
+		{
+		  Swap (face.I1(), face.I2());
+		  facedir += 1;
+		}
+	      if (face.I2() > face.I3())
+		{
+		  Swap (face.I2(), face.I3());
+		  facedir += 2;
+		}
+	      if (face.I1() > face.I2())
+		{
+		  Swap (face.I1(), face.I2());
+		  facedir += 4;
+		}
+	      
+	      if (vert2face.Used (face))
+		facenum = vert2face.Get(face);
+	      else
+		{
+		  nfa++;
+		  vert2face.Set (face, nfa);
+		  facenum = nfa;
+		  
+		  // face2vert.SetSize(face2vert.Size()+1);
+		  INDEX_4 hface;
+		  face2vert.Append (hface);
+		  face2vert.Last()[0] = face.I1();
+		  face2vert.Last()[1] = face.I2();
+		  face2vert.Last()[2] = face.I3();
+		  face2vert.Last()[3] = 0;
+		}
+	      
+	      surffaces.Elem(i) = 8*(facenum-1)+facedir+1;
+	      face2surfel.Elem(facenum) = i;
+	    }
+	  
+	  else
+	    
+	    {
+	      // quad
+	      int facenum;
+	      int facedir;
+	      
+	      INDEX_4Q face4(el.PNum(elfaces[0][0]),
+			     el.PNum(elfaces[0][1]),
+			     el.PNum(elfaces[0][2]),
+			     el.PNum(elfaces[0][3]));
+
+	      facedir = 0;
+	      if (min2 (face4.I1(), face4.I2()) > 
+		  min2 (face4.I4(), face4.I3())) 
+		{  // z - orientation
+		  facedir += 1; 
+		  Swap (face4.I1(), face4.I4());
+		  Swap (face4.I2(), face4.I3());
+		}
+	      if (min2 (face4.I1(), face4.I4()) >
+		  min2 (face4.I2(), face4.I3())) 
+		{  // x - orientation
+		  facedir += 2; 
+		  Swap (face4.I1(), face4.I2());
+		  Swap (face4.I3(), face4.I4());
+		}
+	      if (face4.I2() > face4.I4())
+		{ 
+		  facedir += 4; 
+		  Swap (face4.I2(), face4.I4());
+		}
+	      
+	      INDEX_3 face(face4.I1(), face4.I2(), face4.I3());
+	      
+	      if (vert2face.Used (face))
+		facenum = vert2face.Get(face);
+	      else
+		{
+		  nfa++;
+		  vert2face.Set (face, nfa);
+		  facenum = nfa;
+		  
+		  // face2vert.SetSize(face2vert.Size()+1);
+		  INDEX_4 hface;
+		  face2vert.Append (hface);
+		  face2vert.Last()[0] = face4.I1();
+		  face2vert.Last()[1] = face4.I2();
+		  face2vert.Last()[2] = face4.I3();
+		  face2vert.Last()[3] = face4.I3();
+		}
+	      
+	      surffaces.Elem(i) = 8*(facenum-1)+facedir+1;
+	      face2surfel.Elem(facenum) = i;
+	    }
+	}
+
+      surf2volelement.SetSize (nse);
+      for (i = 1; i <= nse; i++)
+	{
+	  surf2volelement.Elem(i)[0] = 0;
+	  surf2volelement.Elem(i)[1] = 0;
+	}
+      for (i = 1; i <= ne; i++)
+	for (j = 0; j < 6; j++)
+	  {
+	    int fnum = (faces.Get(i)[j]-1) / 8 + 1;
+	    if (fnum > 0 && face2surfel.Elem(fnum))
+	      {
+		int sel = face2surfel.Elem(fnum);
+		surf2volelement.Elem(sel)[1] = 
+		  surf2volelement.Elem(sel)[0];
+		surf2volelement.Elem(sel)[0] = i;
+	      }
+	  }
+
+
+      face2vert.SetAllocSize (face2vert.Size());
+
+      /*
+	cout << "face2vert: ";
+	face2vert.PrintMemInfo(cout);
+	cout << "faces: ";
+	faces.PrintMemInfo(cout);
+	cout << "hashtable: ";
+	vert2face.PrintMemInfo(cout);
+      */
+    }
+  
+  /*
+    for (i = 1; i <= ne; i++)
+    {
+    (*testout) << "Element " << i << endl;
+    (*testout) << "edges: " << endl;
+    for (j = 0; j < 9; j++)
+    (*testout) << edges.Elem(i)[j] << " ";
+    (*testout) << "faces: " << endl;
+    for (j = 0; j < 6; j++)
+    (*testout) << faces.Elem(i)[j] << " ";
+    }
+  */
+  timestamp = NextTimeStamp();
+}
+
+ 
+
+
+int MeshTopology :: GetNVertices (ELEMENT_TYPE et)
+{
+  switch (et)
+    {
+    case SEGMENT:
+    case SEGMENT3:
+      return 2;
+
+    case TRIG:
+    case TRIG6:
+      return 3;
+
+    case QUAD:
+    case QUAD6:
+      return 4;
+
+    case TET:
+    case TET10:
+      return 4;
+
+    case PYRAMID:
+      return 5;
+
+    case PRISM:
+    case PRISM12:
+      return 6;
+
+    case HEX:
+      return 8;
+
+    default:
+      cerr << "Ng_ME_GetNVertices, illegal element type " << et << endl;
+    }
+  return 0;
+}
+
+int MeshTopology :: GetNEdges (ELEMENT_TYPE et)
+{
+  switch (et)
+    {
+    case SEGMENT:
+    case SEGMENT3:
+      return 1;
+
+    case TRIG:
+    case TRIG6:
+      return 3;
+
+    case QUAD:
+    case QUAD6:
+      return 4;
+
+    case TET:
+    case TET10:
+      return 6;
+
+    case PYRAMID:
+      return 8;
+
+    case PRISM:
+    case PRISM12:
+      return 9;
+
+    case HEX:
+      return 12;
+
+    default:
+      cerr << "Ng_ME_GetNEdges, illegal element type " << et << endl;
+    }
+  return 0;
+}
+
+
+int MeshTopology :: GetNFaces (ELEMENT_TYPE et)
+{
+  switch (et)
+    {
+    case SEGMENT:
+    case SEGMENT3:
+      return 0;
+
+    case TRIG:
+    case TRIG6:
+      return 1;
+
+    case QUAD:
+    case QUAD6:
+      return 1;
+
+    case TET:
+    case TET10:
+      return 4;
+
+    case PYRAMID:
+      return 5;
+
+    case PRISM:
+    case PRISM12:
+      return 5;
+
+    case HEX:
+      return 6;
+
+    default:
+      cerr << "Ng_ME_GetNVertices, illegal element type " << et << endl;
+    }
+  return 0;
+}
+
+
+
+
+const Point3d * MeshTopology :: GetVertices (ELEMENT_TYPE et)
+{
+  static Point3d segm_points [] = 
+    { Point3d (1, 0, 0),
+      Point3d (0, 0, 0) };
+  
+  static Point3d trig_points [] = 
+    { Point3d ( 1, 0, 0 ),
+      Point3d ( 0, 1, 0 ),
+      Point3d ( 0, 0, 0 ) };
+
+  static Point3d quad_points [] = 
+    { Point3d ( 0, 0, 0 ),
+      Point3d ( 1, 0, 0 ),
+      Point3d ( 1, 1, 0 ),
+      Point3d ( 0, 1, 0 ) };
+
+  static Point3d tet_points [] = 
+    { Point3d ( 1, 0, 0 ),
+      Point3d ( 0, 1, 0 ),
+      Point3d ( 0, 0, 1 ),
+      Point3d ( 0, 0, 0 ) };
+
+  static Point3d pyramid_points [] =
+    {
+      Point3d ( 0, 0, 0 ),
+      Point3d ( 1, 0, 0 ),
+      Point3d ( 1, 1, 0 ),
+      Point3d ( 0, 1, 0 ),
+      Point3d ( 0, 0, 1-1e-7 ),
+    };    
+  
+  static Point3d prism_points[] = 
+    {
+      Point3d ( 1, 0, 0 ),
+      Point3d ( 0, 1, 0 ),
+      Point3d ( 0, 0, 0 ),
+      Point3d ( 1, 0, 1 ),
+      Point3d ( 0, 1, 1 ),
+      Point3d ( 0, 0, 1 )
+    };
+
+
+  static Point3d hex_points [] = 
+    { Point3d ( 0, 0, 0 ),
+      Point3d ( 1, 0, 0 ),
+      Point3d ( 1, 1, 0 ),
+      Point3d ( 0, 1, 0 ),
+      Point3d ( 0, 0, 1 ),
+      Point3d ( 1, 0, 1 ),
+      Point3d ( 1, 1, 1 ),
+      Point3d ( 0, 1, 1 ) };
+
+
+  switch (et)
+    {
+    case SEGMENT:
+    case SEGMENT3:
+      return segm_points;
+
+    case TRIG:
+    case TRIG6:
+      return trig_points;
+
+    case QUAD:
+    case QUAD6:
+      return quad_points;
+
+    case TET:
+    case TET10:
+      return tet_points;
+
+    case PYRAMID:
+      return pyramid_points;
+
+    case PRISM:
+    case PRISM12:
+      return prism_points;
+
+    case HEX:
+      return hex_points;
+    default:
+      cerr << "Ng_ME_GetVertices, illegal element type " << et << endl;
+    }
+  return 0;
+}
+
+
+
+
+const ELEMENT_EDGE * MeshTopology :: GetEdges (ELEMENT_TYPE et)
+{
+  static int segm_edges[1][2] =
+    { { 1, 2 }};
+
+  static int trig_edges[3][2] =
+    { { 3, 1 },
+      { 2, 3 },        
+      { 1, 2 }};
+
+  static int quad_edges[4][2] =
+    { { 1, 2 },
+      { 3, 4 },
+      { 4, 1 },
+      { 2, 3 }};
+
+
+  static int tet_edges[6][2] =
+    { { 4, 1 },
+      { 4, 2 },
+      { 4, 3 }, 
+      { 1, 2 },
+      { 1, 3 },
+      { 2, 3 }};
+
+  static int prism_edges[9][2] =
+    { { 3, 1 },
+      { 1, 2 },
+      { 3, 2 },
+      { 6, 4 },
+      { 4, 5 },
+      { 6, 5 },
+      { 3, 6 },
+      { 1, 4 },
+      { 2, 5 }};
+
+  static int pyramid_edges[8][2] =
+    { { 1, 2 },
+      { 2, 3 },
+      { 1, 4 },
+      { 4, 3 },
+      { 1, 5 },
+      { 2, 5 },
+      { 3, 5 },
+      { 4, 5 }};
+
+  static int hex_edges[12][2] =
+    {
+      { 1, 2 },
+      { 3, 4 },
+      { 4, 1 },
+      { 2, 3 },
+      { 5, 6 },
+      { 7, 8 },
+      { 8, 5 },
+      { 6, 7 },
+      { 1, 5 },
+      { 2, 6 },
+      { 3, 7 },
+      { 4, 8 },
+    };
+
+  switch (et)
+    {
+    case SEGMENT:
+    case SEGMENT3:
+      return segm_edges;
+
+    case TRIG:
+    case TRIG6:
+      return trig_edges;
+
+    case QUAD:
+    case QUAD6:
+      return quad_edges;
+
+    case TET:
+    case TET10:
+      return tet_edges;
+
+    case PYRAMID:
+      return pyramid_edges;
+
+    case PRISM:
+    case PRISM12:
+      return prism_edges;
+
+    case HEX:
+      return hex_edges;
+    default:
+      cerr << "Ng_ME_GetEdges, illegal element type " << et << endl;
+    }
+  return 0;  
+}
+
+
+const ELEMENT_FACE * MeshTopology :: GetFaces (ELEMENT_TYPE et)
+{
+  static int trig_faces[1][4] = 
+    { { 1, 2, 3, 0 } };
+  static int quad_faces[1][4] = 
+    { { 1, 2, 3, 4 } };
+
+  static int tet_faces[4][4] =
+    { { 4, 2, 3, 0 },
+      { 4, 1, 3, 0 },
+      { 4, 1, 2, 0 },
+      { 1, 2, 3, 0 } };
+  
+  static int prism_faces[5][4] =
+    {
+      { 1, 2, 3, 0 },
+      { 4, 5, 6, 0 },
+      { 3, 1, 4, 6 },
+      { 1, 2, 5, 4 },
+      { 2, 3, 6, 5 } 
+    };
+
+  static int pyramid_faces[5][4] =
+    {
+      { 1, 2, 5, 0 },
+      { 2, 3, 5, 0 },
+      { 3, 4, 5, 0 },
+      { 4, 1, 5, 0 },
+      { 1, 2, 3, 4 } 
+    };
+
+  static int hex_faces[6][4] =
+    {
+      { 1, 2, 3, 4 },
+      { 5, 6, 7, 8 },
+      { 1, 2, 6, 5 },
+      { 2, 3, 7, 6 },
+      { 3, 4, 8, 7 },
+      { 4, 1, 5, 8 }
+    };
+
+
+  
+  switch (et)
+    {
+    case TRIG:
+    case TRIG6:
+      return trig_faces;
+
+    case QUAD:
+    case QUAD6:
+      return quad_faces;
+
+
+    case TET:
+    case TET10:
+      return tet_faces;
+
+    case PRISM:
+    case PRISM12:
+      return prism_faces;
+
+    case PYRAMID:
+      return pyramid_faces;
+
+    case SEGMENT:
+    case SEGMENT3:
+
+    case HEX:
+      return hex_faces;
+
+    default:
+      cerr << "Ng_ME_GetVertices, illegal element type " << et << endl;
+    }
+  return 0;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+void MeshTopology :: GetElementEdges (int elnr, ARRAY<int> & eledges) const
+{
+  int ned = GetNEdges (mesh.VolumeElement(elnr).GetType());
+  eledges.SetSize (ned);
+  for (int i = 0; i < ned; i++)
+    eledges[i] = abs (edges.Get(elnr)[i]);
+}
+void MeshTopology :: GetElementFaces (int elnr, ARRAY<int> & elfaces) const
+{
+  int i;
+  int nfa = GetNFaces (mesh.VolumeElement(elnr).GetType());
+  elfaces.SetSize (nfa);
+  for (i = 1; i <= nfa; i++)
+    elfaces.Elem(i) = (faces.Get(elnr)[i-1]-1) / 8 + 1;
+}
+
+void MeshTopology :: GetElementEdgeOrientations (int elnr, ARRAY<int> & eorient) const
+{
+  int i;
+  int ned = GetNEdges (mesh.VolumeElement(elnr).GetType());
+  eorient.SetSize (ned);
+  for (i = 1; i <= ned; i++)
+    eorient.Elem(i) = (edges.Get(elnr)[i-1] > 0) ? 1 : -1;
+}
+
+void MeshTopology :: GetElementFaceOrientations (int elnr, ARRAY<int> & forient) const
+{
+  int i;
+  int nfa = GetNFaces (mesh.VolumeElement(elnr).GetType());
+  forient.SetSize (nfa);
+  for (i = 1; i <= nfa; i++)
+    forient.Elem(i) = (faces.Get(elnr)[i-1]-1) % 8;
+}
+
+
+
+int MeshTopology :: GetElementEdges (int elnr, int * eledges, int * orient) const
+{
+  int i;
+  //  int ned = GetNEdges (mesh.VolumeElement(elnr).GetType());
+
+  if (mesh.GetDimension()==3 || 1)
+    {
+      if (orient)
+	{
+	  for (i = 0; i < 12; i++)
+	    {
+	      if (!edges.Get(elnr)[i]) return i;
+	      eledges[i] = abs (edges.Get(elnr)[i]);
+	      orient[i] = (edges.Get(elnr)[i] > 0 ) ? 1 : -1;
+	    }
+	}
+      else
+	{
+	  for (i = 0; i < 12; i++)
+	    {
+	      if (!edges.Get(elnr)[i]) return i;
+	      eledges[i] = abs (edges.Get(elnr)[i]);
+	    }
+	}
+      return 12;
+    }
+  else
+    {
+      if (orient)
+	{
+	  for (i = 0; i < 4; i++)
+	    {
+	      if (!surfedges.Get(elnr)[i]) return i;
+	      eledges[i] = abs (surfedges.Get(elnr)[i]);
+	      orient[i] = (surfedges.Get(elnr)[i] > 0 ) ? 1 : -1;
+	    }
+	}
+      else
+	{
+	  if (!surfedges.Get(elnr)[i]) return i;
+	  for (i = 0; i < 4; i++)
+	    eledges[i] = abs (surfedges.Get(elnr)[i]);
+	}
+      return 4;
+      //      return GetSurfaceElementEdges (elnr, eledges, orient);
+    }
+}
+
+int MeshTopology :: GetElementFaces (int elnr, int * elfaces, int * orient) const
+{
+  int i;
+  //  int nfa = GetNFaces (mesh.VolumeElement(elnr).GetType());
+  if (orient)
+    {
+      for (i = 0; i < 6; i++)
+	{
+	  if (!faces.Get(elnr)[i]) return i;
+	  elfaces[i] = (faces.Get(elnr)[i]-1) / 8 + 1;
+	  orient[i] = (faces.Get(elnr)[i]-1) % 8;
+	}
+    }
+  else
+    {
+      for (i = 0; i < 6; i++)
+	{
+	  if (!faces.Get(elnr)[i]) return i;
+	  elfaces[i] = (faces.Get(elnr)[i]-1) / 8 + 1;
+	}
+    }
+  return 6;
+}
+
+void MeshTopology :: GetSurfaceElementEdges (int elnr, ARRAY<int> & eledges) const
+{
+  int i;
+  if (mesh.GetDimension()==3 || 1)
+    {
+      int ned = GetNEdges (mesh.SurfaceElement(elnr).GetType());
+      eledges.SetSize (ned);
+      for (i = 1; i <= ned; i++)
+	eledges.Elem(i) = abs (surfedges.Get(elnr)[i-1]);
+    }
+  else
+    {
+      cout << "surfeledge(" << elnr << ") = " << flush;
+      eledges.SetSize(1); 
+      eledges.Elem(1) = abs (segedges.Get(elnr));
+      cout << eledges.Elem(1) << endl;
+    }
+}
+
+int MeshTopology :: GetSurfaceElementFace (int elnr) const
+{
+  return (surffaces.Get(elnr)-1) / 8 + 1;  
+}
+
+void MeshTopology :: 
+GetSurfaceElementEdgeOrientations (int elnr, ARRAY<int> & eorient) const
+{
+  int i;
+  int ned = GetNEdges (mesh.SurfaceElement(elnr).GetType());
+  eorient.SetSize (ned);
+  for (i = 1; i <= ned; i++)
+    eorient.Elem(i) = (surfedges.Get(elnr)[i-1] > 0) ? 1 : -1;
+}
+
+int MeshTopology :: GetSurfaceElementFaceOrientation (int elnr) const
+{
+  return (surffaces.Get(elnr)-1) % 8;
+}
+
+int MeshTopology :: GetSurfaceElementEdges (int elnr, int * eledges, int * orient) const
+{
+  int i;
+  if (mesh.GetDimension() == 3 || 1)
+    {
+      if (orient)
+	{
+	  for (i = 0; i < 4; i++)
+	    {
+	      if (!surfedges.Get(elnr)[i]) return i;
+	      eledges[i] = abs (surfedges.Get(elnr)[i]);
+	      orient[i] = (surfedges.Get(elnr)[i] > 0 ) ? 1 : -1;
+	    }
+	}
+      else
+	{
+	  for (i = 0; i < 4; i++)
+	    {
+	      if (!surfedges.Get(elnr)[i]) return i;
+	      eledges[i] = abs (surfedges.Get(elnr)[i]);
+	    }
+	}
+      return 4;
+    }
+  else
+    {
+      eledges[0] = abs (segedges.Get(elnr));
+      if (orient)
+	orient[0] = segedges.Get(elnr) > 0 ? 1 : -1;
+    }
+  return 1;
+}
+
+
+void MeshTopology :: GetFaceVertices (int fnr, ARRAY<int> & vertices) const
+{
+  vertices.SetSize(4);
+  int i;
+  for (i = 1; i <= 4; i++)
+    vertices.Elem(i) = face2vert.Get(fnr)[i-1];
+  if (vertices.Elem(4) == 0)
+    vertices.SetSize(3);
+}
+
+void MeshTopology :: GetFaceVertices (int fnr, int * vertices) const
+{
+  for (int i = 0; i <= 3; i++)
+    vertices[i] = face2vert.Get(fnr)[i];
+}
+
+
+void MeshTopology :: GetEdgeVertices (int ednr, int & v1, int & v2) const
+{
+  v1 = edge2vert.Get(ednr)[0];
+  v2 = edge2vert.Get(ednr)[1];
+}
+
+
+void MeshTopology :: GetFaceEdges (int fnr, ARRAY<int> & edges) const
+{
+  ArrayMem<int,4> pi(4);
+  // ArrayMem<int,50> els;
+  ArrayMem<int,12> eledges;
+
+  edges.SetSize (0);
+  GetFaceVertices (fnr, pi);
+  // GetVertexElements (pi[0], els);
+  FlatArray<int> els = GetVertexElements (pi[0]);
+
+  // find one element having all vertices of the face
+  int i, j, k;
+  for (i = 0; i < els.Size(); i++)
+    {
+      const Element & el = mesh.VolumeElement(els[i]);
+      
+      int cntv = 0;
+      for (j = 0; j < el.GetNV(); j++)
+	for (k = 0; k < pi.Size(); k++)
+	  if (el[j] == pi[k])
+	    cntv++;
+
+      if (cntv == pi.Size())
+	{
+	  GetElementEdges (els[i], eledges);
+	  
+	  for (j = 0; j < eledges.Size(); j++)
+	    {
+	      int vi1, vi2;
+	      GetEdgeVertices (eledges[j], vi1, vi2);
+	      bool has1 = 0;
+	      bool has2 = 0;
+	      for (k = 0; k < pi.Size(); k++)
+		{
+		  if (vi1 == pi[k]) has1 = 1;
+		  if (vi2 == pi[k]) has2 = 1;
+		}
+	      if (has1 && has2)
+		edges.Append (eledges[j]);
+	    }
+
+          return;
+	}
+    }
+}
+
+
+ELEMENT_TYPE MeshTopology :: GetFaceType (int fnr) const
+{
+  if (face2vert.Get(fnr)[3] == 0) return TRIG; else return QUAD;
+}
+
+
+void MeshTopology :: GetVertexElements (int vnr, ARRAY<int> & elements) const
+{
+  if (vert2element)
+    {
+      int i;
+      int ne = vert2element->EntrySize(vnr);
+      elements.SetSize(ne);
+      for (i = 1; i <= ne; i++)
+	elements.Elem(i) = vert2element->Get(vnr, i);
+    }
+}
+
+
+FlatArray<int> MeshTopology :: GetVertexElements (int vnr) const
+{
+  if (vert2element)
+    return (*vert2element)[vnr-1];
+  return FlatArray<int> (0,0);
+}
+
+
+}
diff --git a/Netgen/libsrc/meshing/topology.hpp b/Netgen/libsrc/meshing/topology.hpp
new file mode 100644
index 0000000000..751034be49
--- /dev/null
+++ b/Netgen/libsrc/meshing/topology.hpp
@@ -0,0 +1,109 @@
+#ifndef TOPOLOGY
+#define TOPOLOGY
+
+/**************************************************************************/
+/* File:   topology.hh                                                    */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   27. Apr. 01                                                    */
+/**************************************************************************/
+
+/*
+    Mesh topology
+    (Elements, Faces, Edges, Vertices
+*/
+
+
+class MeshTopology
+{
+  const Mesh & mesh;
+  int buildedges;
+  int buildfaces;
+
+  MoveableArray<INDEX_2> edge2vert;
+  MoveableArray<INDEX_4> face2vert;
+  MoveableArray<int[12]> edges;
+  MoveableArray<int[6]> faces;
+  MoveableArray<int[4]> surfedges;
+  MoveableArray<int> segedges;
+  MoveableArray<int> surffaces;
+  MoveableArray<INDEX_2> surf2volelement;
+  MoveableArray<int> face2surfel;
+  TABLE<int> *vert2element;
+  TABLE<int> *vert2surfelement;
+  TABLE<int> *vert2segment;
+  int timestamp;
+public:
+  MeshTopology (const Mesh & amesh);
+
+  void SetBuildEdges (int be)
+  { buildedges = be; }
+  void SetBuildFaces (int bf)
+  { buildfaces = bf; }
+
+  int HasEdges () const
+  { return buildedges; }
+  int HasFaces () const
+  { return buildedges; }
+
+  void Update();
+
+
+  int GetNEdges () const
+  { return edge2vert.Size(); }
+  int GetNFaces () const
+  { return face2vert.Size(); }
+
+  static int GetNVertices (ELEMENT_TYPE et);
+  static int GetNEdges (ELEMENT_TYPE et);
+  static int GetNFaces (ELEMENT_TYPE et);
+
+  static const Point3d * GetVertices (ELEMENT_TYPE et);
+  static const ELEMENT_EDGE * GetEdges (ELEMENT_TYPE et);
+  static const ELEMENT_FACE * GetFaces (ELEMENT_TYPE et);
+
+
+  
+  int GetSegmentEdge (int segnr) const { return abs(segedges[segnr-1]); }
+  int GetSegmentEdgeOrientation (int segnr) const { return sgn(segedges[segnr-1]); }
+
+  void GetSegmentEdge (int segnr, int & enr, int & orient) const
+  {
+    enr = abs(segedges.Get(segnr));
+    orient = segedges.Get(segnr) > 0 ? 1 : -1;
+  }
+
+  void GetElementEdges (int elnr, ARRAY<int> & edges) const;
+  void GetElementFaces (int elnr, ARRAY<int> & faces) const;
+  void GetElementEdgeOrientations (int elnr, ARRAY<int> & eorient) const;
+  void GetElementFaceOrientations (int elnr, ARRAY<int> & forient) const;
+
+  int GetElementEdges (int elnr, int * edges, int * orient) const;
+  int GetElementFaces (int elnr, int * faces, int * orient) const;
+
+  void GetFaceVertices (int fnr, ARRAY<int> & vertices) const;
+  void GetFaceVertices (int fnr, int * vertices) const;
+  void GetEdgeVertices (int fnr, int & v1, int & v2) const;
+  void GetFaceEdges (int fnr, ARRAY<int> & edges) const;
+
+  ELEMENT_TYPE GetFaceType (int fnr) const;
+
+  void GetSurfaceElementEdges (int elnr, ARRAY<int> & edges) const;
+  int GetSurfaceElementFace (int elnr) const;
+  void GetSurfaceElementEdgeOrientations (int elnr, ARRAY<int> & eorient) const;
+  int GetSurfaceElementFaceOrientation (int elnr) const;
+
+  int GetSurfaceElementEdges (int elnr, int * edges, int * orient) const;
+
+  void GetSurface2VolumeElement (int selnr, int & elnr1, int & elnr2) const
+  { 
+    elnr1 = surf2volelement.Get(selnr)[0];
+    elnr2 = surf2volelement.Get(selnr)[1];
+  }
+
+  int GetFace2SurfaceElement (int fnr) const { return face2surfel[fnr-1]; }
+  
+  void GetVertexElements (int vnr, ARRAY<int> & elements) const;
+  FlatArray<int> GetVertexElements (int vnr) const;
+};
+
+#endif
diff --git a/Netgen/libsrc/meshing/triarls.cpp b/Netgen/libsrc/meshing/triarls.cpp
new file mode 100644
index 0000000000..923763306d
--- /dev/null
+++ b/Netgen/libsrc/meshing/triarls.cpp
@@ -0,0 +1,468 @@
+namespace netgen
+{
+const char * triarules[] = {
+"rule \"Free Triangle (1)\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0) { 1.0, 0, 1.0 };\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0.5, 0.866) { 0.5 X2 } { };\n",\
+"\n",\
+"newlines\n",\
+"(1, 3);\n",\
+"(3, 2);\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1.5, 0.7) { 0.5 X2 } { };\n",\
+"(0.5, 1.5) { 0.5 X2 } { };\n",\
+"(-0.5, 0.7) { 0.5 X2 } { };\n",\
+"\n",\
+"freearea2\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(0.5, 0.866) { 0.5 X2 } { };\n",\
+"(0.5, 0.866) { 0.5 X2 } { };\n",\
+"(0.5, 0.866) { 0.5 X2 } { };\n",\
+"\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"rule \"Free Triangle (5)\"\n",\
+"\n",\
+"quality 5\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0) { 1.0, 0, 1.0 };\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0.5, 0.5) { 0.5 X2 } { };\n",\
+"\n",\
+"newlines\n",\
+"(1, 3);\n",\
+"(3, 2);\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1, 0.7) { 1 X2 } { };\n",\
+"(0, 0.7) { } { };\n",\
+"\n",\
+"freearea2\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(0.5, 0.5) { 0.5 X2 } { };\n",\
+"(0.5, 0.5) { 0.5 X2 } { };\n",\
+"\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Free Triangle (10)\"\n",\
+"\n",\
+"quality 10\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0) { 1.0, 0, 1.0 };\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0.5, 0.3) { 0.5 X2 } { };\n",\
+"\n",\
+"newlines\n",\
+"(1, 3);\n",\
+"(3, 2);\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1, 0.5) { 1 X2 } { };\n",\
+"(0, 0.5) { } { };\n",\
+"\n",\
+"freearea2\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(0.5, 0.3) { 0.5 X2 } { };\n",\
+"(0.5, 0.3) { 0.5 X2 } { };\n",\
+"\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Free Triangle (20)\"\n",\
+"\n",\
+"quality 20\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0) { 1.0, 0, 1.0 };\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0.5, 0.1) { 0.5 X2 } { };\n",\
+"\n",\
+"newlines\n",\
+"(1, 3);\n",\
+"(3, 2);\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1, 0.2) { 1 X2 } { };\n",\
+"(0, 0.2) { } { };\n",\
+"\n",\
+"freearea2\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(0.5, 0.1) { 0.5 X2 } { };\n",\
+"(0.5, 0.1) { 0.5 X2 } { };\n",\
+"\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Right 60 (1)\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0) { 0.5, 0, 1.0 };\n",\
+"(0.5, 0.866) { 0.6, 0, 0.8 };\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"(2, 3) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newlines\n",\
+"(1, 3);\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(0.5, 0.866) { 1 X3 } { 1 Y3 };\n",\
+"(-0.125, 0.6495) { -0.5 X2, 0.75 X3 } { -0.5 Y2, 0.75 Y3 };\n",\
+"\n",\
+"freearea2\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(0.5, 0.866) { 1 X3 } { 1 Y3 };\n",\
+"(0.25, 0.433) { 0.5 X3 } { 0.5 Y3 };\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Left 60 (1)\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0);\n",\
+"(0.5, 0.866);\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"(3, 1) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newlines\n",\
+"(3, 2);\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1.125, 0.6495) { 0.75 X2, 0.75 X3 } { 0.75 Y3 };\n",\
+"(0.5, 0.866) { 1 X3 } { 1 Y3 };\n",\
+"\n",\
+"freearea2\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(0.75, 0.433) { 0.5 X2, 0.5 X3 } { 0.5 Y2, 0.5 Y3 };\n",\
+"(0.5, 0.866) { 1 X3 } { 1 Y3 };\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Right 120 (1)\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0);\n",\
+"(1.5, 0.866);\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"(2, 3) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0.5, 0.866) { 1 X3, -1 X2 } { 1 Y3 };\n",\
+"\n",\
+"newlines\n",\
+"(1, 4);\n",\
+"(4, 3);\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1.5, 0.866) { 1 X3 } { 1 Y3 };\n",\
+"(1, 1.732) { -2 X2, 2 X3 } { 2 Y3 };\n",\
+"(0, 1.732) { -3 X2, 2 X3 } { 2 Y3 };\n",\
+"(-0.5, 0.866) { -2 X2, 1 X3 } {1 Y3 };\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 4);\n",\
+"(2, 3, 4);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Left 120 (1)\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0);\n",\
+"(-0.5, 0.866);\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"(3, 1) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0.5, 0.866) { 1 X3, 1 X2 } { 1 Y3 };\n",\
+"\n",\
+"newlines\n",\
+"(3, 4);\n",\
+"(4, 2);\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1.5, 0.866) { 2 X2, 1 X3 } { 1 Y3 };\n",\
+"(1, 1.732) { 2 X2, 2 X3 } { 2 Y3 };\n",\
+"(0, 1.732) { -1 X2, 2 X3 } { 2 Y3 };\n",\
+"(-0.5, 0.866) { 1 X3 } {1 Y3 };\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 4);\n",\
+"(2, 3, 4);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Left Right 120 (1)\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0);\n",\
+"(-0.5, 0.866);\n",\
+"(1.5, 0.866);\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"(3, 1) del;\n",\
+"(2, 4) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0.5, 0.866) { 0.5 X3, 0.5 X4 } { 0.5 Y3, 0.5 Y4 };\n",\
+"\n",\
+"newlines\n",\
+"(3, 5);\n",\
+"(5, 4);\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1.5, 0.866) { 1 X4 } { 1 Y4 };\n",\
+"(1, 1.299) { -0.5 X2, 0.375 X3, 1.125 X4 } { -0.5 Y2, 0.375 Y3, 1.125 Y4 };\n",\
+"(0, 1.299) { 1.125 X3, 0.375 X4 } { 1.125 Y3, 0.375 Y4 };\n",\
+"(-0.5, 0.866) { 1 X3 } { 1 Y3 };\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 5);\n",\
+"(3, 1, 5);\n",\
+"(2, 4, 5);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"rule \"Fill Triangle\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0);\n",\
+"(0.5, 0.866);\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"(2, 3) del;\n",\
+"(3, 1) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newlines\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { 1 Y2 };\n",\
+"(0.5, 0.866) { 1 X3 } { 1 Y3 };\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Vis A Vis (1)\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0);\n",\
+"(0.5, 0.866);\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newlines\n",\
+"(1, 3);\n",\
+"(3, 2);\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1.2, 0.693) { 0.8 X2, 0.8 X3 } { 0.8 Y2, 0.8 Y3 };\n",\
+"(0.5, 0.866) { 1 X3 } { 1 Y3 };\n",\
+"(-0.2, 0.693) { -0.6 X2, 0.8 X3 } { -0.6 Y2, 0.8 Y3 };\n",\
+"\n",\
+"freearea2\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(0.75, 0.433) { 0.5 X2, 0.5 X3 } { 0.5 Y2, 0.5 Y3 };\n",\
+"(0.5, 0.866) { 1 X3 } { 1 Y3 };\n",\
+"(0.25, 0.433) { 0.5 X3 } { 0.5 Y3 };\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"2 h Vis A Vis (1)\"\n",\
+"\n",\
+"quality 3\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0);\n",\
+"(1, 1.732);\n",\
+"(0, 1.732);\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"(3, 4) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0.5, 0.866) { 0.25 X3, 0.25 X4 } { 0.25 Y2, 0.25 Y3, 0.25 Y4 };\n",\
+"\n",\
+"newlines\n",\
+"(1, 5);\n",\
+"(5, 4);\n",\
+"(3, 5);\n",\
+"(5, 2);\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { 1 Y2 };\n",\
+"(1.5, 0.866) { 0.75 X2, 0.75 X3, -0.25 X4 } { 0.75 Y2, 0.75 Y3, -0.25 Y4 };\n",\
+"(1, 1.732) { 1 X3 } { 1 Y3 };\n",\
+"(0, 1.732) { 1 X4 } { 1 Y4 };\n",\
+"(-0.5, 0.866) { 0.75 X4, -0.25 X2, -0.25 X3 } { 0.75 Y4, -0.25 Y3 };\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 5);\n",\
+"(3, 4, 5);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+0};
+}
diff --git a/Netgen/libsrc/meshing/zrefine.cpp b/Netgen/libsrc/meshing/zrefine.cpp
new file mode 100644
index 0000000000..70dc91e1ca
--- /dev/null
+++ b/Netgen/libsrc/meshing/zrefine.cpp
@@ -0,0 +1,735 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+#include <csg.hpp>
+
+namespace netgen
+{
+
+  // find singular edges
+  void SelectSingularEdges (const Mesh & mesh, const CSGeometry & geom, 
+			    INDEX_2_HASHTABLE<int> & singedges,
+			    ZRefinementOptions & opt)
+  {
+    int i, j;
+
+    // edges selected in csg input file
+    for (i = 1; i <= geom.singedges.Size(); i++)
+      {
+	const SingularEdge & se = *geom.singedges.Get(i);
+	for (j = 1; j <= se.segms.Size(); j++)
+	  {
+	    INDEX_2 i2 = se.segms.Get(j);
+	    singedges.Set (i2, 1);
+	  }
+      }
+
+    // edges interactively selected
+    for (i = 1; i <= mesh.GetNSeg(); i++)
+      {
+	const Segment & seg = mesh.LineSegment(i);
+	if (seg.singedge)
+	  {
+	    INDEX_2 i2(seg.p1, seg.p2);
+	    i2.Sort();
+	    singedges.Set (i2, 1);
+	  }
+      }
+  }
+
+
+  /**
+     Convert elements (vol-tets, surf-trigs) into prisms/quads
+  */
+  void MakePrismsSingEdge (Mesh & mesh, INDEX_2_HASHTABLE<int> & singedges)
+  {
+    int i, j, k;
+
+    // volume elements
+    for (i = 1; i <= mesh.GetNE(); i++)
+      {
+	Element & el = mesh.VolumeElement(i);
+	if (el.GetType() != TET) continue;
+
+	for (j = 1; j <= 3; j++)
+	  for (k = j+1; k <= 4; k++)
+	    {
+	      INDEX_2 edge(el.PNum(j), el.PNum(k));
+	      edge.Sort();
+	      if (singedges.Used (edge))
+		{
+		  int pi3 = 1, pi4 = 1;
+		  while (pi3 == j || pi3 == k) pi3++;
+		  pi4 = 10 - j - k - pi3;
+		
+		  int p3 = el.PNum(pi3);
+		  int p4 = el.PNum(pi4);
+
+		  el.SetType(PRISM);
+		  el.PNum(1) = edge.I1();
+		  el.PNum(2) = p3;
+		  el.PNum(3) = p4;
+		  el.PNum(4) = edge.I2();
+		  el.PNum(5) = p3;
+		  el.PNum(6) = p4;
+		}
+	    }
+      }
+
+    // surface elements
+    for (i = 1; i <= mesh.GetNSE(); i++)
+      {
+	Element2d & el = mesh.SurfaceElement(i);
+	if (el.GetType() != TRIG) continue;
+
+	for (j = 1; j <= 3; j++)
+	  {
+	    k = (j % 3) + 1;
+	    INDEX_2 edge(el.PNum(j), el.PNum(k));
+	    edge.Sort();
+
+	    if (singedges.Used (edge))
+	      {
+		int pi3 = 6-j-k;
+		int p3 = el.PNum(pi3);
+		int p1 = el.PNum(j);
+		int p2 = el.PNum(k);
+
+		el.SetType(QUAD);
+		el.PNum(1) = p2;
+		el.PNum(2) = p3;
+		el.PNum(3) = p3;
+		el.PNum(4) = p1;
+	      }
+	  }
+      }
+  }
+
+
+  /*
+    Convert tets and pyramids next to close (identified) points into prisms
+  */
+  void MakePrismsClosePoints (Mesh & mesh)
+  {
+    int i, j, k;
+    for (i = 1; i <= mesh.GetNE(); i++)
+      {
+	Element & el = mesh.VolumeElement(i);
+	if (el.GetType() == TET)
+	  {
+	    for (j = 1; j <= 3; j++)
+	      for (k = j+1; k <= 4; k++)
+		{
+		  INDEX_2 edge(el.PNum(j), el.PNum(k));
+		  edge.Sort();
+		  if (mesh.GetIdentifications().GetSymmetric (el.PNum(j), el.PNum(k)))
+		    {
+		      int pi3 = 1, pi4 = 1;
+		      while (pi3 == j || pi3 == k) pi3++;
+		      pi4 = 10 - j - k - pi3;
+		    
+		      int p3 = el.PNum(pi3);
+		      int p4 = el.PNum(pi4);
+		    
+		      el.SetType(PRISM);
+		      el.PNum(1) = edge.I1();
+		      el.PNum(2) = p3;
+		      el.PNum(3) = p4;
+		      el.PNum(4) = edge.I2();
+		      el.PNum(5) = p3;
+		      el.PNum(6) = p4;
+		    }
+		}
+	  }
+
+	if (el.GetType() == PYRAMID)
+	  {
+	    // pyramid, base face = 1,2,3,4
+	  
+	    for (j = 0; j <= 1; j++)
+	      {
+		int pi1 = el.PNum( (j+0) % 4 + 1);
+		int pi2 = el.PNum( (j+1) % 4 + 1);
+		int pi3 = el.PNum( (j+2) % 4 + 1);
+		int pi4 = el.PNum( (j+3) % 4 + 1);
+		int pi5 = el.PNum(5);
+
+		INDEX_2 edge1(pi1, pi4);
+		INDEX_2 edge2(pi2, pi3);
+		edge1.Sort();
+		edge2.Sort();
+		if (mesh.GetIdentifications().GetSymmetric (pi1, pi4) &&
+		    mesh.GetIdentifications().GetSymmetric (pi2, pi3))
+		  {
+		    int p3 = el.PNum(pi3);
+		    int p4 = el.PNum(pi4);
+		  
+		    el.SetType(PRISM);
+		    el.PNum(1) = pi1;
+		    el.PNum(2) = pi2;
+		    el.PNum(3) = pi5;
+		    el.PNum(4) = pi4;
+		    el.PNum(5) = pi3;
+		    el.PNum(6) = pi5;
+		  }
+	      }
+	  }
+      }
+  
+    for (i = 1; i <= mesh.GetNSE(); i++)
+      {
+	Element2d & el = mesh.SurfaceElement(i);
+	if (el.GetType() != TRIG) continue;
+
+	for (j = 1; j <= 3; j++)
+	  {
+	    k = (j % 3) + 1;
+	    INDEX_2 edge(el.PNum(j), el.PNum(k));
+	    edge.Sort();
+
+	    if (mesh.GetIdentifications().GetSymmetric (el.PNum(j), el.PNum(k)))
+	      {
+		int pi3 = 6-j-k;
+		int p3 = el.PNum(pi3);
+		int p1 = el.PNum(j);
+		int p2 = el.PNum(k);
+
+		el.SetType(QUAD);
+		el.PNum(1) = p2;
+		el.PNum(2) = p3;
+		el.PNum(3) = p3;
+		el.PNum(4) = p1;
+	      }
+	  }
+      }
+  }
+
+
+
+#ifdef OLD
+  void MakeCornerNodes (Mesh & mesh,
+			INDEX_HASHTABLE<int> & cornernodes)
+  {
+    int i, j;
+    int nseg = mesh.GetNSeg();
+    ARRAY<int> edgesonpoint(mesh.GetNP());
+    for (i = 1; i <= mesh.GetNP(); i++)
+      edgesonpoint.Elem(i) = 0;
+
+    for (i = 1; i <= nseg; i++)
+      {
+	for (j = 1; j <= 2; j++)
+	  {
+	    int pi = (j == 1) ? 
+	      mesh.LineSegment(i).p1 :
+	      mesh.LineSegment(i).p2;
+	    edgesonpoint.Elem(pi)++;
+	  }
+      }
+
+    /*
+      cout << "cornernodes: ";
+      for (i = 1; i <= edgesonpoint.Size(); i++)
+      if (edgesonpoint.Get(i) >= 6)
+      {
+      cornernodes.Set (i, 1);
+      cout << i << " ";
+      }
+      cout << endl;
+    */
+    //  cornernodes.Set (5, 1);
+  }
+#endif
+
+
+  void RefinePrisms (Mesh & mesh, const CSGeometry * geom, 
+		     ZRefinementOptions & opt)
+  {
+    int i, j, k;
+    bool found, change;
+    int cnt = 0;
+
+
+    // markers for z-refinement:  p1, p2, levels  
+    // p1-p2 is an edge to be refined
+    ARRAY<INDEX_3> ref_uniform;
+    ARRAY<INDEX_3> ref_singular;
+    ARRAY<INDEX_4 > ref_slices;
+
+    BitArray first_id(geom->identifications.Size());
+    first_id.Set();
+
+  
+    INDEX_2_HASHTABLE<int> & identpts = 
+      mesh.GetIdentifications().GetIdentifiedPoints ();
+
+    if (&identpts)
+      {
+	for (i = 1; i <= identpts.GetNBags(); i++)
+	  for (j = 1; j <= identpts.GetBagSize(i); j++)
+	    {
+	      INDEX_2 pair;
+	      int idnr;
+	      identpts.GetData(i, j, pair, idnr);
+	      const CloseSurfaceIdentification * csid = 
+		dynamic_cast<const CloseSurfaceIdentification*> 
+		(geom->identifications.Get(idnr));
+	      if (csid)
+		{
+		  if (!csid->GetSlices().Size())
+		    {
+		      if (first_id.Test (idnr))
+			{
+			  first_id.Clear(idnr);
+			  ref_uniform.Append (INDEX_3 (pair.I1(), pair.I2(), csid->RefLevels()));
+			  ref_singular.Append (INDEX_3 (pair.I1(), pair.I2(), csid->RefLevels1()));
+			  ref_singular.Append (INDEX_3 (pair.I2(), pair.I1(), csid->RefLevels2()));
+			}
+		    }
+		  else
+		    {
+		      const ARRAY<double> & slices = csid->GetSlices();
+		      INDEX_4 i4;
+		      i4[0] = pair.I1();
+		      i4[1] = pair.I2();
+		      i4[2] = idnr;
+		      i4[3] = csid->GetSlices().Size();
+		      ref_slices.Append (i4);
+		    }
+		}
+	    }
+      }
+
+  
+  
+    ARRAY<EdgePointGeomInfo> epgi;
+
+    while (1)
+      {
+	cnt++;
+	PrintMessage (3, "Z-Refinement, level = ", cnt);
+	INDEX_2_HASHTABLE<int> refedges(mesh.GetNSE()+1);
+
+
+	found = 0;
+	// mark prisms due to close surface flags:
+	int oldsize = ref_uniform.Size();
+	for (i = 1; i <= oldsize; i++)
+	  {
+	    int pi1 = ref_uniform.Get(i).I1();
+	    int pi2 = ref_uniform.Get(i).I2();
+	    int levels = ref_uniform.Get(i).I3();
+
+	    if (levels > 0)
+	      {
+		const Point3d & p1 = mesh.Point(pi1);
+		const Point3d & p2 = mesh.Point(pi2);
+		int npi;
+	      
+		INDEX_2 edge(pi1, pi2);
+		edge.Sort();
+		if (!refedges.Used(edge))
+		  {
+		    Point3d np = Center (p1, p2);
+		    npi = mesh.AddPoint (np);
+		    refedges.Set (edge, npi);
+		    found = 1;
+		  }
+
+		ref_uniform.Elem(i) = INDEX_3(pi1, npi, levels-1);
+		ref_uniform.Append (INDEX_3(pi2, npi, levels-1));
+	      }
+	  }
+	for (i = 1; i <= ref_singular.Size(); i++)
+	  {
+	    int pi1 = ref_singular.Get(i).I1();
+	    int pi2 = ref_singular.Get(i).I2();
+	    int levels = ref_singular.Get(i).I3();
+
+	    if (levels > 0)
+	      {
+		const Point3d & p1 = mesh.Point(pi1);
+		const Point3d & p2 = mesh.Point(pi2);
+		int npi;
+	      
+		INDEX_2 edge(pi1, pi2);
+		edge.Sort();
+		if (!refedges.Used(edge))
+		  {
+		    Point3d np = Center (p1, p2);
+		    npi = mesh.AddPoint (np);
+		    refedges.Set (edge, npi);
+		    found = 1;
+		  }
+		else
+		  npi = refedges.Get (edge);
+
+		ref_singular.Elem(i) = INDEX_3(pi1, npi, levels-1);
+	      }
+	  }
+
+	for (i = 1; i <= ref_slices.Size(); i++)
+	  {
+	    int pi1 = ref_slices.Get(i)[0];
+	    int pi2 = ref_slices.Get(i)[1];
+	    int idnr = ref_slices.Get(i)[2];
+	    int slicenr = ref_slices.Get(i)[3];
+
+	    if (slicenr > 0)
+	      {
+		const Point3d & p1 = mesh.Point(pi1);
+		const Point3d & p2 = mesh.Point(pi2);
+		int npi;
+
+		const CloseSurfaceIdentification * csid = 
+		  dynamic_cast<const CloseSurfaceIdentification*> 
+		  (geom->identifications.Get(idnr));
+
+	      
+		INDEX_2 edge(pi1, pi2);
+		edge.Sort();
+		if (!refedges.Used(edge))
+		  {
+		    const ARRAY<double> & slices = csid->GetSlices();
+		    double slicefac = slices.Get(slicenr);
+		    double slicefaclast = 
+		      (slicenr == slices.Size()) ? 1 : slices.Get(slicenr+1);
+		    
+		    Point3d np = p1 + (slicefac / slicefaclast) * (p2-p1);
+		    npi = mesh.AddPoint (np);
+		    refedges.Set (edge, npi);
+		    found = 1;
+		  }
+		else
+		  npi = refedges.Get (edge);
+		
+		ref_slices.Elem(i)[1] = npi;
+		ref_slices.Elem(i)[3] --;
+	      }
+	  }
+
+
+
+
+	for (i = 1; i <= mesh.GetNE(); i++)
+	  {
+	    Element & el = mesh.VolumeElement (i);
+	    if (el.GetType() != PRISM)
+	      continue;
+
+	    for (j = 1; j <= 3; j++)
+	      {
+		int pi1 = el.PNum(j);
+		int pi2 = el.PNum(j+3);
+		const Point3d & p1 = mesh.Point(pi1);
+		const Point3d & p2 = mesh.Point(pi2);
+
+		bool ref = 0;
+
+		/*
+		  if (Dist (p1, p2) > mesh.GetH (Center (p1, p2)))
+		  ref = 1;
+		*/
+
+		/*
+		  if (cnt <= opt.minref)
+		  ref = 1;
+		*/
+
+		/*
+		  if ((pi1 == 460 || pi2 == 460 ||
+		  pi1 == 461 || pi2 == 461) && cnt <= 8) ref = 1;
+		*/
+		if (ref == 1)
+		  {
+		    INDEX_2 edge(pi1, pi2);
+		    edge.Sort();
+		    if (!refedges.Used(edge))
+		      {
+			Point3d np = Center (p1, p2);
+			int npi = mesh.AddPoint (np);
+			refedges.Set (edge, npi);
+			found = 1;
+		      }
+		  }
+	      }
+	  }
+      
+	if (!found) break;
+
+	// build closure:
+	PrintMessage (5, "start closure");
+	do
+	  {
+	    PrintMessage (5, "start loop");
+	    change = 0;
+	    for (i = 1; i <= mesh.GetNE(); i++)
+	      {
+		Element & el = mesh.VolumeElement (i);
+		if (el.GetType() != PRISM)
+		  continue;
+	      
+		bool hasref = 0, hasnonref = 0;
+		for (j = 1; j <= 3; j++)
+		  {
+		    int pi1 = el.PNum(j);
+		    int pi2 = el.PNum(j+3);
+		    if (pi1 != pi2)
+		      {
+			INDEX_2 edge(pi1, pi2);
+			edge.Sort();
+			if (refedges.Used(edge))
+			  hasref = 1;
+			else 
+			  hasnonref = 1;
+		      }
+		  }
+
+		if (hasref && hasnonref)
+		  {
+		    //		  cout << "el " << i << " in closure" << endl;
+		    change = 1;
+		    for (j = 1; j <= 3; j++)
+		      {
+			int pi1 = el.PNum(j);
+			int pi2 = el.PNum(j+3);
+			const Point3d & p1 = mesh.Point(pi1);
+			const Point3d & p2 = mesh.Point(pi2);
+		      
+			INDEX_2 edge(pi1, pi2);
+			edge.Sort();
+			if (!refedges.Used(edge))
+			  {
+			    Point3d np = Center (p1, p2);
+			    int npi = mesh.AddPoint (np);
+			    refedges.Set (edge, npi);
+			  }
+		      }
+		  }
+	      }
+	  }
+	while (change);
+
+	PrintMessage (5, "Do segments");
+
+	//      (*testout) << "closure formed, np = " << mesh.GetNP() << endl;
+
+	int oldns = mesh.GetNSeg();
+
+	for (i = 1; i <= oldns; i++)
+	  {
+	    const Segment & el = mesh.LineSegment(i);
+
+	    INDEX_2 i2(el.p1, el.p2);
+	    i2.Sort();
+	  
+	    int pnew;
+	    EdgePointGeomInfo ngi;
+      
+	    if (refedges.Used(i2))
+	      {
+		pnew = refedges.Get(i2);
+		//	      ngi = epgi.Get(pnew);
+	      }
+	    else
+	      {
+		continue;
+
+		// 	      Point3d pb;
+
+		// 	      /*
+		// 	      geom->PointBetween (mesh.Point (el.p1),
+		// 				  mesh.Point (el.p2),
+		// 				  el.surfnr1, el.surfnr2,
+		// 				  el.epgeominfo[0], el.epgeominfo[1],
+		// 				  pb, ngi);
+		// 	      */
+		// 	      pb = Center (mesh.Point (el.p1), mesh.Point (el.p2));
+
+		// 	      pnew = mesh.AddPoint (pb);
+	      
+		// 	      refedges.Set (i2, pnew);
+	      
+		// 	      if (pnew > epgi.Size())
+		// 		epgi.SetSize (pnew);
+		// 	      epgi.Elem(pnew) = ngi;
+	      }
+	  
+	    Segment ns1 = el;
+	    Segment ns2 = el;
+	    ns1.p2 = pnew;
+	    ns1.epgeominfo[1] = ngi;
+	    ns2.p1 = pnew;
+	    ns2.epgeominfo[0] = ngi;
+
+	    mesh.LineSegment(i) = ns1;
+	    mesh.AddSegment (ns2);
+	  }
+      
+	PrintMessage (5, "Segments done, NSeg = ", mesh.GetNSeg());
+
+	// do refinement
+	int oldne = mesh.GetNE();
+	for (i = 1; i <= oldne; i++)
+	  {
+	    Element & el = mesh.VolumeElement (i);
+	    if (el.GetNP() != 6)
+	      continue;
+
+	    int npi[3];
+	    for (j = 1; j <= 3; j++)
+	      {
+		int pi1 = el.PNum(j);
+		int pi2 = el.PNum(j+3);
+
+		if (pi1 == pi2)
+		  npi[j-1] = pi1;
+		else
+		  {
+		    INDEX_2 edge(pi1, pi2);
+		    edge.Sort();
+		    if (refedges.Used (edge))
+		      npi[j-1] = refedges.Get(edge);
+		    else
+		      {
+			/*
+			  (*testout) << "ERROR: prism " << i << " has hanging node !!" 
+			  << ", edge = " << edge << endl;
+			  cerr << "ERROR: prism " << i << " has hanging node !!" << endl;
+			*/
+			npi[j-1] = 0;
+		      }
+		  }
+	      }
+
+	    if (npi[0])
+	      {
+		Element nel1(6), nel2(6);
+		for (j = 1; j <= 3; j++)
+		  {
+		    nel1.PNum(j) = el.PNum(j);
+		    nel1.PNum(j+3) = npi[j-1];
+		    nel2.PNum(j) = npi[j-1];
+		    nel2.PNum(j+3) = el.PNum(j+3);
+		  }
+		nel1.SetIndex (el.GetIndex());
+		nel2.SetIndex (el.GetIndex());
+		mesh.VolumeElement (i) = nel1;
+		mesh.AddVolumeElement (nel2);
+	      }
+	  }
+
+      
+	PrintMessage (5, "Elements done, NE = ", mesh.GetNE());
+
+
+	// do surface elements
+	int oldnse = mesh.GetNSE();
+	//      cout << "oldnse = " << oldnse << endl;
+	for (i = 1; i <= oldnse; i++)
+	  {
+	    Element2d & el = mesh.SurfaceElement (i);
+	    if (el.GetType() != QUAD)
+	      continue;
+
+	    int index = el.GetIndex();
+	    int npi[2];
+	    for (j = 1; j <= 2; j++)
+	      {
+		int pi1, pi2;
+
+		if (j == 1)
+		  {
+		    pi1 = el.PNum(1);
+		    pi2 = el.PNum(4);
+		  }
+		else
+		  {
+		    pi1 = el.PNum(2);
+		    pi2 = el.PNum(3);
+		  }
+
+		if (pi1 == pi2)
+		  npi[j-1] = pi1;
+		else
+		  {
+		    INDEX_2 edge(pi1, pi2);
+		    edge.Sort();
+		    if (refedges.Used (edge))
+		      npi[j-1] = refedges.Get(edge);
+		    else
+		      {
+			npi[j-1] = 0;
+		      }
+		  }
+	      }
+
+	    if (npi[0])
+	      {
+		Element2d nel1(QUAD), nel2(QUAD);
+		for (j = 1; j <= 4; j++)
+		  {
+		    nel1.PNum(j) = el.PNum(j);
+		    nel2.PNum(j) = el.PNum(j);
+		  }
+		nel1.PNum(3) = npi[1];
+		nel1.PNum(4) = npi[0];
+		nel2.PNum(1) = npi[0];
+		nel2.PNum(2) = npi[1];
+		/*
+		  for (j = 1; j <= 2; j++)
+		  {
+		  nel1.PNum(j) = el.PNum(j);
+		  nel1.PNum(j+2) = npi[j-1];
+		  nel2.PNum(j) = npi[j-1];
+		  nel2.PNum(j+2) = el.PNum(j+2);
+		  }
+		*/
+		nel1.SetIndex (el.GetIndex());
+		nel2.SetIndex (el.GetIndex());
+
+		mesh.SurfaceElement (i) = nel1;
+		mesh.AddSurfaceElement (nel2);
+
+		int si = mesh.GetFaceDescriptor (index).SurfNr();
+
+		Point<3> hp = mesh.Point(npi[0]);
+		geom->GetSurface(si)->Project (hp);
+		mesh.Point (npi[0]).SetPoint (hp);
+
+		hp = mesh.Point(npi[1]);
+		geom->GetSurface(si)->Project (hp);
+		mesh.Point (npi[1]).SetPoint (hp);
+
+		//	      geom->GetSurface(si)->Project (mesh.Point(npi[0]));
+		//	      geom->GetSurface(si)->Project (mesh.Point(npi[1]));
+	      }
+	  }
+
+	PrintMessage (5, "Surface elements done, NSE = ", mesh.GetNSE());
+
+      }
+  }
+
+
+
+  void ZRefinement (Mesh & mesh, const CSGeometry * geom,
+		    ZRefinementOptions & opt)
+  {
+    INDEX_2_HASHTABLE<int> singedges(mesh.GetNSeg());
+
+    SelectSingularEdges (mesh, *geom, singedges, opt);
+    MakePrismsSingEdge (mesh, singedges);
+    MakePrismsClosePoints (mesh);
+
+    RefinePrisms (mesh, geom, opt);
+  }
+
+
+
+  ZRefinementOptions :: ZRefinementOptions()
+  {
+    minref = 0;
+  }
+
+}
diff --git a/Netgen/libsrc/occ/Makefile b/Netgen/libsrc/occ/Makefile
new file mode 100644
index 0000000000..6fe1d8bc0d
--- /dev/null
+++ b/Netgen/libsrc/occ/Makefile
@@ -0,0 +1,11 @@
+#
+# Makefile for open cascade library
+#
+src =  occgeom.cpp occmeshsurf.cpp occgenmesh.cpp
+
+lib = occ
+libpath = libsrc/occ
+#
+#
+include ../makefile.inc
+
diff --git a/Netgen/libsrc/occ/occgenmesh.cpp b/Netgen/libsrc/occ/occgenmesh.cpp
new file mode 100644
index 0000000000..f7055eb027
--- /dev/null
+++ b/Netgen/libsrc/occ/occgenmesh.cpp
@@ -0,0 +1,666 @@
+#ifdef OCCGEOMETRY
+
+#include <mystdlib.h>
+#include <occgeom.hpp>
+#include <meshing.hpp>
+
+namespace netgen
+{
+
+#include "occmeshsurf.hpp"
+
+#define TCL_OK 0
+#define TCL_ERROR 1
+
+
+void DivideEdge (TopoDS_Edge & edge, ARRAY <MeshPoint> & ps, ARRAY<double> & params, Mesh & mesh)
+{
+  double s0, s1;
+  int j;
+  double maxh = mparam.maxh;
+  int nsubedges = 1;  
+  gp_Pnt pnt;
+  double svalue[1000];
+
+  GProp_GProps system;
+  BRepGProp::LinearProperties(edge, system);
+  double L = system.Mass();
+
+  Handle(Geom_Curve) c = BRep_Tool::Curve(edge, s0, s1);
+
+  double s = s0;
+  j = 0;
+  while (s < s1)
+    {
+      pnt = c->Value(s);
+      svalue[j] = s;
+      s += mesh.GetH(Point3d(pnt.X(), pnt.Y(), pnt.Z()))*(s1-s0)/L;
+      j++;
+      if (s < s1) nsubedges++;
+    }
+  svalue[j] = s;
+  double stretchfac = (s1-s0)/(s-s0);
+
+  if (nsubedges < mparam.segmentsperedge)
+    {
+      nsubedges = 1;
+      s = s0;
+      j = 0;
+      while (s < s1)
+	{
+	  pnt = c->Value(s);
+	  svalue[j] = s;
+	  s += min ((s1-s0)/mparam.segmentsperedge, mesh.GetH(Point3d(pnt.X(), pnt.Y(), pnt.Z()))*(s1-s0)/L);
+	  j++;
+	  if (s < s1) nsubedges++; 
+	}
+      svalue[j] = s;
+      stretchfac = (s1-s0)/(s-s0);
+    }
+
+  ps.SetSize (nsubedges-1);
+  params.SetSize (nsubedges+1);
+
+  for (j = 1; j < nsubedges; j++)
+    {
+      params[j] = s0+stretchfac*(svalue[j]-s0);
+      pnt = c->Value(params[j]);
+      ps[j-1] = MeshPoint (Point3d(pnt.X(), pnt.Y(), pnt.Z()));
+    } 
+
+  params[0] = s0;
+  params[nsubedges] = s1;
+}
+
+
+
+static void FindEdges (OCCGeometry & geom, Mesh & mesh)
+{
+  int i, j;
+  
+  TopExp_Explorer exp0, exp01, exp1, exp2, exp3;
+  
+  int nvertices = geom.vmap.Extent();
+  int nedges = geom.emap.Extent();
+  for (i = 1; i <= nvertices; i++)
+    {
+      gp_Pnt pnt = BRep_Tool::Pnt (TopoDS::Vertex(geom.vmap(i)));
+      MeshPoint mp( Point3d(pnt.X(), pnt.Y(), pnt.Z()) );
+      mesh.AddPoint (mp);
+    }
+  
+  int facenr = 0;
+  int edgenr = 0;
+  
+  for (exp0.Init(geom.shape, TopAbs_SOLID); exp0.More(); exp0.Next())
+    for (exp01.Init(exp0.Current(), TopAbs_SHELL); exp01.More(); exp01.Next())
+      {
+	TopoDS_Shape shell = exp01.Current();
+	
+	for (exp1.Init(shell, TopAbs_FACE); exp1.More(); exp1.Next())
+	  {
+	    TopoDS_Face face = TopoDS::Face(exp1.Current());
+
+	    facenr = geom.fmap.FindIndex (face);
+	    
+	    mesh.AddFaceDescriptor (FaceDescriptor(facenr, 1, 0, 0));
+	    Handle(Geom_Surface) occface = BRep_Tool::Surface(face);
+	    
+	    for (exp2.Init (face, TopAbs_WIRE); exp2.More(); exp2.Next())
+	      {
+		TopoDS_Shape wire = exp2.Current();
+
+		for (exp3.Init (wire, TopAbs_EDGE); exp3.More(); exp3.Next())
+		  {
+		    TopoDS_Edge edge = TopoDS::Edge (exp3.Current());
+		    if (BRep_Tool::Degenerated(edge)) continue;
+
+		    Handle(Geom2d_Curve) cof;
+		    double s0, s1;
+		    cof = BRep_Tool::CurveOnSurface (edge, face, s0, s1);
+		    
+		    int geomedgenr = geom.emap.FindIndex(edge);
+
+		    ARRAY <MeshPoint> mp;
+		    ARRAY <double> params;
+		    
+		    DivideEdge (edge, mp, params, mesh);
+		    
+		    ARRAY <int> pnums;
+		    pnums.SetSize (mp.Size()+2);
+		    
+		    pnums[0] = geom.vmap.FindIndex (TopExp::FirstVertex (edge));
+		    pnums[pnums.Size()-1] = geom.vmap.FindIndex (TopExp::LastVertex (edge));
+
+		    for (i = 1; i <= mp.Size(); i++)
+		      {
+			int exists = 0;
+			
+			for (j = 1; !exists && (j <= mesh.GetNP()-nvertices); j++)
+			  if ((mesh.Point(nvertices+j)-Point<3>(mp[i-1])).Length() < 1e-6) exists = 1;
+			if (exists)
+			  {
+			    pnums[i] = nvertices+j-1;
+			  }
+			else
+			  {
+			    mesh.AddPoint (mp[i-1]);
+			    pnums[i] = mesh.GetNP();
+			  }
+		      }
+		    
+		    for (i = 1; i <= mp.Size()+1; i++)
+		      {
+			edgenr++;
+			Segment seg;
+			
+			seg.p1 = pnums[i-1];
+			seg.p2 = pnums[i];
+			seg.edgenr = edgenr;
+			seg.si = facenr;
+			seg.epgeominfo[0].dist = params[i-1];
+			seg.epgeominfo[1].dist = params[i];
+			seg.epgeominfo[0].edgenr = geomedgenr;
+			seg.epgeominfo[1].edgenr = geomedgenr;
+			
+			gp_Pnt2d p2d;
+			p2d = cof->Value(params[i-1]);
+			seg.epgeominfo[0].u = p2d.X();
+			seg.epgeominfo[0].v = p2d.Y();
+			p2d = cof->Value(params[i]);
+			seg.epgeominfo[1].u = p2d.X();
+			seg.epgeominfo[1].v = p2d.Y();
+			
+			if (edge.Orientation() == TopAbs_REVERSED)
+			  {
+			    swap (seg.p1, seg.p2);
+			    swap (seg.epgeominfo[0].dist, seg.epgeominfo[1].dist);
+			    swap (seg.epgeominfo[0].u, seg.epgeominfo[1].u);
+			    swap (seg.epgeominfo[0].v, seg.epgeominfo[1].v);
+			  }
+			
+			
+			mesh.AddSegment (seg);
+			
+			// (*testout) << "seg" << seg.edgenr << ": " << seg.p1 << " - " << seg.p2 << endl;
+		      }
+		  }
+	      }
+	  }
+      }
+  mesh.CalcSurfacesOfNode();
+}  
+
+
+
+
+static void OCCMeshSurface (OCCGeometry & geom, Mesh & mesh, int perfstepsend)
+{
+  int i, j, k;
+  int changed;
+
+  char * savetask = multithread.task;
+  multithread.task = "Surface meshing";
+  
+  int noldp = mesh.GetNP();
+
+  double starttime = GetTime();
+
+  ARRAY<int> glob2loc(noldp);
+
+  for (k = 1; k <= mesh.GetNFD(); k++)
+    {
+
+      (*testout) << "mesh face " << k << endl;
+      multithread.percent = 100 * k / (mesh.GetNFD()+1e-10);
+
+      FaceDescriptor & fd = mesh.GetFaceDescriptor(k);
+
+      PrintMessage (2, "Surface ", k, " / ", mesh.GetNFD());
+
+      int oldnf = mesh.GetNSE();
+
+      
+      Box<3> bb (Point<3> (-geom.MaxSize(), -geom.MaxSize(), -geom.MaxSize()), 
+		 Point<3> (geom.MaxSize(), geom.MaxSize(), geom.MaxSize()));
+
+      Meshing2OCCSurfaces meshing(TopoDS::Face(geom.fmap(k)), bb); 
+      //      Meshing2OCCSurfaces meshing(f2, bb); 
+      meshing.SetStartTime (starttime);
+
+      /*
+      for (i = 1; i <= noldp; i++)
+	{
+	  // (*testout) << "Add point " << mesh.Point(i) << endl;
+	  meshing.AddPoint (mesh.Point(i), i);
+	}
+      */
+
+      int cntp = 0;
+      glob2loc = 0;
+      for (i = 1; i <= mesh.GetNSeg(); i++)
+	{
+	  Segment & seg = mesh.LineSegment(i);
+	  if (seg.si == k)
+	    {
+	      for (j = 1; j <= 2; j++)
+		{
+		  int pi = (j == 1) ? seg.p1 : seg.p2;
+		  if (!glob2loc.Get(pi))
+		    {
+		      meshing.AddPoint (mesh.Point(pi), pi);
+		      cntp++;
+		      glob2loc.Elem(pi) = cntp;
+		    }
+		}
+	    }
+	}
+
+      for (i = 1; i <= mesh.GetNSeg(); i++)
+	{
+	  Segment & seg = mesh.LineSegment(i);
+	  if (seg.si == k)
+	    {
+	      PointGeomInfo gi0, gi1;
+	      gi0.trignum = gi1.trignum = k;
+	      gi0.u = seg.epgeominfo[0].u;
+	      gi0.v = seg.epgeominfo[0].v;
+	      gi1.u = seg.epgeominfo[1].u;
+	      gi1.v = seg.epgeominfo[1].v;
+
+	      meshing.AddBoundaryElement (glob2loc.Get(seg.p1), glob2loc.Get(seg.p2), gi0, gi1);
+	      
+	      (*testout) << "Add BE " << seg.p1 << "-" << seg.p2 << " (" << ")" << endl;
+	    }
+	}
+
+      double maxh = mparam.maxh;
+
+      MESHING2_RESULT res =
+	meshing.GenerateMesh (mesh, maxh, k);
+
+      if (res != MESHING2_OK)
+	{
+	  PrintError ("Problem in Surface mesh generation");
+	  throw NgException ("Problem in Surface mesh generation");
+	}
+      
+      for (i = oldnf+1; i <= mesh.GetNSE(); i++)
+	mesh.SurfaceElement(i).SetIndex (k);
+
+    }
+
+  if (multithread.terminate || perfstepsend < MESHCONST_OPTSURFACE)
+    return;
+
+  multithread.task = "Optimizing surface";
+  
+  for (k = 1; k <= mesh.GetNFD(); k++)
+    {
+      (*testout) << "optimize face " << k << endl;
+      multithread.percent = 100 * k / (mesh.GetNFD()+1e-10);
+      
+      FaceDescriptor & fd = mesh.GetFaceDescriptor(k);
+      
+      PrintMessage (1, "Optimize Surface ", k);
+      for (i = 1; i <= mparam.optsteps2d; i++)
+	{
+	  if (multithread.terminate) return;
+	  
+	  {
+	    MeshOptimize2dOCCSurfaces meshopt(geom);
+	    meshopt.SetFaceIndex (k);
+	    meshopt.SetImproveEdges (0);
+	    meshopt.SetMetricWeight (0.2);
+	    meshopt.SetWriteStatus (0);
+	    
+	    meshopt.EdgeSwapping (mesh, (i > mparam.optsteps2d/2));
+	  }
+	  
+	  if (multithread.terminate) return;
+	  {
+	    MeshOptimize2dOCCSurfaces meshopt(geom);
+	    meshopt.SetFaceIndex (k);
+	    meshopt.SetImproveEdges (0);
+	    meshopt.SetMetricWeight (0.2);
+	    meshopt.SetWriteStatus (0);
+	    
+	    meshopt.ImproveMesh (mesh);
+	  }
+	  
+	  {
+	    MeshOptimize2dOCCSurfaces meshopt(geom);
+	    meshopt.SetFaceIndex (k);
+	    meshopt.SetImproveEdges (0);
+	    meshopt.SetMetricWeight (0.2);
+	    meshopt.SetWriteStatus (0);
+	    
+	    meshopt.CombineImprove (mesh);
+	  }
+	  
+	  if (multithread.terminate) return;
+	  {
+	    MeshOptimize2dOCCSurfaces meshopt(geom);
+	    meshopt.SetFaceIndex (k);
+	    meshopt.SetImproveEdges (0);
+	    meshopt.SetMetricWeight (0.2);
+	    meshopt.SetWriteStatus (0);
+	    
+	    meshopt.ImproveMesh (mesh);
+	  }
+	}
+      
+    }
+  
+  
+  mesh.CalcSurfacesOfNode();
+  mesh.Compress();
+
+  multithread.task = savetask;
+}
+
+double ComputeH (double kappa)
+{
+  double hret;
+  kappa *= mparam.curvaturesafety;
+  
+  if (mparam.maxh * kappa < 1)
+    hret = mparam.maxh;
+  else
+    hret = 1 / kappa;
+  
+  if (mparam.maxh < hret)
+    hret = mparam.maxh;
+
+  return (hret);
+}
+
+
+int OCCGenerateMesh (OCCGeometry & geom,
+		  Mesh *& mesh,
+		  int perfstepsstart, int perfstepsend,
+		  char * optstr)
+{
+  int i, j;
+
+  if (perfstepsstart <= MESHCONST_ANALYSE)
+    {
+      delete mesh;
+      mesh = new Mesh();
+
+      mesh->SetGlobalH (mparam.maxh);
+
+      ARRAY<double> maxhdom(1);
+      maxhdom[0] = mparam.maxh;
+      double maxsize = geom.MaxSize(); 
+      
+      mesh->SetMaxHDomain (maxhdom);
+      mesh->SetLocalH (Point<3>(-maxsize, -maxsize, -maxsize),
+		       Point<3>(maxsize, maxsize, maxsize),
+		       0.5);
+
+      if (mparam.uselocalh)
+	{
+
+	  char * savetask = multithread.task;
+	  multithread.task = "Setting local mesh size";
+  
+	  double maxsize = geom.MaxSize(); 
+	  mesh->SetLocalH (Point<3>(-maxsize, -maxsize, -maxsize),
+			   Point<3>(maxsize, maxsize, maxsize),
+			   mparam.grading);
+
+	  cout << "maxsize = " << maxsize << endl;
+	  
+	  int nfaces = geom.fmap.Extent();
+	  
+	  int i;
+	  for (i = 1; i <= nfaces; i++)
+	    {
+	      (*testout) << "face " << i << endl;
+	      multithread.percent = 100 * (i-1)/double(nfaces);
+	      TopoDS_Face face = TopoDS::Face(geom.fmap(i));
+	      TopLoc_Location loc;
+	      Handle(Geom_Surface) surf = BRep_Tool::Surface (face);
+	      Handle(Poly_Triangulation) triangulation = BRep_Tool::Triangulation (face, loc);
+	      BRepAdaptor_Surface sf(face, Standard_False);
+	      BRepLProp_SLProps prop(sf, 2, 1e-5);
+	      
+	      int ntriangles = triangulation -> NbTriangles();
+	      for (j = 1; j <= ntriangles; j++)
+		{
+		  int k;
+		  gp_Pnt p[3];
+		  gp_Pnt2d par[3];
+
+		  for (k = 1; k <=3; k++)
+		    {
+		      int n = triangulation->Triangles()(j)(k);
+		      p[k-1] = triangulation->Nodes()(n);
+		      par[k-1] = triangulation->UVNodes()(n);
+		    }
+
+		  double lp2p0 = p[2].Distance(p[0]);
+		  double lp2p1 = p[2].Distance(p[1]);
+
+		  prop.SetParameters (p[2].X(), p[2].Y());
+		  double h;
+
+		  if (!prop.IsCurvatureDefined()) continue;
+
+		  h = ComputeH (max(fabs(prop.MinCurvature()),
+				    fabs(prop.MaxCurvature()))+1e-10);
+		  
+		  double h0 = h/lp2p0;
+		  double h1 = h/lp2p1;
+
+		  h0 = min (h0, 1.0);
+		  h1 = min (h1, 1.0);
+
+		  double l0, l1, l2;
+		  for (l0 = 0; l0 <= 1; l0+=h0)
+		    for (l1 = 0; l1 <= 1-l0; l1+=h1)
+		      {
+			l2 = 1-l0-l1;
+			double u = l0*par[0].X() + l1*par[1].X() + l2*par[2].X();
+			double v = l0*par[0].Y() + l1*par[1].Y() + l2*par[2].Y();
+
+			prop.SetParameters (u, v);
+
+			if (!prop.IsCurvatureDefined()) continue;
+
+			gp_Pnt pnt = prop.Value();
+
+			mesh->RestrictLocalH (Point3d(pnt.X(), pnt.Y(), pnt.Z()),
+					      ComputeH (max(fabs(prop.MinCurvature()),
+							    fabs(prop.MaxCurvature()))+1e-10));
+		      }
+		  
+		}
+
+	      /*
+	      // schmale lange drei+viereckerl
+	      TopExp_Explorer exp;
+	      for (exp.Init (face, TopAbs_WIRE); exp.More(); exp.Next())
+		{
+		  bool done = 0;
+		  BRepTools_WireExplorer wexp;
+		  double L[4];
+		  GProp_GProps system;
+		  int i = 0;
+		  double minL = 1e10;
+
+		  for (wexp.Init (TopoDS::Wire(exp.Current())); wexp.More() && i < 4; wexp.Next())
+		    {
+		      BRepGProp::LinearProperties(wexp.Current(), system);
+		      L[i++] = system.Mass();
+		      minL = min (minL, L[i-1]);
+		    }
+
+		  if (i == 4 && wexp.More()) continue; // more that 4 edges
+
+		    
+		  double h = minL;
+
+		  for (j = 1; j <= ntriangles; j++)
+		    {
+		      int k;
+		      gp_Pnt p[3];
+		      gp_Pnt2d par[3];
+
+		      for (k = 1; k <=3; k++)
+			{
+			  int n = triangulation->Triangles()(j)(k);
+			  p[k-1] = triangulation->Nodes()(n);
+			  par[k-1] = triangulation->UVNodes()(n);
+			}
+
+		      double lp2p0 = p[2].Distance(p[0]);
+		      double lp2p1 = p[2].Distance(p[1]);
+
+		      prop.SetParameters (p[2].X(), p[2].Y());
+		  
+		      double h0 = h/lp2p0;
+		      double h1 = h/lp2p1;
+
+		      h0 = min (h0, 1.0);
+		      h1 = min (h1, 1.0);
+
+		      double l0, l1, l2;
+		      for (l0 = 0; l0 <= 1; l0+=h0)
+		      for (l1 = 0; l1 <= 1-l0; l1+=h1)
+		      {
+			l2 = 1-l0-l1;
+			double u = l0*par[0].X() + l1*par[1].X() + l2*par[2].X();
+			double v = l0*par[0].Y() + l1*par[1].Y() + l2*par[2].Y();
+
+			prop.SetParameters (u, v);
+			gp_Pnt pnt = prop.Value();
+
+			mesh->RestrictLocalH (Point3d(pnt.X(), pnt.Y(), pnt.Z()), h);
+		      }
+		      
+		    }
+		}
+	      */
+
+
+	    }
+	  
+	  multithread.task = savetask;
+	}
+    }
+
+
+  if (multithread.terminate || perfstepsend <= MESHCONST_ANALYSE) 
+    return TCL_OK;
+
+  if (perfstepsstart <= MESHCONST_MESHEDGES)
+    {
+      FindEdges (geom, *mesh);
+
+#ifdef LOG_STREAM      
+      (*logout) << "Edges meshed" << endl
+		<< "time = " << GetTime() << " sec" << endl
+		<< "points: " << mesh->GetNP() << endl;
+#endif
+    }
+
+   if (multithread.terminate || perfstepsend <= MESHCONST_MESHEDGES)
+    return TCL_OK;
+
+  if (perfstepsstart <= MESHCONST_MESHSURFACE)
+    {
+      OCCMeshSurface (geom, *mesh, perfstepsend);  
+      if (multithread.terminate) return TCL_OK;
+      
+#ifdef LOG_STREAM
+      (*logout) << "Surfaces meshed" << endl
+		<< "time = " << GetTime() << " sec" << endl
+		<< "points: " << mesh->GetNP() << endl;
+#endif      
+      
+#ifdef STAT_STREAM
+      (*statout) << mesh->GetNSeg() << " & "
+		 << mesh->GetNSE() << " & - &" 
+		 << GetTime() << " & " << endl;
+#endif  
+      
+      //      MeshQuality2d (*mesh);
+      mesh->CalcSurfacesOfNode();
+    }
+
+  if (multithread.terminate || perfstepsend <= MESHCONST_OPTSURFACE)
+    return TCL_OK;
+  
+
+  if (perfstepsstart <= MESHCONST_MESHVOLUME)
+    {
+      multithread.task = "Volume meshing";
+      
+      MESHING3_RESULT res =
+	MeshVolume (mparam, *mesh);
+
+      if (res != MESHING3_OK) return TCL_ERROR;
+      
+      if (multithread.terminate) return TCL_OK;
+      
+      RemoveIllegalElements (*mesh);
+      if (multithread.terminate) return TCL_OK;
+
+      MeshQuality3d (*mesh);
+      
+#ifdef STAT_STREAM
+      (*statout) << GetTime() << " & ";
+#endif      
+      
+#ifdef LOG_STREAM
+      (*logout) << "Volume meshed" << endl
+		<< "time = " << GetTime() << " sec" << endl
+	    << "points: " << mesh->GetNP() << endl;
+#endif
+    }
+
+  if (multithread.terminate || perfstepsend <= MESHCONST_MESHVOLUME)
+    return TCL_OK;
+
+
+  if (perfstepsstart <= MESHCONST_OPTVOLUME)
+    {
+      multithread.task = "Volume optimization";
+      
+      OptimizeVolume (mparam, *mesh, NULL);
+      if (multithread.terminate) return TCL_OK;
+      
+#ifdef STAT_STREAM
+      (*statout) << GetTime() << " & "
+		 << mesh->GetNE() << " & "
+		 << mesh->GetNP() << " " << '\\' << '\\' << " \\" << "hline" << endl;
+#endif      
+
+#ifdef LOG_STREAM      
+      (*logout) << "Volume optimized" << endl
+		<< "time = " << GetTime() << " sec" << endl
+	    << "points: " << mesh->GetNP() << endl;
+#endif
+
+     
+      cout << "Optimization complete" << endl;
+      
+    }
+
+  (*testout) << "NP: " << mesh->GetNP() << endl;
+  for (i = 1; i <= mesh->GetNP(); i++)
+      (*testout) << mesh->Point(i) << endl;
+ 
+  (*testout) << endl << "NSegments: " << mesh->GetNSeg() << endl;
+  for (i = 1; i <= mesh->GetNSeg(); i++)
+    (*testout) << mesh->LineSegment(i) << endl;
+   
+
+
+  return TCL_OK;
+}
+}
+
+#endif
diff --git a/Netgen/libsrc/occ/occgeom.cpp b/Netgen/libsrc/occ/occgeom.cpp
new file mode 100644
index 0000000000..bc50d82975
--- /dev/null
+++ b/Netgen/libsrc/occ/occgeom.cpp
@@ -0,0 +1,106 @@
+#ifdef OCCGEOMETRY
+
+#include <mystdlib.h>
+#include <occgeom.hpp>  
+
+
+namespace netgen
+{
+
+void PrintContents (OCCGeometry * geom)
+{
+  TopExp_Explorer exp0;
+  int cnt;
+
+  (*testout) << "OCC CONTENTS" << endl
+	     << "============" << endl;
+
+  for (cnt = 0, exp0.Init(geom->shape, TopAbs_COMPOUND); exp0.More(); exp0.Next()) cnt++;
+  (*testout) << "COMPOUND : " << cnt << endl;
+
+  for (cnt = 0, exp0.Init(geom->shape, TopAbs_COMPSOLID); exp0.More(); exp0.Next()) cnt++;
+  (*testout) << "COMPSOLID: " << cnt << endl;
+
+  for (cnt = 0, exp0.Init(geom->shape, TopAbs_SOLID); exp0.More(); exp0.Next()) cnt++;
+  (*testout) << "SOLID    : " << cnt << endl;
+
+  for (cnt = 0, exp0.Init(geom->shape, TopAbs_SHELL); exp0.More(); exp0.Next()) cnt++;
+  (*testout) << "SHELL    : " << cnt << endl;
+
+  for (cnt = 0, exp0.Init(geom->shape, TopAbs_FACE); exp0.More(); exp0.Next()) cnt++;
+  (*testout) << "FACE     : " << cnt << endl;
+
+  for (cnt = 0, exp0.Init(geom->shape, TopAbs_WIRE); exp0.More(); exp0.Next()) cnt++;
+  (*testout) << "WIRE     : " << cnt << endl;
+
+  for (cnt = 0, exp0.Init(geom->shape, TopAbs_EDGE); exp0.More(); exp0.Next()) cnt++;
+  (*testout) << "EDGE     : " << cnt << endl;
+
+  for (cnt = 0, exp0.Init(geom->shape, TopAbs_VERTEX); exp0.More(); exp0.Next()) cnt++;
+  (*testout) << "VERTEX   : " << cnt << endl;
+}
+
+
+void HealGeometry (OCCGeometry * geom)
+{
+  TopExp_Explorer exp0;
+  int cnt;
+
+
+  for (cnt = 0, exp0.Init(geom->shape, TopAbs_SOLID); exp0.More(); exp0.Next()) cnt++;
+  if (cnt == 0)
+    {
+      cout << "OCC: Geometry file invalid! No solids. Generating one common solid" << endl;
+
+      BRepOffsetAPI_Sewing sewedObj;
+      for (exp0.Init(geom->shape, TopAbs_FACE); exp0.More(); exp0.Next())
+	sewedObj.Add (TopoDS::Face(exp0.Current()));
+      sewedObj.Perform();
+
+      BRepBuilderAPI_MakeSolid ms;
+      for (exp0.Init(sewedObj.SewedShape(), TopAbs_SHELL); exp0.More(); exp0.Next())
+	ms.Add (TopoDS::Shell(exp0.Current()));
+
+      geom->shape = ms;
+    }
+}
+
+
+OCCGeometry * LoadOCC_IGES (const char * filename)
+{
+  OCCGeometry * occgeo;
+  occgeo = new OCCGeometry;
+  
+  IGESControl_Reader reader;
+  Standard_Integer stat = reader.LoadFile((char*)filename);
+  reader.TransferRoots (Standard_False); // Tranlate IGES -> OCC
+  occgeo->shape = reader.OneShape();
+  occgeo->changed = 1;
+  PrintContents (occgeo);
+  HealGeometry (occgeo);
+  occgeo->BuildFMap();
+  return occgeo;
+}
+
+OCCGeometry * LoadOCC_STEP (const char * filename)
+{
+  OCCGeometry * occgeo;
+  occgeo = new OCCGeometry;
+  
+  STEPControl_Reader reader;
+  Standard_Integer stat = reader.ReadFile((char*)filename);
+  Standard_Integer nb = reader.NbRootsForTransfer();
+  reader.TransferRoots (); // Tranlate STEP -> OCC
+  occgeo->shape = reader.OneShape();
+  occgeo->changed = 1;
+  PrintContents (occgeo);
+  HealGeometry (occgeo);
+  occgeo->BuildFMap();
+  return occgeo;
+}
+
+
+}
+
+
+#endif
diff --git a/Netgen/libsrc/occ/occgeom.hpp b/Netgen/libsrc/occ/occgeom.hpp
new file mode 100644
index 0000000000..99472e71ff
--- /dev/null
+++ b/Netgen/libsrc/occ/occgeom.hpp
@@ -0,0 +1,181 @@
+#ifndef FILE_OCCGEOM
+#define FILE_OCCGEOM
+
+/* *************************************************************************/
+/* File:   occgeom.hpp                                                     */
+/* Author: Robert Gaisbauer                                                */
+/* Date:   26. May  03                                                     */
+/* *************************************************************************/
+
+#ifdef OCCGEOMETRY
+
+#include <meshing.hpp>
+
+#include "BRep_Tool.hxx"
+#include "Geom_Curve.hxx"
+#include "Geom2d_Curve.hxx"
+#include "Geom_Surface.hxx"
+#include "GeomAPI_ProjectPointOnSurf.hxx"
+#include "GeomAPI_ProjectPointOnCurve.hxx"
+#include "BRepTools.hxx"
+#include "TopExp.hxx"
+#include "BRepBuilderAPI_MakeVertex.hxx"
+#include "BRepBuilderAPI_MakeShell.hxx"
+#include "BRepBuilderAPI_MakeSolid.hxx"
+#include "BRepOffsetAPI_Sewing.hxx"
+#include "BRepLProp_SLProps.hxx"
+#include "BRepAdaptor_Surface.hxx"
+#include "Poly_Triangulation.hxx"
+#include "Poly_Array1OfTriangle.hxx"
+#include "TColgp_Array1OfPnt2d.hxx"
+#include "Poly_Triangle.hxx"
+#include "GProp_GProps.hxx"
+#include "BRepGProp.hxx"
+#include "Geom_Surface.hxx"
+#include "TopExp.hxx"
+#include "gp_Pnt.hxx"
+#include "TopoDS.hxx"
+#include "TopExp_Explorer.hxx"
+#include "BRep_Tool.hxx"
+#include "Geom_Curve.hxx"
+#include "Geom2d_Curve.hxx"
+#include "Geom_Surface.hxx"
+#include "GeomAPI_ProjectPointOnSurf.hxx"
+#include "GeomAPI_ProjectPointOnCurve.hxx"
+#include "TopoDS_Wire.hxx"
+#include "BRepTools_WireExplorer.hxx"
+#include "BRepTools.hxx"
+#include "TopTools_IndexedMapOfShape.hxx"
+#include "TopExp.hxx"
+#include "BRepBuilderAPI_MakeVertex.hxx"
+#include "BRepBuilderAPI_MakeShell.hxx"
+#include "BRepBuilderAPI_MakeSolid.hxx"
+#include "BRepOffsetAPI_Sewing.hxx"
+#include "BRepLProp_SLProps.hxx"
+#include "BRepAdaptor_Surface.hxx"
+#include "Poly_Triangulation.hxx"
+#include "Poly_Array1OfTriangle.hxx"
+#include "TColgp_Array1OfPnt2d.hxx"
+#include "Poly_Triangle.hxx"
+#include "GProp_GProps.hxx"
+#include "BRepGProp.hxx"
+#include "IGESControl_Reader.hxx"
+#include "STEPControl_Reader.hxx"
+#include "TopoDS_Shape.hxx"
+#include "TopoDS_Face.hxx"
+
+
+
+namespace netgen
+{
+
+#include "occmeshsurf.hpp"
+
+
+class OCCGeometry
+{
+public:
+  TopoDS_Shape shape;
+  TopTools_IndexedMapOfShape fmap, emap, vmap;
+  double maxsize;
+
+  bool changed;
+
+
+  OCCGeometry()
+  {
+    fmap.Clear();
+    emap.Clear();
+    vmap.Clear();
+  }
+
+
+  void BuildFMap()
+  {
+    TopExp_Explorer exp0, exp1, exp2, exp3;
+    maxsize = 0;
+
+    /*    
+    for (exp3.Init(shape, TopAbs_EDGE); exp3.More(); exp3.Next())
+      {
+	TopoDS_Edge edge = TopoDS::Edge(exp3.Current());
+	(*testout) << edge.Orientation() << endl;
+	if (emap.FindIndex(edge) < 1)
+	  emap.Add (edge);
+      }
+    */
+   
+
+    for (exp0.Init(shape, TopAbs_SOLID); exp0.More(); exp0.Next())
+      for (exp1.Init(exp0.Current(), TopAbs_SHELL); exp1.More(); exp1.Next())
+	{
+	  TopoDS_Shape shell = exp1.Current().Composed (exp0.Current().Orientation());
+
+	  for (exp2.Init(shell, TopAbs_FACE); exp2.More(); exp2.Next())
+	    {
+	      fmap.Add (exp2.Current().Composed(shell.Orientation()));
+	      
+	      for (exp3.Init(exp2.Current(), TopAbs_EDGE); exp3.More(); exp3.Next())
+		{
+		  TopoDS_Edge edge = TopoDS::Edge(exp3.Current());
+		  if (emap.FindIndex(edge) < 1)
+		    emap.Add (edge);
+		  /*
+		  else
+		    {
+		      cout << edge.Orientation() << " = " << emap(emap.FindIndex(edge)).Orientation() << endl;
+		    }
+		  */
+		}
+	      
+	      for (exp3.Init(exp2.Current(), TopAbs_VERTEX); exp3.More(); exp3.Next())
+		{
+		  TopoDS_Vertex vertex = TopoDS::Vertex(exp3.Current());
+		  if (vmap.FindIndex(vertex) < 1)
+		    {
+		      vmap.Add (vertex);
+		      
+		      gp_Pnt p = BRep_Tool::Pnt(vertex);
+		      maxsize = max (maxsize, fabs(p.X()));
+		      maxsize = max (maxsize, fabs(p.Y()));
+		      maxsize = max (maxsize, fabs(p.Y()));
+		    }
+		}
+	    }
+	}
+    maxsize *= 2;
+  }
+
+
+  double MaxSize()
+  {
+    return maxsize;
+  }
+
+
+
+  void Project (int surfi, Point<3> & p) const
+  {
+    static int cnt = 0;
+    if (cnt++ % 1000 == 0) cout << "Project cnt = " << cnt << endl;
+
+    gp_Pnt pnt(p(0), p(1), p(2));
+
+    GeomAPI_ProjectPointOnSurf proj(pnt, BRep_Tool::Surface(TopoDS::Face(fmap(surfi))));
+    pnt = proj.NearestPoint();
+    p = Point<3> (pnt.X(), pnt.Y(), pnt.Z());
+  }
+
+};
+
+
+void PrintContents (OCCGeometry * geom);
+void HealGeometry (OCCGeometry * geom);
+OCCGeometry * LoadOCC_IGES (const char * filename);
+OCCGeometry * LoadOCC_STEP (const char * filename);
+
+}
+
+#endif
+
+#endif
diff --git a/Netgen/libsrc/occ/occmeshsurf.cpp b/Netgen/libsrc/occ/occmeshsurf.cpp
new file mode 100644
index 0000000000..c8be2c0770
--- /dev/null
+++ b/Netgen/libsrc/occ/occmeshsurf.cpp
@@ -0,0 +1,387 @@
+#ifdef OCCGEOMETRY
+
+#include <mystdlib.h>
+
+#include <occgeom.hpp>
+#include <meshing.hpp>
+
+
+namespace netgen
+{
+#include "occmeshsurf.hpp"
+
+void OCCSurface :: GetNormalVector (const Point<3> & p, 
+				    const PointGeomInfo & geominfo,
+				    Vec<3> & n) const
+{
+  gp_Pnt pnt;
+  gp_Vec du, dv;
+  occface->D1(geominfo.u,geominfo.v,pnt,du,dv);
+
+  n = Cross (Vec<3>(du.X(), du.Y(), du.Z()),
+	     Vec<3>(dv.X(), dv.Y(), dv.Z()));
+  n.Normalize();
+
+  if (orient == TopAbs_REVERSED) n = -1*n;
+}
+
+
+void OCCSurface :: DefineTangentialPlane (const Point<3> & ap1,
+					  const PointGeomInfo & geominfo1,
+					  const Point<3> & ap2,
+					  const PointGeomInfo & geominfo2)
+{
+  p1 = ap1; p2 = ap2;
+  
+  GetNormalVector (p1, geominfo1, ez);
+
+  ex = p2 - p1;
+  ex -= (ex * ez) * ez;
+  ex.Normalize();
+  ey = Cross (ez, ex); 
+
+  /*
+  double u, v;
+  gp_Vec du, dv;
+  gp_Pnt pnt(ap2(0), ap2(1), ap2(2));
+  GeomAPI_ProjectPointOnSurf proj(pnt, occface);
+  proj.LowerDistanceParameters (u, v);
+  occface->D1(u, v, pnt, du, dv);
+  n2 = Cross (Vec<3>(du.X(), du.Y(), du.Z()),
+	      Vec<3>(dv.X(), dv.Y(), dv.Z()));
+  n2.Normalize();
+  if (orient == TopAbs_REVERSED) n2 = -1*n2;
+  */
+
+  GetNormalVector (p2, geominfo2, n2);
+ 
+  nmid = 0.5*(n2+ez);
+
+  ez = nmid;
+  ez.Normalize(); 
+
+  ex = (p2 - p1).Normalize();
+  ez -= (ez * ex) * ex;
+  ez.Normalize();
+  ey = Cross (ez, ex);
+  nmid = ez;
+ 
+}
+
+
+void OCCSurface :: ToPlane (const Point<3> & p3d,
+			    const PointGeomInfo & geominfo,
+			    Point<2> & pplane, 
+			    double h, int & zone) const
+{
+  Vec<3> p1p, n;
+  GetNormalVector (p3d, geominfo, n);
+
+  p1p = p3d - p1;
+  pplane(0) = (p1p * ex) / h;
+  pplane(1) = (p1p * ey) / h;
+
+  if (n * nmid < 0)
+    zone = -1;
+  else
+    zone = 0;
+  
+  /*
+  Vec<3> v = p3d - p1;
+  Vec<3> n;
+  GetNormalVector (p3d, geominfo, n);
+
+  if (n * nmid < 0)
+    zone = -1;
+  else
+    {
+      double nom = h*(n(0)*(ex(1)*ey(2)-ex(2)*ey(1)) + 
+		      n(1)*(ex(2)*ey(0)-ex(0)*ey(2)) +
+		      n(2)*(ex(0)*ey(1)-ex(1)*ey(0)));
+
+      pplane(0) = (n(0)*(ey(2)*v(1)-ey(1)*v(2)) +
+		   n(1)*(ey(0)*v(2)-ey(2)*v(0)) +
+		   n(2)*(ey(1)*v(0)-ey(0)*v(1)))/nom;
+
+      pplane(1) = (n(0)*(ex(1)*v(2)-ex(2)*v(1)) +
+		   n(1)*(ex(2)*v(0)-ex(0)*v(2)) +
+		   n(2)*(ex(0)*v(1)-ex(1)*v(0)))/nom;
+      
+      zone = 0;
+    }
+  */
+}	
+
+
+void OCCSurface :: FromPlane (const Point<2> & pplane, 
+			      Point<3> & p3d,
+			      PointGeomInfo & gi,
+			      double h) 
+{ 
+  p3d = p1 + (h * pplane(0)) * ex + (h * pplane(1)) * ey;
+  Project (p3d, gi);  
+}
+
+
+
+void OCCSurface :: Project (Point<3> & p, PointGeomInfo & gi)
+{
+  //   static int cnt = 0;
+  //  if (cnt++ % 1000 == 0) cout << "********************************************** OCCSurfce :: Project, cnt = " << cnt << endl;
+  
+  gp_Pnt pnt(p(0), p(1), p(2));
+  GeomAPI_ProjectPointOnSurf proj(pnt, occface);
+
+  pnt = proj.NearestPoint();
+  proj.LowerDistanceParameters (gi.u, gi.v);
+  gi.trignum = 1;
+
+  p = Point<3> (pnt.X(), pnt.Y(), pnt.Z());
+}
+
+
+Meshing2OCCSurfaces :: Meshing2OCCSurfaces (const TopoDS_Shape & asurf,
+					    const Box<3> & abb)
+  : Meshing2(Box3d(abb.PMin(), abb.PMax())), surface(TopoDS::Face(asurf))
+{
+  ;
+}
+
+
+void Meshing2OCCSurfaces :: DefineTransformation (Point3d & p1, Point3d & p2,
+						  const PointGeomInfo * geominfo1,
+						  const PointGeomInfo * geominfo2)
+{
+  ((OCCSurface&)surface).DefineTangentialPlane (p1, *geominfo1, p2, *geominfo2);
+}
+
+void Meshing2OCCSurfaces :: TransformToPlain (const Point3d & locpoint, 
+					   const MultiPointGeomInfo & geominfo,
+					   Point2d & planepoint, 
+					   double h, int & zone)
+{
+  Point<2> hp;
+  surface.ToPlane (locpoint, geominfo.GetPGI(1), hp, h, zone);
+  planepoint.X() = hp(0);
+  planepoint.Y() = hp(1);
+}
+
+int Meshing2OCCSurfaces :: TransformFromPlain (Point2d & planepoint,
+					       Point3d & locpoint,
+					       PointGeomInfo & gi,
+					       double h)
+{
+  Point<3> hp;
+  Point<2> hp2 (planepoint.X(), planepoint.Y());
+  surface.FromPlane (hp2, hp, gi, h);
+  locpoint = hp;
+  return 0;
+}
+
+
+
+double Meshing2OCCSurfaces :: CalcLocalH (const Point3d & p, double gh) const
+{
+  return gh;
+}
+
+
+
+
+
+
+MeshOptimize2dOCCSurfaces :: MeshOptimize2dOCCSurfaces (const OCCGeometry & ageometry)
+  : MeshOptimize2d(), geometry(ageometry)
+{
+  ;
+}
+
+
+void MeshOptimize2dOCCSurfaces :: ProjectPoint (INDEX surfind, Point3d & p) const
+{
+  Point<3> hp = p;
+  geometry.Project (surfind, hp);
+  p = hp;
+}
+
+void MeshOptimize2dOCCSurfaces :: ProjectPoint2 (INDEX surfind, INDEX surfind2, 
+					      Point3d & p) const
+{
+  TopExp_Explorer exp0, exp1;
+  int done = 0;
+  Handle(Geom_Curve) c;
+
+  for (exp0.Init(geometry.fmap(surfind), TopAbs_EDGE); !done && exp0.More(); exp0.Next())
+    for (exp1.Init(geometry.fmap(surfind2), TopAbs_EDGE); !done && exp1.More(); exp1.Next())
+      {
+	if (TopoDS::Edge(exp0.Current()).IsSame(TopoDS::Edge(exp1.Current())))
+	  {
+	    done = 1;
+	    double s0, s1;
+	    c = BRep_Tool::Curve(TopoDS::Edge(exp0.Current()), s0, s1);
+	  }
+      }
+  
+  gp_Pnt pnt(p.X(), p.Y(), p.Z());
+  GeomAPI_ProjectPointOnCurve proj(pnt, c);
+  pnt = proj.NearestPoint();  
+  p.X() = pnt.X();
+  p.Y() = pnt.Y();
+  p.Z() = pnt.Z();
+	
+}
+
+void MeshOptimize2dOCCSurfaces :: 
+GetNormalVector(INDEX surfind, const Point3d & p, PointGeomInfo & geominfo, Vec3d & n) const
+{
+  gp_Pnt pnt;
+  gp_Vec du, dv;
+
+  Handle(Geom_Surface) occface;
+  occface = BRep_Tool::Surface(TopoDS::Face(geometry.fmap(surfind)));
+
+  occface->D1(geominfo.u,geominfo.v,pnt,du,dv);
+
+  n = Cross (Vec<3>(du.X(), du.Y(), du.Z()),
+	     Vec<3>(dv.X(), dv.Y(), dv.Z()));
+  n.Normalize();
+
+  if (geometry.fmap(surfind).Orientation() == TopAbs_REVERSED) n = -1*n;  
+  
+  //  GetNormalVector (surfind, p, n);
+}
+
+
+void MeshOptimize2dOCCSurfaces :: 
+GetNormalVector(INDEX surfind, const Point3d & p, Vec3d & n) const
+{
+  //  static int cnt = 0;
+  //  if (cnt++ % 1000 == 0) cout << "GetNV cnt = " << cnt << endl;
+  Standard_Real u,v;
+
+  gp_Pnt pnt(p.X(), p.Y(), p.Z());
+
+  Handle(Geom_Surface) occface;
+  occface = BRep_Tool::Surface(TopoDS::Face(geometry.fmap(surfind)));
+
+  GeomAPI_ProjectPointOnSurf proj(pnt, occface);
+
+  if (proj.NbPoints() < 1)
+    {
+      cout << "ERROR: OCCSurface :: GetNormalVector: GeomAPI_ProjectPointOnSurf failed!"
+	   << endl;
+      cout << p << endl;
+      return;
+    }
+ 
+  proj.LowerDistanceParameters (u, v);
+
+  gp_Vec du, dv;
+  occface->D1(u,v,pnt,du,dv);
+
+  /*
+  if (!occface->IsCNu (1) || !occface->IsCNv (1))
+    (*testout) << "SurfOpt: Differentiation FAIL" << endl;
+  */
+
+  n = Cross (Vec3d(du.X(), du.Y(), du.Z()),
+	     Vec3d(dv.X(), dv.Y(), dv.Z()));
+  n.Normalize();
+
+  if (geometry.fmap(surfind).Orientation() == TopAbs_REVERSED) n = -1*n;  
+}
+
+
+int MeshOptimize2dOCCSurfaces :: 
+CalcPointGeomInfo(int surfind, PointGeomInfo& gi, const Point3d& p) const
+{
+  Standard_Real u,v;
+
+  gp_Pnt pnt(p.X(), p.Y(), p.Z());
+
+  Handle(Geom_Surface) occface;
+  occface = BRep_Tool::Surface(TopoDS::Face(geometry.fmap(surfind)));
+
+  GeomAPI_ProjectPointOnSurf proj(pnt, occface);
+
+  if (proj.NbPoints() < 1)
+    {
+      cout << "ERROR: OCCSurface :: GetNormalVector: GeomAPI_ProjectPointOnSurf failed!"
+	   << endl;
+      cout << p << endl;
+      return 0;
+    }
+ 
+  proj.LowerDistanceParameters (u, v);  
+
+  gi.u = u;
+  gi.v = v;
+  return 1;
+}
+
+
+
+
+
+
+OCCRefinementSurfaces :: OCCRefinementSurfaces (const OCCGeometry & ageometry)
+  : Refinement(), geometry(ageometry)
+{
+  ;
+}
+
+OCCRefinementSurfaces :: ~OCCRefinementSurfaces ()
+{
+  ;
+}
+  
+void OCCRefinementSurfaces :: 
+PointBetween (const Point3d & p1, const Point3d & p2, double secpoint,
+	      int surfi, 
+	      const PointGeomInfo & gi1, 
+	      const PointGeomInfo & gi2,
+	      Point3d & newp, PointGeomInfo & newgi)
+{
+  Point<3> hnewp;
+  hnewp = p1+secpoint*(p2-p1);
+
+  if (surfi > 0)
+    {
+      geometry.Project (surfi, hnewp);
+      newgi.trignum = 1;
+    }
+  
+  newp = hnewp;
+}
+
+
+void OCCRefinementSurfaces :: 
+PointBetween (const Point3d & p1, const Point3d & p2, double secpoint,
+ 	      int surfi1, int surfi2, 
+	      const EdgePointGeomInfo & ap1, 
+	      const EdgePointGeomInfo & ap2,
+	      Point3d & newp, EdgePointGeomInfo & newgi)
+{
+  double s0, s1;
+
+  Point<3> hnewp = p1+secpoint*(p2-p1);
+  gp_Pnt pnt(hnewp(0), hnewp(1), hnewp(2));
+  GeomAPI_ProjectPointOnCurve proj(pnt, BRep_Tool::Curve(TopoDS::Edge(geometry.emap(ap1.edgenr)), s0, s1));
+  pnt = proj.NearestPoint();
+  hnewp = Point<3> (pnt.X(), pnt.Y(), pnt.Z());
+  newp = hnewp;
+};
+
+
+void OCCRefinementSurfaces :: ProjectToSurface (Point<3> & p, int surfi)
+{
+  if (surfi > 0)
+    geometry.Project (surfi, p);
+};
+
+
+
+}
+
+
+#endif
diff --git a/Netgen/libsrc/occ/occmeshsurf.hpp b/Netgen/libsrc/occ/occmeshsurf.hpp
new file mode 100644
index 0000000000..aa0399ac23
--- /dev/null
+++ b/Netgen/libsrc/occ/occmeshsurf.hpp
@@ -0,0 +1,175 @@
+#ifdef OCCGEOMETRY
+
+#ifndef FILE_OCCMESHSURF
+#define FILE_OCCMESHSURF
+
+#include "occgeom.hpp"
+
+class OCCGeometry;
+
+class OCCSurface
+{
+public:
+  TopoDS_Face topods_face;
+  Handle(Geom_Surface) occface;
+  TopAbs_Orientation orient;
+
+protected:
+  Point<3> p1;
+  Point<3> p2;
+
+  /// in plane, directed p1->p2
+  Vec<3> ex;
+  /// in plane
+  Vec<3> ey;
+  /// outer normal direction
+  Vec<3> ez;
+
+  /// normal vector in p2
+  Vec<3> n2;
+
+  /// average normal vector
+  Vec<3> nmid;
+
+  // for transformation to parameter space
+  Point<2> psp1;
+  Point<2> psp2;
+  Vec<2> psex;
+  Vec<2> psey;
+  Mat<2,2> Amat, Amatinv;
+
+public:
+  OCCSurface (const TopoDS_Face & aface)
+  {
+    topods_face = aface;
+    occface = BRep_Tool::Surface(topods_face);
+    orient = topods_face.Orientation();
+    /*
+    TopExp_Explorer exp1;
+    exp1.Init (topods_face, TopAbs_WIRE);
+    orient = TopAbs::Compose (orient, exp1.Current().Orientation());
+    */
+  };
+  
+  ~OCCSurface()
+  {};
+
+  void Project (Point<3> & p, PointGeomInfo & gi);
+
+  void GetNormalVector (const Point<3> & p,
+			const PointGeomInfo & geominfo,
+			Vec<3> & n) const;
+
+  /**
+    Defines tangential plane in ap1.
+    The local x-coordinate axis point to the direction of ap2 */
+  void DefineTangentialPlane (const Point<3> & ap1, 
+			      const PointGeomInfo & geominfo1,
+			      const Point<3> & ap2,
+			      const PointGeomInfo & geominfo2);
+
+
+  /// Transforms 3d point p3d to local coordinates pplane
+  void ToPlane (const Point<3> & p3d, const PointGeomInfo & geominfo,
+		Point<2> & pplane, double h, int & zone) const;
+  
+  /// Transforms point pplane in local coordinates to 3d point
+  void FromPlane (const Point<2> & pplane, 
+		  Point<3> & p3d,
+		  PointGeomInfo & gi,
+		  double h);
+};
+
+
+
+///
+class Meshing2OCCSurfaces : public Meshing2
+{
+  ///
+  OCCSurface surface;
+   
+public:
+  ///
+  Meshing2OCCSurfaces (const TopoDS_Shape & asurf, const Box<3> & aboundingbox);
+
+protected:
+  ///
+  virtual void DefineTransformation (Point3d & p1, Point3d & p2,
+				     const PointGeomInfo * geominfo1,
+				     const PointGeomInfo * geominfo2);
+  ///
+  virtual void TransformToPlain (const Point3d & locpoint, 
+				 const MultiPointGeomInfo & geominfo,
+				 Point2d & plainpoint, 
+				 double h, int & zone);
+  ///
+  virtual int TransformFromPlain (Point2d & plainpoint,
+				  Point3d & locpoint,
+				  PointGeomInfo & gi,
+				  double h);
+  ///
+  virtual double CalcLocalH (const Point3d & p, double gh) const;
+  
+};
+
+
+
+///
+class MeshOptimize2dOCCSurfaces : public MeshOptimize2d
+  {
+  ///
+  const OCCGeometry & geometry;
+
+public:
+    ///
+    MeshOptimize2dOCCSurfaces (const OCCGeometry & ageometry); 
+   
+    ///
+    virtual void ProjectPoint (INDEX surfind, Point3d & p) const;
+    ///
+    virtual void ProjectPoint2 (INDEX surfind, INDEX surfind2, Point3d & p) const;
+    ///
+    virtual void GetNormalVector(INDEX surfind, const Point3d & p, Vec3d & n) const;
+    ///
+    virtual void GetNormalVector(INDEX surfind, const Point3d & p, PointGeomInfo & gi, Vec3d & n) const;
+
+    
+  virtual int CalcPointGeomInfo(int surfind, PointGeomInfo& gi, const Point3d& p3) const;
+
+};
+
+
+
+class OCCGeometry;
+
+
+class OCCRefinementSurfaces : public Refinement
+{
+  const OCCGeometry & geometry;
+
+public:
+  OCCRefinementSurfaces (const OCCGeometry & ageometry);
+  virtual ~OCCRefinementSurfaces ();
+  
+  virtual void PointBetween (const Point3d & p1, const Point3d & p2, double secpoint,
+			     int surfi, 
+			     const PointGeomInfo & gi1, 
+			     const PointGeomInfo & gi2,
+			     Point3d & newp, PointGeomInfo & newgi);
+
+  virtual void PointBetween (const Point3d & p1, const Point3d & p2, double secpoint,
+			     int surfi1, int surfi2, 
+			     const EdgePointGeomInfo & ap1, 
+			     const EdgePointGeomInfo & ap2,
+			     Point3d & newp, EdgePointGeomInfo & newgi);
+
+  virtual void ProjectToSurface (Point<3> & p, int surfi);
+};
+
+
+
+#endif
+
+
+
+#endif
diff --git a/Netgen/libsrc/opti/Makefile b/Netgen/libsrc/opti/Makefile
new file mode 100644
index 0000000000..d73441553f
--- /dev/null
+++ b/Netgen/libsrc/opti/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for optimisation library
+#
+src = bfgs.cpp linsearch.cpp linopt.cpp 
+#
+lib = opti
+libpath = libsrc/opti
+#
+#
+include ../makefile.inc
diff --git a/Netgen/libsrc/opti/bfgs.cpp b/Netgen/libsrc/opti/bfgs.cpp
new file mode 100644
index 0000000000..31a499a64d
--- /dev/null
+++ b/Netgen/libsrc/opti/bfgs.cpp
@@ -0,0 +1,367 @@
+/***************************************************************************/
+/*                                                                         */
+/* Vorlesung Optimierung I, Gfrerer, WS94/95                               */
+/* BFGS-Verfahren zur Lösung freier nichtlinearer Optimierungsprobleme     */
+/*                                                                         */
+/* Programmautor:  Joachim Schöberl                                        */
+/* Matrikelnummer: 9155284                                                 */
+/*                                                                         */
+/***************************************************************************/
+
+#include <mystdlib.h>
+#include <myadt.hpp> 
+
+#include <linalg.hpp>
+#include "opti.hpp"
+
+
+namespace netgen
+{
+
+void Cholesky (const DenseMatrix & a,
+	       DenseMatrix & l, Vector & d)
+{
+  // Factors   A = L D L^T
+
+  double x;
+
+  int i, j, k;
+  int n = a.Height();
+  
+  //  (*testout) << "a = " << a << endl;
+
+  l = a;
+
+  for (i = 1; i <= n; i++)
+    {
+      for (j = i; j <= n; j++)
+	{
+	  x = l.Get(i, j);
+
+	  for (k = 1; k < i; k++)
+	    x -= l.Get(i, k) * l.Get(j, k) * d.Get(k); 
+	  
+	  if (i == j)
+	    {
+	      d.Elem(i) = x;
+	    }
+	  else
+	    {
+	      l.Elem(j, i) = x / d.Get(k);
+	    }
+	}
+    }
+
+  for (i = 1; i <= n; i++)
+    {
+      l.Elem(i, i) = 1;
+      for (j = i+1; j <= n; j++)
+	l.Elem(i, j) = 0;
+    }
+
+  /*
+  // Multiply:
+  (*testout) << "multiplied factors: " << endl;
+  for (i = 1; i <= n; i++)
+    for (j = 1; j <= n; j++)
+      {
+	x = 0;
+	for (k = 1; k <= n; k++)
+	  x += l.Get(i, k) * l.Get(j, k) * d.Get(k);
+	(*testout) << x << " ";
+      }
+  (*testout) << endl;
+  */
+}
+
+
+void MultLDLt (const DenseMatrix & l, const Vector & d, const Vector & g, Vector & p)
+{
+  int i, j, n;
+  double val;
+
+  n = l.Height();
+  p = g;
+  for (i = 1; i <= n; i++)
+    {
+      val = 0;
+      for (j = i; j <= n; j++)
+	val += p.Get(j) * l.Get(j, i);
+      p.Set(i, val);
+    }
+  for (i = 1; i <= n; i++)
+    p.Elem(i) *= d.Get(i);
+
+  for (i = n; i >= 1; i--)
+    {
+      val = 0;
+      for (j = 1; j <= i; j++)
+	val += p.Get(j) * l.Get(i, j);
+      p.Set(i, val);
+    }
+}
+
+void SolveLDLt (const DenseMatrix & l, const Vector & d, const Vector & g, Vector & p)
+{
+  int i, j, n;
+  double val;
+
+  n = l.Height();
+  p = g;
+
+  for (i = 1; i <= n; i++)
+    {
+      val = 0;
+      for (j = 1; j < i; j++)
+	val += p.Get(j) * l.Get(i, j);
+      p.Elem(i) -= val;
+    }
+  for (i = 1; i <= n; i++)
+    p.Elem(i) /= d.Get(i);
+
+  for (i = n; i >= 1; i--)
+    {
+      val = 0;
+      for (j = i+1; j <= n; j++)
+	val += p.Get(j) * l.Get(j, i);
+      p.Elem(i) -= val;
+    }
+}
+
+int LDLtUpdate (DenseMatrix & l, Vector & d, double a, const Vector & u)
+{
+  // Bemerkung: Es wird a aus R erlaubt
+  // Rueckgabewert: 0 .. D bleibt positiv definit
+  //                1 .. sonst
+
+  int i, j, n;
+
+  n = l.Height();
+
+  Vector v(n);
+  double t, told, xi;
+
+  told = 1;
+  v = u;
+
+  for (j = 1; j <= n; j++)
+    {
+      t = told + a * sqr (v.Elem(j)) / d.Get(j);
+
+      if (t <= 0) return 1;
+
+      xi = a * v.Elem(j) / (d.Get(j) * t);
+
+      d.Elem(j) *= t / told;
+
+      for (i = j + 1; i <= n; i++)
+	{
+	  v.Elem(i) -= v.Elem(j) * l.Elem(i, j);
+	  l.Elem(i, j) += xi * v.Elem(i);
+	}
+
+      told = t;
+    }
+
+  return 0;
+}
+
+
+double BFGS (
+	     Vector & x,         // i: Startwert
+	     // o: Loesung, falls IFAIL = 0
+	     const MinFunction & fun,
+	     const OptiParameters & par,
+	     double eps
+	     )
+
+
+{
+
+  int i, j, n = x.Size();
+  long it;
+  char a1crit, a3acrit;
+
+
+  Vector d(n), g(n), p(n), temp(n), bs(n), xneu(n), y(n), s(n), x0(n);
+  DenseMatrix l(n);
+  DenseMatrix hesse(n);
+
+  double /* normg, */ alphahat, hd, fold;
+  double a1, a2;
+  const double mu1 = 0.1, sigma = 0.1, xi1 = 1, xi2 = 10;
+  const double tau = 0.1, tau1 = 0.1, tau2 = 0.6;
+
+  Vector typx(x.Size());      // i: typische Groessenordnung der Komponenten
+  double f, f0;
+  double typf;               // i: typische Groessenordnung der Loesung
+  double fmin = -1e5;           // i: untere Schranke fuer Funktionswert
+  //  double eps = 1e-8;            // i: Abbruchschranke fuer relativen Gradienten
+  double tauf = 0.1;            // i: Abbruchschranke fuer die relative Aenderung der
+                                //    Funktionswerte
+  int ifail;                    // o:  0 .. Erfolg
+                                //    -1 .. Unterschreitung von fmin
+                                //     1 .. kein Erfolg bei Liniensuche
+                                //     2 .. Ãœberschreitung von itmax
+
+  typx = par.typx;
+  typf = par.typf;
+
+
+  l = 0;
+  for (i = 1; i <= n; i++)
+    l.Elem(i, i) = 1;
+
+  f = fun.FuncGrad (x, g);
+  f0 = f;
+  x0 = x;
+
+
+  it = 0;
+  do
+    {
+      // Restart
+
+      if (it % (5 * n) == 0)
+	{
+
+	  for (i = 1; i <= n; i++)
+	    d.Elem(i) = typf/ sqr (typx.Get(i));   // 1;
+	  for (i = 2; i <= n; i++)
+	    for (j = 1; j < i; j++)
+	      l.Elem(i, j) = 0;
+
+	  /*
+	  hesse = 0;
+	  for (i = 1; i <= n; i++)
+	    hesse.Elem(i, i) = typf / sqr (typx.Get(i));  
+
+	  fun.ApproximateHesse (x, hesse);
+
+	  Cholesky (hesse, l, d);
+	  */
+	}
+
+      it++;
+      if (it > par.maxit_bfgs)
+	{
+	  ifail = 2;
+	  break;
+	}
+
+
+      // Solve with factorized B
+
+      SolveLDLt (l, d, g, p);
+
+
+      p *= -1;
+      y = g;
+
+      fold = f;
+
+      // line search
+
+      alphahat = 1;
+      lines (x, xneu, p, f, g, fun, par, alphahat, fmin,
+	     mu1, sigma, xi1, xi2, tau, tau1, tau2, ifail);
+
+      /*
+      if (it > par.maxit_bfgs/2)
+	{
+	  (*testout) << "x = " << x << endl;
+	  (*testout) << "xneu = " << xneu << endl;
+	  (*testout) << "f = " << f << endl;
+	  (*testout) << "g = " << g << endl;
+	}
+      */
+
+
+      //      (*testout) << "it = " << it << " f = " << f << endl;
+      //      if (ifail != 0) break;
+
+      s.Set2 (1, xneu, -1, x);
+      y *= -1;
+      y.Add (1,g); // y += g;
+
+      x = xneu;
+
+      // BFGS Update
+
+      MultLDLt (l, d, s, bs);
+
+      a1 = y * s;
+      a2 = s * bs;
+
+      if (a1 > 0 && a2 > 0)
+	{
+	  if (LDLtUpdate (l, d, 1 / a1, y) != 0)
+	    {
+	      cerr << "update error1" << endl;
+	      ifail = 1;
+	      break;
+	    }
+
+	  if (LDLtUpdate (l, d, -1 / a2, bs) != 0)
+	    {
+	      cerr << "update error2" << endl;
+	      ifail = 1;
+	      break;
+	    }
+	}
+
+      // Calculate stop conditions
+
+      hd = eps * max2 (typf, fabs (f));
+      a1crit = 1;
+      for (i = 1; i <= n; i++)
+	if ( fabs (g.Elem(i)) * max2 (typx.Elem(i), fabs (x.Elem(i))) > hd)
+	  a1crit = 0;
+
+
+      a3acrit = (fold - f <= tauf * max2 (typf, fabs (f)));
+
+      //    testout << "g = " << g << endl;
+      //    testout << "a1crit, a3crit = " << int(a1crit) << ", " << int(a3acrit) << endl;
+
+      /*
+	// Output for tests
+
+	normg = sqrt (g * g);
+
+	testout << "it =" << setw (5) << it
+	<< " f =" << setw (12) << setprecision (5) << f
+	<< " |g| =" << setw (12) << setprecision (5) << normg;
+
+	testout << " x = (" << setw (12) << setprecision (5) << x.Elem(1);
+	for (i = 2; i <= n; i++)
+	testout << "," << setw (12) << setprecision (5) << x.Elem(i);
+	testout << ")" << endl;
+	*/
+
+      //      (*testout) << "it = " << it << " f = " << f << " x = " << x << endl
+      //		 << " g = " << g << " p = " << p << endl << endl;
+
+      //      (*testout) << "|g| = " << g.L2Norm() << endl;
+
+      if (g.L2Norm() < fun.GradStopping (x)) break;
+
+    }
+  while (!a1crit || !a3acrit);
+
+  /*
+  (*testout) << "it = " << it << " g = " << g << " f = " << f 
+	     << " fail = " << ifail << endl;
+  */
+  if (f0 < f || (ifail == 1))
+    {
+      (*testout) << "fail, f = " << f << " f0 = " << f0 << endl;
+      f = f0;
+      x = x0;
+    }
+
+  //  (*testout) << "x = " << x << ", x0 = " << x0 << endl;
+  return f;
+}
+
+}
diff --git a/Netgen/libsrc/opti/linopt.cpp b/Netgen/libsrc/opti/linopt.cpp
new file mode 100644
index 0000000000..a5d381e6b7
--- /dev/null
+++ b/Netgen/libsrc/opti/linopt.cpp
@@ -0,0 +1,73 @@
+#include <mystdlib.h>
+#include <myadt.hpp>
+
+#include <linalg.hpp>
+#include "opti.hpp"
+
+namespace netgen
+{
+
+void LinearOptimize (const DenseMatrix & a, const Vector & b, 
+    const Vector & c, Vector & x)
+    
+  {
+  int i1, i2, i3, j;
+  DenseMatrix m(3), inv(3);
+  Vector rs(3), hx(3), res(a.Height()), res2(3);
+  double f, fmin;
+  int nrest;
+    
+  if (a.Width() != 3)
+    {
+    cerr << "LinearOptimize only implemented for 3 unknowns" << endl;
+    return;
+    }
+    
+  fmin = 1e10;
+  x = 0;
+  nrest = a.Height();
+  for (i1 = 1; i1 <= nrest; i1++)
+    for (i2 = i1 + 1; i2 <= nrest; i2++)
+      for (i3 = i2 + 1; i3 <= nrest; i3++)
+        {
+        for (j = 1; j <= 3; j++)
+          {
+          m.Elem(1, j) = a.Get(i1, j);
+          m.Elem(2, j) = a.Get(i2, j);
+          m.Elem(3, j) = a.Get(i3, j);
+          }
+          
+        rs.Elem(1) = b.Get(i1);
+        rs.Elem(2) = b.Get(i2);
+        rs.Elem(3) = b.Get(i3);
+        
+        if (fabs (m.Det()) < 1e-12) continue;
+        
+        CalcInverse (m, inv);
+        inv.Mult (rs, hx);
+        
+        a.Residuum (hx, b, res);
+//        m.Residuum (hx, rs, res2);
+        f = c * hx;
+
+/*        
+        testout -> precision(12);
+        (*testout) << "i = (" << i1 << "," << i2 << "," << i3 
+           << "), f = " << f << " x = " << x << " res = " << res 
+           <<  " resmin = " << res.Min() 
+           << " res2 = " << res2 << " prod = " << prod << endl;
+*/
+
+	
+	double rmin = res.Elem(1);
+	for (int hi = 2; hi <= res.Size(); hi++)
+	  if (res.Elem(hi) < rmin) rmin = res.Elem(hi);
+        
+        if ( (f < fmin) && rmin >= -1e-8)
+          {
+          fmin = f;
+          x = hx;
+          }
+        }
+  }
+}
diff --git a/Netgen/libsrc/opti/linsearch.cpp b/Netgen/libsrc/opti/linsearch.cpp
new file mode 100644
index 0000000000..c847911dae
--- /dev/null
+++ b/Netgen/libsrc/opti/linsearch.cpp
@@ -0,0 +1,346 @@
+/***************************************************************************/
+/*                                                                         */
+/* Problem:        Liniensuche                                             */
+/*                                                                         */
+/* Programmautor:  Joachim Schöberl                                        */
+/* Matrikelnummer: 9155284                                                 */
+/*                                                                         */
+/* Algorithmus nach:                                                       */
+/*                                                                         */
+/*   Optimierung I, Gfrerer, WS94/95                                       */
+/*   Algorithmus 2.1: Liniensuche Problem (ii)                             */
+/*                                                                         */
+/***************************************************************************/
+
+
+
+#include <mystdlib.h>
+
+#include <myadt.hpp>  // min, max, sqr
+
+#include <linalg.hpp>
+#include "opti.hpp"
+
+
+namespace netgen
+{
+const double eps0 = 1E-15;
+
+// Liniensuche
+
+
+double MinFunction :: Func (const Vector & /* x */) const
+{
+  cerr << "Func of MinFunction called" << endl;
+  return 0;
+}
+
+void MinFunction :: Grad (const Vector & /* x */, Vector & /* g */) const
+{
+  cerr << "Grad of MinFunction called" << endl;
+}
+  
+double MinFunction :: FuncGrad (const Vector & x, Vector & g) const
+{
+  int n = x.Size();
+  int i, j;
+
+  static Vector xr;
+  static Vector xl;
+  xr.SetSize(n);
+  xl.SetSize(n);
+
+  double eps = 1e-6;
+  double fl, fr;
+  
+  for (i = 1; i <= n; i++)
+    {
+      xr.Set (1, x);
+      xl.Set (1, x);
+      xr.Elem(i) += eps;
+      xl.Elem(i) -= eps;
+
+      fl = Func (xl);
+      fr = Func (xr);
+
+      g.Elem(i) = (fr - fl) / (2 * eps);
+    }
+
+  double f = Func(x);
+  //  (*testout) << "f = " << f << " grad = " << g << endl;
+  return f;
+}
+
+
+double MinFunction :: FuncDeriv (const Vector & x, const Vector & dir, double & deriv) const
+{
+  Vector g(x.Size());
+  double f = FuncGrad (x, g);
+  deriv = (g * dir);
+
+  //  (*testout) << "g = " << g << ", dir = " << dir << ", deriv = " << deriv << endl;
+  return f;
+}
+
+void MinFunction :: ApproximateHesse (const Vector & x,
+				      DenseMatrix & hesse) const
+{
+  int n = x.Size();
+  int i, j;
+
+  static Vector hx;
+  hx.SetSize(n);
+
+  double eps = 1e-6;
+  double f, f11, f12, f21, f22;
+  
+  for (i = 1; i <= n; i++)
+    {
+      for (j = 1; j < i; j++)
+	{
+	  hx = x;
+	  hx.Elem(i) = x.Get(i) + eps;
+	  hx.Elem(j) = x.Get(j) + eps;
+	  f11 = Func(hx);
+	  hx.Elem(i) = x.Get(i) + eps;
+	  hx.Elem(j) = x.Get(j) - eps;
+	  f12 = Func(hx);
+	  hx.Elem(i) = x.Get(i) - eps;
+	  hx.Elem(j) = x.Get(j) + eps;
+	  f21 = Func(hx);
+	  hx.Elem(i) = x.Get(i) - eps;
+	  hx.Elem(j) = x.Get(j) - eps;
+	  f22 = Func(hx);
+
+	  hesse.Elem(i, j) = hesse.Elem(j, i) =
+	    (f11 + f22 - f12 - f21) / (2 * eps * eps);
+	}
+
+      hx = x;
+      f = Func(x);
+      hx.Elem(i) = x.Get(i) + eps;
+      f11 = Func(hx);
+      hx.Elem(i) = x.Get(i) - eps;
+      f22 = Func(hx);
+
+      hesse.Elem(i, i) = (f11 + f22 - 2 * f) / (eps * eps);
+    }
+  //  (*testout) << "hesse = " << hesse << endl;
+}
+
+
+
+
+
+
+
+/// Line search, modified Mangasarien conditions
+void lines (Vector & x,         // i: initial point of line-search
+	    Vector & xneu,      // o: solution, if successful
+	    Vector & p,         // i: search direction
+	    double & f,         // i: function-value at x
+	    // o: function-value at xneu, iff ifail = 0
+	    Vector & g,         // i: gradient at x
+	    // o: gradient at xneu, iff ifail = 0
+	    const MinFunction & fun,  // function to minimize
+	    const OptiParameters & par,
+	     double & alphahat,  // i: initial value for alpha_hat
+	    // o: solution alpha iff ifail = 0
+	     double fmin,        // i: lower bound for f
+	     double mu1,         // i: Parameter mu_1 of Alg.2.1
+	     double sigma,       // i: Parameter sigma of Alg.2.1
+	     double xi1,         // i: Parameter xi_1 of Alg.2.1
+	     double xi2,         // i: Parameter xi_1 of Alg.2.1
+	     double tau,         // i: Parameter tau of Alg.2.1
+	     double tau1,        // i: Parameter tau_1 of Alg.2.1
+	     double tau2,        // i: Parameter tau_2 of Alg.2.1
+	     int & ifail)        // o: 0 on success
+  //    -1 bei termination because lower limit fmin
+  //     1 bei illegal termination due to different reasons
+
+{
+  double phi0, phi0prime, phi1, phi1prime, phihatprime;
+  double alpha1, alpha2, alphaincr, c;
+  char flag = 1;
+  long it;
+
+  alpha1 = 0;
+  alpha2 = 1e50;
+  phi0 = phi1 = f;
+
+  phi0prime = g * p;
+
+
+  if (phi0prime > 0)
+    {
+      ifail = 1;
+      return;
+    }
+
+  phi1prime = phi0prime;
+
+  //  (*testout) << "phi0prime = " << phi0prime << endl;
+
+  //  it = 100000l;
+  it = 0;
+
+  while (it++ <= par.maxit_linsearch)
+    {
+      //      (*testout) << "alphahat = " << alphahat << endl;
+
+      xneu.Set2 (1, x, alphahat, p);
+
+      // f = fun.FuncGrad (xneu, g);
+      //      f = fun.Func (xneu);
+      f = fun.FuncDeriv (xneu, p, phihatprime);
+
+      //      (*testout) << "f = " << f << " phip = " << phihatprime << endl;
+
+      if (f < fmin)
+	{
+	  ifail = -1;
+	  break;
+	}
+
+
+      if (alpha2 - alpha1 < eps0 * alpha2)
+	{
+	  ifail = 0;
+	  break;
+	}
+
+      //      (*testout) << "i = " << it << " al = " << alphahat << " f = " << f << " fprime " << phihatprime << endl;;
+
+      if (f - phi0 > mu1 * alphahat * phi1prime + eps0 * fabs (phi0))
+
+	{
+
+	  flag = 0;
+	  alpha2 = alphahat;
+
+	  c = 
+	    (f - phi1 - phi1prime * (alphahat-alpha1)) / 
+	    sqr (alphahat-alpha1);
+
+	  alphahat = alpha1 - 0.5 * phi1prime / c;
+
+	  if (alphahat > alpha2)
+	    alphahat = alpha1 + 1/(4*c) *
+	      ( (sigma+mu1) * phi0prime - 2*phi1prime
+		+ sqrt (sqr(phi1prime - mu1 * phi0prime) -
+			4 * (phi1 - phi0 - mu1 * alpha1 * phi0prime) * c));
+
+	  alphahat = max2 (alphahat, alpha1 + tau * (alpha2 - alpha1));
+	  alphahat = min2 (alphahat, alpha2 - tau * (alpha2 - alpha1));
+	  
+	  //	  (*testout) << " if-branch" << endl;
+
+	}
+
+      else
+
+	{
+	  /*
+	  f = fun.FuncGrad (xneu, g);
+	  phihatprime = g * p;
+	  */
+	  f = fun.FuncDeriv (xneu, p, phihatprime);
+
+	  if (phihatprime < sigma * phi0prime * (1 + eps0))
+
+	    {
+	      if (phi1prime < phihatprime)   
+		// Approximationsfunktion ist konvex
+
+		alphaincr = (alphahat - alpha1) * phihatprime /
+		  (phi1prime - phihatprime);
+
+	      else
+		alphaincr = 1e99; // MAXDOUBLE;
+
+	      if (flag)
+		{
+		  alphaincr = max2 (alphaincr, xi1 * (alphahat-alpha1));
+		  alphaincr = min2 (alphaincr, xi2 * (alphahat-alpha1));
+		}
+	      else
+		{
+		  alphaincr = max2 (alphaincr, tau1 * (alpha2 - alphahat));
+		  alphaincr = min2 (alphaincr, tau2 * (alpha2 - alphahat));
+		}
+
+	      alpha1 = alphahat;
+	      alphahat += alphaincr;
+	      phi1 = f;
+	      phi1prime = phihatprime;
+	    }
+
+	  else
+
+	    {
+	      ifail = 0;     // Erfolg !!
+	      break;
+	    }
+	  
+	  //	  (*testout) << " else, " << endl;
+
+	}
+
+    }
+
+  //  (*testout) << "linsearch: it = " << it << " ifail = " << ifail << endl;
+
+  fun.FuncGrad (xneu, g);
+
+
+  if (it < 0)
+    ifail = 1;
+
+  //  (*testout) << "fail = " << ifail << endl;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+void SteepestDescent (Vector & x, const MinFunction & fun,
+		      const OptiParameters & par)
+{
+  int it, n = x.Size();
+  Vector xnew(n), p(n), g(n), g2(n);
+  double val, alphahat;
+  int fail;
+
+  val = fun.FuncGrad(x, g);
+
+  alphahat = 1;
+  //  testout << "f = ";
+  for (it = 0; it < 10; it++)
+    {
+      //    testout << val << " ";
+
+      // p = -g;
+      p.Set (-1, g);
+
+      lines (x, xnew, p, val, g, fun, par, alphahat, -1e5,
+	     0.1, 0.1, 1, 10, 0.1, 0.1, 0.6, fail);
+
+      x = xnew;
+    }
+  //  testout << endl;
+}
+}
diff --git a/Netgen/libsrc/opti/opti.hpp b/Netgen/libsrc/opti/opti.hpp
new file mode 100644
index 0000000000..5fa0735bd0
--- /dev/null
+++ b/Netgen/libsrc/opti/opti.hpp
@@ -0,0 +1,142 @@
+#ifndef FILE_OPTI
+#define FILE_OPTI
+
+/**************************************************************************/
+/* File:   opti.hpp                                                       */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Jun. 95                                                    */
+/**************************************************************************/
+
+
+
+namespace netgen
+{
+
+  /** 
+      Function to be minimized.
+  */
+  class MinFunction 
+  {
+  public:
+    ///
+    virtual double Func (const Vector & x) const;
+    ///
+    virtual void Grad (const Vector & x, Vector & g) const;
+    /// function and gradient
+    virtual double FuncGrad (const Vector & x, Vector & g) const;
+    /// directional derivative
+    virtual double FuncDeriv (const Vector & x, const Vector & dir, double & deriv) const;
+    /// if |g| < gradaccuray, then stop bfgs
+    virtual double GradStopping (const Vector & /* x */) const { return 0; } 
+
+    ///
+    virtual void ApproximateHesse (const Vector & /* x */,
+				   DenseMatrix & /* hesse */) const;
+  };
+
+
+  class OptiParameters
+  {
+  public:
+    int maxit_linsearch;
+    int maxit_bfgs;
+    double typf;
+    double typx;
+
+    OptiParameters ()
+    {
+      maxit_linsearch = 100;
+      maxit_bfgs = 100;
+      typf = 1;
+      typx = 1;
+    }
+  };
+  
+  
+  /** Implementation of BFGS method.
+      Efficient method for non-linear minimiztion problems.
+      @param x initial value and solution 
+      @param fun function to be minimized
+  */
+  extern double BFGS (Vector & x, const MinFunction & fun, 
+		      const OptiParameters & par,
+		      double eps = 1e-8);
+
+  /** Steepest descent method.
+      Simple method for non-linear minimization problems.
+      @param x initial value and solution 
+      @param fun function to be minimized
+  */
+  void SteepestDescent (Vector & x, const MinFunction & fun,
+			const OptiParameters &  par);
+
+
+  extern void lines (
+		     Vector & x,         // i: Ausgangspunkt der Liniensuche
+		     Vector & xneu,      // o: Loesung der Liniensuche bei Erfolg
+		     Vector & p,         // i: Suchrichtung
+		     double & f,         // i: Funktionswert an der Stelle x
+		     // o: Funktionswert an der Stelle xneu, falls ifail = 0
+		     Vector & g,         // i: Gradient an der Stelle x
+		     // o: Gradient an der Stelle xneu, falls ifail = 0
+
+		     const MinFunction & fun,  // function to minmize
+		     const OptiParameters & par, // parameters
+		     double & alphahat,  // i: Startwert für alpha_hat
+		     // o: Loesung falls ifail = 0
+		     double fmin,        // i: untere Schranke für f
+		     double mu1,         // i: Parameter mu_1 aus Alg.2.1
+		     double sigma,       // i: Parameter sigma aus Alg.2.1
+		     double xi1,         // i: Parameter xi_1 aus Alg.2.1
+		     double xi2,         // i: Parameter xi_1 aus Alg.2.1
+		     double tau,         // i: Parameter tau aus Alg.2.1
+		     double tau1,        // i: Parameter tau_1 aus Alg.2.1
+		     double tau2,        // i: Parameter tau_2 aus Alg.2.1
+		     int & ifail);        // o:  0 bei erfolgreicher Liniensuche
+  //    -1 bei Abbruch wegen Unterschreiten von fmin
+  //    1 bei Abbruch, aus sonstigen Gründen
+
+
+
+
+  /**  
+       Solvers linear programming problem.
+
+       \begin{verbatim}
+       min      c^t x
+       A x <= b    
+       \end{verbatim}
+  */
+  extern void LinearOptimize (const DenseMatrix & a, const Vector & b, 
+			      const Vector & c, Vector & x);
+
+
+#ifdef NONE
+
+  /**
+     Simple projection iteration.
+  
+     find $u = argmin_{v >= 0}  0.5 u A u - f u$
+  */
+  extern void ApproxProject (const BaseMatrix & a, Vector & u, 
+			     const Vector & f,
+			     double tau, int its);
+ 
+
+  /**
+     CG Algorithm for quadratic programming problem.
+     See: Dostal ...
+
+     d ... diag(A) ^{-1}
+  */
+  extern void ApproxProjectCG (const BaseMatrix & a, Vector & x, 
+			       const Vector & b, const class DiagMatrix & d,
+			       double gamma, int & steps, int & changes);
+
+#endif
+
+
+}
+
+#endif
+
diff --git a/Netgen/libsrc/stlgeom/Makefile b/Netgen/libsrc/stlgeom/Makefile
new file mode 100644
index 0000000000..007a979cad
--- /dev/null
+++ b/Netgen/libsrc/stlgeom/Makefile
@@ -0,0 +1,11 @@
+#
+# Makefile for geometric library
+#
+src = stlgeom.cpp stltopology.cpp stlgeomchart.cpp stlgeommesh.cpp meshstlsurface.cpp stlline.cpp stltool.cpp
+#
+lib = stlgeom
+libpath = libsrc/stlgeom 
+#
+#
+include ../makefile.inc
+#
diff --git a/Netgen/libsrc/stlgeom/meshstlsurface.cpp b/Netgen/libsrc/stlgeom/meshstlsurface.cpp
new file mode 100644
index 0000000000..b912779237
--- /dev/null
+++ b/Netgen/libsrc/stlgeom/meshstlsurface.cpp
@@ -0,0 +1,1118 @@
+#include <mystdlib.h>
+#include <myadt.hpp>
+
+#include <linalg.hpp>
+#include <gprim.hpp>
+
+#include <meshing.hpp>
+
+
+#include "stlgeom.hpp"
+
+
+namespace netgen
+{
+
+static void STLFindEdges (STLGeometry & geom,
+			  class Mesh & mesh)
+{
+  int i, j, k;
+  double h;
+
+  h = mparam.maxh;
+
+  // mark edge points:
+  int ngp = geom.GetNP();
+
+  cout << "h1(0,0,0) = " << mesh.LocalHFunction().GetH (Point3d (0,0,0)) << endl;
+  geom.RestrictLocalH(mesh, h);
+  cout << "h2(0,0,0) = " << mesh.LocalHFunction().GetH (Point3d (0,0,0)) << endl;
+
+  PushStatusF("Mesh Lines");
+
+  ARRAY<STLLine*> meshlines;
+  ARRAY<Point3d> meshpoints;
+
+  PrintMessage(3,"Mesh Lines");
+
+  for (i = 1; i <= geom.GetNLines(); i++)
+    {
+      meshlines.Append(geom.GetLine(i)->Mesh(geom.GetPoints(), meshpoints, h, mesh)); 
+      SetThreadPercent(100.0 * (double)i/(double)geom.GetNLines());
+    }
+
+  geom.meshpoints.SetSize(0); //testing
+  geom.meshlines.SetSize(0);  //testing
+  for (i = 1; i <= meshpoints.Size(); i++)
+    {
+      geom.meshpoints.Append(meshpoints.Get(i)); //testing
+
+      int pim = mesh.AddPoint(meshpoints.Get(i));
+    }
+  //(++++++++++++++testing
+  for (i = 1; i <= geom.GetNLines(); i++)
+    {
+      geom.meshlines.Append(meshlines.Get(i));
+    }
+  //++++++++++++++testing)
+
+  PrintMessage(7,"feed with edges");
+
+  for (i = 1; i <= meshlines.Size(); i++)
+    {
+      STLLine* line = meshlines.Get(i);
+      (*testout) << "store line " << i << endl;
+      for (j = 1; j <= line->GetNS(); j++)
+	{
+	  int p1, p2;
+	  
+	  line->GetSeg(j, p1, p2);
+	  int trig1, trig2, trig1b, trig2b;
+
+	  if (p1 == p2) 
+	    cout << "Add Segment, p1 == p2 == " << p1 << endl;
+
+	  // Test auf geschlossener Rand mit 2 Segmenten 
+	      
+	  if ((j == 2) && (line->GetNS() == 2))
+	    {
+	      int oldp1, oldp2;
+	      line->GetSeg (1, oldp1, oldp2);
+	      if (oldp1 == p2 && oldp2 == p1)
+		{
+		  PrintMessage(7,"MESSAGE: don't use second segment");
+		  continue;
+		}
+	    }
+
+
+	  //mesh point number
+	  //p1 = geom2meshnum.Get(p1); // for unmeshed lines!!!
+	  //p2 = geom2meshnum.Get(p2); // for unmeshed lines!!!
+	  
+	  //left and right trigs
+	  trig1 = line->GetLeftTrig(j);
+	  trig2 = line->GetRightTrig(j);
+	  trig1b = line->GetLeftTrig(j+1);
+	  trig2b = line->GetRightTrig(j+1);
+	  
+	  (*testout) << "j = " << j << ", p1 = " << p1 << ", p2 = " << p2 << endl;
+	  (*testout) << "segm-trigs: "
+		   << "trig1 = " << trig1
+		   << ", trig1b = " << trig1b
+		   << ", trig2 = " << trig2
+		   << ", trig2b = " << trig2b << endl;
+
+	  if (trig1 <= 0 || trig2 <= 0 || trig1b <= 0 || trig2b <= 0)
+	    {
+	      cout << "negative trigs, "
+		   << ", trig1 = " << trig1
+		   << ", trig1b = " << trig1b
+		   << ", trig2 = " << trig2
+		   << ", trig2b = " << trig2b << endl;
+	    }
+	  /*
+	  (*testout) << "   trigs p1: " << trig1 << " - " << trig2 << endl;
+	  (*testout) << "   trigs p2: " << trig1b << " - " << trig2b << endl;
+	  (*testout) << "   charts p1: " << geom.GetChartNr(trig1) << " - " << geom.GetChartNr(trig2) << endl;
+	  (*testout) << "   charts p2: " << geom.GetChartNr(trig1b) << " - " << geom.GetChartNr(trig2b) << endl;
+	  */
+	  Point3d hp, hp2;
+	  Segment seg;
+	  seg.p1 = p1;
+	  seg.p2 = p2;
+	  seg.si = geom.GetTriangle(trig1).GetFaceNum();
+	  seg.edgenr = i;
+
+	  seg.epgeominfo[0].edgenr = i;
+	  seg.epgeominfo[0].dist = line->GetDist(j);
+	  seg.epgeominfo[1].edgenr = i;
+	  seg.epgeominfo[1].dist = line->GetDist(j+1);
+	  /*
+	  (*testout) << "seg = " 
+		     << "edgenr " << seg.epgeominfo[0].edgenr
+		     << " dist " << seg.epgeominfo[0].dist
+		     << " edgenr " << seg.epgeominfo[1].edgenr
+		     << " dist " << seg.epgeominfo[1].dist << endl;
+	  */
+	  
+	  seg.geominfo[0].trignum = trig1;
+	  seg.geominfo[1].trignum = trig1b;
+
+	  /*
+	  geom.SelectChartOfTriangle (trig1);
+	  hp = hp2 = mesh.Point (seg.p1);
+	  seg.geominfo[0].trignum = geom.Project (hp);
+
+	  (*testout) << "hp = " << hp2 << ", hp proj = " << hp << ", trignum = " << seg.geominfo[0].trignum << endl;
+	  if (Dist (hp, hp2) > 1e-5 || seg.geominfo[0].trignum == 0) 
+	    {
+	      (*testout) << "PROBLEM" << endl;
+	    }
+
+	  geom.SelectChartOfTriangle (trig1b);
+	  hp = hp2 = mesh.Point (seg.p2);
+	  seg.geominfo[1].trignum = geom.Project (hp);
+
+	  (*testout) << "hp = " << hp2 << ", hp proj = " << hp << ", trignum = " << seg.geominfo[1].trignum << endl;
+	  if (Dist (hp, hp2) > 1e-5 || seg.geominfo[1].trignum == 0) 
+	    {
+	      (*testout) << "PROBLEM" << endl;
+	    }
+	  */
+
+
+	  if (Dist (mesh.Point(seg.p1), mesh.Point(seg.p2)) < 1e-10)
+	    {
+	      (*testout) << "ERROR: Line segment of length 0" << endl;
+	      (*testout) << "pi1, 2 = " << seg.p1 << ", " << seg.p2 << endl;
+	      (*testout) << "p1, 2 = " << mesh.Point(seg.p1)
+			 << ", " << mesh.Point(seg.p2) << endl;
+	      throw NgException ("Line segment of length 0");
+	    }
+	  
+	  mesh.AddSegment (seg);
+
+
+	  Segment seg2;
+	  seg2.p1 = p2;
+	  seg2.p2 = p1;
+	  seg2.si = geom.GetTriangle(trig2).GetFaceNum();
+	  seg2.edgenr = i;
+
+	  seg2.epgeominfo[0].edgenr = i;
+	  seg2.epgeominfo[0].dist = line->GetDist(j+1);
+	  seg2.epgeominfo[1].edgenr = i;
+	  seg2.epgeominfo[1].dist = line->GetDist(j);
+	  /*
+	  (*testout) << "seg = " 
+		     << "edgenr " << seg2.epgeominfo[0].edgenr
+		     << " dist " << seg2.epgeominfo[0].dist
+		     << " edgenr " << seg2.epgeominfo[1].edgenr
+		     << " dist " << seg2.epgeominfo[1].dist << endl;
+	  */
+	  
+	  seg2.geominfo[0].trignum = trig2b;
+	  seg2.geominfo[1].trignum = trig2;
+	  
+	  /*
+	  geom.SelectChartOfTriangle (trig2);
+	  hp = hp2 = mesh.Point (seg.p1);
+	  seg2.geominfo[0].trignum = geom.Project (hp);
+
+	  (*testout) << "hp = " << hp2 << ", hp proj = " << hp << ", trignum = " << seg.geominfo[0].trignum << endl;
+	  if (Dist (hp, hp2) > 1e-5 || seg2.geominfo[0].trignum == 0) 
+	    {
+	      (*testout) << "Get GeomInfo PROBLEM" << endl;
+	    }
+
+
+	  geom.SelectChartOfTriangle (trig2b);
+	  hp = hp2 = mesh.Point (seg.p2);
+	  seg2.geominfo[1].trignum = geom.Project (hp);
+	  (*testout) << "hp = " << hp2 << ", hp proj = " << hp << ", trignum = " << seg.geominfo[1].trignum << endl;
+	  if (Dist (hp, hp2) > 1e-5 || seg2.geominfo[1].trignum == 0) 
+	    {
+	      (*testout) << "Get GeomInfo PROBLEM" << endl;
+	    }
+	  */	  
+
+	  mesh.AddSegment (seg2);
+
+
+	  /*
+	  // should be start triangle and end triangle
+	  int bothtrigs1[2] = { trig1, trig1 };
+	  meshing.AddBoundaryElement (p1, p2, sizeof (bothtrigs1), &bothtrigs1);
+	  
+	  int bothtrigs2[2] = { trig2, trig2 };
+	  meshing.AddBoundaryElement (p2, p1, sizeof (bothtrigs2), &bothtrigs2);
+	  */
+	}
+    }
+
+  PopStatus();
+}
+
+
+
+
+void STLSurfaceMeshing1 (STLGeometry & geom,
+			 class Mesh & mesh,
+			 int retrynr);
+
+int STLSurfaceMeshing (STLGeometry & geom,
+		       class Mesh & mesh)
+{
+  int i, j;
+  PrintFnStart("Do Surface Meshing");
+
+  geom.PrepareSurfaceMeshing();
+
+  if (mesh.GetNSeg() == 0)
+    STLFindEdges (geom, mesh);
+
+  int nopen;
+  int outercnt = 20;
+
+  //  mesh.Save ("mesh.edges");
+  
+  for (i = 1; i <= mesh.GetNSeg(); i++)
+    {
+      const Segment & seg = mesh.LineSegment (i);
+      if (seg.geominfo[0].trignum <= 0 || seg.geominfo[1].trignum <= 0)
+	{
+	  (*testout) << "Problem with segment " << i << ": " << seg << endl;
+	}
+    }
+
+
+  do
+    {
+      outercnt--;
+      if (outercnt <= 0)
+	  return MESHING3_OUTERSTEPSEXCEEDED;
+
+      if (multithread.terminate)
+	{
+	  return MESHING3_TERMINATE;
+	}
+
+      mesh.FindOpenSegments();
+      nopen = mesh.GetNOpenSegments();
+
+      if (nopen)
+	{
+	  int trialcnt = 0;
+	  while (nopen && trialcnt <= 5)
+	    {
+	      if (multithread.terminate)
+		{
+		  return MESHING3_TERMINATE;
+		}
+	      trialcnt++;
+	      STLSurfaceMeshing1 (geom, mesh, trialcnt);
+
+	      mesh.FindOpenSegments();
+	      nopen = mesh.GetNOpenSegments();
+
+	      if (nopen)
+		{
+		  geom.ClearMarkedSegs();
+		  for (i = 1; i <= nopen; i++)
+		    {
+		      const Segment & seg = mesh.GetOpenSegment (i);
+		      geom.AddMarkedSeg(mesh.Point(seg.p1),mesh.Point(seg.p2));
+		    }
+
+		  geom.InitMarkedTrigs();
+		  for (i = 1; i <= nopen; i++)
+		    {
+		      const Segment & seg = mesh.GetOpenSegment (i);
+		      geom.SetMarkedTrig(seg.geominfo[0].trignum,1);
+		      geom.SetMarkedTrig(seg.geominfo[1].trignum,1);
+		    }
+
+		  MeshOptimizeSTLSurface optmesh(geom);
+		  optmesh.SetFaceIndex (0);
+		  optmesh.SetImproveEdges (0);
+		  optmesh.SetMetricWeight (0);
+		  
+		  mesh.CalcSurfacesOfNode();
+		  optmesh.EdgeSwapping (mesh, 0);
+		  mesh.CalcSurfacesOfNode();
+		  optmesh.ImproveMesh (mesh);
+		}
+
+	      mesh.FindOpenSegments();
+	      nopen = mesh.GetNOpenSegments();
+
+	      if (trialcnt <= 5 && nopen)
+		{
+		  mesh.RemoveOneLayerSurfaceElements();
+
+		  if (trialcnt >= 4)
+		    {
+		      mesh.FindOpenSegments();
+		      mesh.RemoveOneLayerSurfaceElements();
+
+		      mesh.FindOpenSegments ();		  
+		      nopen = mesh.GetNOpenSegments();
+		    }
+		}
+	    }
+
+
+	  if (multithread.terminate)
+	    return MESHING3_TERMINATE;
+
+	  if (nopen)
+	    {
+	      
+	      PrintMessage(3,"Meshing failed, trying to refine");
+
+	      mesh.FindOpenSegments ();
+	      nopen = mesh.GetNOpenSegments();
+			  
+	      mesh.FindOpenSegments ();
+	      mesh.RemoveOneLayerSurfaceElements();
+	      mesh.FindOpenSegments ();
+	      mesh.RemoveOneLayerSurfaceElements();
+
+	      // Open edge-segments will be refined !
+	      INDEX_2_HASHTABLE<int> openseght (nopen+1);
+	      for (i = 1; i <= mesh.GetNOpenSegments(); i++)
+		{
+		  const Segment & seg = mesh.GetOpenSegment (i);
+		  INDEX_2 i2(seg.p1, seg.p2);
+		  i2.Sort();
+		  openseght.Set (i2, 1);
+		}
+
+	      
+	      mesh.FindOpenSegments ();
+	      mesh.RemoveOneLayerSurfaceElements();
+	      mesh.FindOpenSegments ();
+	      mesh.RemoveOneLayerSurfaceElements();
+	      
+
+	      INDEX_2_HASHTABLE<int> newpht(100);
+
+	      int nsegold = mesh.GetNSeg();
+	      for (i = 1; i <= nsegold; i++)
+		{
+		  Segment seg = mesh.LineSegment(i);
+		  INDEX_2 i2(seg.p1, seg.p2);
+		  i2.Sort();
+		  if (openseght.Used (i2))
+		    {
+		      // segment will be split
+		      PrintMessage(7,"Split segment ", int(seg.p1), "-", int(seg.p2));
+	      
+		      Segment nseg1, nseg2;
+		      EdgePointGeomInfo newgi;
+		      
+		      const EdgePointGeomInfo & gi1 = seg.epgeominfo[0];
+		      const EdgePointGeomInfo & gi2 = seg.epgeominfo[1];
+		      
+		      newgi.dist = 0.5 * (gi1.dist + gi2.dist);
+		      newgi.edgenr = gi1.edgenr;
+
+		      int hi;
+		      
+		      Point3d newp;
+		      int newpi;
+		      
+		      if (!newpht.Used (i2))
+			{
+			  newp = geom.GetLine (gi1.edgenr)->
+			    GetPointInDist (geom.GetPoints(), newgi.dist, hi);
+			  newpi = mesh.AddPoint (newp);
+			  newpht.Set (i2, newpi);
+			}
+		      else
+			{
+			  newpi = newpht.Get (i2);
+			  newp = mesh.Point (newpi);
+			}
+
+		      nseg1 = seg;
+		      nseg2 = seg;
+		      nseg1.p2 = newpi;
+		      nseg1.epgeominfo[1] = newgi;
+		      
+		      nseg2.p1 = newpi;
+		      nseg2.epgeominfo[0] = newgi;
+		      
+		      mesh.LineSegment(i) = nseg1;
+		      mesh.AddSegment (nseg2);
+		      
+		      mesh.RestrictLocalH (Center (mesh.Point(nseg1.p1),
+						   mesh.Point(nseg1.p2)),
+					   Dist (mesh.Point(nseg1.p1),
+						 mesh.Point(nseg1.p2)));
+		      mesh.RestrictLocalH (Center (mesh.Point(nseg2.p1),
+						   mesh.Point(nseg2.p2)),
+					   Dist (mesh.Point(nseg2.p1),
+						 mesh.Point(nseg2.p2)));
+		    }
+		}
+
+	    }
+
+	  nopen = -1;
+	}
+    
+      else
+
+	{
+	  PrintMessage(5,"mesh is closed, verifying ...");
+
+	  // no open elements, check wrong elemetns (intersecting..)
+
+
+	 	  
+	  PrintMessage(5,"check overlapping");
+	  // 	  mesh.FindOpenElements(); // would leed to locked points
+	  mesh.CheckOverlappingBoundary();
+
+	  geom.InitMarkedTrigs();
+
+	  for (i = 1; i <= mesh.GetNSE(); i++)
+	    if (mesh.SurfaceElement(i).BadElement())
+	      {
+		int trig = mesh.SurfaceElement(i).PNum(1);
+		geom.SetMarkedTrig(trig,1);
+		PrintMessage(7, "overlapping element, will be removed");
+	      }
+	  
+	  
+
+	  ARRAY<Point3d> refpts;
+	  ARRAY<double> refh;
+
+	  // was commented:
+
+	  for (i = 1; i <= mesh.GetNSE(); i++)
+	    if (mesh.SurfaceElement(i).BadElement())
+	      {
+		for (j = 1; j <= 3; j++)
+		  {
+		    refpts.Append (mesh.Point (mesh.SurfaceElement(i).PNum(j)));
+		    refh.Append (mesh.GetH (refpts.Last()) / 2);
+		  }
+		mesh.DeleteSurfaceElement(i);
+	      }
+	  	  
+	  // delete wrong oriented element
+	  for (i = 1; i <= mesh.GetNSE(); i++)
+	    {
+	      const Element2d & el = mesh.SurfaceElement(i);
+	      if (!el.PNum(1))
+		continue;
+
+	      Vec3d n = Cross (Vec3d (mesh.Point(el.PNum(1)), 
+				      mesh.Point(el.PNum(2))),
+			       Vec3d (mesh.Point(el.PNum(1)), 
+				      mesh.Point(el.PNum(3))));
+	      Vec3d ng = geom.GetTriangle(el.GeomInfoPi(1).trignum).Normal();
+	      if (n * ng < 0)
+		{
+		  refpts.Append (mesh.Point (mesh.SurfaceElement(i).PNum(1)));
+		  refh.Append (mesh.GetH (refpts.Last()) / 2);
+		  mesh.DeleteSurfaceElement(i);
+		}
+	    }
+	  // end comments
+
+	  for (i = 1; i <= refpts.Size(); i++)
+	    mesh.RestrictLocalH (refpts.Get(i), refh.Get(i));
+
+	  mesh.RemoveOneLayerSurfaceElements();
+
+	  mesh.Compress();
+	  
+	  mesh.FindOpenSegments ();
+	  nopen = mesh.GetNOpenSegments();
+
+	  /*
+	  if (!nopen)
+	    {
+	      // mesh is still ok
+
+	      void STLSurfaceOptimization (STLGeometry & geom,
+					   class Mesh & mesh,
+					   MeshingParameters & mparam)
+	      
+	    }
+	  */
+	}
+      
+    }
+  while (nopen);
+
+  mesh.Compress();
+  mesh.CalcSurfacesOfNode();
+
+  return MESHING3_OK;
+}
+
+
+
+
+
+
+void STLSurfaceMeshing1 (STLGeometry & geom,
+			 class Mesh & mesh,
+			 int retrynr)
+{
+  int i, j, k;
+  double h;
+  
+  
+  h = mparam.maxh;
+
+  mesh.FindOpenSegments();
+  
+  ARRAY<int> spiralps(0);
+  spiralps.SetSize(0);
+  for (i = 1; i <= geom.GetNP(); i++)
+    {
+      if (geom.GetSpiralPoint(i)) {spiralps.Append(i);}
+    }
+  
+  PrintMessage(7,"NO spiralpoints = ", spiralps.Size());
+  int spfound;
+  int sppointnum;
+  int spcnt = 0;
+
+  ARRAY<int> meshsp(mesh.GetNP());
+  for (i = 1; i <= mesh.GetNP(); i++)
+    {
+      meshsp.Elem(i) = 0;
+      for (j = 1; j <= spiralps.Size(); j++)
+	if (Dist2(geom.GetPoint(spiralps.Get(j)), mesh.Point(i)) < 1e-20) 
+	  meshsp.Elem(i) = spiralps.Get(j);
+    }
+
+
+  ARRAY<int> opensegsperface(mesh.GetNFD());
+  for (i = 1; i <= mesh.GetNFD(); i++)
+    opensegsperface.Elem(i) = 0;
+  for (i = 1; i <= mesh.GetNOpenSegments(); i++)
+    {
+      int si = mesh.GetOpenSegment (i).si;
+      if (si >= 1 && si <= mesh.GetNFD())
+	{
+	  opensegsperface.Elem(si)++;
+	}
+      else
+	{
+	  cerr << "illegal face index" << endl;
+	}
+    }
+
+
+  double starttime = GetTime ();
+
+  for (int fnr = 1; fnr <= mesh.GetNFD(); fnr++)
+    if (opensegsperface.Get(fnr))
+      {
+	if (multithread.terminate)
+	  return;
+	
+	PrintMessage(5,"Meshing surface ", fnr, "/", mesh.GetNFD());
+	MeshingSTLSurface meshing (geom);
+	
+	meshing.SetStartTime (starttime);
+	
+	for (i = 1; i <= mesh.GetNP(); i++)
+	  {
+	    /*
+	      spfound = 0;
+	      for (j = 1; j <= spiralps.Size(); j++)
+	      {
+	      if (Dist2(geom.GetPoint(spiralps.Get(j)),mesh.Point(i)) < 1e-20) 
+		{spfound =  1; sppointnum = spiralps.Get(j);}
+		}
+	    */
+	    sppointnum = 0;
+	    if (i <= meshsp.Size())
+	      sppointnum = meshsp.Get(i);
+	    
+	  //spfound = 0;
+	  if (sppointnum)
+	    {
+	      MultiPointGeomInfo mgi;
+  
+	      int ntrigs = geom.NOTrigsPerPoint(sppointnum);
+	      spcnt++;
+	      
+	      for (j = 0; j < ntrigs; j++)
+		{
+		  PointGeomInfo gi;
+		  gi.trignum = geom.TrigPerPoint(sppointnum, j+1);
+		  mgi.AddPointGeomInfo (gi);
+		}
+	      
+	      // Einfuegen von ConePoint: Point bekommt alle
+	      // Dreiecke (werden dann intern kopiert)
+	      // Ein Segment zum ConePoint muss vorhanden sein !!!
+	      
+	      meshing.AddPoint (mesh.Point(i), i, &mgi);
+	      
+	    }
+	  else
+	    {
+	      meshing.AddPoint (mesh.Point(i), i);
+	    }
+	}
+      
+      
+      for (i = 1; i <= mesh.GetNOpenSegments(); i++)
+	{
+	  const Segment & seg = mesh.GetOpenSegment (i);
+	  if (seg.si == fnr)
+	    meshing.AddBoundaryElement (seg.p1, seg.p2, seg.geominfo[0], seg.geominfo[1]);
+	}
+      
+      
+      PrintMessage(3,"start meshing, trialcnt = ", retrynr);
+
+      /*
+      (*testout) << "start meshing with h = " << h << endl;
+      */
+      meshing.GenerateMesh (mesh, h, fnr);  // face index
+#ifdef OPENGL
+      extern void Render();
+      Render();
+#endif
+    }    
+      
+  
+  mesh.CalcSurfacesOfNode();
+}
+
+
+
+void STLSurfaceOptimization (STLGeometry & geom,
+			     class Mesh & mesh,
+			     MeshingParameters & mparam)
+{
+  PrintFnStart("optimize STL Surface");
+
+
+  MeshOptimizeSTLSurface optmesh(geom);
+  //
+
+  int i, j;
+  /*
+  for (i = 1; i <= mparam.optsteps2d; i++)
+    {
+      EdgeSwapping (mesh, 1, 1);
+      CombineImprove (mesh, 1);
+      optmesh.ImproveMesh (mesh, 0, 10, 1, 1);
+    }
+  */
+
+  optmesh.SetFaceIndex (0);
+  optmesh.SetImproveEdges (0);
+  optmesh.SetMetricWeight (mparam.elsizeweight);
+
+  PrintMessage(5,"optimize string = ", mparam.optimize2d, " elsizew = ", mparam.elsizeweight);
+
+  for (i = 1; i <= mparam.optsteps2d; i++)
+    for (j = 1; j <= strlen(mparam.optimize2d); j++)
+      {
+	if (multithread.terminate)
+	  break;
+
+	mesh.CalcSurfacesOfNode();
+	switch (mparam.optimize2d[j-1])
+	  {
+	  case 's': 
+	    {
+	      optmesh.EdgeSwapping (mesh, 0);
+	      break;
+	    }
+	  case 'S': 
+	    {
+	      optmesh.EdgeSwapping (mesh, 1);
+	      break;
+	    }
+	  case 'm': 
+	    {
+	      optmesh.ImproveMesh(mesh);
+	      break;
+	    }
+	  case 'c': 
+	    {
+	      optmesh.CombineImprove (mesh);
+	      break;
+	    }
+	  }
+      }
+
+  geom.surfaceoptimized = 1;
+
+  mesh.Compress();
+  mesh.CalcSurfacesOfNode();
+
+
+}
+
+
+
+MeshingSTLSurface :: MeshingSTLSurface (STLGeometry & ageom)
+  : Meshing2(Box3d (ageom.GetBoundingBox().PMin(),
+		    ageom.GetBoundingBox().PMax())), geom(ageom)
+{
+  ;
+}
+
+void MeshingSTLSurface :: DefineTransformation (Point3d & p1, Point3d & p2,
+						const PointGeomInfo * geominfo,
+						const PointGeomInfo * geominfo2)
+{
+  transformationtrig = geominfo[0].trignum;
+  
+  geom.DefineTangentialPlane(p1, p2, transformationtrig);
+}
+
+void MeshingSTLSurface :: TransformToPlain (const Point3d & locpoint, const MultiPointGeomInfo & gi,
+					    Point2d & plainpoint, double h, int & zone)
+{
+  int trigs[10000];
+  int i;
+
+  if (gi.GetNPGI() >= 9999) 
+    {
+      PrintError("In Transform to plane: increase size of trigs!!!");
+    }
+
+  for (i = 1; i <= gi.GetNPGI(); i++)
+    trigs[i-1] = gi.GetPGI(i).trignum;
+  trigs[gi.GetNPGI()] = 0;
+
+  //  int trig = gi.trignum;
+  //   (*testout) << "locpoint = " << locpoint;
+
+  Point<2> hp2d;
+  geom.ToPlane (locpoint, trigs, hp2d, h, zone, 1);
+  plainpoint = hp2d;
+
+  //  geom.ToPlane (locpoint, NULL, plainpoint, h, zone, 1);
+  /*
+  (*testout) << " plainpoint = " << plainpoint
+	     << " h = " << h 
+	     << endl;
+  */
+}
+
+/*
+int MeshingSTLSurface :: ComputeLineGeoInfo (const Point3d & p1, const Point3d & p2,
+					      int & geoinfosize, void *& geoinfo)
+{
+  static int geomtrig[2] = { 0, 0 };
+
+  Point3d hp;
+  hp = p1;
+  geomtrig[0] = geom.Project (hp);
+
+  hp = p2;
+  geomtrig[1] = geom.Project (hp);
+  
+  geoinfosize = sizeof (geomtrig);
+  geoinfo = &geomtrig;
+
+  if (geomtrig[0] == 0)
+    {
+      return 1;
+    }
+  return 0;
+}
+*/
+
+
+int MeshingSTLSurface :: ComputePointGeomInfo (const Point3d & p, PointGeomInfo & gi)
+{
+  // compute triangle of point,
+  // if non-unique: 0
+
+  Point<3> hp = p;
+  gi.trignum = geom.Project (hp);
+
+  if (!gi.trignum)
+    {
+      return 1;
+    }
+
+  return 0;
+}
+
+
+int MeshingSTLSurface :: 
+ChooseChartPointGeomInfo (const MultiPointGeomInfo & mpgi, 
+			  PointGeomInfo & pgi)
+{
+  int i;
+
+  for (i = 1; i <= mpgi.GetNPGI(); i++)
+    if (geom.TrigIsInOC (mpgi.GetPGI(i).trignum, geom.meshchart))
+      {
+	pgi = mpgi.GetPGI(i);
+	return 0;
+      }
+  /*
+  for (i = 0; i < mpgi.cnt; i++)
+    {
+      //      (*testout) << "d" << endl;
+      if (geom.TrigIsInOC (mpgi.mgi[i].trignum, geom.meshchart))
+	{
+	  pgi = mpgi.mgi[i];
+	  return 0;
+	}
+    }
+  */
+  PrintMessage(7,"INFORM: no gi on chart");
+  pgi.trignum = 1;
+  return 1;
+}
+
+
+
+int MeshingSTLSurface :: 
+IsLineVertexOnChart (const Point3d & p1, const Point3d & p2,
+		     int endpoint, const PointGeomInfo & gi)
+{
+  Vec3d baselinenormal = geom.meshtrignv;
+
+  int lineendtrig = gi.trignum;
+
+  
+  return geom.TrigIsInOC (lineendtrig, geom.meshchart);
+
+  //  Vec3d linenormal = geom.GetTriangleNormal (lineendtrig);
+  //  return ( (baselinenormal * linenormal) > cos (30 * (M_PI/180)) );
+}
+
+void MeshingSTLSurface :: 
+GetChartBoundary (ARRAY<Point2d > & points, 
+		  ARRAY<Point3d > & points3d,
+		  ARRAY<INDEX_2> & lines, double h) const
+{
+  points.SetSize (0);
+  points3d.SetSize (0);
+  lines.SetSize (0);
+  geom.GetMeshChartBoundary (points, points3d, lines, h);
+}
+
+
+
+
+int MeshingSTLSurface :: TransformFromPlain (Point2d & plainpoint,
+					     Point3d & locpoint, 
+					     PointGeomInfo & gi, 
+					     double h)
+{
+  //return 0, wenn alles OK
+  Point<3> hp3d;
+  int res = geom.FromPlane (plainpoint, hp3d, h);
+  locpoint = hp3d;
+  ComputePointGeomInfo (locpoint, gi);
+  return res;
+}
+
+
+int MeshingSTLSurface :: 
+BelongsToActiveChart (const Point3d & p, 
+		      const PointGeomInfo & gi)
+{
+  return (geom.TrigIsInOC(gi.trignum, geom.meshchart) != 0);
+}
+
+
+
+double MeshingSTLSurface :: CalcLocalH (const Point3d & p, double gh) const
+{
+  return gh;
+}
+
+double MeshingSTLSurface :: Area () const
+{
+  return geom.Area();
+}
+
+
+
+
+
+
+MeshOptimizeSTLSurface :: MeshOptimizeSTLSurface (STLGeometry & ageom)
+  : MeshOptimize2d(), geom(ageom)
+{
+  ;
+}
+
+
+void MeshOptimizeSTLSurface :: SelectSurfaceOfPoint (const Point3d & p,
+						     const PointGeomInfo & gi)
+{
+  //  (*testout) << "sel char: " << gi.trignum << endl;
+  
+  geom.SelectChartOfTriangle (gi.trignum);
+  //  geom.SelectChartOfPoint (p);
+}
+
+
+void MeshOptimizeSTLSurface :: ProjectPoint (INDEX surfind, Point3d & p) const
+{
+  Point<3> hp = p;
+  if (!geom.Project (hp))
+    {
+      PrintMessage(7,"project failed");
+      
+      if (!geom.ProjectOnWholeSurface(hp)) 
+	{
+	  PrintMessage(7, "project on whole surface failed");
+	}
+    }
+  p = hp;
+  //  geometry.GetSurface(surfind)->Project (p);
+}
+
+void MeshOptimizeSTLSurface :: ProjectPoint2 (INDEX surfind, INDEX surfind2, Point3d & p) const
+{
+  /*
+  ProjectToEdge ( geometry.GetSurface(surfind), 
+		  geometry.GetSurface(surfind2), p);
+  */
+}
+
+int  MeshOptimizeSTLSurface :: CalcPointGeomInfo(PointGeomInfo& gi, const Point3d& p3) const
+{
+  Point<3> hp = p3;
+  gi.trignum = geom.Project (hp);
+
+  if (gi.trignum)
+    {
+      return 1;
+    }
+
+  return 0;
+  
+}
+
+void MeshOptimizeSTLSurface :: GetNormalVector(INDEX surfind, const Point3d & p, Vec3d & n) const
+{
+  n = geom.GetChartNormalVector();
+  
+  /*
+  geometry.GetSurface(surfind)->CalcGradient (p, n);
+  n /= n.Length();
+  if (geometry.GetSurface(surfind)->Inverse())
+    n *= -1;
+  */
+}
+  
+
+
+
+
+
+
+
+
+
+RefinementSTLGeometry :: RefinementSTLGeometry (const STLGeometry & ageom)
+  : Refinement(), geom(ageom)
+{
+  ;
+}
+
+RefinementSTLGeometry :: ~RefinementSTLGeometry ()
+{
+  ;
+}
+  
+void RefinementSTLGeometry :: 
+PointBetween  (const Point3d & p1, const Point3d & p2, double secpoint,
+	       int surfi, 
+	       const PointGeomInfo & gi1, 
+	       const PointGeomInfo & gi2,
+	       Point3d & newp, PointGeomInfo & newgi)
+{
+  newp = p1+secpoint*(p2-p1);
+
+  /*
+  (*testout) << "surf-between: p1 = " << p1 << ", p2 = " << p2
+	     << ", gi = " << gi1 << " - " << gi2 << endl;
+  */
+
+  if (gi1.trignum > 0)
+    {
+      //      ((STLGeometry&)geom).SelectChartOfTriangle (gi1.trignum);
+
+      Point<3> np1 = newp;
+      Point<3> np2 = newp;
+      ((STLGeometry&)geom).SelectChartOfTriangle (gi1.trignum);
+      int tn1 = geom.Project (np1);
+
+      ((STLGeometry&)geom).SelectChartOfTriangle (gi2.trignum);
+      int tn2 = geom.Project (np2);
+
+      newgi.trignum = tn1; //urspruengliche version
+      newp = np1;          //urspruengliche version
+
+      if (!newgi.trignum) 
+	{ newgi.trignum = tn2; newp = np2; }
+      if (!newgi.trignum) newgi.trignum = gi1.trignum;
+
+      /*    
+      if (tn1 != 0 && tn2 != 0 && ((STLGeometry&)geom).GetAngle(tn1,tn2) < M_PI*0.05)	{
+	  newgi.trignum = tn1;
+	  newp = np1;
+	}
+      else
+	{
+	  newp = ((STLGeometry&)geom).PointBetween(p1, gi1.trignum, p2, gi2.trignum);
+	  tn1 = ((STLGeometry&)geom).Project(newp);
+	  newgi.trignum = tn1;
+
+	  if (!tn1) 
+	    {
+	      newp = Center (p1, p2);
+	      newgi.trignum = 0;
+	      
+	    }
+	}
+      */
+    }
+  else
+    {
+      //      (*testout) << "WARNING: PointBetween got geominfo = 0" << endl;
+      newp =  p1+secpoint*(p2-p1);
+      newgi.trignum = 0;
+    }
+     
+  //  (*testout) << "newp = " << newp << ", ngi = " << newgi << endl;
+}
+
+void RefinementSTLGeometry ::
+PointBetween (const Point3d & p1, const Point3d & p2, double secpoint,
+	      int surfi1, int surfi2, 
+	      const EdgePointGeomInfo & gi1, 
+	      const EdgePointGeomInfo & gi2,
+	      Point3d & newp, EdgePointGeomInfo & newgi)
+{
+  /*
+  (*testout) << "edge-between: p1 = " << p1 << ", p2 = " << p2
+	     << ", gi1,2 = " << gi1 << ", " << gi2 << endl;
+  */
+  /*
+  newp = Center (p1, p2);
+  ((STLGeometry&)geom).SelectChartOfTriangle (gi1.trignum);
+  newgi.trignum = geom.Project (newp);
+  */
+  int hi;
+  newgi.dist = (1.0-secpoint) * gi1.dist + secpoint*gi2.dist;
+  newgi.edgenr = gi1.edgenr;
+
+  /*
+  (*testout) << "p1 = " << p1 << ", p2 = " << p2 << endl;
+  (*testout) << "refedge: " << gi1.edgenr
+	     << " d1 = " << gi1.dist << ", d2 = " << gi2.dist << endl;
+  */
+  newp = geom.GetLine (gi1.edgenr)->GetPointInDist (geom.GetPoints(), newgi.dist, hi);
+
+  //  (*testout) << "newp = " << newp << endl;
+}
+
+
+void RefinementSTLGeometry :: ProjectToSurface (Point<3> & p, int surfi)
+{
+  cout << "RefinementSTLGeometry :: ProjectToSurface not implemented!" << endl;
+};
+
+ 
+}
diff --git a/Netgen/libsrc/stlgeom/meshstlsurface.hpp b/Netgen/libsrc/stlgeom/meshstlsurface.hpp
new file mode 100644
index 0000000000..99d2918fd1
--- /dev/null
+++ b/Netgen/libsrc/stlgeom/meshstlsurface.hpp
@@ -0,0 +1,120 @@
+#ifndef FILE_MESHSTLSURF
+#define FILE_MESHSTLSURF
+
+/* *************************************************************************/
+/* File:   meshstlsurf.hpp                                                 */
+/* Author: Johannes Gerstmayr, Joachim Schoeberl                           */
+/* Date:   01. Aug. 99                                                     */
+/* *************************************************************************/
+
+/*
+
+The interface between mesh generation and stl geometry
+
+*/
+
+
+/// 
+class MeshingSTLSurface : public Meshing2
+{
+  ///
+  STLGeometry & geom;
+  ///
+  int transformationtrig;
+public:
+  ///
+  MeshingSTLSurface (STLGeometry & ageom);
+
+protected:
+  ///
+  virtual void DefineTransformation (Point3d & p1, Point3d & p2,
+				     const PointGeomInfo * geominfo1,
+				     const PointGeomInfo * geominfo2);
+  ///
+  virtual void TransformToPlain (const Point3d & locpoint, const MultiPointGeomInfo & geominfo,
+      Point2d & plainpoint, double h, int & zone);
+  ///
+  virtual int TransformFromPlain (Point2d & plainpoint,
+				  Point3d & locpoint, 
+				  PointGeomInfo & gi,
+				  double h);
+  ///
+  virtual int BelongsToActiveChart (const Point3d & p, 
+				    const PointGeomInfo & gi);
+
+  ///
+  virtual int ComputePointGeomInfo (const Point3d & p, PointGeomInfo & gi);
+  ///
+  virtual int ChooseChartPointGeomInfo (const MultiPointGeomInfo & mpgi, 
+					 PointGeomInfo & pgi);
+
+  ///
+  virtual int IsLineVertexOnChart (const Point3d & p1, const Point3d & p2,
+				   int endpoint, const PointGeomInfo & gi);
+
+  virtual void GetChartBoundary (ARRAY<Point2d > & points, 
+				 ARRAY<Point3d > & poitns3d,
+				 ARRAY<INDEX_2> & lines, double h) const;
+
+  ///
+  virtual double CalcLocalH (const Point3d & p, double gh) const;
+
+  ///
+  virtual double Area () const;
+};
+
+
+
+///
+class MeshOptimizeSTLSurface : public MeshOptimize2d
+  {
+  ///
+    STLGeometry & geom;
+
+public:
+    ///
+    MeshOptimizeSTLSurface (STLGeometry & ageom); 
+   
+    ///
+    virtual void SelectSurfaceOfPoint (const Point3d & p,
+				       const PointGeomInfo & gi);
+    ///
+    virtual void ProjectPoint (INDEX surfind, Point3d & p) const;
+    ///
+    virtual void ProjectPoint2 (INDEX surfind, INDEX surfind2, Point3d & p) const;
+    ///
+    virtual int CalcPointGeomInfo(PointGeomInfo& gi, const Point3d& p3) const;
+    ///
+    virtual void GetNormalVector(INDEX surfind, const Point3d & p, Vec3d & n) const;
+};
+
+
+
+
+class RefinementSTLGeometry : public Refinement
+{
+  const STLGeometry & geom;
+
+public:
+  RefinementSTLGeometry (const STLGeometry & ageom);
+  virtual ~RefinementSTLGeometry ();
+  
+  virtual void PointBetween (const Point3d & p1, const Point3d & p2, double secpoint,
+			     int surfi, 
+			     const PointGeomInfo & gi1, 
+			     const PointGeomInfo & gi2,
+			     Point3d & newp, PointGeomInfo & newgi);
+
+  virtual void PointBetween (const Point3d & p1, const Point3d & p2, double secpoint,
+			     int surfi1, int surfi2, 
+			     const EdgePointGeomInfo & ap1, 
+			     const EdgePointGeomInfo & ap2,
+			     Point3d & newp, EdgePointGeomInfo & newgi);
+
+  virtual void ProjectToSurface (Point<3> & p, int surfi);
+};
+
+
+
+#endif
+
diff --git a/Netgen/libsrc/stlgeom/stlgeom.cpp b/Netgen/libsrc/stlgeom/stlgeom.cpp
new file mode 100644
index 0000000000..d28ac37ff5
--- /dev/null
+++ b/Netgen/libsrc/stlgeom/stlgeom.cpp
@@ -0,0 +1,3477 @@
+#include <mystdlib.h>
+
+#include <myadt.hpp>
+#include <linalg.hpp>
+#include <gprim.hpp>
+
+#include <meshing.hpp>
+
+#include "stlgeom.hpp"
+
+
+namespace netgen
+{
+
+//globalen searchtree fuer gesamte geometry aktivieren
+int geomsearchtreeon = 0;
+
+int usechartnormal = 1;  
+
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+void STLMeshing (STLGeometry & geom,
+		 Mesh & mesh)
+{
+  geom.Clear();
+  geom.BuildEdges();
+  geom.MakeAtlas(mesh);
+  geom.CalcFaceNums();
+  geom.AddFaceEdges();
+  geom.LinkEdges();
+
+  int i;
+  mesh.ClearFaceDescriptors();
+  for (i = 1; i <= geom.GetNOFaces(); i++)
+    mesh.AddFaceDescriptor (FaceDescriptor (i, 1, 0, 0));
+}
+
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//+++++++++++++++++++   STL GEOMETRY   ++++++++++++++++++++++++++++
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+
+STLGeometry :: STLGeometry()
+  : edges(), edgesperpoint(),
+    normals(),  externaledges(),
+    atlas(), chartmark(), 
+    lines(), outerchartspertrig(), vicinity(), markedtrigs(), markedsegs(),
+    lineendpoints(), spiralpoints(), edgedata(*this), selectedmultiedge()
+{
+  externaledges.SetSize(0);
+  Clear();
+  meshchart = 0; // initialize all ?? JS
+
+  if (geomsearchtreeon)
+    searchtree = new Box3dTree (GetBoundingBox().PMin() - Vec3d(1,1,1),
+				GetBoundingBox().PMax() + Vec3d(1,1,1));
+  else
+    searchtree = NULL;
+
+  status = STL_GOOD;
+  statustext = "Good Geometry";
+  smoothedges = NULL;
+}
+
+STLGeometry :: ~STLGeometry()
+{
+  ;
+}
+
+void STLGeometry :: STLInfo(double* data)
+{
+  data[0] = GetNT();
+
+  Box<3> b = GetBoundingBox();
+  data[1] = b.PMin()(0);
+  data[2] = b.PMax()(0);
+  data[3] = b.PMin()(1);
+  data[4] = b.PMax()(1);
+  data[5] = b.PMin()(2);
+  data[6] = b.PMax()(2);
+
+  int i;
+ 
+  int cons = 1;
+  for (i = 1; i <= GetNT(); i++)
+    {
+      if (NONeighbourTrigs(i) != 3) {cons = 0;}
+    }
+  data[7] = cons;
+}
+
+void STLGeometry :: MarkNonSmoothNormals()
+{
+
+  PrintFnStart("Mark Non-Smooth Normals");
+
+  int i,j;
+
+  markedtrigs.SetSize(GetNT());
+
+  for (i = 1; i <= GetNT(); i++)
+    {
+      SetMarkedTrig(i, 0);
+    }
+
+  double dirtyangle = stlparam.yangle/180.*M_PI;
+
+  int cnt = 0;
+  int p1,p2;
+  for (i = 1; i <= GetNT(); i++)
+    {
+      for (j = 1; j <= NONeighbourTrigs(i); j++)
+	{
+	  if (GetAngle(i, NeighbourTrig(i,j)) > dirtyangle)
+	    {
+	      GetTriangle(i).GetNeighbourPoints(GetTriangle(NeighbourTrig(i,j)), p1, p2);
+	      if (!IsEdge(p1,p2))
+		{
+		  if (!IsMarkedTrig(i)) {SetMarkedTrig(i,1); cnt++;}
+		}
+	    }
+	}
+    }
+
+  PrintMessage(5,"marked ",cnt," non-smooth trig-normals");
+
+}
+
+void STLGeometry :: SmoothNormals()
+{
+  multithread.terminate = 0;
+
+  //  UseExternalEdges();
+
+  BuildEdges();
+
+
+  DenseMatrix m(3), hm(3);
+  Vector rhs(3), sol(3), hv(3), hv2(3);
+
+  Vec<3> ri;
+
+  double wnb = stldoctor.smoothnormalsweight;   // neigbour normal weight
+  double wgeom = 1-wnb;   // geometry normal weight
+
+
+  // minimize 
+  //  wgeom sum_T  \sum ri  \| ri^T (n - n_geom) \|^2  
+  //  + wnb sum_SE  \| ri x (n - n_nb) \|^2
+  
+  int i, j, k, l;
+  int nt = GetNT();
+  
+  PushStatusF("Smooth Normals");
+    
+  int testmode;
+
+  for (i = 1; i <= nt; i++)
+    {
+
+      SetThreadPercent( 100.0 * (double)i / (double)nt);
+
+      const STLTriangle & trig = GetTriangle (i);
+      
+      m = 0;
+      rhs = 0;
+
+      // normal of geometry:
+      Vec<3> ngeom = trig.GeomNormal(points);
+      ngeom.Normalize();
+
+      for (j = 1; j <= 3; j++)
+	{ 
+	  int pi1 = trig.PNumMod (j);
+	  int pi2 = trig.PNumMod (j+1);
+
+	  // edge vector
+	  ri = GetPoint (pi2) - GetPoint (pi1);
+	  
+	  for (k = 0; k < 3; k++)
+	    for (l = 0; l < 3; l++)
+	      hm.Elem(k+1, l+1) = wgeom * ri(k) * ri(l);
+	  
+	  
+	  for (k = 0; k < 3; k++)
+	    hv.Elem(k+1) = ngeom(k);
+	  
+	  hm.Mult (hv, hv2);
+	  /*
+	  if (testmode)
+	    (*testout) << "add vec " << hv2 << endl 
+		       << " add m " << hm << endl;
+	  */
+	  rhs.Add (1, hv2);
+	  m += hm;
+
+
+	  int nbt = 0;
+	  int fp1,fp2;
+	  for (k = 1; k <= NONeighbourTrigs(i); k++)
+	    {
+	      trig.GetNeighbourPoints(GetTriangle(NeighbourTrig(i, k)),fp1,fp2);
+	      if (fp1 == pi1 && fp2 == pi2)
+		{
+		  nbt = NeighbourTrig(i, k);
+		}
+	    }
+
+	  if (!nbt)
+	    {
+	      cerr << "ERROR: stlgeom::Smoothnormals, nbt = 0" << endl;
+	    }
+
+	  // smoothed normal
+	  Vec<3> nnb = GetTriangle(nbt).Normal();   // neighbour normal
+	  nnb.Normalize();
+
+	  if (!IsEdge(pi1,pi2)) 
+	    {
+	      double lr2 = ri * ri;
+	      for (k = 0; k < 3; k++)
+		{
+		  for (l = 0; l < k; l++)
+		    {
+		      hm.Elem(k+1, l+1) = -wnb * ri(k) * ri(l);
+		      hm.Elem(l+1, k+1) = -wnb * ri(k) * ri(l);
+		    }
+		  
+		  hm.Elem(k+1, k+1) = wnb * (lr2 - ri(k) * ri(k));
+		}
+	      
+	      for (k = 0; k < 3; k++)
+		hv.Elem(k+1) = nnb(k);
+	      
+	      hm.Mult (hv, hv2);
+	      /*
+	      if (testmode)
+		(*testout) << "add nb vec " << hv2 << endl 
+			   << " add nb m " << hm << endl;
+	      */
+
+	      rhs.Add (1, hv2);
+	      m += hm;
+	    }
+	}
+
+      m.Solve (rhs, sol);
+      Vec3d newn(sol.Get(1), sol.Get(2), sol.Get(3));
+      newn /= (newn.Length() + 1e-24);      
+
+      GetTriangle(i).SetNormal(newn);
+      // setnormal (sol);
+    }
+
+  /*
+  for (i = 1; i <= nt; i++)
+    SetMarkedTrig(i, 0);      		
+
+
+
+  int crloop;
+  for (crloop = 1; crloop <= 3; crloop++)
+    {
+
+  // find critical:
+
+  ARRAY<INDEX_2> critpairs;
+  for (i = 1; i <= nt; i++)
+    {
+      const STLTriangle & trig = GetTriangle (i);
+      
+      Vec3d ngeom = GetTriangleNormal (i); // trig.Normal(points);
+      ngeom /= (ngeom.Length() + 1e-24);
+
+      for (j = 1; j <= 3; j++)
+	{ 
+	  int pi1 = trig.PNumMod (j);
+	  int pi2 = trig.PNumMod (j+1);
+
+	  int nbt = 0;
+	  int fp1,fp2;
+	  for (k = 1; k <= NONeighbourTrigs(i); k++)
+	    {
+	      trig.GetNeighbourPoints(GetTriangle(NeighbourTrig(i, k)),fp1,fp2);
+	      if (fp1 == pi1 && fp2 == pi2)
+		{
+		  nbt = NeighbourTrig(i, k);
+		}
+	    }
+	  
+	  if (!nbt)
+	    {
+	      cerr << "ERROR: stlgeom::Smoothnormals, nbt = 0" << endl;
+	    }
+
+	  Vec3d nnb = GetTriangleNormal(nbt);   // neighbour normal
+	  nnb /= (nnb.Length() + 1e-24);
+
+	  if (!IsEdge(pi1,pi2)) 
+	    {
+	      if (Angle (nnb, ngeom) > 150 * M_PI/180)
+		{
+		  SetMarkedTrig(i, 1);      		
+		  SetMarkedTrig(nbt, 1);      		
+		  critpairs.Append (INDEX_2 (i, nbt));
+		}
+	    }
+
+	}
+    }
+
+  if (!critpairs.Size())
+    {
+      break;
+    }
+
+  if (critpairs.Size())
+    {
+
+      ARRAY<int> friends;
+      double area1 = 0, area2 = 0;
+
+      for (i = 1; i <= critpairs.Size(); i++)
+	{
+	  int tnr1 = critpairs.Get(i).I1();
+	  int tnr2 = critpairs.Get(i).I2();
+	  (*testout) << "t1 = " << tnr1 << ", t2 = " << tnr2
+		     << " angle = " << Angle (GetTriangleNormal (tnr1),
+					      GetTriangleNormal (tnr2))
+		     << endl;
+
+	  // who has more friends ?
+	  int side;
+	  area1 = 0;
+	  area2 = 0;
+	  for (side = 1; side <= 2; side++)
+	    {
+	      friends.SetSize (0);
+	      friends.Append ( (side == 1) ? tnr1 : tnr2);
+
+	      for (j = 1; j <= 3; j++)
+		{
+		  int fsize = friends.Size();
+		  for (k = 1; k <= fsize; k++)
+		    {
+		      int testtnr = friends.Get(k);
+		      Vec3d ntt = GetTriangleNormal(testtnr);
+		      ntt /= (ntt.Length() + 1e-24);
+		      
+		      for (l = 1; l <= NONeighbourTrigs(testtnr); l++)
+			{
+			  int testnbnr = NeighbourTrig(testtnr, l);
+			  Vec3d nbt = GetTriangleNormal(testnbnr);
+			  nbt /= (nbt.Length() + 1e-24);
+
+			  if (Angle (nbt, ntt) < 15 * M_PI/180)
+			    {
+			      int ii;
+			      int found = 0;
+			      for (ii = 1; ii <= friends.Size(); ii++)
+				{
+				  if (friends.Get(ii) == testnbnr)
+				    {
+				      found = 1;
+				      break;
+				    }
+				}
+			      if (!found)
+				friends.Append (testnbnr);
+			    }
+			}
+		    }
+		}
+
+	      // compute area:
+	      for (k = 1; k <= friends.Size(); k++)
+		{
+		  double area = 
+		    GetTriangle (friends.Get(k)).Area(points);
+
+		  if (side == 1)
+		    area1 += area;
+		  else
+		    area2 += area;
+		}
+	      
+	    }
+
+	  (*testout) << "area1 = " << area1 << " area2 = " << area2 << endl;
+	  if (area1 < 0.1 * area2)
+	    {
+	      Vec3d n = GetTriangleNormal (tnr1);
+	      n *= -1;
+	      SetTriangleNormal(tnr1, n);
+	    }
+	  if (area2 < 0.1 * area1)
+	    {
+	      Vec3d n = GetTriangleNormal (tnr2);
+	      n *= -1;
+	      SetTriangleNormal(tnr2, n);
+	    }
+	}
+    }
+    }
+  */
+
+  calcedgedataanglesnew = 1;
+  PopStatus();
+}
+
+
+int STLGeometry :: AddEdge(int p1, int p2)
+{
+  STLEdge e(p1,p2);
+  e.SetLeftTrig(GetLeftTrig(p1,p2));
+  e.SetRightTrig(GetRightTrig(p1,p2));
+  return edges.Append(e);
+}
+
+void STLGeometry :: STLDoctorConfirmEdge()
+{
+  StoreEdgeData();
+  if (GetSelectTrig() >= 1 && GetSelectTrig() <= GetNT() && GetNodeOfSelTrig())
+    {
+      if (stldoctor.selectmode == 1)
+	{
+	  int p1 = GetTriangle(GetSelectTrig()).PNum(GetNodeOfSelTrig());
+	  int p2 = GetTriangle(GetSelectTrig()).PNumMod(GetNodeOfSelTrig()+1);
+	  edgedata.Elem(edgedata.GetEdgeNum(p1,p2)).SetStatus (ED_CONFIRMED);
+	}
+      else if (stldoctor.selectmode == 3 || stldoctor.selectmode == 4)
+	{
+	  int i;
+	  for (i = 1; i <= selectedmultiedge.Size(); i++)
+	    {
+	      int p1 = selectedmultiedge.Get(i).i1;
+	      int p2 = selectedmultiedge.Get(i).i2;
+	      edgedata.Elem(edgedata.GetEdgeNum(p1,p2)).SetStatus (ED_CONFIRMED);
+	    }
+	}
+    }
+}
+
+void STLGeometry :: STLDoctorCandidateEdge()
+{
+  StoreEdgeData();
+  if (GetSelectTrig() >= 1 && GetSelectTrig() <= GetNT() && GetNodeOfSelTrig())
+    {
+      if (stldoctor.selectmode == 1)
+	{
+	  int p1 = GetTriangle(GetSelectTrig()).PNum(GetNodeOfSelTrig());
+	  int p2 = GetTriangle(GetSelectTrig()).PNumMod(GetNodeOfSelTrig()+1);
+	  edgedata.Elem(edgedata.GetEdgeNum(p1,p2)).SetStatus (ED_CANDIDATE);
+	}
+      else if (stldoctor.selectmode == 3 || stldoctor.selectmode == 4)
+	{
+	  int i;
+	  for (i = 1; i <= selectedmultiedge.Size(); i++)
+	    {
+	      int p1 = selectedmultiedge.Get(i).i1;
+	      int p2 = selectedmultiedge.Get(i).i2;
+	      edgedata.Elem(edgedata.GetEdgeNum(p1,p2)).SetStatus (ED_CANDIDATE);
+	    }
+	}
+    }
+}
+
+void STLGeometry :: STLDoctorExcludeEdge()
+{
+  StoreEdgeData();
+  if (GetSelectTrig() >= 1 && GetSelectTrig() <= GetNT() && GetNodeOfSelTrig())
+    {
+      if (stldoctor.selectmode == 1)
+	{
+	  int p1 = GetTriangle(GetSelectTrig()).PNum(GetNodeOfSelTrig());
+	  int p2 = GetTriangle(GetSelectTrig()).PNumMod(GetNodeOfSelTrig()+1);
+	  edgedata.Elem(edgedata.GetEdgeNum(p1,p2)).SetStatus(ED_EXCLUDED);
+	}
+      else if (stldoctor.selectmode == 3 || stldoctor.selectmode == 4)
+	{
+	  int i;
+	  for (i = 1; i <= selectedmultiedge.Size(); i++)
+	    {
+	      int p1 = selectedmultiedge.Get(i).i1;
+	      int p2 = selectedmultiedge.Get(i).i2;
+	      edgedata.Elem(edgedata.GetEdgeNum(p1,p2)).SetStatus(ED_EXCLUDED);
+	    }
+	}
+    }
+}
+
+void STLGeometry :: STLDoctorUndefinedEdge()
+{
+  StoreEdgeData();
+  if (GetSelectTrig() >= 1 && GetSelectTrig() <= GetNT() && GetNodeOfSelTrig())
+    {
+      if (stldoctor.selectmode == 1)
+	{
+	  int p1 = GetTriangle(GetSelectTrig()).PNum(GetNodeOfSelTrig());
+	  int p2 = GetTriangle(GetSelectTrig()).PNumMod(GetNodeOfSelTrig()+1);
+	  edgedata.Elem(edgedata.GetEdgeNum(p1,p2)).SetStatus(ED_UNDEFINED);
+	}
+      else if (stldoctor.selectmode == 3 || stldoctor.selectmode == 4)
+	{
+	  int i;
+	  for (i = 1; i <= selectedmultiedge.Size(); i++)
+	    {
+	      int p1 = selectedmultiedge.Get(i).i1;
+	      int p2 = selectedmultiedge.Get(i).i2;
+	      edgedata.Elem(edgedata.GetEdgeNum(p1,p2)).SetStatus(ED_UNDEFINED);
+	    }
+	}
+    }
+}
+
+void STLGeometry :: STLDoctorSetAllUndefinedEdges()
+{
+  edgedata.ResetAll();
+}
+
+void STLGeometry :: STLDoctorEraseCandidateEdges()
+{
+  StoreEdgeData();
+  edgedata.ChangeStatus(ED_CANDIDATE, ED_UNDEFINED);
+}
+
+void STLGeometry :: STLDoctorConfirmCandidateEdges()
+{
+  StoreEdgeData();
+  edgedata.ChangeStatus(ED_CANDIDATE, ED_CONFIRMED);
+}
+
+void STLGeometry :: STLDoctorConfirmedToCandidateEdges()
+{
+  StoreEdgeData();
+  edgedata.ChangeStatus(ED_CONFIRMED, ED_CANDIDATE);
+}
+
+void STLGeometry :: STLDoctorDirtyEdgesToCandidates()
+{
+  StoreEdgeData();
+}
+
+void STLGeometry :: STLDoctorLongLinesToCandidates()
+{
+  StoreEdgeData();
+}
+
+twoint STLGeometry :: GetNearestSelectedDefinedEdge()
+{
+  Point<3> pestimate = Center(GetTriangle(GetSelectTrig()).center,
+  			     GetPoint(GetTriangle(GetSelectTrig()).PNum(GetNodeOfSelTrig())));
+    //Point3d pestimate = GetTriangle(GetSelectTrig()).center;
+
+  int i, j, en;
+  ARRAY<int> vic;
+  GetVicinity(GetSelectTrig(),4,vic);
+  
+
+  twoint fedg;
+  fedg.i1 = 0;
+  fedg.i2 = 0;
+  double mindist = 1E50;
+  double dist;
+  Point<3> p;
+
+  for (i = 1; i <= vic.Size(); i++)
+  {
+    const STLTriangle& t = GetTriangle(vic.Get(i));
+    for (j = 1; j <= 3; j++)
+      {
+	en = edgedata.GetEdgeNum(t.PNum(j),t.PNumMod(j+1));
+	if (edgedata.Get(en).GetStatus() != ED_UNDEFINED)
+	  {
+	    p = pestimate;
+	    dist = GetDistFromLine(GetPoint(t.PNum(j)),GetPoint(t.PNumMod(j+1)),p);
+	    if (dist < mindist)
+	      {
+		mindist = dist;
+		fedg.i1 = t.PNum(j);
+		fedg.i2 = t.PNumMod(j+1);
+	      }
+	  }
+      }
+  }
+  return fedg;
+}
+ 
+void STLGeometry :: BuildSelectedMultiEdge(twoint ep)
+{
+  if (edgedata.Size() == 0 || 
+      !GetEPPSize()) 
+    {
+      return; 
+    }
+
+  selectedmultiedge.SetSize(0);
+  int tenum = GetTopEdgeNum (ep.i1, ep.i2);
+
+  if (edgedata.Get(tenum).GetStatus() == ED_UNDEFINED)
+    {
+      twoint epnew = GetNearestSelectedDefinedEdge();
+      if (epnew.i1) 
+	{
+	  ep = epnew;
+	  tenum = GetTopEdgeNum (ep.i1, ep.i2);
+	}
+    }
+
+  selectedmultiedge.Append(twoint(ep));
+
+  if (edgedata.Get(tenum).GetStatus() == ED_UNDEFINED)
+    {
+      return;
+    }
+
+  edgedata.BuildLineWithEdge(ep.i1,ep.i2,selectedmultiedge);
+}
+
+void STLGeometry :: BuildSelectedEdge(twoint ep)
+{
+  if (edgedata.Size() == 0 || 
+      !GetEPPSize()) 
+    {
+      return; 
+    }
+
+  selectedmultiedge.SetSize(0);
+
+  selectedmultiedge.Append(twoint(ep));
+}
+
+void STLGeometry :: BuildSelectedCluster(twoint ep)
+{
+  if (edgedata.Size() == 0 || 
+      !GetEPPSize()) 
+    {
+      return; 
+    }
+
+  selectedmultiedge.SetSize(0);
+
+  int tenum = GetTopEdgeNum (ep.i1, ep.i2);
+
+  if (edgedata.Get(tenum).GetStatus() == ED_UNDEFINED)
+    {
+      twoint epnew = GetNearestSelectedDefinedEdge();
+      if (epnew.i1) 
+	{
+	  ep = epnew;
+	  tenum = GetTopEdgeNum (ep.i1, ep.i2);
+	}
+    }
+
+  selectedmultiedge.Append(twoint(ep));
+
+  if (edgedata.Get(tenum).GetStatus() == ED_UNDEFINED)
+    {
+      return;
+    }
+
+  edgedata.BuildClusterWithEdge(ep.i1,ep.i2,selectedmultiedge);
+}
+
+void STLGeometry :: ImportEdges()
+{
+  StoreEdgeData();
+
+  PrintMessage(5, "import edges from file 'edges.ng'");
+  ifstream fin("edges.ng");
+
+  int ne;
+  fin >> ne;
+
+  ARRAY<Point<3> > eps;
+
+  int i;
+  Point<3> p;
+  for (i = 1; i <= 2*ne; i++)
+    {
+      fin >> p(0); 
+      fin >> p(1); 
+      fin >> p(2);
+      eps.Append(p);
+    }
+  AddEdges(eps);
+}
+
+void STLGeometry :: AddEdges(const ARRAY<Point<3> >& eps)
+{
+  int i;
+  int ne = eps.Size()/2;
+  
+  ARRAY<int> epsi;
+  Box<3> bb = GetBoundingBox();
+  bb.Increase(1);
+
+  Point3dTree pointtree (bb.PMin(), 
+			 bb.PMax());
+  ARRAY<int> pintersect;
+
+  double gtol = GetBoundingBox().Diam()/1.E10;
+  Point<3> p;
+
+  for (i = 1; i <= GetNP(); i++)
+    {
+      p = GetPoint(i);
+      pointtree.Insert (p, i);
+    }
+  
+  int error = 0;
+  for (i = 1; i <= 2*ne; i++)
+    {
+      p = eps.Get(i);
+      Point3d pmin = p - Vec3d (gtol, gtol, gtol);
+      Point3d pmax = p + Vec3d (gtol, gtol, gtol);
+	  
+      pointtree.GetIntersecting (pmin, pmax, pintersect);
+      if (pintersect.Size() > 1)
+	{
+	  PrintError("Found too much points in epsilon-dist");
+	  error = 1;
+	}
+      else if (pintersect.Size() == 0)
+	{
+	  error = 1;
+	  PrintError("edgepoint does not exist!");
+	  PrintMessage(5,"p=",Point3d(eps.Get(i)));
+	}
+      else
+	{
+	  epsi.Append(pintersect.Get(1));
+	}
+    }
+
+  if (error) return;
+
+  int en;
+  for (i = 1; i <= ne; i++)
+    {
+      if (epsi.Get(2*i-1) == epsi.Get(2*i)) {PrintError("Edge with zero length!");}
+      else 
+	{
+	  en = edgedata.GetEdgeNum(epsi.Get(2*i-1),epsi.Get(2*i));
+	  edgedata.Elem(en).SetStatus (ED_CONFIRMED);
+	}
+    }
+
+}
+
+
+
+void STLGeometry :: ImportExternalEdges(const char * filename)
+{
+  //AVL edges!!!!!!
+
+  ifstream inf (filename);
+  char ch;
+  int cnt = 0;
+  int records, units, i, j;
+  PrintFnStart("Import edges from ",filename);
+  
+  const int flen=30;
+  char filter[flen+1];
+  filter[flen] = 0;
+  char buf[20];
+
+  ARRAY<Point3d> importpoints;
+  ARRAY<int> importlines;
+  ARRAY<int> importpnums;
+
+  while (inf.good())
+    {
+      inf.get(ch);
+      //      (*testout) << cnt << ": " << ch << endl;
+      
+      for (i = 0; i < flen; i++)
+	filter[i] = filter[i+1];
+      filter[flen-1] = ch;
+      //      (*testout) << filter << endl;
+
+      if (strcmp (filter+flen-7, "RECORDS") == 0)
+	{
+	  inf.get(ch);  // '='
+	  inf >> records;
+	}
+      if (strcmp (filter+flen-5, "UNITS") == 0)
+	{
+	  inf.get(ch);  // '='
+	  inf >> units;
+	}
+
+      if (strcmp (filter+flen-17, "EDGE NODE NUMBERS") == 0)
+	{
+	  int nodenr;
+	  importlines.SetSize (units);
+	  for (i = 1; i <= units; i++)
+	    {
+	      inf >> nodenr;
+	      importlines.Elem(i) = nodenr;
+	      //	      (*testout) << nodenr << endl;
+	    }
+	}
+
+      if (strcmp (filter+flen-23, "EDGE POINT COORD IN DIR") == 0)
+	{
+	  int coord;
+
+	  inf >> coord;
+	  
+	  importpoints.SetSize (units);
+
+	  inf >> ch;
+	  inf.putback (ch);
+
+	  int nodenr;
+	  for (i = 1; i <= units; i++)
+	    {
+	      for (j = 0; j < 12; j++)
+		inf.get (buf[j]);
+	      buf[12] = 0;
+
+	      importpoints.Elem(i).X(coord) = 1000 * atof (buf);
+	    }
+	}
+    }
+
+  /*
+  (*testout) << "lines: " << endl;
+  for (i = 1; i <= importlines.Size(); i++)
+    (*testout) << importlines.Get(i) << endl;
+  (*testout) << "points: " << endl;
+  for (i = 1; i <= importpoints.Size(); i++)
+    (*testout) << importpoints.Get(i) << endl;
+  */
+
+
+
+  importpnums.SetSize (importpoints.Size());
+  
+
+  Box3d bb (GetBoundingBox().PMin() + Vec3d (-1,-1,-1),
+	    GetBoundingBox().PMax() + Vec3d (1, 1, 1));
+
+  Point3dTree pointtree (bb.PMin(), 
+			 bb.PMax());
+
+
+  PrintMessage(7,"stl - bb: ",bb.PMin(), " - ", bb.PMax());
+  
+  Box3d ebb;
+  ebb.SetPoint (importpoints.Get(1));
+  for (i = 1; i <= importpoints.Size(); i++)
+    ebb.AddPoint (importpoints.Get(i));
+  PrintMessage(7,"edgep - bb: ", ebb.PMin(), " - ", ebb.PMax());
+
+  ARRAY<int> pintersect;
+
+  double gtol = GetBoundingBox().Diam()/1.E6;
+
+  for (i = 1; i <= GetNP(); i++)
+    {
+      Point3d p = GetPoint(i);
+      //      (*testout) << "stlpt: " << p << endl;
+      pointtree.Insert (p, i);
+    }
+  
+
+  for (i = 1; i <= importpoints.Size(); i++)
+    {
+      Point3d p = importpoints.Get(i);
+      Point3d pmin = p - Vec3d (gtol, gtol, gtol);
+      Point3d pmax = p + Vec3d (gtol, gtol, gtol);
+	  
+      pointtree.GetIntersecting (pmin, pmax, pintersect);
+      if (pintersect.Size() > 1)
+	{
+	  importpnums.Elem(i) = 0;
+	  PrintError("Found too many points in epsilon-dist");
+	}
+      else if (pintersect.Size() == 0)
+	{
+	  importpnums.Elem(i) = 0;
+	  PrintError("Edgepoint does not exist!");
+	}
+      else
+	{
+	  importpnums.Elem(i) = pintersect.Get(1);
+	}
+    }
+
+  //  if (!error) 
+    {
+      PrintMessage(7,"found all edge points in stl file");
+
+
+      StoreEdgeData();
+
+      int oldp = 0;
+
+      for (i = 1; i <= importlines.Size(); i++)
+	{
+	  int newp = importlines.Get(i);
+	  if (!importpnums.Get(abs(newp)))
+	    newp = 0;
+
+	  if (oldp && newp)
+	    {
+	      int en = edgedata.GetEdgeNum(importpnums.Get(oldp), 
+					   importpnums.Get(abs(newp)));
+	      edgedata.Elem(en).SetStatus (ED_CONFIRMED);
+	    }
+	  
+	  if (newp < 0)
+	    oldp = 0;
+	  else
+	    oldp = newp;
+	}
+    }
+
+
+}
+
+
+
+void STLGeometry :: ExportEdges()
+{
+  PrintFnStart("Save edges to file 'edges.ng'");
+
+  ofstream fout("edges.ng");
+  fout.precision(16);
+
+  int n = edgedata.GetNConfEdges();
+  
+  fout << n << endl;
+
+  int i;
+  for (i = 1; i <= edgedata.Size(); i++)
+    {
+      if (edgedata.Get(i).GetStatus() == ED_CONFIRMED)
+	{
+	  const STLTopEdge & e = edgedata.Get(i);
+	  fout << GetPoint(e.PNum(1))(0) << " " << GetPoint(e.PNum(1))(1) << " " << GetPoint(e.PNum(1))(2) << endl;
+	  fout << GetPoint(e.PNum(2))(0) << " " << GetPoint(e.PNum(2))(1) << " " << GetPoint(e.PNum(2))(2) << endl;
+	}
+    }
+
+}
+
+void STLGeometry :: LoadEdgeData(const char* file)
+{
+  StoreEdgeData();
+
+  PrintFnStart("Load edges from file '", file, "'");
+  ifstream fin(file);
+
+  edgedata.Read(fin);
+
+  //  calcedgedataanglesnew = 1;
+}
+
+void STLGeometry :: SaveEdgeData(const char* file)
+{
+  PrintFnStart("save edges to file '", file, "'");
+  ofstream fout(file);
+
+  edgedata.Write(fout);
+}
+
+
+
+
+
+
+
+/*
+void STLGeometry :: SaveExternalEdges()
+{
+  ofstream fout("externaledgesp3.ng");
+  fout.precision(16);
+
+  int n = NOExternalEdges();
+  fout << n << endl;
+
+  int i;
+  for (i = 1; i <= n; i++)
+    {
+      twoint e = GetExternalEdge(i);
+      fout << GetPoint(e.i1)(0) << " " << GetPoint(e.i1)(1) << " " << GetPoint(e.i1)(2) << endl;
+      fout << GetPoint(e.i2)(0) << " " << GetPoint(e.i2)(1) << " " << GetPoint(e.i2)(2) << endl;
+    }
+
+}
+*/
+void STLGeometry :: StoreExternalEdges()
+{
+  storedexternaledges.SetSize(0);
+  undoexternaledges = 1;
+  int i;
+  for (i = 1; i <= externaledges.Size(); i++)
+    {
+      storedexternaledges.Append(externaledges.Get(i));      
+    }
+
+}
+
+void STLGeometry :: UndoExternalEdges()
+{
+  if (!undoexternaledges) 
+    {
+      PrintMessage(1, "undo not further possible!");
+      return;
+    }
+  RestoreExternalEdges();
+  undoexternaledges = 0;
+}
+
+void STLGeometry :: RestoreExternalEdges()
+{
+  externaledges.SetSize(0);
+  int i;
+  for (i = 1; i <= storedexternaledges.Size(); i++)
+    {
+      externaledges.Append(storedexternaledges.Get(i));      
+    }
+
+}
+
+
+void STLGeometry :: AddExternalEdgeAtSelected()
+{
+  StoreExternalEdges();
+  if (GetSelectTrig() >= 1 && GetSelectTrig() <= GetNT())
+    {
+      int p1 = GetTriangle(GetSelectTrig()).PNum(GetNodeOfSelTrig());
+      int p2 = GetTriangle(GetSelectTrig()).PNumMod(GetNodeOfSelTrig()+1);
+      if (!IsExternalEdge(p1,p2)) {AddExternalEdge(p1,p2);}
+    }
+}
+
+void STLGeometry :: AddClosedLinesToExternalEdges()
+{
+  StoreExternalEdges();
+
+  int i, j;
+  for (i = 1; i <= GetNLines(); i++)
+    {
+      STLLine* l = GetLine(i);
+      if (l->StartP() == l->EndP()) 
+	{
+	  for (j = 1; j < l->NP(); j++)
+	    {
+	      int p1 = l->PNum(j);
+	      int p2 = l->PNum(j+1);
+
+	      if (!IsExternalEdge(p1,p2)) {AddExternalEdge(p1,p2);}	      
+	    }
+	}
+    }
+}
+
+void STLGeometry :: AddLongLinesToExternalEdges()
+{
+  StoreExternalEdges();
+
+  double diamfact = stldoctor.dirtytrigfact;
+  double diam = GetBoundingBox().Diam();
+
+  int i, j;
+  for (i = 1; i <= GetNLines(); i++)
+    {
+      STLLine* l = GetLine(i);
+      if (l->GetLength(points) >= diamfact*diam) 
+	{
+	  for (j = 1; j < l->NP(); j++)
+	    {
+	      int p1 = l->PNum(j);
+	      int p2 = l->PNum(j+1);
+
+	      if (!IsExternalEdge(p1,p2)) {AddExternalEdge(p1,p2);}	      
+	    }
+	}
+    }
+}
+
+void STLGeometry :: AddAllNotSingleLinesToExternalEdges()
+{
+  StoreExternalEdges();
+
+  int i, j;
+  for (i = 1; i <= GetNLines(); i++)
+    {
+      STLLine* l = GetLine(i);
+      if (GetNEPP(l->StartP()) > 1 || GetNEPP(l->EndP()) > 1) 
+	{
+	  for (j = 1; j < l->NP(); j++)
+	    {
+	      int p1 = l->PNum(j);
+	      int p2 = l->PNum(j+1);
+
+	      if (!IsExternalEdge(p1,p2)) {AddExternalEdge(p1,p2);}	      
+	    }
+	}
+    }
+}
+
+void STLGeometry :: DeleteDirtyExternalEdges()
+{
+  //delete single triangle edges and single edge-lines in clusters"
+  StoreExternalEdges();
+
+  int i, j;
+  for (i = 1; i <= GetNLines(); i++)
+    {
+      STLLine* l = GetLine(i);
+      if (l->NP() <= 3 || (l->StartP() == l->EndP() && l->NP() == 4))
+	{
+	  for (j = 1; j < l->NP(); j++)
+	    {
+	      int p1 = l->PNum(j);
+	      int p2 = l->PNum(j+1);
+
+	      if (IsExternalEdge(p1,p2)) {DeleteExternalEdge(p1,p2);}	      
+	    }
+	}
+    }
+}
+
+void STLGeometry :: AddExternalEdgesFromGeomLine()
+{
+  StoreExternalEdges();
+  if (GetSelectTrig() >= 1 && GetSelectTrig() <= GetNT())
+    {
+      int p1 = GetTriangle(GetSelectTrig()).PNum(GetNodeOfSelTrig());
+      int p2 = GetTriangle(GetSelectTrig()).PNumMod(GetNodeOfSelTrig()+1);
+
+      if (IsEdge(p1,p2))
+	{
+	  int edgenum = IsEdgeNum(p1,p2);
+	  if (!IsExternalEdge(p1,p2)) {AddExternalEdge(p1,p2);}
+	  
+	  int noend = 1;
+	  int startp = p1;
+	  int laste = edgenum;
+	  int np1, np2;
+	  while (noend)
+	    {
+	      if (GetNEPP(startp) == 2)
+		{
+		  if (GetEdgePP(startp,1) != laste) {laste = GetEdgePP(startp,1);}
+		  else {laste = GetEdgePP(startp,2);}
+		  np1 = GetEdge(laste).PNum(1);
+		  np2 = GetEdge(laste).PNum(2);
+		  
+		  if (!IsExternalEdge(np1, np2)) {AddExternalEdge(np1, np2);}
+		  else {noend = 0;}
+		  if (np1 != startp) {startp = np1;}
+		  else {startp = np2;}
+		}
+	      else {noend = 0;}
+	    }
+
+	  startp = p2;
+	  laste = edgenum;
+	  noend = 1;
+	  while (noend)
+	    {
+	      if (GetNEPP(startp) == 2)
+		{
+		  if (GetEdgePP(startp,1) != laste) {laste = GetEdgePP(startp,1);}
+		  else {laste = GetEdgePP(startp,2);}
+		  np1 = GetEdge(laste).PNum(1);
+		  np2 = GetEdge(laste).PNum(2);
+		  
+		  if (!IsExternalEdge(np1, np2)) {AddExternalEdge(np1, np2);}
+		  else {noend = 0;}
+		  if (np1 != startp) {startp = np1;}
+		  else {startp = np2;}
+		}
+	      else {noend = 0;}
+	    }
+	  
+	}
+
+    }
+  
+}
+
+void STLGeometry :: ClearEdges()
+{
+  edgesfound = 0;
+  edges.SetSize(0);
+  //edgedata.SetSize(0);
+  // externaledges.SetSize(0);
+  edgesperpoint.SetSize(0);
+  undoexternaledges = 0;
+
+}
+
+void STLGeometry :: STLDoctorBuildEdges()
+{
+  //  if (!trigsconverted) {return;}
+  ClearEdges();
+
+  meshlines.SetSize(0);
+  FindEdgesFromAngles();
+}
+
+void STLGeometry :: DeleteExternalEdgeAtSelected()
+{
+  StoreExternalEdges();
+  if (GetSelectTrig() >= 1 && GetSelectTrig() <= GetNT())
+    {
+      int p1 = GetTriangle(GetSelectTrig()).PNum(GetNodeOfSelTrig());
+      int p2 = GetTriangle(GetSelectTrig()).PNumMod(GetNodeOfSelTrig()+1);
+      if (IsExternalEdge(p1,p2)) {DeleteExternalEdge(p1,p2);}
+    }
+}
+
+void STLGeometry :: DeleteExternalEdgeInVicinity()
+{
+  StoreExternalEdges();
+  if (!stldoctor.showvicinity || vicinity.Size() != GetNT()) {return;}
+
+  int i, j, k, p1, p2;
+  
+  for (i = 1; i <= GetNT(); i++)
+    {
+      if (vicinity.Elem(i))
+	{
+	  for (j = 1; j <= 3; j++)
+	    {
+	      p1 = GetTriangle(i).PNum(j);
+	      p2 = GetTriangle(i).PNumMod(j+1);
+
+	      if (IsExternalEdge(p1,p2))
+		{
+		  DeleteExternalEdge(p1,p2);
+		}
+	    }
+	}
+    }
+}
+
+void STLGeometry :: BuildExternalEdgesFromEdges()
+{
+  StoreExternalEdges();
+
+  if (GetNE() == 0) {PrintWarning("Edges possibly not generated!");}
+
+  int i, p1, p2;
+  externaledges.SetSize(0);
+
+  for (i = 1; i <= GetNE(); i++)
+    {
+      STLEdge e = GetEdge(i);
+      AddExternalEdge(e.PNum(1), e.PNum(2));
+    }
+
+}
+
+
+void STLGeometry :: AddExternalEdge(int p1, int p2)
+{
+  externaledges.Append(twoint(p1,p2));
+}
+
+void STLGeometry :: DeleteExternalEdge(int p1, int p2)
+{
+
+  int i;
+  int found = 0;
+  for (i = 1; i <= NOExternalEdges(); i++)
+    {
+      if ((GetExternalEdge(i).i1 == p1 && GetExternalEdge(i).i2 == p2) ||
+	  (GetExternalEdge(i).i1 == p2 && GetExternalEdge(i).i2 == p1)) {found = 1;};
+      if (found && i < NOExternalEdges())
+	{
+	  externaledges.Elem(i) = externaledges.Get(i+1);
+	}
+    }
+  if (!found) {PrintWarning("edge not found");}
+  else
+    {
+      externaledges.SetSize(externaledges.Size()-1);
+    }
+
+}
+
+int STLGeometry :: IsExternalEdge(int p1, int p2)
+{
+  int i;
+  for (i = 1; i <= NOExternalEdges(); i++)
+    {
+      if ((GetExternalEdge(i).i1 == p1 && GetExternalEdge(i).i2 == p2) ||
+	  (GetExternalEdge(i).i1 == p2 && GetExternalEdge(i).i2 == p1)) {return 1;};
+    }
+  return 0;
+}
+
+void STLGeometry :: DestroyDirtyTrigs()
+{
+
+  PrintFnStart("Destroy dirty triangles");
+  PrintMessage(5,"original number of triangles=", GetNT());
+
+  //destroy every triangle with other than 3 neighbours;
+  int changed = 1;
+  int i, j, k;
+  while (changed)
+    {
+      changed = 0;
+      Clear();
+
+      for (i = 1; i <= GetNT(); i++)
+	{
+	  int dirty = NONeighbourTrigs(i) < 3;
+
+	  for (j = 1; j <= 3; j++)
+	    {
+	      int pnum = GetTriangle(i).PNum(j);
+	      /*
+	      if (pnum == 1546)
+		{
+		// for (k = 1; k <=  NOTrigsPerPoint(pnum); k++)
+		}
+	      */
+	      if (NOTrigsPerPoint(pnum) <= 2) 
+		dirty = 1;
+	    }
+	  
+	  int pi1 = GetTriangle(i).PNum(1);
+	  int pi2 = GetTriangle(i).PNum(2);
+	  int pi3 = GetTriangle(i).PNum(3);
+	  if (pi1 == pi2 || pi1 == pi3 || pi2 == pi3)
+	    {
+	      PrintMessage(5,"triangle with Volume 0: ", i, "  nodes: ", pi1, ", ", pi2, ", ", pi3);
+	      dirty = 1;
+	    }
+
+	  if (dirty)
+	    {
+	      for (k = i+1; k <= GetNT(); k++)
+		{
+		  trias.Elem(k-1) = trias.Get(k);
+		  // readtrias: not longer permanent, JS
+		  //		  readtrias.Elem(k-1) = readtrias.Get(k); 
+		}
+	      int size = GetNT();
+	      trias.SetSize(size-1);
+	      //	      readtrias.SetSize(size-1);
+	      changed = 1;
+	      break;
+	    }
+	}
+    }  
+
+  FindNeighbourTrigs();
+  PrintMessage(5,"final number of triangles=", GetNT());
+}
+
+void STLGeometry :: CalcNormalsFromGeometry()
+{
+  int i;
+  for (i = 1; i <= GetNT(); i++)
+    {
+      const STLTriangle & tr = GetTriangle(i);
+      const Point3d& p1 = GetPoint(tr.PNum(1));
+      const Point3d& p2 = GetPoint(tr.PNum(2));
+      const Point3d& p3 = GetPoint(tr.PNum(3));
+
+      Vec3d normal = Cross (p2-p1, p3-p1);
+      
+      if (normal.Length() != 0)
+	{
+	  normal /= (normal.Length());		  
+	}
+      GetTriangle(i).SetNormal(normal);
+    }
+  PrintMessage(5,"Normals calculated from geometry!!!");
+
+  calcedgedataanglesnew = 1;
+}
+
+void STLGeometry :: SetSelectTrig(int trig)
+{
+  stldoctor.selecttrig = trig;
+}
+
+int STLGeometry :: GetSelectTrig() const
+{
+  return stldoctor.selecttrig;
+}
+
+void STLGeometry :: SetNodeOfSelTrig(int n)
+{
+  stldoctor.nodeofseltrig = n;
+}
+
+int STLGeometry :: GetNodeOfSelTrig() const
+{
+  return stldoctor.nodeofseltrig;
+}
+
+void STLGeometry :: MoveSelectedPointToMiddle()
+{
+  if (GetSelectTrig() >= 1 && GetSelectTrig() <= GetNT())
+    {
+      int p = GetTriangle(GetSelectTrig()).PNum(GetNodeOfSelTrig());
+      Point<3> pm(0.,0.,0.); //Middlevector;
+      Point<3> p0(0.,0.,0.);
+      PrintMessage(5,"original point=", Point3d(GetPoint(p)));
+
+      int i;
+      int cnt = 0;
+      for (i = 1; i <= trigsperpoint.EntrySize(p); i++)
+	{
+	  const STLTriangle& tr = GetTriangle(trigsperpoint.Get(p,i));
+	  int j;
+	  for (j = 1; j <= 3; j++)
+	    {
+	      if (tr.PNum(j) != p)
+		{
+		  cnt++;
+		  pm(0) += GetPoint(tr.PNum(j))(0);
+		  pm(1) += GetPoint(tr.PNum(j))(1);
+		  pm(2) += GetPoint(tr.PNum(j))(2);
+		}
+	    }
+	}
+
+      Point<3> origp = GetPoint(p);
+      double fact = 0.2;
+
+      SetPoint(p, p0 + fact*(1./(double)cnt)*(pm-p0)+(1.-fact)*(origp-p0));
+
+      PrintMessage(5,"middle point=", Point3d (GetPoint(p)));
+      
+      PrintMessage(5,"moved point ", Point3d (p));
+
+    }
+}
+
+void STLGeometry :: PrintSelectInfo()
+{
+
+  int trig = GetSelectTrig();
+  int p = GetTriangle(trig).PNum(GetNodeOfSelTrig());
+  
+  PrintMessage(1,"touch triangle ", GetSelectTrig()
+       , ", local node ", GetNodeOfSelTrig()
+       , " (=", GetTriangle(GetSelectTrig()).PNum(GetNodeOfSelTrig()), ")");
+  if (AtlasMade() && GetSelectTrig() >= 1 && GetSelectTrig() <= GetNT())
+    {
+      PrintMessage(1,"           chartnum=",GetChartNr(GetSelectTrig()));
+      /*      
+      PointBetween(Center(Center(GetPoint(GetTriangle(270).PNum(1)),
+				 GetPoint(GetTriangle(270).PNum(2))),
+			  GetPoint(GetTriangle(270).PNum(3))),270,
+		   Center(Center(GetPoint(GetTriangle(trig).PNum(1)),
+				 GetPoint(GetTriangle(trig).PNum(2))),
+			  GetPoint(GetTriangle(trig).PNum(3))),trig);
+      */
+      //PointBetween(Point3d(5.7818, 7.52768, 4.14879),260,Point3d(6.80292, 6.55392, 4.70184),233);
+    }
+}
+
+void STLGeometry :: ShowSelectedTrigChartnum()
+{
+  int st = GetSelectTrig();
+
+  if (st >= 1 && st <= GetNT() && AtlasMade())
+    PrintMessage(1,"selected trig ", st, " has chartnumber ", GetChartNr(st));
+}
+
+void STLGeometry :: ShowSelectedTrigCoords()
+{
+  int st = GetSelectTrig();
+
+  /*
+  //testing!!!!
+  ARRAY<int> trigs;
+  GetSortedTrianglesAroundPoint(GetTriangle(st).PNum(GetNodeOfSelTrig()),st,trigs);
+  */
+
+  if (st >= 1 && st <= GetNT())
+    {
+      PrintMessage(1, "coordinates of selected trig ", st, ":");
+      PrintMessage(1, "   p1 = ", GetTriangle(st).PNum(1), " = ", 
+		   Point3d (GetPoint(GetTriangle(st).PNum(1))));
+      PrintMessage(1, "   p2 = ", GetTriangle(st).PNum(2), " = ", 
+		   Point3d (GetPoint(GetTriangle(st).PNum(2))));
+      PrintMessage(1, "   p3 = ", GetTriangle(st).PNum(3), " = ", 
+		   Point3d (GetPoint(GetTriangle(st).PNum(3))));
+    }
+}
+
+void STLGeometry :: LoadMarkedTrigs()
+{
+  PrintFnStart("load marked trigs from file 'markedtrigs.ng'");
+  ifstream fin("markedtrigs.ng");
+
+  int n;
+  fin >> n;
+  if (n != GetNT() || n == 0) {PrintError("Not a suitable marked-trig-file!"); return;}
+
+  int i, m;
+  for (i = 1; i <= n; i++)
+    {
+      fin >> m;
+      SetMarkedTrig(i, m);      
+    }
+
+  fin >> n;
+  if (n != 0) 
+    {
+      int i, m;
+      Point<3> p1, p2;
+      for (i = 1; i <= n; i++)
+	{
+	  fin >> p1(0); fin >> p1(1); fin >> p1(2);
+	  fin >> p2(0); fin >> p2(1); fin >> p2(2);
+	  AddMarkedSeg(p1,p2);      
+	}
+    }
+}
+
+void STLGeometry :: SaveMarkedTrigs()
+{
+  PrintFnStart("save marked trigs to file 'markedtrigs.ng'");
+  ofstream fout("markedtrigs.ng");
+
+  int n = GetNT();
+  fout << n << endl;
+
+  int i, m;
+  for (i = 1; i <= n; i++)
+    {
+      fout << IsMarkedTrig(i) << "\n";
+    }
+
+  n = GetNMarkedSegs();
+  fout << n << endl;
+
+  Point<3> p1,p2;
+  for (i = 1; i <= n; i++)
+    {
+      GetMarkedSeg(i,p1,p2);
+      fout << p1(0) << " " << p1(1) << " " << p1(2) << "  ";
+      fout << p2(0) << " " << p2(1) << " " << p2(2) << " " << "\n";
+    }
+
+}
+
+void STLGeometry :: NeighbourAnglesOfSelectedTrig()
+{
+  int st = GetSelectTrig();
+
+  if (st >= 1 && st <= GetNT())
+    {
+      int i;
+      PrintMessage(1,"Angle to triangle ", st, ":");
+      for (i = 1; i <= NONeighbourTrigs(st); i++)
+	{
+	  PrintMessage(1,"   triangle ", NeighbourTrig(st,i), ": angle = " 
+	       , 180./M_PI*GetAngle(st, NeighbourTrig(st,i)), "°"
+	       , ", calculated = ", 180./M_PI*Angle(GetTriangle(st).GeomNormal(points), 
+						       GetTriangle(NeighbourTrig(st,i)).GeomNormal(points)), "°");
+	}
+    }
+}
+
+void STLGeometry :: GetVicinity(int starttrig, int size, ARRAY<int>& vic)
+{
+  if (starttrig == 0 || starttrig > GetNT()) {return;} 
+
+  ARRAY<int> vicarray;
+  vicarray.SetSize(GetNT());
+
+  int i;
+  for (i = 1; i <= vicarray.Size(); i++)
+    {
+      vicarray.Elem(i) = 0;
+    }
+ 
+  vicarray.Elem(starttrig) = 1;
+  
+  int j = 0,k;
+
+  ARRAY <int> list1;
+  list1.SetSize(0);
+  ARRAY <int> list2;
+  list2.SetSize(0);
+  list1.Append(starttrig);
+
+  while (j < size)
+    {
+      j++;
+      for (i = 1; i <= list1.Size(); i++)
+	{
+	  for (k = 1; k <= NONeighbourTrigs(i); k++)
+	    {
+	      int nbtrig = NeighbourTrig(list1.Get(i),k);
+	      if (nbtrig && vicarray.Get(nbtrig) == 0)
+		{
+		  list2.Append(nbtrig);
+		  vicarray.Elem(nbtrig) = 1;
+		}
+	    }
+	}
+      list1.SetSize(0);
+      for (i = 1; i <= list2.Size(); i++)
+	{
+	  list1.Append(list2.Get(i));
+	}
+      list2.SetSize(0);
+    }
+
+  vic.SetSize(0);
+  for (i = 1; i <= vicarray.Size(); i++)
+    {
+      if (vicarray.Get(i)) {vic.Append(i);}
+    }
+}
+
+void STLGeometry :: CalcVicinity(int starttrig)
+{
+  if (starttrig == 0 || starttrig > GetNT()) {return;} 
+
+  vicinity.SetSize(GetNT());
+
+  if (!stldoctor.showvicinity) {return;}
+
+  int i;
+  for (i = 1; i <= vicinity.Size(); i++)
+    {
+      vicinity.Elem(i) = 0;
+    }
+ 
+  vicinity.Elem(starttrig) = 1;
+  
+  int j = 0,k;
+
+  ARRAY <int> list1;
+  list1.SetSize(0);
+  ARRAY <int> list2;
+  list2.SetSize(0);
+  list1.Append(starttrig);
+
+  //  int cnt = 1;
+  while (j < stldoctor.vicinity)
+    {
+      j++;
+      for (i = 1; i <= list1.Size(); i++)
+	{
+	  for (k = 1; k <= NONeighbourTrigs(i); k++)
+	    {
+	      int nbtrig = NeighbourTrig(list1.Get(i),k);
+	      if (nbtrig && vicinity.Get(nbtrig) == 0)
+		{
+		  list2.Append(nbtrig);
+		  vicinity.Elem(nbtrig) = 1;
+		  //cnt++;
+		}
+	    }
+	}
+      list1.SetSize(0);
+      for (i = 1; i <= list2.Size(); i++)
+	{
+	  list1.Append(list2.Get(i));
+	}
+      list2.SetSize(0);
+    }
+
+}
+
+int STLGeometry :: Vicinity(int trig) const 
+{
+  if (trig <= vicinity.Size() && trig >=1)
+    {
+      return vicinity.Get(trig);
+    }
+  else {PrintSysError("In STLGeometry::Vicinity");}
+  return 0;
+}
+
+void STLGeometry :: InitMarkedTrigs()
+{
+  markedtrigs.SetSize(GetNT());
+  int i;
+  for (i = 1; i <= GetNT(); i++)
+    {
+      SetMarkedTrig(i, 0);
+    }
+}
+
+void STLGeometry :: MarkDirtyTrigs()
+{
+  PrintFnStart("mark dirty trigs");
+  int i,j;
+
+  markedtrigs.SetSize(GetNT());
+
+  for (i = 1; i <= GetNT(); i++)
+    {
+      SetMarkedTrig(i, 0);
+    }
+
+  int found;
+  double dirtyangle = stlparam.yangle/2./180.*M_PI;
+  int cnt = 0;
+  for (i = 1; i <= GetNT(); i++)
+    {
+      found = 0;
+      for (j = 1; j <= NONeighbourTrigs(i); j++)
+	{
+	  if (GetAngle(i, NeighbourTrig(i,j)) > dirtyangle)
+	    {
+	      found++;
+	    }
+	}
+      if (found && GetTriangle(i).MinHeight(points) < 
+	  stldoctor.dirtytrigfact*GetTriangle(i).MaxLength(points))
+	{
+	  SetMarkedTrig(i, 1); cnt++;
+	}
+      /*
+      else if (found == 3)
+	{
+	  SetMarkedTrig(i, 1); cnt++;	  
+	}
+      */
+    }
+
+  PrintMessage(1, "marked ", cnt, " dirty trigs");
+}
+
+
+void STLGeometry :: MarkTopErrorTrigs()
+{
+  int cnt = 0;
+  markedtrigs.SetSize(GetNT());
+  for (int i = 1; i <= GetNT(); i++)
+    {
+      const STLTriangle & trig = GetTriangle(i);
+
+      SetMarkedTrig(i, trig.flags.toperror);
+      if (trig.flags.toperror) cnt++;
+    }
+  PrintMessage(1,"marked ", cnt, " inconsistent triangles");
+}
+
+
+
+double STLGeometry :: CalcTrigBadness(int i)
+{
+  int j;
+  double maxbadness = 0;
+  int p1, p2;
+  for (j = 1; j <= NONeighbourTrigs(i); j++)
+    {
+      GetTriangle(i).GetNeighbourPoints(GetTriangle(NeighbourTrig(i,j)), p1, p2);
+      
+      if (!IsEdge(p1,p2) && GetGeomAngle(i, NeighbourTrig(i,j)) > maxbadness)
+	{
+	  maxbadness = GetGeomAngle(i, NeighbourTrig(i,j));
+	}
+    }
+  return maxbadness;
+
+}
+
+void STLGeometry :: GeomSmoothRevertedTrigs()
+{
+  double revertedangle = stldoctor.smoothangle/180.*M_PI;
+  double fact = stldoctor.dirtytrigfact;
+
+  MarkRevertedTrigs();
+
+  int i, j, k, l, p;
+
+  for (i = 1; i <= GetNT(); i++)
+    {
+      if (IsMarkedTrig(i)) 
+	{
+	  for (j = 1; j <= 3; j++)
+	    {
+	      double origbadness = CalcTrigBadness(i);
+
+	      p = GetTriangle(i).PNum(j);
+	      Point<3> pm(0.,0.,0.); //Middlevector;
+	      Point<3> p0(0.,0.,0.);
+
+	      int cnt = 0;
+
+	      for (k = 1; k <= trigsperpoint.EntrySize(p); k++)
+		{
+		  const STLTriangle& tr = GetTriangle(trigsperpoint.Get(p,k));
+		  for (l = 1; l <= 3; l++)
+		    {
+		      if (tr.PNum(l) != p)
+			{
+			  cnt++;
+			  pm(0) += GetPoint(tr.PNum(l))(0);
+			  pm(1) += GetPoint(tr.PNum(l))(1);
+			  pm(2) += GetPoint(tr.PNum(l))(2);
+			}
+		    }
+		}
+	      Point3d origp = GetPoint(p);
+	      Point3d newp = p0 + fact*(1./(double)cnt)*(pm-p0)+(1.-fact)*(origp-p0);
+
+	      SetPoint(p, newp);
+
+	      if (CalcTrigBadness(i) > 0.9*origbadness) {SetPoint(p,origp); PrintDot('f');}
+	      else {PrintDot('s');}
+	    }
+	}
+    }
+  MarkRevertedTrigs();
+}
+
+void STLGeometry :: MarkRevertedTrigs()
+{
+  int i,j;
+  if (edgesperpoint.Size() != GetNP()) {BuildEdges();}
+
+  PrintFnStart("mark reverted trigs");
+
+  InitMarkedTrigs();
+
+  int found;
+  double revertedangle = stldoctor.smoothangle/180.*M_PI;
+
+  int cnt = 0;
+  int p1, p2;
+  for (i = 1; i <= GetNT(); i++)
+    {
+      found = 0;
+      for (j = 1; j <= NONeighbourTrigs(i); j++)
+	{
+	  GetTriangle(i).GetNeighbourPoints(GetTriangle(NeighbourTrig(i,j)), p1, p2);
+
+	  if (!IsEdge(p1,p2))
+	    {
+              if (GetGeomAngle(i, NeighbourTrig(i,j)) > revertedangle)
+		{
+		  found = 1;
+		  break;
+		}
+	    }
+	}
+      
+      if (found)
+	{
+	  SetMarkedTrig(i, 1); cnt++;
+	}
+      
+    }
+
+  PrintMessage(5, "found ", cnt, " reverted trigs");
+
+
+}
+
+void STLGeometry :: SmoothDirtyTrigs()
+{
+  PrintFnStart("smooth dirty trigs");
+
+  MarkDirtyTrigs();
+
+  int i,j;
+  int changed = 1;
+  int p1, p2;
+  
+  while (changed)
+    {
+      changed = 0;
+      for (i = 1; i <= GetNT(); i++)
+	{
+	  if (IsMarkedTrig(i))
+	    {
+	      int foundtrig = 0;
+	      double maxlen = 0;
+	      // JS: darf normalvector nicht ueber kurze Seite erben
+	      maxlen = GetTriangle(i).MaxLength(GetPoints()) / 2.1; //JG: bei flachem dreieck auch kurze Seite
+
+	      for (j = 1; j <= NONeighbourTrigs(i); j++)
+		{
+		  if (!IsMarkedTrig(NeighbourTrig(i,j)))
+		    {
+		      GetTriangle(i).GetNeighbourPoints(GetTriangle(NeighbourTrig(i,j)),p1,p2);
+		      if (Dist(GetPoint(p1),GetPoint(p2)) >= maxlen)
+			{
+			  foundtrig = NeighbourTrig(i,j);
+			  maxlen = Dist(GetPoint(p1),GetPoint(p2));
+			}
+		    }
+		}
+	      if (foundtrig)
+		{
+		  GetTriangle(i).SetNormal(GetTriangle(foundtrig).Normal());
+		  changed = 1;
+		  SetMarkedTrig(i,0);
+		}
+	    }
+	}
+    }
+
+  calcedgedataanglesnew = 1;
+
+
+  MarkDirtyTrigs();
+
+  int cnt = 0;
+  for (i = 1; i <= GetNT(); i++)
+    {
+      if (IsMarkedTrig(i)) {cnt++;}
+    }
+
+  PrintMessage(5,"NO marked dirty trigs=", cnt);
+
+}
+
+int STLGeometry :: IsMarkedTrig(int trig) const 
+{
+  if (trig <= markedtrigs.Size() && trig >=1)
+    {
+      return markedtrigs.Get(trig);
+    }
+  else {PrintSysError("In STLGeometry::IsMarkedTrig");}
+
+  return 0;  
+}
+
+void STLGeometry :: SetMarkedTrig(int trig, int num)
+{
+  if (trig <= markedtrigs.Size() && trig >=1)
+    {
+      markedtrigs.Elem(trig) = num;
+    }
+  else {PrintSysError("In STLGeometry::SetMarkedTrig");}
+}
+
+void STLGeometry :: Clear()
+{
+  PrintFnStart("Clear");
+
+  surfacemeshed = 0;
+  surfaceoptimized = 0;
+  volumemeshed = 0;
+
+  selectedmultiedge.SetSize(0);
+  meshlines.SetSize(0);
+  // neighbourtrigs.SetSize(0);
+  outerchartspertrig.SetSize(0);
+  atlas.SetSize(0);
+  ClearMarkedSegs();
+  ClearSpiralPoints();
+  ClearLineEndPoints();
+
+  SetSelectTrig(0);
+  SetNodeOfSelTrig(1);
+  facecnt = 0;
+
+  SetThreadPercent(100.);
+
+  ClearEdges();
+}
+
+double STLGeometry :: Area()
+{
+  double ar = 0;
+  int i;
+  for (i = 1; i <= GetNT(); i++)
+    {
+      ar += GetTriangle(i).Area(points);
+    }
+  return ar;
+}
+
+double STLGeometry :: GetAngle(int t1, int t2)
+{
+  return Angle(GetTriangle(t1).Normal(),GetTriangle(t2).Normal());
+}
+
+double STLGeometry :: GetGeomAngle(int t1, int t2)
+{
+  Vec3d n1 = GetTriangle(t1).GeomNormal(points);
+  Vec3d n2 = GetTriangle(t2).GeomNormal(points);
+  return Angle(n1,n2);
+}
+
+
+void STLGeometry :: InitSTLGeometry(const ARRAY<STLReadTriangle> & readtrias)
+{
+  PrintFnStart("Init STL Geometry");
+  STLTopology::InitSTLGeometry(readtrias);
+
+  int i, j, k;
+
+  const double geometry_tol_fact = 1E8; //distances lower than max_box_size/tol are ignored
+
+  int np = GetNP();
+  PrintMessage(5,"NO points= ", GetNP());
+  normals.SetSize(GetNP());
+  ARRAY<int> normal_cnt(GetNP()); // counts number of added normals in a point
+
+  for (i = 1; i <= np; i++)
+    {
+      normal_cnt.Elem(i) = 0;
+      normals.Elem(i) = Vec3d (0,0,0);
+    }
+
+  for(i = 1; i <= GetNT(); i++)
+    {
+      //      STLReadTriangle t = GetReadTriangle(i);
+      //      STLTriangle st;
+
+      Vec<3> n = GetTriangle(i).Normal ();
+
+      for (k = 1; k <= 3; k++)
+	{
+	  int pi = GetTriangle(i).PNum(k);
+	  
+	  normal_cnt.Elem(pi)++;
+	  SetNormal(pi, GetNormal(pi) + n);
+	}
+    } 
+
+  //normalize the normals
+  for (i = 1; i <= GetNP(); i++)
+    {
+      SetNormal(i,1./(double)normal_cnt.Get(i)*GetNormal(i));
+    }
+
+  trigsconverted = 1;
+
+  vicinity.SetSize(GetNT());
+  markedtrigs.SetSize(GetNT());
+  for (i = 1; i <= GetNT(); i++)
+    {
+      markedtrigs.Elem(i) = 0;
+      vicinity.Elem(i) = 1;
+    }
+
+  ha_points.SetSize(GetNP());
+  for (i = 1; i <= GetNP(); i++)
+    ha_points.Elem(i) = 0;
+
+  calcedgedataanglesnew = 0;
+  edgedatastored = 0;
+  edgedata.Clear();
+
+
+  if (GetStatus() == STL_ERROR) return;
+
+  CalcEdgeData();
+  CalcEdgeDataAngles();
+
+  ClearLineEndPoints();
+
+  CheckGeometryOverlapping();
+}
+
+void STLGeometry :: TopologyChanged()
+{
+  calcedgedataanglesnew = 1;
+}
+
+int STLGeometry :: CheckGeometryOverlapping()
+{
+  int i, j, k;
+
+  Box<3> geombox = GetBoundingBox();
+  Point<3> pmin = geombox.PMin();
+  Point<3> pmax = geombox.PMax();
+
+  Box3dTree setree(pmin, pmax);
+  ARRAY<int> inters;
+
+  int oltrigs = 0;
+  markedtrigs.SetSize(GetNT());
+
+  for (i = 1; i <= GetNT(); i++)
+    SetMarkedTrig(i, 0);
+
+  for (i = 1; i <= GetNT(); i++)
+    {
+      const STLTriangle & tri = GetTriangle(i);
+      
+      Point<3> tpmin = tri.box.PMin();
+      Point<3> tpmax = tri.box.PMax();
+      Vec<3> diag = tpmax - tpmin;
+
+      tpmax = tpmax + 0.001 * diag;
+      tpmin = tpmin - 0.001 * diag;
+
+      setree.Insert (tpmin, tpmax, i);
+    }
+
+  for (i = 1; i <= GetNT(); i++)
+    {
+      const STLTriangle & tri = GetTriangle(i);
+      
+      Point<3> tpmin = tri.box.PMin();
+      Point<3> tpmax = tri.box.PMax();
+
+      setree.GetIntersecting (tpmin, tpmax, inters);
+
+      for (j = 1; j <= inters.Size(); j++)
+	{
+	  const STLTriangle & tri2 = GetTriangle(inters.Get(j));
+
+	  const Point3d *trip1[3], *trip2[3];	
+	  Point3d hptri1[3], hptri2[3];
+	  /*
+	  for (k = 1; k <= 3; k++)
+	    {
+	      trip1[k-1] = &GetPoint (tri.PNum(k));
+	      trip2[k-1] = &GetPoint (tri2.PNum(k));
+	    }
+	  */
+
+	  for (k = 0; k < 3; k++)
+	    {
+	      hptri1[k] = GetPoint (tri[k]);
+	      hptri2[k] = GetPoint (tri2[k]);
+	      trip1[k] = &hptri1[k];
+	      trip2[k] = &hptri2[k];
+	    }
+
+	  if (IntersectTriangleTriangle (&trip1[0], &trip2[0]))
+	    {
+	      oltrigs++;
+	      PrintMessage(5,"Intersecting Triangles: trig ",i," with ",inters.Get(j),"!");
+	      SetMarkedTrig(i, 1);
+	      SetMarkedTrig(inters.Get(j), 1);
+	    }
+	}
+    }
+
+  PrintMessage(3,"Check Geometry Overlapping: overlapping triangles = ",oltrigs);
+  return oltrigs;
+}
+
+/*
+void STLGeometry :: InitSTLGeometry()
+{
+  STLTopology::InitSTLGeometry();
+
+  int i, j, k;
+
+  const double geometry_tol_fact = 1E8; //distances lower than max_box_size/tol are ignored
+
+
+  trias.SetSize(0);
+  points.SetSize(0);
+  normals.SetSize(0);
+
+  ARRAY<int> normal_cnt; // counts number of added normals in a point
+
+  Box3d bb (GetBoundingBox().PMin() + Vec3d (-1,-1,-1),
+	    GetBoundingBox().PMax() + Vec3d (1, 1, 1));
+
+  Point3dTree pointtree (bb.PMin(), 
+			 bb.PMax());
+  ARRAY<int> pintersect;
+
+  double gtol = GetBoundingBox().CalcDiam()/geometry_tol_fact;
+
+  for(i = 1; i <= GetReadNT(); i++)
+    {
+      //if (i%500==499) {(*mycout) << (double)i/(double)GetReadNT()*100. << "%" << endl;}
+
+      STLReadTriangle t = GetReadTriangle(i);
+      STLTriangle st;
+      Vec3d n = t.normal;
+
+      for (k = 0; k < 3; k++)
+	{
+	  Point3d p = t.pts[k];
+
+	  Point3d pmin = p - Vec3d (gtol, gtol, gtol);
+	  Point3d pmax = p + Vec3d (gtol, gtol, gtol);
+	  
+	  pointtree.GetIntersecting (pmin, pmax, pintersect);
+	  
+	  if (pintersect.Size() > 1)
+	    (*mycout) << "found too much  " << char(7) << endl;
+	  int foundpos = 0;
+	  if (pintersect.Size())
+	    foundpos = pintersect.Get(1);
+
+	  if (foundpos) 
+	    {
+	      normal_cnt[foundpos]++;
+	      SetNormal(foundpos,GetNormal(foundpos)+n);
+	      //	      (*testout) << "found p " << p << endl;
+	    }
+	  else
+	    {
+	      foundpos = AddPoint(p);
+	      AddNormal(n);
+	      normal_cnt.Append(1);
+
+	      pointtree.Insert (p, foundpos);
+	    }
+	  //(*mycout) << "foundpos=" << foundpos << endl;
+	  st.pts[k] = foundpos;
+	}
+
+      if ( (st.pts[0] == st.pts[1]) || 
+	   (st.pts[0] == st.pts[2]) || 
+	   (st.pts[1] == st.pts[2]) )
+	{
+	  (*mycout) << "ERROR: STL Triangle degenerated" << endl;
+	}
+      else
+	{
+	  // do not add ? js
+	  AddTriangle(st);
+	}
+      //(*mycout) << "TRIG" << i << " = " << st << endl;
+      
+    } 
+  //normal the normals
+  for (i = 1; i <= GetNP(); i++)
+    {
+      SetNormal(i,1./(double)normal_cnt[i]*GetNormal(i));
+    }
+
+  trigsconverted = 1;
+
+  vicinity.SetSize(GetNT());
+  markedtrigs.SetSize(GetNT());
+  for (i = 1; i <= GetNT(); i++)
+    {
+      markedtrigs.Elem(i) = 0;
+      vicinity.Elem(i) = 1;
+    }
+
+  ha_points.SetSize(GetNP());
+  for (i = 1; i <= GetNP(); i++)
+    ha_points.Elem(i) = 0;
+
+  calcedgedataanglesnew = 0;
+  edgedatastored = 0;
+  edgedata.Clear();
+
+  CalcEdgeData();
+  CalcEdgeDataAngles();
+
+  ClearLineEndPoints();
+
+  (*mycout) << "done" << endl;
+}
+*/
+
+
+
+void STLGeometry :: SetLineEndPoint(int pn) 
+{
+  if (pn <1 || pn > lineendpoints.Size()) {PrintSysError("Illegal pnum in SetLineEndPoint!!!"); return; }
+  lineendpoints.Elem(pn) = 1;
+}
+
+int STLGeometry :: IsLineEndPoint(int pn) 
+{
+  //  return 0;
+  if (pn <1 || pn > lineendpoints.Size()) 
+    {PrintSysError("Illegal pnum in IsLineEndPoint!!!"); return 0;}
+  return lineendpoints.Get(pn);
+}
+
+void STLGeometry :: ClearLineEndPoints()
+{
+  lineendpoints.SetSize(GetNP());
+  int i;
+  for (i = 1; i <= GetNP(); i++)
+    {
+      lineendpoints.Elem(i) = 0;
+    }
+}
+
+int STLGeometry :: IsEdge(int p1, int p2)
+{
+  int i,j;
+  for (i = 1; i <= GetNEPP(p1); i++)
+    {
+      for (j = 1; j <= GetNEPP(p2); j++)
+	{
+	  if (GetEdgePP(p1,i) == GetEdgePP(p2,j)) {return 1;}
+	}
+    }
+  return 0;
+}
+
+int STLGeometry :: IsEdgeNum(int p1, int p2)
+{
+  int i,j;
+  for (i = 1; i <= GetNEPP(p1); i++)
+    {
+      for (j = 1; j <= GetNEPP(p2); j++)
+	{
+	  if (GetEdgePP(p1,i) == GetEdgePP(p2,j)) {return GetEdgePP(p1,i);}
+	}
+    }
+  return 0;
+}
+
+
+void STLGeometry :: BuildEdges()
+{
+  //PrintFnStart("build edges");
+  edges.SetSize(0);
+  meshlines.SetSize(0);
+  FindEdgesFromAngles();
+}
+
+void STLGeometry :: UseExternalEdges()
+{
+  int i;
+  for (i = 1; i <= NOExternalEdges(); i++)
+    {
+      AddEdge(GetExternalEdge(i).i1,GetExternalEdge(i).i2);
+    }
+  //BuildEdgesPerPointy();
+}
+
+void STLGeometry :: UndoEdgeChange()
+{
+  if (edgedatastored) 
+    {
+      RestoreEdgeData();
+    }
+  else
+    {
+      PrintWarning("no edge undo possible");
+    }
+}
+
+
+void STLGeometry :: StoreEdgeData()
+{
+  //  edgedata_store = edgedata;
+  
+  edgedata.Store();
+  edgedatastored = 1;
+
+  // put stlgeom-edgedata to stltopology edgedata 
+  /*
+  int i;
+  for (i = 1; i <= GetNTE(); i++)
+    {
+      const STLTopEdge & topedge = GetTopEdge (i);
+      int ednum = edgedata.GetEdgeNum (topedge.PNum(1),
+				       topedge.PNum(2));
+      topedges.Elem(i).SetStatus (edgedata.Get (ednum).status);
+    }
+  */
+}
+
+void STLGeometry :: RestoreEdgeData()
+{
+  //  edgedata = edgedata_store;
+  edgedata.Restore();
+  edgedatastored=0;
+}
+
+
+void STLGeometry :: CalcEdgeData()
+{
+  PushStatus("Calc Edge Data");
+
+  int np1, np2;
+  double ang;
+  int i;
+  
+  int ecnt = 0;
+  edgedata.SetSize(GetNT()/2*3);
+
+  for (i = 1; i <= GetNT(); i++)
+    {
+      SetThreadPercent((double)i/(double)GetNT()*100.);
+      
+      const STLTriangle & t1 = GetTriangle(i);
+
+      for (int j = 1; j <= NONeighbourTrigs(i); j++)
+	{
+	  int nbti = NeighbourTrig(i,j);
+	  if (nbti > i)
+	    {
+	      const STLTriangle & t2 = GetTriangle(nbti);
+
+	      if (t1.IsNeighbourFrom(t2))
+		{
+		  ecnt++; if (ecnt > edgedata.Size()) {PrintError("In Calc edge data, illegal geometry");}
+
+		  t1.GetNeighbourPoints(t2,np1,np2);
+
+		  /* ang = GetAngle(i,nbti);
+		     if (ang < -M_PI) {ang += 2*M_PI;}*/
+
+
+		  // edgedata.Add(STLEdgeData(0, np1, np2, i, nbti),ecnt);
+		  edgedata.Elem(ecnt).SetStatus(ED_UNDEFINED);
+
+		  // edgedata.Elem(ecnt).top = this;
+		  // edgedata.Elem(ecnt).topedgenr = GetTopEdgeNum (np1, np2);
+		}
+	    }
+	}      
+    }
+  
+  //BuildEdgesPerPoint();
+  PopStatus();  
+}
+
+void STLGeometry :: CalcEdgeDataAngles()
+{
+  PrintMessage(5,"calc edge data angles");
+
+  double ang;
+  int i;
+  int t1,t2;
+
+  for (i = 1; i <= GetNTE(); i++)
+    {
+      STLTopEdge & edge = GetTopEdge (i);
+      double cosang = 
+	GetTriangle(edge.TrigNum(1)).Normal() *
+	GetTriangle(edge.TrigNum(2)).Normal();
+      edge.SetCosAngle (cosang);
+    }
+
+  for (i = 1; i <= edgedata.Size(); i++)
+    {
+      /*
+      const STLEdgeData& e = edgedata.Get(i);
+      ang = GetAngle(e.lt,e.rt);
+      if (ang < -M_PI) {ang += 2*M_PI;}
+      edgedata.Elem(i).angle = fabs(ang);
+      */
+    }
+  
+}
+
+void STLGeometry :: FindEdgesFromAngles()
+{
+  //  PrintFnStart("find edges from angles");
+
+  double min_edge_angle = stlparam.yangle/180.*M_PI;
+  double cont_min_edge_angle = stlparam.contyangle/180.*M_PI;
+
+  double cos_min_edge_angle = cos (min_edge_angle);
+  double cos_cont_min_edge_angle = cos (cont_min_edge_angle);
+
+  if (calcedgedataanglesnew) {CalcEdgeDataAngles(); calcedgedataanglesnew = 0;}
+
+  int i;
+  for (i = 1; i <= edgedata.Size(); i++)
+    {
+      STLTopEdge & sed = edgedata.Elem(i);
+      if (sed.GetStatus() == ED_CANDIDATE || 
+	  sed.GetStatus() == ED_UNDEFINED)
+	{
+	  if (sed.CosAngle() <= cos_min_edge_angle)
+	    {
+	      sed.SetStatus (ED_CANDIDATE);
+	    }
+	  else
+	    {
+	      sed.SetStatus(ED_UNDEFINED);
+	    }
+	} 
+    }
+
+  if (stlparam.contyangle < stlparam.yangle)
+    {
+      int changed = 1;
+      int its = 0;
+      while (changed && stlparam.contyangle < stlparam.yangle)
+	{
+	  its++;
+	  //(*mycout) << "." << flush;
+	  changed = 0;
+	  for (i = 1; i <= edgedata.Size(); i++)
+	    {
+	      STLTopEdge & sed = edgedata.Elem(i);
+	      if (sed.CosAngle() <= cos_cont_min_edge_angle 
+		  && sed.GetStatus() == ED_UNDEFINED && 
+		  (edgedata.GetNConfCandEPP(sed.PNum(1)) == 1 || 
+		   edgedata.GetNConfCandEPP(sed.PNum(2)) == 1))
+		{
+		  changed = 1;
+		  sed.SetStatus (ED_CANDIDATE);
+		}
+	    }
+	}
+    }
+  
+  int confcand = 0;
+  if (edgedata.GetNConfEdges() == 0) 
+    {
+      confcand = 1;
+    }
+  
+  for (i = 1; i <= edgedata.Size(); i++)
+    {
+      STLTopEdge & sed = edgedata.Elem(i);
+      if (sed.GetStatus() == ED_CONFIRMED || 
+	  (sed.GetStatus() == ED_CANDIDATE && confcand))
+	{
+	  STLEdge se(sed.PNum(1),sed.PNum(2));
+	  se.SetLeftTrig(sed.TrigNum(1));
+	  se.SetRightTrig(sed.TrigNum(2));
+	  AddEdge(se);
+	}
+    }
+  BuildEdgesPerPoint();
+
+  
+
+  //(*mycout) << "its for continued angle = " << its << endl;
+  PrintMessage(5,"built ", GetNE(), " edges with yellow angle = ", stlparam.yangle, " degree");
+  
+}
+
+/*
+void STLGeometry :: FindEdgesFromAngles()
+{
+  double yangle = stlparam.yangle;
+  char * savetask = multithread.task;
+  multithread.task = "find edges";
+
+  const double min_edge_angle = yangle/180.*M_PI;
+
+  int np1, np2;
+  double ang;
+  int i;
+
+  //(*mycout) << "area=" << Area() << endl;
+
+  for (i = 1; i <= GetNT(); i++)
+    {
+      multithread.percent = (double)i/(double)GetReadNT()*100.;
+      
+      const STLTriangle & t1 = GetTriangle(i);
+      //NeighbourTrigs(nt,i);
+
+      for (int j = 1; j <= NONeighbourTrigs(i); j++)
+	{
+	  int nbti = NeighbourTrig(i,j);
+	  if (nbti > i)
+	    {
+	      const STLTriangle & t2 = GetTriangle(nbti);
+
+	      if (t1.IsNeighbourFrom(t2))
+		{
+		  ang = GetAngle(i,nbti);
+		  if (ang < -M_PI*0.5) {ang += 2*M_PI;}
+
+		  t1.GetNeighbourPoints(t2,np1,np2);
+		  
+		  if (fabs(ang) >= min_edge_angle)
+		    {
+		      STLEdge se(np1,np2);
+		      se.SetLeftTrig(i);
+		      se.SetRightTrig(nbti);
+		      AddEdge(se);
+		    }
+		}
+	    }
+	}      
+    }
+  
+  (*mycout) << "added " << GetNE() << " edges" << endl;
+
+  //BuildEdgesPerPoint();
+
+  multithread.percent = 100.;
+  multithread.task = savetask;
+  
+}
+*/
+void STLGeometry :: BuildEdgesPerPoint()
+{
+  //cout << "*** build edges per point" << endl;
+  edgesperpoint.SetSize(GetNP());
+
+  //add edges to points
+  int i, j;
+  for (i = 1; i <= GetNE(); i++)
+    {
+      //(*mycout) << "EDGE " << GetEdge(i).PNum(1) << " - " << GetEdge(i).PNum(2) << endl;
+      for (int j = 1; j <= 2; j++)
+	{
+	  AddEdgePP(GetEdge(i).PNum(j),i);
+	}
+    }
+}
+
+void STLGeometry :: AddFaceEdges()
+{
+  PrintFnStart("Add starting edges for faces");
+
+  //für Kugel eine STLLine hinzufügen (Vorteil: verfeinerbar, unabhängig von Auflösung der Geometrie!!!):
+  //Grenze von 1. gefundener chart
+
+  ARRAY<int> edgecnt;
+  ARRAY<int> chartindex;
+  edgecnt.SetSize(GetNOFaces());
+  chartindex.SetSize(GetNOFaces());
+
+  int i,j;
+  for (i = 1; i <= GetNOFaces(); i++)
+    {
+      edgecnt.Elem(i) = 0;
+      chartindex.Elem(i) = 0;
+    }
+
+  for (i = 1; i <= GetNT(); i++)
+    {
+      int fn = GetTriangle(i).GetFaceNum();
+      if (!chartindex.Get(fn)) {chartindex.Elem(fn) = GetChartNr(i);}
+      for (j = 1; j <= 3; j++)
+	{
+	  edgecnt.Elem(fn) += GetNEPP(GetTriangle(i).PNum(j));
+	}
+    }
+
+  for (i = 1; i <= GetNOFaces(); i++)
+    {
+      if (!edgecnt.Get(i)) {PrintMessage(5,"Face", i, " has no edge!");}
+    }
+  
+  int changed = 0;
+  int k, p1, p2;
+  for (i = 1; i <= GetNOFaces(); i++)
+    {
+      if (!edgecnt.Get(i))
+      {
+	const STLChart& c = GetChart(chartindex.Get(i));
+	for (j = 1; j <= c.GetNChartT(); j++)
+	  {
+	    const STLTriangle& t1 = GetTriangle(c.GetChartTrig(j));
+	    for (k = 1; k <= 3; k++)
+	      {
+		int nt = NeighbourTrig(c.GetChartTrig(j),k);
+		if (GetChartNr(nt) != chartindex.Get(i))
+		  {
+		    t1.GetNeighbourPoints(GetTriangle(nt),p1,p2);
+		    AddEdge(p1,p2);
+		    changed = 1;
+		  }
+	      }
+	  }
+      }
+      
+    }
+  
+  if (changed) BuildEdgesPerPoint();
+  
+}
+
+void STLGeometry :: LinkEdges()
+{
+  PushStatusF("Link Edges");
+  PrintMessage(5,"have now ", GetNE(), " edges with yellow angle = ", stlparam.yangle, " degree");
+
+  int i;
+
+  lines.SetSize(0);
+  int starte;
+  int edgecnt = 0;
+  int found;
+  int rev; //indicates, that edge is inserted reverse
+
+  //worked edges
+  ARRAY<int> we(GetNE());
+
+  //setlineendpoints; wenn 180°, dann keine endpunkte
+  //nur punkte mit 2 edges kommen in frage, da bei mehr oder weniger punkten ohnehin ein meshpoint hinkommt
+
+  Vec3d v1,v2;
+  double cos_eca = cos(stlparam.edgecornerangle/180.*M_PI);
+  int ecnt = 0;
+  int lp1, lp2;
+  if (stlparam.edgecornerangle < 180)
+    {
+      for (i = 1; i <= GetNP(); i++)
+	{
+	  if (GetNEPP(i) == 2)
+	    {
+	      if (GetEdge(GetEdgePP(i,1)).PNum(2) == GetEdge(GetEdgePP(i,2)).PNum(1) ||
+		  GetEdge(GetEdgePP(i,1)).PNum(1) == GetEdge(GetEdgePP(i,2)).PNum(2))
+		{
+		  lp1 = 1; lp2 = 2;
+		}
+	      else
+		{
+		  lp1 = 2; lp2 = 1;
+		}
+
+	      v1 = Vec3d(GetPoint(GetEdge(GetEdgePP(i,1)).PNum(1)),
+			 GetPoint(GetEdge(GetEdgePP(i,1)).PNum(2)));
+	      v2 = Vec3d(GetPoint(GetEdge(GetEdgePP(i,2)).PNum(lp1)),
+			 GetPoint(GetEdge(GetEdgePP(i,2)).PNum(lp2)));
+	      if ((v1*v2)/sqrt(v1.Length2()*v2.Length2()) < cos_eca) 
+		{
+		  //(*testout) << "add edgepoint " << i << endl;
+		  SetLineEndPoint(i);
+		  ecnt++;
+		}
+	    }	  
+	}
+    }
+  PrintMessage(5, "added ", ecnt, " mesh_points due to edge corner angle (", 
+	       stlparam.edgecornerangle, " degree)");
+
+  for (i = 1; i <= GetNE(); i++) {we.Elem(i) = 0;}
+
+  while(edgecnt < GetNE())
+    {
+      SetThreadPercent((double)edgecnt/(double)GetNE()*100.);
+
+      STLLine* line = new STLLine(this);
+
+      //find start edge
+      int j = 1;
+      found = 0;
+      //try second time, if only rings are left!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+      int second = 0;
+
+      //find a starting edge at point with 1 or more than 2 edges or at lineendpoint
+      while (!found && j<=GetNE())
+	{
+	  if (!we.Get(j))
+	    {
+	      if (GetNEPP(GetEdge(j).PNum(1)) != 2 || IsLineEndPoint(GetEdge(j).PNum(1)))
+		{
+		  starte = j;
+		  found = 1;
+		  rev = 0;
+		}
+	      else 
+	      if (GetNEPP(GetEdge(j).PNum(2)) != 2 || IsLineEndPoint(GetEdge(j).PNum(2)))
+		{
+		  starte = j;
+		  found = 1;
+		  rev = 1;
+		}
+	      else if (second)
+		{
+		  starte = j;
+		  found = 1;
+		  rev = 0; //0 or 1 are possible
+		}
+	    }
+	  j++;
+	  if (!second && j == GetNE()) {second = 1; j = 1;}
+	}
+
+      if (!found) {PrintSysError("No starting edge found, edgecnt=", edgecnt, ", GETNE=", GetNE());}
+
+      line->AddPoint(GetEdge(starte).PNum(1+rev));
+      line->AddPoint(GetEdge(starte).PNum(2-rev));
+      if (!rev)
+	{
+	  line->AddLeftTrig(GetEdge(starte).LeftTrig());
+	  line->AddRightTrig(GetEdge(starte).RightTrig());
+	}
+      else
+	{
+	  line->AddLeftTrig(GetEdge(starte).RightTrig());
+	  line->AddRightTrig(GetEdge(starte).LeftTrig());
+	}
+      edgecnt++; we.Elem(starte) = 1;
+
+      //add segments to line as long as segments other than starting edge are found or lineendpoint is reached 
+      found = 1;
+      int other;
+      while(found)
+	{
+	  found = 0;
+	  int fp = GetEdge(starte).PNum(2-rev);
+	  if (GetNEPP(fp) == 2 && !IsLineEndPoint(fp))
+	    {
+	      //find the "other" edge of point fp
+	      other = 0;
+	      if (GetEdgePP(fp,1) == starte) {other = 1;}
+
+	      starte = GetEdgePP(fp,1+other);
+
+	      //falls ring -> aufhoeren !!!!!!!!!!!
+	      if (!we.Elem(starte))
+		{
+		  found = 1;
+		  rev = 0;
+		  if (GetEdge(starte).PNum(2) == fp) {rev = 1;}
+		  else if (GetEdge(starte).PNum(1) != fp) {PrintSysError("In Link Edges!");}
+
+		  line->AddPoint(GetEdge(starte).PNum(2-rev));
+		  if (!rev) 
+		    {
+		      line->AddLeftTrig(GetEdge(starte).LeftTrig());
+		      line->AddRightTrig(GetEdge(starte).RightTrig());
+		    }
+		  else
+		    {
+		      line->AddLeftTrig(GetEdge(starte).RightTrig());
+		      line->AddRightTrig(GetEdge(starte).LeftTrig());
+		    }
+		  edgecnt++; we.Elem(starte) = 1;
+		}
+	    }     
+	}
+      AddLine(line);      
+    }
+  PrintMessage(5,"number of lines generated = ", GetNLines());
+
+  //check, which lines must have at least one midpoint
+  INDEX_2_HASHTABLE<int> lineht(GetNLines()+1);
+
+  for (i = 1; i <= GetNLines(); i++)
+    {
+      if (GetLine(i)->StartP() == GetLine(i)->EndP())
+	{
+	  GetLine(i)->DoSplit();	  
+	}
+    }
+
+  for (i = 1; i <= GetNLines(); i++)
+    {
+      INDEX_2 lineep (GetLine(i)->StartP(),GetLine(i)->EndP());
+      lineep.Sort();
+
+      if (lineht.Used (lineep))
+	{
+	  GetLine(i)->DoSplit();
+	  int other = lineht.Get(lineep);
+	  GetLine(other)->DoSplit();
+	}
+      else
+	{
+	  lineht.Set (lineep, i);
+	}
+    }
+
+  for (i = 1; i <= GetNLines(); i++)
+    {
+      STLLine* line = GetLine(i);
+      for (int ii = 1; ii <= line->GetNS(); ii++)
+	{
+	  int p1, p2;
+	  line->GetSeg(ii,p1,p2);
+	  //	  (*mycout) << "SEG " << p1 << " - " << p2 << endl;
+	}
+    }
+
+  PopStatus();
+}
+
+int STLGeometry :: GetNOBodys()
+{
+  int markedtrigs = 0;
+  int starttrig = 1;
+  int i, k, nnt;
+  int bodycnt = 0;
+
+  ARRAY<int> bodynum(GetNT());
+
+  for (i = 1; i <= GetNT(); i++)
+    bodynum.Elem(i)=0;
+
+
+  while (markedtrigs < GetNT())
+    {
+      for (i = starttrig; i <= GetNT(); i++)
+	{
+	  if (!bodynum.Get(i))
+	    {
+	      starttrig = i;
+	      break;
+	    }
+	} 
+      //add all triangles around starttriangle, which is reachable without going over an edge
+      ARRAY<int> todolist;
+      ARRAY<int> nextlist;
+      bodycnt++;
+      markedtrigs++;
+      bodynum.Elem(starttrig) = bodycnt;
+      todolist.Append(starttrig);
+      int p1, p2;
+
+      while(todolist.Size())
+	{
+	  for (i = 1; i <= todolist.Size(); i++)
+	    {
+	      const STLTriangle& tt = GetTriangle(todolist.Get(i));
+	      for (k = 1; k <= NONeighbourTrigs(todolist.Get(i)); k++)
+		{
+		  nnt = NeighbourTrig(todolist.Get(i),k);
+		  if (!bodynum.Get(nnt))
+		    {
+		      nextlist.Append(nnt);
+		      bodynum.Elem(nnt) = bodycnt;
+		      markedtrigs++;
+		    }
+		}
+	    }
+	  
+	  todolist.SetSize(0);
+	  for (i = 1; i <= nextlist.Size(); i++)
+	    {
+	      todolist.Append(nextlist.Get(i));
+	    }
+	  nextlist.SetSize(0);	  
+	}
+    }
+  PrintMessage(3, "Geometry has ", bodycnt, " separated bodys");
+
+  return bodycnt;
+}
+
+void STLGeometry :: CalcFaceNums()
+{
+  int markedtrigs = 0;
+  int starttrig;
+  int laststarttrig = 1;
+  int i, k, nnt;
+  facecnt = 0;
+
+
+  for (i = 1; i <= GetNT(); i++)
+    GetTriangle(i).SetFaceNum(0);
+
+
+  while (markedtrigs < GetNT())
+    {
+      for (i = laststarttrig; i <= GetNT(); i++)
+	{
+	  if (!GetTriangle(i).GetFaceNum()) 
+	    {
+	      starttrig = i;
+	      laststarttrig = i;
+	      break;
+	    }
+	} 
+      //add all triangles around starttriangle, which is reachable without going over an edge
+      ARRAY<int> todolist;
+      ARRAY<int> nextlist;
+      facecnt++;
+      markedtrigs++;
+      GetTriangle(starttrig).SetFaceNum(facecnt);
+      todolist.Append(starttrig);
+      int p1, p2;
+
+      while(todolist.Size())
+	{
+	  for (i = 1; i <= todolist.Size(); i++)
+	    {
+	      const STLTriangle& tt = GetTriangle(todolist.Get(i));
+	      for (k = 1; k <= NONeighbourTrigs(todolist.Get(i)); k++)
+		{
+		  nnt = NeighbourTrig(todolist.Get(i),k);
+		  STLTriangle& nt = GetTriangle(nnt);
+		  if (!nt.GetFaceNum())
+		    {
+		      tt.GetNeighbourPoints(nt,p1,p2);
+		      if (!IsEdge(p1,p2))
+			{
+			  nextlist.Append(nnt);
+			  nt.SetFaceNum(facecnt);
+			  markedtrigs++;
+			}
+		    }
+		}
+	    }
+	  
+	  todolist.SetSize(0);
+	  for (i = 1; i <= nextlist.Size(); i++)
+	    {
+	      todolist.Append(nextlist.Get(i));
+	    }
+	  nextlist.SetSize(0);	  
+	}
+    }
+  GetNOBodys();
+  PrintMessage(3,"generated ", facecnt, " faces");
+}
+ 
+void STLGeometry :: ClearSpiralPoints()
+{
+  spiralpoints.SetSize(GetNP());
+  int i;
+  for (i = 1; i <= spiralpoints.Size(); i++)
+    {
+      spiralpoints.Elem(i) = 0;
+    }
+}
+
+
+void STLGeometry :: BuildSmoothEdges ()
+{
+  if (smoothedges) delete smoothedges;
+
+  smoothedges = new INDEX_2_HASHTABLE<int> (GetNE()/10 + 1);
+
+
+  // Jack: Ok ?
+  //  UseExternalEdges();
+
+  PushStatusF("Build Smooth Edges");
+
+  int i, j, k, l;
+  int nt = GetNT();
+  Vec3d ng1, ng2;
+
+  for (i = 1; i <= nt; i++)
+    {
+      if (multithread.terminate)
+	{PopStatus();return;}
+
+      SetThreadPercent(100.0 * (double)i / (double)nt);
+
+      const STLTriangle & trig = GetTriangle (i);
+      
+      Vec3d ng1 = trig.GeomNormal(points);
+      ng1 /= (ng1.Length() + 1e-24);
+
+      for (j = 1; j <= 3; j++)
+	{ 
+	  int nbt = NeighbourTrig (i, j);
+	  
+	  Vec3d ng2 = GetTriangle(nbt).GeomNormal(points);
+	  ng2 /= (ng2.Length() + 1e-24);
+	  
+	  
+	  int pi1, pi2;
+
+	  trig.GetNeighbourPoints(GetTriangle(nbt), pi1, pi2);
+
+	  if (!IsEdge(pi1,pi2)) 
+	    {
+	      if (ng1 * ng2 < 0)
+		{
+		  PrintMessage(7,"smoothedge found");
+		  INDEX_2 i2(pi1, pi2);
+		  i2.Sort();
+		  smoothedges->Set (i2, 1);
+		}
+	    }
+	}
+    }
+
+  PopStatus();
+}
+
+
+
+
+
+int STLGeometry :: IsSmoothEdge (int pi1, int pi2) const
+{
+  if (!smoothedges)
+    return 0;
+  INDEX_2 i2(pi1, pi2);
+  i2.Sort();
+  return smoothedges->Used (i2);
+}
+
+
+
+
+//function is not used now
+int IsInArray(int n, const ARRAY<int>& ia)
+{
+  int i;
+  for (i = 1; i <= ia.Size(); i++)
+    {
+      if (ia.Get(i) == n) {return 1;}
+    }
+  return 0;
+}
+
+void STLGeometry :: AddConeAndSpiralEdges()
+{
+  PrintMessage(5,"have now ", GetNE(), " edges with yellow angle = ", stlparam.yangle, " degree");
+
+  PrintFnStart("AddConeAndSpiralEdges");
+
+  int i,j,k,n;
+  //  int changed = 0;
+
+  //check edges, where inner chart and no outer chart come together without an edge
+  int np1, np2, nt;
+  int cnt = 0;
+
+  for (i = 1; i <= GetNOCharts(); i++)
+    {
+      STLChart& chart = GetChart(i);
+      for (j = 1; j <= chart.GetNChartT(); j++)
+	{
+	  int t = chart.GetChartTrig(j); 
+	  const STLTriangle& tt = GetTriangle(t);
+
+	  for (k = 1; k <= 3; k++)
+	    {
+	      nt = NeighbourTrig(t,k); 
+	      if (GetChartNr(nt) != i && !TrigIsInOC(nt,i))
+		{	      
+		  tt.GetNeighbourPoints(GetTriangle(nt),np1,np2);
+		  if (!IsEdge(np1,np2))
+		    {
+		      STLEdge se(np1,np2);
+		      se.SetLeftTrig(t);
+		      se.SetRightTrig(nt);
+		      int edgenum = AddEdge(se);
+		      AddEdgePP(np1,edgenum);
+		      AddEdgePP(np2,edgenum);
+		      //changed = 1;
+		      PrintWarning("Found a spiral like structure: chart=", i,
+				   ", trig=", t, ", p1=", np1, ", p2=", np2);
+		      cnt++;
+		    }
+		}
+	    }
+	}
+	  
+    }
+
+  PrintMessage(5, "found ", cnt, " spiral like structures");
+  PrintMessage(5, "added ", cnt, " edges due to spiral like structures");
+  
+  cnt = 0;
+  int edgecnt = 0;
+
+  ARRAY<int> trigsaroundp;
+  ARRAY<int> chartpointchecked; //gets number of chart, if in this chart already checked
+  chartpointchecked.SetSize(GetNP());
+
+  for (i = 1; i <= GetNP(); i++)
+    {
+      chartpointchecked.Elem(i) = 0;
+    }
+
+  int onoc, notonoc, tpp, pn;
+  int p1, p2, tn1, tn2, l, problem;
+
+  if (!stldoctor.conecheck) {PrintWarning("++++++++++++ \ncone checking deactivated by user!!!!!\n+++++++++++++++"); return ;}
+
+  PushStatus("Find Critical Points");
+
+  int addedges = 0;
+
+  for (i = 1; i <= GetNOCharts(); i++)
+    {
+      SetThreadPercent((double)i/(double)GetNOCharts()*100.);
+      if (multithread.terminate)
+	{PopStatus();return;}
+
+      STLChart& chart = GetChart(i);
+      for (j = 1; j <= chart.GetNChartT(); j++)
+	{
+	  int t = chart.GetChartTrig(j); 
+	  const STLTriangle& tt = GetTriangle(t);
+
+	  for (k = 1; k <= 3; k++)
+	    {
+	      pn = tt.PNum(k);
+	      if (chartpointchecked.Get(pn) == i)
+		{continue;}
+	      
+	      int checkpoint = 0;
+	      for (n = 1; n <= trigsperpoint.EntrySize(pn); n++)
+		{
+		  if (trigsperpoint.Get(pn,n) != t && 
+		      GetChartNr(trigsperpoint.Get(pn,n)) != i &&
+		      !TrigIsInOC(trigsperpoint.Get(pn,n),i)) {checkpoint = 1;};
+		}
+	      if (checkpoint)
+		{
+		  chartpointchecked.Elem(pn) = i;
+
+		  int worked = 0;
+		  int spworked = 0;
+		  GetSortedTrianglesAroundPoint(pn,t,trigsaroundp);
+		  trigsaroundp.Append(t);
+		      
+		  problem = 0;
+		  for (l = 2; l <= trigsaroundp.Size()-1; l++)
+		    {
+		      tn1 = trigsaroundp.Get(l-1);
+		      tn2 = trigsaroundp.Get(l);
+		      const STLTriangle& t1 = GetTriangle(tn1);
+		      const STLTriangle& t2 = GetTriangle(tn2);
+		      t1.GetNeighbourPoints(t2, p1, p2);
+		      if (IsEdge(p1,p2)) break;
+		      
+		      if (GetChartNr(tn2) != i && !TrigIsInOC(tn2,i)) {problem = 1;}
+		    }
+
+		  if (problem)
+		    {
+		      for (l = 2; l <= trigsaroundp.Size()-1; l++)
+			{
+			  tn1 = trigsaroundp.Get(l-1);
+			  tn2 = trigsaroundp.Get(l);
+			  const STLTriangle& t1 = GetTriangle(tn1);
+			  const STLTriangle& t2 = GetTriangle(tn2);
+			  t1.GetNeighbourPoints(t2, p1, p2);
+			  if (IsEdge(p1,p2)) break;
+			  
+			  if ((GetChartNr(tn1) == i && GetChartNr(tn2) != i && TrigIsInOC(tn2,i)) ||
+			      (GetChartNr(tn2) == i && GetChartNr(tn1) != i && TrigIsInOC(tn1,i))) 				 
+			    {
+			      if (addedges || !GetNEPP(pn))
+				{
+				  STLEdge se(p1,p2);
+				  se.SetLeftTrig(tn1);
+				  se.SetRightTrig(tn2);
+				  int edgenum = AddEdge(se);
+				  AddEdgePP(p1,edgenum);
+				  AddEdgePP(p2,edgenum);
+				  edgecnt++;
+				}
+			      if (!addedges && !GetSpiralPoint(pn))
+				{
+				  SetSpiralPoint(pn);
+				  spworked = 1;
+				}
+			      worked = 1;
+			    }
+			}
+		    }
+		  //backwards:
+		  problem = 0;
+		  for (l = trigsaroundp.Size()-1; l >= 2; l--)
+		    {
+		      tn1 = trigsaroundp.Get(l+1);
+		      tn2 = trigsaroundp.Get(l);
+		      const STLTriangle& t1 = GetTriangle(tn1);
+		      const STLTriangle& t2 = GetTriangle(tn2);
+		      t1.GetNeighbourPoints(t2, p1, p2);
+		      if (IsEdge(p1,p2)) break;
+		      
+		      if (GetChartNr(tn2) != i && !TrigIsInOC(tn2,i)) {problem = 1;}
+		    }
+		  if (problem)
+		    for (l = trigsaroundp.Size()-1; l >= 2; l--)
+		      {
+			tn1 = trigsaroundp.Get(l+1);
+			tn2 = trigsaroundp.Get(l);
+			const STLTriangle& t1 = GetTriangle(tn1);
+			const STLTriangle& t2 = GetTriangle(tn2);
+			t1.GetNeighbourPoints(t2, p1, p2);
+			if (IsEdge(p1,p2)) break;
+			
+			if ((GetChartNr(tn1) == i && GetChartNr(tn2) != i && TrigIsInOC(tn2,i)) ||
+			    (GetChartNr(tn2) == i && GetChartNr(tn1) != i && TrigIsInOC(tn1,i))) 				 
+			  {
+			    if (addedges || !GetNEPP(pn))
+			      {
+				STLEdge se(p1,p2);
+				se.SetLeftTrig(tn1);
+				se.SetRightTrig(tn2);
+				int edgenum = AddEdge(se);
+				AddEdgePP(p1,edgenum);
+				AddEdgePP(p2,edgenum);
+				edgecnt++;
+			      }
+			    if (!addedges && !GetSpiralPoint(pn))
+			      {
+				SetSpiralPoint(pn);
+				spworked = 1;
+				//if (GetNEPP(pn) == 0) {(*mycout) << "ERROR: spiralpoint with no edge found!" << endl;}
+			      }
+			    worked = 1;
+			  }
+		      }
+
+		  if (worked)
+		    {		      
+		      //(*testout) << "set edgepoint due to spirals: pn=" << i << endl;
+		      SetLineEndPoint(pn);
+		    }
+		  if (spworked)
+		    {		
+		      /*      
+		      (*mycout) << "Warning: Critical Point " << tt.PNum(k) 
+			   << "( chart " << i << ", trig " << t
+			   << ") has been neutralized!!!" << endl;
+		      */
+		      cnt++;
+		    }
+		  //		  markedpoints.Elem(tt.PNum(k)) = 1;
+		}
+	    }
+	}
+    }
+  PrintMessage(5, "found ", cnt, " critical points!");
+  PrintMessage(5, "added ", edgecnt, " edges due to critical points!");
+
+  PopStatus();
+
+  //search points where inner chart and outer chart and "no chart" trig come together at edge-point
+
+  PrintMessage(7,"search for special chart points");
+  for (i = 1; i <= GetNOCharts(); i++)
+    {
+      STLChart& chart = GetChart(i);
+      for (j = 1; j <= chart.GetNChartT(); j++)
+	{
+	  int t = chart.GetChartTrig(j); 
+	  const STLTriangle& tt = GetTriangle(t);
+
+	  for (k = 1; k <= 3; k++)
+	    {
+	      pn = tt.PNum(k);
+	      if (GetNEPP(pn) == 2)
+		{
+		  onoc = 0;
+		  notonoc = 0;
+		  for (n = 1; n <= trigsperpoint.EntrySize(pn); n++)
+		    {
+		      tpp = trigsperpoint.Get(pn,n);
+		      if (tpp != t && GetChartNr(tpp) != i)
+			{
+			  if (TrigIsInOC(tpp,i)) {onoc = 1;}
+			  if (!TrigIsInOC(tpp,i)) {notonoc = 1;}
+			}
+		    }
+		  if (onoc && notonoc && !IsLineEndPoint(pn)) 
+		    {
+		      GetSortedTrianglesAroundPoint(pn,t,trigsaroundp);
+		      int here = 1; //we start on this side of edge, !here = there
+		      int thereOC = 0;
+		      int thereNotOC = 0;
+		      for (l = 2; l <= trigsaroundp.Size(); l++)
+			{
+			  GetTriangle(trigsaroundp.Get(l-1)).
+			    GetNeighbourPoints(GetTriangle(trigsaroundp.Get(l)), p1, p2);
+			  if (IsEdge(p1,p2)) {here = (here+1)%2;}
+			  if (!here && TrigIsInOC(trigsaroundp.Get(l),i)) {thereOC = 1;}
+			  if (!here && !TrigIsInOC(trigsaroundp.Get(l),i)) {thereNotOC = 1;}
+			}
+		      if (thereOC && thereNotOC)
+			{
+			  //(*mycout) << "Special OCICnotC - point " << pn << " found!" << endl;
+			  //(*testout) << "set edgepoint due to spirals: pn=" << i << endl;
+			  SetLineEndPoint(pn);
+			}
+		    }
+		}
+	    }
+	}
+    }
+  PrintMessage(5,"have now ", GetNE(), " edges with yellow angle = ", stlparam.yangle, " degree");
+}
+
+//get trigs at a point, started with starttrig, then every left
+void STLGeometry :: GetSortedTrianglesAroundPoint(int p, int starttrig, ARRAY<int>& trigs)
+{
+  int acttrig = starttrig;
+  trigs.SetAllocSize(trigsperpoint.EntrySize(p));
+  trigs.SetSize(0);
+  trigs.Append(acttrig);
+  int i, j, t, p1, p2, locindex1, locindex2;
+
+  //(*mycout) << "trigs around point " << p << endl;
+
+  int end = 0;
+  while (!end)
+    {
+      const STLTriangle& at = GetTriangle(acttrig);
+      for (i = 1; i <= trigsperpoint.EntrySize(p); i++)
+	{
+	  t = trigsperpoint.Get(p,i);
+	  const STLTriangle& nt = GetTriangle(t);
+	  if (at.IsNeighbourFrom(nt))
+	    {
+	      at.GetNeighbourPoints(nt, p1, p2);
+	      if (p2 == p) {Swap(p1,p2);}
+	      if (p1 != p) {PrintSysError("In GetSortedTrianglesAroundPoint!!!");}
+	      
+	      for (j = 1; j <= 3; j++) 
+		{
+		  if (at.PNum(j) == p1) {locindex1 = j;};
+		  if (at.PNum(j) == p2) {locindex2 = j;};
+		}
+	      if ((locindex2+1)%3+1 == locindex1) 
+		{
+		  if (t != starttrig)
+		    {
+		      trigs.Append(t);
+		      //		      (*mycout) << "trig " << t << endl;
+		      acttrig = t;
+		    }
+		  else
+		    {
+		      end = 1;
+		    }
+		  break;
+		}
+	    }
+	}
+    }
+  
+}
+
+/*
+int STLGeometry :: NeighbourTrig(int trig, int nr) const
+{
+  return neighbourtrigs.Get(trig,nr);
+}
+*/
+
+
+
+void STLGeometry :: SmoothGeometry ()
+{
+  int i, j, k;
+  
+  int np = GetNP();
+  double maxerr0, maxerr;
+
+  for (i = 1; i <= np; i++)
+    {
+      if (GetNEPP(i)) continue;
+      
+      maxerr0 = 0;
+      for (j = 1; j <= NOTrigsPerPoint(i); j++)
+	{
+	  int tnum = TrigPerPoint(i, j);
+	  double err = Angle (GetTriangle(tnum).Normal (), 
+			      GetTriangle(tnum).GeomNormal(GetPoints()));
+	  if (err > maxerr0)
+	    maxerr0 = err;
+	}
+
+      Point3d pi = GetPoint (i);
+      if (maxerr0 < 1.1) continue;    // about 60 degree
+
+      maxerr0 /= 2;  // should be at least halfen
+      
+      for (k = 1; k <= NOTrigsPerPoint(i); k++)
+	{
+	  const STLTriangle & trig = GetTriangle (TrigPerPoint (i, k));
+	  Point3d c = Center(GetPoint (trig.PNum(1)),
+			     GetPoint (trig.PNum(2)),
+			     GetPoint (trig.PNum(3)));
+
+	  Point3d np = pi + 0.1 * (c - pi);
+	  SetPoint (i, np);
+	  
+	  maxerr = 0;
+	  for (j = 1; j <= NOTrigsPerPoint(i); j++)
+	    {
+	      int tnum = TrigPerPoint(i, j);
+	      double err = Angle (GetTriangle(tnum).Normal (), 
+				  GetTriangle(tnum).GeomNormal(GetPoints()));
+	      if (err > maxerr)
+		maxerr = err;
+	    }
+	  
+	  if (maxerr < maxerr0)
+	    {
+	      pi = np;
+	    }
+	}
+
+      SetPoint (i, pi);
+    }
+}
+}
diff --git a/Netgen/libsrc/stlgeom/stlgeom.hpp b/Netgen/libsrc/stlgeom/stlgeom.hpp
new file mode 100644
index 0000000000..2ac1cd1e36
--- /dev/null
+++ b/Netgen/libsrc/stlgeom/stlgeom.hpp
@@ -0,0 +1,450 @@
+#ifndef FILE_STLGEOM
+#define FILE_STLGEOM
+
+/**************************************************************************/
+/* File:   stlgeom.hpp                                                     */
+/* Author: Joachim Schoeberl                                              */
+/* Author2: Johannes Gerstmayr                                            */
+/* Date:   26. Jul. 99                                                    */
+/**************************************************************************/
+
+/**
+   STL Geometry
+
+
+   Terminology:
+   
+   Point ... coordinates of STL triangles
+   Triangle  (short Trig)  STL triangle
+   TopEdge .... edge in topology, boundary of STL triangles (many)
+   Edge .... Edges which will occur in the mesh (confirmed edges, less)
+*/
+
+
+#include <gprim.hpp>
+#include <meshing.hpp>
+
+
+
+namespace netgen
+{
+  extern int IsInArray(int n, const ARRAY<int>& ia);
+  extern int AddIfNotExists(ARRAY<int>& list, int x);
+
+
+#include "stltopology.hpp"
+#include "stltool.hpp"
+#include "stlline.hpp"
+
+
+
+
+
+
+
+  class STLEdgeDataList
+  {
+    ARRAY<int> storedstatus;
+    STLTopology & geom;
+  public:
+  
+    STLEdgeDataList(STLTopology & ageom);
+    ~STLEdgeDataList();
+
+    void Store ();
+    void Restore ();
+
+    void SetSize(int size) { };
+    void Clear() { };
+    int Size() const { return geom.GetNTE(); }
+    const STLTopEdge & Get(int i) const { return geom.GetTopEdge(i); }
+    STLTopEdge & Elem(int i) { return geom.GetTopEdge(i); }
+
+    int GetNEPP(int pn) const {return geom.NTopEdgesPerPoint(pn); }
+    int GetEdgePP(int pn, int vi) const {return geom.TopEdgePerPoint(pn, vi);};
+
+    //void AddEdgePP(int pn, int vn) { } ;
+
+    void ResetAll();
+    void ChangeStatus(int status1, int status2);
+
+    int GetEdgeNum(int np1, int np2) const
+    { return geom.GetTopEdgeNum (np1, np2); }
+
+    int GetNConfEdges() const;
+
+    void Write(ofstream& of) const;
+    void Read(ifstream& ifs);
+
+    void BuildLineWithEdge(int ep1, int ep2, ARRAY<twoint>& line);
+    void BuildClusterWithEdge(int ep1, int ep2, ARRAY<twoint>& line);
+
+    int GetNEPPStat(int p, int status) const;
+    int GetNConfCandEPP(int p) const;
+  };
+
+
+
+
+
+
+  class STLGeometry : public STLTopology
+  {
+    // edges to be meshed:
+    ARRAY<STLEdge> edges;
+    //edges per point
+    TABLE<int> edgesperpoint;
+
+    // line: a connection of edges
+    ARRAY<STLLine*> lines;
+    ARRAY<int> lineendpoints; //per geometrypoint, 1 = is endpoint; 0 = no endpoint,
+
+    ARRAY<Vec3d> normals; //normals belong to points!
+
+    ARRAY<twoint> externaledges;
+
+    int undoexternaledges;
+    ARRAY<twoint> storedexternaledges;
+
+    STLEdgeDataList edgedata;
+    //  STLEdgeDataList edgedata_store;
+    int calcedgedataanglesnew;
+
+    int edgedatastored;
+
+
+
+    int facecnt; 
+    //meshpoint is only set, if an edge is at this point!!!
+
+    ARRAY<int> vicinity; //is one, if a triangle belongs to vicinity (eg. of selecttrig)
+    ARRAY<int> markedtrigs; //is one, if a triangle belongs to marked triangles (calcdirtystrigs)
+    ARRAY<Point3d> markedsegs; //every pointpair is a segment!!!  
+    ARRAY<twoint> selectedmultiedge;
+
+
+    //spiralpoints:
+    ARRAY<int> spiralpoints;
+    //
+    ARRAY<STLChart*> atlas;
+    //marks all already charted trigs with chartnumber
+    ARRAY<int> chartmark; 
+    //outerchartspertrig, ascending sorted
+    TABLE<int> outerchartspertrig;
+
+
+    //for meshing and project:
+    ARRAY<int> meshcharttrigs; //per trig: 1=belong to chart, 0 not
+    int meshchart;
+
+    ARRAY<int> ha_points;  // help array, np long, filled with 0 
+
+
+    // sharp geometric edges not declared as edges
+    // (not considered for spiral check)
+    INDEX_2_HASHTABLE<int> * smoothedges;
+
+
+    //transformation:
+    Vec<3> meshtrignv;
+    Vec<3> ex, ey, ez;
+    Point<3> p1;
+
+  public:
+    int edgesfound;
+    int surfacemeshed;
+    int surfaceoptimized;
+    int volumemeshed;
+
+    int trigsconverted; //when STLTriangles exist -> 1
+
+    //for selecting nodes
+    //int selecttrig, nodeofseltrig;
+
+    //only for testing;
+    ARRAY<STLLine*> meshlines;
+    ARRAY<Point3d> meshpoints;
+
+  public:
+    STLGeometry();
+    virtual ~STLGeometry();
+
+
+    void Clear();
+
+
+
+    void STLInfo(double* data);
+    //stldoctor:
+    void SmoothNormals();
+    void MarkNonSmoothNormals();
+
+    void CalcEdgeData();
+    void CalcEdgeDataAngles();
+
+    const STLEdgeDataList& EdgeDataList() const {return edgedata;}
+
+    void UndoEdgeChange();
+    void StoreEdgeData();
+    void RestoreEdgeData();
+
+    //void ClearSelectedMultiEdge() {selectedmultiedge.SetSize(0);}
+    //void AddSelectedMultiEdge(twoint ep) {selectedmultiedge.Append(ep);}
+    //int SelectedMultiEdgeSize() {return selectedmultiedge.Size();}
+    const ARRAY<twoint>& SelectedMultiEdge() {return selectedmultiedge;}
+    twoint GetNearestSelectedDefinedEdge();
+    void BuildSelectedMultiEdge(twoint ep);
+    void BuildSelectedEdge(twoint ep);
+    void BuildSelectedCluster(twoint ep);
+
+    void ImportEdges();
+    void AddEdges(const ARRAY<Point<3> >& eps);
+    void ExportEdges();
+    void LoadEdgeData(const char* file);
+    void SaveEdgeData(const char* file);
+    //  void SetEdgeAtSelected(int mode);
+  
+
+    void STLDoctorConfirmEdge();
+    void STLDoctorCandidateEdge();
+    void STLDoctorExcludeEdge();
+    void STLDoctorUndefinedEdge();
+
+    void STLDoctorSetAllUndefinedEdges();
+    void STLDoctorEraseCandidateEdges();
+    void STLDoctorConfirmCandidateEdges();
+    void STLDoctorConfirmedToCandidateEdges();
+
+    void STLDoctorDirtyEdgesToCandidates();
+    void STLDoctorLongLinesToCandidates();
+
+    void UndoExternalEdges();
+    void StoreExternalEdges();
+    void RestoreExternalEdges();
+
+    void ImportExternalEdges(const char * filename);  // Flame edges, JS
+    //  void LoadExternalEdges();
+
+    void BuildExternalEdgesFromEdges();
+    void SaveExternalEdges();
+    void AddExternalEdgeAtSelected();
+    void AddClosedLinesToExternalEdges();
+    void AddLongLinesToExternalEdges();
+    void AddAllNotSingleLinesToExternalEdges();
+    void STLDoctorBuildEdges();
+    void AddExternalEdgesFromGeomLine();
+    void DeleteDirtyExternalEdges();
+    void DeleteExternalEdgeAtSelected();
+    void DeleteExternalEdgeInVicinity();
+    void AddExternalEdge(int p1, int p2);
+    void DeleteExternalEdge(int p1, int p2);
+    int IsExternalEdge(int p1, int p2);
+    int NOExternalEdges() const {return externaledges.Size();}
+    twoint GetExternalEdge(int i) const {return externaledges.Get(i);}
+
+    void DestroyDirtyTrigs();
+    void CalcNormalsFromGeometry();
+    void MoveSelectedPointToMiddle();
+    void NeighbourAnglesOfSelectedTrig();
+    void PrintSelectInfo();
+    void ShowSelectedTrigChartnum();
+    void ShowSelectedTrigCoords();
+    void SmoothGeometry ();
+
+
+    void LoadMarkedTrigs();
+    void SaveMarkedTrigs();
+    void ClearMarkedSegs() {markedsegs.SetSize(0);}
+    void AddMarkedSeg(const Point<3> & p1, const Point<3> & p2) 
+    {
+      markedsegs.Append(p1);markedsegs.Append(p2);
+    }
+
+    void GetMarkedSeg(int i, Point<3> & p1, Point<3> & p2) 
+    {
+      p1=markedsegs.Get(i*2-1); 
+      p2=markedsegs.Get(i*2);
+    }
+    int GetNMarkedSegs() {return markedsegs.Size()/2;}
+    void CalcVicinity(int starttrig);
+    void GetVicinity(int starttrig, int size, ARRAY<int>& vic);
+
+    int Vicinity(int trig) const;
+
+    void InitMarkedTrigs();
+    void MarkDirtyTrigs();
+    void SmoothDirtyTrigs();
+    void GeomSmoothRevertedTrigs();
+    void MarkRevertedTrigs();
+    double CalcTrigBadness(int i);
+    int IsMarkedTrig(int trig) const;
+    void SetMarkedTrig(int trig, int num);
+    void MarkTopErrorTrigs ();
+
+    //Selected triangle
+    void SetSelectTrig(int trig);
+    int GetSelectTrig() const;
+    void SetNodeOfSelTrig(int n);
+    int GetNodeOfSelTrig() const;
+
+
+    int AddNormal(const Vec3d& n) {return normals.Append(n);}
+    const Vec3d & GetNormal(int nr) const {return normals.Get(nr);}
+    void SetNormal(int nr, const Vec3d& n) {normals.Elem(nr) = n;}
+
+    int AddEdge(const STLEdge& v) {return edges.Append(v);}
+    int AddEdge(int p1, int p2);
+
+    STLEdge GetEdge(int nr) {return edges.Get(nr);}
+    int GetNE() {return edges.Size();}
+
+    double Area();
+
+    double GetAngle(int t1, int t2);
+    double GetGeomAngle(int t1, int t2);
+    //if triangles t1 and t2 touch, return 1 and in p1, p2 the touching points
+    //int TrigsTouch(int t1, int t2, int& p1, int& p2);
+
+
+  
+    ///
+
+    ///ReadTriangle->STLTriangle, initialise some important variables, always after load!!!
+    virtual void InitSTLGeometry (const ARRAY<STLReadTriangle> & readtrigs);
+    virtual void TopologyChanged(); //do some things, if topology changed!
+    int CheckGeometryOverlapping();
+
+    //get NO edges per point
+    int GetEPPSize() const {return edgesperpoint.Size();};
+    int GetNEPP(int pn) 
+    {
+      if (edgesperpoint.Size() == 0) {BuildEdgesPerPoint();}
+      return edgesperpoint.EntrySize(pn);
+    };
+    int GetEdgePP(int pn, int vi)
+    {
+      if (edgesperpoint.Size() == 0) {BuildEdgesPerPoint();}
+      return edgesperpoint.Get(pn,vi);
+    };
+    void AddEdgePP(int pn, int vn) {edgesperpoint.Add1(pn,vn);};
+    //von 2 punkten ermitteln, ob sie eine Kante sind
+    int IsEdge(int p1, int p2);
+    int IsEdgeNum(int p1, int p2);
+
+    ///Build EdgeSegments
+    void ClearEdges();
+    void BuildEdges();
+    void BuildEdgesPerPoint();
+    void UseExternalEdges();
+
+
+    void FindEdgesFromAngles();
+    void CalcFaceNums();
+    int GetNOBodys();
+    int GetNOFaces() {return facecnt;}
+    void LinkEdges();
+
+    void AddConeAndSpiralEdges();
+    void AddFaceEdges(); //each face should have at least one starting edge (outherwise it won't be meshed)
+
+    void GetDirtyChartTrigs(int chartnum, STLChart& chart, const ARRAY<int>& outercharttrigs, 
+			    ARRAY<int>& chartpointchecked, ARRAY<int>& dirtytrigs);
+
+    void ClearSpiralPoints();
+    void SetSpiralPoint(int pn) {spiralpoints.Elem(pn) = 1;};
+    int GetSpiralPoint(int pn) const {return spiralpoints.Get(pn);};
+
+    void GetSortedTrianglesAroundPoint(int p, int starttrig, ARRAY<int>& trigs);
+
+    // smooth edges: sharp geometric edges not declared as edges
+    void BuildSmoothEdges ();
+    int IsSmoothEdge (int pi1, int pi2) const;
+
+
+    //make charts with regions of a max. angle
+    void MakeAtlas(class Mesh & mesh);
+
+    //outerchartspertrig, sorted!
+    int GetOCPTSize() const {return outerchartspertrig.Size();};
+    int GetNOCPT(int tn) const {return outerchartspertrig.EntrySize(tn);};
+    int GetOCPT(int tn, int vi) const {return outerchartspertrig.Get(tn,vi);};
+    void SetOCPT(int tn, int vi, int ocn) {outerchartspertrig.Set(tn,vi,ocn);};
+    void AddOCPT(int tn, int ocn) {outerchartspertrig.Add1(tn, ocn);};
+    int TrigIsInOC(int tn, int ocn) const;
+ 
+    //get chart number of a trig or 0 if unmarked
+    int GetChartNr(int i) const;
+    int GetMarker(int i) const 
+    { return chartmark.Get(i); }
+    void SetMarker(int nr, int m);
+    int GetNOCharts() const;
+    //get a chart from atlas
+    const STLChart& GetChart(int nr) const;
+    STLChart& GetChart(int nr) {return *(atlas.Get(nr));};
+    int AtlasMade() const;
+  
+    void GetInnerChartLimes(ARRAY<twoint>& limes, int chartnum);
+
+    //FOR MESHING
+    int GetMeshChartNr () { return meshchart; }
+    void GetMeshChartBoundary (ARRAY<Point2d > & points,
+			       ARRAY<Point3d > & points3d,
+			       ARRAY<INDEX_2> & lines, double h);
+
+
+    Point<3> PointBetween(const Point<3> & p1, int t1, const Point<3> & p2, int t2);
+
+    //select triangles in meshcharttrigs of actual (defined by trig) whole chart
+    void PrepareSurfaceMeshing();
+    //
+    void DefineTangentialPlane(const Point<3> & ap1, const Point<3> & ap2, int trig);
+    //
+    void SelectChartOfTriangle (int trignum);
+    //
+    void SelectChartOfPoint (const Point<3> & p);
+    //
+    const Vec<3> & GetChartNormalVector () const { return meshtrignv; }
+
+    // list of trigs
+    void ToPlane (const Point<3> & locpoint, int * trigs, Point<2> & plainpoint, 
+		  double h, int& zone, int checkchart);
+    //return 0, wenn alles OK, 1 sonst
+    int FromPlane (const Point<2> & plainpoint, Point<3> & locpoint, double h);
+  
+    //get nearest point in actual chart and return any triangle where it lies on
+    int ProjectNearest(Point<3> & p3d) const;
+    //project point with normal nv from last define tangential plane
+
+    int LastTrig() const;
+    int Project(Point<3> & p3d) const;
+    int ProjectOnWholeSurface (Point<3> & p3d) const;
+
+    int GetNLines() const {return lines.Size();}
+    int AddLine(STLLine* line) {return lines.Append(line);}
+    STLLine* GetLine(int nr) const {return lines.Get(nr);}
+    int GetLineP(int lnr, int pnr) const {return lines.Get(lnr)->PNum(pnr);}
+    int GetLineNP(int nr) const {return lines.Get(nr)->NP();}
+
+    void SetLineEndPoint(int pn);
+    int IsLineEndPoint(int pn);
+    int LineEndPointsSet() const {return lineendpoints.Size() == GetNP();}
+    void ClearLineEndPoints();
+
+    void RestrictLocalH(class Mesh & mesh, double gh);
+    void RestrictLocalHCurv(class Mesh & mesh, double gh);
+    void RestrictHChartDistOneChart(int chartnum, ARRAY<int>& acttrigs, class Mesh & mesh, 
+				    double gh, double fact, double minh);
+
+    friend class MeshingSTLSurface;
+  };
+ 
+
+#include "meshstlsurface.hpp"
+
+
+  extern int STLMeshingDummy (STLGeometry* stlgeometry, Mesh*& mesh,
+			      int perfstepsstart, int perfstepsend, char* optstring);
+
+
+}
+#endif
diff --git a/Netgen/libsrc/stlgeom/stlgeomchart.cpp b/Netgen/libsrc/stlgeom/stlgeomchart.cpp
new file mode 100644
index 0000000000..6e3fe8b2d3
--- /dev/null
+++ b/Netgen/libsrc/stlgeom/stlgeomchart.cpp
@@ -0,0 +1,801 @@
+//20.11.1999 third part of stlgeom.cc, functions with chart and atlas
+
+#include <mystdlib.h>
+
+#include <myadt.hpp>
+#include <linalg.hpp>
+#include <gprim.hpp>
+
+#include <meshing.hpp>
+
+#include "stlgeom.hpp"
+
+namespace netgen
+{
+
+int chartdebug = 0;
+
+
+
+void STLGeometry :: MakeAtlas(class Mesh & mesh)
+{
+
+  double h, h2;
+
+  h = mparam.maxh;
+   
+
+  PushStatusF("Make Atlas");
+
+  int i,j,k,l,m,ctl;
+
+  double atlasminh = 5e-3 * Dist (boundingbox.PMin(), boundingbox.PMax());
+  PrintMessage(5, "atlasminh = ", atlasminh);
+
+  //speedup for make atlas
+  if (GetNT() > 50000)
+    {
+      mesh.SetGlobalH(0.05*Dist (boundingbox.PMin(), boundingbox.PMax()));
+    }
+
+
+  atlas.SetSize(0);
+  ClearSpiralPoints();
+  BuildSmoothEdges();
+  
+
+  double chartangle = stlparam.chartangle;
+  double outerchartangle = stlparam.outerchartangle;
+
+  chartangle = chartangle/180.*M_PI;
+  outerchartangle = outerchartangle/180.*M_PI;
+
+  double coschartangle = cos(chartangle);
+  double cosouterchartangle = cos(outerchartangle);
+  double cosouterchartanglehalf = cos(0.5*outerchartangle);
+  double sinchartangle = sin(chartangle);
+  double sinouterchartangle = sin(outerchartangle);
+
+  ARRAY<int> outermark(GetNT()); //marks all trigs form actual outer region
+  ARRAY<int> outertested(GetNT()); //marks tested trigs for outer region
+  ARRAY<int> pointstochart(GetNP()); //point in chart becomes chartnum
+  ARRAY<int> innerpointstochart(GetNP()); //point in chart becomes chartnum
+  ARRAY<int> chartpoints; //point in chart becomes chartnum
+  ARRAY<int> innerchartpoints;
+  ARRAY<int> dirtycharttrigs;
+  ARRAY<int> chartpointchecked;
+
+  ARRAY<int> chartdistacttrigs; //outercharttrigs
+  chartdistacttrigs.SetSize(GetNT());
+  for (i = 1; i <= GetNT(); i++)
+    {
+      chartdistacttrigs.Elem(i) = 0;
+    }
+  
+  STLBoundary chartbound(this); //knows the actual chart boundary
+  int chartboundarydivisions = 10;
+  markedsegs.SetSize(0); //for testing!!!
+
+  chartpointchecked.SetSize(GetNP()); //for dirty-chart-trigs
+
+  outermark.SetSize(GetNT());
+  outertested.SetSize(GetNT());
+  pointstochart.SetSize(GetNP());
+  innerpointstochart.SetSize(GetNP());
+  chartmark.SetSize(GetNT());
+
+  for (i = 1; i <= GetNP(); i++)
+    {
+      innerpointstochart.Elem(i) = 0;
+      pointstochart.Elem(i) = 0;
+      chartpointchecked.Elem(i) = 0;
+    }
+
+  double eps = 1e-12 * Dist (boundingbox.PMin(), boundingbox.PMax());
+
+  int spiralcheckon = stldoctor.spiralcheck;
+  if (!spiralcheckon) {PrintWarning("++++++++++++\nspiral deactivated by user!!!!\n+++++++++++++++"); }
+
+  for (i = 1; i <= GetNT(); i++)
+    {
+      chartmark.Elem(i) = 0;
+    }
+
+  for (i = 1; i <= GetNT(); i++)
+    {
+      outermark.Elem(i) = 0;
+      outertested.Elem(i) = 0;
+    }
+
+  int markedtrigcnt = 0;
+  int found = 1;
+  double atlasarea = Area();
+  double workedarea = 0;
+  double showinc = 100.*5000./(double)GetNT();
+  double nextshow = 0;
+  Point<3> startp;
+  int lastunmarked = 1;
+  int prelastunmarked;
+
+  PrintMessage(5,"one dot per 5000 triangles: ");
+
+  while(markedtrigcnt < GetNT() && found)
+    {      
+      if (multithread.terminate)
+	{PopStatus();return;}
+
+      if (workedarea / atlasarea*100. >= nextshow) 
+      	{PrintDot(); nextshow+=showinc;}
+
+      SetThreadPercent(100.0 * workedarea / atlasarea);
+
+      /*
+      for (j = 1; j <= GetNT(); j++)
+	{
+	  outermark.Elem(j) = 0;
+	}
+      */
+      STLChart * chart = new STLChart(this);
+      atlas.Append(chart);
+
+      //find unmarked trig
+      prelastunmarked = lastunmarked;
+      j = lastunmarked;
+      found = 0;
+      while (!found && j <= GetNT())
+	{
+	  if (!GetMarker(j)) {found = 1; lastunmarked = j;}
+	  else {j++;}
+	}
+
+      chartpoints.SetSize(0);  
+      innerchartpoints.SetSize(0);
+      chartbound.Clear();
+      chartbound.SetChart(chart);
+
+      if (!found) {PrintSysError("Make Atlas, no starttrig found"); return;}
+
+      //find surrounding trigs
+      int starttrig = j;
+
+      double mindist, tdist;
+      startp = GetPoint(GetTriangle(starttrig).PNum(1));
+
+      int accepted;
+      int chartnum = GetNOCharts();
+	  
+      Vec<3> sn = GetTriangle(starttrig).Normal();
+      chart->SetNormal (startp, sn);
+
+
+      SetMarker(starttrig, chartnum);
+      markedtrigcnt++;
+      chart->AddChartTrig(starttrig);
+      chartbound.AddTriangle(GetTriangle(starttrig));
+
+      workedarea += GetTriangle(starttrig).Area(points);
+
+      for (i = 1; i <= 3; i++)
+	{	      
+	  innerpointstochart.Elem(GetTriangle(starttrig).PNum(i)) = chartnum;
+	  pointstochart.Elem(GetTriangle(starttrig).PNum(i)) = chartnum;
+	  chartpoints.Append(GetTriangle(starttrig).PNum(i));
+	  innerchartpoints.Append(GetTriangle(starttrig).PNum(i));
+	}
+
+      Vec<3> n2, n3;
+      int changed = 1;
+      int nt;
+      int ic;
+      int oldstartic = 1;
+      int oldstartic2;
+      int np1, np2;
+
+      while (changed)
+	{   
+	  changed = 0;
+	  oldstartic2 = oldstartic;
+	  oldstartic = chart->GetNT();
+	  //	      for (ic = oldstartic2; ic <= chart->GetNT(); ic++)
+	  for (ic = oldstartic2; ic <= oldstartic; ic++)
+	    {
+	      i = chart->GetTrig(ic);
+	      if (GetMarker(i) == chartnum)
+		{
+		  for (j = 1; j <= NONeighbourTrigs(i); j++)
+		    {
+		      nt = NeighbourTrig(i,j);
+		      GetTriangle(i).GetNeighbourPoints(GetTriangle(nt),np1,np2);
+		      if (GetMarker(nt) == 0 && !IsEdge(np1,np2))
+			{
+			  n2 = GetTriangle(nt).Normal();
+			  if ( (n2 * sn) >= coschartangle )
+			    {
+			      
+			      accepted = 1;
+			      /*
+				//alter spiralentest, schnell, aber ungenau
+			      for (k = 1; k <= 3; k++)
+				{
+				  //find overlapping charts:
+				  Point3d pt = GetPoint(GetTriangle(nt).PNum(k));
+				  if (innerpointstochart.Get(GetTriangle(nt).PNum(k)) != chartnum)
+				    {
+				      for (l = 1; l <= chartpoints.Size(); l++)
+					{
+					  Vec3d vptpl(GetPoint(chartpoints.Get(l)), pt);
+					  double vlen = vptpl.Length();
+					  if (vlen > 0)
+					    {
+					      vptpl /= vlen;
+					      if ( fabs( vptpl * sn) > sinchartangle )
+						{
+						  accepted = 0;
+						  break;
+						}
+					    } 
+					}
+
+				    }
+				}
+			      */
+			      
+			      int nnp1, nnp2; 
+			      int nnt; 
+			      //find overlapping charts exacter: 
+			      for (k = 1; k <= 3; k++) 
+				{ 
+				  nnt = NeighbourTrig(nt,k);
+				  if (GetMarker(nnt) != chartnum)
+				    {
+				      GetTriangle(nt).GetNeighbourPoints(GetTriangle(nnt),nnp1,nnp2);
+
+				      accepted = chartbound.TestSeg(GetPoint(nnp1),
+								    GetPoint(nnp2),
+								    sn,sinchartangle,1 /*chartboundarydivisions*/ ,points, eps);
+
+
+				      n3 = GetTriangle(nnt).Normal();
+				      if ( (n3 * sn) >= coschartangle  &&
+					   IsSmoothEdge (nnp1, nnp2) )
+					accepted = 1;
+				    }
+				  if (!accepted) {break;}
+				}
+			      
+			      /*
+				mindist = 1E50;
+				for (int ii = 1; ii <= 3; ii++)
+				{
+				tdist = Dist(GetPoint(GetTriangle(nt).PNum(ii)),startp);
+				if (tdist < mindist) {mindist = tdist;}
+				}
+				if (mindist > maxdist1) {accepted = 0;}
+			      */
+
+			      if (accepted)
+				{
+				  SetMarker(nt, chartnum); 
+				  changed = 1;
+				  markedtrigcnt++;
+				  workedarea += GetTriangle(nt).Area(points);
+				  chart->AddChartTrig(nt);
+
+				  chartbound.AddTriangle(GetTriangle(nt));
+
+				  for (k = 1; k <= 3; k++)
+				    {
+				      if (innerpointstochart.Get(GetTriangle(nt).PNum(k))
+					  != chartnum) 
+					{
+					  innerpointstochart.Elem(GetTriangle(nt).PNum(k)) = chartnum;
+					  pointstochart.Elem(GetTriangle(nt).PNum(k)) = chartnum;
+					  chartpoints.Append(GetTriangle(nt).PNum(k));
+					  innerchartpoints.Append(GetTriangle(nt).PNum(k));
+					}
+				    }
+				}
+			    }	       
+			}
+		    }
+		}
+	    }
+	}
+
+
+      //find outertrigs
+
+      //      chartbound.Clear(); 
+      // warum, ic-bound auf edge macht Probleme js ???
+
+
+      outermark.Elem(starttrig) = chartnum;
+      //chart->AddOuterTrig(starttrig);
+      changed = 1;
+      oldstartic = 1;
+      while (changed)
+	{   
+	  changed = 0;
+	  oldstartic2 = oldstartic;
+	  oldstartic = chart->GetNT();
+	  //for (ic = oldstartic2; ic <= chart->GetNT(); ic++)
+	  for (ic = oldstartic2; ic <= oldstartic; ic++)
+	    {
+	      i = chart->GetTrig(ic);
+
+	      if (outermark.Get(i) == chartnum)
+		{
+		  for (j = 1; j <= NONeighbourTrigs(i); j++)
+		    {
+		      nt = NeighbourTrig(i,j);
+		      if (outermark.Get(nt) == chartnum)
+			continue;
+
+		      const STLTriangle & ntrig = GetTriangle(nt);
+		      GetTriangle(i).GetNeighbourPoints(GetTriangle(nt),np1,np2);
+
+		      if (IsEdge (np1, np2))
+			continue;
+
+
+		      /*
+		      if (outertested.Get(nt) == chartnum)
+			continue;
+		      */
+		      outertested.Elem(nt) = chartnum;
+			  
+
+		      n2 = GetTriangle(nt).Normal();
+		      /*
+			double ang;
+			ang = Angle(n2,sn);
+			if (ang < -M_PI*0.5) {ang += 2*M_PI;}
+			    
+			(*testout) << "ang < ocharang = " << (fabs(ang) <= outerchartangle);
+			(*testout) << " = " << ( (n2 * sn) >= cosouterchartangle) << endl;
+			    
+			//			      if (fabs(ang) <= outerchartangle) 
+		      */
+		      //abfragen, ob noch im tolerierten Winkel
+		      if ( (n2 * sn) >= cosouterchartangle )
+			{
+			  accepted = 1;
+
+			  int isdirtytrig = 0;
+			  Vec<3> gn = GetTriangle(nt).GeomNormal(points);
+			  double gnlen = gn.Length();
+			  
+			  if (n2 * gn <= cosouterchartanglehalf * gnlen)
+			    {isdirtytrig = 1;}
+			  
+			  //zurueckweisen, falls eine Spiralartige outerchart entsteht
+			  int nnp1, nnp2; 
+			  int nnt; 
+			  //find overlapping charts exacter: 
+			  //do not check dirty trigs!
+			  
+
+			  if (spiralcheckon && !isdirtytrig)
+			    for (k = 1; k <= 3; k++) 
+			      { 
+				nnt = NeighbourTrig(nt,k);
+				
+				if (outermark.Elem(nnt) != chartnum)
+				  {
+				    GetTriangle(nt).GetNeighbourPoints(GetTriangle(nnt),nnp1,nnp2);
+
+				    accepted = 
+				      chartbound.TestSeg(GetPoint(nnp1),GetPoint(nnp2),
+							 sn,sinouterchartangle, 0 /*chartboundarydivisions*/ ,points, eps);
+				    
+
+				    n3 = GetTriangle(nnt).Normal();
+				    if ( (n3 * sn) >= cosouterchartangle  &&
+					 IsSmoothEdge (nnp1, nnp2) )
+				      accepted = 1;
+				  }
+				if (!accepted) {break;}
+			      }
+			  
+			  //}
+		      
+		      
+			  // outer chart is only small environment of
+			  //    inner chart:
+			  if (accepted)
+			    {
+			      accepted = 0;
+
+			      for (k = 1; k <= 3; k++)
+				{
+				  if (innerpointstochart.Get(ntrig.PNum(k)) == chartnum)
+				    {
+				      accepted = 1; 
+				      break;
+				    }
+				}
+
+			      if (!accepted)
+				for (k = 1; k <= 3; k++)
+				  {
+				    Point<3> pt = GetPoint(ntrig.PNum(k));					  
+				    h2 = sqr(mesh.GetH(pt));
+				      
+				    for (l = 1; l <= innerchartpoints.Size(); l++)
+				      {
+					tdist = Dist2(pt, GetPoint (innerchartpoints.Get(l)));
+					if (tdist < 4 * h2)
+					  {
+					    accepted = 1; 
+					    break;
+					  }
+				      }
+				    if (accepted) {break;}
+				  }
+			    }
+
+			      
+			  if (accepted)
+			    {
+			      changed = 1;
+			      outermark.Elem(nt) = chartnum;
+
+			      if (GetMarker(nt) != chartnum)
+				{
+				  chartbound.AddTriangle(GetTriangle(nt));
+				  chart->AddOuterTrig(nt);
+				  for (k = 1; k <= 3; k++)
+				    {
+				      if (pointstochart.Get(GetTriangle(nt).PNum(k))
+					  != chartnum) 
+					{
+					  pointstochart.Elem(GetTriangle(nt).PNum(k)) = chartnum;
+					  chartpoints.Append(GetTriangle(nt).PNum(k));
+					}
+				    }
+				}
+			    }
+			}	       
+		    }
+		}
+	    }            
+	}
+      //end of while loop for outer chart
+      GetDirtyChartTrigs(chartnum, *chart, outermark, chartpointchecked, dirtycharttrigs);
+      //dirtycharttrigs are local (chart) point numbers!!!!!!!!!!!!!!!!
+
+      if (dirtycharttrigs.Size() != 0 && 
+	  (dirtycharttrigs.Size() != chart->GetNChartT() || dirtycharttrigs.Size() != 1))
+	{
+	  if (dirtycharttrigs.Size() == chart->GetNChartT() && dirtycharttrigs.Size() != 1)
+	    {
+	      //if all trigs would be eliminated -> leave 1 trig!
+	      dirtycharttrigs.SetSize(dirtycharttrigs.Size() - 1);
+	    }
+	  for (k = 1; k <= dirtycharttrigs.Size(); k++)
+	    {
+	      int tn = chart->GetChartTrig(dirtycharttrigs.Get(k));
+	      outermark.Elem(tn) = 0; //not necessary, for later use
+	      SetMarker(tn, 0); 
+	      markedtrigcnt--;
+	      workedarea -= GetTriangle(tn).Area(points);
+	    }
+	  chart->MoveToOuterChart(dirtycharttrigs);
+	  lastunmarked = 1;
+	  lastunmarked = prelastunmarked;
+	}
+
+      //calculate an estimate meshsize, not to produce to large outercharts, with factor 2 larger!
+      RestrictHChartDistOneChart(chartnum, chartdistacttrigs, mesh, h, 0.5, atlasminh);
+    }
+  
+  PrintMessage(5,"");
+  PrintMessage(5,"NO charts=", atlas.Size());
+
+  int cnttrias = 0;
+  //int found2;
+  outerchartspertrig.SetSize(GetNT());
+
+  for (i = 1; i <= atlas.Size(); i++)
+    {
+      int j;
+      //found2 = 1;
+      for (j = 1; j <= GetChart(i).GetNT(); j++)
+	{
+	  int tn = GetChart(i).GetTrig(j);
+	  AddOCPT(tn,i);
+
+	}
+      
+      cnttrias += GetChart(i).GetNT();
+    }
+  PrintMessage(5, "NO outer chart trias=", cnttrias);
+
+  //sort outerchartspertrig
+  for (i = 1; i <= GetNT(); i++)
+    {
+      int j,k, swap;
+      for (k = 1; k < GetNOCPT(i); k++)
+	{
+
+	  for (j = 1; j < GetNOCPT(i); j++)
+	    {
+	      swap = GetOCPT(i,j);
+	      if (GetOCPT(i,j+1) < swap)
+		{
+		  SetOCPT(i,j,GetOCPT(i,j+1));
+		  SetOCPT(i,j+1,swap);
+		}
+	    }
+	}
+      
+      // check make atlas
+      if (GetChartNr(i) <= 0 || GetChartNr(i) > GetNOCharts()) 
+	{
+	  PrintSysError("Make Atlas: chartnr(", i, ")=0!!");
+	};
+    }
+
+  mesh.SetGlobalH(mparam.maxh);
+  
+  
+  AddConeAndSpiralEdges();
+  
+  PrintMessage(5,"Make Atlas finished");
+
+  PopStatus();
+}
+
+
+int STLGeometry::TrigIsInOC(int tn, int ocn) const
+{
+  if (tn < 1 || tn > GetNT())
+    {
+      // assert (1);
+      abort ();
+      PrintSysError("STLGeometry::TrigIsInOC illegal tn: ", tn);
+      
+      return 0;
+    }
+
+  /*
+  int firstval = 0;
+  int i;
+  for (i = 1; i <= GetNOCPT(tn); i++)
+    {
+      if (GetOCPT(tn, i) == ocn) {firstval = 1;}
+    }
+  */
+
+  int found = 0;
+
+  int inc = 1;
+  while (inc <= GetNOCPT(tn)) {inc *= 2;}
+  inc /= 2;
+
+  int start = inc;
+
+  while (!found && inc > 0)
+    {
+      if (GetOCPT(tn,start) > ocn) {inc = inc/2; start -= inc;}
+      else if (GetOCPT(tn,start) < ocn) {inc = inc/2; if (start+inc <= GetNOCPT(tn)) {start += inc;}}
+      else {found = 1;}
+    }
+
+  return GetOCPT(tn, start) == ocn;
+}
+
+int STLGeometry :: GetChartNr(int i) const
+{
+  if (i > chartmark.Size()) 
+    {
+      PrintSysError("GetChartNr(", i, ") not possible!!!");
+      i = 1;
+    }
+  return chartmark.Get(i);
+}
+/*
+int STLGeometry :: GetMarker(int i) const
+{
+  return chartmark.Get(i);
+}
+*/
+void STLGeometry :: SetMarker(int nr, int m) 
+{
+  chartmark.Elem(nr) = m;
+}
+int STLGeometry :: GetNOCharts() const
+{
+  return atlas.Size();
+}
+const STLChart& STLGeometry :: GetChart(int nr) const 
+{
+  if (nr > atlas.Size()) 
+    {
+      PrintSysError("GetChart(", nr, ") not possible!!!");
+      nr = 1;
+    }
+  return *(atlas.Get(nr));
+}
+
+int STLGeometry :: AtlasMade() const
+{
+  return chartmark.Size() != 0;
+}
+
+
+//return 1 if not exists
+int AddIfNotExists(ARRAY<int>& list, int x)
+{
+  int i;
+  for (i = 1; i <= list.Size(); i++)
+    {
+      if (list.Get(i) == x) {return 0;} 
+    }
+  list.Append(x);
+  return 1;
+}
+
+void STLGeometry :: GetInnerChartLimes(ARRAY<twoint>& limes, int chartnum)
+{
+  int j, k;
+  
+  int t, nt, np1, np2;
+  STLTriangle tt;
+  
+  limes.SetSize(0);
+
+  STLChart& chart = GetChart(chartnum);
+
+  for (j = 1; j <= chart.GetNChartT(); j++)
+    {
+      t = chart.GetChartTrig(j); 
+      const STLTriangle& tt = GetTriangle(t);
+      for (k = 1; k <= 3; k++)
+	{
+	  nt = NeighbourTrig(t,k); 
+	  if (GetChartNr(nt) != chartnum)
+	    {	      
+	      tt.GetNeighbourPoints(GetTriangle(nt),np1,np2);
+	      if (!IsEdge(np1,np2))
+		{
+		  limes.Append(twoint(np1,np2));
+		  /*
+		  p3p1 = GetPoint(np1);
+		  p3p2 = GetPoint(np2);
+		  if (AddIfNotExists(limes,np1)) 
+		    {
+		      plimes1.Append(p3p1); 
+		      //plimes1trigs.Append(t);
+		      //plimes1origin.Append(np1);
+		    }
+		  if (AddIfNotExists(limes1,np2)) 
+		    {
+		      plimes1.Append(p3p2); 
+		      //plimes1trigs.Append(t);
+		      //plimes1origin.Append(np2); 			      
+		    }
+		  //chart.AddILimit(twoint(np1,np2));
+		  
+		  for (int di = 1; di <= divisions; di++)
+		    {
+		      double f1 = (double)di/(double)(divisions+1.);
+		      double f2 = (divisions+1.-(double)di)/(double)(divisions+1.);
+		      
+		      plimes1.Append(Point3d(p3p1.X()*f1+p3p2.X()*f2,
+					     p3p1.Y()*f1+p3p2.Y()*f2,
+					     p3p1.Z()*f1+p3p2.Z()*f2));
+		      //plimes1trigs.Append(t);
+		      //plimes1origin.Append(0); 			      
+		    }
+		  */
+		}
+	    }
+	}
+    }
+}
+	 
+
+
+void STLGeometry :: GetDirtyChartTrigs(int chartnum, STLChart& chart,
+				       const ARRAY<int>& outercharttrigs,
+				       ARRAY<int>& chartpointchecked,
+				       ARRAY<int>& dirtytrigs)
+{
+  dirtytrigs.SetSize(0);
+  int j,k,n;
+
+  int np1, np2, nt;
+  int cnt = 0;
+
+  for (j = 1; j <= chart.GetNChartT(); j++)
+    {
+      int t = chart.GetChartTrig(j); 
+      const STLTriangle& tt = GetTriangle(t);
+      
+      for (k = 1; k <= 3; k++)
+	{
+	  nt = NeighbourTrig(t,k); 
+	  if (GetChartNr(nt) != chartnum && outercharttrigs.Get(nt) != chartnum)
+	    {	      
+	      tt.GetNeighbourPoints(GetTriangle(nt),np1,np2);
+	      if (!IsEdge(np1,np2))
+		{
+		  dirtytrigs.Append(j); //local numbers!!!
+		  cnt++;
+		  break; //only once per trig!!!
+		}
+	    }
+	}
+    }
+  cnt = 0;
+
+  int addedges = 0;
+  int p1, p2, tn1, tn2, l, problem, pn;
+  ARRAY<int> trigsaroundp;
+
+  for (j = chart.GetNChartT(); j >= 1; j--)
+    {
+      int t = chart.GetChartTrig(j); 
+      const STLTriangle& tt = GetTriangle(t);
+      
+      for (k = 1; k <= 3; k++)
+	{
+	  pn = tt.PNum(k);
+	  //if (chartpointchecked.Get(pn) == chartnum)
+	  //{continue;}
+	  
+	  int checkpoint = 0;
+	  for (n = 1; n <= trigsperpoint.EntrySize(pn); n++)
+	    {
+	      if (trigsperpoint.Get(pn,n) != t && //ueberfluessig???
+		  GetChartNr(trigsperpoint.Get(pn,n)) != chartnum &&
+		  outercharttrigs.Get(trigsperpoint.Get(pn,n)) != chartnum) {checkpoint = 1;};
+	    }
+	  if (checkpoint)
+	    {
+	      chartpointchecked.Elem(pn) = chartnum;
+
+	      int worked = 0;
+	      GetSortedTrianglesAroundPoint(pn,t,trigsaroundp);
+	      trigsaroundp.Append(t); //ring
+	      
+	      problem = 0;
+	      //forward:
+	      for (l = 2; l <= trigsaroundp.Size()-1; l++)
+		{
+		  tn1 = trigsaroundp.Get(l-1);
+		  tn2 = trigsaroundp.Get(l);
+		  const STLTriangle& t1 = GetTriangle(tn1);
+		  const STLTriangle& t2 = GetTriangle(tn2);
+		  t1.GetNeighbourPoints(t2, p1, p2);
+		  if (IsEdge(p1,p2)) break;
+		  
+		  if (GetChartNr(tn2) != chartnum && outercharttrigs.Get(tn2) != chartnum) {problem = 1;}
+		}
+
+	      //backwards:
+	      for (l = trigsaroundp.Size()-1; l >= 2; l--)
+		{
+		  tn1 = trigsaroundp.Get(l+1);
+		  tn2 = trigsaroundp.Get(l);
+		  const STLTriangle& t1 = GetTriangle(tn1);
+		  const STLTriangle& t2 = GetTriangle(tn2);
+		  t1.GetNeighbourPoints(t2, p1, p2);
+		  if (IsEdge(p1,p2)) break;
+		  
+		  if (GetChartNr(tn2) != chartnum && outercharttrigs.Get(tn2) != chartnum) {problem = 1;}
+		}
+	      if (problem && !IsInArray(j,dirtytrigs))
+		{
+		  dirtytrigs.Append(j);
+		  cnt++;
+		  break; //only once per triangle
+		}
+	    }
+	}
+    }
+  
+}
+
+}
diff --git a/Netgen/libsrc/stlgeom/stlgeommesh.cpp b/Netgen/libsrc/stlgeom/stlgeommesh.cpp
new file mode 100644
index 0000000000..37656495e7
--- /dev/null
+++ b/Netgen/libsrc/stlgeom/stlgeommesh.cpp
@@ -0,0 +1,1591 @@
+//20.11.1999 second part of stlgeom.cc, mainly mesh functions
+
+#include <mystdlib.h>
+
+#include <myadt.hpp>
+#include <linalg.hpp>
+#include <gprim.hpp>
+
+#include <meshing.hpp>
+
+#include "stlgeom.hpp"
+
+namespace netgen
+{
+int EdgeUsed(int p1, int p2, ARRAY<INDEX_2>& edges, INDEX_2_HASHTABLE<int>& hashtab)
+{
+  if (p1 > p2) {Swap (p1,p2);}
+
+  if (hashtab.Used(INDEX_2(p1,p2))) 
+    {return hashtab.Get(INDEX_2(p1,p2));}
+
+  return 0;
+}
+
+Point<3> STLGeometry :: PointBetween(const Point<3> & p1, int t1, 
+				     const Point<3> & p2, int t2)
+{
+  //funktioniert nicht in allen Fällen!
+
+  PrintWarning("Point between");
+
+
+  ClearMarkedSegs();
+
+  InitMarkedTrigs();
+  SetMarkedTrig(t1,1);
+  SetMarkedTrig(t2,1);
+
+  TABLE<Point3d> edgepoints;
+  TABLE<double> edgepointdists;
+  TABLE<int> edgepointorigines;
+  TABLE<int> edgepointoriginps;
+
+  ARRAY<int> edgetrigs;
+  ARRAY<INDEX_2> edgepointnums;
+  ARRAY<int> edgetriglocinds;
+
+  int size = 3*GetNT();
+  INDEX_2_HASHTABLE<int> hashtab(size);
+
+  int divisions = 10;
+
+  edgepoints.SetSize(size);
+  edgepointdists.SetSize(size);
+  edgepointorigines.SetSize(size);
+  edgepointoriginps.SetSize(size);
+
+  edgetrigs.SetSize(size);
+  edgepointnums.SetSize(size);
+  edgetriglocinds.SetSize(size);
+
+  ARRAY<int> edgelist1;
+  ARRAY<int> edgelist2;
+
+  edgelist1.SetSize(0);
+  edgelist2.SetSize(0);
+
+
+  int i, j, k, l, m;
+  int edgecnt = 0;
+
+  //first triangle:
+  for (i = 1; i <= 3; i++)
+    {
+      int ptn1 = GetTriangle(t1).PNum(i);
+      int ptn2 = GetTriangle(t1).PNumMod(i+1);
+
+      if (ptn1 > ptn2) {Swap(ptn1,ptn2);}
+
+      Point3d pt1 = GetPoint(ptn1);
+      Point3d pt2 = GetPoint(ptn2);
+
+      edgecnt++;
+      edgetrigs.Elem(edgecnt) = t1;
+      edgepointnums.Elem(edgecnt) = INDEX_2(ptn1,ptn2);
+      hashtab.Set(edgepointnums.Get(edgecnt),edgecnt);
+
+      edgetriglocinds.Elem(edgecnt) = i;
+      edgelist1.Append(edgecnt);
+
+      for (j = 1; j <= divisions; j++)
+	{
+	  double lfact = (double)j/(double)divisions;
+	  Point3d pbtw(lfact*pt1.X()+(1.-lfact)*pt2.X(),
+		       lfact*pt1.Y()+(1.-lfact)*pt2.Y(),
+		       lfact*pt1.Z()+(1.-lfact)*pt2.Z());
+
+	  //AddMarkedSeg(p1,pbtw);
+	
+	  edgepoints.Add1(edgecnt,pbtw);
+	  edgepointdists.Add1(edgecnt,Dist(pbtw,p1));
+	  edgepointorigines.Add1(edgecnt,0);
+	  edgepointoriginps.Add1(edgecnt,0);
+	}
+    }
+
+  int finished = 0;
+  int endpointorigine = 0;
+  int endpointoriginp = 0;
+  double endpointmindist = 1E50;
+
+  int cnt = 0;
+  int maxsize = 0;
+  while (!finished)
+    {
+      finished = 1;
+      
+      if (edgelist1.Size() > maxsize) {maxsize = edgelist1.Size();}
+
+      for (i = 1; i <= edgelist1.Size(); i++)
+	{
+	  int en = edgelist1.Get(i);
+	  int trig = edgetrigs.Get(en);
+	  int edgenum = edgetriglocinds.Get(en);
+	  int tn = NeighbourTrigSorted(trig,edgenum);
+
+	  if (tn != t2)
+	    {
+	      for (k = 1; k <= 3; k++)
+		{
+		  int pnt1 = GetTriangle(tn).PNum(k);
+		  int pnt2 = GetTriangle(tn).PNumMod(k+1);
+		      
+		  if (pnt1 > pnt2) {Swap(pnt1,pnt2);}
+
+		  Point3d pt1 = GetPoint(pnt1);
+		  Point3d pt2 = GetPoint(pnt2);
+		      
+		  //AddMarkedSeg(pt1,pt2);
+		  
+		  //if (!(pnt1 == ep1 && pnt2 == ep2))
+		  //  {
+		  int edgeused = 0;
+		  int edgenum = EdgeUsed(pnt1, pnt2, edgepointnums, hashtab);
+		  if (edgenum != en)
+		    {
+		      if (edgenum != 0) 
+			{edgeused = 1;}
+		      else 
+			{
+			  edgecnt++; 
+			  edgenum = edgecnt;
+			  
+			  edgetrigs.Elem(edgenum) = tn;
+			  edgepointnums.Elem(edgenum) = INDEX_2(pnt1,pnt2);
+			  hashtab.Set(edgepointnums.Get(edgenum),edgenum);
+			  edgetriglocinds.Elem(edgenum) = k;
+			}
+		      
+		      if (edgenum > size || edgenum == 0) {PrintSysError("edgenum = ", edgenum);}
+			  
+		      double minofmindist = 1E50;
+		      int changed = 0;
+		      
+		      for (l = 1; l <= divisions; l++)
+			{
+			  double lfact = (double)l/(double)divisions;
+			  Point3d pbtw(lfact*pt1.X()+(1.-lfact)*pt2.X(),
+				       lfact*pt1.Y()+(1.-lfact)*pt2.Y(),
+				       lfact*pt1.Z()+(1.-lfact)*pt2.Z());
+			  
+			  double mindist = 1E50;
+			  int index=0;
+			  
+			  for (m = 1; m <= divisions; m++)
+			    {
+			      const Point3d& p = edgepoints.Get(en,m);
+			      if (Dist(pbtw,p) + edgepointdists.Get(en,m) < mindist)
+				{mindist = Dist(pbtw,p) + edgepointdists.Get(en,m); index = m;}
+			    }
+			  
+			  //if (mindist < endpointmindist) {finished = 0;}
+			  if (mindist < minofmindist) {minofmindist = mindist;}
+			  
+			  
+			  if (!edgeused)
+			    {
+			      //AddMarkedSeg(pbtw,edgepoints.Get(en,index));
+
+			      edgepoints.Add1(edgenum,pbtw);
+			      edgepointdists.Add1(edgenum,mindist);
+			      edgepointorigines.Add1(edgenum,en);
+			      edgepointoriginps.Add1(edgenum,index);
+			      changed = 1;
+			    }
+			  else
+			    {
+			      if (mindist < edgepointdists.Get(edgenum,l))
+				{
+				  edgepointdists.Set(edgenum,l,mindist);
+				  edgepointorigines.Set(edgenum,l,en);
+				  edgepointoriginps.Set(edgenum,l,index);
+				  changed = 1;
+				}			      
+			    }
+			}
+		      if (minofmindist < endpointmindist-1E-10 && changed)
+			{
+			  finished = 0;
+			  edgelist2.Append(edgenum);
+			}
+		    }
+		}
+	    }
+	  else
+	    {
+	      double mindist = 1E50;
+	      int index;
+	      for (m = 1; m <= divisions; m++)
+		{
+		  const Point3d& p = edgepoints.Get(en,m);
+		  if (Dist(p2,p) + edgepointdists.Get(en,m) < mindist)
+		    {mindist = Dist(p2,p) + edgepointdists.Get(en,m); index = m;}
+		}
+	      if (mindist < endpointmindist)
+		{
+		  endpointorigine = en;
+		  endpointoriginp = index;
+		  endpointmindist = mindist;
+		}
+	    }
+	}
+      edgelist1.SetSize(0);
+      for (i = 1; i <= edgelist2.Size(); i++)
+	{
+	  edgelist1.Append(edgelist2.Get(i));
+	}
+    }
+
+  if (!endpointorigine) {PrintSysError("No connection found!");}
+
+  ARRAY<Point3d> plist;
+
+  plist.Append(p2);
+  int laste = endpointorigine;
+  int lastp = endpointoriginp;
+  int lle, llp;
+
+
+  while (laste)
+    {
+      plist.Append(edgepoints.Get(laste,lastp));
+
+      lle = laste;
+      llp = lastp; 
+      laste = edgepointorigines.Get(lle,llp);
+      lastp = edgepointoriginps.Get(lle,llp);
+    }
+
+  plist.Append(p1);
+
+  for (i = 1; i <= plist.Size()-1; i++)
+    {
+      AddMarkedSeg(plist.Get(i),plist.Get(i+1));
+    }
+
+  PrintMessage(5,"PointBetween: complexity=", maxsize);
+
+
+  Point3d pm;
+  double dist = 0;
+  int found = 0;
+  
+  for (i = 1; i <= plist.Size()-1; i++)
+    {
+      dist += Dist(plist.Get(i),plist.Get(i+1));
+      if (dist > endpointmindist*0.5) 
+	{
+	  double segl = Dist(plist.Get(i), plist.Get(i+1));
+	  double d = dist - endpointmindist * 0.5;
+	  pm = Point3d(d/segl*plist.Get(i).X() + (1.-d/segl)*plist.Get(i+1).X(),
+		       d/segl*plist.Get(i).Y() + (1.-d/segl)*plist.Get(i+1).Y(),
+		       d/segl*plist.Get(i).Z() + (1.-d/segl)*plist.Get(i+1).Z());
+	  found = 1;
+	  break;
+	}
+    }
+  if (!found) {PrintWarning("Problem in PointBetween"); pm = Center(p1,p2);}
+
+  AddMarkedSeg(pm, Point3d(0.,0.,0.));
+  
+  return pm;
+  
+}
+
+
+void STLGeometry :: PrepareSurfaceMeshing()
+{
+  meshchart = -1; //clear no old chart
+  meshcharttrigs.SetSize(GetNT());
+  int i;
+  for (i = 1; i <= GetNT(); i++) 
+    {meshcharttrigs.Elem(i) = 0;}
+}
+
+void STLGeometry::GetMeshChartBoundary (ARRAY<Point2d > & points,
+					ARRAY<Point3d > & points3d,
+					ARRAY<INDEX_2> & lines, double h)
+{
+  int i, j;
+  twoint seg, newseg;
+  int zone;
+  int psize;
+  Point<2> p2;
+
+  const STLChart& chart = GetChart(meshchart);
+
+
+  for (i = 1; i <= chart.GetNOLimit(); i++)
+    {
+      seg = chart.GetOLimit(i);
+      INDEX_2 i2;
+      for (j = 1; j <= 2; j++)
+	{
+	  int pi = (j == 1) ? seg.i1 : seg.i2;
+	  int lpi;
+	  if (ha_points.Get(pi) == 0)
+	    {
+	      const Point<3> & p3d = GetPoint (pi);
+	      Point<2> p2d;
+
+	      points3d.Append (p3d);
+	      ToPlane(p3d, 0, p2d, h, zone, 0);
+	      points.Append (p2d);
+	      
+	      lpi = points.Size();
+	      ha_points.Elem(pi) = lpi;
+	    }
+	  else
+	    lpi = ha_points.Get(pi);
+
+	  i2.I(j) = lpi;
+	}
+      lines.Append (i2);
+
+      /*
+      seg = chart.GetOLimit(i);
+      psize = points.Size();
+
+      newseg.i1 = psize+1;
+      newseg.i2 = psize+2;
+
+      ToPlane(GetPoint(seg.i1), 0, p2, h, zone, 0);
+      points.Append(p2);
+      points3d.Append (GetPoint(seg.i1));
+      ToPlane(GetPoint(seg.i2), 0, p2, h, zone, 0);
+      points.Append(p2);
+      points3d.Append (GetPoint(seg.i2));
+      lines.Append (INDEX_2 (points.Size()-1, points.Size()));
+      */
+    }
+
+  for (i = 1; i <= chart.GetNOLimit(); i++)
+    {
+      seg = chart.GetOLimit(i);
+      ha_points.Elem(seg.i1) = 0;
+      ha_points.Elem(seg.i2) = 0;
+    }
+}
+
+void STLGeometry :: DefineTangentialPlane (const Point<3> & ap1, const Point<3> & ap2, int trig)
+{
+  p1 = ap1; //save for ToPlane, in data of STLGeometry class
+  Point<3> p2 = ap2; //only locally used
+
+  meshchart = GetChartNr(trig);
+
+  if (usechartnormal)
+    meshtrignv = GetChart(meshchart).GetNormal();
+  else
+    meshtrignv = GetTriangle(trig).Normal();
+
+  //meshtrignv = GetTriangle(trig).Normal(points);
+
+  meshtrignv /= meshtrignv.Length();
+
+  GetTriangle(trig).ProjectInPlain(points, meshtrignv, p2);
+
+
+  ez = meshtrignv;
+  ez /= ez.Length();
+  ex = p2 - p1;
+  ex -= (ex * ez) * ez;
+  ex /= ex.Length();
+  ey = Cross (ez, ex);
+
+}
+
+
+void STLGeometry :: SelectChartOfTriangle (int trignum)
+{
+  meshchart = GetChartNr(trignum);
+  meshtrignv = GetTriangle(trignum).Normal();	
+}
+
+
+void STLGeometry :: SelectChartOfPoint (const Point<3> & p)
+{
+  int i, ii, j, k;
+  
+  ARRAY<int> trigsinbox;
+  
+  Box<3> box(p,p);
+  box.Increase (1e-6);
+  GetTrianglesInBox (box, trigsinbox);
+  
+
+  //  for (i = 1; i <= GetNT(); i++)
+  for (ii = 1; ii <= trigsinbox.Size(); ii++)
+    {
+      i = trigsinbox.Get(ii);
+      Point<3> hp = p;
+      if (GetTriangle(i).GetNearestPoint(points, hp) <= 1E-8)
+	{
+	  SelectChartOfTriangle (i);
+	  break;
+      }
+    }
+  return;
+}
+
+
+
+void STLGeometry :: ToPlane (const Point<3> & locpoint, int * trigs,
+			     Point<2> & plainpoint, double h, int& zone,
+			     int checkchart)
+{
+  if (checkchart)
+    {
+
+      //check if locpoint lies on actual chart:
+      zone = 0;
+      
+      
+      //  Point3d p;
+      int i = 1;
+      const STLChart& chart = GetChart(meshchart);
+      int foundinchart = 0;
+      const double range = 1e-6; //1e-4 old
+      
+      
+      
+      
+      if (trigs)
+	{
+	  int * htrigs = trigs;
+	  int ci = 1;
+	  while (*htrigs)
+	    {
+	      if (TrigIsInOC (*htrigs, meshchart))
+		{
+		  foundinchart = 1;
+		  break;
+		}
+	      htrigs++;
+	    }
+	}
+      
+      else
+	{
+	  ARRAY<int> trigsinbox;
+
+	  if (!geomsearchtreeon)
+	    {
+	      //alter chart-tree
+	      Box<3> box(locpoint, locpoint);
+	      box.Increase (range);
+	      chart.GetTrianglesInBox (box.PMin(), box.PMax(), trigsinbox);
+	    }
+	  else
+	    {
+	      ARRAY<int> trigsinbox2;
+	      Box<3> box(locpoint, locpoint);
+	      box.Increase (range);
+	      GetTrianglesInBox (box, trigsinbox2);
+	      for (i = 1; i <= trigsinbox2.Size(); i++)
+		{
+		  if (TrigIsInOC(trigsinbox2.Get(i),meshchart)) {trigsinbox.Append(trigsinbox2.Get(i));}
+		}
+	      
+	    }
+	  
+	  
+	  for (i = 1; i <= trigsinbox.Size(); i++)
+	    {
+	      Point<3> p = locpoint;
+	      if (GetTriangle(trigsinbox.Get(i)).GetNearestPoint(points, p) 
+		  <= 1E-8)
+		{
+		  foundinchart = 1;
+		  break;
+		}
+	      
+	    }
+	}
+      
+  //do not use this point (but do correct projection (joachim)
+      if (!foundinchart) 
+	{
+	  zone = -1; // plainpoint.X() = 11111; plainpoint.Y() = 11111; return; 
+	}
+    }
+  
+  else
+    {
+      zone = 0;
+    }
+  
+  //transform in plane
+  Vec<3> p1p = locpoint - p1;
+  plainpoint(0) = (p1p * ex) / h;
+  plainpoint(1) = (p1p * ey) / h;
+
+}
+
+int STLGeometry :: FromPlane (const Point<2> & plainpoint, 
+			      Point<3> & locpoint, double h)
+{
+  Point2d plainpoint2 (plainpoint);
+
+  plainpoint2.X() *= h;
+  plainpoint2.Y() *= h;
+  Vec3d p1p = plainpoint2.X() * ex + plainpoint2.Y() * ey;
+  locpoint = p1 + p1p;
+
+
+  int rv = Project(locpoint);
+  if (!rv) {return 1;} //project nicht gegangen
+  return 0;
+}
+
+int lasttrig;
+int STLGeometry :: LastTrig() const {return lasttrig;};
+
+//project normal to tangential plane
+int STLGeometry :: Project(Point<3> & p3d) const
+{
+  Point<3> p, pf;
+
+  int i, j, k;
+  int fi = 0;
+  int cnt = 0;
+  int different = 0;
+  const double lamtol = 1e-6;
+
+  const STLChart& chart = GetChart(meshchart);
+
+  int nt = chart.GetNT();
+
+   QuadraticFunction3d quadfun(p3d, meshtrignv);
+ 
+   /*
+     Vec3d hv = meshtrignv;
+     hv /= hv.Length();
+     Vec3d t1, t2;
+     hv.GetNormal (t1);
+     Cross (hv, t1, t2);
+   */
+  
+  for (j = 1; j <= nt; j++)
+    {
+      i = chart.GetTrig(j);
+
+      const Point<3> & c = GetTriangle(i).center;
+      /*
+      double d1 = t1 * (c-p3d);
+      double d2 = t2 * (c-p3d);
+      */
+      /*
+      if (d1 * d1 + d2 * d2 > sqr (GetTriangle(i).rad))
+	continue;
+      */
+      if (quadfun.Eval(c) > sqr (GetTriangle(i).rad))
+	continue;
+
+      p = p3d;
+      Vec<3> lam;
+      int err = GetTriangle(i).ProjectInPlain(points, meshtrignv, p, lam);      
+      int inside = (err == 0 && lam(0) > -lamtol && 
+		    lam(1) > -lamtol && (1-lam(0)-lam(1)) > -lamtol);
+
+
+      /*
+      p = p3d;
+      GetTriangle(i).ProjectInPlain(points, meshtrignv, p);
+      if (GetTriangle(i).PointInside(points, p)) 
+      */
+      if (inside)
+	{
+	  if (cnt != 0) 
+	    {
+	      if (Dist2(p,pf)>=1E-16) 
+		{
+		  //		  (*testout) << "ERROR: found two points to project which are different" << endl;
+		  //(*testout) << "p=" << p << ", pf=" << pf << endl;
+		  different = 1;
+		}
+	    }
+	  pf = p; fi = i; cnt++;
+	}
+
+      if (inside)
+	break;
+
+    }
+
+  //  if (cnt == 2) {(*testout) << "WARNING: found 2 triangles to project" << endl;}
+  //if (cnt == 3) {(*testout) << "WARNING: found 3 triangles to project" << endl;}
+  //if (cnt > 3) {(*testout) << "WARNING: found more than 3 triangles to project" << endl;}
+
+  if (fi != 0) {lasttrig = fi;}
+  if (fi != 0 && !different) {p3d = pf; return fi;}
+
+  //  (*testout) << "WARNING: Project failed" << endl;
+  return 0;
+  
+}
+
+//project normal to tangential plane
+int STLGeometry :: ProjectOnWholeSurface(Point<3> & p3d) const
+{
+  Point<3> p, pf;
+
+  int i, k;
+  int fi = 0;
+  int cnt = 0;
+  int different = 0;
+  const double lamtol = 1e-6;
+
+  for (i = 1; i <= GetNT(); i++)
+    {
+      p = p3d;
+      Vec<3> lam;
+      int err =
+	GetTriangle(i).ProjectInPlain(points, meshtrignv, p, lam);      
+      int inside = (err == 0 && lam(0) > -lamtol && 
+		    lam(1) > -lamtol && (1-lam(0)-lam(1)) > -lamtol);
+
+      /*
+      p = p3d;
+      GetTriangle(i).ProjectInPlain(points, meshtrignv, p);
+      if (GetTriangle(i).PointInside(points, p)) 
+      */
+      if (inside)
+	{
+	  if (cnt != 0) 
+	    {
+	      if (Dist2(p,pf)>=1E-16) 
+		{
+		  //		  (*testout) << "ERROR: found two points to project which are different" << endl;
+		  //		  (*testout) << "p=" << p << ", pf=" << pf << endl;
+		  different = 1;
+		}
+	    }
+	  pf = p; fi = i; cnt++;
+	}
+    }
+  /*
+  if (cnt == 2) {(*testout) << "WARNING: found 2 triangles to project" << endl;}
+  if (cnt == 3) {(*testout) << "WARNING: found 3 triangles to project" << endl;}
+  if (cnt > 3) {(*testout) << "WARNING: found more than 3 triangles to project" << endl;}
+  */
+  if (fi != 0) {lasttrig = fi;}
+  if (fi != 0 && !different) {p3d = pf; return fi;}
+
+  //  (*testout) << "WARNING: Project failed" << endl;
+  return 0;
+  
+}
+
+
+int STLGeometry :: ProjectNearest(Point<3> & p3d) const
+{
+  Point<3> p, pf;
+
+  //set new chart
+  const STLChart& chart = GetChart(meshchart);
+  int i;
+  double nearest = 1E50;
+  double dist;
+  int ft = 0;
+
+  for (i = 1; i <= chart.GetNT(); i++)
+    {
+      p = p3d;
+      dist  = GetTriangle(chart.GetTrig(i)).GetNearestPoint(points, p);
+      if (dist < nearest)
+	{
+	  pf = p;
+	  nearest = dist;
+	  ft = chart.GetTrig(i);
+	}      
+    }
+  p3d = pf;
+  //if (!ft) {(*testout) << "ERROR: ProjectNearest failed" << endl;}
+  
+  return ft;
+}
+
+
+
+	
+//Restrict local h due to curvature for make atlas
+void STLGeometry :: RestrictLocalHCurv(class Mesh & mesh, double gh)
+{
+  PushStatusF("Restrict H due to surface curvature");
+
+  //bei jedem Dreieck alle Nachbardreiecke vergleichen, und, fallskein Kante dazwischen,
+  //die Meshsize auf ein bestimmtes Mass limitieren
+  int i,j;
+
+  int p1,p2,p3,p4;
+  Point<3> p1p, p2p, p3p, p4p;
+  double mindist, ang;
+  Vec<3> n, ntn;
+  double rzyl, sinang, localh;
+
+  //  double localhfact = 0.5;
+  double geometryignorelength = 1E-4;
+  double minlocalh = stlparam.atlasminh;
+
+  Box<3> bb = GetBoundingBox();
+  //  mesh.SetLocalH(bb.PMin() - Vec3d(10, 10, 10),bb.PMax() + Vec3d(10, 10, 10),
+  //		 mparam.grading);
+
+  //  mesh.SetGlobalH(gh);
+
+  double mincalch = 1E10;
+  double maxcalch = -1E10;
+
+  double objectsize = bb.Diam();
+  double geometryignoreedgelength = objectsize * 1e-5;
+
+  if (stlparam.resthatlasenable)
+    {
+      ARRAY<double> minh; //minimales h pro punkt
+      minh.SetSize(GetNP());
+      for (i = 1; i <= GetNP(); i++)
+	{
+	  minh.Elem(i) = gh;
+	}
+      
+      for (i = 1; i <= GetNT(); i++)
+	{
+	  SetThreadPercent((double)i/(double)GetNT()*100.);
+
+	  if (multithread.terminate)
+	    {PopStatus(); return;}
+
+	  const STLTriangle& trig = GetTriangle(i);
+	  n = GetTriangle(i).Normal();
+	  for (j = 1; j <= 3; j++)
+	    {
+	      const STLTriangle& nt = GetTriangle(NeighbourTrig(i,j));
+	      
+	      trig.GetNeighbourPointsAndOpposite(nt,p1,p2,p3);	    	    
+	      
+	      //checken, ob p1-p2 eine Kante sind
+	      if (IsEdge(p1,p2)) continue;
+	      
+	      p4 = trig.PNum(1) + trig.PNum(2) + trig.PNum(3) - p1 - p2;
+	      
+	      p1p = GetPoint(p1); p2p = GetPoint(p2); 
+	      p3p = GetPoint(p3); p4p = GetPoint(p4);
+	      
+	      double h1 = GetDistFromInfiniteLine(p1p,p2p, p4p);
+	      double h2 = GetDistFromInfiniteLine(p1p,p2p, p3p);
+	      double diaglen = Dist (p1p, p2p);
+	      
+	      if (diaglen < geometryignoreedgelength)
+		continue;
+	      rzyl = ComputeCylinderRadius 
+		(n, GetTriangle(NeighbourTrig(i,j)).Normal(), 
+		 h1, h2);
+	      
+	      
+	      if (h1 < 1e-3 * diaglen && h2 < 1e-3 * diaglen)
+		continue;
+	      if (h1 < 1e-5 * objectsize && h2 < 1e-5 * objectsize)
+		continue;
+	      
+	      
+	      //	      rzyl = mindist/(2*sinang);
+	      localh = 10.*rzyl / stlparam.resthatlasfac;
+	      if (localh < mincalch) {mincalch = localh;}
+	      if (localh > maxcalch) {maxcalch = localh;}
+
+	      if (localh < minlocalh) {localh = minlocalh;}
+	      if (localh < gh)
+		{
+		  minh.Elem(p1) = min2(minh.Elem(p1),localh);
+		  minh.Elem(p2) = min2(minh.Elem(p2),localh);
+		}
+	      
+	      //if (localh < 0.2) {localh = 0.2;}
+	      mesh.RestrictLocalHLine(p1p, p2p, localh);
+	    }
+	  
+	}
+    }
+  PrintMessage(7, "done\nATLAS H: nmin local h=", mincalch);
+  PrintMessage(7, "ATLAS H: max local h=", maxcalch);
+  PrintMessage(7, "Local h tree has ", mesh.LocalHFunction().GetNBoxes(), " boxes of size ",
+	       (int)sizeof(GradingBox));
+
+  PopStatus();
+
+}
+  //restrict local h due to near edges and due to outer chart distance
+void STLGeometry :: RestrictLocalH(class Mesh & mesh, double gh)
+{
+  
+  //bei jedem Dreieck alle Nachbardreiecke vergleichen, und, fallskein Kante dazwischen,
+  //die Meshsize auf ein bestimmtes Mass limitieren
+  int i,j;
+
+  int p1,p2,p3,p4;
+  Point3d p1p, p2p, p3p, p4p;
+  double mindist, ang;
+  Vec3d n, ntn;
+  double rzyl, sinang, localh;
+
+  //  double localhfact = 0.5;
+  double geometryignorelength = 1E-4;
+
+  Box<3> bb = GetBoundingBox();
+  //mesh.SetLocalH(bb.PMin() - Vec3d(10, 10, 10),bb.PMax() + Vec3d(10, 10, 10),
+  //		 mparam.grading);
+
+  //mesh.SetGlobalH(gh);
+
+  double mincalch = 1E10;
+  double maxcalch = -1E10;
+
+  double objectsize = bb.Diam();
+  double geometryignoreedgelength = objectsize * 1e-5;
+
+  if (stlparam.resthsurfcurvenable)
+    {
+      PushStatusF("Restrict H due to surface curvature");
+
+      ARRAY<double> minh; //minimales h pro punkt
+      minh.SetSize(GetNP());
+      for (i = 1; i <= GetNP(); i++)
+	{
+	  minh.Elem(i) = gh;
+	}
+
+      for (i = 1; i <= GetNT(); i++)
+	{
+	  SetThreadPercent((double)i/(double)GetNT()*100.);
+	  if (i%20000==19999) {PrintMessage(7, (double)i/(double)GetNT()*100. , "%");}
+
+	  if (multithread.terminate)
+	    {PopStatus(); return;}
+	  
+	  const STLTriangle& trig = GetTriangle(i);
+	  n = GetTriangle(i).Normal();
+	  for (j = 1; j <= 3; j++)
+	    {
+	      const STLTriangle& nt = GetTriangle(NeighbourTrig(i,j));
+	      
+	      trig.GetNeighbourPointsAndOpposite(nt,p1,p2,p3);	    	    
+	      
+	      //checken, ob p1-p2 eine Kante sind
+	      if (IsEdge(p1,p2)) continue;
+	      
+	      p4 = trig.PNum(1) + trig.PNum(2) + trig.PNum(3) - p1 - p2;
+	      
+	      p1p = GetPoint(p1); p2p = GetPoint(p2); 
+	      p3p = GetPoint(p3); p4p = GetPoint(p4);
+	      
+	      double h1 = GetDistFromInfiniteLine(p1p,p2p, p4p);
+	      double h2 = GetDistFromInfiniteLine(p1p,p2p, p3p);
+	      double diaglen = Dist (p1p, p2p);
+	      
+	      if (diaglen < geometryignoreedgelength)
+		continue;
+	      rzyl = ComputeCylinderRadius 
+		(n, GetTriangle (NeighbourTrig(i,j)).Normal(), 
+		 h1, h2);
+	      
+	      
+	      if (h1 < 1e-3 * diaglen && h2 < 1e-3 * diaglen)
+		continue;
+	      if (h1 < 1e-5 * objectsize && h2 < 1e-5 * objectsize)
+		continue;
+	      
+	      
+	      //	      rzyl = mindist/(2*sinang);
+	      localh = rzyl / stlparam.resthsurfcurvfac;
+	      if (localh < mincalch) {mincalch = localh;}
+	      if (localh > maxcalch) {maxcalch = localh;}
+	      if (localh < gh) 
+		{
+		  minh.Elem(p1) = min2(minh.Elem(p1),localh);
+		  minh.Elem(p2) = min2(minh.Elem(p2),localh);
+		}
+	      
+	      //if (localh < 0.2) {localh = 0.2;}
+	      mesh.RestrictLocalHLine(p1p, p2p, localh);
+	      
+	      if (localh < 0.1)
+		{
+		  localh = 0.1;
+		}
+	      
+	    }
+	}
+      PrintMessage(7, "done\nmin local h=", mincalch, "\nmax local h=", maxcalch);
+      PopStatus();
+    }
+
+  if (stlparam.resthcloseedgeenable)
+    {
+      PushStatusF("Restrict H due to close edges");
+      //geht nicht für spiralen!!!!!!!!!!!!!!!!!!
+      
+      double disttohfact = sqr(10.0 / stlparam.resthcloseedgefac);
+      int k,l;
+      double h1, h2, dist;
+      int rc = 0;
+      Point3d p3p1, p3p2;
+      double mindist = 1E50;
+      
+      PrintMessage(7,"build search tree...");
+      Box3dTree* searchtree = new Box3dTree (GetBoundingBox().PMin() - Vec3d(1,1,1),
+					     GetBoundingBox().PMax() + Vec3d(1,1,1));
+      
+      ARRAY<Point3d> pmins(GetNLines());
+      ARRAY<Point3d> pmaxs(GetNLines());
+
+      double maxhline;
+      for (i = 1; i <= GetNLines(); i++)
+	{
+	  maxhline = 0;
+	  STLLine* l1 = GetLine(i);
+	  Point3d pmin(GetPoint(l1->StartP())), pmax(GetPoint(l1->StartP())), px;
+
+	  for (j = 2; j <= l1->NP(); j++)
+	    {
+	      px = GetPoint(l1->PNum(j));
+	      maxhline = max2(maxhline,mesh.GetH(px));
+	      pmin.SetToMin (px);
+	      pmax.SetToMax (px);
+	    }
+	  Box3d box(pmin,pmax);
+	  box.Increase(maxhline);
+
+	  searchtree->Insert (box.PMin(), box.PMax(), i);
+	  pmins.Elem(i) = box.PMin();
+	  pmaxs.Elem(i) = box.PMax();
+	}
+
+      ARRAY<int> linenums;
+      int k2;
+
+      for (i = 1; i <= GetNLines(); i++)
+	{
+	  SetThreadPercent((double)i/(double)GetNLines()*100.);
+	  if (multithread.terminate)
+	    {PopStatus(); return;}
+
+	  linenums.SetSize(0);
+	  searchtree->GetIntersecting(pmins.Get(i),pmaxs.Get(i),linenums);
+	      
+	  STLLine* l1 = GetLine(i);
+	  for (j = 1; j <= l1->NP(); j++)
+	    {
+	      p3p1 = GetPoint(l1->PNum(j));
+	      h1 = sqr(mesh.GetH(p3p1));
+	      
+	      for (k2 = 1; k2 <= linenums.Size(); k2++)
+		{
+		  k = linenums.Get(k2);
+		  if (k <= i) {continue;} 
+		  /*  
+		   //old, without searchtrees
+		     for (k = i+1; k <= GetNLines(); k++)
+		     {
+		  */
+		  STLLine* l2 = GetLine(k);
+		  for (l = 1; l <= l2->NP(); l++)
+		    {
+		      const Point3d& p3p2 = GetPoint(l2->PNum(l));
+		      h2 = sqr(mesh.GetH(p3p2));
+		      dist = Dist2(p3p1,p3p2)*disttohfact;		  
+		      if (dist > 1E-12)
+			{
+			  if (dist < h1) 
+			    {
+			      mesh.RestrictLocalH(p3p1,sqrt(dist)); 
+			      rc++;
+			      mindist = min2(mindist,sqrt(dist));
+			    }
+			  if (dist < h2) 
+			    {
+			      mesh.RestrictLocalH(p3p2,sqrt(dist)); 
+			      rc++;
+			      mindist = min2(mindist,sqrt(dist));
+			    }
+			}
+		    }
+		}	  
+	    }
+	}
+      PrintMessage(5, "done\n Restricted h in ", rc, " points due to near edges!");
+      PopStatus(); 
+    }
+
+  if (stlparam.resthedgeangleenable)
+    {
+      PushStatusF("Restrict h due to close edges");
+
+      int ecnt = 0;
+      int lp1, lp2;
+      int i;
+      Vec3d v1,v2;
+      double rzyl;
+      double mincalch = 1E50;
+      double maxcalch = -1E50;
+
+      for (i = 1; i <= GetNP(); i++)
+	{
+	  SetThreadPercent((double)i/(double)GetNP()*100.);
+	  if (multithread.terminate)
+	    {PopStatus(); return;}
+
+	  if (GetNEPP(i) == 2 && !IsLineEndPoint(i))
+	    {
+	      if (GetEdge(GetEdgePP(i,1)).PNum(2) == GetEdge(GetEdgePP(i,2)).PNum(1) ||
+		  GetEdge(GetEdgePP(i,1)).PNum(1) == GetEdge(GetEdgePP(i,2)).PNum(2))
+		{
+		  lp1 = 1; lp2 = 2;
+		}
+	      else
+		{
+		  lp1 = 2; lp2 = 1;
+		}
+
+	      v1 = Vec3d(GetPoint(GetEdge(GetEdgePP(i,1)).PNum(1)),
+			 GetPoint(GetEdge(GetEdgePP(i,1)).PNum(2)));
+	      v2 = Vec3d(GetPoint(GetEdge(GetEdgePP(i,2)).PNum(lp1)),
+			 GetPoint(GetEdge(GetEdgePP(i,2)).PNum(lp2)));
+
+	      rzyl = ComputeCylinderRadius(v1, v2, v1.Length(), v2.Length());
+	      	      
+	      localh = rzyl / stlparam.resthedgeanglefac;
+	      if (localh < mincalch) {mincalch = localh;}
+	      if (localh > maxcalch) {maxcalch = localh;}
+	      
+	      if (localh != 0)
+		mesh.RestrictLocalH(GetPoint(i), localh);
+	    }	  
+	}
+      PrintMessage(7,"edge-angle min local h=", mincalch, "\nedge-angle max local h=", maxcalch);
+      PopStatus();
+    }
+
+  if (stlparam.resthchartdistenable)
+    {
+      PushStatusF("Restrict H due to outer chart distance");
+      
+      // mesh.LocalHFunction().Delete();
+
+      //berechne minimale distanz von chart zu einem nicht-outerchart-punkt in jedem randpunkt einer chart
+      
+      ARRAY<int> acttrigs; //outercharttrigs
+      acttrigs.SetSize(GetNT());
+      for (i = 1; i <= GetNT(); i++)
+	{
+	  acttrigs.Elem(i) = 0;
+	}
+      for (i = 1; i <= GetNOCharts(); i++)
+	{
+	  SetThreadPercent((double)i/(double)GetNOCharts()*100.);
+	  if (multithread.terminate)
+	    {PopStatus(); return;}
+
+	  RestrictHChartDistOneChart(i, acttrigs, mesh, gh, 1., 0.);
+	}
+      
+      PopStatus();
+    }
+
+  if (stlparam.resthlinelengthenable)
+    {
+      //restrict h due to short lines
+      PushStatusF("Restrict H due to line-length");
+      
+      double minhl = 1E50;
+      double linefact = 1./stlparam.resthlinelengthfac;
+      double l;
+      for (i = 1; i <= GetNLines(); i++)
+	{
+	  SetThreadPercent((double)i/(double)GetNLines()*100.);
+	  if (multithread.terminate)
+	    {PopStatus(); return;}
+	  
+	  l = GetLine(i)->GetLength(points);
+	  
+	  const Point3d& p1 = GetPoint(GetLine(i)->StartP());
+	  const Point3d& p2 = GetPoint(GetLine(i)->EndP());
+	  
+	  if (l != 0)
+	    {
+	      minhl = min2(minhl,l*linefact);
+	      
+	      mesh.RestrictLocalH(p1, l*linefact);
+	      mesh.RestrictLocalH(p2, l*linefact);      
+	    }
+	}
+      PopStatus();
+      PrintMessage(5, "minh due to line length=", minhl);
+  }
+}
+
+void STLGeometry :: RestrictHChartDistOneChart(int chartnum, ARRAY<int>& acttrigs, 
+					       class Mesh & mesh, double gh, double fact, double minh)
+{
+  int i = chartnum;
+  int j;
+
+  double limessafety = stlparam.resthchartdistfac*fact;  // original: 2
+  double localh;
+
+  double f1,f2;
+  //  mincalch = 1E10;
+  //maxcalch = -1E10;  
+  ARRAY<int> limes1;
+  ARRAY<int> limes2;
+	  
+  ARRAY<Point3d> plimes1;
+  ARRAY<Point3d> plimes2;
+	  
+  ARRAY<int> plimes1trigs; //check from wich trig the points come
+  ARRAY<int> plimes2trigs;
+	  
+  ARRAY<int> plimes1origin; //either the original pointnumber or zero, if new point
+
+  int divisions = 10;
+	  
+  int k, t, nt, np1, np2;
+  Point3d p3p1, p3p2;
+  STLTriangle tt;
+      
+  limes1.SetSize(0);
+  limes2.SetSize(0);
+  plimes1.SetSize(0);
+  plimes2.SetSize(0);
+  plimes1trigs.SetSize(0);
+  plimes2trigs.SetSize(0);
+  plimes1origin.SetSize(0);
+
+  STLChart& chart = GetChart(i);
+  chart.ClearOLimit();
+  chart.ClearILimit();
+
+  for (j = 1; j <= chart.GetNChartT(); j++)
+    {
+      t = chart.GetChartTrig(j); 
+      tt = GetTriangle(t);
+      for (k = 1; k <= 3; k++)
+	{
+	  nt = NeighbourTrig(t,k); 
+	  if (GetChartNr(nt) != i)
+	    {	      
+	      tt.GetNeighbourPoints(GetTriangle(nt),np1,np2);
+	      if (!IsEdge(np1,np2) && !GetSpiralPoint(np1) && !GetSpiralPoint(np2))
+		{
+		  p3p1 = GetPoint(np1);
+		  p3p2 = GetPoint(np2);
+		  if (AddIfNotExists(limes1,np1)) 
+		    {
+		      plimes1.Append(p3p1); 
+		      plimes1trigs.Append(t);
+		      plimes1origin.Append(np1); 			      
+		    }
+		  if (AddIfNotExists(limes1,np2)) 
+		    {
+		      plimes1.Append(p3p2); 
+		      plimes1trigs.Append(t);
+		      plimes1origin.Append(np2); 			      
+		    }
+		  chart.AddILimit(twoint(np1,np2));
+
+		  for (int di = 1; di <= divisions; di++)
+		    {
+		      f1 = (double)di/(double)(divisions+1.);
+		      f2 = (divisions+1.-(double)di)/(double)(divisions+1.);
+			      
+		      plimes1.Append(Point3d(p3p1.X()*f1+p3p2.X()*f2,
+					     p3p1.Y()*f1+p3p2.Y()*f2,
+					     p3p1.Z()*f1+p3p2.Z()*f2));
+		      plimes1trigs.Append(t);
+		      plimes1origin.Append(0); 			      
+		    }
+		}
+	    }
+	}
+    }
+	  
+	 
+  for (j = 1; j <= chart.GetNT(); j++)
+    {
+      acttrigs.Elem(chart.GetTrig(j)) = i;
+    }
+	  
+  for (j = 1; j <= chart.GetNOuterT(); j++)
+    {
+      t = chart.GetOuterTrig(j); 
+      tt = GetTriangle(t);
+      for (k = 1; k <= 3; k++)
+	{
+	  nt = NeighbourTrig(t,k);
+
+	  if (acttrigs.Get(nt) != i)
+	    {
+	      tt.GetNeighbourPoints(GetTriangle(nt),np1,np2);
+		      
+	      if (!IsEdge(np1,np2))
+		{
+		  p3p1 = GetPoint(np1);
+		  p3p2 = GetPoint(np2);
+			  
+		  if (AddIfNotExists(limes2,np1)) {plimes2.Append(p3p1); plimes2trigs.Append(t);}
+		  if (AddIfNotExists(limes2,np2)) {plimes2.Append(p3p2); plimes2trigs.Append(t);}
+		  chart.AddOLimit(twoint(np1,np2));
+
+		  for (int di = 1; di <= divisions; di++)
+		    {
+		      f1 = (double)di/(double)(divisions+1.);
+		      f2 = (divisions+1.-(double)di)/(double)(divisions+1.);
+			      
+		      plimes2.Append(Point3d(p3p1.X()*f1+p3p2.X()*f2,
+					     p3p1.Y()*f1+p3p2.Y()*f2,
+					     p3p1.Z()*f1+p3p2.Z()*f2));
+		      plimes2trigs.Append(t);
+		    }
+		}
+	    }
+	}
+    }
+	  
+	  
+  double chartmindist = 1E50;
+
+  if (plimes2.Size())
+    {
+      Box3d bbox;
+      bbox.SetPoint (plimes2.Get(1));
+      for (j = 2; j <= plimes2.Size(); j++)
+	bbox.AddPoint (plimes2.Get(j));
+      Point3dTree stree(bbox.PMin(), bbox.PMax());
+      for (j = 1; j <= plimes2.Size(); j++)
+	stree.Insert (plimes2.Get(j), j);
+      ARRAY<int> foundpts;
+	  
+      for (j = 1; j <= plimes1.Size(); j++)
+	{
+	  double mindist = 1E50;
+	  double dist;
+
+	  const Point3d & p1 = plimes1.Get(j);
+	  double boxs = mesh.GetH (plimes1.Get(j)) * limessafety;
+
+	  Point3d pmin = p1 - Vec3d (boxs, boxs, boxs);
+	  Point3d pmax = p1 + Vec3d (boxs, boxs, boxs);
+
+	  stree.GetIntersecting (pmin, pmax, foundpts);
+
+
+	  for (int kk = 1; kk <= foundpts.Size(); kk++)
+	    {
+	      k = foundpts.Get(kk);
+	      dist = Dist2(plimes1.Get(j),plimes2.Get(k));
+	      if (dist < mindist) 
+		{
+		  mindist = dist;
+		}
+	    }
+
+	  /*
+	    const Point3d & p1 = plimes1.Get(j);
+	    double his = mesh.GetH (plimes1.Get(j));
+
+	    double xmin = p1.X() - his * limessafety;
+	    double xmax = p1.X() + his * limessafety;	      
+	    double ymin = p1.Y() - his * limessafety;
+	    double ymax = p1.Y() + his * limessafety;	      
+	    double zmin = p1.Z() - his * limessafety;
+	    double zmax = p1.Z() + his * limessafety;	      
+
+	    for (k = 1; k <= plimes2.Size(); k++)
+	    {
+	    const Point3d & p2 = plimes2.Get(k);
+	    if (p2.X() >= xmin && p2.X() <= xmax &&
+	    p2.Y() >= ymin && p2.Y() <= ymax &&
+	    p2.Z() >= zmin && p2.Z() <= zmax)
+	    {
+	    dist = Dist2(plimes1.Get(j),plimes2.Get(k));
+	    if (dist < mindist) 
+	    {
+	    mindist = dist;
+	    }
+	    }
+	    }
+	  */
+	  mindist = sqrt(mindist);
+	  localh = mindist/limessafety;
+
+	  if (localh < minh && localh != 0) {localh = minh;} //minh is generally 0! (except make atlas)
+	  if (localh < gh && localh > 0)
+	    {
+	      mesh.RestrictLocalH(plimes1.Get(j), localh);
+	      //	      if (mindist < mincalch) {mincalch = mindist;}
+	      //	      if (mindist > maxcalch) {maxcalch = mindist;}
+	      if (mindist < chartmindist) {chartmindist = mindist;}
+	    }
+	}
+    }
+
+}
+
+
+//void * STLMeshingDummy (void *)
+int STLMeshingDummy (STLGeometry* stlgeometry, Mesh*& mesh,
+			    int perfstepsstart, int perfstepsend, char* optstring)
+{
+  if (perfstepsstart > perfstepsend) return 0;
+
+  multithread.terminate = 0;
+  int success = 1;
+  //int trialcntouter = 0;
+
+  if (perfstepsstart <= MESHCONST_MESHEDGES)
+    {
+
+      mesh = new Mesh();
+      mesh -> SetGlobalH (mparam.maxh);
+      mesh -> SetLocalH (stlgeometry->GetBoundingBox().PMin() - Vec3d(10, 10, 10),
+			 stlgeometry->GetBoundingBox().PMax() + Vec3d(10, 10, 10),
+			 mparam.grading);
+      
+      int i;
+      success = 0;
+  
+      //mesh->DeleteMesh();
+ 
+      STLMeshing (*stlgeometry, *mesh);
+
+      stlgeometry->edgesfound = 1;
+      stlgeometry->surfacemeshed = 0;
+      stlgeometry->surfaceoptimized = 0;
+      stlgeometry->volumemeshed = 0;
+    }
+
+  if (multithread.terminate)
+    return 0;
+
+  if (perfstepsstart <= MESHCONST_MESHSURFACE && 
+      perfstepsend >= MESHCONST_MESHSURFACE)
+    {
+
+      if (!stlgeometry->edgesfound) 
+	{
+	  PrintUserError("You have to do 'analyse geometry' first!!!");
+	  return 0; 
+	}
+      if (stlgeometry->surfacemeshed || stlgeometry->surfacemeshed) 
+	{
+	  PrintUserError("Already meshed. Please start again with 'Analyse Geometry'!!!"); 
+	  return 0; 
+	}
+
+      success = 0;
+      int retval = STLSurfaceMeshing (*stlgeometry, *mesh);
+      if (retval == MESHING3_OK)
+	{
+	  PrintMessage(3,"Success !!!!");
+	  stlgeometry->surfacemeshed = 1;
+	  stlgeometry->surfaceoptimized = 0;
+	  stlgeometry->volumemeshed = 0;
+	  success = 1;
+	} 
+      else if (retval == MESHING3_OUTERSTEPSEXCEEDED)
+	{
+	  PrintError("Give up because of too many trials. Meshing aborted!");
+	}
+      else if (retval == MESHING3_TERMINATE)
+	{
+	  PrintWarning("Meshing Stopped by user!");
+	}
+      else
+	{
+	  PrintError("Surface meshing not successful. Meshing aborted!");
+	}
+      
+#ifdef STAT_STREAM
+      (*statout) << mesh->GetNSeg() << " & " << endl
+		 << mesh->GetNSE() << " & " << endl
+		 << GetTime() << " & ";
+#endif
+    }
+  if (multithread.terminate)
+    return 0;
+
+  if (success)
+    {
+      if (perfstepsstart <= MESHCONST_OPTSURFACE && 
+	  perfstepsend >= MESHCONST_OPTSURFACE)
+	{
+	  if (!stlgeometry->edgesfound) 
+	    {
+	      PrintUserError("You have to do 'meshing->analyse geometry' first!!!"); 
+	      return 0; 
+	    }
+	  if (!stlgeometry->surfacemeshed) 
+	    {
+	      PrintUserError("You have to do 'meshing->mesh surface' first!!!"); 
+	      return 0; 
+	    }
+	  if (stlgeometry->volumemeshed) 
+	    {
+	      PrintWarning("Surface optimization with meshed volume is dangerous!!!"); 
+	    }
+
+	  if (!optstring || strlen(optstring) == 0)
+	    {
+	      mparam.optimize2d = "smcm";
+	    }
+	  else
+	    {
+	      mparam.optimize2d = optstring;
+	    }
+
+	  STLSurfaceOptimization (*stlgeometry, *mesh, mparam);
+	  
+	  if (stlparam.recalc_h_opt)
+	    {
+	      mesh -> SetLocalH (stlgeometry->GetBoundingBox().PMin() - Vec3d(10, 10, 10),
+				 stlgeometry->GetBoundingBox().PMax() + Vec3d(10, 10, 10),
+				 mparam.grading);
+	      
+	      mesh -> CalcLocalHFromSurfaceCurvature (stlparam.resthsurfmeshcurvfac);
+	      mparam.optimize2d = "cmsmSm";
+	      STLSurfaceOptimization (*stlgeometry, *mesh, mparam);
+#ifdef STAT_STREAM
+	      (*statout) << GetTime() << " & ";
+#endif
+
+#ifdef OPENGL
+	      extern void Render();
+	      Render();
+#endif	      
+	    }
+	  stlgeometry->surfaceoptimized = 1;
+	}
+      if (multithread.terminate)
+	return 0;
+
+      if (perfstepsstart <= MESHCONST_MESHVOLUME && 
+	  perfstepsend >= MESHCONST_MESHVOLUME)
+	{
+	  if (stlgeometry->volumemeshed) 
+	    {
+	      PrintUserError("Volume already meshed!"); return 0;
+	    }
+
+	  if (!stlgeometry->edgesfound) 
+	    {
+	      PrintUserError("You have to do 'meshing->analyse geometry' first!!!"); 
+	      return 0; 
+	    }
+	  if (!stlgeometry->surfacemeshed) 
+	    {
+	      PrintUserError("You have to do 'meshing->mesh surface' first!!!"); 
+	      return 0; 
+	    }
+	  if (!stlgeometry->surfaceoptimized) 
+	    {
+	      PrintWarning("You should do 'meshing->optimize surface' first!!!"); 
+	    }
+
+	  PrintMessage(5,"Check Overlapping boundary: ");
+	  mesh->FindOpenElements();
+	  mesh->CheckOverlappingBoundary();
+	  PrintMessage(5,"");
+	  
+	  if (stlparam.recalc_h_opt)
+	    {
+	      mesh -> SetLocalH (stlgeometry->GetBoundingBox().PMin() - Vec3d(10, 10, 10),
+				 stlgeometry->GetBoundingBox().PMax() + Vec3d(10, 10, 10),
+				 mparam.grading);	  
+	      mesh -> CalcLocalH ();
+	    }
+	  
+	  
+	  PrintMessage(5,"Volume meshing");
+	  int retval = MeshVolume (mparam, *mesh);
+	  if (retval == MESHING3_OK)
+	    {
+	      RemoveIllegalElements(*mesh);
+	      stlgeometry->volumemeshed = 1;
+	    } 
+	  else if (retval == MESHING3_OUTERSTEPSEXCEEDED)
+	    {
+	      PrintError("Give up because of too many trials. Meshing aborted!");
+	      return 0;
+	    }
+	  else if (retval == MESHING3_TERMINATE)
+	    {
+	      PrintWarning("Meshing Stopped by user!");
+	    }
+	  else
+	    {
+	      PrintError("Volume meshing not successful. Meshing aborted!");
+	      return 0;
+	    }
+
+#ifdef STAT_STREAM
+	  (*statout) << GetTime() << " & " << endl;
+#endif
+	  MeshQuality3d (*mesh);
+	}
+
+      if (multithread.terminate)
+	return 0;
+
+      if (perfstepsstart <= MESHCONST_OPTVOLUME && 
+	  perfstepsend >= MESHCONST_OPTVOLUME)
+	{
+	  if (!stlgeometry->edgesfound) 
+	    {
+	      PrintUserError("You have to do 'meshing->analyse geometry' first!!!"); 
+	      return 0; 
+	    }
+	  if (!stlgeometry->surfacemeshed) 
+	    {
+	      PrintUserError("You have to do 'meshing->mesh surface' first!!!"); 
+	      return 0; 
+	    }
+	  if (!stlgeometry->volumemeshed) 
+	    {
+	      PrintUserError("You have to do 'meshing->mesh volume' first!!!"); 
+	      return 0; 
+	    }
+
+	  if (!optstring || strlen(optstring) == 0)
+	    {
+	      mparam.optimize3d = "cmdmstm";
+	    }
+	  else
+	    {
+	      mparam.optimize3d = optstring;
+	    }
+
+
+	  OptimizeVolume (mparam, *mesh, NULL);
+	  
+#ifdef STAT_STREAM
+	  (*statout) << GetTime() << " & " << endl;
+	  (*statout) << mesh->GetNE() << " & " << endl
+		     << mesh->GetNP() << " " << '\\' << '\\' << " \\" << "hline" << endl;
+#endif
+
+#ifdef OPENGL
+	  extern void Render();
+	  Render();
+#endif	      
+
+	}
+    }
+  
+
+  return 0;
+}
+
+
+
+}
diff --git a/Netgen/libsrc/stlgeom/stlline.cpp b/Netgen/libsrc/stlgeom/stlline.cpp
new file mode 100644
index 0000000000..792b1fcd43
--- /dev/null
+++ b/Netgen/libsrc/stlgeom/stlline.cpp
@@ -0,0 +1,780 @@
+#include <mystdlib.h>
+
+#include <myadt.hpp>
+#include <linalg.hpp>
+#include <gprim.hpp>
+
+#include <meshing.hpp>
+
+#include "stlgeom.hpp"
+
+namespace netgen
+{
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//++++++++++++++  EDGE DATA     ++++++++++++++++++++++++++++++++++++++++++
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+
+/*
+void STLEdgeData :: Write(ofstream& of) const
+{
+  of // << angle << " "
+     << p1 << " "
+     << p2 << " "
+     << lt << " "
+     << rt << " "
+    //     << status
+     << endl;
+}
+
+void STLEdgeData :: Read(ifstream& ifs)
+{
+  // ifs >> angle;
+  ifs >> p1;
+  ifs >> p2;
+  ifs >> lt;
+  ifs >> rt;
+  //  ifs >> status;
+}
+
+
+int STLEdgeData :: GetStatus () const
+{
+  if (topedgenr <= 0 || topedgenr > top->GetNTE()) return 0;
+  return top->GetTopEdge (topedgenr).GetStatus(); 
+}
+
+void STLEdgeData ::SetStatus (int stat)
+{
+  if (topedgenr >= 1 && topedgenr <= top->GetNTE())
+    top->GetTopEdge (topedgenr).SetStatus(stat); 
+}
+
+
+float STLEdgeData :: CosAngle() const
+{
+  return top->GetTopEdge (topedgenr).CosAngle(); 
+}
+
+
+
+void STLEdgeDataList :: ResetAll()
+{
+  int i;
+  for (i = 1; i <= edgedata.Size(); i++)
+    {
+      edgedata.Elem(i).SetUndefined();
+    }
+}
+
+void STLEdgeDataList :: ResetCandidates()
+{
+  int i;
+  for (i = 1; i <= edgedata.Size(); i++)
+    {
+      if (edgedata.Get(i).Candidate())
+	{edgedata.Elem(i).SetUndefined();}
+    }
+}
+
+int STLEdgeDataList :: GetNConfEdges() const
+{
+  int i;
+  int cnt = 0;
+  for (i = 1; i <= edgedata.Size(); i++)
+    {
+      if (edgedata.Get(i).Confirmed()) {cnt++;}
+    }
+  return cnt;
+}
+
+void STLEdgeDataList :: ConfirmCandidates()
+{
+  int i;
+  for (i = 1; i <= edgedata.Size(); i++)
+    {
+      if (edgedata.Get(i).Candidate())
+	{edgedata.Elem(i).SetConfirmed();}
+    }
+}
+
+int STLEdgeDataList :: GetEdgeNum(int np1, int np2) const
+{
+  INDEX_2 ed(np1,np2);
+  ed.Sort();
+  if (hashtab.Used(ed))
+    {
+      return hashtab.Get(ed);
+    }
+
+//   int i;
+//   for (i = 1; i <= Size(); i++)
+//     {
+//       if ((Get(i).p1 == np1 && Get(i).p2 == np2) ||
+// 	  (Get(i).p2 == np1 && Get(i).p1 == np2))
+// 	{
+// 	  return i;
+// 	}
+//     }
+
+  return 0;
+}
+
+const STLEdgeDataList& STLEdgeDataList :: operator=(const STLEdgeDataList& edl)
+{
+  int i;
+  SetSize(edl.Size());
+  for (i = 1; i <= Size(); i++)
+    {
+      Add(edl.Get(i), i);
+    }
+  return *this;
+} 
+
+void STLEdgeDataList :: Add(const STLEdgeData& ed, int i)
+{
+  INDEX_2 edge(ed.p1,ed.p2);
+  edge.Sort();
+  hashtab.Set(edge, i);
+  Elem(i) = ed;
+  AddEdgePP(ed.p1,i);
+  AddEdgePP(ed.p2,i);
+}
+
+void STLEdgeDataList :: Write(ofstream& of) const
+{
+  of.precision(16);
+  int i;
+  of << Size() << endl;
+  
+  for (i = 1; i <= Size(); i++)
+    {
+      Get(i).Write(of);
+    }
+}
+
+void STLEdgeDataList :: Read(ifstream& ifs)
+{
+  int i,n;
+  ifs >> n;
+
+  SetSize(n);
+  STLEdgeData ed;
+  for (i = 1; i <= n; i++)
+    {
+      ed.Read(ifs);
+      Add(ed,i);
+    }
+}
+
+int STLEdgeDataList :: GetNEPPStat(int p, int status) const
+{
+  int i;
+  int cnt = 0;
+  for (i = 1; i <= GetNEPP(p); i++)
+    {
+      if (Get(GetEdgePP(p,i)).GetStatus() == status)
+	{
+	  cnt++;
+	}
+    }
+  return cnt;
+}
+
+int STLEdgeDataList :: GetNConfCandEPP(int p) const
+{
+  int i;
+  int cnt = 0;
+  for (i = 1; i <= GetNEPP(p); i++)
+    {
+      if (Get(GetEdgePP(p,i)).ConfCand())
+	{
+	  cnt++;
+	}
+    }
+  return cnt;
+}
+
+
+void STLEdgeDataList :: BuildLineWithEdge(int ep1, int ep2, ARRAY<twoint>& line)
+{
+  int status = Get(GetEdgeNum(ep1,ep2)).GetStatus();
+
+  int found, pstart, p, en, pnew, ennew;
+  int closed = 0;
+  int j, i;
+  for (j = 1; j <= 2; j++)
+    {
+      if (j == 1) {p = ep1;}
+      if (j == 2) {p = ep2;}
+
+      pstart = p;
+      en = GetEdgeNum(ep1,ep2);
+
+      found = 1;
+      while (found && !closed)
+	{
+	  found = 0;
+	  
+	  if (GetNEPPStat(p,status) == 2)
+	    {
+	      for (i = 1; i <= GetNEPP(p); i++)
+		{		
+		  const STLEdgeData& e = Get(GetEdgePP(p,i));
+		  if (GetEdgePP(p,i) != en && e.GetStatus() == status) 
+		    {
+		      if (e.p1 == p) 
+			{pnew = e.p2;}
+		      else 
+			{pnew = e.p1;}
+
+		      ennew = GetEdgePP(p,i);
+		    }
+		}
+	      if (pnew == pstart) {closed = 1;}
+	      else
+		{
+		  line.Append(twoint(p,pnew));
+		  p = pnew;
+		  en = ennew;
+		  found = 1;
+		}
+	    }
+	}
+    }
+  
+}
+*/
+
+
+
+
+STLEdgeDataList :: STLEdgeDataList (STLTopology & ageom)
+  : geom(ageom)
+{
+  ;
+}
+
+STLEdgeDataList :: ~STLEdgeDataList()
+{
+  ;
+}
+
+
+void STLEdgeDataList :: Store ()
+{
+  int i, ne = geom.GetNTE();
+  storedstatus.SetSize(ne);
+  for (i = 1; i <= ne; i++)
+    {
+      storedstatus.Elem(i) = Get(i).GetStatus();
+    }
+}
+
+void STLEdgeDataList :: Restore ()
+{
+  int i, ne = geom.GetNTE();
+  if (storedstatus.Size() == ne)
+    for (i = 1; i <= ne; i++)
+      geom.GetTopEdge(i).SetStatus (storedstatus.Elem(i));
+}
+
+
+void STLEdgeDataList :: ResetAll()
+{
+  int i, ne = geom.GetNTE();
+  for (i = 1; i <= ne; i++)
+    geom.GetTopEdge (i).SetStatus (ED_UNDEFINED);
+}
+
+int STLEdgeDataList :: GetNConfEdges() const
+{
+  int i, ne = geom.GetNTE();
+  int cnt = 0;
+  for (i = 1; i <= ne; i++)
+    if (geom.GetTopEdge (i).GetStatus() == ED_CONFIRMED)
+      cnt++;
+  return cnt; 
+}
+
+void STLEdgeDataList :: ChangeStatus(int status1, int status2)
+{
+  int i, ne = geom.GetNTE();
+  for (i = 1; i <= ne; i++)
+    if (geom.GetTopEdge (i).GetStatus() == status1)
+      geom.GetTopEdge (i).SetStatus (status2);
+}
+
+/*
+void STLEdgeDataList :: Add(const STLEdgeData& ed, int i)
+{
+  INDEX_2 edge(ed.p1,ed.p2);
+  edge.Sort();
+  hashtab.Set(edge, i);
+  Elem(i) = ed;
+  AddEdgePP(ed.p1,i);
+  AddEdgePP(ed.p2,i);
+}
+*/
+
+void STLEdgeDataList :: Write(ofstream& of) const
+{
+  
+  /*
+  of.precision(16);
+  int i;
+  of << Size() << endl;
+  
+  for (i = 1; i <= Size(); i++)
+    {
+      Get(i).Write(of);
+    }
+
+  */
+  of.precision(16);
+  int i, ne = geom.GetNTE();
+  //of << GetNConfEdges() << endl;
+  of << geom.GetNTE() << endl;
+
+  for (i = 1; i <= ne; i++)
+    {
+      const STLTopEdge & edge = geom.GetTopEdge(i);
+      //if (edge.GetStatus() == ED_CONFIRMED)
+      of << edge.GetStatus() << " ";
+
+      const Point3d & p1 = geom.GetPoint (edge.PNum(1));
+      const Point3d & p2 = geom.GetPoint (edge.PNum(2));
+      of << p1.X() << " "
+	 << p1.Y() << " "
+	 << p1.Z() << " "
+	 << p2.X() << " "
+	 << p2.Y() << " "
+	 << p2.Z() << endl;
+    }
+  
+}
+
+void STLEdgeDataList :: Read(ifstream& ifs)
+{
+  int i, nce;
+  Point3d p1, p2;
+  int pi1, pi2;
+  int status, ednum;
+
+  ifs >> nce;
+  for (i = 1; i <= nce; i++)
+    {
+      ifs >> status;
+      ifs >> p1.X() >> p1.Y() >> p1.Z();
+      ifs >> p2.X() >> p2.Y() >> p2.Z();
+
+      pi1 = geom.GetPointNum (p1);
+      pi2 = geom.GetPointNum (p2);
+      ednum = geom.GetTopEdgeNum (pi1, pi2);
+
+
+      if (ednum)
+	{ 
+	  geom.GetTopEdge(ednum).SetStatus (status);
+	//	geom.GetTopEdge (ednum).SetStatus (ED_CONFIRMED);
+	}
+    }
+    /*
+  int i,n;
+  ifs >> n;
+
+  SetSize(n);
+  STLEdgeData ed;
+  for (i = 1; i <= n; i++)
+    {
+      ed.Read(ifs);
+      Add(ed,i);
+    }
+  */
+}
+
+int STLEdgeDataList :: GetNEPPStat(int p, int status) const
+{
+  int i;
+  int cnt = 0;
+  for (i = 1; i <= GetNEPP(p); i++)
+    {
+      if (Get(GetEdgePP(p,i)).GetStatus() == status)
+	{
+	  cnt++;
+	}
+    }
+  return cnt;
+}
+
+int STLEdgeDataList :: GetNConfCandEPP(int p) const
+{
+  int i;
+  int cnt = 0;
+  for (i = 1; i <= GetNEPP(p); i++)
+    {
+      if (Get(GetEdgePP(p,i)).GetStatus() == ED_CANDIDATE || 
+	  Get(GetEdgePP(p,i)).GetStatus() == ED_CONFIRMED)
+	{
+	  cnt++;
+	}
+    }
+  return cnt;
+}
+
+
+void STLEdgeDataList :: BuildLineWithEdge(int ep1, int ep2, ARRAY<twoint>& line)
+{
+  int status = Get(GetEdgeNum(ep1,ep2)).GetStatus();
+
+  int found, pstart, p, en, pnew, ennew;
+  int closed = 0;
+  int j, i;
+  for (j = 1; j <= 2; j++)
+    {
+      if (j == 1) {p = ep1;}
+      if (j == 2) {p = ep2;}
+
+      pstart = p;
+      en = GetEdgeNum(ep1,ep2);
+
+      found = 1;
+      while (found && !closed)
+	{
+	  found = 0;
+	  
+	  if (GetNEPPStat(p,status) == 2)
+	    {
+	      for (i = 1; i <= GetNEPP(p); i++)
+		{		
+		  const STLTopEdge & e = Get(GetEdgePP(p,i));
+		  if (GetEdgePP(p,i) != en && e.GetStatus() == status) 
+		    {
+		      if (e.PNum(1) == p) 
+			{pnew = e.PNum(2);}
+		      else 
+			{pnew = e.PNum(1);}
+
+		      ennew = GetEdgePP(p,i);
+		    }
+		}
+	      if (pnew == pstart) {closed = 1;}
+	      else
+		{
+		  line.Append(twoint(p,pnew));
+		  p = pnew;
+		  en = ennew;
+		  found = 1;
+		}
+	    }
+	}
+    }
+  
+}
+
+int Exists(int p1, int p2, const ARRAY<twoint>& line)
+{
+  int i;
+  for (i = 1; i <= line.Size(); i++)
+    {
+      if (line.Get(i).i1 == p1 && line.Get(i).i2 == p2 ||
+	  line.Get(i).i1 == p2 && line.Get(i).i2 == p1) {return 1;}
+    }
+  return 0;
+}
+
+void STLEdgeDataList :: BuildClusterWithEdge(int ep1, int ep2, ARRAY<twoint>& line)
+{
+  int status = Get(GetEdgeNum(ep1,ep2)).GetStatus();
+
+  int p, en;
+  int j, i, k;
+  int oldend;
+  int newend = 1;
+  int pnew, ennew;
+
+  int changed = 1;
+  while (changed)
+    {
+      changed = 0;
+      for (j = 1; j <= 2; j++)
+	{
+	  oldend = newend;
+	  newend = line.Size();
+	  for (k = oldend; k <= line.Size(); k++)
+	    {
+	      if (j == 1) p = line.Get(k).i1;
+	      if (j == 2) p = line.Get(k).i2;
+	      en = GetEdgeNum(line.Get(k).i1, line.Get(k).i2);
+
+	      for (i = 1; i <= GetNEPP(p); i++)
+		{		
+		  pnew = 0;
+		  const STLTopEdge & e = Get(GetEdgePP(p,i));
+		  if (GetEdgePP(p,i) != en && e.GetStatus() == status) 
+		    {
+		      if (e.PNum(1) == p) 
+			{pnew = e.PNum(2);}
+		      else 
+			{pnew = e.PNum(1);}
+
+		      ennew = GetEdgePP(p,i);
+		    }
+		  if (pnew && !Exists(p,pnew,line))
+		    {
+		      changed = 1;
+		      line.Append(twoint(p,pnew));
+		      p = pnew;
+		      en = ennew;
+		    }
+		}
+	      
+	    }
+	}
+
+    }
+
+}
+
+
+
+
+
+
+
+
+
+
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//+++++++++++++++++++   STL LINE    +++++++++++++++++++++++++++++++
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+STLLine :: STLLine(const STLGeometry * ageometry)
+  : pts(), lefttrigs(), righttrigs()
+{
+  geometry = ageometry;
+  split = 0;
+};
+
+int STLLine :: GetNS() const
+{
+  if (pts.Size() <= 1) {return 0;}
+  return pts.Size()-1;
+}
+void STLLine :: GetSeg(int nr, int& p1, int& p2) const
+{
+  p1 = pts.Get(nr);
+  p2 = pts.Get(nr+1);
+}
+
+int STLLine :: GetLeftTrig(int nr) const 
+{
+  if (nr > lefttrigs.Size()) {PrintSysError("In STLLine::GetLeftTrig!!!"); return 0;}
+  return lefttrigs.Get(nr);
+};
+
+int STLLine :: GetRightTrig(int nr) const 
+{
+  if (nr > righttrigs.Size()) {PrintSysError("In STLLine::GetRightTrig!!!"); return 0;}
+  return righttrigs.Get(nr);
+};
+
+double STLLine :: GetSegLen(const ARRAY<Point<3> >& ap, int nr) const
+{
+  return Dist(ap.Get(PNum(nr)),ap.Get(PNum(nr+1)));
+}
+
+double STLLine :: GetLength(const ARRAY<Point<3> >& ap) const
+{
+  double len = 0;
+  for (int i = 2; i <= pts.Size(); i++)
+    {
+      len += (ap.Get(pts.Get(i)) - ap.Get(pts.Get(i-1))).Length();
+    }
+  return len;
+}
+
+void STLLine :: GetBoundingBox (const ARRAY<Point<3> > & ap, Box<3> & box) const
+{
+  box.Set (ap.Get (pts[0]));
+  for (int i = 1; i < pts.Size(); i++)
+    box.Add (ap.Get(pts[i]));
+}
+
+
+
+Point<3> STLLine :: 
+GetPointInDist(const ARRAY<Point<3> >& ap, double dist, int& index) const
+{
+  if (dist <= 0)
+    {
+      index = 1;
+      return ap.Get(StartP());
+    }
+  
+  double len = 0;
+  int i;
+  for (i = 1; i < pts.Size(); i++)
+    {
+      double seglen = Dist (ap.Get(pts.Get(i)),
+			    ap.Get(pts.Get(i+1)));
+
+      if (len + seglen > dist)
+	{
+	  index = i;
+	  double relval = (dist - len) / (seglen + 1e-16);
+	  Vec3d v (ap.Get(pts.Get(i)), ap.Get(pts.Get(i+1)));
+	  return ap.Get(pts.Get(i)) + relval * v;
+	}
+
+      len += seglen;
+    }
+
+  index = pts.Size() - 1;
+  return ap.Get(EndP());
+}
+
+
+/*
+double stlgh;
+double GetH(const Point3d& p, double x) 
+{
+  return stlgh;//+0.5)*(x+0.5);
+}
+*/
+STLLine* STLLine :: Mesh(const ARRAY<Point<3> >& ap, 
+			 ARRAY<Point3d>& mp, double ghi,
+			 class Mesh& mesh) const
+{
+  STLLine* line = new STLLine(geometry);
+
+  //stlgh = ghi; //uebergangsloesung!!!!
+  
+  double len = GetLength(ap);
+  double inthl = 0; //integral of 1/h
+  double dist = 0;
+  double h;
+  int ind;
+  Point3d p;
+
+  int i, j;
+
+  Box<3> bbox;
+  GetBoundingBox (ap, bbox);
+  double diam = bbox.Diam();
+
+  double minh = mesh.LocalHFunction().GetMinH (bbox.PMin(), bbox.PMax());
+
+  double maxseglen = 0;
+  for (i = 1; i <= GetNS(); i++)
+    maxseglen = max2 (maxseglen, GetSegLen (ap, i));
+  
+  int nph = 10+int(maxseglen / minh); //anzahl der integralauswertungen pro segment
+
+  ARRAY<double> inthi(GetNS()*nph);
+  ARRAY<double> curvelen(GetNS()*nph);
+
+
+  for (i = 1; i <= GetNS(); i++)
+    {
+      double seglen = GetSegLen(ap,i);
+      for (j = 1; j <= nph; j++)
+	{
+	  p = GetPointInDist(ap,dist,ind);
+	  //h = GetH(p,dist/len);
+	  h = mesh.GetH(p);
+
+	  
+	  dist += GetSegLen(ap,i)/(double)nph;
+	  
+	  inthl += GetSegLen(ap,i)/nph/(h);
+	  inthi.Elem((i-1)*nph+j) = GetSegLen(ap,i)/nph/h;
+	  curvelen.Elem((i-1)*nph+j) = GetSegLen(ap,i)/nph;
+	}
+    }
+
+
+  int inthlint = int(inthl+1);
+
+  if ( (inthlint < 3) && (StartP() == EndP()))
+    {
+      inthlint = 3;
+    }
+  if ( (inthlint == 1) && ShouldSplit())
+    {
+      inthlint = 2; 
+    }
+     
+  double fact = inthl/(double)inthlint;
+  dist = 0;
+  j = 1;
+
+
+  p = ap.Get(StartP());
+  int pn = AddPointIfNotExists(mp, p, 1e-10*diam);
+
+  int segn = 1;
+  line->AddPoint(pn);
+  line->AddLeftTrig(GetLeftTrig(segn));
+  line->AddRightTrig(GetRightTrig(segn));
+  line->AddDist(dist);
+
+  inthl = 0; //restart each meshseg
+  for (i = 1; i <= inthlint; i++)
+    {
+      while (inthl < 1.000000001 && j <= inthi.Size())
+      //      while (inthl-1. < 1e-9) && j <= inthi.Size())
+	{
+	  inthl += inthi.Get(j)/fact;
+	  dist += curvelen.Get(j);
+	  j++;
+	}
+
+      //went to far:
+      j--;
+      double tofar = (inthl - 1)/inthi.Get(j);
+      inthl -= tofar*inthi.Get(j);
+      dist -= tofar*curvelen.Get(j)*fact;
+
+      if (i == inthlint && fabs(dist - len) >= 1E-8) 
+	{
+	  PrintSysError("meshline failed!!!"); 
+	}
+
+      if (i != inthlint) 
+	{
+	  p = GetPointInDist(ap,dist,ind);
+	  pn = AddPointIfNotExists(mp, p, 1e-10*diam);
+	  segn = ind;
+	  line->AddPoint(pn);
+	  line->AddLeftTrig(GetLeftTrig(segn));
+	  line->AddRightTrig(GetRightTrig(segn));
+	  line->AddDist(dist);
+	}
+
+      inthl = tofar*inthi.Get(j);
+      dist += tofar*curvelen.Get(j)*fact;
+      j++;
+    }
+
+  p = ap.Get(EndP());
+  pn = AddPointIfNotExists(mp, p, 1e-10*diam);
+  segn = GetNS();
+  line->AddPoint(pn);
+  line->AddLeftTrig(GetLeftTrig(segn));
+  line->AddRightTrig(GetRightTrig(segn));
+  line->AddDist(dist);
+  
+  for (int ii = 1; ii <= line->GetNS(); ii++)
+    {
+      int p1, p2;
+      line->GetSeg(ii,p1,p2);
+    }
+  /*  
+  (*testout) << "line, " << ap.Get(StartP()) << "-" << ap.Get(EndP())
+	     << " len = " << Dist (ap.Get(StartP()), ap.Get(EndP())) << endl;
+  */
+  return line;
+}
+}
diff --git a/Netgen/libsrc/stlgeom/stlline.hpp b/Netgen/libsrc/stlgeom/stlline.hpp
new file mode 100644
index 0000000000..70393ca060
--- /dev/null
+++ b/Netgen/libsrc/stlgeom/stlline.hpp
@@ -0,0 +1,188 @@
+#ifndef FILE_STLLINE
+#define FILE_STLLINE
+
+
+/**************************************************************************/
+/* File:   stlline.hh                                                     */
+/* Author: Joachim Schoeberl                                              */
+/* Author2: Johannes Gerstmayr                                            */
+/* Date:   20. Nov. 99                                                    */
+/**************************************************************************/
+
+class STLGeometry;
+class STLTopology;
+
+class STLEdge
+{
+public:
+  int pts[2];
+  int trigs[2]; //left and right trig
+
+  STLEdge (const int * apts) {pts[0] = apts[0]; pts[1] = apts[1];}
+  STLEdge (int v1, int v2) {pts[0] = v1; pts[1] = v2;}
+  STLEdge () {pts[0]=0;pts[1]=0;}
+  int PNum(int i) const {return pts[(i-1)];}
+
+  int LeftTrig() const {return trigs[0];}
+  int RightTrig() const {return trigs[1];}
+  void SetLeftTrig(int i) {trigs[0] = i;}
+  void SetRightTrig(int i) {trigs[1] = i;}
+};
+
+enum STL_ED_STATUS { ED_EXCLUDED, ED_CONFIRMED, ED_CANDIDATE, ED_UNDEFINED };
+                       
+
+/*
+
+class STLEdgeData
+{
+public:
+  //  float angle;
+  int p1;
+  int p2;
+  int lt; //left trig
+  int rt; //right trig
+  //  int status;
+
+  STLTopology * top;  // pointer to stl topology
+  int topedgenr;  // number of corresponding topology edge
+
+  STLEdgeData() {}; 
+  STLEdgeData(float anglei, int p1i, int p2i, int lti, int rti) 
+{
+//     angle = anglei; 
+p1 = p1i; p2 = p2i;
+      lt = lti; rt = rti;
+    }
+
+  int GetStatus () const;
+  void SetStatus (int stat);
+
+  void SetExcluded() { SetStatus (ED_EXCLUDED); }
+  void SetConfirmed() { SetStatus (ED_CONFIRMED); }
+  void SetCandidate() { SetStatus (ED_CANDIDATE); }
+  void SetUndefined() { SetStatus (ED_UNDEFINED); }
+
+  int Excluded() const {return GetStatus() == ED_EXCLUDED;}
+  int Confirmed() const {return GetStatus() == ED_CONFIRMED;}
+  int Candidate() const {return GetStatus() == ED_CANDIDATE;}
+  int Undefined() const {return GetStatus() == ED_UNDEFINED;}
+  int ConfCand() const {return GetStatus() == ED_CONFIRMED || GetStatus() == ED_CANDIDATE;}
+
+  float CosAngle() const; 
+
+  void Write(ofstream& of) const;
+  void Read(ifstream& ifs);
+};
+
+class STLEdgeDataList
+{
+private:
+  INDEX_2_HASHTABLE<int> hashtab;
+  ARRAY<STLEdgeData> edgedata;
+  TABLE<int> edgesperpoint;
+  
+public:
+
+  STLEdgeDataList():edgedata(),hashtab(1),edgesperpoint() {};
+  const STLEdgeDataList& operator=(const STLEdgeDataList& edl); 
+  void SetSize(int size) 
+    {
+      edgedata.SetSize(size);
+      hashtab.SetSize(size);
+      edgesperpoint.SetSize(size);
+    }
+  void Clear() {SetSize(0);}
+  int Size() const {return edgedata.Size();}
+  const STLEdgeData& Get(int i) const {return edgedata.Get(i);}
+  STLEdgeData& Elem(int i) {return edgedata.Elem(i);}
+  void Add(const STLEdgeData& ed, int i);
+
+  int GetNEPP(int pn) const 
+    {
+      return edgesperpoint.EntrySize(pn);
+    };
+  int GetEdgePP(int pn, int vi) const
+    {
+      return edgesperpoint.Get(pn,vi);
+    };
+  void AddEdgePP(int pn, int vn) {edgesperpoint.Add(pn,vn);};
+
+  void ResetAll();
+  void ResetCandidates();
+  void ConfirmCandidates();
+  int GetEdgeNum(int np1, int np2) const;
+
+  int GetNConfEdges() const;
+
+  void Write(ofstream& of) const;
+  void Read(ifstream& ifs);
+
+  void BuildLineWithEdge(int ep1, int ep2, ARRAY<twoint>& line);
+
+  int GetNEPPStat(int p, int status) const;
+  int GetNConfCandEPP(int p) const;
+};
+*/
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+//a line defined by several points (polyline)
+class STLLine
+{
+private:
+  const STLGeometry * geometry;
+  ARRAY<int> pts;
+  ARRAY<int> lefttrigs;
+  ARRAY<int> righttrigs;
+  ARRAY<double> dists;
+  int split;
+
+public:
+  STLLine(const STLGeometry * ageometry);
+  void AddPoint(int i) {pts.Append(i);}
+  int PNum(int i) const {return pts.Get(i);}
+  int NP() const {return pts.Size();}
+  int GetNS() const;
+  void GetSeg(int nr, int& p1, int& p2) const;
+  double GetSegLen(const ARRAY<Point<3> >& ap, int nr) const;
+  int GetLeftTrig(int nr) const;
+  int GetRightTrig(int nr) const;
+  double GetDist(int nr) const { return dists.Get(nr);};
+  void GetBoundingBox (const ARRAY<Point<3> > & ap, Box<3> & box) const;
+
+  void AddLeftTrig(int nr) {lefttrigs.Append(nr);}
+  void AddRightTrig(int nr) {righttrigs.Append(nr);}
+  void AddDist (double dist) {dists.Append(dist); }
+  int StartP() const {return pts.Get(1);}
+  int EndP() const {return pts.Get(pts.Size());}
+    
+  double GetLength(const ARRAY<Point<3> >& ap) const;
+
+  //suche punkt in entfernung (in linienkoordinaten) dist
+  //in index ist letzter punkt VOR dist (d.h. max pts.Size()-1)
+  Point<3> GetPointInDist(const ARRAY<Point<3> >& ap, double dist, int& index) const;
+
+  //return a meshed polyline
+  STLLine* Mesh(const ARRAY<Point<3> >& ap, 
+		ARRAY<Point3d>& mp, double ghi,
+		class Mesh& mesh) const;
+
+  void DoSplit() {split = 1;}
+  int ShouldSplit() const {return split;}
+};
+
+#endif
diff --git a/Netgen/libsrc/stlgeom/stltool.cpp b/Netgen/libsrc/stlgeom/stltool.cpp
new file mode 100644
index 0000000000..9513904bfa
--- /dev/null
+++ b/Netgen/libsrc/stlgeom/stltool.cpp
@@ -0,0 +1,1288 @@
+#include <mystdlib.h>
+
+#include <myadt.hpp>
+#include <linalg.hpp>
+#include <gprim.hpp>
+
+#include <meshing.hpp>
+
+#include "stlgeom.hpp"
+
+namespace netgen
+{
+
+
+//add a point into a pointlist, return pointnumber
+int AddPointIfNotExists(ARRAY<Point3d>& ap, const Point3d& p, double eps)
+{
+  int i;
+  for (i = 1; i <= ap.Size(); i++)
+    {
+      if (Dist(ap.Get(i),p) <= eps ) {return i;}
+    }
+  return ap.Append(p);
+}
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+double GetDistFromLine(const Point<3> & lp1, const Point<3> & lp2, 
+		       Point<3> & p)
+{
+  Vec3d vn = lp2 - lp1;
+  Vec3d v1 = p - lp1;
+  Vec3d v2 = lp2 - p;
+
+  Point3d pold = p;
+
+  if (v2 * vn <= 0) {p = lp2; return (pold - p).Length();}
+  if (v1 * vn <= 0) {p = lp1; return (pold - p).Length();}
+    
+  double vnl = vn.Length();
+  if (vnl == 0) {return Dist(lp1,p);}
+
+  vn /= vnl;
+  p = lp1 + (v1 * vn) * vn;
+  return (pold - p).Length();
+};
+
+double GetDistFromInfiniteLine(const Point<3>& lp1, const Point<3>& lp2, const Point<3>& p)
+{
+  Vec3d vn(lp1, lp2);
+  Vec3d v1(lp1, p);
+
+  double vnl = vn.Length();
+
+  if (vnl == 0)
+    {
+      return Dist (lp1, p);
+    }
+  else
+    {
+      return Cross (vn, v1).Length() / vnl;
+    }
+};
+
+
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//Binary IO-Manipulation
+
+
+
+void FIOReadInt(istream& ios, int& i)
+{
+  const int ilen = sizeof(int);
+  
+  char buf[ilen];
+  int j;
+  for (j = 0; j < ilen; j++)
+    {
+      ios.get(buf[j]);
+    }
+  memcpy(&i, &buf, ilen);
+}
+
+void FIOWriteInt(ostream& ios, const int& i)
+{
+  const int ilen = sizeof(int);
+  
+  char buf[ilen];
+  memcpy(&buf, &i, ilen);
+
+  int j;
+  for (j = 0; j < ilen; j++)
+    {
+      ios << buf[j];
+    }
+}
+
+void FIOReadDouble(istream& ios, double& i)
+{
+  const int ilen = sizeof(double);
+  
+  char buf[ilen];
+  int j;
+  for (j = 0; j < ilen; j++)
+    {
+      ios.get(buf[j]);
+    }
+  memcpy(&i, &buf, ilen);
+}
+
+void FIOWriteDouble(ostream& ios, const double& i)
+{
+  const int ilen = sizeof(double);
+  
+  char buf[ilen];
+  memcpy(&buf, &i, ilen);
+
+  int j;
+  for (j = 0; j < ilen; j++)
+    {
+      ios << buf[j];
+    }
+}
+
+void FIOReadFloat(istream& ios, float& i)
+{
+  const int ilen = sizeof(float);
+  
+  char buf[ilen];
+  int j;
+  for (j = 0; j < ilen; j++)
+    {
+      ios.get(buf[j]);
+    }
+  memcpy(&i, &buf, ilen);
+}
+
+void FIOWriteFloat(ostream& ios, const float& i)
+{
+  const int ilen = sizeof(float);
+  
+  char buf[ilen];
+  memcpy(&buf, &i, ilen);
+
+  int j;
+  for (j = 0; j < ilen; j++)
+    {
+      ios << buf[j];
+     }
+}
+
+void FIOReadString(istream& ios, char* str, int len)
+{
+  int j;
+  for (j = 0; j < len; j++)
+    {
+      ios.get(str[j]);
+    }
+}
+
+//read string and add terminating 0
+void FIOReadStringE(istream& ios, char* str, int len)
+{
+  int j;
+  for (j = 0; j < len; j++)
+    {
+      ios.get(str[j]);
+    }
+  str[len] = 0;
+}
+
+void FIOWriteString(ostream& ios, char* str, int len)
+{
+  int j;
+  for (j = 0; j < len; j++)
+    {
+      ios << str[j];
+    }
+}
+
+
+/*
+void FIOReadInt(istream& ios, int& i)
+{
+  const int ilen = sizeof(int);
+  
+  char buf[ilen];
+  int j;
+  for (j = 0; j < ilen; j++)
+    {
+      ios.get(buf[ilen-j-1]);
+    }
+  memcpy(&i, &buf, ilen);
+}
+
+void FIOWriteInt(ostream& ios, const int& i)
+{
+  const int ilen = sizeof(int);
+  
+  char buf[ilen];
+  memcpy(&buf, &i, ilen);
+
+  int j;
+  for (j = 0; j < ilen; j++)
+    {
+      ios << buf[ilen-j-1];
+    }
+}
+
+void FIOReadDouble(istream& ios, double& i)
+{
+  const int ilen = sizeof(double);
+  
+  char buf[ilen];
+  int j;
+  for (j = 0; j < ilen; j++)
+    {
+      ios.get(buf[ilen-j-1]);
+    }
+  memcpy(&i, &buf, ilen);
+}
+
+void FIOWriteDouble(ostream& ios, const double& i)
+{
+  const int ilen = sizeof(double);
+  
+  char buf[ilen];
+  memcpy(&buf, &i, ilen);
+
+  int j;
+  for (j = 0; j < ilen; j++)
+    {
+      ios << buf[ilen-j-1];
+    }
+}
+
+void FIOReadFloat(istream& ios, float& i)
+{
+  const int ilen = sizeof(float);
+  
+  char buf[ilen];
+  int j;
+  for (j = 0; j < ilen; j++)
+    {
+      ios.get(buf[ilen-j-1]);
+    }
+  memcpy(&i, &buf, ilen);
+}
+
+void FIOWriteFloat(ostream& ios, const float& i)
+{
+  const int ilen = sizeof(float);
+  
+  char buf[ilen];
+  memcpy(&buf, &i, ilen);
+
+  int j;
+  for (j = 0; j < ilen; j++)
+    {
+      ios << buf[ilen-j-1];
+    }
+}
+
+void FIOReadString(istream& ios, char* str, int len)
+{
+  int j;
+  for (j = 0; j < len; j++)
+    {
+      ios.get(str[j]);
+    }
+}
+
+//read string and add terminating 0
+void FIOReadStringE(istream& ios, char* str, int len)
+{
+  int j;
+  for (j = 0; j < len; j++)
+    {
+      ios.get(str[j]);
+    }
+  str[len] = 0;
+}
+
+void FIOWriteString(ostream& ios, char* str, int len)
+{
+  int j;
+  for (j = 0; j < len; j++)
+    {
+      ios << str[j];
+    }
+}
+*/
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+STLReadTriangle :: STLReadTriangle (const Point<3> * apts,
+				    const Vec<3> & anormal)
+{
+  pts[0] = apts[0];
+  pts[1] = apts[1];
+  pts[2] = apts[2]; 
+  normal = anormal;
+}
+
+
+
+STLTriangle :: STLTriangle(const int * apts)
+{
+  pts[0] = apts[0];
+  pts[1] = apts[1];
+  pts[2] = apts[2];
+
+  facenum = 0;
+}
+
+int STLTriangle :: IsNeighbourFrom(const STLTriangle& t) const
+{
+  //triangles must have same orientation!!!
+  int i, j;
+  for(i = 0; i <= 2; i++)
+    {
+      for(j = 0; j <= 2; j++)
+	{
+	  if (t.pts[(i+1)%3] == pts[j] &&
+	      t.pts[i] == pts[(j+1)%3])
+	    {return 1;}
+	}
+    }
+  return 0;      
+}
+
+int STLTriangle :: IsWrongNeighbourFrom(const STLTriangle& t) const
+{
+  //triangles have not same orientation!!!
+  int i, j;
+  for(i = 0; i <= 2; i++)
+    {
+      for(j = 0; j <= 2; j++)
+	{
+	  if (t.pts[(i+1)%3] == pts[(j+1)%3] &&
+	      t.pts[i] == pts[j])
+	    {return 1;}
+	}
+    }
+  return 0;      
+}
+
+void STLTriangle :: GetNeighbourPoints(const STLTriangle& t, int& p1, int& p2) const
+{
+  int i, j;
+  for(i = 1; i <= 3; i++)
+    {
+      for(j = 1; j <= 3; j++)
+	{
+	  if (t.PNumMod(i+1) == PNumMod(j) &&
+	      t.PNumMod(i) == PNumMod(j+1))
+	    {p1 = PNumMod(j); p2 = PNumMod(j+1); return;}
+	}
+    }
+  PrintSysError("Get neighbourpoints failed!");
+}
+
+int STLTriangle :: GetNeighbourPointsAndOpposite(const STLTriangle& t, int& p1, int& p2, int& po) const
+{
+  int i, j;
+  for(i = 1; i <= 3; i++)
+    {
+      for(j = 1; j <= 3; j++)
+	{
+	  if (t.PNumMod(i+1) == PNumMod(j) &&
+	      t.PNumMod(i) == PNumMod(j+1))
+	    {p1 = PNumMod(j); p2 = PNumMod(j+1); po = PNumMod(j+2); return 1;}
+	}
+    }
+  return 0;
+}
+
+Vec<3> STLTriangle :: GeomNormal(const ARRAY<Point<3> >& ap) const
+{
+  const Point<3> & p1 = ap.Get(PNum(1));
+  const Point<3> & p2 = ap.Get(PNum(2));
+  const Point<3> & p3 = ap.Get(PNum(3));
+  
+  return Cross(p2-p1, p3-p1);
+}
+
+
+void STLTriangle :: SetNormal (const Vec<3> & n)
+{
+  double len = n.Length();
+  if (len > 0)
+    {
+      normal = n;
+      normal.Normalize();
+    }
+  else
+    {
+      normal = Vec<3> (1, 0, 0);
+    }
+}
+
+
+void STLTriangle :: ChangeOrientation()
+{ 
+  normal *= -1;
+  Swap(pts[0],pts[1]); 
+}
+
+
+
+double STLTriangle :: Area(const ARRAY<Point<3> >& ap) const
+{
+  return 0.5 * Cross(ap.Get(PNum(2))-ap.Get(PNum(1)), 
+		     ap.Get(PNum(3))-ap.Get(PNum(1))).Length();
+}
+
+double STLTriangle :: MinHeight(const ARRAY<Point<3> >& ap) const
+{
+  double ml = MaxLength(ap);
+  if (ml != 0) {return 2.*Area(ap)/ml;}
+  PrintWarning("max Side Length of a triangle = 0!!!");
+  return 0;
+}
+
+double STLTriangle :: MaxLength(const ARRAY<Point<3> >& ap) const
+{
+  return max3(Dist(ap.Get(PNum(1)),ap.Get(PNum(2))),
+	      Dist(ap.Get(PNum(2)),ap.Get(PNum(3))),
+	      Dist(ap.Get(PNum(3)),ap.Get(PNum(1))));
+}
+
+void STLTriangle :: ProjectInPlain(const ARRAY<Point<3> >& ap, 
+				   const Vec<3> & n, Point<3> & pp) const
+{
+  const Point<3> & p1 = ap.Get(PNum(1));
+  const Point<3> & p2 = ap.Get(PNum(2));
+  const Point<3> & p3 = ap.Get(PNum(3));
+  
+  Vec<3> v1 = p2 - p1;
+  Vec<3> v2 = p3 - p1;
+  Vec<3> nt = Cross(v1, v2);
+
+  double c = - (p1(0)*nt(0) + p1(1)*nt(1) + p1(2)*nt(2));
+
+  double prod = n * nt;  
+
+  if (fabs(prod) == 0) 
+    {
+      pp = Point<3>(1.E20,1.E20,1.E20); 
+      return; 
+    }
+
+  double nfact = -(pp(0)*nt(0) + pp(1)*nt(1) + pp(2)*nt(2) + c) / (prod);
+  pp = pp + (nfact) * n;
+
+}
+
+
+int STLTriangle :: ProjectInPlain (const ARRAY<Point<3> >& ap, 
+				   const Vec<3> & nproj, 
+				   Point<3> & pp, Vec<3> & lam) const
+{
+  const Point<3> & p1 = ap.Get(PNum(1));
+  const Point<3> & p2 = ap.Get(PNum(2));
+  const Point<3> & p3 = ap.Get(PNum(3));
+  
+  Vec<3> v1 = p2-p1;
+  Vec<3> v2 = p3-p1;
+
+  Mat<3> mat;
+  for (int i = 0; i < 3; i++)
+    {
+      mat(i,0) = v1(i);
+      mat(i,1) = v2(i);
+      mat(i,2) = nproj(i);
+    }
+
+  int err = 0;
+  mat.Solve (pp-p1, lam);
+  //  int err = SolveLinearSystem (v1, v2, nproj, pp-p1, lam);
+
+  if (!err)
+    {
+      //      pp = p1 + lam(0) * v1 + lam(1) * v2;
+
+      pp(0) = p1(0) + lam(0) * v1(0) + lam(1) * v2(0);
+      pp(1) = p1(1) + lam(0) * v1(1) + lam(1) * v2(1);
+      pp(2) = p1(2) + lam(0) * v1(2) + lam(1) * v2(2);
+    }
+  return err;
+}
+
+
+
+
+
+void STLTriangle :: ProjectInPlain(const ARRAY<Point<3> >& ap, 
+				   Point<3> & pp) const
+{
+  const Point<3> & p1 = ap.Get(PNum(1));
+  const Point<3> & p2 = ap.Get(PNum(2));
+  const Point<3> & p3 = ap.Get(PNum(3));
+  
+  Vec<3> v1 = p2 - p1;
+  Vec<3> v2 = p3 - p1;
+  Vec<3> nt = Cross(v1, v2);
+
+  double c = - (p1(0)*nt(0) + p1(1)*nt(1) + p1(2)*nt(2));
+  
+  double prod = nt * nt;  
+
+  double nfact = -(pp(0)*nt(0) + pp(1)*nt(1) + pp(2)*nt(2) + c) / (prod);
+
+  pp = pp + (nfact) * nt;
+}
+
+int STLTriangle :: PointInside(const ARRAY<Point<3> > & ap, 
+			       const Point<3> & pp) const
+{
+  const Point<3> & p1 = ap.Get(PNum(1));
+  const Point<3> & p2 = ap.Get(PNum(2));
+  const Point<3> & p3 = ap.Get(PNum(3));
+  
+  Vec<3> v1 = p2 - p1;
+  Vec<3> v2 = p3 - p1;
+  Vec<3> v  = pp - p1;
+  double det, l1, l2;
+  Vec<3> ex, ey, ez;
+
+
+  ez = GeomNormal(ap);
+  ez /= ez.Length();
+  ex = v1;
+  ex /= ex.Length();
+  ey = Cross (ez, ex);
+  
+  Vec<2> v1p(v1*ex, v1*ey);
+  Vec<2> v2p(v2*ex, v2*ey);
+  Vec<2> vp(v*ex, v*ey);
+
+  det = v2p(1) * v1p(0) - v2p(0) * v1p(1);
+
+  if (fabs(det) == 0) {return 0;}
+  
+  l2 = (vp(1) * v1p(0) - vp(0) * v1p(1)) / det;
+  
+  if (v1p(0) != 0.)
+    {
+      l1 = (vp(0) - l2 * v2p(0)) / v1p(0);
+    }
+  else if (v1p(1) != 0.)
+    {
+      l1 = (vp(1) - l2 * v2p(1)) / v1p(1);
+    }
+  else {return 0;}
+  
+  if (l1 >= -1E-10 && l2 >= -1E-10 && l1 + l2 <= 1.+1E-10) {return 1;}
+  return 0; 
+}
+
+double STLTriangle :: GetNearestPoint(const ARRAY<Point<3> >& ap, 
+				      Point<3> & p3d) const
+{
+  Point<3> p = p3d;
+  ProjectInPlain(ap, p);
+  double dist = (p - p3d).Length();
+
+  if (PointInside(ap, p)) {p3d = p; return dist;}
+  else
+    {
+      Point<3> pf;
+      double nearest = 1E50;
+      int fi = 0;
+      int j;
+      
+      for (j = 1; j <= 3; j++)
+	{
+	  p = p3d;
+	  dist = GetDistFromLine(ap.Get(PNum(j)), ap.Get(PNumMod(j+1)), p);
+	  if (dist < nearest)
+	    {
+	      nearest = dist; 
+	      pf = p;
+	    }
+	}
+      p3d = pf;
+      return nearest;
+    }
+}
+
+int STLTriangle :: HasEdge(int p1, int p2) const
+{
+  int i;
+  for (i = 1; i <= 3; i++)
+    {
+      if (p1 == PNum(i) && p2 == PNumMod(i+1)) {return 1;}
+    }
+  return 0;
+}
+
+ostream& operator<<(ostream& os, const STLTriangle& t)
+{
+  os << "[";
+  os << t[0] << ",";
+  os << t[1] << ",";
+  os << t[2] << "]";
+
+  return os;
+};
+
+
+
+STLTopEdge :: STLTopEdge ()
+{
+  pts[0] = pts[1] = 0;
+  trigs[0] = trigs[1] = 0;
+  cosangle = 1;
+  status = ED_UNDEFINED;
+}
+
+STLTopEdge :: STLTopEdge (int p1, int p2, int trig1, int trig2)
+{ 
+  pts[0] = p1; 
+  pts[1] = p2; 
+  trigs[0] = trig1; 
+  trigs[1] = trig2; 
+  cosangle = 1;
+  status = ED_UNDEFINED;
+}
+
+
+
+
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//+++++++++++++++++++   STL CHART   +++++++++++++++++++++++++++++++
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+STLChart :: STLChart(STLGeometry * ageometry)
+{
+  charttrigs = new ARRAY<int> (0,0);
+  outertrigs = new ARRAY<int> (0,0);
+  ilimit = new ARRAY<twoint> (0,0);
+  olimit = new ARRAY<twoint> (0,0);
+
+  geometry = ageometry;
+
+  if ( (stlparam.usesearchtree == 1))
+    searchtree = new Box3dTree (geometry->GetBoundingBox().PMin() - Vec3d(1,1,1),
+				geometry->GetBoundingBox().PMax() + Vec3d(1,1,1));
+  else
+    searchtree = NULL;
+}
+
+void STLChart :: AddChartTrig(int i)
+{
+  charttrigs->Append(i);
+  
+  const STLTriangle & trig = geometry->GetTriangle(i);
+  const Point3d & p1 = geometry->GetPoint (trig.PNum(1));
+  const Point3d & p2 = geometry->GetPoint (trig.PNum(2));
+  const Point3d & p3 = geometry->GetPoint (trig.PNum(3));
+
+  Point3d pmin(p1), pmax(p1);
+  pmin.SetToMin (p2);
+  pmin.SetToMin (p3);
+  pmax.SetToMax (p2);
+  pmax.SetToMax (p3);
+  
+  if (!geomsearchtreeon && (stlparam.usesearchtree == 1))
+    {searchtree->Insert (pmin, pmax, i);}
+}
+
+void STLChart :: AddOuterTrig(int i)
+{
+  outertrigs->Append(i);
+
+  const STLTriangle & trig = geometry->GetTriangle(i);
+  const Point3d & p1 = geometry->GetPoint (trig.PNum(1));
+  const Point3d & p2 = geometry->GetPoint (trig.PNum(2));
+  const Point3d & p3 = geometry->GetPoint (trig.PNum(3));
+
+  Point3d pmin(p1), pmax(p1);
+  pmin.SetToMin (p2);
+  pmin.SetToMin (p3);
+  pmax.SetToMax (p2);
+  pmax.SetToMax (p3);
+  
+  if (!geomsearchtreeon && (stlparam.usesearchtree==1))
+    {searchtree->Insert (pmin, pmax, i);}
+}
+
+int STLChart :: IsInWholeChart(int nr) const
+{
+  int i;
+  for (i = 1; i <= charttrigs->Size(); i++)
+    {
+      if (charttrigs->Get(i) == nr) {return 1;}
+    }
+  for (i = 1; i <= outertrigs->Size(); i++)
+    {
+      if (outertrigs->Get(i) == nr) {return 1;}
+    }
+  return 0;
+}
+
+void STLChart :: GetTrianglesInBox (const Point3d & pmin,
+				    const Point3d & pmax,
+				    ARRAY<int> & trias) const
+{
+  if (geomsearchtreeon) {PrintMessage(5,"geomsearchtreeon is set!!!");}
+
+  if (searchtree)
+    searchtree -> GetIntersecting (pmin, pmax, trias);
+  else
+    {
+      int i;
+      Box3d box1(pmin, pmax);
+      box1.Increase (1e-4);
+      Box3d box2;
+
+      trias.SetSize(0);
+      
+      int nt = GetNT();
+      for (i = 1; i <= nt; i++)
+	{
+
+	  int trignum = GetTrig(i);
+	  const STLTriangle & trig = geometry->GetTriangle(trignum);
+	  box2.SetPoint (geometry->GetPoint (trig.PNum(1)));
+	  box2.AddPoint (geometry->GetPoint (trig.PNum(2)));
+	  box2.AddPoint (geometry->GetPoint (trig.PNum(3)));
+	  
+	  if (box1.Intersect (box2))
+	    {
+	      trias.Append (trignum);
+	    }
+	}
+    }
+}
+
+//trigs may contain the same triangle double
+void STLChart :: MoveToOuterChart(const ARRAY<int>& trigs)
+{
+  if (!trigs.Size()) {return;}
+  int i;
+  for (i = 1; i <= trigs.Size(); i++)
+    {
+      if (charttrigs->Get(trigs.Get(i)) != -1) 
+	{AddOuterTrig(charttrigs->Get(trigs.Get(i)));}
+      charttrigs->Elem(trigs.Get(i)) = -1;
+    }
+  DelChartTrigs(trigs);
+}
+
+//trigs may contain the same triangle double
+void STLChart :: DelChartTrigs(const ARRAY<int>& trigs)
+{
+  if (!trigs.Size()) {return;}
+
+  int i;
+  for (i = 1; i <= trigs.Size(); i++)
+    {
+      charttrigs->Elem(trigs.Get(i)) = -1;
+    }
+
+  int cnt = 0;
+  for (i = 1; i <= charttrigs->Size(); i++)
+    {
+      if (charttrigs->Elem(i) == -1)
+	{
+	  cnt++;
+	}
+      if (cnt != 0 && i < charttrigs->Size())
+	{
+	  charttrigs->Elem(i-cnt+1) = charttrigs->Get(i+1);
+	}
+    }
+  i = charttrigs->Size() - trigs.Size();
+  charttrigs->SetSize(i);
+
+  if (!geomsearchtreeon && stlparam.usesearchtree == 1)
+    {
+      PrintMessage(7, "Warning: unsecure routine due to first use of searchtrees!!!");
+      //bould new searchtree!!!
+      searchtree = new Box3dTree (geometry->GetBoundingBox().PMin() - Vec3d(1,1,1),
+				  geometry->GetBoundingBox().PMax() + Vec3d(1,1,1));
+
+      for (i = 1; i <= charttrigs->Size(); i++)
+	{
+	  const STLTriangle & trig = geometry->GetTriangle(i);
+	  const Point3d & p1 = geometry->GetPoint (trig.PNum(1));
+	  const Point3d & p2 = geometry->GetPoint (trig.PNum(2));
+	  const Point3d & p3 = geometry->GetPoint (trig.PNum(3));
+	  
+	  Point3d pmin(p1), pmax(p1);
+	  pmin.SetToMin (p2);
+	  pmin.SetToMin (p3);
+	  pmax.SetToMax (p2);
+	  pmax.SetToMax (p3);
+	  
+	  searchtree->Insert (pmin, pmax, i);	  
+	}
+    }
+}
+
+
+void STLChart :: SetNormal (const Point<3> & apref, const Vec<3> & anormal)
+{
+  pref = apref;
+  normal = anormal;
+  double len = normal.Length();
+  if (len) normal /= len;
+  else normal = Vec<3> (1, 0, 0);
+
+  t1 = normal.GetNormal ();
+  t2 = Cross (normal, t1);
+}
+
+Point<2> STLChart :: Project2d (const Point<3> & p3d) const
+{
+  Vec<3> v = p3d-pref;
+  return Point<2> (t1 * v, t2 * v);
+}
+
+
+
+/*
+  Point3d p1, p2, center;
+  double rad;
+  int i1, i2;
+public:
+*/
+STLBoundarySeg :: 
+STLBoundarySeg (int ai1, int ai2, const ARRAY<Point<3> > & points,
+		const STLChart * chart)
+{
+  i1 = ai1;
+  i2 = ai2; 
+  p1 = points.Get(i1);
+  p2 = points.Get(i2);
+  center = ::netgen::Center (p1, p2);
+  rad = Dist (p1, center);
+
+  p2d1 = chart->Project2d (p1);
+  p2d2 = chart->Project2d (p2);
+  
+  boundingbox.Set (p2d1);
+  boundingbox.Add (p2d2);
+}
+
+void STLBoundarySeg :: Swap ()
+{
+  ::netgen::Swap (i1, i2);
+  ::netgen::Swap (p1, p2);
+}
+
+
+
+STLBoundary :: STLBoundary (STLGeometry * ageometry)
+  : boundary(), geometry(ageometry)
+{
+  ;
+}
+
+
+void STLBoundary :: AddOrDelSegment(const STLBoundarySeg & seg)
+{
+  int i;
+  int found = 0;
+  for (i = 1; i <= boundary.Size(); i++)
+    {
+      if (found) {boundary.Elem(i-1) = boundary.Get(i);}
+      if (boundary.Get(i) == seg) {found = 1;}
+    }
+  if (!found) 
+    {
+      boundary.Append(seg);
+    }
+  else 
+    {
+      boundary.SetSize(boundary.Size()-1);
+    }
+}
+
+void STLBoundary ::AddTriangle(const STLTriangle & t)
+{
+  int i;
+  int found1 = 0;
+  int found2 = 0;
+  int found3 = 0;
+  int offset = 0;
+  
+
+  STLBoundarySeg seg1(t[0],t[1], geometry->GetPoints(), chart);
+  STLBoundarySeg seg2(t[1],t[2], geometry->GetPoints(), chart);
+  STLBoundarySeg seg3(t[2],t[0], geometry->GetPoints(), chart);
+
+  seg1.SetSmoothEdge (geometry->IsSmoothEdge (seg1.I1(), seg1.I2()));
+  seg2.SetSmoothEdge (geometry->IsSmoothEdge (seg2.I1(), seg2.I2()));
+  seg3.SetSmoothEdge (geometry->IsSmoothEdge (seg3.I1(), seg3.I2()));
+
+  /*
+  for (i = 1; i <= boundary.Size(); i++)
+    {
+      if (offset) {boundary.Elem(i-offset) = boundary.Get(i);}
+      if (boundary.Get(i) == seg1) {found1 = 1; offset++;}
+      if (boundary.Get(i) == seg2) {found2 = 1; offset++;}
+      if (boundary.Get(i) == seg3) {found3 = 1; offset++;}
+    }
+
+  if (offset)
+    {
+      boundary.SetSize(boundary.Size()-offset);
+    }    
+  */
+  for (i = boundary.Size(); i >= 1; i--)
+    {
+      if (boundary.Get(i) == seg1) 
+	{ boundary.DeleteElement (i); found1 = 1; } 
+      else if (boundary.Get(i) == seg2) 
+	{ boundary.DeleteElement (i); found2 = 1; } 
+      else if (boundary.Get(i) == seg3) 
+	{ boundary.DeleteElement (i); found3 = 1; } 
+    }
+
+  if (!found1) {seg1.Swap(); boundary.Append(seg1);}
+  if (!found2) {seg2.Swap(); boundary.Append(seg2);}
+  if (!found3) {seg3.Swap(); boundary.Append(seg3);}
+}
+
+int STLBoundary :: TestSeg(const Point<3>& p1, const Point<3> & p2, const Vec<3> & sn, 
+			   double sinchartangle, int divisions, ARRAY<Point<3> >& points, double eps)
+{
+
+  if (usechartnormal)
+    return TestSegChartNV (p1, p2, sn);
+
+  // for statistics
+  {
+    int i;
+    static ARRAY<int> cntclass;
+    static int cnt = 0;
+    static int cnti = 0, cnto = 0;
+    static long int cntsegs = 0;
+    if (cntclass.Size() == 0)
+      {
+	cntclass.SetSize (20);
+	for (i = 1; i <= cntclass.Size(); i++)
+	  cntclass.Elem(i) = 0;
+      }
+    
+    cntsegs += NOSegments();
+    int cla = int (log (double(NOSegments()+1)) / log(2.0));
+    if (cla < 1) cla = 1;
+    if (cla > cntclass.Size()) cla = cntclass.Size();
+    cntclass.Elem(cla)++;
+    cnt++;
+    if (divisions)
+      cnti++;
+    else
+      cnto++;
+    if (cnt > 100000) 
+      {
+	cnt = 0;
+	/*
+	(*testout) << "TestSeg-calls for classes:" << endl;
+	(*testout) << cnti << " inner calls, " << cnto << " outercalls" << endl;
+	(*testout) << "total testes segments: " << cntsegs << endl;
+	for (i = 1; i <= cntclass.Size(); i++)
+	  {
+	    (*testout) << int (exp (i * log(2.0))) << " bnd segs: " << cntclass.Get(i) << endl;
+	  }
+	*/
+      }
+  }
+
+
+  int i,j,k;
+  Point<3> seg1p/*, seg2p*/;
+  Point<3> sp1,sp2;
+  double lambda1, lambda2, vlen2;
+  Vec<3> vptpl;
+  double sinchartangle2 = sqr(sinchartangle);
+  double scal;
+  int possible;
+
+  double maxval = -1;
+  double maxvalnew = -1;
+
+
+
+  double scalp1 = p1(0) * sn(0) + p1(1) * sn(1) + p1(2) * sn(2);
+  double scalp2 = p2(0) * sn(0) + p2(1) * sn(1) + p2(2) * sn(2);
+  double minl = min2(scalp1, scalp2);
+  double maxl = max2(scalp1, scalp2);
+  Point<3> c = Center (p1, p2);
+  double dist1 = Dist (c, p1);
+ 
+  int nseg = NOSegments();
+  for (j = 1; j <= nseg; j++)
+    {
+      const STLBoundarySeg & seg = GetSegment(j);
+
+
+      if (seg.IsSmoothEdge())
+	continue;
+
+
+      sp1 = seg.P1();
+      sp2 = seg.P2();
+
+      // Test, ob Spiral Konfikt moeglich
+      
+      possible = 1;
+
+      double scalsp1 = sp1(0) * sn(0) + sp1(1) * sn(1) + sp1(2) * sn(2);
+      double scalsp2 = sp2(0) * sn(0) + sp2(1) * sn(1) + sp2(2) * sn(2);
+
+      double minsl = min2(scalsp1, scalsp2);
+      double maxsl = max2(scalsp1, scalsp2);
+      
+      double maxdiff = max2 (maxsl - minl, maxl - minsl);
+      
+      /*
+      Point3d sc = Center (sp1, sp2);
+      double mindist = Dist(c, sc) - dist1 - GetSegment(j).Radius();
+      if (maxdiff < sinchartangle * mindist)
+	{
+	  possible = 0;
+	}
+      */
+       
+      double hscal = maxdiff + sinchartangle * (dist1 + seg.Radius());
+      if (hscal * hscal < sinchartangle * Dist2(c, seg.center ))
+	possible = 0;
+
+
+      /*      
+      if (possible)
+	{
+	  double mindist2ex = MinDistLL2 (p1, p2, sp1, sp2);
+	  if (maxdiff * maxdiff < sinchartangle2 * mindist2ex)
+	    possible = 0;
+	}
+      */
+
+      if (possible)
+      	{
+	  LinearPolynomial2V lp (scalp1 - scalsp1,
+				 scalp2 - scalp1,
+				 -(scalsp2 - scalsp1));
+	  QuadraticPolynomial2V slp;
+	  slp.Square (lp);
+	  
+      
+	  Vec3d v (p1, sp1);
+	  Vec3d vl (p1, p2);
+	  Vec3d vsl (sp1, sp2);
+      
+	  QuadraticPolynomial2V qp (v.Length2(),
+				    -2 * (v * vl),
+				    2 * (v * vsl),
+				    vl.Length2(),
+				    -2 * (vl * vsl),
+				    vsl.Length2());
+	  
+	  slp.Add (-sinchartangle2, qp);
+
+	  double hv = slp.MaxUnitSquare();
+
+	  if (hv > eps) return 0;
+	  /*
+	  if (hv > maxvalnew)
+	    maxvalnew = hv;
+	  */
+	}
+      
+
+      if (possible && 0)
+
+	for (i = 0; i <= divisions; i++)
+	  {
+	    
+	    lambda1 = (double)i/(double)divisions;
+	    seg1p = Point3d(p1(0)*lambda1+p2(0)*(1.-lambda1),
+			    p1(1)*lambda1+p2(1)*(1.-lambda1),
+			    p1(2)*lambda1+p2(2)*(1.-lambda1));
+	    
+
+	    
+	    for (k = 0; k <= divisions; k++)
+	      {
+		lambda2 = (double)k/(double)divisions;
+		vptpl = Vec3d(sp1(0)*lambda2+sp2(0)*(1.-lambda2)-seg1p(0),
+			      sp1(1)*lambda2+sp2(1)*(1.-lambda2)-seg1p(1),
+			      sp1(2)*lambda2+sp2(2)*(1.-lambda2)-seg1p(2));
+		
+		vlen2 = vptpl.Length2();
+
+		//		if (vlen2 > 0)
+		  {
+		    scal = vptpl * sn;
+		    double hv = scal*scal - sinchartangle2*vlen2;
+
+
+
+		    /*
+		    if (hv > maxval)
+		      maxval = hv;
+		    */
+		    if (hv > eps) return 0;
+		  }
+	      } 
+	  }
+    }
+  
+  return 1;
+  //  return (maxvalnew < eps);
+}
+
+
+
+// checks, whether 2d projection intersects
+int STLBoundary :: TestSegChartNV(const Point3d & p1, const Point3d& p2, 
+				  const Vec3d& sn)
+{
+  int i, j;
+  int nseg = NOSegments();
+
+  Point<2> p2d1 = chart->Project2d (p1);
+  Point<2> p2d2 = chart->Project2d (p2);
+
+  Box<2> box2d;
+  box2d.Set (p2d1);
+  box2d.Add (p2d2);
+  /*
+  Point2d pmin(p2d1);
+  pmin.SetToMin (p2d2);
+  Point2d pmax(p2d1);
+  pmax.SetToMax (p2d2);
+  */
+
+  Line2d l1 (p2d1, p2d2);
+
+  double lam1, lam2;
+  double eps = 1e-3;
+  
+  for (j = 1; j <= nseg; j++)
+    {
+      const STLBoundarySeg & seg = GetSegment(j);
+
+      if (!box2d.Intersect (seg.BoundingBox()))
+	continue;
+      /*
+      if (seg.P2DMin()(0) > pmax(0)) continue;
+      if (seg.P2DMin()(1) > pmax(1)) continue;
+      if (seg.P2DMax()(0) < pmin(0)) continue;
+      if (seg.P2DMax()(1) < pmin(1)) continue;
+      */
+
+      if (seg.IsSmoothEdge()) continue;
+
+      const Point<2> & sp1 = seg.P2D1();
+      const Point<2> & sp2 = seg.P2D2();
+      
+
+      Line2d l2 (sp1, sp2);
+      
+      int err =
+	CrossPointBarycentric (l1, l2, lam1, lam2);
+      /*
+      if (chartdebug)
+	{
+	  
+	  (*testout) << "lam1 = " << lam1 << ", lam2 = " << lam2 << endl;
+	  (*testout) << "p2d = " << p2d1 << ", " << p2d2 << endl;
+	  (*testout) << "sp2d = " << sp1 << ", " << sp2 << endl;
+	  (*testout) << "i1,2 = " << seg.I1() << ", " << seg.I2() << endl;
+	  
+	}
+      */
+      if (!err && lam1 > eps && lam1 < 1-eps &&
+	  lam2 > eps && lam2 < 1-eps)
+	return 0;
+    }
+  return 1;
+}
+
+
+
+STLDoctorParams :: STLDoctorParams()
+{
+  drawmeshededges = 1;
+  geom_tol_fact = 1E-6;
+  longlinefact = 0;
+  showexcluded = 1;
+
+  selectmode = 0;
+  edgeselectmode = 0;
+  useexternaledges = 0;
+  showfaces = 0;
+  showtouchedtrigchart = 1;
+  showedgecornerpoints = 1;
+  conecheck = 1;
+  spiralcheck = 1;
+  selecttrig = 0;
+  nodeofseltrig = 1;
+  selectwithmouse = 1;
+  showmarkedtrigs = 1;
+  dirtytrigfact = 0.001;
+  smoothangle = 90;
+  smoothnormalsweight = 0.2;
+  vicinity = 0;
+  showvicinity = 0;
+}
+
+
+
+STLDoctorParams stldoctor;
+
+void STLDoctorParams :: Print (ostream & ost) const
+{
+  ost << "STL doctor parameters:" << endl
+      << "selecttrig = " << selecttrig << endl
+      << "selectlocalpoint = " << nodeofseltrig << endl
+      << "selectwithmouse = " << selectwithmouse << endl
+      << "showmarkedtrigs = " << showmarkedtrigs << endl
+      << "dirtytrigfact = " << dirtytrigfact << endl
+      << "smoothangle = " << smoothangle << endl;
+}
+
+
+STLParameters ::   STLParameters()
+{
+  yangle = 30;
+  contyangle = 20;
+  edgecornerangle = 60;
+  chartangle = 15;
+  outerchartangle = 70;
+     
+  usesearchtree = 0;
+  atlasminh = 1E-4;
+  resthsurfcurvfac = 2;
+  resthsurfcurvenable = 0;
+  resthatlasfac = 2;
+  resthatlasenable = 1;
+  resthchartdistfac = 1.2;
+  resthchartdistenable = 1;
+  resthlinelengthfac = 0.5;
+  resthlinelengthenable = 1;
+  resthcloseedgefac = 1;
+  resthcloseedgeenable = 1;
+  resthedgeanglefac = 1;
+  resthedgeangleenable = 0;
+  resthsurfmeshcurvfac = 1;
+  resthsurfmeshcurvenable = 0;
+  recalc_h_opt = 1;
+}
+
+void STLParameters :: Print (ostream & ost) const
+{
+  ost << "STL parameters:" << endl
+      << "yellow angle = " << yangle << endl
+      << "continued yellow angle = " << contyangle << endl
+      << "edgecornerangle = " << edgecornerangle << endl
+      << "chartangle = " << chartangle << endl
+      << "outerchartangle = " << outerchartangle << endl
+      << "restrict h due to ..., enable and safety factor: " << endl
+      << "surface curvature: " << resthsurfcurvenable
+      << ", fac = " << resthsurfcurvfac << endl
+      << "atlas surface curvature: " << resthatlasenable
+      << ", fac = " << resthatlasfac << endl
+      << "chart distance: " << resthchartdistenable
+      << ", fac = " << resthchartdistfac << endl
+      << "line length: " << resthlinelengthenable
+      << ", fac = " << resthlinelengthfac << endl
+      << "close edges: " << resthcloseedgeenable
+      << ", fac = " << resthcloseedgefac << endl
+      << "edge angle: " << resthedgeangleenable
+      << ", fac = " << resthedgeanglefac << endl;
+}
+
+
+STLParameters stlparam;
+
+
+}
diff --git a/Netgen/libsrc/stlgeom/stltool.hpp b/Netgen/libsrc/stlgeom/stltool.hpp
new file mode 100644
index 0000000000..278a7ce4ee
--- /dev/null
+++ b/Netgen/libsrc/stlgeom/stltool.hpp
@@ -0,0 +1,271 @@
+#ifndef FILE_STLTOOL
+#define FILE_STLTOOL
+
+
+//#include "gprim/gprim.hh"
+
+/**************************************************************************/
+/* File:   stlgeom.hh                                                     */
+/* Author: Joachim Schoeberl                                              */
+/* Author2: Johannes Gerstmayr                                            */
+/* Date:   20. Nov. 99                                                    */
+/**************************************************************************/
+
+
+
+// use one normal vector for whole chart
+extern int usechartnormal;
+extern int chartdebug;
+
+extern int geomsearchtreeon;
+extern int AddPointIfNotExists(ARRAY<Point3d>& ap, const Point3d& p, double eps = 1e-8);
+//get distance from line lp1-lp2 to point p
+extern double GetDistFromLine(const Point<3>& lp1, const Point<3>& lp2, Point<3>& p);
+extern double GetDistFromInfiniteLine(const Point<3>& lp1, const Point<3>& lp2, const Point<3>& p);
+
+
+extern void FIOReadInt(istream& ios, int& i);
+extern void FIOWriteInt(ostream& ios, const int& i);
+extern void FIOReadDouble(istream& ios, double& i);
+extern void FIOWriteDouble(ostream& ios, const double& i);
+extern void FIOReadFloat(istream& ios, float& i);
+extern void FIOWriteFloat(ostream& ios, const float& i);
+extern void FIOReadString(istream& ios, char* str, int len);
+extern void FIOReadStringE(istream& ios, char* str, int len);
+extern void FIOWriteString(ostream& ios, char* str, int len);
+
+
+typedef ARRAY <int> * ARRAYINTPTR;
+
+class STLGeometry;
+
+class STLChart
+{
+private:
+  STLGeometry * geometry;
+  ARRAY<int>* charttrigs; // trigs which only belong to this chart
+  ARRAY<int>* outertrigs; // trigs which belong to other charts
+  Box3dTree * searchtree; // ADT containing outer trigs
+
+  ARRAY<twoint>* olimit; //outer limit of outer chart
+  ARRAY<twoint>* ilimit; //outer limit of inner chart
+
+
+public:
+  
+  STLChart(STLGeometry * ageometry);
+  void AddChartTrig(int i);
+  void AddOuterTrig(int i);
+  
+  int IsInWholeChart(int nr) const;
+
+  int GetChartTrig(int i) const {return charttrigs->Get(i);}
+  int GetOuterTrig(int i) const {return outertrigs->Get(i);}
+  //get all trigs:
+  int GetTrig(int i) const
+    {
+      if (i <= charttrigs->Size()) {return charttrigs->Get(i);}
+      else {return outertrigs->Get(i-charttrigs->Size());}
+    }
+  
+  int GetNChartT() const {return charttrigs->Size();}
+  int GetNOuterT() const {return outertrigs->Size();}
+  int GetNT() const {return charttrigs->Size()+outertrigs->Size(); }
+
+  void GetTrianglesInBox (const Point3d & pmin,
+			  const Point3d & pmax,
+			  ARRAY<int> & trias) const;
+  void AddOLimit(twoint l) {olimit->Append(l);}
+  void AddILimit(twoint l) {ilimit->Append(l);}
+
+  void ClearOLimit() {olimit->SetSize(0);}
+  void ClearILimit() {ilimit->SetSize(0);}
+
+  int GetNOLimit() const {return olimit->Size();}
+  int GetNILimit() const {return ilimit->Size();}
+
+  twoint GetOLimit(int i) const {return olimit->Get(i);}
+  twoint GetILimit(int i) const {return ilimit->Get(i);}
+
+  //move triangles trigs (local chart-trig numbers) to outer chart
+  void MoveToOuterChart(const ARRAY<int>& trigs);
+  void DelChartTrigs(const ARRAY<int>& trigs);
+
+
+  // define local coordinate system, JS:
+private:
+  Vec<3> normal;
+  Point<3> pref;
+  Vec<3> t1, t2;
+public:
+  void SetNormal (const Point<3> & apref, const Vec<3> & anormal);
+  const Vec<3> & GetNormal () const { return normal; }
+  Point<2> Project2d (const Point<3> & p3d) const;
+};
+
+class STLBoundarySeg
+{
+  Point<3> p1, p2, center;
+  Point<2> p2d1, p2d2;
+  Box<2> boundingbox;
+  //  Point<2> p2dmin, p2dmax;
+
+  double rad;
+  int i1, i2;
+  int smoothedge;
+public:
+  STLBoundarySeg () { ; }
+  STLBoundarySeg (int ai1, int ai2, const ARRAY<Point<3> > & points,
+		  const STLChart * achart);
+
+  int operator== (const STLBoundarySeg & s2) const
+    { return i1 == s2.i1 && i2 == s2.i2; }
+  void Swap ();
+  int I1() const { return i1; }
+  int I2() const { return i2; }
+  const Point<3> & P1() const { return p1; }
+  const Point<3> & P2() const { return p2; }
+  const Point<2> & P2D1() const { return p2d1; }
+  const Point<2> & P2D2() const { return p2d2; }
+  const Point<2> & P2DMin() const { return boundingbox.PMin(); }
+  const Point<2> & P2DMax() const { return boundingbox.PMax(); }
+  const Point<3> & Center() const { return center; }
+  const Box<2> & BoundingBox() const { return boundingbox; }
+  double Radius () const { return rad; }
+
+  void SetSmoothEdge (int se) { smoothedge = se; }
+  int IsSmoothEdge () const { return smoothedge; }
+  friend class STLBoundary;
+};
+
+class STLBoundary
+{
+private:
+  STLGeometry * geometry;
+  const STLChart * chart;
+  ARRAY<STLBoundarySeg> boundary;
+public:
+  STLBoundary(STLGeometry * ageometry);
+  // : boundary() {};
+
+  void Clear() {boundary.SetSize(0);};
+  void SetChart (const STLChart * achart) { chart = achart; }
+  //don't check, if already exists!
+  void AddNewSegment(const STLBoundarySeg & seg) {boundary.Append(seg);};
+  //check if segment exists
+  void AddOrDelSegment(const STLBoundarySeg & seg);
+  //addordelsegment for all 3 triangle segments!
+  void AddTriangle(const STLTriangle & t);
+  int NOSegments() {return boundary.Size();};
+  const STLBoundarySeg & GetSegment(int i) {return boundary.Get(i);}
+
+  int TestSeg(const Point<3> & p1, const Point<3> & p2, const Vec<3> & sn, 
+	      double sinchartangle, int divisions, ARRAY<Point<3> >& points,
+	      double eps);
+
+  int TestSegChartNV(const Point3d& p1, const Point3d& p2, const Vec3d& sn);
+};
+
+
+class STLDoctorParams
+{
+public:
+  int drawmeshededges;
+  double geom_tol_fact;
+
+  double longlinefact;
+  int showexcluded;
+
+  int selectmode; //0==trig, 1==edge, 2==point, 3==multiedge, 4==line cluster
+  int edgeselectmode;
+
+  int useexternaledges;
+  int showfaces;
+  int showedgecornerpoints;
+  int showtouchedtrigchart;
+  int conecheck;
+  int spiralcheck;
+  int selecttrig;
+  int nodeofseltrig;
+  int selectwithmouse;
+  int showmarkedtrigs;
+  double dirtytrigfact;
+  double smoothangle;
+
+  double smoothnormalsweight;
+
+  int showvicinity;
+  int vicinity;
+  ///
+  STLDoctorParams();
+  ///
+  void Print (ostream & ost) const;
+};
+
+extern STLDoctorParams stldoctor;
+
+
+
+class STLParameters
+{
+public:
+  /// angle for edge detection
+  double yangle;
+  double contyangle; //edges continued with contyangle
+  /// angle of geometry edge at which the mesher should set a point
+  double edgecornerangle;
+  /// angle inside on chart
+  double chartangle;
+  /// angle for overlapping parts of char
+  double outerchartangle;
+  /// 0 .. no, 1 .. local, (2 .. global)
+  int usesearchtree;
+  ///
+  double resthatlasfac; 
+  int resthatlasenable;
+  double atlasminh;
+
+  double resthsurfcurvfac; 
+  int resthsurfcurvenable;
+
+  double resthchartdistfac;
+  int resthchartdistenable;
+
+  double resthcloseedgefac;
+  int resthcloseedgeenable;
+  
+  double resthedgeanglefac;
+  int resthedgeangleenable;
+  
+  double resthsurfmeshcurvfac;
+  int resthsurfmeshcurvenable;
+  
+  double resthlinelengthfac;
+  int resthlinelengthenable;
+
+  ///
+  int recalc_h_opt;
+  ///
+  STLParameters();
+  ///
+  void Print (ostream & ost) const;
+};
+
+extern STLParameters stlparam;
+
+
+void STLMeshing (STLGeometry & geom,
+		 class Mesh & mesh);
+
+
+int STLSurfaceMeshing (STLGeometry & geom,
+			class Mesh & mesh);
+
+void STLSurfaceOptimization (STLGeometry & geom,
+			     class Mesh & mesh,
+			     class MeshingParameters & mparam);
+
+
+
+
+#endif
diff --git a/Netgen/libsrc/stlgeom/stltopology.cpp b/Netgen/libsrc/stlgeom/stltopology.cpp
new file mode 100644
index 0000000000..1d5315fbec
--- /dev/null
+++ b/Netgen/libsrc/stlgeom/stltopology.cpp
@@ -0,0 +1,1067 @@
+#include <mystdlib.h>
+
+#include <myadt.hpp>
+#include <linalg.hpp>
+#include <gprim.hpp>
+
+#include <meshing.hpp>
+
+#include "stlgeom.hpp"
+
+namespace netgen
+{
+
+
+STLTopology :: STLTopology()
+  : trias(), topedges(), points(), ht_topedges(NULL), 
+    neighbourtrigs(), trigsperpoint()
+{
+  ;
+}
+
+STLTopology :: ~STLTopology()
+{
+  ;
+}
+
+
+
+
+STLGeometry *  STLTopology :: LoadBinary (istream & ist)
+{
+  STLGeometry * geom = new STLGeometry();
+  ARRAY<STLReadTriangle> readtrigs;
+
+  PrintMessage(1,"Read STL binary file");
+  
+  if (sizeof(int) != 4 || sizeof(float) != 4) 
+    {
+      PrintWarning("for stl-binary compatibility only use 32 bit compilation!!!");
+    }
+
+  //specific settings for stl-binary format
+  const int namelen = 80; //length of name of header in file
+  const int nospaces = 2; //number of spaces after a triangle
+
+  //read header: name
+  char buf[namelen+1];
+  FIOReadStringE(ist,buf,namelen);
+  PrintMessage(5,"header = ",buf);
+
+  //Read Number of facets
+  int nofacets;
+  FIOReadInt(ist,nofacets);
+  PrintMessage(5,"NO facets = ",nofacets);
+
+  Point<3> pts[3];
+  Vec<3> normal;
+
+  int cntface, j;
+  int vertex = 0;
+  float f;
+  char spaces[nospaces+1];
+
+  for (cntface = 0; cntface < nofacets; cntface++)
+    {
+      if (cntface % 10000 == 9999) { PrintDot(); } 
+
+      FIOReadFloat(ist,f); normal(0) = f;
+      FIOReadFloat(ist,f); normal(1) = f;
+      FIOReadFloat(ist,f); normal(2) = f;
+      
+      for (j = 0; j < 3; j++)
+	{
+	  FIOReadFloat(ist,f); pts[j](0) = f;
+	  FIOReadFloat(ist,f); pts[j](1) = f;
+	  FIOReadFloat(ist,f); pts[j](2) = f;	  
+	} 
+
+      readtrigs.Append (STLReadTriangle (pts, normal));
+      FIOReadString(ist,spaces,nospaces);
+    }	    
+  
+
+  geom->InitSTLGeometry(readtrigs);
+
+  return geom;
+}
+
+
+void STLTopology :: SaveBinary (const char* filename, const char* aname)
+{
+  ofstream ost(filename);
+  PrintFnStart("Write STL binary file '",filename,"'");
+
+  if (sizeof(int) != 4 || sizeof(float) != 4) 
+    {PrintWarning("for stl-binary compatibility only use 32 bit compilation!!!");}
+
+  //specific settings for stl-binary format
+  const int namelen = 80; //length of name of header in file
+  const int nospaces = 2; //number of spaces after a triangle
+
+  //write header: aname
+  int i, j;
+  char buf[namelen+1];
+  int strend = 0;
+  for(i = 0; i <= namelen; i++) 
+    {
+      if (aname[i] == 0) {strend = 1;}
+      if (!strend) {buf[i] = aname[i];}
+      else {buf[i] = 0;}
+    }
+
+  FIOWriteString(ost,buf,namelen);
+  PrintMessage(5,"header = ",buf);
+
+  //RWrite Number of facets
+  int nofacets = GetNT();
+  FIOWriteInt(ost,nofacets);
+  PrintMessage(5,"NO facets = ", nofacets);
+
+  float f;
+  char spaces[nospaces+1];
+  for (i = 0; i < nospaces; i++) {spaces[i] = ' ';}
+  spaces[nospaces] = 0;
+
+  for (i = 1; i <= GetNT(); i++)
+    {
+      const STLTriangle & t = GetTriangle(i);
+
+      const Vec<3> & n = t.Normal();
+      f = n(0); FIOWriteFloat(ost,f);
+      f = n(1); FIOWriteFloat(ost,f);
+      f = n(2); FIOWriteFloat(ost,f);
+
+      for (j = 1; j <= 3; j++)
+	{
+	  const Point3d p = GetPoint(t.PNum(j));
+	  
+	  f = p.X(); FIOWriteFloat(ost,f);
+	  f = p.Y(); FIOWriteFloat(ost,f);
+	  f = p.Z(); FIOWriteFloat(ost,f);
+	}
+      FIOWriteString(ost,spaces,nospaces);
+    }
+  PrintMessage(5,"done");
+}
+
+
+void STLTopology :: SaveSTLE (const char* filename)
+{
+  ofstream outf (filename);
+  int i, j;
+  
+  outf << GetNT() << endl;
+  for (i = 1; i <= GetNT(); i++)
+    {
+      const STLTriangle & t = GetTriangle(i);
+      for (j = 1; j <= 3; j++)
+	{
+	  const Point3d p = GetPoint(t.PNum(j));
+	  outf << p.X() << " " << p.Y() << " " << p.Z() << endl;
+	}
+    }
+
+
+  int ned = 0;
+  for (i = 1; i <= GetNTE(); i++)
+    {
+      if (GetTopEdge (i).GetStatus() == ED_CONFIRMED)
+	ned++;
+    }
+  
+  outf << ned << endl;
+
+  for (i = 1; i <= GetNTE(); i++)
+    {
+      const STLTopEdge & edge = GetTopEdge (i);
+      if (edge.GetStatus() == ED_CONFIRMED)
+	for (j = 1; j <= 2; j++)
+	  {
+	    const Point3d p = GetPoint(edge.PNum(j));
+	    outf << p.X() << " " << p.Y() << " " << p.Z() << endl;
+	  }
+    }      
+}
+
+
+
+STLGeometry *  STLTopology :: LoadNaomi (istream & ist)
+{
+  int i;
+  STLGeometry * geom = new STLGeometry();
+  ARRAY<STLReadTriangle> readtrigs;
+
+  PrintFnStart("read NAOMI file format");
+  
+  char buf[100];
+  Vec<3> normal;
+
+  int cntface = 0;
+  int cntvertex = 0;
+  double px, py, pz;
+    
+
+  int noface, novertex;
+  ARRAY<Point<3> > readpoints;
+
+  ist >> buf;
+  if (strcmp (buf, "NODES") == 0)
+    {
+      ist >> novertex;
+      PrintMessage(5,"nuber of vertices = ", novertex);
+      for (i = 0; i < novertex; i++)
+	{
+	  ist >> px;
+	  ist >> py;
+	  ist >> pz;
+	  readpoints.Append(Point<3> (px,py,pz));
+	}
+    }
+  else
+    {
+      PrintFileError("no node information");
+    }
+
+
+  ist >> buf;
+  if (strcmp (buf, "2D_EDGES") == 0)
+    {
+      ist >> noface;
+      PrintMessage(5,"number of faces=",noface);
+      int dummy, p1, p2, p3;
+      Point<3> pts[3];
+
+      for (i = 0; i < noface; i++)
+	{
+	  ist >> dummy; //2
+	  ist >> dummy; //1
+	  ist >> p1;
+	  ist >> p2;
+	  ist >> p3;
+	  ist >> dummy; //0
+
+	  pts[0] = readpoints.Get(p1);
+	  pts[1] = readpoints.Get(p2);
+	  pts[2] = readpoints.Get(p3);
+	  
+	  normal = Cross (pts[1]-pts[0], pts[2]-pts[0]) . Normalize();
+
+	  readtrigs.Append (STLReadTriangle (pts, normal));
+
+	}
+      PrintMessage(5,"read ", readtrigs.Size(), " triangles");
+    }
+  else
+    {
+      PrintMessage(5,"read='",buf,"'\n");
+      PrintFileError("ERROR: no Triangle information");
+    }
+
+  geom->InitSTLGeometry(readtrigs);
+
+  return geom;
+}
+
+void STLTopology :: Save (const char* filename)
+{ 
+  PrintFnStart("Write stl-file '",filename, "'");
+
+  ofstream fout(filename);
+  fout << "solid\n";
+
+  char buf1[50];
+  char buf2[50];
+  char buf3[50];
+
+  int i, j;
+  for (i = 1; i <= GetNT(); i++)
+    {
+      const STLTriangle & t = GetTriangle(i);
+
+      fout << "facet normal ";
+      const Vec3d& n = GetTriangle(i).Normal();
+
+      sprintf(buf1,"%1.9g",n.X());
+      sprintf(buf2,"%1.9g",n.Y());
+      sprintf(buf3,"%1.9g",n.Z());
+
+      fout << buf1 << " " << buf2 << " " << buf3 << "\n";
+      fout << "outer loop\n";
+
+      for (j = 1; j <= 3; j++)
+	{
+	  const Point3d p = GetPoint(t.PNum(j));
+	  
+	  sprintf(buf1,"%1.9g",p.X());
+	  sprintf(buf2,"%1.9g",p.Y());
+	  sprintf(buf3,"%1.9g",p.Z());
+
+	  fout << "vertex " << buf1 << " " << buf2 << " " << buf3 << "\n";
+	}
+
+      fout << "endloop\n";
+      fout << "endfacet\n"; 
+    }
+  fout << "endsolid\n";
+
+  
+  // write also NETGEN surface mesh:
+  ofstream fout2("geom.surf");
+  fout2 << "surfacemesh" << endl;
+  fout2 << GetNP() << endl;
+  for (i = 1; i <= GetNP(); i++)
+    {
+      for (j = 0; j < 3; j++)
+	{
+	  fout2.width(8);
+	  fout2 << GetPoint(i)(j);
+	}
+
+      fout2 << endl;
+    }
+
+  fout2 << GetNT() << endl;
+  for (i = 1; i <= GetNT(); i++)
+    {
+      const STLTriangle & t = GetTriangle(i);  
+      for (j = 1; j <= 3; j++)
+	{
+	  fout2.width(8);
+	  fout2 << t.PNum(j);
+	}
+      fout2 << endl;
+    }
+}
+
+
+STLGeometry *  STLTopology ::Load (istream & ist)
+{
+  int i;
+  STLGeometry * geom = new STLGeometry();
+
+  ARRAY<STLReadTriangle> readtrigs;
+
+  char buf[100];
+  Point<3> pts[3];
+  Vec<3> normal;
+
+  int cntface = 0;
+  int vertex = 0;
+  bool badnormals = 0;
+
+  while (ist.good())
+    {
+      ist >> buf;
+
+      int n = strlen (buf);
+      for (i = 0; i < n; i++)
+	buf[i] = tolower (buf[i]);
+
+      if (strcmp (buf, "facet") == 0)
+	{
+	  cntface++;
+	}
+
+      if (strcmp (buf, "normal") == 0)
+	{
+	  ist >> normal(0)
+	      >> normal(1)
+	      >> normal(2);
+	  normal.Normalize();
+	}
+      
+      if (strcmp (buf, "vertex") == 0)
+	{
+	  ist >> pts[vertex](0)
+	      >> pts[vertex](1)
+	      >> pts[vertex](2);
+
+	  vertex++;
+
+	  if (vertex == 3)
+	    {
+	      if (normal.Length() <= 1e-5)
+
+		{
+		  normal = Cross (pts[1]-pts[0], pts[2]-pts[0]);
+		  normal.Normalize();
+		}
+
+	      else
+
+		{
+		  Vec<3> hnormal;
+		  hnormal = Cross (pts[1]-pts[0], pts[2]-pts[0]);
+		  hnormal.Normalize();
+
+		  if (normal * hnormal < 0.5)
+		    {
+		      badnormals = 1;
+		    }
+		}
+
+	      vertex = 0;
+
+	      if ( (Dist2 (pts[0], pts[1]) > 1e-16) &&
+		   (Dist2 (pts[0], pts[2]) > 1e-16) &&
+		   (Dist2 (pts[1], pts[2]) > 1e-16) )
+		
+		readtrigs.Append (STLReadTriangle (pts, normal));
+	    }
+	}
+    }
+  
+  if (badnormals) 
+    {
+      PrintWarning("File has normal vectors which differ extremly from geometry->correct with stldoctor!!!");
+    }
+
+  geom->InitSTLGeometry(readtrigs);
+  return geom;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+void STLTopology :: InitSTLGeometry(const ARRAY<STLReadTriangle> & readtrigs)
+{
+  int i, j, k;
+  
+  // const double geometry_tol_fact = 1E6; 
+  // distances lower than max_box_size/tol are ignored
+
+  trias.SetSize(0);
+  points.SetSize(0);
+
+  PrintMessage(3,"number of triangles = ", readtrigs.Size());
+
+  if (!readtrigs.Size())
+    return;
+  
+
+  boundingbox.Set (readtrigs[0][0]);
+  for (i = 0; i < readtrigs.Size(); i++)
+    for (k = 0; k < 3; k++)
+      boundingbox.Add (readtrigs[i][k]);
+  
+  PrintMessage(5,"boundingbox: ", Point3d(boundingbox.PMin()), " - ", 
+	       Point3d(boundingbox.PMax()));
+
+  Box<3> bb = boundingbox;
+  bb.Increase (1);
+
+  pointtree = new Point3dTree (bb.PMin(), bb.PMax());
+
+
+
+  ARRAY<int> pintersect;
+
+  pointtol = boundingbox.Diam() * stldoctor.geom_tol_fact;
+  PrintMessage(5,"point tolerance = ", pointtol);
+
+  for(i = 0; i < readtrigs.Size(); i++)
+    {
+      const STLReadTriangle & t = readtrigs[i];
+      STLTriangle st;
+      Vec<3> n = t.Normal();
+      st.SetNormal (t.Normal());
+
+      for (k = 0; k < 3; k++)
+	{
+	  Point<3> p = t[k];
+
+	  Point<3> pmin = p - Vec<3> (pointtol, pointtol, pointtol);
+	  Point<3> pmax = p + Vec<3> (pointtol, pointtol, pointtol);
+	  
+	  pointtree->GetIntersecting (pmin, pmax, pintersect);
+	  
+	  if (pintersect.Size() > 1)
+	    PrintError("too many close points");
+	  int foundpos = -1;
+	  if (pintersect.Size())
+	    foundpos = pintersect[0];
+	  
+	  if (foundpos == -1)
+	    {
+	      foundpos = AddPoint(p);
+	      pointtree->Insert (p, foundpos);
+	    }
+	  st[k] = foundpos;
+	}
+
+      if ( (st[0] == st[1]) ||
+	   (st[0] == st[2]) || 
+	   (st[1] == st[2]) )
+	{
+	  PrintError("STL Triangle degenerated");
+	}
+      else
+	{
+	  AddTriangle(st);
+	}
+      
+    } 
+
+  FindNeighbourTrigs();
+}
+
+
+
+
+int STLTopology :: GetPointNum (const Point<3> & p)
+{
+  Point<3> pmin = p - Vec<3> (pointtol, pointtol, pointtol);
+  Point<3> pmax = p + Vec<3> (pointtol, pointtol, pointtol);
+  
+  ARRAY<int> pintersect;
+
+  pointtree->GetIntersecting (pmin, pmax, pintersect);
+  if (pintersect.Size() == 1)
+    return pintersect[0];
+  else 
+    return 0;
+}
+
+
+
+void STLTopology :: FindNeighbourTrigs()
+{
+  //  if (topedges.Size()) return;
+
+  PushStatusF("Find Neighbour Triangles");
+
+  int i, j, k, l;
+
+  // build up topology tables
+
+  int np = GetNP();
+  int nt = GetNT();
+
+  INDEX_2_HASHTABLE<int> * oldedges = ht_topedges;
+  ht_topedges = new INDEX_2_HASHTABLE<int> (GetNP()+1);
+  topedges.SetSize(0);
+  
+  for (i = 1; i <= nt; i++)
+    {
+      STLTriangle & trig = GetTriangle(i);
+
+
+      for (j = 1; j <= 3; j++)
+	{
+	  int pi1 = trig.PNumMod (j+1);
+	  int pi2 = trig.PNumMod (j+2);
+	  
+	  INDEX_2 i2(pi1, pi2);
+	  i2.Sort();
+
+	  int enr;
+	  int othertn;
+
+	  if (ht_topedges->Used(i2))
+	    {
+	      enr = ht_topedges->Get(i2);
+	      topedges.Elem(enr).TrigNum(2) = i;
+
+	      othertn = topedges.Get(enr).TrigNum(1);
+	      STLTriangle & othertrig = GetTriangle(othertn);
+
+	      trig.NBTrigNum(j) = othertn;
+	      trig.EdgeNum(j) = enr;
+	      for (k = 1; k <= 3; k++)
+		if (othertrig.EdgeNum(k) == enr)
+		  othertrig.NBTrigNum(k) = i;
+	    }
+	  else
+	    {
+	      enr = topedges.Append (STLTopEdge (pi1, pi2, i, 0));
+	      ht_topedges->Set (i2, enr);
+	      trig.EdgeNum(j) = enr;
+	    }
+	}
+    }
+
+  
+  PrintMessage(5,"topology built, checking");
+
+  topology_ok = 1;
+  int ne = GetNTE();
+
+  for (i = 1; i <= nt; i++)
+    GetTriangle(i).flags.toperror = 0;
+
+  for (i = 1; i <= nt; i++)
+    for (j = 1; j <= 3; j++)
+      {
+	const STLTopEdge & edge = GetTopEdge (GetTriangle(i).EdgeNum(j));
+	if (edge.TrigNum(1) != i && edge.TrigNum(2) != i)
+	  {
+	    topology_ok = 0;
+	    GetTriangle(i).flags.toperror = 1;
+	  }
+      }
+
+  for (i = 1; i <= ne; i++)
+    {
+      const STLTopEdge & edge = GetTopEdge (i);
+      if (!edge.TrigNum(2))
+	{
+	  topology_ok = 0;
+	  GetTriangle(edge.TrigNum(1)).flags.toperror = 1;
+	}
+    }
+ 
+  if (topology_ok)
+    {
+      orientation_ok = 1;
+      for (i = 1; i <= nt; i++)
+	{
+	  const STLTriangle & t = GetTriangle (i);
+	  for (j = 1; j <= 3; j++)
+	    {
+	      const STLTriangle & nbt = GetTriangle (t.NBTrigNum(j));
+	      if (!t.IsNeighbourFrom (nbt))
+		orientation_ok = 0;
+	    }
+	}
+    }
+  else
+    orientation_ok = 0;
+  
+
+
+  status = STL_GOOD;
+  statustext = "";
+  if (!topology_ok || !orientation_ok)
+    {
+      status = STL_ERROR;
+      if (!topology_ok)
+	statustext = "Topology not ok";
+      else
+	statustext = "Orientation not ok";
+    }
+
+
+  PrintMessage(3,"topology_ok = ",topology_ok);
+  PrintMessage(3,"orientation_ok = ",orientation_ok);
+  PrintMessage(3,"topology found");
+
+  // generate point -> trig table
+
+  trigsperpoint.SetSize(GetNP());
+  for (i = 1; i <= GetNT(); i++)
+    for (j = 1; j <= 3; j++)
+      trigsperpoint.Add1(GetTriangle(i).PNum(j),i);
+
+
+  //check trigs per point:
+  /*
+  for (i = 1; i <= GetNP(); i++)
+    {
+      if (trigsperpoint.EntrySize(i) < 3)
+	{
+	  (*testout) << "ERROR: Point " << i << " has " << trigsperpoint.EntrySize(i) << " triangles!!!" << endl;
+	}
+    }
+  */
+  topedgesperpoint.SetSize (GetNP());
+  for (i = 1; i <= ne; i++)
+    for (j = 1; j <= 2; j++)
+      topedgesperpoint.Add1 (GetTopEdge (i).PNum(j), i);
+
+  PrintMessage(5,"point -> trig table generated");
+
+
+
+  // transfer edge data:
+  // .. to be done
+  delete oldedges;
+
+
+
+  for (STLTrigIndex ti = 0; ti < GetNT(); ti++)
+    {
+      STLTriangle & trig = trias[ti];
+      for (k = 0; k < 3; k++)
+	{
+	  STLPointIndex pi = trig[k] - STLBASE;
+	  STLPointIndex pi2 = trig[(k+1)%3] - STLBASE;
+	  STLPointIndex pi3 = trig[(k+2)%3] - STLBASE;
+	  
+	  // vector along edge
+	  Vec<3> ve = points[pi2] - points[pi];
+	  ve.Normalize();
+
+	  // vector along third point
+	  Vec<3> vt = points[pi3] - points[pi];
+	  vt -= (vt * ve) * ve;
+	  vt.Normalize();
+
+	  Vec<3> vn = trig.GeomNormal (points);
+	  vn.Normalize();
+
+	  double phimin = 10, phimax = -1; // out of (0, 2 pi)
+
+	  for (j = 0; j < trigsperpoint[pi].Size(); j++)
+	    {
+	      STLTrigIndex ti2 = trigsperpoint[pi][j] - STLBASE;
+	      const STLTriangle & trig2 = trias[ti2];
+
+	      if (ti == ti2) continue;
+	      
+	      bool hasboth = 0;
+	      for (l = 0; l < 3; l++)
+		if (trig2[l] - STLBASE == pi2)
+		  {
+		    hasboth = 1;
+		    break;
+		  }
+	      if (!hasboth) continue;
+
+	      STLPointIndex pi4;
+	      for (l = 0; l < 3; l++)
+		if (trig2[l] - STLBASE != pi && trig2[l] - STLBASE != pi2)
+		  pi4 = trig2[l] - STLBASE;
+
+	      Vec<3> vt2 = points[pi4] - points[pi];
+	      
+	      double phi = atan2 (vt2 * vn, vt2 * vt);
+	      if (phi < 0) phi += 2 * M_PI;
+	      
+	      if (phi < phimin)
+		{
+		  phimin = phi;
+		  trig.NBTrig (0, (k+2)%3) = ti2 + STLBASE;
+		}
+	      if (phi > phimax)
+		{
+		  phimax = phi;
+		  trig.NBTrig (1, (k+2)%3) = ti2 + STLBASE;
+		}
+	    }
+	}
+    }
+
+
+
+
+  if (status == STL_GOOD)
+    {
+      // for compatibility:
+      neighbourtrigs.SetSize(GetNT());
+      for (i = 1; i <= GetNT(); i++)
+	for (k = 1; k <= 3; k++)
+	  AddNeighbourTrig (i, GetTriangle(i).NBTrigNum(k));
+    }
+  else
+    {
+      // assemble neighbourtrigs (should be done only for illegal topology):
+      
+      neighbourtrigs.SetSize(GetNT());
+
+      int tr, found;
+      int wrongneighbourfound = 0;
+      for (i = 1; i <= GetNT(); i++)
+	{
+	  SetThreadPercent((double)i/(double)GetNT()*100.);
+	  if (multithread.terminate)
+	    {
+	      PopStatus();
+	      return;
+	    }
+	  
+	  for (k = 1; k <= 3; k++)
+	    {
+	      for (j = 1; j <= trigsperpoint.EntrySize(GetTriangle(i).PNum(k)); j++)
+		{
+		  tr = trigsperpoint.Get(GetTriangle(i).PNum(k),j);
+		  if (i != tr && (GetTriangle(i).IsNeighbourFrom(GetTriangle(tr))
+				  || GetTriangle(i).IsWrongNeighbourFrom(GetTriangle(tr))))
+		    {
+		      if (GetTriangle(i).IsWrongNeighbourFrom(GetTriangle(tr)))
+			{
+			  /*(*testout) << "ERROR: triangle " << i << " has a wrong neighbour triangle!!!" << endl;*/
+			  wrongneighbourfound ++;
+			}
+		      
+		      found = 0;
+		      for (int ii = 1; ii <= NONeighbourTrigs(i); ii++) 
+			{if (NeighbourTrig(i,ii) == tr) {found = 1;break;};}
+		      if (! found) {AddNeighbourTrig(i,tr);}
+		    }
+		}
+	    }
+	  if (NONeighbourTrigs(i) != 3) 
+	    {
+	      PrintError("TRIG ",i," has ",NONeighbourTrigs(i)," neighbours!!!!");
+	      for (int kk=1; kk <= NONeighbourTrigs(i); kk++)
+		{
+		  PrintMessage(5,"neighbour-trig",kk," = ",NeighbourTrig(i,kk));
+		}
+	    };
+	}
+      if (wrongneighbourfound)
+	{
+	  PrintError("++++++++++++++++++++\n");
+	  PrintError(wrongneighbourfound, " wrong oriented neighbourtriangles found!");
+	  PrintError("try to correct it (with stldoctor)!");
+	  PrintError("++++++++++++++++++++\n");
+	  
+	  status = STL_ERROR;
+	  statustext = "STL Mesh not consistent";
+
+	  multithread.terminate = 1;
+#ifdef STAT_STREAM
+	  (*statout) << "non-conform stl geometry \\hline" << endl;
+#endif
+	}
+    }
+
+  TopologyChanged();
+
+  PopStatus();
+}
+
+
+
+
+
+
+
+void STLTopology :: GetTrianglesInBox (/* 
+					  const Point<3> & pmin,
+					  const Point<3> & pmax,
+				       */
+				       const Box<3> & box,
+				       ARRAY<int> & trias) const
+{
+  if (searchtree)
+
+    searchtree -> GetIntersecting (box.PMin(), box.PMax(), trias);
+  
+  else
+    {    
+      int i;
+      Box<3> box1 = box;
+      box1.Increase (1e-4);
+
+      trias.SetSize(0);
+   
+      int nt = GetNT();
+      for (i = 1; i <= nt; i++)
+	{
+	  if (box1.Intersect (GetTriangle(i).box))
+	    {
+	      trias.Append (i);
+	    }
+	}    
+    }
+}
+
+
+
+void STLTopology :: AddTriangle(const STLTriangle& t)
+{
+  trias.Append(t);
+  
+  const Point<3> & p1 = GetPoint (t.PNum(1));
+  const Point<3> & p2 = GetPoint (t.PNum(2));
+  const Point<3> & p3 = GetPoint (t.PNum(3));
+
+  Box<3> box;
+  box.Set (p1);
+  box.Add (p2);
+  box.Add (p3);
+  /*
+  //  Point<3> pmin(p1), pmax(p1);
+  pmin.SetToMin (p2);
+  pmin.SetToMin (p3);
+  pmax.SetToMax (p2);
+  pmax.SetToMax (p3);
+  */
+
+  trias.Last().box = box; 
+  trias.Last().center = Center (p1, p2, p3);
+  double r1 = Dist (p1, trias.Last().center);
+  double r2 = Dist (p2, trias.Last().center);
+  double r3 = Dist (p3, trias.Last().center);
+  trias.Last().rad = max2 (max2 (r1, r2), r3);
+
+  if (geomsearchtreeon)
+    {searchtree->Insert (box.PMin(), box.PMax(), trias.Size());}
+}
+
+
+
+
+int STLTopology :: GetLeftTrig(int p1, int p2) const
+{
+  int i;
+  for (i = 1; i <= trigsperpoint.EntrySize(p1); i++)
+    {
+      if (GetTriangle(trigsperpoint.Get(p1,i)).HasEdge(p1,p2)) {return trigsperpoint.Get(p1,i);}
+    }
+  PrintSysError("ERROR in GetLeftTrig !!!");
+
+  return 0;
+}
+
+int STLTopology :: GetRightTrig(int p1, int p2) const
+{
+  return GetLeftTrig(p2,p1);
+}
+
+
+int STLTopology :: NeighbourTrigSorted(int trig, int edgenum) const
+{
+  int i, p1, p2;
+  int psearch = GetTriangle(trig).PNum(edgenum);
+
+  for (i = 1; i <= 3; i++)
+    {
+      GetTriangle(trig).GetNeighbourPoints(GetTriangle(NeighbourTrig(trig,i)),p1,p2);
+      if (p1 == psearch) {return NeighbourTrig(trig,i);}
+    }
+
+  PrintSysError("ERROR in NeighbourTrigSorted");
+  return 0;
+}
+
+
+
+
+
+
+int STLTopology :: GetTopEdgeNum (int pi1, int pi2) const
+{
+  if (!ht_topedges) return 0;
+
+  INDEX_2 i2(pi1, pi2);
+  i2.Sort();
+
+  if (!ht_topedges->Used(i2)) return 0;
+  return ht_topedges->Get(i2);
+}
+
+
+
+
+void STLTopology :: InvertTrig (int trig)
+{
+  if (trig >= 1 && trig <= GetNT())
+    {
+      GetTriangle(trig).ChangeOrientation();
+      FindNeighbourTrigs();
+    }
+  else
+    {
+      PrintUserError("no triangle selected!");
+    }
+}
+
+
+
+
+void STLTopology :: DeleteTrig (int trig)
+{
+  if (trig >= 1 && trig <= GetNT())
+    {
+      trias.DeleteElement(trig);
+      FindNeighbourTrigs();
+    }
+  else
+    {
+      PrintUserError("no triangle selected!");
+    }
+}
+
+
+
+void STLTopology :: OrientAfterTrig (int trig)
+{
+  int starttrig = trig;
+
+  if (starttrig >= 1 && starttrig <= GetNT())
+    {
+
+      ARRAY <int> oriented;
+      oriented.SetSize(GetNT());
+      int i;
+      for (i = 1; i <= oriented.Size(); i++)
+	{
+	  oriented.Elem(i) = 0;
+	}
+ 
+      oriented.Elem(starttrig) = 1;
+  
+      int j = 0,k;
+      
+      ARRAY <int> list1;
+      list1.SetSize(0);
+      ARRAY <int> list2;
+      list2.SetSize(0);
+      list1.Append(starttrig);
+
+      int cnt = 1;
+      int end = 0;
+      int nt;
+      while (!end)
+	{
+	  end = 1;
+	  for (i = 1; i <= list1.Size(); i++)
+	    {
+	      const STLTriangle& tt = GetTriangle(list1.Get(i));
+	      for (k = 1; k <= 3; k++)
+		{
+		  nt = tt.NBTrigNum (k); // NeighbourTrig(list1.Get(i),k);
+		  if (oriented.Get(nt) == 0)
+		    {
+		      if (tt.IsWrongNeighbourFrom(GetTriangle(nt)))
+			{
+			  GetTriangle(nt).ChangeOrientation();
+			}
+		      oriented.Elem(nt) = 1;
+		      list2.Append(nt);
+		      cnt++;
+		      end = 0;
+		    }
+		}
+	    }
+	  list1.SetSize(0);
+	  for (i = 1; i <= list2.Size(); i++)
+	    {
+	      list1.Append(list2.Get(i));
+	    }
+	  list2.SetSize(0);
+	}
+
+      PrintMessage(5,"NO corrected triangles = ",cnt);
+      if (cnt == GetNT()) 
+	{
+	  PrintMessage(5,"ALL triangles oriented in same way!");
+	}
+      else
+	{
+	  PrintWarning("NOT ALL triangles oriented in same way!");
+	}
+
+      //      topedges.SetSize(0);
+      FindNeighbourTrigs();
+    }
+  else
+    {
+      PrintUserError("no triangle selected!");
+    }
+}
+
+
+}
diff --git a/Netgen/libsrc/stlgeom/stltopology.hpp b/Netgen/libsrc/stlgeom/stltopology.hpp
new file mode 100644
index 0000000000..80e5a68178
--- /dev/null
+++ b/Netgen/libsrc/stlgeom/stltopology.hpp
@@ -0,0 +1,362 @@
+#ifndef FILE_STLTOPOLOGY
+#define FILE_STLTOPOLOGY
+
+/**************************************************************************/
+/* File:   stltopology.hpp                                                */
+/* Author: Joachim Schoeberl                                              */
+/* Author2: Johannes Gerstmayr                                            */
+/* Date:   26. Jul. 99                                                    */
+/**************************************************************************/
+
+/*
+  The STLTopology contains topologic information as
+  triangle->point, point->triangles, triangle->edge, 2-points->edge,...
+*/
+
+
+class STLGeometry;
+
+#define STLBASE 1
+
+class STLPointIndex
+{
+  int i;
+public:
+  STLPointIndex () { ; }
+  STLPointIndex (int ai) : i(ai) { ; }
+  STLPointIndex & operator= (const STLPointIndex & ai) { i = ai.i; return *this; }
+  STLPointIndex & operator= (int ai) { i = ai; return *this; }
+  operator int () const { return i; }
+  STLPointIndex operator++ (int) { return i++; }
+  STLPointIndex operator-- (int) { return i--; }
+};
+
+
+
+class STLTrigIndex
+{
+  int i;
+public:
+  STLTrigIndex () { ; }
+  STLTrigIndex (int ai) : i(ai) { ; }
+  STLTrigIndex & operator= (const STLTrigIndex & ai) { i = ai.i; return *this; }
+  STLTrigIndex & operator= (int ai) { i = ai; return *this; }
+  operator int () const { return i; }
+  STLTrigIndex operator++ (int) { return i++; }
+  STLTrigIndex operator-- (int) { return i--; }
+};
+
+
+
+
+
+// triangle structure for loading stl files
+class STLReadTriangle
+{
+  Vec<3> normal;
+  Point<3> pts[3];
+public:
+  STLReadTriangle (const Point<3> * apts, const Vec<3> & anormal);
+  STLReadTriangle () {};
+  const Point<3> & operator[] (int i) const { return pts[i]; }
+  const Vec<3> & Normal() const { return normal; }
+};
+
+
+
+class STLTriangle
+{
+  // topology edges of triangle, edge[i] opposite to point[i]
+  int topedges[3];
+  // neighbour triangles, trig[i] opposite to point[i]
+  int nbtrigs[2][3]; 
+  // normalized stored normal vector ??
+  Vec<3> normal;
+  // point numbers of triangle
+  int pts[3];
+  // front-side and back-side domains
+  int domains[2];
+
+
+public:
+
+  Box<3> box;
+  Point<3> center;
+  double rad;
+  int facenum;
+
+  struct 
+  {
+    unsigned int toperror : 1;
+  } flags;
+
+
+
+
+  STLTriangle (const int * apts);
+  STLTriangle () {pts[0]=0;pts[1]=0;pts[2]=0;}
+
+  int operator[] (int i) const { return pts[i]; }
+  int & operator[] (int i) { return pts[i]; }
+
+  int EdgeNum(int i) const { return topedges[(i-1)]; }
+  int & EdgeNum(int i) { return topedges[(i-1)]; }
+
+  int NBTrig (bool side, int i) const { return nbtrigs[side][i]; }
+  int & NBTrig (bool side, int i) { return nbtrigs[side][i]; }
+
+  
+  int Domain (bool side) const { return domains[side]; }
+  int & Domain (bool side) { return domains[side]; }
+
+
+
+  // obsolete:
+  int PNum(int i) const { return pts[(i-1)]; }
+  int & PNum(int i) { return pts[(i-1)]; }
+  int PNumMod(int i) const { return pts[(i-1)%3]; }
+  int & PNumMod(int i)  { return pts[(i-1)%3]; }
+
+  int EdgeNumMod(int i) const { return topedges[(i-1)%3]; }
+  int & EdgeNumMod(int i)  { return topedges[(i-1)%3]; }
+
+  int NBTrigNum(int i) const { return nbtrigs[0][(i-1)]; }
+  int & NBTrigNum(int i) { return nbtrigs[0][(i-1)]; }
+  int NBTrigNumMod(int i) const { return nbtrigs[0][(i-1)%3]; }
+  int & NBTrigNumMod(int i)  { return nbtrigs[0][(i-1)%3]; }
+  
+
+  // consistently oriented neighbour:
+  int IsNeighbourFrom(const STLTriangle& t) const;
+  // opposite to consistently oriented neighbour:
+  int IsWrongNeighbourFrom(const STLTriangle& t) const;
+
+  ///Get the two points of neighbour-Triangles in orientation of this-Triangle
+  void GetNeighbourPoints(const STLTriangle& t, int& p1, int& p2) const;
+  int GetNeighbourPointsAndOpposite(const STLTriangle& t, int& p1, int& p2, int& po) const;
+
+
+
+  // NON-normalized geometry - normal vector
+  Vec<3> GeomNormal(const ARRAY<Point<3> >& ap) const;
+  
+  // Stored normal vector, normalized
+  void SetNormal (const Vec<3> & n);
+  const Vec<3> & Normal () const { return normal; }
+
+
+  void ChangeOrientation(); 
+
+  //project with a certain normal vector in plane
+  void ProjectInPlain(const ARRAY<Point<3> >& ap, 
+		      const Vec<3> & n, Point<3> & pp) const;
+  //project with the triangle's normal vector in plane
+  void ProjectInPlain(const ARRAY<Point<3> > & ap, Point<3> & pp) const;
+
+
+  /*
+    Project the point pp along the nproj into the plane of
+    the triangle. The triangle normal is given by ntrig to 
+    avoid numerical instabilities.
+    The local coordinates lam are defined by
+
+    pp(input) = P1 + lam1 v1 + lam2 v2 + lam3 n
+
+    the result is
+    
+    pp(output) = P1 + lam1 v1 + lam2 v2
+  */
+  int ProjectInPlain (const ARRAY<Point<3> >& ap, 
+		      const Vec<3> & nproj, 
+		      Point<3> & pp, Vec<3> & lam) const;
+
+  int PointInside(const ARRAY<Point<3> >& ap, const Point<3> & pp) const;
+
+  //get nearest point on triangle and distance to it
+  double GetNearestPoint(const ARRAY<Point<3> >& ap, 
+			 Point<3> & p3d) const;
+
+  double Area(const ARRAY<Point<3> >& ap) const;
+
+  double MinHeight(const ARRAY<Point<3> >& ap) const;
+  double MaxLength(const ARRAY<Point<3> >& ap) const; 
+  //max length of a side of triangle
+
+  int GetFaceNum() {return facenum;}
+  void SetFaceNum(int i) {facenum = i;}
+
+  int HasEdge(int p1, int p2) const;
+};
+
+
+/**
+   Topology Edge:
+   Useful unside a face.
+   A edges sharing more than 2 faces: trigs are undefined 
+ */
+class STLTopEdge 
+{
+  int pts[2];  
+  int trigs[2];  
+  double cosangle;
+  int status;  // excluded, confirmed, candidate, undefined
+public:
+  STLTopEdge ();
+  STLTopEdge (int p1, int p2, int trig1, int trig2);
+
+  int operator[] (int i) const { return pts[i]; }
+  int & operator[] (int i) { return pts[i]; }
+
+
+  int PNum(int i) const { return pts[(i-1)]; }
+  int & PNum(int i) { return pts[(i-1)]; }
+  int PNumMod(int i) const { return pts[(i-1)%2]; }
+  int & PNumMod(int i)  { return pts[(i-1)%2]; }
+
+  int TrigNum(int i) const { return trigs[(i-1)]; }
+  int & TrigNum(int i) { return trigs[(i-1)]; }
+  int TrigNumMod(int i) const { return trigs[(i-1)%2]; }
+  int & TrigNumMod(int i)  { return trigs[(i-1)%2]; }
+
+  void SetCosAngle (double ca) { cosangle = ca; }
+  double CosAngle () const { return cosangle; }
+  double Angle () const { return acos (cosangle); }
+
+  void SetStatus (int stat) { status = stat; }
+  int GetStatus () const { return status; }
+};
+
+
+
+ostream& operator<<(ostream& os, const STLTriangle& t);
+
+
+
+
+
+
+
+class STLTopology
+{
+protected:
+  ARRAY<STLTriangle> trias;
+  ARRAY<STLTopEdge> topedges;
+  ARRAY<Point<3> > points;
+
+  // mapping of sorted pair of points to topedge
+  INDEX_2_HASHTABLE<int> * ht_topedges;
+  // mapping of node to trigs
+  TABLE<int> trigsperpoint; 
+  // mapping of node to edges
+  TABLE<int> topedgesperpoint; 
+  
+  // searchtree for trigs and points
+
+  Box3dTree * searchtree; // ADT
+  Point3dTree * pointtree;
+
+  Box<3> boundingbox;
+  double pointtol;
+
+public:
+  enum STL_GEOM_STATUS { STL_GOOD, STL_WARNING, STL_ERROR };
+
+protected:
+  STL_GEOM_STATUS status;
+  string statustext;
+  
+  bool topology_ok;
+  bool orientation_ok;
+
+public:
+  STLTopology();
+  virtual ~STLTopology();
+
+  static STLGeometry * LoadNaomi (istream & ist);
+  static STLGeometry * Load (istream & ist);
+  static STLGeometry * LoadBinary (istream & ist);
+
+  void Save (const char* filename);
+  void SaveBinary (const char* filename, const char* aname);
+  void SaveSTLE (const char * filename); // stores trigs and edges
+  
+  virtual void InitSTLGeometry (const ARRAY<STLReadTriangle> & readtrigs);
+
+  virtual void TopologyChanged() {}; //do some things, if topology changed!
+
+  /// Generate topology tables
+  void FindNeighbourTrigs();
+
+  
+  void GetTrianglesInBox (const Box<3> & box,
+			  ARRAY<int> & trias) const;
+
+
+  int GetNP() const { return points.Size(); }
+  int AddPoint(const Point<3> & p) { return points.Append(p); }
+  const Point<3> & GetPoint(int nr) const { return points.Get(nr); }
+  int GetPointNum (const Point<3> & p);
+  void SetPoint(int nr, const Point<3> & p) { points.Elem(nr) = p; }
+  const ARRAY<Point<3> >& GetPoints() const { return points; }
+
+  const Point<3> & operator[] (STLPointIndex i) const { return points[i]; }
+  Point<3> & operator[] (STLPointIndex i) { return points[i]; }
+
+
+
+
+  int GetNT() const { return trias.Size(); }
+  void AddTriangle(const STLTriangle& t);
+  const STLTriangle & GetTriangle (int nr) const { return trias.Get(nr); }
+  STLTriangle & GetTriangle (int nr) { return trias.Elem(nr); }
+  
+  const STLTriangle & operator[] (STLTrigIndex i) const { return trias[i]; }
+  STLTriangle & operator[] (STLTrigIndex i) { return trias[i]; }
+
+
+  int GetNTE() const { return topedges.Size(); }
+  const STLTopEdge & GetTopEdge (int nr) const { return topedges.Get(nr); }
+  STLTopEdge & GetTopEdge (int nr)  { return topedges.Elem(nr); }
+  int GetTopEdgeNum (int pi1, int pi2) const;
+
+
+  int NOTrigsPerPoint(int pn) { return trigsperpoint.EntrySize(pn); }
+  int TrigPerPoint(int pn, int i) { return trigsperpoint.Get(pn, i); }
+
+
+  int NTopEdgesPerPoint (int pn) const { return topedgesperpoint.EntrySize(pn); }
+  int TopEdgePerPoint (int pn, int ei) const { return topedgesperpoint.Get(pn, ei); }
+
+  
+  bool Topology_Ok() const { return topology_ok; }
+  bool Orientation_Ok() const { return orientation_ok; }
+
+  STL_GEOM_STATUS GetStatus () const { return status; }
+  const string & GetStatusText () const { return statustext; }
+
+  void InvertTrig (int trig);
+  void DeleteTrig (int trig);
+  void OrientAfterTrig (int trig);
+
+
+  // Table will be constructed, if topology is not ok
+  /// neighbourtrigs for surfacetrigs
+  TABLE<int> neighbourtrigs;
+
+  /// get nr-th neighbour Triangle for triangle trig
+  int NONeighbourTrigs(int trig) const { return neighbourtrigs.EntrySize(trig); }
+  int NeighbourTrig(int trig, int nr) const { return neighbourtrigs.Get(trig,nr); }
+  int NeighbourTrigSorted(int trig, int nr) const;
+  void AddNeighbourTrig(int i, int nt) { neighbourtrigs.Add1(i, nt); }
+
+
+
+
+  int GetLeftTrig (int p1, int p2) const;
+  int GetRightTrig (int p1, int p2) const;
+
+  const Box<3> & GetBoundingBox () const { return boundingbox; }
+};
+
+
+#endif
diff --git a/Netgen/libsrc/visualization/Makefile b/Netgen/libsrc/visualization/Makefile
new file mode 100644
index 0000000000..f8e80916e9
--- /dev/null
+++ b/Netgen/libsrc/visualization/Makefile
@@ -0,0 +1,13 @@
+#
+# Makefile for visualization library
+#
+src = stlmeshing.cpp mvdraw.cpp vscsg.cpp vsmesh.cpp vssolution.cpp meshdoc.cpp
+#
+lib = vis
+libpath = libsrc/visualization
+#
+#
+include ../makefile.inc
+#
+
+
diff --git a/Netgen/libsrc/visualization/meshdoc.cpp b/Netgen/libsrc/visualization/meshdoc.cpp
new file mode 100644
index 0000000000..4c0f064c05
--- /dev/null
+++ b/Netgen/libsrc/visualization/meshdoc.cpp
@@ -0,0 +1,615 @@
+#include <mystdlib.h>
+
+#include <meshing.hpp>
+
+#include "incvis.hpp"
+
+
+
+namespace netgen
+{
+#include "mvdraw.hpp"
+#include "meshdoc.hpp"
+
+
+MeshDoctorParameters meshdoctor;
+VisualSceneMeshDoctor vsmeshdoc;
+
+extern AutoPtr<Mesh> mesh;
+
+  int Ng_MeshDoctor (ClientData clientData,
+		     Tcl_Interp * interp,
+		     int argc, tcl_const char *argv[])
+{
+  cout << "Mesh Doctor:" << endl;
+  int i;
+  for (i = 0; i < argc; i++)
+    cout << argv[i] << " ";
+  cout << endl;
+
+  meshdoctor.active = 
+    atoi (Tcl_GetVar (interp, "meshdoctor.active", 0)); 
+
+
+  if (argc >= 2)
+    {
+      if (strcmp (argv[1], "markedgedist") == 0)
+	{
+	  vsmeshdoc.SetMarkEdgeDist (atoi (argv[2]));
+	}
+
+      if (strcmp (argv[1], "deletemarkedsegments") == 0)
+	{
+	  for (i = 1; i <= mesh->GetNSeg(); i++)
+	    if (vsmeshdoc.IsSegmentMarked (i))
+	      mesh->DeleteSegment (i);
+
+	  //	  for (i = 1; i <= mesh->GetNSE(); i++)
+	  //	    mesh->SurfaceElement(i).SetIndex (1);
+	  mesh->Compress();
+	}
+    }
+
+
+  vsmeshdoc.UpdateTables ();
+  vsmeshdoc.BuildScene();
+  return TCL_OK;
+}
+
+
+
+
+
+VisualSceneMeshDoctor :: VisualSceneMeshDoctor ()
+  : VisualScene()
+{
+  filledlist = 0;
+  outlinelist = 0;
+  edgelist = 0;
+  selelement = 0;
+  locpi = 1;
+  selpoint = 0;
+  selpoint2 = 0;
+  markedgedist = 1;
+
+  UpdateTables ();
+}
+
+VisualSceneMeshDoctor :: ~VisualSceneMeshDoctor ()
+{
+  ;
+}
+
+void VisualSceneMeshDoctor :: DrawScene ()
+{
+  int i, j, k;
+
+  if (!mesh) return;
+
+  int hchval = mesh->GetNP() + mesh->GetNE() + mesh->GetNSE();
+  if (changeval != hchval)
+    {
+      changeval = hchval;
+      BuildScene();
+    }
+
+
+  glClearColor(backcolor, backcolor, backcolor, 1.0);
+  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+  glEnable (GL_COLOR_MATERIAL);
+  glColor3f (1.0f, 1.0f, 1.0f);
+  glLineWidth (1.0f);
+
+  SetLight();
+
+  glPushMatrix();
+  glMultMatrixf (transformationmat);
+  
+  glInitNames ();
+  glPushName (0);
+  
+  glPolygonOffset (1, 1);
+  glEnable (GL_POLYGON_OFFSET_FILL);
+
+  SetClippingPlane ();
+
+  if (vispar.drawfilledtrigs)
+    glCallList (filledlist);
+
+  glDisable (GL_POLYGON_OFFSET_FILL);
+  
+  if (vispar.drawoutline)
+    glCallList (outlinelist);
+  
+  glPolygonOffset (-1, -1);
+  glEnable (GL_POLYGON_OFFSET_LINE);
+
+  if (vispar.drawedges)
+    glCallList (edgelist);
+  
+
+  glDisable (GL_POLYGON_OFFSET_LINE);
+
+  
+  
+  glPopName();
+
+  if (selpoint > 0 && selpoint <= mesh->GetNP())
+    {
+      GLfloat matcolblue[] = { 0, 0, 1, 1 };
+
+      glPointSize (10);
+      glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, matcolblue);
+      glBegin (GL_POINTS);
+      
+      const Point3d p = mesh->Point(selpoint);
+      glVertex3f (p.X(), p.Y(), p.Z());
+      glEnd();
+    }
+
+  glDisable(GL_CLIP_PLANE0);
+
+
+  glPopMatrix();
+  glFinish();  
+}
+
+
+
+
+void VisualSceneMeshDoctor :: BuildScene (int zoomall)
+{
+  int i, j, k;
+ 
+
+  if (zoomall)
+    {
+      Point3d pmin, pmax;
+      mesh->GetBox (pmin, pmax, -1);
+
+      if (vispar.centerpoint)
+	center = mesh->Point (vispar.centerpoint);
+      else
+	center = Center (pmin, pmax);
+  
+      rad = 0.5 * Dist (pmin, pmax);
+
+      glEnable (GL_NORMALIZE);
+  
+      CalcTransformationMatrices();
+    }
+
+
+
+
+  if (filledlist)
+    {
+      glDeleteLists (filledlist, 1);
+      glDeleteLists (outlinelist, 1);
+      glDeleteLists (edgelist, 1);
+    }
+
+  
+  filledlist = glGenLists (1);
+  glNewList (filledlist, GL_COMPILE);
+
+  glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
+  
+  static float matcol0[] = { 0.0f, 0.0f, 0.0f, 1.0f };
+  static float matcol1[] = { 1.0f, 1.0f, 1.0f, 1.0f };
+  static float matcolsel[] = { 1.0f, 0.0f, 0.0f, 1.0f };
+  static float matcolnosel[] = { 0.0f, 1.0f, 0.0f, 1.0f };
+  
+  glLineWidth (1.0f);
+  
+  glDisable (GL_COLOR_MATERIAL);
+    
+  for (i = 1; i <= mesh->GetNSE(); i++)
+    {
+      glLoadName (i);
+
+      // copy to be thread-safe
+      Element2d el = mesh->SurfaceElement (i);
+
+      int drawel = 1;
+      for (j = 1; j <= el.GetNP(); j++)
+	{
+	  if (!el.PNum(j))
+	    drawel = 0;
+	}
+
+      if (!drawel)
+	continue;
+
+      GLfloat matcol[] = { 0, 1, 0, 1 };
+      GLfloat matcolsel[] = { 1, 0, 0, 1 };
+
+      if (i == selelement)
+	glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, matcolsel);
+      else
+	glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, matcol);
+
+      if (el.GetNP() == 3)
+	{
+	  glBegin (GL_TRIANGLES);
+	  
+	  const Point3d & lp1 = mesh->Point (el.PNum(1));
+	  const Point3d & lp2 = mesh->Point (el.PNum(2));
+	  const Point3d & lp3 = mesh->Point (el.PNum(3));
+	  Vec3d n = Cross (Vec3d (lp1, lp2), Vec3d (lp1, lp3));
+	  n /= (n.Length()+1e-12);
+	  glNormal3d (n.X(), n.Y(), n.Z());
+
+	  if (!vispar.colormeshsize)
+	    {
+	      glVertex3d (lp1.X(), lp1.Y(), lp1.Z());
+	      glVertex3d (lp2.X(), lp2.Y(), lp2.Z());
+	      glVertex3d (lp3.X(), lp3.Y(), lp3.Z());
+	    }
+	  else
+	    {
+	      double h1 = mesh->GetH (lp1);
+	      double h2 = mesh->GetH (lp2);
+	      double h3 = mesh->GetH (lp3);
+	      
+	      SetOpenGlColor  (h1, 0.1, 10);
+	      glVertex3d (lp1.X(), lp1.Y(), lp1.Z());
+
+	      SetOpenGlColor  (h2, 0.1, 10);
+	      glVertex3d (lp2.X(), lp2.Y(), lp2.Z());
+
+	      SetOpenGlColor  (h3, 0.1, 10);
+	      glVertex3d (lp3.X(), lp3.Y(), lp3.Z());
+	    }	    
+	  glEnd();
+	}
+      else if (el.GetNP() == 4)
+	{
+	  glBegin (GL_QUADS);
+	  
+	  const Point3d & lp1 = mesh->Point (el.PNum(1));
+	  const Point3d & lp2 = mesh->Point (el.PNum(2));
+	  const Point3d & lp3 = mesh->Point (el.PNum(4));
+	  const Point3d & lp4 = mesh->Point (el.PNum(3));
+	  Vec3d n = Cross (Vec3d (lp1, lp2), 
+			   Vec3d (lp1, Center (lp3, lp4)));
+	  n /= (n.Length()+1e-12);
+	  glNormal3d (n.X(), n.Y(), n.Z()); 
+	  glVertex3d (lp1.X(), lp1.Y(), lp1.Z());
+	  glVertex3d (lp2.X(), lp2.Y(), lp2.Z());
+	  glVertex3d (lp4.X(), lp4.Y(), lp4.Z());
+	  glVertex3d (lp3.X(), lp3.Y(), lp3.Z());
+	  glEnd();
+	}
+      else if (el.GetNP() == 6)
+	{
+	  glBegin (GL_TRIANGLES);
+	  static int trigs[4][3] = {
+	    { 1, 6, 5 },
+	    { 2, 4, 6 },
+	    { 3, 5, 4 },
+	    { 4, 5, 6 } };
+
+	  for (j = 0; j < 4; j++)
+	    {
+	      const Point3d & lp1 = mesh->Point (el.PNum(trigs[j][0]));
+	      const Point3d & lp2 = mesh->Point (el.PNum(trigs[j][1]));
+	      const Point3d & lp3 = mesh->Point (el.PNum(trigs[j][2]));
+	      Vec3d n = Cross (Vec3d (lp1, lp2), Vec3d (lp1, lp3));
+	      n /= (n.Length() + 1e-12);
+	      glNormal3d (n.X(), n.Y(), n.Z());
+	      glVertex3d (lp1.X(), lp1.Y(), lp1.Z());
+	      glVertex3d (lp2.X(), lp2.Y(), lp2.Z());
+	      glVertex3d (lp3.X(), lp3.Y(), lp3.Z());
+	    }
+	  glEnd();
+	}
+    }
+  glLoadName (0);
+  
+  glEndList ();
+
+  
+  
+  outlinelist = glGenLists (1);
+  glNewList (outlinelist, GL_COMPILE);
+
+  glLineWidth (1.0f);
+  glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
+
+  glColor3f (0.0f, 0.0f, 0.0f);
+  glEnable (GL_COLOR_MATERIAL);
+  
+  for (i = 1; i <= mesh->GetNSE(); i++)
+    {
+      Element2d el = mesh->SurfaceElement(i);
+
+      int drawel = 1;
+      for (j = 1; j <= el.GetNP(); j++)
+	{
+	  if (!el.PNum(j))
+	    drawel = 0;
+	}
+
+      if (!drawel)
+	continue;
+
+
+      if (el.GetNP() == 3)
+	{
+	  glBegin (GL_TRIANGLES);
+	  
+	  const Point3d & lp1 = mesh->Point (el.PNum(1));
+	  const Point3d & lp2 = mesh->Point (el.PNum(2));
+	  const Point3d & lp3 = mesh->Point (el.PNum(3));
+	  Vec3d n = Cross (Vec3d (lp1, lp2), Vec3d (lp1, lp3));
+	  n /= (n.Length() + 1e-12);
+	  glNormal3d (n.X(), n.Y(), n.Z());
+	  glVertex3d (lp1.X(), lp1.Y(), lp1.Z());
+	  glVertex3d (lp2.X(), lp2.Y(), lp2.Z());
+	  glVertex3d (lp3.X(), lp3.Y(), lp3.Z());
+	  glEnd();
+	}
+      else if (el.GetNP() == 4)
+	{
+	  glBegin (GL_QUADS);
+	  
+	  const Point3d & lp1 = mesh->Point (el.PNum(1));
+	  const Point3d & lp2 = mesh->Point (el.PNum(2));
+	  const Point3d & lp3 = mesh->Point (el.PNum(4));
+	  const Point3d & lp4 = mesh->Point (el.PNum(3));
+	  Vec3d n = Cross (Vec3d (lp1, lp2), 
+			   Vec3d (lp1, Center (lp3, lp4)));
+	  n /= (n.Length() + 1e-12);
+	  glNormal3d (n.X(), n.Y(), n.Z());
+	  glVertex3d (lp1.X(), lp1.Y(), lp1.Z());
+	  glVertex3d (lp2.X(), lp2.Y(), lp2.Z());
+	  glVertex3d (lp4.X(), lp4.Y(), lp4.Z());
+	  glVertex3d (lp3.X(), lp3.Y(), lp3.Z());
+	  glEnd();
+	}
+      else if (el.GetNP() == 6)
+	{
+	  glBegin (GL_LINES);
+	  
+	  const Point3d & lp1 = mesh->Point (el.PNum(1));
+	  const Point3d & lp2 = mesh->Point (el.PNum(2));
+	  const Point3d & lp3 = mesh->Point (el.PNum(3));
+	  const Point3d & lp4 = mesh->Point (el.PNum(4));
+	  const Point3d & lp5 = mesh->Point (el.PNum(5));
+	  const Point3d & lp6 = mesh->Point (el.PNum(6));
+
+	  Vec3d n = Cross (Vec3d (lp1, lp2), Vec3d (lp1, lp3));
+	  n /= (n.Length()+1e-12);
+	  glNormal3d (n.X(), n.Y(), n.Z());
+
+	  glVertex3d (lp1.X(), lp1.Y(), lp1.Z());
+	  glVertex3d (lp6.X(), lp6.Y(), lp6.Z());
+	  glVertex3d (lp2.X(), lp2.Y(), lp2.Z());
+	  glVertex3d (lp6.X(), lp6.Y(), lp6.Z());
+
+	  glVertex3d (lp1.X(), lp1.Y(), lp1.Z());
+	  glVertex3d (lp5.X(), lp5.Y(), lp5.Z());
+	  glVertex3d (lp3.X(), lp3.Y(), lp3.Z());
+	  glVertex3d (lp5.X(), lp5.Y(), lp5.Z());
+
+	  glVertex3d (lp2.X(), lp2.Y(), lp2.Z());
+	  glVertex3d (lp4.X(), lp4.Y(), lp4.Z());
+	  glVertex3d (lp3.X(), lp3.Y(), lp3.Z());
+	  glVertex3d (lp4.X(), lp4.Y(), lp4.Z());
+	  glEnd();
+	}
+    }
+  glLoadName (0);  
+  glEndList ();
+
+
+
+
+
+  edgelist = glGenLists (1);
+  glNewList (edgelist, GL_COMPILE);
+
+  glDisable (GL_COLOR_MATERIAL);
+
+  GLfloat matcoledge[] = { 0, 0, 1, 1 };
+  GLfloat matcolseledge[] = { 1, 0, 1, 1 };
+
+  glLineWidth (2.0f);
+
+  for (i = 1; i <= mesh->GetNSeg(); i++)
+    {
+      const Segment & seg = mesh->LineSegment(i);
+      const Point3d & p1 = mesh->Point(seg.p1);
+      const Point3d & p2 = mesh->Point(seg.p2);
+
+      if (edgedist.Get(seg.p1) <= markedgedist &&
+	  edgedist.Get(seg.p2) <= markedgedist)
+	{
+	  glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, 
+			matcolseledge);
+	  glLineWidth (4.0f);
+	}
+      else
+	{
+	  glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, 
+			matcoledge);
+	  glLineWidth (2.0f);
+	}
+      glBegin (GL_LINES);
+      glVertex3f (p1.X(), p1.Y(), p1.Z());
+      glVertex3f (p2.X(), p2.Y(), p2.Z());
+      glEnd(); 
+    }
+
+  glLineWidth (1.0f);
+  glEndList ();
+}
+
+
+
+
+void VisualSceneMeshDoctor :: MouseDblClick (int px, int py)
+{
+  cout << "dblclick: " << px << " - " << py << endl;
+  
+  int i, j, k, hits;
+
+  // select surface triangle by mouse click
+  GLuint selbuf[10000];
+  glSelectBuffer (10000, selbuf);
+
+
+  glRenderMode (GL_SELECT);
+
+  GLint viewport[4];
+  glGetIntegerv (GL_VIEWPORT, viewport);
+
+  glMatrixMode (GL_PROJECTION); 
+  glPushMatrix();
+
+  GLdouble projmat[16];
+  glGetDoublev (GL_PROJECTION_MATRIX, projmat);
+
+  glLoadIdentity(); 
+  gluPickMatrix (px, viewport[3] - py, 1, 1, viewport); 
+  glMultMatrixd (projmat);
+  
+
+  glClearColor(backcolor, backcolor, backcolor, 1.0);
+  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+  glMatrixMode (GL_MODELVIEW); 
+
+  glPushMatrix();
+  glMultMatrixf (transformationmat);
+
+  glInitNames();
+  glPushName (1);
+
+  glPolygonOffset (1, 1);
+  glEnable (GL_POLYGON_OFFSET_FILL);
+
+  glCallList (filledlist);
+
+  glDisable (GL_POLYGON_OFFSET_FILL);
+  
+  glPopName();
+
+  glMatrixMode (GL_PROJECTION); 
+  glPopMatrix();
+
+  glMatrixMode (GL_MODELVIEW); 
+  glPopMatrix();
+
+  glFlush();  
+
+	
+  hits = glRenderMode (GL_RENDER);
+
+  cout << "hits = " << hits << endl;
+
+  int minname = 0;
+  GLuint mindepth = 0;
+  for (i = 0; i < hits; i++)
+    {
+      int curname = selbuf[4*i+3];
+      GLuint curdepth = selbuf[4*i+1];
+
+      if (curname &&
+	  (curdepth < mindepth || !minname))
+	{
+	  mindepth = curdepth;
+	  minname = curname;
+	}
+    }
+
+  cout << "clicked element: " << minname << endl;
+
+  ClickElement (minname);
+
+  BuildScene ();
+}
+
+
+
+
+void VisualSceneMeshDoctor :: SetMarkEdgeDist (int dist)
+{
+  markedgedist = dist;
+  BuildScene();
+}
+
+void VisualSceneMeshDoctor :: ClickElement (int elnr)
+{
+  selelement = elnr;
+
+  int oldlocpi = locpi;
+  locpi = locpi % 3 + 1;
+  
+  if (selelement > 0 && selelement <= mesh->GetNSE())
+    {
+      selpoint = mesh->SurfaceElement(selelement).PNum(locpi);
+      selpoint2 = mesh->SurfaceElement(selelement).PNum(oldlocpi);
+      cout << "selpts = " << selpoint << ", " << selpoint2 << endl;
+    }
+
+  UpdateTables();
+}
+
+
+void VisualSceneMeshDoctor :: UpdateTables ()
+{
+  if (!mesh) return;
+
+  edgedist.SetSize(mesh->GetNP());
+  int i, changed;
+
+  for (i = 1; i <= mesh->GetNP(); i++)
+    edgedist.Elem(i) = 10000;
+
+  for (i = 1; i <= mesh->GetNSeg(); i++)
+    {
+      const Segment & seg = mesh->LineSegment(i);
+      if (seg.p1 == selpoint && seg.p2 == selpoint2 ||
+	  seg.p2 == selpoint && seg.p1 == selpoint2)
+	{
+	  edgedist.Elem(selpoint) = 1;
+	  edgedist.Elem(selpoint2) = 1;
+	}
+    }
+
+  do
+    {
+      changed = 0;
+
+      for (i = 1; i <= mesh->GetNSeg(); i++)
+	{
+	  const Segment & seg = mesh->LineSegment(i);
+	  
+	  int edist = min2 (edgedist.Get(seg.p1), edgedist.Get(seg.p2));
+	  edist++;
+
+	  if (edgedist.Get(seg.p1) > edist)
+	    {
+	      edgedist.Elem(seg.p1) = edist;
+	      changed = 1;
+	    }
+	  if (edgedist.Get(seg.p2) > edist)
+	    {
+	      edgedist.Elem(seg.p2) = edist;
+	      changed = 1;
+	    }
+	}	    
+    }
+  while (changed);
+}
+
+int VisualSceneMeshDoctor :: IsSegmentMarked (int segnr) const
+{
+  const Segment & seg = mesh->LineSegment(segnr);
+  return (edgedist.Get(seg.p1) <= markedgedist &&
+	  edgedist.Get(seg.p2) <= markedgedist);
+}
+}
diff --git a/Netgen/libsrc/visualization/meshdoc.hpp b/Netgen/libsrc/visualization/meshdoc.hpp
new file mode 100644
index 0000000000..5cc11aef78
--- /dev/null
+++ b/Netgen/libsrc/visualization/meshdoc.hpp
@@ -0,0 +1,37 @@
+
+class VisualSceneMeshDoctor : public VisualScene
+{
+  int filledlist;
+  int outlinelist;
+  int edgelist;
+
+  int selelement, locpi;
+  int selpoint, selpoint2;
+
+  // for edgemarking:
+  ARRAY<int> edgedist;
+  int markedgedist;
+  
+
+public:
+  VisualSceneMeshDoctor ();
+  virtual ~VisualSceneMeshDoctor ();
+
+  virtual void BuildScene (int zoomall = 0);
+  virtual void DrawScene ();
+  virtual void MouseDblClick (int px, int py);
+
+  void SetMarkEdgeDist (int dist);
+  void ClickElement (int elnr);
+  void UpdateTables ();
+  int IsSegmentMarked (int segnr) const;
+};
+
+class MeshDoctorParameters 
+{
+public:
+  int active;
+};
+
+
+extern MeshDoctorParameters meshdoctor;
diff --git a/Netgen/libsrc/visualization/mvdraw.cpp b/Netgen/libsrc/visualization/mvdraw.cpp
new file mode 100644
index 0000000000..c166e5aac3
--- /dev/null
+++ b/Netgen/libsrc/visualization/mvdraw.cpp
@@ -0,0 +1,1540 @@
+#include <mystdlib.h>
+#include <myadt.hpp>
+#include <meshing.hpp>
+#include <csg.hpp>
+#include <geometry2d.hpp>
+#include <stlgeom.hpp>
+
+#ifdef OCCGEOMETRY
+#include <occgeom.hpp>
+#include "TopoDS_Shape.hxx"
+#include "TopoDS_Vertex.hxx"
+#include "TopExp_Explorer.hxx"
+#include "BRep_Tool.hxx"
+#include "TopoDS.hxx"
+#include "gp_Pnt.hxx"
+#include "Geom_Curve.hxx"
+#include "Poly_Triangulation.hxx"
+#include "Poly_Array1OfTriangle.hxx"
+#include "TColgp_Array1OfPnt2d.hxx"
+#include "Poly_Triangle.hxx"
+#include "BRepMesh.hxx"
+#endif
+
+
+#include "incvis.hpp"
+
+
+#ifdef STEP
+#include <stepgeom.hpp>
+#endif
+
+namespace netgen
+{
+
+#include "mvdraw.hpp"
+
+Point3d VisualScene :: center;
+double VisualScene :: rad;
+double VisualScene :: backcolor;
+GLuint VisualScene :: fontbase = 0;
+
+// texture for color decoding
+GLubyte * VisualScene :: colortexture = NULL;
+GLuint VisualScene :: coltexname = 1;
+int VisualScene :: ntexcols = -1;
+  // bool VisualScene :: linear_colors = 1;
+
+float VisualScene :: lookatmat[16];
+float VisualScene :: transmat[16];
+float VisualScene :: rotmat[16];
+float VisualScene :: centermat[16];
+float VisualScene :: transformationmat[16];
+
+
+
+VisualizationParameters :: VisualizationParameters()
+{
+  lightamb = 0.3;
+  lightdiff = 0.7;
+  lightspec = 1;
+  shininess = 50;
+  transp = 0.3;
+  locviewer = 0;
+  showstltrias = 0;
+  centerpoint = 0;
+  usedispllists = 1;
+  strcpy (selectvisual, "cross");
+};
+VisualizationParameters vispar;
+
+
+
+double dist = 0;
+  // double dist = 6;
+// vorher: pnear = 2;
+double pnear = 0.1;
+double pfar = 10;
+
+
+
+extern CSGeometry * geometry;
+extern STLGeometry * stlgeometry;
+extern SplineGeometry2d * geometry2d;
+
+#ifdef OCCGEOMETRY
+extern OCCGeometry * occgeometry;
+#endif
+
+#ifdef STEP
+using STEP_AP203::STEPGeometry;
+extern STEPGeometry * stepgeometry;
+#endif // STEP
+extern AutoPtr<Mesh> mesh;
+extern ARRAY<SpecialPoint> specpoints;
+
+//Tcl_Interp * hinterp;
+
+
+VisualScene :: VisualScene ()
+{
+  changeval = -1;
+  backcolor = 0;
+
+
+
+}
+
+VisualScene :: ~VisualScene()
+{
+  ;
+}
+
+
+void Render ()
+{
+  multithread.redraw = 1;
+  //  while (multithread.redraw);
+      //   Tcl_Eval (hinterp, ".ndraw render");
+}
+
+void VisualScene :: BuildScene (int zoomall)
+{
+  center = Point3d (0,0,0);
+  rad = 1;
+
+  CalcTransformationMatrices();
+
+  glEnable(GL_DEPTH_TEST);
+  glDisable (GL_DITHER);
+  
+  GLfloat ambvals[] = { 0.4f, 0.4f, 0.4f, 1.0f };
+  GLfloat diffvals[] = { 0.5f, 0.5f, 0.5f, 1.0f };
+  GLfloat specvals[] =  { 0.7f, 0.7f, 0.7f, 1.0f };
+  glLightfv(GL_LIGHT0, GL_AMBIENT, ambvals);
+  glLightfv(GL_LIGHT0, GL_DIFFUSE, diffvals);
+  glLightfv(GL_LIGHT0, GL_SPECULAR, specvals);
+  
+  GLfloat light_position[] = { 1, 3, 3, 0 };
+  glLightfv(GL_LIGHT0, GL_POSITION, light_position);
+  
+  glLightModeli (GL_LIGHT_MODEL_TWO_SIDE, 0);
+  glEnable(GL_LIGHTING);
+  glEnable(GL_LIGHT0);
+}
+
+
+void VisualScene :: DrawScene ()
+{
+  if (changeval == -1)
+    BuildScene();
+  changeval = 0;
+
+  glClearColor(backcolor, backcolor, backcolor, 1.0);
+  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+  glEnable (GL_COLOR_MATERIAL);
+  glColor3f (1.0f, 1.0f, 1.0f);
+  glLineWidth (1.0f);
+
+  /*
+  glPushMatrix();
+  //  glLoadIdentity();
+  glMultMatrixf (transformationmat);
+  
+  glBegin(GL_LINES);
+  glVertex3f (0.0f, 0.0f, 0.0f);
+  glVertex3f (1.0f, 0.0f, 0.0f);
+  glVertex3f (0.0f, 0.0f, 0.0f);
+  glVertex3f (0.0f, 1.0f, 0.0f);
+  glVertex3f (0.0f, 0.0f, 0.0f);
+  glVertex3f (0.0f, 0.0f, 1.0f);
+  glEnd ();
+  
+  glPopMatrix();
+  */
+
+  DrawCoordinateCross ();
+  DrawNetgenLogo ();
+  glFinish();  
+}
+
+
+void VisualScene :: CalcTransformationMatrices()
+{
+
+  // prepare model view matrix
+  
+  glPushMatrix();
+
+  glLoadIdentity();
+  gluLookAt (0, 0, 6, 0, 0, 0, 0, 1, 0);
+  glGetFloatv (GL_MODELVIEW_MATRIX, lookatmat);
+
+  glLoadIdentity();
+  glTranslatef(0.0f, 0.0f, -dist);
+  glGetFloatv (GL_MODELVIEW_MATRIX, transmat);
+  
+  glLoadIdentity();
+  glGetFloatv (GL_MODELVIEW_MATRIX, rotmat);
+
+  glScalef (1/rad, 1/rad, 1/rad);
+  glTranslated (-center.X(), -center.Y(), -center.Z());
+  glGetFloatv (GL_MODELVIEW_MATRIX, centermat);
+
+  glLoadIdentity();
+  glMultMatrixf (lookatmat);
+  glMultMatrixf (transmat);
+  glMultMatrixf (rotmat);
+  glMultMatrixf (centermat);
+  glGetFloatv (GL_MODELVIEW_MATRIX, transformationmat);
+
+  glPopMatrix();
+}
+
+void VisualScene :: StandardRotation (const char * dir)
+{
+  glPushMatrix();
+
+  glLoadIdentity();
+  
+  if (strcmp (dir, "xy") == 0)
+    ;
+  else if (strcmp (dir, "yx") == 0)
+    glRotatef(180.0, 1.0f, 1.0f, 0.0f);    
+  else if (strcmp (dir, "xz") == 0)
+    glRotatef(-90.0, 1.0f, 0.0f, 0.0f);    
+  else if (strcmp (dir, "zx") == 0)
+    {
+      glRotatef(180.0, 1.0f, 1.0f, 0.0f);    
+      glRotatef(-90.0, 1.0f, 0.0f, 0.0f);    
+    }
+  else if (strcmp (dir, "yz") == 0)
+    {
+      glRotatef(-90.0, 0.0f, 0.0f, 1.0f);    
+      glRotatef(-90.0, 0.0f, 1.0f, 0.0f);    
+    }
+  else if (strcmp (dir, "zy") == 0)
+    glRotatef(90.0, 0.0f, 1.0f, 0.0f);    
+    
+
+  glGetFloatv (GL_MODELVIEW_MATRIX, rotmat);
+
+  glLoadIdentity();
+  glMultMatrixf (lookatmat);
+  glMultMatrixf (transmat);
+  glMultMatrixf (rotmat);
+  glMultMatrixf (centermat);
+  glGetFloatv (GL_MODELVIEW_MATRIX, transformationmat);
+  
+  glPopMatrix();
+}
+
+void VisualScene :: MouseMove(int oldx, int oldy,
+			      int newx, int newy,
+			      char mode)
+{
+  int deltax = newx - oldx;
+  int deltay = newy - oldy;
+  
+  glPushMatrix();
+  glLoadIdentity ();
+  
+  switch (mode)
+    {
+    case 'r':
+      {	
+	glRotatef(float(deltax)/2, 0.0f, 1.0f, 0.0f);
+	glRotatef(float(deltay)/2, 1.0f, 0.0f, 0.0f);
+	glMultMatrixf (rotmat);
+	glGetFloatv (GL_MODELVIEW_MATRIX, rotmat);
+	break;
+      }
+    case 'm':
+      {
+	GLdouble projmat[16], modelviewmat[16];
+	GLint viewport[4];
+	glGetDoublev (GL_PROJECTION_MATRIX, projmat);
+	glGetDoublev (GL_MODELVIEW_MATRIX, modelviewmat);
+	glGetIntegerv (GL_VIEWPORT, viewport);
+	
+	// vorher pvz1/2 = 0
+	GLdouble pvx1 = 0, pvy1 = 0, pvz1 = 0.95;
+	GLdouble pvx2 = deltax, pvy2 = -deltay, pvz2 = 0.95;
+
+	GLdouble px1, py1, pz1;
+	GLdouble px2, py2, pz2;
+	
+	gluUnProject (pvx1, pvy1, pvz1, 
+		      modelviewmat, projmat, viewport,
+		      &px1, &py1, &pz1);
+	gluUnProject (pvx2, pvy2, pvz2, 
+		      modelviewmat, projmat, viewport,
+		      &px2, &py2, &pz2);
+	/*
+	gluUnProject (oldx, oldy, 1, 
+		      modelviewmat, projmat, viewport,
+		      &px1, &py1, &pz1);
+	gluUnProject (newx, newy, 1, 
+		      modelviewmat, projmat, viewport,
+		      &px2, &py2, &pz2);
+	*/
+
+	/*	
+	cout << "pv1 = " << pvx1 << ", " << pvy1 << ", " << pvz1 << endl;
+	cout << "p1 = " << px1 << ", " << py1 << ", " << pz1 << endl;
+	*/
+
+	glTranslated (px2-px1, py2-py1, pz2-pz1);
+	
+	glMultMatrixf (transmat);
+	glGetFloatv (GL_MODELVIEW_MATRIX, transmat);
+	break;
+      }
+    case 'z':
+      {
+	// glTranslatef(0.0f, 0.0f, -dist);
+	glScaled (exp (float (-deltay)/100), 
+		  exp (float (-deltay)/100), 
+		  exp (float (-deltay)/100));
+	// glTranslatef(0.0f, 0.0f, dist);
+	glMultMatrixf (transmat);
+	glGetFloatv (GL_MODELVIEW_MATRIX, transmat);
+	break;
+      }
+    }
+
+  glLoadIdentity();
+  glMultMatrixf (lookatmat);
+  glMultMatrixf (transmat);
+  glMultMatrixf (rotmat);
+  glMultMatrixf (centermat);
+  glGetFloatv (GL_MODELVIEW_MATRIX, transformationmat);
+  
+  glPopMatrix();
+}
+
+
+void VisualScene :: LookAt (const Point<3> & cam, const Point<3> & obj,
+			    const Point<3> & camup)
+{
+  glPushMatrix();
+  glLoadIdentity ();
+  gluLookAt (cam(0), cam(1), cam(2), 
+	     obj(0), obj(1), obj(2),
+	     camup(0), camup(1), camup(2));
+  glMultMatrixf (centermat);
+  glGetFloatv (GL_MODELVIEW_MATRIX, transformationmat);
+  glPopMatrix();
+}
+
+  
+void VisualScene :: SetClippingPlane ()
+{
+  if (vispar.clipenable)
+    {
+      Vec3d n = vispar.clipnormal;
+      n /= (n.Length()+1e-10);
+      clipplane[0] = n.X();
+      clipplane[1] = n.Y();
+      clipplane[2] = n.Z();
+      clipplane[3] = -(Vec3d(center) * n) + rad * vispar.clipdist;
+
+      glClipPlane(GL_CLIP_PLANE0, clipplane);
+      glEnable(GL_CLIP_PLANE0);
+    }
+  else
+    glDisable (GL_CLIP_PLANE0);
+}
+
+
+
+
+void VisualScene :: MouseDblClick (int px, int py)
+{
+  ;
+}
+
+
+
+void VisualScene :: SetLight()
+{
+  GLfloat vals[3];
+  double lightamb = vispar.lightamb;
+  vals[0] = vals[1] = vals[2] = lightamb;
+  glLightfv(GL_LIGHT0, GL_AMBIENT, vals);
+
+  double lightdiff = vispar.lightdiff;
+  vals[0] = vals[1] = vals[2] = lightdiff;
+  glLightfv(GL_LIGHT0, GL_DIFFUSE, vals);
+
+  double lightspec = vispar.lightspec;
+  vals[0] = vals[1] = vals[2] = lightspec;
+  glLightfv(GL_LIGHT0, GL_SPECULAR, vals);
+
+  glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, vispar.shininess);
+  glLightModeli (GL_LIGHT_MODEL_LOCAL_VIEWER, vispar.locviewer);
+
+  float mat_spec_col[] = { 1, 1, 1, 1 };
+  glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, mat_spec_col);
+
+  glEnable (GL_LIGHTING);
+  glEnable (GL_LIGHT0);
+}
+
+
+
+
+void VisualScene :: SetOpenGlColor(double h, double hmin, double hmax,
+				   int logscale)
+{
+  double value;
+
+  if (!logscale)
+    value = (h - hmin) / (hmax - hmin);
+  else
+    {
+      if (hmax <= 0) hmax = 1;
+      if (hmin <= 0) hmin = 1e-4 * hmax;
+      value = (log(fabs(h)) - log(hmin)) / (log(hmax) - log(hmin));
+    }
+
+  if (!invcolor)
+    value = 1 - value;
+
+  glTexCoord1f ( 0.999 * value + 0.001);
+
+  if (value > 1) value = 1;
+  if (value < 0) value = 0;
+
+  value *= 4;
+
+  const double colp[][3] =
+  {
+    { 1, 0, 0 },
+    { 1, 1, 0 },
+    { 0, 1, 0 },
+    { 0, 1, 1 },
+    { 0, 0, 1 },
+    { 1, 0, 1 },
+    { 1, 0, 0 },
+  };
+  
+  int i = int(value);
+  double r = value - i;
+
+  GLdouble col[3];
+  int j;
+  for (j = 0; j < 3; j++)
+    col[j] = (1-r) * colp[i][j] + r * colp[i+1][j];
+  
+  glColor3d (col[0], col[1], col[2]);
+}
+
+
+void VisualScene :: CreateTexture (int ncols, int linear)
+{
+  int i;
+
+  if (ncols < 2) ncols = 2;
+  ncols = 8;
+
+  if (ntexcols != ncols)
+    {
+      if (colortexture) 
+	{
+	  glDeleteTextures (1, &coltexname);
+	  delete colortexture;
+	}
+      
+      ntexcols = ncols;
+      
+      colortexture = new GLubyte[4*ncols+4];
+
+      const double colp[][3] =
+      {
+	{ 1, 0, 0 },
+	{ 1, 1, 0 },
+	{ 0, 1, 0 },
+	{ 0, 1, 1 },
+	{ 0, 0, 1 },
+	{ 1, 0, 1 },
+	{ 1, 0, 0 },
+      };
+  
+      for (i = 0; i < ncols; i++)
+	{
+	  double value = 4.0 * i / (ncols-1);
+
+	  int iv = int(value);
+	  double r = value - iv;
+
+	  GLdouble col[3];
+	  int j;
+	  for (j = 0; j < 3; j++)
+	    col[j] = (1-r) * colp[iv][j] + r * colp[iv+1][j];
+	  
+	  glColor3d (col[0], col[1], col[2]);
+
+	  colortexture[4*i] = GLubyte (255 * col[0]);
+	  colortexture[4*i+1] = GLubyte (255 * col[1]);
+	  colortexture[4*i+2] = GLubyte (255 * col[2]);
+	  colortexture[4*i+3] = GLubyte(255);
+	}
+
+      //      glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
+
+      
+      glGenTextures (1, &coltexname);
+
+
+      glBindTexture (GL_TEXTURE_1D, coltexname);
+
+      glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+      glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+      glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+
+      glTexImage1D (GL_TEXTURE_1D, 0, 4, ncols, 0, GL_RGBA, GL_UNSIGNED_BYTE, colortexture);
+      glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
+ 
+    }
+
+
+  glBindTexture (GL_TEXTURE_1D, coltexname);
+  if (linear)
+    {
+      glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+      glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    }
+  else
+    {
+      glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+      glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    }
+}
+
+
+
+
+void VisualScene :: DrawColorBar (double minval, double maxval,
+				  int logscale)
+{
+  int i;
+
+  if (!vispar.drawcolorbar) return;
+
+  CreateTexture (8, 1);
+
+  if (logscale && maxval <= 0) maxval = 1;
+  if (logscale && minval <= 0) minval = 1e-4 * maxval;
+
+
+  double minx = -1;
+  double maxx = 1;
+  double miny = 0.75;
+  double maxy = 0.8;
+      
+  double x;
+
+  glEnable (GL_COLOR_MATERIAL);
+  glEnable (GL_TEXTURE_1D);
+  glNormal3d (0, 0, 1);
+
+  glBegin (GL_LINES);
+  for (x = minx; x <= maxx; x += (maxx - minx) / 1000)
+    {
+      SetOpenGlColor (x, minx, maxx);
+      glVertex3d (x, miny,-5);
+      glVertex3d (x, maxy,-5);
+    }
+  glEnd();
+
+  glDisable (GL_TEXTURE_1D);
+
+  glEnable (GL_COLOR_MATERIAL);
+  GLfloat textcol[3] = { 1 - backcolor,
+			 1 - backcolor,
+			 1 - backcolor };
+  glColor3fv (textcol);
+  glPushAttrib (GL_LIST_BIT);
+  glListBase (fontbase);
+
+  char buf[20];
+  for (i = 0; i <= 4; i++)
+    {
+      x = minx + i * (maxx-minx) / 4;
+      glRasterPos3d (x, 0.7,-5);
+      
+      double val;
+      if (logscale)
+	val = minval * pow (maxval / minval, i / 4.0);
+      else
+	val = minval + i * (maxval-minval) / 4;
+
+      sprintf (buf, "%8.3e", val);
+      glCallLists (strlen (buf), GL_UNSIGNED_BYTE, buf);
+    }
+
+  glPopAttrib ();
+}
+
+
+void VisualScene :: DrawCoordinateCross ()
+{
+  if (!vispar.drawcoordinatecross) return;
+
+  glMatrixMode (GL_PROJECTION); 
+  glPushMatrix();
+  glLoadIdentity();
+
+  glMatrixMode (GL_MODELVIEW); 
+  glPushMatrix();
+  glLoadIdentity();
+
+  GLint viewport[4];
+  glGetIntegerv (GL_VIEWPORT, viewport);
+
+  glTranslatef (-1, -1, 0.0);
+  glScalef (40.0 / viewport[2], 40.0 / viewport[3], 1);
+  glTranslatef (2.0, 2.0, 0.0);
+  glMultMatrixf (rotmat);
+
+  glEnable (GL_COLOR_MATERIAL);
+  glDisable (GL_LIGHTING);
+
+  GLfloat textcol[3] = { 1 - backcolor,
+			 1 - backcolor,
+			 1 - backcolor };
+  glColor3fv (textcol);
+
+  glLineWidth (1.0f);
+
+  float len = 1;
+  glBegin(GL_LINES);
+  glVertex3f (0.0f, 0.0f, 0.0f);
+  glVertex3f (len, 0.0f, 0.0f);
+  glVertex3f (0.0f, 0.0f, 0.0f);
+  glVertex3f (0.0f, len, 0.0f);
+  glVertex3f (0.0f, 0.0f, 0.0f);
+  glVertex3f (0.0f, 0.0f, len);
+  glEnd ();
+
+
+  glPushAttrib (GL_LIST_BIT);
+  glListBase (fontbase);
+
+  char buf[20];
+
+  glRasterPos3d (len, 0.0f, 0.0f);
+  sprintf (buf, "x");
+  glCallLists (strlen (buf), GL_UNSIGNED_BYTE, buf);
+  glRasterPos3d (0.0f, len, 0.0f);
+  sprintf (buf, "y");
+  glCallLists (strlen (buf), GL_UNSIGNED_BYTE, buf);
+  glRasterPos3d (0.0f, 0.0f, len);
+  sprintf (buf, "z");
+  glCallLists (strlen (buf), GL_UNSIGNED_BYTE, buf);
+
+  glPopAttrib ();
+  glEnable (GL_LIGHTING);
+
+  glMatrixMode (GL_PROJECTION); 
+  glPopMatrix();
+  glMatrixMode (GL_MODELVIEW); 
+  glPopMatrix();
+}
+
+
+void VisualScene :: DrawNetgenLogo ()
+{
+  if (!vispar.drawnetgenlogo) return;
+
+  glMatrixMode (GL_PROJECTION); 
+  glPushMatrix();
+  glLoadIdentity();
+
+  glMatrixMode (GL_MODELVIEW); 
+  glPushMatrix();
+  glLoadIdentity();
+
+  GLint viewport[4];
+  glGetIntegerv (GL_VIEWPORT, viewport);
+
+
+
+  glTranslatef (1, -1, 0.0);
+  glScalef (40.0 / viewport[2], 40.0 / viewport[3], 1);
+  glTranslatef (-6.0, 2.0, 0.0);
+  //  glMultMatrixf (rotmat);
+
+  glEnable (GL_COLOR_MATERIAL);
+  GLfloat textcol[3] = { 1 - backcolor,
+			 1 - backcolor,
+			 1 - backcolor };
+  glColor3fv (textcol);
+
+  glLineWidth (1.0f);
+
+  glPushAttrib (GL_LIST_BIT);
+  glListBase (fontbase);
+
+  char buf[20];
+
+  glRasterPos3d (0.0f, 0.0f, 0.0f);
+  sprintf (buf, "Netgen 4.3.1");
+  glCallLists (strlen (buf), GL_UNSIGNED_BYTE, buf);
+  glPopAttrib ();
+
+  glMatrixMode (GL_PROJECTION); 
+  glPopMatrix();
+  glMatrixMode (GL_MODELVIEW); 
+  glPopMatrix();
+}
+
+
+
+
+
+
+
+
+VisualSceneGeometry2d :: VisualSceneGeometry2d ()
+  : VisualScene()
+{
+  ;
+}
+
+VisualSceneGeometry2d :: ~VisualSceneGeometry2d ()
+{
+  ;
+}
+
+
+
+
+
+
+void VisualSceneGeometry2d :: DrawScene ()
+{
+  int i, j;
+
+  if (changeval != geometry2d->GetSplines().Size())
+    BuildScene();
+  changeval = geometry2d->GetSplines().Size();
+
+  
+  glClearColor(backcolor, backcolor, backcolor, 1.0);
+  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+  SetLight();
+
+  //  glEnable (GL_LIGHT0);
+  glDisable (GL_LIGHTING);
+  glPushMatrix();
+  glMultMatrixf (transformationmat);
+
+  //  SetClippingPlane ();
+
+  glShadeModel (GL_SMOOTH);
+  glEnable (GL_COLOR_MATERIAL);
+  glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
+  
+  //  float mat_col[] = { 0, 0, 1, 1 };
+  //  glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_col);
+  glColor3f (0, 0, 1);
+  
+
+  ARRAY<Point<2> > points, otherpoints;
+
+  for (i = 1; i <= geometry2d->GetSplines().Size(); i++)
+    {
+      geometry2d->GetSplines().Get(i)->GetPoints (20, points);
+      
+      glBegin (GL_LINE_STRIP);
+      for (j = 0; j < points.Size(); j++)
+	glVertex3f (points[j](0), points[j](1), 0);
+      glEnd(); 
+    }
+
+  glColor3f (1, 0, 0);
+
+  for (i = 1; i <= geometry2d->GetSplines().Size(); i++)
+    {
+      int other = geometry2d->GetSplines().Get(i)->copyfrom;
+      if (other != -1)
+	{
+	  geometry2d->GetSplines().Get(i)->GetPoints (6, points);
+	  geometry2d->GetSplines().Get(other)->GetPoints (6, otherpoints);
+	  glBegin (GL_LINES);
+	  for (j = 1; j < 5; j++)
+	    {
+	      glVertex3f (points[j](0), points[j](1), 0);
+	      glVertex3f (otherpoints[j](0), otherpoints[j](1), 0);
+	    }
+	  glEnd ();
+	}
+    }
+
+
+
+  glPopMatrix();
+  
+  DrawCoordinateCross ();
+  DrawNetgenLogo ();
+
+  glFinish();  
+}
+
+
+void VisualSceneGeometry2d :: BuildScene (int zoomall)
+{
+  Box<2> bbox;
+
+  geometry2d->GetBoundingBox (bbox);
+  
+  Point<2> c = Center (bbox.PMin(), bbox.PMax());
+
+  center = Point3d (c(0), c(1), 0);
+  rad = Dist (bbox.PMin(), bbox.PMax()) / 2;
+
+  CalcTransformationMatrices();
+}
+
+
+
+
+
+
+
+
+
+
+/* *********************** Draw STL Geometry **************** */
+
+
+VisualSceneSTLGeometry :: VisualSceneSTLGeometry ()
+  : VisualScene()
+{
+  ;
+}
+
+VisualSceneSTLGeometry :: ~VisualSceneSTLGeometry ()
+{
+  ;
+}
+
+void VisualSceneSTLGeometry :: DrawScene ()
+{
+  int i, j, k;
+
+  if (changeval != stlgeometry->GetNT())
+    BuildScene();
+
+  changeval = stlgeometry->GetNT();
+
+
+  glClearColor(backcolor, backcolor, backcolor, 1.0);
+  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+  SetLight();
+
+
+  glPushMatrix();
+  glMultMatrixf (transformationmat);
+
+
+
+
+  glShadeModel (GL_SMOOTH);
+  glDisable (GL_COLOR_MATERIAL);
+  glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
+
+  glEnable (GL_BLEND);
+  glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+
+  double shine = vispar.shininess;
+  double transp = vispar.transp;
+
+  glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, shine);
+  glLogicOp (GL_COPY);
+
+
+  float mat_col[] = { 0.2, 0.2, 0.8, 1 };
+  glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_col);
+
+  glPolygonOffset (1, 1);
+  glEnable (GL_POLYGON_OFFSET_FILL);
+
+  glCallList (trilists.Get(1));
+
+  glDisable (GL_POLYGON_OFFSET_FILL);
+
+
+  int showtrias = vispar.showstltrias;
+
+  if (showtrias)
+    {
+      float mat_coll[] = { 0.2, 0.2, 0.2, 1 };
+      glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_coll);
+      glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
+      
+      glCallList (trilists.Get(1));
+    }
+
+  /*
+
+  glBegin (GL_TRIANGLES);
+  for (j = 1; j <= stlgeometry -> GetNT(); j++)
+    {
+      const STLTriangle & tria = stlgeometry -> GetTriangle(j);
+      glNormal3f (tria.normal.X(),
+		  tria.normal.Y(),
+		  tria.normal.Z());
+		  
+      for (k = 0; k < 3; k++)
+	{
+	  glVertex3f (tria.pts[k].X(),
+		      tria.pts[k].Y(),
+		      tria.pts[k].Z());
+	}
+    }    
+  glEnd ();
+  */  
+
+
+
+ 
+  glPopMatrix();
+  glFinish();  
+}
+
+
+void VisualSceneSTLGeometry :: BuildScene (int zoomall)
+{
+  int i, j, k;
+  
+  // cout << "rebuild stl geometry scene" << endl;
+
+  center = stlgeometry -> GetBoundingBox().Center();
+  rad = stlgeometry -> GetBoundingBox().Diam() / 2;
+
+
+  CalcTransformationMatrices();
+
+  for (i = 1; i <= trilists.Size(); i++)
+    glDeleteLists (trilists.Elem(i), 1);
+  trilists.SetSize(0);
+
+
+  trilists.Append (glGenLists (1));
+  glNewList (trilists.Last(), GL_COMPILE);
+
+  glEnable (GL_NORMALIZE);
+
+
+  glBegin (GL_TRIANGLES);
+  for (j = 1; j <= stlgeometry -> GetNT(); j++)
+    {
+      const Vec3d & n = stlgeometry->GetTriangle(j).Normal();
+      glNormal3f (n.X(), n.Y(), n.Z());
+      
+      for (k = 1; k <= 3; k++)
+	{
+	  const Point3d & p = 
+	    stlgeometry->GetPoint (stlgeometry -> GetTriangle(j).PNum(k));
+	  glVertex3f (p.X(),p.Y(), p.Z());
+ 
+	  //	  int pi = ta.GetTriangle(j).PNum(k);
+	  //	  glNormal3f (ta.GetNormal (pi).X(),
+	  //	      ta.GetNormal (pi).Y(),
+	  //	      ta.GetNormal (pi).Z());
+	  //	  glVertex3f (ta.GetPoint(pi).X(),
+	  //	      ta.GetPoint(pi).Y(),
+	  //	      ta.GetPoint(pi).Z());
+	}
+    }    
+  glEnd ();
+      
+  glEndList ();
+}
+
+
+
+#ifdef OCCGEOMETRY
+/* *********************** Draw OCC Geometry **************** */
+
+
+VisualSceneOCCGeometry :: VisualSceneOCCGeometry ()
+  : VisualScene()
+{
+  trilists.SetSize(0);
+  linelists.SetSize(1);
+}
+
+VisualSceneOCCGeometry :: ~VisualSceneOCCGeometry ()
+{
+  ;
+}
+
+void VisualSceneOCCGeometry :: DrawScene ()
+{
+  int i, j, k;
+
+
+  if ( occgeometry->changed )
+    {
+      BuildScene();
+      occgeometry -> changed = 0;
+    }
+
+  glClearColor(backcolor, backcolor, backcolor, 1.0);
+  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+  SetLight();
+
+  //  glEnable (GL_COLOR_MATERIAL);
+
+  //  glDisable (GL_SHADING);
+  //  glColor3f (0.0f, 1.0f, 1.0f);
+  //  glLineWidth (1.0f);
+  //  glShadeModel (GL_SMOOTH);
+
+  //  glCallList (linelists.Get(1));
+
+  //  SetLight();
+
+  glPushMatrix();
+  glMultMatrixf (transformationmat);
+
+  glShadeModel (GL_SMOOTH);
+  glDisable (GL_COLOR_MATERIAL);
+  glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
+
+  glEnable (GL_BLEND);
+  glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+  //  glEnable (GL_LIGHTING);
+
+  double shine = vispar.shininess;
+  double transp = vispar.transp;
+
+  glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, shine);
+  glLogicOp (GL_COPY);
+
+
+  float mat_col[] = { 0.2, 0.2, 0.8, 1 };
+  glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_col);
+
+  glPolygonOffset (1, 1);
+  glEnable (GL_POLYGON_OFFSET_FILL);
+
+  glCallList (linelists.Get(1));
+
+  glDisable (GL_POLYGON_OFFSET_FILL);
+ 
+  glPopMatrix();
+  DrawCoordinateCross ();
+  DrawNetgenLogo ();
+  glFinish();  
+
+  glDisable (GL_POLYGON_OFFSET_FILL);
+
+}
+
+
+void VisualSceneOCCGeometry :: BuildScene (int zoomall)
+{
+  int i = 0, j, k;
+  
+  Box3d box;
+
+  TopExp_Explorer ex, ex_edge;
+
+  for (ex.Init(occgeometry -> shape, TopAbs_VERTEX); ex.More(); ex.Next())
+    {
+      i++;
+      gp_Pnt p = BRep_Tool::Pnt (TopoDS::Vertex(ex.Current()));
+
+      if (i == 1) 
+	box.SetPoint (Point<3>(p.X(), p.Y(), p.Z()));
+      else
+	box.AddPoint (Point<3>(p.X(), p.Y(), p.Z()));
+    }
+
+  center = box.CalcCenter();
+  rad = box.CalcDiam() / 2;
+  
+  CalcTransformationMatrices();
+
+
+  linelists.Elem(1) = glGenLists (1);
+  glNewList (linelists.Last(), GL_COMPILE);
+
+  for (ex_edge.Init(occgeometry -> shape, TopAbs_EDGE);
+       ex_edge.More(); ex_edge.Next())
+    {
+      if (BRep_Tool::Degenerated(TopoDS::Edge(ex_edge.Current()))) continue;
+
+      glBegin (GL_LINE_STRIP);
+
+      double s0, s1, s;
+      Handle(Geom_Curve) c = BRep_Tool::Curve(TopoDS::Edge(ex_edge.Current()), s0, s1);
+      double d = s1-s0;
+      int i;
+      
+      for (i = 0; i<=50; i++)
+	{
+	  s = s0 + i*d/50;
+	  gp_Pnt p = c->Value (s);
+	  glVertex3f (p.X(),p.Y(), p.Z());
+	}
+
+      glEnd ();
+    }
+
+  //    glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
+
+  glBegin (GL_TRIANGLES);
+  //  int nfaces = occgeometry -> fmap.Extent();
+
+  i = 0;
+
+  TopExp_Explorer exp0, exp1, exp2, exp3;
+
+  //  BRepMesh::Mesh (occgeometry -> shape, occgeometry -> MaxSize()/100);
+
+  for (exp0.Init(occgeometry -> shape, TopAbs_SOLID); exp0.More(); exp0.Next())
+    for (exp1.Init(exp0.Current(), TopAbs_SHELL); exp1.More(); exp1.Next())
+      for (exp2.Init(exp1.Current().Composed(exp0.Current().Orientation()), TopAbs_FACE); exp2.More(); exp2.Next())
+	{
+	  TopoDS_Face face = TopoDS::Face (exp2.Current().Composed(exp1.Current().Orientation()));
+
+	  TopLoc_Location loc;
+	  Handle(Geom_Surface) surf = BRep_Tool::Surface (face);
+	  BRepAdaptor_Surface sf(face, Standard_False);
+	  BRepLProp_SLProps prop(sf, 1, 1e-5);
+
+	  //	  BRepMesh::Mesh (face, 1e-3);
+	  (*testout) << "meshing face " << ++i << endl;
+	  {
+	    int edges = 0;
+	    for (exp3.Init (face, TopAbs_EDGE); exp3.More(); exp3.Next())
+	      {
+		edges++;
+		(*testout) << "edge " << edges;
+		if (BRep_Tool::Degenerated(TopoDS::Edge(exp3.Current())))
+		  (*testout) << " degenerated";
+		(*testout) << endl;
+	      }
+	  }
+	  BRepMesh::Mesh (face, occgeometry -> MaxSize()/100);
+	  (*testout) << "done" << endl;
+	  //	  cout << "Warning: mvdraw fixed meshing size for visualization" << endl;
+	  // cout << "face " << ++i << endl;
+
+	  Handle(Poly_Triangulation) triangulation = BRep_Tool::Triangulation (face, loc);
+	  if (!triangulation) continue;
+	  
+	  int ntriangles = triangulation -> NbTriangles();
+	  //	  cout << "nbtriangles = " << ntriangles << endl;
+	  for (j = 1; j <= ntriangles; j++)
+	    {
+	      // (*testout) << "drawing trig " << j << "/" << ntriangles << " " << flush;
+	      //	      cout << "j = " << j << endl;
+	      Poly_Triangle triangle = (triangulation -> Triangles())(j);
+	      for (k = 1; k <= 3; k++)
+		{
+		  (*testout) << "." << flush;
+		  gp_Pnt2d uv = (triangulation -> UVNodes())(triangle(k));
+		  gp_Pnt pnt;
+		  gp_Vec du, dv;
+		  prop.SetParameters (uv.X(), uv.Y());
+		  surf->D0 (uv.X(), uv.Y(), pnt);
+		  gp_Vec n;
+
+		  if (prop.IsNormalDefined())
+		    {
+		      n = prop.Normal();
+		    }
+		  else
+		    n = gp_Vec (0,0,0);
+
+
+		  //		  surf->D1 (uv.X(), uv.Y(), pnt, du, dv);
+		  //		  gp_Vec n = du.Crossed(dv).Normalized();
+		  if (face.Orientation() == TopAbs_REVERSED) n *= -1;
+		  glNormal3f (n.X(), n.Y(), n.Z());
+		  glVertex3f (pnt.X(), pnt.Y(), pnt.Z());
+		}
+	      (*testout) << endl;
+	    }
+	}
+  
+  glEnd ();
+
+
+
+  glEndList ();
+
+}
+
+#endif
+
+
+
+#ifdef STEP
+
+/* *********************** Draw STEP Geometry **************** */
+
+
+VisualSceneSTEPGeometry :: VisualSceneSTEPGeometry ()
+  : VisualScene ()
+{
+  gllists.SetSize(0);
+}
+
+
+VisualSceneSTEPGeometry :: ~VisualSceneSTEPGeometry ()
+{
+  cout << "VisualSceneSTEPGeometry::~VisualSceneSTEPGeometry called "
+       << "but not implemented" << endl;
+}
+  
+
+void VisualSceneSTEPGeometry :: BuildScene (int zoomall)
+{
+  cout << "VisualSceneSTEPGeometry::BuildScene called" << endl;
+
+  const VisualApproximation & visapprox = 
+    stepgeometry->GetVisualApproximation();
+
+  INDEX i, k, pi;
+
+  Box3d box;
+  int hasp = 0;
+
+  for (i = 1; i <= visapprox.GetNP(); i++)      
+    {
+      if (hasp)
+	box.AddPoint (visapprox.GetPoint(i));
+      else
+	{
+	  hasp = 1;
+	  box.SetPoint (visapprox.GetPoint(i));
+	}
+    }
+  if (hasp)
+    {
+      center = box.CalcCenter();
+      rad = box.CalcDiam() / 2;
+    }
+
+  cout << "center " << center << endl
+       << "radius " << rad << endl;
+
+  CalcTransformationMatrices();
+
+  for (i = 1; i <= gllists.Size(); i++)
+    glDeleteLists (gllists.Elem(i), 1);
+  gllists.SetSize(0);
+
+  // build list of points
+  gllists.Append (glGenLists (1));
+  glNewList (gllists.Last(), GL_COMPILE);
+   
+  glPointSize( 3.0 );
+
+  glBegin( GL_POINTS );
+    for (i = 1; i <= visapprox.GetNP(); i++)
+      {
+	const Point3d & p = visapprox.GetPoint(i);
+        glVertex3f( p.X(), p.Y(), p.Z());
+      }
+  glEnd();
+
+  glEndList();
+
+  // build list of segments
+  gllists.Append (glGenLists (1));
+  glNewList (gllists.Last(), GL_COMPILE);
+   
+  glLineWidth( 1.0f );
+
+  glBegin(GL_LINES);
+    for (i = 1; i <= visapprox.GetNSeg(); i++)
+      {
+	for (k = 1; k <= 2; k++)
+	  {
+	    pi = visapprox.GetSegment(i).PNum(k);
+	    glVertex3f(visapprox.GetPoint(pi).X(),
+		       visapprox.GetPoint(pi).Y(),
+		       visapprox.GetPoint(pi).Z());
+	  }
+      }    
+  glEnd();
+
+  glEndList();
+}
+
+
+void VisualSceneSTEPGeometry :: DrawScene ()
+{
+  if (! stepgeometry)
+    {
+      cerr << "VisualSceneSTEPGeometry::DrawScene: no STEP geometry" << endl;
+      return;
+    }
+
+  const VisualApproximation & visapprox = 
+    stepgeometry -> GetVisualApproximation();
+  if (changeval != visapprox.GetNP())
+    BuildScene();
+
+  changeval = visapprox.GetNP();
+
+  glClearColor(backcolor, backcolor, backcolor, 1.0);
+  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+  glPushMatrix();
+  glMultMatrixf (transformationmat);
+
+  // draw segments
+//   float mat_coll[] = { 0.2, 0.2, 0.2, 1 };
+//   glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_coll);
+//   glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
+
+  glEnable (GL_COLOR_MATERIAL);
+  glColor3f(0.0, 1.0, 0.0);
+  glCallList (gllists.Get(2));
+  glColor3f (1.0, 0.0, 0.0);
+  glCallList (gllists.Get(1));
+
+  glPopMatrix();
+  glFinish();
+}
+
+#endif
+
+
+
+
+
+
+
+
+
+
+VisualSceneSpecPoints :: VisualSceneSpecPoints ()
+  : VisualScene()
+{
+  ;
+}
+
+VisualSceneSpecPoints :: ~VisualSceneSpecPoints ()
+{
+  ;
+}
+
+
+void VisualSceneSpecPoints :: DrawScene ()
+{
+  int i, j, k;
+
+
+  if (!mesh) 
+    {
+      VisualScene::DrawScene();
+      return;
+    }
+
+  if (changeval != specpoints.Size())
+    BuildScene();
+  changeval = specpoints.Size();
+
+
+
+  glClearColor(backcolor, backcolor, backcolor, 1.0);
+  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+  glEnable (GL_COLOR_MATERIAL);
+  glColor3f (1.0f, 1.0f, 1.0f);
+  glLineWidth (1.0f);
+
+  glPushMatrix();
+  glMultMatrixf (transformationmat);
+
+  //  glEnable (GL_COLOR);
+  //  glDisable (GL_COLOR_MATERIAL);
+  if (vispar.drawedtangents)
+    {
+      glColor3d (1, 0, 0);
+      glBegin (GL_LINES);
+      for (i = 1; i <= specpoints.Size(); i++)
+	{
+	  const Point3d p1 = specpoints.Get(i).p;
+	  const Point3d p2 = specpoints.Get(i).p + len * specpoints.Get(i).v;
+	  glVertex3d (p1.X(), p1.Y(), p1.Z());
+	  glVertex3d (p2.X(), p2.Y(), p2.Z());
+	}
+      glEnd();
+    }
+
+  if (vispar.drawededges)
+    {
+      glColor3d (1, 0, 0);
+      glBegin (GL_LINES);
+      for (i = 1; i <= mesh->GetNSeg(); i++)
+	{
+	  const Segment & seg = mesh -> LineSegment (i);
+	  const Point3d p1 = mesh -> Point (seg.p1);
+	  const Point3d p2 = mesh -> Point (seg.p2);
+	  glVertex3d (p1.X(), p1.Y(), p1.Z());
+	  glVertex3d (p2.X(), p2.Y(), p2.Z());
+	}
+      glEnd();
+    }
+
+  if (vispar.drawededgenrs)
+    {
+      glEnable (GL_COLOR_MATERIAL);
+      GLfloat textcol[3] = { 1 - backcolor,
+			       1 - backcolor,
+			       1 - backcolor };
+      glColor3fv (textcol);
+      glNormal3d (0, 0, 1);
+      glPushAttrib (GL_LIST_BIT);
+      glListBase (fontbase);
+
+      char buf[20];
+      for (i = 1; i <= mesh->GetNSeg(); i++)
+	{
+	  const Segment & seg = mesh -> LineSegment (i);
+	  const Point3d p1 = mesh -> Point (seg.p1);
+	  const Point3d p2 = mesh -> Point (seg.p2);
+
+	  const Point3d p = Center (p1, p2);
+	  glRasterPos3d (p.X(), p.Y(), p.Z());
+	  
+	  sprintf (buf, "%d", seg.edgenr);
+	  glCallLists (strlen (buf), GL_UNSIGNED_BYTE, buf);
+	}
+      
+      glPopAttrib ();
+      glDisable (GL_COLOR_MATERIAL);
+    }
+
+
+  if (vispar.drawedpoints)
+    {
+      glColor3d (0, 0, 1);
+      glPointSize( 3.0 );
+
+      glBegin( GL_POINTS );
+      for (i = 1; i <= mesh -> GetNP(); i++)
+	{
+	  const Point3d & p = mesh -> Point(i);
+	  glVertex3f( p.X(), p.Y(), p.Z());
+	}
+      glEnd();
+    }
+
+  if (vispar.drawedpointnrs)
+    {
+      glEnable (GL_COLOR_MATERIAL);
+      GLfloat textcol[3] = { 1 - backcolor,
+			       1 - backcolor,
+			       1 - backcolor };
+      glColor3fv (textcol);
+      glNormal3d (0, 0, 1);
+      glPushAttrib (GL_LIST_BIT);
+      glListBase (fontbase);
+      
+      char buf[20];
+      for (i = 1; i <= mesh->GetNP(); i++)
+	{
+	  const Point3d & p = mesh->Point(i);
+	  glRasterPos3d (p.X(), p.Y(), p.Z());
+	  
+	  sprintf (buf, "%d", i);
+	  glCallLists (strlen (buf), GL_UNSIGNED_BYTE, buf);
+	}
+      
+      glPopAttrib ();
+      glDisable (GL_COLOR_MATERIAL);
+    }
+
+
+  glPopMatrix();
+
+  if (vispar.drawcoordinatecross)
+    DrawCoordinateCross ();
+  DrawNetgenLogo ();
+
+  glFinish();  
+}
+
+
+void VisualSceneSpecPoints :: BuildScene (int zoomall)
+{
+  int i, j, k;
+  
+  if (!mesh) 
+    {
+      VisualScene::BuildScene(zoomall);
+      return;
+    }
+
+  Box3d box;
+
+  if (mesh->GetNSeg())
+    {
+      box.SetPoint (mesh->Point (mesh->LineSegment(1).p1));
+      for (i = 1; i <= mesh->GetNSeg(); i++)
+	{
+	  box.AddPoint (mesh->Point (mesh->LineSegment(i).p1));
+	  box.AddPoint (mesh->Point (mesh->LineSegment(i).p2));
+	}
+    }
+  else if (specpoints.Size() >= 2)
+    {
+      box.SetPoint (specpoints.Get(1).p);
+      for (i = 2; i <= specpoints.Size(); i++)
+	box.AddPoint (specpoints.Get(i).p);
+    }
+  else
+    {
+      box = Box3d (Point3d (0,0,0), Point3d (1,1,1));
+    }
+  
+  if (zoomall == 2 && vispar.centerpoint >= 1 && vispar.centerpoint <= mesh->GetNP())
+    center = mesh->Point (vispar.centerpoint);
+  else
+    center = Center (box.PMin(), box.PMax());
+
+  rad = 0.5 * Dist (box.PMin(), box.PMax());
+  
+
+  CalcTransformationMatrices();
+}
+
+}
diff --git a/Netgen/libsrc/visualization/mvdraw.hpp b/Netgen/libsrc/visualization/mvdraw.hpp
new file mode 100644
index 0000000000..691ac246cb
--- /dev/null
+++ b/Netgen/libsrc/visualization/mvdraw.hpp
@@ -0,0 +1,352 @@
+#ifndef FILE_MVDRAW
+#define FILE_MVDRAW
+
+class VisualizationParameters
+{
+public:
+  double lightamb;
+  double lightdiff;
+  double lightspec;
+  double shininess;
+  double transp;
+  int locviewer;
+  char selectvisual[20];
+  int showstltrias;
+  
+  Vec3d clipnormal;
+  double clipdist;
+  int clipenable;
+  int clipplanetimestamp;
+
+  int colormeshsize;
+
+  int drawfilledtrigs;
+  int drawbadels;
+  int drawoutline;
+  int drawedges;
+  int subdivisions;
+
+  int drawprisms;
+  int drawpyramids;
+  int drawhexes;
+  double shrink;
+  int drawidentified;
+  int drawpointnumbers;
+  int drawedgenumbers;
+  int drawfacenumbers;
+  int drawelementnumbers;
+  int drawdomainsurf;
+  int drawtets;
+  int drawtetsdomain;
+
+  int drawededges;
+  int drawedpoints;
+  int drawedpointnrs;
+  int drawedtangents;
+  int drawededgenrs;
+
+  int drawcurveproj;
+  int drawcurveprojedge;
+  
+
+  int centerpoint;
+  int drawelement;
+
+  // stl:
+  int stlshowtrias;
+  int stlshowfilledtrias;
+  int stlshowedges;
+  int stlshowmarktrias;
+  int stlshowactivechart;
+  int stlchartnumber;
+  int stlchartnumberoffset;
+
+  bool whitebackground;
+  int stereo;
+  bool usedispllists;
+  bool drawcoordinatecross;
+  bool drawcolorbar;
+  bool drawnetgenlogo;
+
+  
+public:
+  VisualizationParameters();
+};
+extern VisualizationParameters vispar;
+
+
+
+extern void InitDrawMesh ();
+extern void DrawMesh ();
+extern void MouseMove(int oldx, int oldy,
+		      int newx, int newy,
+		      char mode);
+
+extern void Render ();
+
+
+class VisualScene
+{
+protected:
+  static Point3d center;
+  static double rad;
+
+  static float lookatmat[16];
+  static float transmat[16];
+  static float rotmat[16];
+  static float centermat[16];
+  static float transformationmat[16];
+
+  GLdouble clipplane[4];
+
+  int changeval;
+  static double backcolor;
+
+public:
+  static GLuint fontbase;
+  static GLubyte * colortexture;
+  static GLuint coltexname;
+  static int ntexcols;
+  // static bool linear_colors;
+  int invcolor;
+
+
+public:
+  VisualScene ();
+  virtual ~VisualScene();
+
+  virtual void BuildScene (int zoomall = 0);
+  virtual void DrawScene ();
+  
+  void CalcTransformationMatrices();
+  void StandardRotation (const char * dir);
+
+  void MouseMove(int oldx, int oldy,
+		 int newx, int newy,
+		 char mode);
+
+  void LookAt (const Point<3> & cam, const Point<3> & obj,
+	       const Point<3> & camup);
+
+  void SetClippingPlane ();
+
+  virtual void MouseDblClick (int px, int py);
+
+  void SetLight ();
+  static void SetBackGroundColor (double col)
+    { backcolor = col; }
+
+  void CreateTexture (int ncols, int linear);
+  void DrawColorBar (double minval, double maxval, int logscale = 0);
+  void DrawCoordinateCross ();
+  void DrawNetgenLogo ();
+  void SetOpenGlColor(double val, double valmin, double valmax, int logscale = 0);
+};
+
+
+class VisualSceneGeometry : public VisualScene
+{
+  ARRAY<int> trilists;
+  int selsurf;
+public:
+  VisualSceneGeometry ();
+  virtual ~VisualSceneGeometry ();
+
+  virtual void SelectSurface (int aselsurf);
+  virtual void BuildScene (int zoomall = 0);
+  virtual void DrawScene ();
+};
+
+
+
+class VisualSceneSTLGeometry : public VisualScene
+{
+  ARRAY<int> trilists;
+  
+public:
+  VisualSceneSTLGeometry ();
+  virtual ~VisualSceneSTLGeometry ();
+
+  virtual void BuildScene (int zoomall = 0);
+  virtual void DrawScene ();
+};
+
+
+class VisualSceneGeometry2d : public VisualScene
+{
+public:
+  VisualSceneGeometry2d ();
+  virtual ~VisualSceneGeometry2d ();
+
+  virtual void BuildScene (int zoomall = 0);
+  virtual void DrawScene ();
+};
+
+
+#ifdef OCCGEOMETRY
+class VisualSceneOCCGeometry : public VisualScene
+{
+  ARRAY<int> trilists;
+  ARRAY<int> linelists;
+  int selsurf;
+public:
+  VisualSceneOCCGeometry ();
+  virtual ~VisualSceneOCCGeometry ();
+
+  virtual void BuildScene (int zoomall = 0);
+  virtual void DrawScene ();
+};
+#endif
+
+
+
+
+#ifdef STEP
+class VisualSceneSTEPGeometry : public VisualScene
+{
+  ARRAY<int> gllists;
+  
+public:
+  VisualSceneSTEPGeometry ();
+  virtual ~VisualSceneSTEPGeometry ();
+
+  virtual void BuildScene (int zoomall = 0);
+  virtual void DrawScene ();
+};
+#endif
+
+
+class VisualSceneSTLMeshing : public VisualScene
+{
+  ARRAY<int> trilists;
+  int selecttrig, nodeofseltrig;
+
+public:
+  VisualSceneSTLMeshing ();
+  virtual ~VisualSceneSTLMeshing ();
+
+  virtual void BuildScene (int zoomall = 0);
+  virtual void DrawScene ();
+  virtual void MouseDblClick (int px, int py);
+
+  int seltria;
+};
+
+
+
+
+class VisualSceneSurfaceMeshing : public VisualScene
+{
+public:
+  VisualSceneSurfaceMeshing ();
+  virtual ~VisualSceneSurfaceMeshing ();
+
+  virtual void BuildScene (int zoomall = 0);
+  virtual void DrawScene ();
+};
+
+
+
+
+
+
+
+class VisualSceneMesh : public VisualScene
+{
+  int filledlist;
+  int linelist;
+  int pointnumberlist;
+
+  int tetlist;
+  int prismlist;
+  int pyramidlist;
+  int hexlist;
+
+  int badellist;
+  int identifiedlist;
+  int domainsurflist;
+
+  int vstimestamp, selecttimestamp;
+  int filledtimestamp;
+  int linetimestamp;
+  int pointnumbertimestamp;
+
+  int tettimestamp;
+  int prismtimestamp;
+  int pyramidtimestamp;
+  int hextimestamp;
+
+  int badeltimestamp;
+  int identifiedtimestamp;
+  int domainsurftimestamp;
+
+  NgLock *lock;
+
+  int selface, selelement;
+  int selpoint, selpoint2, locpi;
+  int seledge;
+
+  double minh, maxh; // for meshsize coloring
+
+public:
+  VisualSceneMesh ();
+  virtual ~VisualSceneMesh ();
+
+  virtual void BuildScene (int zoomall = 0);
+  virtual void DrawScene ();
+  virtual void MouseDblClick (int px, int py);
+
+  int SelectedFace () const
+    { return selface; }
+  void SetSelectedFace (int asf) 
+    { selface = asf; selecttimestamp = GetTimeStamp(); }
+
+  int SelectedEdge () const
+    { return seledge; }
+  int SelectedElement () const
+    { return selelement; }
+  int SelectedPoint () const
+    { return selpoint; }
+private:
+  void BuildFilledList();
+  void BuildLineList();
+  void BuildPointNumberList();
+
+  void BuildTetList();
+  void BuildPrismList();
+  void BuildPyramidList();
+  void BuildHexList();
+
+  void BuildBadelList();
+  void BuildIdentifiedList();
+  void BuildDomainSurfList();
+};
+
+
+
+
+
+
+
+class VisualSceneSpecPoints : public VisualScene
+{
+public:
+  VisualSceneSpecPoints ();
+  virtual ~VisualSceneSpecPoints ();
+
+  virtual void BuildScene (int zoomall = 0);
+  virtual void DrawScene ();
+
+  double len;
+};
+
+// extern struct Tcl_Interp * hinterp;
+
+
+extern void AddVisualizationScene (const string & name, 
+				   VisualScene * vs);
+
+
+
+#endif
+
diff --git a/Netgen/libsrc/visualization/soldata.hpp b/Netgen/libsrc/visualization/soldata.hpp
new file mode 100644
index 0000000000..b2c11cfbd0
--- /dev/null
+++ b/Netgen/libsrc/visualization/soldata.hpp
@@ -0,0 +1,41 @@
+#ifndef FILE_SOLDATA
+#define FILE_SOLDATA
+
+
+
+class SolutionData
+{
+protected:
+  std::string name;
+  int components;
+  bool iscomplex;
+
+  // int dist;
+  // int order;
+public:
+  SolutionData (const std::string & aname, 
+		int acomponents = 1, bool aiscomplex = 0)
+    : name(aname), components(acomponents), iscomplex(aiscomplex)
+  { ; }
+
+  virtual ~SolutionData ()
+  { ; }
+
+  int GetComponents() { return components; }
+  bool IsComplex() { return iscomplex; }
+
+  virtual bool GetValue (int elnr, 
+			 double lam1, double lam2, double lam3,
+			 double * values) 
+  { return 0; }
+
+  virtual bool GetSurfValue (int selnr,
+			     double lam1, double lam2, 
+			     double * values)
+  { return 0; }
+
+};
+
+
+#endif
+
diff --git a/Netgen/libsrc/visualization/stlmeshing.cpp b/Netgen/libsrc/visualization/stlmeshing.cpp
new file mode 100644
index 0000000000..3fdbbadaf7
--- /dev/null
+++ b/Netgen/libsrc/visualization/stlmeshing.cpp
@@ -0,0 +1,1080 @@
+#include <mystdlib.h>
+#include <myadt.hpp>
+
+#include <linalg.hpp>
+#include <stlgeom.hpp>
+
+#include <meshing.hpp>
+#include <visual.hpp>
+
+namespace netgen
+{
+
+/*
+//mmm
+#include "stlgeom/modeller.hpp"
+*/
+
+/* *********************** Draw STL Geometry **************** */
+
+extern STLGeometry * stlgeometry;
+extern AutoPtr<Mesh> mesh;
+
+
+#ifdef OPENGL
+
+// #include "../../ngtcltk/mvdraw.hpp"
+
+
+VisualSceneSTLMeshing :: VisualSceneSTLMeshing ()
+  : VisualScene()
+{
+  selecttrig = 0;
+  nodeofseltrig = 1;
+  stlgeometry->SetSelectTrig(selecttrig);
+  stlgeometry->SetNodeOfSelTrig(nodeofseltrig);
+}
+
+VisualSceneSTLMeshing :: ~VisualSceneSTLMeshing ()
+{
+  ;
+}
+
+void VisualSceneSTLMeshing :: DrawScene ()
+{
+  int i, j, k;
+
+  if (changeval != stlgeometry->GetNT())
+    BuildScene();
+  changeval = stlgeometry->GetNT();
+
+  int colormeshsize = vispar.colormeshsize;
+  
+  double hmin, hmax;
+
+  if (colormeshsize)
+    {
+      hmax = -1E50;
+      hmin = +1E50;
+      double ms;
+
+      for (i = 1; i <= stlgeometry->GetNP(); i++)
+	{
+	  ms = mesh->GetH (stlgeometry->GetPoint(i));
+	  hmin = min2(hmin,ms);
+	  hmax = max2(hmax,ms);
+	}
+
+      //hmax = mparam.maxh;
+      //hmin = mesh->GetMinH (stlgeometry->GetBoundingBox().PMin(),
+      //			    stlgeometry->GetBoundingBox().PMax());
+  
+      if (hmin == 0) hmin = 0.1 * hmax;
+      //hmax *= 1.1;
+    }
+  
+
+
+  glClearColor(backcolor, backcolor, backcolor, 1.0);
+  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+
+  SetLight();
+
+  glPushMatrix();
+  glMultMatrixf (transformationmat);
+
+  SetClippingPlane ();
+
+  glShadeModel (GL_SMOOTH);
+  glDisable (GL_COLOR_MATERIAL);
+  glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
+
+  glEnable (GL_BLEND);
+  glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+  float mat_spec_col[] = { 1, 1, 1, 1 };
+  glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, mat_spec_col);
+
+  double shine = vispar.shininess;
+  double transp = vispar.transp;
+
+  glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, shine);
+  glLogicOp (GL_COPY);
+
+  float mat_colred[] = { 0.9, 0.0, 0.0, 1 };
+  float mat_colgreen[] = { 0.0, 0.9, 0.0, 1 };
+  float mat_colblue[] = { 0.1, 0.1, 1., 1 };
+
+  float mat_colbluegreen[] = { 0.1, 0.5, 0.9, 1 };
+  float mat_colpink[] = { 1., 0.1, 0.5, 1 };
+  float mat_colviolet[] = { 1., 0.1, 1., 1 };
+  float mat_colbrown[] = { 0.8, 0.6, 0.1, 1 };
+  float mat_colorange[] = { 0.9, 0.7, 0.1, 1 };
+  float mat_colturquis[] = { 0.0, 1., 0.8, 1 };
+
+  float mat_colgrey[] = { 0.3, 0.3, 0.3, 1 };
+
+  float mat_collred[] = { 1., 0.5, 0.5, 1 };
+  float mat_collgreen[] = { 0.2, 1., 0.2, 1 };
+  float mat_collbrown[] = { 1., 0.8, 0.3, 1 };
+
+  float mat_collgrey[] = { 0.8, 0.8, 0.8, 1 };
+  float mat_colmgrey[] = { 0.4, 0.4, 0.4, 1 };
+
+  float mat_colstlbody[] = { 0., 0., 0.8, 1 };
+  float mat_colseltrig[] = { 0.7, 0.7, 0.3, 1 };
+  float mat_colseledge[] = { 0.7, 0.7, 1., 1 };
+
+  glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colblue);
+
+  float pgoff = 0.5;
+
+  glPolygonOffset (pgoff*1, pgoff*1);
+  glEnable (GL_POLYGON_OFFSET_FILL);
+
+  glEnable (GL_NORMALIZE);
+
+  /*
+  {
+    //mmm
+    //test modeller
+    Modeller model;
+    
+    //MoZylinder z1(Point3d(0,0,0),Vec3d(100,0,0),20,0.01);
+    //model.Add(&z1);
+    //MoZylinder z2(Point3d(50,50,0),Vec3d(0,-100,0),20,0.01);
+    //model.Add(&z2);
+    
+    MoZylinder z1(Point3d(0,0,0),Vec3d(100,0,0),20,0.01);
+    MoZylinder z2(Point3d(50,50,0),Vec3d(0,-100,0),20,0.01);
+    MoCombine cb1(&z1,&z2);
+    model.Add(&cb1);
+    
+    ARRAY<MoTriangle> trigs;
+    model.GetTriangles(trigs);
+    int i, k;
+    glBegin (GL_TRIANGLES);
+    for (i = 1; i <= trigs.Size(); i++)
+      {
+	const MoTriangle & tria = trigs.Get(i);
+	glNormal3f (tria.normal.X(),
+		    tria.normal.Y(),
+		    tria.normal.Z());
+	
+	for (k = 0; k < 3; k++)
+	  {
+	    glVertex3f (tria.pts[k].X(),
+			tria.pts[k].Y(),
+			tria.pts[k].Z());
+	  }
+      }    
+    glEnd ();
+    
+
+  }
+
+*/
+
+
+
+  
+  if (!stlgeometry->trigsconverted)
+    {
+      glBegin (GL_TRIANGLES);
+      for (j = 1; j <= stlgeometry -> GetNT(); j++)
+	{
+	  /*
+	  if (j % 10 == seltria)
+	    glMaterialfv (GL_FRONT_AND_BACK, 
+			  GL_AMBIENT_AND_DIFFUSE, mat_colred);
+	  */
+
+	  const Vec3d & n = stlgeometry->GetTriangle(j).Normal();
+	  glNormal3f (n.X(), n.Y(), n.Z());
+	  /*
+	  const STLReadTriangle & tria = stlgeometry -> GetReadTriangle(j);
+	  glNormal3f (tria.normal.X(),
+		      tria.normal.Y(),
+		      tria.normal.Z());
+	  */
+
+	  
+	  for (k = 1; k <= 3; k++)
+	    {
+	      const Point3d & tp = stlgeometry->GetPoint(stlgeometry->GetTriangle(j).PNum(k));
+	      glVertex3f (tp.X(), tp.Y(), tp.Z());
+
+	    }
+	  /*
+	  if (j%10 == seltria)
+	    glMaterialfv (GL_FRONT_AND_BACK, 
+			  GL_AMBIENT_AND_DIFFUSE, mat_colblue);
+	  */
+	}    
+      glEnd ();
+  
+      glDisable (GL_POLYGON_OFFSET_FILL);
+
+      int showtrias = vispar.stlshowtrias;
+
+      if (showtrias)
+	{
+	  float mat_coll[] = { 0.2, 0.2, 0.2, 1 };
+	  glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_coll);
+	  glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
+      
+	  glEnable (GL_NORMALIZE);
+      
+	  glBegin (GL_TRIANGLES);
+	  for (j = 1; j <= stlgeometry -> GetNT(); j++)
+	    {
+	      const Vec3d & n = stlgeometry->GetTriangle(j).Normal();
+	      glNormal3f (n.X(), n.Y(), n.Z());
+	      /*
+	      const STLReadTriangle & tria = stlgeometry -> GetReadTriangle(j);
+	      glNormal3f (tria.normal.X(),
+			  tria.normal.Y(),
+			  tria.normal.Z());
+	      */  
+
+	      for (k = 1; k <= 3; k++)
+		{
+		  const Point3d & tp = 
+		    stlgeometry->GetPoint(stlgeometry->GetTriangle(j).PNum(k));
+		  glVertex3f (tp.X(), tp.Y(), tp.Z());
+		  
+		}
+	      
+	      /*
+	      for (k = 0; k < 3; k++)
+		{
+		  glVertex3f (tria.pts[k].X(),
+			      tria.pts[k].Y(),
+			      tria.pts[k].Z());
+		}
+	      */
+	    }    
+	  glEnd ();
+	}
+    }
+  else
+    {
+      int showfilledtrias = vispar.stlshowfilledtrias;
+
+      //(*mycout) << "in " << showfilledtrias << ", NT=" << stlgeometry -> GetNT() << endl;
+
+      int chartnumber;
+      if (vispar.stlshowmarktrias)
+	chartnumber = vispar.stlchartnumber + vispar.stlchartnumberoffset;
+      else
+	chartnumber = stlgeometry->GetMeshChartNr();
+
+      if (showfilledtrias)
+	{
+	  glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
+	  if (colormeshsize)
+	    glEnable (GL_COLOR_MATERIAL);
+	  
+	  glPolygonOffset (pgoff*4, pgoff*4);
+	  glEnable (GL_POLYGON_OFFSET_FILL);
+	  glEnable (GL_NORMALIZE);
+
+
+	  glBegin (GL_TRIANGLES);
+
+	  int selt = stlgeometry -> GetSelectTrig();
+	  if (stldoctor.selectmode != 0) 
+	    {selt = 0; } //do not show selected triangle!!!!
+
+	  glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colstlbody);
+
+	  for (j = 1; j <= stlgeometry -> GetNT(); j++)
+	    {
+	      if (stldoctor.showvicinity && !stlgeometry->Vicinity(j)) {continue;}
+
+	      if (j == selt)
+		{
+		  glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colseltrig);
+		}
+	      else if (j == selt+1)
+		{
+		  glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colstlbody);
+		}
+	      
+	      const STLTriangle& st = stlgeometry -> GetTriangle(j);
+
+	      const Vec3d & n = stlgeometry->GetTriangle(j).Normal();
+	      glNormal3f (n.X(), n.Y(), n.Z());
+	  
+	      /*
+	      const STLReadTriangle& tria = stlgeometry -> GetReadTriangle(j);
+	      glNormal3f (tria.normal.X(),
+			  tria.normal.Y(),
+			  tria.normal.Z());
+	      */
+	      for (k = 0; k < 3; k++)
+		{
+		  const Point3d & p = stlgeometry->GetPoint(st[k]);
+		  if (colormeshsize)
+		    {
+		      SetOpenGlColor (mesh->GetH (p), hmin, hmax, 1);
+		    }
+
+		  glVertex3f (p.X(), p.Y(), p.Z());
+		}
+	    } 
+   
+	  glEnd ();
+	}
+      
+      int foundseltrig = stlgeometry -> GetSelectTrig();
+      if (foundseltrig == 0 || foundseltrig > stlgeometry->GetNT() ||
+	  (stldoctor.showvicinity && !stlgeometry->Vicinity(foundseltrig)))
+	{foundseltrig = 0;}
+
+      if (foundseltrig)
+	{
+
+	  glPolygonOffset (pgoff*0, 0);
+	  glEnable (GL_POLYGON_OFFSET_FILL);
+
+	  //glDisable (GL_POLYGON_OFFSET_FILL);      
+	  glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colseledge);
+	  glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
+	  
+	  glEnable (GL_NORMALIZE);
+
+	  if (stldoctor.selectmode == 2)
+	    {
+	      //point
+	      const STLTriangle& st = stlgeometry -> GetTriangle(foundseltrig);
+	      const Point3d & p1 = stlgeometry->GetPoint(st[0]);
+	      const Point3d & p2 = stlgeometry->GetPoint(st[1]);
+	      const Point3d & p3 = stlgeometry->GetPoint(st[2]);
+
+	      double cs = (Dist(p1,p2)+Dist(p2,p3)+Dist(p3,p1))/100.;
+
+	      const Point3d & p = stlgeometry->GetPoint(st[nodeofseltrig-1]);
+	      
+	      glLineWidth (4);
+	      glBegin (GL_LINES);
+	      glVertex3f(p.X()+cs, p.Y()+cs, p.Z()+cs);
+	      glVertex3f(p.X()-cs, p.Y()-cs, p.Z()-cs);
+	      
+	      glVertex3f(p.X()-cs, p.Y()+cs, p.Z()+cs);
+	      glVertex3f(p.X()+cs, p.Y()-cs, p.Z()-cs);
+
+	      glVertex3f(p.X()-cs, p.Y()+cs, p.Z()+cs);
+	      glVertex3f(p.X()+cs, p.Y()-cs, p.Z()-cs);
+	      
+	      glVertex3f(p.X()+cs, p.Y()-cs, p.Z()+cs);
+	      glVertex3f(p.X()-cs, p.Y()+cs, p.Z()-cs);
+	      
+	      glEnd ();	  
+	      glLineWidth (1);
+	    }
+	  else if (stldoctor.selectmode == 1 || 
+		   stldoctor.selectmode == 3 || 
+		   stldoctor.selectmode == 4)
+	    {
+	      //multiedge
+	      
+	      const ARRAY<twoint>& me = stlgeometry->SelectedMultiEdge();
+	      if (stlgeometry->GetSelectTrig() > 0 && 
+		  stlgeometry->GetSelectTrig() <= stlgeometry->GetNT() &&
+		  me.Size())
+		{
+
+		  int en = stlgeometry->EdgeDataList().GetEdgeNum(me.Get(1).i1,me.Get(1).i2);
+		  int status = stlgeometry->EdgeDataList().Get(en).GetStatus();
+		  
+		  switch (status)
+		    {
+		    case ED_CONFIRMED:
+		      glMaterialfv (GL_FRONT_AND_BACK, 
+				    GL_AMBIENT_AND_DIFFUSE, mat_collgreen);
+		      break;
+		    case ED_CANDIDATE:
+		      glMaterialfv (GL_FRONT_AND_BACK, 
+				    GL_AMBIENT_AND_DIFFUSE, mat_collbrown);
+		      break;
+		    case ED_EXCLUDED:
+		      glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_collred);
+		      break;
+		    }
+
+		  glLineWidth (2);
+		  glBegin (GL_LINES);
+		  for (j = 1; j <= me.Size(); j++)
+		    { 
+		      Point3d p1 = stlgeometry->GetPoint(me.Get(j).i1);
+		      Point3d p2 = stlgeometry->GetPoint(me.Get(j).i2);
+		      
+		      glVertex3f(p1.X(), p1.Y(), p1.Z());
+		      glVertex3f(p2.X(), p2.Y(), p2.Z());
+		    }
+		  glEnd ();
+		  glLineWidth (1);
+		}
+	    }
+	}
+
+      int showmarktrias = vispar.stlshowmarktrias || vispar.stlshowactivechart;
+ 
+      if (stldoctor.showmarkedtrigs)
+	{
+	  //(*mycout) << "marked" << endl;
+	  glPolygonMode (GL_FRONT_AND_BACK, GL_LINE); //GL_LINE
+	  glPolygonOffset (pgoff*1, pgoff*1);
+	  glEnable (GL_POLYGON_OFFSET_FILL);
+	  glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colbluegreen);
+	  glEnable (GL_NORMALIZE);
+
+	  glBegin (GL_TRIANGLES);
+
+	  for (j = 1; j <= stlgeometry -> GetNT(); j++)
+	    {
+	      if (stldoctor.showvicinity && !stlgeometry->Vicinity(j)) 
+		{continue;}
+
+	      if (!stlgeometry->IsMarkedTrig(j)) 
+		{continue;}
+	      
+	      const STLTriangle& st = stlgeometry -> GetTriangle(j);
+
+	      const Vec3d & n = stlgeometry->GetTriangle(j).Normal();
+	      glNormal3f (n.X(), n.Y(), n.Z());
+	      /*
+	      const STLReadTriangle& tria = stlgeometry -> GetReadTriangle(j);
+	      glNormal3f (tria.normal.X(),
+			  tria.normal.Y(),
+			  tria.normal.Z());
+	      */
+	      for (k = 0; k < 3; k++)
+		{
+		  const Point3d & p = stlgeometry->GetPoint(st[k]);
+		  glVertex3f (p.X(), p.Y(), p.Z());
+		}
+	    }    
+	  glEnd ();
+
+	  //show OpenSegments on original geometry
+	  glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colviolet);
+	  glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
+	  glPolygonOffset (pgoff*1, 1);
+      
+	  glEnable (GL_NORMALIZE);
+      
+	  glBegin (GL_LINES);
+
+	  if (stlgeometry->GetNMarkedSegs())
+	    {
+	      Point<3> p1,p2;	      
+	      for (j = 1; j <= stlgeometry -> GetNMarkedSegs(); j++)
+		{
+		  stlgeometry->GetMarkedSeg(j,p1,p2);
+		  glVertex3dv(&p1(0));
+		  glVertex3dv(&p2(0));
+		}
+	    }
+	  glEnd ();
+	}
+
+
+      if (stldoctor.showfaces)
+	{
+	  int facenumber = vispar.stlchartnumber + vispar.stlchartnumberoffset;
+
+	  glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
+	  glPolygonOffset (pgoff*3, 3);
+	  glEnable (GL_POLYGON_OFFSET_FILL);
+	  glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_collgrey);
+	  glEnable (GL_NORMALIZE);
+
+	  glBegin (GL_TRIANGLES);
+
+	  for (j = 1; j <= stlgeometry -> GetNT(); j++)
+	    {
+	      if (stldoctor.showvicinity && !stlgeometry->Vicinity(j)) 
+		{continue;}
+
+	      //(*mycout) << " facenum = " << stlgeometry->GetTriangle(j).GetFaceNum() << " ";
+	      if (stlgeometry->GetTriangle(j).GetFaceNum() != facenumber) 
+		{continue;}
+	      
+	      const STLTriangle& st = stlgeometry -> GetTriangle(j);
+
+	      const Vec3d & n = stlgeometry->GetTriangle(j).Normal();
+	      glNormal3f (n.X(), n.Y(), n.Z());
+	      /*
+	      const STLReadTriangle& tria = stlgeometry -> GetReadTriangle(j);
+	      glNormal3f (tria.normal.X(),
+			  tria.normal.Y(),
+			  tria.normal.Z());
+	      */
+	      for (k = 0; k < 3; k++)
+		{
+		  Point3d p = stlgeometry->GetPoint(st[k]);
+		  glVertex3f (p.X(), p.Y(), p.Z());
+		}
+	    }    
+	  glEnd ();
+	}
+
+      if (showmarktrias && stlgeometry->AtlasMade())
+	{
+	  glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
+	  glPolygonOffset (pgoff*3, 3);
+	  glEnable (GL_POLYGON_OFFSET_FILL);
+
+	  glBegin (GL_TRIANGLES);
+	  
+	  if (chartnumber >= 1 && chartnumber <= stlgeometry->GetNOCharts())
+	    {
+	      glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colbrown);
+	      const STLChart& chart = stlgeometry->GetChart(chartnumber);
+	      for (j = 1; j <= chart.GetNChartT(); j++)
+		{
+		  /*
+		  if (j == charttrignumber) 
+		    {glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colred);}
+		  else
+		    {glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colbrown);}
+		  */
+		  const STLTriangle& st = stlgeometry -> GetTriangle(chart.GetChartTrig(j));
+
+		  
+		  const Vec3d & n = stlgeometry->GetTriangle(chart.GetChartTrig(j)).Normal();
+		  glNormal3f (n.X(), n.Y(), n.Z());
+		  /*
+		  const STLReadTriangle& tria = stlgeometry -> GetReadTriangle(chart.GetChartTrig(j));
+		  glNormal3f (tria.normal.X(),
+			      tria.normal.Y(),
+			      tria.normal.Z());
+		  */
+		  for (k = 0; k < 3; k++)
+		    {
+		      glVertex3f (stlgeometry->GetPoint(st[k])(0),
+				  stlgeometry->GetPoint(st[k])(1),
+				  stlgeometry->GetPoint(st[k])(2));
+		    }
+		}
+	      glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colgreen);
+	      
+	      for (j = 1; j <= chart.GetNOuterT(); j++)
+		{
+		  
+		  const STLTriangle& st = stlgeometry -> GetTriangle(chart.GetOuterTrig(j));
+
+		  const Vec3d & n = stlgeometry->GetTriangle(chart.GetOuterTrig(j)).Normal();
+		  glNormal3f (n.X(), n.Y(), n.Z());
+
+
+		  /*
+		  const STLReadTriangle& tria = stlgeometry -> GetReadTriangle(chart.GetOuterTrig(j));
+		  glNormal3f (tria.normal.X(),
+			      tria.normal.Y(),
+			      tria.normal.Z());
+		  */
+		  for (k = 0; k < 3; k++)
+		    {
+		      glVertex3f (stlgeometry->GetPoint(st[k])(0),
+				  stlgeometry->GetPoint(st[k])(1),
+				  stlgeometry->GetPoint(st[k])(2));
+		    }
+		}
+	    }
+	  glEnd ();
+	}
+
+      int showtrias = vispar.stlshowtrias;
+
+      if (showtrias)
+	{
+	  glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colgrey);
+	  glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
+	  glPolygonOffset (pgoff*2, 2);
+	  glEnable (GL_POLYGON_OFFSET_FILL);
+	  glEnable (GL_NORMALIZE);
+
+	  glBegin (GL_TRIANGLES);
+	  
+	  for (j = 1; j <= stlgeometry -> GetNT(); j++)
+	    {	  
+	      if (stldoctor.showvicinity && !stlgeometry->Vicinity(j)) {continue;}
+
+	      const STLTriangle& st = stlgeometry -> GetTriangle(j);
+
+	      const Vec3d & n = stlgeometry->GetTriangle(j).Normal();
+	      glNormal3f (n.X(), n.Y(), n.Z());
+	      /*
+	      const STLReadTriangle& tria = stlgeometry -> GetReadTriangle(j);
+	      glNormal3f (tria.normal.X(),
+			  tria.normal.Y(),
+			  tria.normal.Z());
+	      */	  
+	      for (k = 0; k < 3; k++)
+		{
+		  glVertex3f (stlgeometry->GetPoint(st[k])(0),
+			      stlgeometry->GetPoint(st[k])(1),
+			      stlgeometry->GetPoint(st[k])(2));
+		}
+	    }    
+	  glEnd ();
+	} 
+
+      int showedges = vispar.stlshowedges;
+      
+      if (showedges)
+	{
+	  glPolygonOffset (pgoff*1, 1);
+	  glEnable (GL_POLYGON_OFFSET_FILL);
+	  //glDisable (GL_POLYGON_OFFSET_FILL);      
+
+	  glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colgreen);
+	  glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
+      
+	  glEnable (GL_NORMALIZE);
+      
+	  glBegin (GL_LINES);
+
+	  /*
+	  if (stldoctor.useexternaledges)
+	    {
+	      glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colorange);
+	      for (j = 1; j <= stlgeometry -> NOExternalEdges(); j++)
+		{
+		  twoint v = stlgeometry->GetExternalEdge(j);
+		  Point3d p1 = stlgeometry->GetPoint(v.i1);
+		  Point3d p2 = stlgeometry->GetPoint(v.i2);
+		  
+		  Vec3d n1 = stlgeometry->GetNormal(v.i1);
+		  Vec3d n2 = stlgeometry->GetNormal(v.i2);
+		  
+		  glNormal3f(n1.X(), n1.Y(), n1.Z());
+		  glVertex3f(p1.X(), p1.Y(), p1.Z());
+		  glNormal3f(n2.X(), n2.Y(), n2.Z());
+		  glVertex3f(p2.X(), p2.Y(), p2.Z());
+		}
+	    }
+	  */
+
+	  
+	  if (!stlgeometry->meshlines.Size() || !stldoctor.drawmeshededges)
+	    {
+	      /*
+	      for (j = 1; j <= stlgeometry -> GetNE(); j++)
+		{
+		  STLEdge v = stlgeometry->GetEdge(j);
+		  Point3d p1 = stlgeometry->GetPoint(v.pts[0]);
+		  Point3d p2 = stlgeometry->GetPoint(v.pts[1]);
+		  
+		  Vec3d n1 = stlgeometry->GetNormal(v.pts[0]);
+		  Vec3d n2 = stlgeometry->GetNormal(v.pts[1]);
+		  
+		  glNormal3f(n1.X(), n1.Y(), n1.Z());
+		  glVertex3f(p1.X(), p1.Y(), p1.Z());
+		  glNormal3f(n2.X(), n2.Y(), n2.Z());
+		  glVertex3f(p2.X(), p2.Y(), p2.Z());
+		}
+	      */
+	      const STLEdgeDataList& ed = stlgeometry->EdgeDataList();
+	      for (i = 1; i <= ed.Size(); i++)
+		{
+		  if (ed.Get(i).GetStatus() != ED_UNDEFINED)
+		    {
+		      switch (ed.Get(i).GetStatus())
+			{
+			case ED_CONFIRMED:
+			  glMaterialfv (GL_FRONT_AND_BACK, 
+					GL_AMBIENT_AND_DIFFUSE, mat_colgreen);
+			  break;
+			case ED_CANDIDATE:
+			  glMaterialfv (GL_FRONT_AND_BACK, 
+					GL_AMBIENT_AND_DIFFUSE, mat_colbrown);
+			  break;
+			case ED_EXCLUDED:
+			  glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colred);
+			  break;
+			}
+
+		      if (ed.Get(i).GetStatus() == ED_EXCLUDED && !stldoctor.showexcluded) continue;
+
+		      Point3d p1 = stlgeometry->GetPoint(ed.Get(i).PNum(1));
+		      Point3d p2 = stlgeometry->GetPoint(ed.Get(i).PNum(2));
+		      glVertex3f(p1.X(), p1.Y(), p1.Z());
+		      glVertex3f(p2.X(), p2.Y(), p2.Z());		   
+		    }
+		}
+	    }
+
+	  /*
+	  else     
+	  if (stlgeometry->meshlines.Size() == 0)
+	    {
+	      for (j = 1; j <= stlgeometry->GetNLines(); j++)
+		{
+		  STLLine* line = stlgeometry->GetLine(j);
+		  int pn1, pn2;
+		  for (int k = 1; k <= line->NP()-1; k++)
+		    {
+		      pn1 = line->PNum(k);
+		      pn2 = line->PNum(k+1);
+
+		      Point3d p1 = stlgeometry->GetPoint(pn1);
+		      Point3d p2 = stlgeometry->GetPoint(pn2);
+		  
+		      Vec3d n1 = stlgeometry->GetNormal(pn1);
+		      Vec3d n2 = stlgeometry->GetNormal(pn2);
+		  
+		      glNormal3f(n1.X(), n1.Y(), n1.Z());
+		      glVertex3f(p1.X(), p1.Y(), p1.Z());
+		      glNormal3f(n2.X(), n2.Y(), n2.Z());
+		      glVertex3f(p2.X(), p2.Y(), p2.Z());
+		    }
+		}    
+	    }
+	  */
+	    
+	  else if (stlgeometry->meshlines.Size() != 0)
+	    {
+	      glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colgreen);
+	      for (j = 1; j <= stlgeometry->meshlines.Size(); j++)
+		{
+		  STLLine* line = stlgeometry->meshlines.Get(j);
+		  int pn1, pn2;
+		  for (int k = 1; k <= line->NP()-1; k++)
+		    {
+		      pn1 = line->PNum(k);
+		      pn2 = line->PNum(k+1);
+
+		      Point3d p1 = stlgeometry->meshpoints.Get(pn1);
+		      Point3d p2 = stlgeometry->meshpoints.Get(pn2);
+		  		  
+		      glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colgreen);
+		      glVertex3f(p1.X(), p1.Y(), p1.Z());
+		      glVertex3f(p2.X(), p2.Y(), p2.Z());
+
+		      
+		      glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colred);
+		      double cs = 0.02*Dist(p1,p2);
+		      glVertex3f(p1.X()+cs, p1.Y()+cs, p1.Z()+cs);
+		      glVertex3f(p1.X()-cs, p1.Y()-cs, p1.Z()-cs);
+		      glVertex3f(p2.X()+cs, p2.Y()+cs, p2.Z()+cs);
+		      glVertex3f(p2.X()-cs, p2.Y()-cs, p2.Z()-cs);
+
+		      glVertex3f(p1.X()-cs, p1.Y()+cs, p1.Z()+cs);
+		      glVertex3f(p1.X()+cs, p1.Y()-cs, p1.Z()-cs);
+		      glVertex3f(p2.X()-cs, p2.Y()+cs, p2.Z()+cs);
+		      glVertex3f(p2.X()+cs, p2.Y()-cs, p2.Z()-cs);
+		      
+		    }
+		}
+	    }
+	    
+
+	  glEnd ();
+	}
+
+      if (stldoctor.showedgecornerpoints && stlgeometry->LineEndPointsSet())
+	{
+	  glPointSize (5);
+	  glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colred);
+	  glBegin (GL_POINTS);
+	  for (i = 1; i <= stlgeometry->GetNP(); i++)
+	    {
+	      if (stlgeometry->IsLineEndPoint(i))
+		{
+		  const Point3d p = stlgeometry->GetPoint(i);
+		  glVertex3f (p.X(), p.Y(), p.Z());
+		}
+	    }
+	  glEnd();
+	  
+	}
+
+
+    }
+
+ 
+  glPopMatrix();
+
+  if (vispar.colormeshsize)
+    DrawColorBar (hmin, hmax, 1);
+
+  glFinish();  
+}
+
+
+void VisualSceneSTLMeshing :: BuildScene (int zoomall)
+{
+  int i, j, k;
+
+  if (selecttrig && zoomall == 2)
+    {
+      center = stlgeometry -> GetPoint ( stlgeometry->GetTriangle(selecttrig).PNum(nodeofseltrig));
+    }
+  else
+    center = stlgeometry -> GetBoundingBox().Center();
+  rad = stlgeometry -> GetBoundingBox().Diam() / 2;
+
+  CalcTransformationMatrices();
+}
+
+
+
+void VisualSceneSTLMeshing :: MouseDblClick (int px, int py)
+{
+  //  (*mycout) << "dblclick: " << px << " - " << py << endl;
+  
+
+  int i, j, k, hits;
+
+  // select surface triangle by mouse click
+
+  GLuint selbuf[10000];
+  glSelectBuffer (10000, selbuf);
+
+
+  glRenderMode (GL_SELECT);
+
+  GLint viewport[4];
+  glGetIntegerv (GL_VIEWPORT, viewport);
+
+  /*  
+  (*mycout) << "viewport = " << viewport[0] << " " 
+       << viewport[1] << " " << viewport[2] << " " << viewport[3] << endl;
+  */
+
+  glMatrixMode (GL_PROJECTION); 
+  glPushMatrix();
+
+
+  GLdouble projmat[16];
+  glGetDoublev (GL_PROJECTION_MATRIX, projmat);
+
+  glLoadIdentity(); 
+  gluPickMatrix (px, viewport[3] - py, 1, 1, viewport); 
+  glMultMatrixd (projmat);
+  
+
+
+  glClearColor(backcolor, backcolor, backcolor, 1.0);
+  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+  glMatrixMode (GL_MODELVIEW); 
+
+  glPushMatrix();
+  glMultMatrixf (transformationmat);
+
+
+  glInitNames();
+  glPushName (1);
+
+
+  glEnable (GL_POLYGON_OFFSET_FILL);
+  for (j = 1; j <= stlgeometry -> GetNT(); j++)
+    {
+      if (stldoctor.showvicinity && !stlgeometry->Vicinity(j)) {continue;}
+
+      const STLTriangle& st = stlgeometry -> GetTriangle(j);
+			
+      //const STLReadTriangle& tria = stlgeometry -> GetReadTriangle(j);
+      //glNormal3f (tria.normal.X(), tria.normal.Y(), tria.normal.Z());
+      
+      if (stldoctor.selectmode == 0)
+	{
+	  glLoadName (j);
+	  glBegin (GL_TRIANGLES);
+	  for (k = 0; k < 3; k++)
+	    {
+	      Point3d p = stlgeometry->GetPoint(st[k]);
+	      glVertex3f (p.X(), p.Y(), p.Z());
+	    }
+	  glEnd ();
+	} 
+      else if (stldoctor.selectmode == 1 || stldoctor.selectmode == 3
+	        || stldoctor.selectmode == 4)
+	{
+	  Point3d pm = Center(stlgeometry->GetPoint(st[0]),
+			      stlgeometry->GetPoint(st[1]),
+			      stlgeometry->GetPoint(st[2]));
+
+	  for (k = 0; k < 3; k++)
+	    {
+	      glLoadName (j*3+k-2);
+	      glBegin (GL_TRIANGLES);
+
+	      Point3d p1 = stlgeometry->GetPoint(st[k]);
+	      Point3d p2 = stlgeometry->GetPoint(st[(k+1)%3]);
+	      glVertex3f (p1.X(), p1.Y(), p1.Z());
+	      glVertex3f (p2.X(), p2.Y(), p2.Z());
+	      glVertex3f (pm.X(), pm.Y(), pm.Z());
+
+	      glEnd ();
+	    }
+	}
+      else
+	{
+	  Point3d pm1 = Center(stlgeometry->GetPoint(st[0]),
+			       stlgeometry->GetPoint(st[1]));
+	  Point3d pm2 = Center(stlgeometry->GetPoint(st[1]),
+			       stlgeometry->GetPoint(st[2]));
+	  Point3d pm3 = Center(stlgeometry->GetPoint(st[2]),
+			       stlgeometry->GetPoint(st[0]));
+
+	  Point3d p1 = stlgeometry->GetPoint(st[0]);
+	  Point3d p2 = stlgeometry->GetPoint(st[1]);
+	  Point3d p3 = stlgeometry->GetPoint(st[2]);
+
+	  glLoadName (j*4-3);
+	  glBegin (GL_TRIANGLES);
+	  glVertex3f (p1.X(), p1.Y(), p1.Z());
+	  glVertex3f (pm1.X(), pm1.Y(), pm1.Z());
+	  glVertex3f (pm3.X(), pm3.Y(), pm3.Z());
+	  glEnd ();
+
+	  glLoadName (j*4-2);
+	  glBegin (GL_TRIANGLES);
+	  glVertex3f (p2.X(), p2.Y(), p2.Z());
+	  glVertex3f (pm2.X(), pm2.Y(), pm2.Z());
+	  glVertex3f (pm1.X(), pm1.Y(), pm1.Z());
+	  glEnd ();
+
+	  glLoadName (j*4-1);
+	  glBegin (GL_TRIANGLES);
+	  glVertex3f (p3.X(), p3.Y(), p3.Z());
+	  glVertex3f (pm3.X(), pm3.Y(), pm3.Z());
+	  glVertex3f (pm2.X(), pm2.Y(), pm2.Z());
+	  glEnd ();
+
+	  glLoadName (j*4);
+	  glBegin (GL_TRIANGLES);
+	  glVertex3f (pm1.X(), pm1.Y(), pm1.Z());
+	  glVertex3f (pm2.X(), pm2.Y(), pm2.Z());
+	  glVertex3f (pm3.X(), pm3.Y(), pm3.Z());
+	  glEnd ();
+	}
+    }    
+
+  glPopName();
+
+  glMatrixMode (GL_PROJECTION); 
+  glPopMatrix();
+
+  glMatrixMode (GL_MODELVIEW); 
+  glPopMatrix();
+
+  glFlush();  
+
+	
+  hits = glRenderMode (GL_RENDER);
+
+  //  (*mycout) << "hits = " << hits << endl;
+
+  //int minrec = -1;
+  int minname = 0;
+  GLuint mindepth = 0;
+  for (i = 0; i < hits; i++)
+    {
+      int curname = selbuf[4*i+3];
+      GLuint curdepth = selbuf[4*i+1];
+
+      /*      
+      (*mycout) << selbuf[4*i] << " " << selbuf[4*i+1] << " " 
+	   << selbuf[4*i+2] << " " << selbuf[4*i+3] << endl;
+      */
+      if (curname &&
+	  (curdepth < mindepth || !minname))
+	{
+	  //minrec = i;
+	  mindepth = curdepth;
+	  minname = curname;
+	}
+    }
+
+  if (!minname) {return;}
+  
+  if (stldoctor.selectmode == 0)
+    {
+      int oldtrig = selecttrig;
+      selecttrig = minname;
+      if (selecttrig == oldtrig)
+	nodeofseltrig = (nodeofseltrig % 3) + 1;
+      else
+	nodeofseltrig = 1;
+
+      stlgeometry->SetSelectTrig(selecttrig);
+      stlgeometry->SetNodeOfSelTrig(nodeofseltrig);
+      stlgeometry->PrintSelectInfo();
+      
+    }
+  else if (stldoctor.selectmode == 1 || stldoctor.selectmode == 3 || stldoctor.selectmode == 4)
+    {
+      selecttrig = (minname-1) / 3 + 1;
+      nodeofseltrig = minname-selecttrig*3+3;
+
+      stlgeometry->SetSelectTrig(selecttrig);
+      stlgeometry->SetNodeOfSelTrig(nodeofseltrig);
+      stlgeometry->PrintSelectInfo();
+
+      if (stldoctor.selectmode == 1)
+	{
+	  stlgeometry->BuildSelectedEdge(twoint(stlgeometry->GetTriangle(selecttrig).PNumMod(nodeofseltrig),
+						stlgeometry->GetTriangle(selecttrig).PNumMod(nodeofseltrig+1)));
+	}
+      if (stldoctor.selectmode == 3)
+	{
+	  stlgeometry->BuildSelectedMultiEdge(twoint(stlgeometry->GetTriangle(selecttrig).PNumMod(nodeofseltrig),
+						     stlgeometry->GetTriangle(selecttrig).PNumMod(nodeofseltrig+1)));
+	}
+      else if (stldoctor.selectmode == 4)
+	{
+	  stlgeometry->BuildSelectedCluster(twoint(stlgeometry->GetTriangle(selecttrig).PNumMod(nodeofseltrig),
+						   stlgeometry->GetTriangle(selecttrig).PNumMod(nodeofseltrig+1)));
+	}
+ 
+      switch (stldoctor.edgeselectmode)
+	{
+	case 1: stlgeometry->STLDoctorUndefinedEdge(); break;
+	case 2: stlgeometry->STLDoctorConfirmEdge(); break;
+	case 3: stlgeometry->STLDoctorCandidateEdge(); break;
+	case 4: stlgeometry->STLDoctorExcludeEdge(); break;
+	default: break;
+	}
+    }
+  else if (stldoctor.selectmode == 2)
+    {
+      selecttrig = (minname-1) / 4 + 1;
+      nodeofseltrig = minname-selecttrig*4+4;
+      if (nodeofseltrig == 4) {nodeofseltrig = 1;}
+
+      stlgeometry->SetSelectTrig(selecttrig);
+      stlgeometry->SetNodeOfSelTrig(nodeofseltrig);
+      stlgeometry->PrintSelectInfo();
+
+    }
+
+  if (stldoctor.showtouchedtrigchart && stlgeometry->AtlasMade() && stlgeometry->GetSelectTrig())
+    {
+      vispar.stlchartnumber =  stlgeometry->GetChartNr(stlgeometry->GetSelectTrig());
+      vispar.stlchartnumberoffset = 0;
+    }
+  
+}
+
+
+
+
+
+
+
+VisualSceneSTLMeshing vsstlmeshing;
+
+#endif
+
+
+
+ 
+}
diff --git a/Netgen/libsrc/visualization/visual.hpp b/Netgen/libsrc/visualization/visual.hpp
new file mode 100644
index 0000000000..3e5910b351
--- /dev/null
+++ b/Netgen/libsrc/visualization/visual.hpp
@@ -0,0 +1,26 @@
+#ifndef FILE_VISUAL
+#define FILE_VISUAL
+
+/* *************************************************************************/
+/* File:   visual.hpp                                                       */
+/* Author: Joachim Schoeberl                                               */
+/* Date:   02. Dec. 01                                                     */
+/* *************************************************************************/
+
+/* 
+
+Visualization
+
+*/
+
+#include <incvis.hpp>
+
+namespace netgen
+{
+#include "mvdraw.hpp"
+#include "soldata.hpp"
+#include "vssolution.hpp"
+#include "meshdoc.hpp"
+}
+
+#endif
diff --git a/Netgen/libsrc/visualization/vscsg.cpp b/Netgen/libsrc/visualization/vscsg.cpp
new file mode 100644
index 0000000000..42891f0a63
--- /dev/null
+++ b/Netgen/libsrc/visualization/vscsg.cpp
@@ -0,0 +1,199 @@
+#include <mystdlib.h>
+#include "incvis.hpp"
+
+#include <myadt.hpp>
+#include <meshing.hpp>
+#include <csg.hpp>
+#include <stlgeom.hpp>
+
+
+namespace netgen
+{
+#include "mvdraw.hpp"
+
+/* *********************** Draw Geometry **************** */
+
+
+
+
+extern CSGeometry * geometry;
+
+
+VisualSceneGeometry :: VisualSceneGeometry ()
+  : VisualScene()
+{
+  selsurf = 0;
+}
+
+VisualSceneGeometry :: ~VisualSceneGeometry ()
+{
+  ;
+}
+
+void VisualSceneGeometry :: SelectSurface (int aselsurf)
+{
+  selsurf = aselsurf;
+  DrawScene();
+}
+
+
+void VisualSceneGeometry :: DrawScene ()
+{
+  int i;
+
+  if (changeval != geometry->GetChangeVal())
+    BuildScene();
+  changeval = geometry->GetChangeVal();
+
+  glClearColor(backcolor, backcolor, backcolor, 1.0);
+  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+  SetLight();
+
+
+  glPushMatrix();
+  glMultMatrixf (transformationmat);
+
+  SetClippingPlane ();
+
+  glShadeModel (GL_SMOOTH);
+  glDisable (GL_COLOR_MATERIAL);
+  glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
+
+  glEnable (GL_BLEND);
+  glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+  /*
+  float mat_spec_col[] = { 1, 1, 1, 1 };
+  glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, mat_spec_col);
+  */
+
+  double shine = vispar.shininess;
+  double transp = vispar.transp;
+
+  glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, shine);
+  glLogicOp (GL_COPY);
+
+  glEnable (GL_NORMALIZE);
+
+  for (i = 0; i < geometry->GetNTopLevelObjects(); i++)
+    {
+      const TopLevelObject * tlo = geometry -> GetTopLevelObject (i);
+      if (tlo->GetVisible() && !tlo->GetTransparent())
+	{
+	  float mat_col[] = { tlo->GetRed(), tlo->GetGreen(), tlo->GetBlue(), 1 };
+	  glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_col);
+	  
+	  glCallList (trilists[i]);
+	}
+    }
+
+
+  glPolygonOffset (1, 1);
+  glEnable (GL_POLYGON_OFFSET_FILL);
+
+  glLogicOp (GL_NOOP);
+  for (i = 0; i < geometry->GetNTopLevelObjects(); i++)
+    {
+      const TopLevelObject * tlo = geometry -> GetTopLevelObject (i);
+      if (tlo->GetVisible() && tlo->GetTransparent())
+	{
+	  float mat_col[] = { tlo->GetRed(), tlo->GetGreen(), tlo->GetBlue(), transp };
+
+	  glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_col);
+	  
+	  glCallList (trilists[i]);
+	}
+    }
+
+  glDisable (GL_POLYGON_OFFSET_FILL);
+
+  glPopMatrix();
+
+  glDisable(GL_CLIP_PLANE0);
+
+  DrawCoordinateCross ();
+  DrawNetgenLogo ();  
+
+  glFinish();  
+
+}
+
+
+void VisualSceneGeometry :: BuildScene (int zoomall)
+{
+  int i, j, k;
+  
+  Box<3> box;
+  int hasp = 0;
+  for (i = 0; i < geometry->GetNTopLevelObjects(); i++)
+    {
+      const TriangleApproximation & ta =
+	*geometry->GetTriApprox(i);
+      if (!&ta) continue;
+
+      for (j = 0; j < ta.GetNP(); j++)      
+	{
+	  if (hasp)
+	    box.Add (ta.GetPoint(j));
+	  else
+	    {
+	      hasp = 1;
+	      box.Set (ta.GetPoint(j));
+	    }
+	}
+    }
+  if (hasp)
+    {
+      center = box.Center();
+      rad = box.Diam() / 2;
+    }
+  else
+    {
+      center = Point3d(0,0,0);
+      rad = 1;
+    }
+
+  CalcTransformationMatrices();
+
+  for (i = 0; i < trilists.Size(); i++)
+    glDeleteLists (trilists[i], 1);
+  trilists.SetSize(0);
+
+  for (i = 0; i < geometry->GetNTopLevelObjects(); i++)
+    {
+      trilists.Append (glGenLists (1));
+      glNewList (trilists.Last(), GL_COMPILE);
+
+      glEnable (GL_NORMALIZE);
+      const TriangleApproximation & ta =
+	*geometry->GetTriApprox(i);
+      if (&ta) 
+	{
+	  glBegin (GL_TRIANGLES);
+	  for (j = 0; j < ta.GetNT(); j++)
+	    {
+	      
+	      for (k = 0; k < 3; k++)
+		{
+		  int pi = ta.GetTriangle(j)[k];
+		  glNormal3f (ta.GetNormal (pi)(0),
+			      ta.GetNormal (pi)(1),
+			      ta.GetNormal (pi)(2));
+		  glVertex3f (ta.GetPoint(pi)(0),
+			      ta.GetPoint(pi)(1),
+			      ta.GetPoint(pi)(2));
+		}
+	    }
+	  glEnd ();
+	}
+      glEndList ();
+    }
+
+}
+
+
+
+
+
+}
diff --git a/Netgen/libsrc/visualization/vsmesh.cpp b/Netgen/libsrc/visualization/vsmesh.cpp
new file mode 100644
index 0000000000..f88cb55284
--- /dev/null
+++ b/Netgen/libsrc/visualization/vsmesh.cpp
@@ -0,0 +1,2741 @@
+#include <mystdlib.h>
+#include "incvis.hpp"
+
+
+#include <myadt.hpp>
+#include <meshing.hpp>
+#include <csg.hpp>
+#include <stlgeom.hpp>
+
+namespace netgen
+{
+
+#include "mvdraw.hpp"
+
+
+  // #define FAST3DELEMENTS
+
+
+
+  extern AutoPtr<Mesh> mesh;
+  extern STLGeometry * stlgeometry;
+  VisualSceneMesh vsmesh;
+
+
+
+  VisualSceneMesh :: VisualSceneMesh ()
+    : VisualScene()
+  {
+    filledlist = 0;
+    linelist = 0;
+    badellist = 0;
+    tetlist = 0;
+    prismlist = 0;
+    hexlist = 0;
+    pyramidlist = 0;
+    identifiedlist = 0;
+    pointnumberlist = 0;
+    domainsurflist = 0;
+
+    vstimestamp = GetTimeStamp();
+    selecttimestamp = GetTimeStamp();
+    filledtimestamp = GetTimeStamp();
+    linetimestamp = GetTimeStamp();
+    pointnumbertimestamp = GetTimeStamp();
+  
+    tettimestamp = GetTimeStamp();
+    prismtimestamp = GetTimeStamp();
+    hextimestamp = GetTimeStamp();
+    pyramidtimestamp = GetTimeStamp();
+  
+    badeltimestamp = GetTimeStamp();
+    identifiedtimestamp = GetTimeStamp();
+    domainsurftimestamp = GetTimeStamp();
+
+
+    selface = -1;
+    selelement = -1;
+    locpi = 1;
+    selpoint = -1;
+    selpoint2 = -1;
+    seledge = -1;
+  }
+
+  VisualSceneMesh :: ~VisualSceneMesh ()
+  {
+    ;
+  }
+
+
+
+  
+  ARRAY<Point3d> drawel;
+  void VisualSceneMesh :: DrawScene ()
+  {
+    /*
+      if (multithread.running)
+      {
+      VisualScene::DrawScene();      
+      return;
+      }
+    */
+    int i;
+    
+    
+    if (!mesh) 
+      {
+	VisualScene::DrawScene();
+	return;
+      }
+
+    
+    lock = NULL;
+    
+    BuildScene();
+    
+    glClearColor(backcolor, backcolor, backcolor, 1.0);
+    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+    
+    glEnable (GL_COLOR_MATERIAL);
+    glColor3f (1.0f, 1.0f, 1.0f);
+    glLineWidth (1.0f);
+
+    SetLight();
+
+    glPushMatrix();
+    glMultMatrixf (transformationmat);
+
+    GLdouble projmat[16];
+    glGetDoublev (GL_PROJECTION_MATRIX, projmat);
+  
+  
+    glInitNames ();
+    glPushName (0);
+
+    //    glEnable (GL_LINE_SMOOTH);
+    //    glEnable (GL_BLEND);
+    //    glEnable (GL_POLYGON_SMOOTH);
+    //    glDisable (GL_DEPTH_TEST);
+    //    glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+    //    glHint (GL_LINE_SMOOTH_HINT, GL_DONT_CARE);
+  
+    glDisable (GL_COLOR_MATERIAL);
+  
+    GLfloat matcol0[] = { 0, 0, 0, 1 };
+    GLfloat matcol1[] = { 1, 1, 1, 1 };
+    GLfloat matcolf[] = { 0, 1, 0, 1 };
+    GLfloat matcolb[] = { 0.5, 0, 0, 1 };
+    GLfloat matcolblue[] = { 0, 0, 1, 1 };
+  
+    glMatrixMode (GL_MODELVIEW); 
+  
+    glMaterialfv(GL_FRONT, GL_EMISSION, matcol0);
+    glMaterialfv(GL_BACK, GL_EMISSION, matcol0);
+    glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, matcol1);
+    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, matcolf);
+    glMaterialfv(GL_BACK, GL_AMBIENT_AND_DIFFUSE, matcolb);
+  
+    glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
+
+    glPolygonOffset (1,1);
+    glEnable (GL_POLYGON_OFFSET_FILL);
+
+    SetClippingPlane ();
+
+    if (vispar.drawfilledtrigs)
+      {
+	BuildFilledList ();
+	glCallList (filledlist);
+      }
+
+    if (vispar.drawbadels)
+      glCallList (badellist);
+
+    if (vispar.drawprisms)
+      {
+	BuildPrismList ();
+	static float prismcol[] = { 1.0f, 1.0f, 0.0f, 1.0f };
+	glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, prismcol);
+	glLineWidth (1.0f);
+	glCallList (prismlist);
+      }
+
+    if (vispar.drawpyramids)
+      {
+	BuildPyramidList ();
+	static float pyramidcol[] = { 1.0f, 1.0f, 0.0f, 1.0f };
+	glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, pyramidcol);
+	glLineWidth (1.0f);
+	glCallList (pyramidlist);
+      }
+
+    if (vispar.drawhexes)
+      {
+	BuildHexList ();
+	static float hexcol[] = { 1.0f, 0.0f, 0.0f, 1.0f };
+	glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, hexcol);
+	glLineWidth (1.0f);
+	glCallList (hexlist);
+      }
+
+
+
+    if (vispar.drawtets)
+      {
+	BuildTetList ();
+	static float tetcol[] = { 1.0f, 1.0f, 0.0f, 1.0f };
+	glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, tetcol);
+	glLineWidth (1.0f);
+	glCallList (tetlist);
+      }
+    if (vispar.drawdomainsurf)
+      {
+	BuildDomainSurfList();
+	glCallList (domainsurflist);
+      }
+    glDisable (GL_POLYGON_OFFSET_FILL);
+  
+    // draw lines
+
+    glMatrixMode (GL_MODELVIEW); 
+  
+    glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, matcol0);
+    glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, matcol0);
+    glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, matcol0);
+  
+    glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
+    glLineWidth (1.0f);
+    glColor3f (0.0f, 0.0f, 0.0f);
+    glDisable (GL_LINE_SMOOTH);
+  
+    if (vispar.drawoutline)
+      {
+	glPolygonOffset (1, -1);
+	glEnable (GL_POLYGON_OFFSET_LINE);
+
+	BuildLineList ();
+	glCallList (linelist);
+      
+	glDisable (GL_POLYGON_OFFSET_LINE);
+      }
+
+    /*
+      // not drawing subdivision mesh
+
+    if (vispar.drawtets)
+      {
+	glCallList (tetlist);
+      }
+
+    if (vispar.drawprisms)
+      {
+	glCallList (prismlist);
+      }
+
+    if (vispar.drawpyramids)
+      {
+	glCallList (pyramidlist);
+      }
+
+    */
+
+    if (vispar.drawidentified)
+      {
+	glPolygonOffset (-1, -1);
+	glEnable (GL_POLYGON_OFFSET_LINE);
+	glCallList (identifiedlist);
+	glDisable (GL_POLYGON_OFFSET_LINE);
+      }
+  
+    if (vispar.drawpointnumbers ||
+	vispar.drawedgenumbers ||
+	vispar.drawfacenumbers ||
+	vispar.drawelementnumbers)
+      glCallList (pointnumberlist);
+  
+  
+    glPopName();
+
+    if (vispar.drawedges)
+      {
+	GLfloat matcoledge[] = { 0, 0, 1, 1 };
+	GLfloat matcolsingedge[] = { 1, 0, 1, 1 };
+
+	glEnable (GL_POLYGON_OFFSET_LINE);
+	glPolygonOffset (-1, -1);
+	glLineWidth (2);
+      
+
+	for (i = 1; i <= mesh->GetNSeg(); i++)
+	  {
+	    const Segment & seg = mesh->LineSegment(i);
+	    const Point3d & p1 = (*mesh)[seg.p1];
+	    const Point3d & p2 = (*mesh)[seg.p2];
+
+	    if (seg.singedge)
+	      glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, 
+			    matcolsingedge);
+	    else
+	      glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, 
+			    matcoledge);
+
+	    if (seg.edgenr == seledge)
+	      glLineWidth(5);
+	    else
+	      glLineWidth(2);
+
+	    if (mesh->GetCurvedElements().IsHighOrder()) {
+
+	      int j;
+	      int hoplotn = 1 << vispar.subdivisions; 
+	      // mesh->GetCurvedElements().GetNVisualSubsecs();
+
+	      Point<3> x;
+	      glBegin (GL_LINE_STRIP);
+
+	      for (j = 0; j <= hoplotn; j++) {
+		mesh->GetCurvedElements().CalcSegmentTransformation ((double) j/hoplotn, i-1, x);
+		glVertex3d (x(0), x(1), x(2));
+	      }
+
+	      glEnd();
+             
+	    } else {
+
+	      glBegin (GL_LINES);
+	      glVertex3f (p1.X(), p1.Y(), p1.Z());
+	      glVertex3f (p2.X(), p2.Y(), p2.Z());
+	      glEnd();
+
+	    }
+	  }
+
+	glLineWidth (2);
+	glDisable (GL_POLYGON_OFFSET_LINE);
+      }
+
+
+    if (selpoint > 0 && selpoint <= mesh->GetNP())
+      {
+	glPointSize (10);
+	glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, matcolblue);
+	glBegin (GL_POINTS);
+      
+	const Point3d p = mesh->Point(selpoint);
+	glVertex3f (p.X(), p.Y(), p.Z());
+	glEnd();
+      }
+
+
+    glDisable(GL_CLIP_PLANE0);
+
+    glPopMatrix();
+
+    if (vispar.colormeshsize)
+      DrawColorBar (minh, maxh, 1);
+
+    DrawCoordinateCross ();
+    DrawNetgenLogo ();
+
+    if (lock)
+      {
+	lock -> UnLock();
+	delete lock;
+      }
+
+    glFinish();  
+  }
+
+
+  void VisualSceneMesh :: BuildScene (int zoomall)
+  {
+    if (!mesh)
+      {
+	VisualScene::BuildScene (zoomall);
+	return;
+      }
+      
+    int i, j;
+	
+	
+    Point3d pmin, pmax;
+    static double oldrad = 0;
+	
+    ARRAY<Element2d> faces;
+
+    if (mesh->GetTimeStamp() > vstimestamp || zoomall)
+      {
+	mesh->GetBox (pmin, pmax, SURFACEPOINT);
+
+	if (selpoint >= 1 && zoomall == 2)
+	  center = mesh->Point (selpoint);
+	else if (vispar.centerpoint >= 1 && zoomall == 2)
+	  center = mesh->Point (vispar.centerpoint);
+	else
+	  center = Center (pmin, pmax);
+      
+	rad = 0.5 * Dist (pmin, pmax);
+      
+      
+	if (rad > 1.5 * oldrad || 
+	    mesh->GetMajorTimeStamp() > vstimestamp || 
+	    zoomall)
+	  {
+	    CalcTransformationMatrices();
+	    oldrad = rad;
+	  }
+	vstimestamp = mesh->GetTimeStamp();
+      }
+
+    glEnable (GL_NORMALIZE);
+
+    if (pointnumberlist)
+      {
+	glDeleteLists (pointnumberlist, 1);      
+	pointnumberlist = 0;
+      }
+
+    if (badellist)
+      {
+	glDeleteLists (badellist, 1);
+	badellist = 0;
+      }
+    if (prismlist)
+      {
+	glDeleteLists (prismlist, 1);
+	prismlist = 0;
+      }
+    if (pyramidlist)
+      {
+	glDeleteLists (pyramidlist, 1);
+	pyramidlist = 0;
+      }
+    if (hexlist)
+      {
+	glDeleteLists (hexlist, 1);
+	hexlist = 0;
+      }
+    if (identifiedlist)
+      {
+	glDeleteLists (identifiedlist, 1);
+	identifiedlist = 0;
+      }
+
+
+    pointnumberlist = glGenLists (1);
+    glNewList (pointnumberlist, GL_COMPILE);
+
+    if (vispar.drawpointnumbers ||
+	vispar.drawedgenumbers ||
+	vispar.drawfacenumbers ||
+	vispar.drawelementnumbers)
+      {
+	glEnable (GL_COLOR_MATERIAL);
+	GLfloat textcol[3] = { 1 - backcolor,
+			       1 - backcolor,
+			       1 - backcolor };
+	glColor3fv (textcol);
+	glNormal3d (0, 0, 1);
+	glPushAttrib (GL_LIST_BIT);
+	glListBase (fontbase);
+      
+	char buf[30];
+
+	if (vispar.drawpointnumbers)
+	  for (i = 1; i <= mesh->GetNP(); i++)
+	    {
+	      const Point3d & p = mesh->Point(i);
+	      glRasterPos3d (p.X(), p.Y(), p.Z());
+
+	      sprintf (buf, "%d", i);
+
+	      glCallLists (strlen (buf), GL_UNSIGNED_BYTE, buf);
+	    }
+
+	if (vispar.drawedgenumbers)
+	  {
+	    const MeshTopology & top = mesh->GetTopology();
+	    for (i = 1; i <= top.GetNEdges(); i++)
+	      {
+		int v1, v2;
+		top.GetEdgeVertices (i, v1, v2);
+		const Point3d & p1 = mesh->Point(v1);
+		const Point3d & p2 = mesh->Point(v2);
+		const Point3d p = Center (p1, p2);
+		glRasterPos3d (p.X(), p.Y(), p.Z());
+
+		sprintf (buf, "%d", i);
+
+		glCallLists (strlen (buf), GL_UNSIGNED_BYTE, buf);
+	      }
+	  }      
+
+
+	if (vispar.drawfacenumbers)
+	  {
+	    const MeshTopology & top = mesh->GetTopology();
+	    ARRAY<int> v;
+	    for (i = 1; i <= top.GetNFaces(); i++)
+	      {
+		top.GetFaceVertices (i, v);
+		const Point3d & p1 = mesh->Point(v.Elem(1));
+		const Point3d & p2 = mesh->Point(v.Elem(2));
+		const Point3d & p3 = mesh->Point(v.Elem(3));
+		Point3d p;
+		if (v.Elem(4) == 0)
+		  {
+		    p = Center (p1, p2, p3);
+		  }
+		else
+		  {
+		    const Point3d & p4 = mesh->Point(v.Elem(4));
+		    Point3d hp1 = Center (p1, p2);
+		    Point3d hp2 = Center (p3, p4);
+		    p = Center (hp1, hp2);
+		  }
+
+		glRasterPos3d (p.X(), p.Y(), p.Z());
+		sprintf (buf, "%d", i);
+		glCallLists (strlen (buf), GL_UNSIGNED_BYTE, buf);
+	      }
+	  }      
+
+
+	glPopAttrib ();
+	glDisable (GL_COLOR_MATERIAL);
+      }
+    glEndList ();
+
+
+
+
+
+
+
+
+
+
+
+
+
+    badellist = glGenLists (1);
+    glNewList (badellist, GL_COMPILE);
+
+    if (vispar.drawbadels)
+      {
+	//  SetClippingPlane ();
+
+	static float badelcol[] = { 1.0f, 0.0f, 1.0f, 1.0f };
+	glLineWidth (1.0f);
+
+	for (i = 1; i <= mesh->GetNE(); i++)
+	  {
+	    if (mesh->VolumeElement(i).flags.badel || 
+		mesh->VolumeElement(i).flags.illegal || 
+		(i == vispar.drawelement))
+	      {
+		// copy to be thread-safe
+		Element el = mesh->VolumeElement (i);
+		el.GetSurfaceTriangles (faces);
+
+		glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, badelcol);
+
+
+		//	  if ( (el.GetNP() == 4) || (el.GetNP() == 10))
+		if (el.PNum(1))
+		  {
+		    glBegin (GL_TRIANGLES);
+	      
+		    for (j = 1; j <= faces.Size(); j++)
+		      {
+			Element2d & face = faces.Elem(j);
+			const Point3d & lp1 = mesh->Point (el.PNum(face.PNum(1)));
+			const Point3d & lp2 = mesh->Point (el.PNum(face.PNum(2)));
+			const Point3d & lp3 = mesh->Point (el.PNum(face.PNum(3)));
+			Vec3d n = Cross (Vec3d (lp1, lp2), Vec3d (lp1, lp3));
+			n /= (n.Length()+1e-12);
+			glNormal3d (n.X(), n.Y(), n.Z());
+			glVertex3d (lp1.X(), lp1.Y(), lp1.Z());
+			glVertex3d (lp2.X(), lp2.Y(), lp2.Z());
+			glVertex3d (lp3.X(), lp3.Y(), lp3.Z());
+		      }
+	      
+		    glEnd();
+		  }
+	      }
+	  }
+
+
+
+	for (i = 1; i <= mesh->GetNE(); i++)
+	  {
+	    if (mesh->VolumeElement(i).flags.badel)
+	      {
+		// copy to be thread-safe
+		Element el = mesh->VolumeElement (i);
+		if ( (el.GetNP() == 4) || (el.GetNP() == 10))
+		  {
+		    glBegin (GL_LINES);
+		    glVertex3d (0,0,0);
+		    const Point3d & p = mesh->Point(el.PNum(1));
+		    glVertex3d (p.X(), p.Y(), p.Z());
+		    glEnd();
+		  }
+	      }
+	  }
+  
+
+	for (i = 1; i <= mesh->GetNE(); i++)
+	  {
+	    Element el = mesh->VolumeElement (i);
+	    int hascp = 0;
+	    for (j = 1; j <= el.GetNP(); j++)
+	      if (el.PNum(j) == vispar.centerpoint)
+		hascp = 1;
+
+	    if (hascp)
+	      {
+		(*testout) << "draw el " << i << " : ";
+		for (j = 1; j <= el.GetNP(); j++)
+		  (*testout) << el.PNum(j) << " ";
+		(*testout) << endl;
+
+		if (el.GetNP() == 4)
+		  {
+		    int et[6][2] = 
+		      { { 1, 2 },
+			{ 1, 3 },
+			{ 1, 4 },
+			{ 2, 3 },
+			{ 2, 4 },
+			{ 3, 4 } } ;
+
+		    for (j = 0; j < 6; j++)
+		      {
+			glBegin (GL_LINES);
+			const Point3d & p1 = mesh->Point (el.PNum(et[j][0]));
+			const Point3d & p2 = mesh->Point (el.PNum(et[j][1]));
+			glVertex3d (p1.X(), p1.Y(), p1.Z());
+			glVertex3d (p2.X(), p2.Y(), p2.Z());
+			glEnd ();
+		      }
+		  }
+
+
+		if (el.GetNP() == 10)
+		  {
+		    int et[12][2] = 
+		      { { 1, 5 },
+			{ 2, 5 },
+			{ 1, 6 },
+			{ 3, 6 },
+			{ 1, 7 },
+			{ 4, 7 },
+			{ 2, 8 },
+			{ 3, 8 },
+			{ 2, 9 },
+			{ 4, 9 },
+			{ 3, 10 },
+			{ 4, 10 } };
+
+		    for (j = 0; j < 12; j++)
+		      {
+			glBegin (GL_LINES);
+			const Point3d & p1 = mesh->Point (el.PNum(et[j][0]));
+			const Point3d & p2 = mesh->Point (el.PNum(et[j][1]));
+			glVertex3d (p1.X(), p1.Y(), p1.Z());
+			glVertex3d (p2.X(), p2.Y(), p2.Z());
+			glEnd ();
+		      }
+		  }
+	      }
+	  }
+
+
+	for (i = 1; i <= mesh->GetNSE(); i++)
+	  {
+	    Element2d el = mesh->SurfaceElement(i);
+	    if (!el.BadElement())
+	      continue;
+
+	    int drawel = 1;
+	    for (j = 1; j <= el.GetNP(); j++)
+	      if (!el.PNum(j))
+		drawel = 0;
+
+	    if (!drawel)
+	      continue;
+
+	    cout << int (el.GetType()) << " " << flush;
+	    switch (el.GetType())
+	      {
+	      case TRIG:
+		{
+		  glBegin (GL_TRIANGLES);
+	    
+		  Point3d & lp1 = mesh->Point (el.PNum(1));
+		  Point3d & lp2 = mesh->Point (el.PNum(2));
+		  Point3d & lp3 = mesh->Point (el.PNum(3));
+		  Vec3d n = Cross (Vec3d (lp1, lp2), Vec3d (lp1, lp3));
+		  n /= (n.Length() + 1e-12);
+		  glNormal3dv (&n.X());
+		  glVertex3dv (&lp1.X());
+		  glVertex3dv (&lp2.X());
+		  glVertex3dv (&lp3.X());
+		  glEnd();
+		  break;
+		}
+	      case QUAD:
+		{
+		  glBegin (GL_QUADS);
+	    
+		  const Point3d & lp1 = mesh->Point (el.PNum(1));
+		  const Point3d & lp2 = mesh->Point (el.PNum(2));
+		  const Point3d & lp3 = mesh->Point (el.PNum(4));
+		  const Point3d & lp4 = mesh->Point (el.PNum(3));
+		  Vec3d n = Cross (Vec3d (lp1, lp2), 
+				   Vec3d (lp1, Center (lp3, lp4)));
+		  n /= (n.Length() + 1e-12);
+		  glNormal3d (n.X(), n.Y(), n.Z());
+		  glVertex3d (lp1.X(), lp1.Y(), lp1.Z());
+		  glVertex3d (lp2.X(), lp2.Y(), lp2.Z());
+		  glVertex3d (lp4.X(), lp4.Y(), lp4.Z());
+		  glVertex3d (lp3.X(), lp3.Y(), lp3.Z());
+		  glEnd();
+		  break;
+		}
+	      case TRIG6:
+		{
+		  int lines[6][2] = {
+		    { 1, 6 }, { 2, 6 },
+		    { 1, 5 }, { 3, 5 },
+		    { 2, 4 }, { 3, 4 } };
+	      
+		  glBegin (GL_LINES);
+		  for (j = 0; j < 6; j++)
+		    {
+		      glVertex3dv (&mesh->Point (el.PNum(lines[j][0])).X());
+		      glVertex3dv (&mesh->Point (el.PNum(lines[j][0])).X());
+		    }
+		  glEnd();
+		  break;
+		}
+
+	      case QUAD6:
+		{
+		  int lines[6][2] = {
+		    { 1, 5 }, { 2, 5 },
+		    { 3, 6 }, { 4, 6 },
+		    { 1, 4 }, { 2, 3 } };
+	      
+		  glBegin (GL_LINES);
+	    
+		  for (j = 0; j < 6; j++)
+		    {
+		      const Point3d & lp1 = mesh->Point (el.PNum(lines[j][0]));
+		      const Point3d & lp2 = mesh->Point (el.PNum(lines[j][1]));
+		
+		      glVertex3d (lp1.X(), lp1.Y(), lp1.Z());
+		      glVertex3d (lp2.X(), lp2.Y(), lp2.Z());
+		    }
+		  glEnd ();
+		  break;
+		}
+	      default:
+		PrintSysError ("Cannot draw surface element of type ", 
+				 int(el.GetType()));
+	      }
+	  }
+	glLoadName (0);  
+
+      }
+    glEndList ();
+  
+
+
+  
+
+    if (1)
+      {
+      
+	identifiedlist = glGenLists (1);
+	glNewList (identifiedlist, GL_COMPILE);
+  
+	GLfloat identifiedcol[] = { 1, 0, 1, 1 };
+  
+	glLineWidth (3);
+      
+
+	//  for (i = 1; i <= mesh->GetNSeg(); i++)
+	INDEX_2_HASHTABLE<int> & idpts = 
+	  mesh->GetIdentifications().GetIdentifiedPoints();
+	if (&idpts)
+	  for (i = 1; i <= idpts.GetNBags(); i++)
+	    for (j = 1; j <= idpts.GetBagSize(i); j++)
+	      {
+		INDEX_2 pts;
+		int val;
+
+		idpts.GetData (i, j, pts, val);
+		const Point3d & p1 = mesh->Point(pts.I1());
+		const Point3d & p2 = mesh->Point(pts.I2());
+      
+		glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, 
+			      identifiedcol);
+
+		glBegin (GL_LINES);
+		glVertex3f (p1.X(), p1.Y(), p1.Z());
+		glVertex3f (p2.X(), p2.Y(), p2.Z());
+		glEnd(); 
+	      }
+
+	glEndList ();
+      }
+  }
+
+
+
+
+  void VisualSceneMesh :: BuildFilledList()
+  {
+    clock_t starttime, endtime;
+    starttime = clock();
+
+    int i, j;
+    SurfaceElementIndex sei;
+
+    if (filledtimestamp > mesh->GetTimeStamp () &&
+	filledtimestamp > selecttimestamp)
+      return;
+  
+    if (!lock)
+      {
+	lock = new NgLock (mesh->Mutex());
+	lock -> Lock();
+      }
+
+    filledtimestamp = NextTimeStamp();
+
+    if (filledlist)
+      glDeleteLists (filledlist, 1);
+
+
+    int checkvicinity = (stlgeometry != NULL) && stldoctor.showvicinity;
+
+    filledlist = glGenLists (1);
+    glNewList (filledlist, GL_COMPILE);
+
+
+    glEnable (GL_NORMALIZE);
+      
+    glLineWidth (1.0f);
+  
+    Vector locms;
+
+    if (vispar.colormeshsize)
+      {
+	glEnable (GL_COLOR_MATERIAL);
+	locms.SetSize (mesh->GetNP());
+	double maxh = -1;
+	double minh = 1e99;
+	for (i = 1; i <= locms.Size(); i++)
+	  {
+	    Point3d p = mesh->Point(i);
+	    locms.Elem(i) = mesh->GetH (p);
+	    if (locms.Elem(i) > maxh) maxh = locms.Elem(i);
+	    if (locms.Elem(i) < minh) minh = locms.Elem(i);
+	  }
+	//	minh = locms.Min();
+	//	maxh = locms.Max();
+	if (!locms.Size())
+	  { minh = 1; maxh = 10; }
+      }
+    else
+      glDisable (GL_COLOR_MATERIAL);
+
+
+    GLfloat matcol[] = { 0, 1, 0, 1 };
+    GLfloat matcolsel[] = { 1, 0, 0, 1 };
+	
+    for (int col = 1; col <= 2; col++)
+      {
+	if (col == 2)
+	  glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, matcolsel);
+	else
+	  glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, matcol);
+
+
+	for (sei = 0; sei < mesh->GetNSE(); sei++)
+	  {
+	    const Element2d & el = (*mesh)[sei];
+
+	    bool drawel = !el.IsDeleted();
+
+	    for (j = 0; j < el.GetNP(); j++)
+	      {
+		if (checkvicinity && !stlgeometry->Vicinity(el.GeomInfoPi(j+1).trignum))
+		  drawel = 0;
+	      }
+
+	    if (!drawel)
+	      continue;
+
+	    if (vispar.colormeshsize && col == 2)
+	      continue;
+	    if (!vispar.colormeshsize &&
+		(col == 2) != (el.GetIndex() == selface))
+	      continue;
+
+	    glLoadName (sei+1);
+
+	    switch (el.GetType())
+	      {
+	      case TRIG:
+		{
+		  CurvedElements & curv = mesh->GetCurvedElements();
+		  if (curv.IsHighOrder() && curv.IsSurfaceElementCurved(sei))
+		    {
+		      int hoplotn = 1 << vispar.subdivisions; 
+		      // int hoplotn = curv.GetNVisualSubsecs();
+
+		      Point<2> xr[3];
+		      Point<3> xg;
+		      Vec<3> dx, dy, n;
+
+		      glBegin (GL_TRIANGLES);
+
+		      for (int i = 0; i < hoplotn; i++)
+			for (int j = 0; j < hoplotn-i; j++)
+			  for (int k = 0; k < 2; k++)
+			    {
+			      if (k == 0)
+				{
+				  xr[0](0) = (double)    i/hoplotn; xr[0](1) = (double)    j/hoplotn;
+				  xr[1](0) = (double)(i+1)/hoplotn; xr[1](1) = (double)    j/hoplotn;
+				  xr[2](0) = (double)    i/hoplotn; xr[2](1) = (double)(j+1)/hoplotn;
+				} else
+				  {
+				    if (j == hoplotn-i-1) continue;
+				    xr[0](0) = (double)(i+1)/hoplotn; xr[0](1) = (double)    j/hoplotn;
+				    xr[1](0) = (double)(i+1)/hoplotn; xr[1](1) = (double)(j+1)/hoplotn;
+				    xr[2](0) = (double)    i/hoplotn; xr[2](1) = (double)(j+1)/hoplotn;
+				  };
+
+			      for (int l=0; l<3; l++)
+				{
+				  Mat<3,2> dxdxi;
+
+				  curv.CalcSurfaceTransformation (xr[l], sei, xg, dxdxi);
+				  for (int i = 0; i < 3; i++)
+				    {
+				      dx(i) = dxdxi(i,0);
+				      dy(i) = dxdxi(i,1);
+				    }
+				  n = Cross (dx, dy);
+				  n.Normalize();
+				  glNormal3d (n(0), n(1), n(2));
+				  glVertex3d (xg(0), xg(1), xg(2));
+				}
+			    }
+  
+		      glEnd();
+
+
+		    } else // not high order
+		      {
+			  
+			glBegin (GL_TRIANGLES);
+
+			Point<3> lp0 = (*mesh) [el.PNum(1)];
+			Point<3> lp1 = (*mesh) [el.PNum(2)];
+			Point<3> lp2 = (*mesh) [el.PNum(3)];
+                  
+			Vec<3> n = Cross (lp1-lp0, lp2-lp0);
+			n.Normalize();
+                  
+			glNormal3d (n(0), n(1), n(2));
+
+			    
+			if (vispar.colormeshsize)
+			  SetOpenGlColor  (locms.Get(el.PNum(1)), minh, maxh, 1);
+			glVertex3d (lp0(0), lp0(1), lp0(2));
+			if (vispar.colormeshsize)
+			  SetOpenGlColor  (locms.Get(el.PNum(2)), minh, maxh, 1);
+			glVertex3d (lp1(0), lp1(1), lp1(2));
+			if (vispar.colormeshsize)
+			  SetOpenGlColor  (locms.Get(el.PNum(3)), minh, maxh, 1);
+			glVertex3d (lp2(0), lp2(1), lp2(2));
+                  
+			glEnd();
+		      }
+
+		  break;
+
+		}
+	      case QUAD:
+		{
+		  // cout << "BuildFilledList: QUAD" << endl;
+		  CurvedElements & curv = mesh->GetCurvedElements();
+		  if (curv.IsHighOrder() && curv.IsSurfaceElementCurved(sei))
+		    {
+		      int hoplotn = 1 << vispar.subdivisions; 
+		      // int hoplotn = curv.GetNVisualSubsecs();
+
+		      Point<2> xr[4];
+		      Point<3> xg;
+		      Vec<3> dx, dy, n;
+
+		      glBegin (GL_QUADS);
+
+		      for (int i = 0; i < hoplotn; i++)
+			for (int j = 0; j < hoplotn; j++)
+			  {
+			    xr[0](0) = (double)    i/hoplotn; xr[0](1) = (double)    j/hoplotn;
+			    xr[1](0) = (double)(i+1)/hoplotn; xr[1](1) = (double)    j/hoplotn;
+			    xr[2](0) = (double)(i+1)/hoplotn; xr[2](1) = (double)(j+1)/hoplotn;
+			    xr[3](0) = (double)    i/hoplotn; xr[3](1) = (double)(j+1)/hoplotn;
+
+			    for (int l=0; l<4; l++)
+			      {
+				Mat<3,2> dxdxi;
+
+				curv.CalcSurfaceTransformation (xr[l], sei, xg, dxdxi);
+				for (int i = 0; i < 3; i++)
+				  {
+				    dx(i) = dxdxi(i,0);
+				    dy(i) = dxdxi(i,1);
+				  }
+
+				n = Cross (dx, dy);
+				n.Normalize();
+				glNormal3d (n(0), n(1), n(2));
+				glVertex3d (xg(0), xg(1), xg(2));
+			      }
+
+			  }
+                    
+		      glEnd();
+
+
+		    } else // not high order
+		      {
+                  
+			glBegin (GL_QUADS);
+
+			const Point3d & lp1 = mesh->Point (el.PNum(1));
+			const Point3d & lp2 = mesh->Point (el.PNum(2));
+			const Point3d & lp3 = mesh->Point (el.PNum(4));
+			const Point3d & lp4 = mesh->Point (el.PNum(3));
+			Vec3d n = Cross (Vec3d (lp1, lp2),
+					 Vec3d (lp1, Center (lp3, lp4)));
+			n /= (n.Length()+1e-12);
+			glNormal3d (n.X(), n.Y(), n.Z());
+			glVertex3d (lp1.X(), lp1.Y(), lp1.Z());
+			glVertex3d (lp2.X(), lp2.Y(), lp2.Z());
+			glVertex3d (lp4.X(), lp4.Y(), lp4.Z());
+			glVertex3d (lp3.X(), lp3.Y(), lp3.Z());
+
+			glEnd ();
+                
+		      }
+		  break;
+		}
+	      case TRIG6:
+		{
+		  glBegin (GL_TRIANGLES);
+
+		  static int trigs[4][3] = {
+		    { 1, 6, 5 },
+		    { 2, 4, 6 },
+		    { 3, 5, 4 },
+		    { 4, 5, 6 } };
+		
+		  for (j = 0; j < 4; j++)
+		    {
+		      Point3d & lp1 = mesh->Point (el.PNum(trigs[j][0]));
+		      Point3d & lp2 = mesh->Point (el.PNum(trigs[j][1]));
+		      Point3d & lp3 = mesh->Point (el.PNum(trigs[j][2]));
+		      Vec3d n = Cross (Vec3d (lp1, lp2), Vec3d (lp1, lp3));
+		      n /= (n.Length() + 1e-12);
+		      glNormal3dv (&n.X());
+		      glVertex3dv (&lp1.X());
+		      glVertex3dv (&lp2.X());
+		      glVertex3dv (&lp3.X());
+		    }
+		  glEnd();
+		  break;
+		}
+	      case QUAD6:
+		{
+		  glBegin (GL_QUADS);
+		  static int quads[2][4] = {
+		    { 1, 5, 6, 4 },
+		    { 5, 2, 3, 6 } };
+		
+		  for (j = 0; j < 2; j++)
+		    {
+		      Point3d & lp1 = mesh->Point (el.PNum(quads[j][0]));
+		      Point3d & lp2 = mesh->Point (el.PNum(quads[j][1]));
+		      Point3d & lp3 = mesh->Point (el.PNum(quads[j][2]));
+		      Point3d & lp4 = mesh->Point (el.PNum(quads[j][3]));
+		      Vec3d n = Cross (Vec3d (lp1, lp2), Vec3d (lp1, lp3));
+		      n /= (n.Length() + 1e-12);
+		      glNormal3dv (&n.X());
+		      glVertex3dv (&lp1.X());
+		      glVertex3dv (&lp2.X());
+		      glVertex3dv (&lp3.X());
+		      glVertex3dv (&lp4.X());
+		    }
+		  glEnd();
+		  break;
+		}
+	      default:
+		PrintSysError ("Cannot draw (2) surface element of type ", 
+				 int(el.GetType()));
+	      }
+	  }
+      }
+    glLoadName (0);
+    glEndList ();
+
+    endtime = clock();
+
+    // cout << "BuildFillList time = " << double(endtime - starttime)/CLOCKS_PER_SEC << endl;
+  }
+
+
+  void VisualSceneMesh :: BuildLineList()
+  {
+    int j;
+    SurfaceElementIndex sei;
+
+    if (linetimestamp > mesh->GetTimeStamp () &&
+	linetimestamp > selecttimestamp)
+      return;
+
+    if (!lock)
+      {
+	lock = new NgLock (mesh->Mutex());
+	lock -> Lock();
+      }
+
+    linetimestamp = NextTimeStamp();
+
+
+    int checkvicinity = (stlgeometry != NULL) && stldoctor.showvicinity;
+
+    if (linelist)
+      glDeleteLists (linelist, 1);
+
+  
+    linelist = glGenLists (1);
+    glNewList (linelist, GL_COMPILE);
+
+
+    glLineWidth (1.0f);
+  
+    for (sei = 0; sei < mesh->GetNSE(); sei++)
+      {
+	const Element2d & el = (*mesh)[sei];
+      
+	bool drawel = !el.IsDeleted();
+	for (j = 0; j < el.GetNP(); j++)
+	  {
+	    if (checkvicinity && !stlgeometry->Vicinity(el.GeomInfoPi(j+1).trignum))
+	      drawel = 0;
+	  }
+
+	if (!drawel)
+	  continue;
+
+	switch (el.GetType())
+	  {
+	    /*
+	      case TRIG:
+	      {
+	      CurvedElements & curv = mesh->GetCurvedElements();
+	      if (curv.IsHighOrder() && curv.IsSurfaceElementCurved(sei))
+	      {
+	      const MeshTopology & top = mesh->GetTopology();
+                  
+	      int hoplotn = 1 << vispar.subdivisions; 	      
+	      // int hoplotn = curv.GetNVisualSubsecs();
+		  
+	      Point<2> xr[3];
+	      Point<3> xg;
+	      Vec<3> dx, dy, n;
+		  
+	      glBegin (GL_TRIANGLES);
+
+	      for (int i = 0; i < hoplotn; i++)
+	      for (int j = 0; j < hoplotn-i; j++)
+	      for (int k = 0; k < 2; k++)
+	      {
+	      if (k == 0)
+	      {
+	      xr[0](0) = (double)    i/hoplotn; xr[0](1) = (double)    j/hoplotn;
+	      xr[1](0) = (double)(i+1)/hoplotn; xr[1](1) = (double)    j/hoplotn;
+	      xr[2](0) = (double)    i/hoplotn; xr[2](1) = (double)(j+1)/hoplotn;
+	      } else
+	      {
+	      if (j == hoplotn-i-1) continue;
+	      xr[0](0) = (double)(i+1)/hoplotn; xr[0](1) = (double)    j/hoplotn;
+	      xr[1](0) = (double)(i+1)/hoplotn; xr[1](1) = (double)(j+1)/hoplotn;
+	      xr[2](0) = (double)    i/hoplotn; xr[2](1) = (double)(j+1)/hoplotn;
+	      };
+
+	      for (int l=0; l<3; l++)
+	      {
+	      Mat<3,2> dxdxi;
+
+	      curv.CalcSurfaceTransformation (xr[l], sei, xg, dxdxi);
+	      for (int i = 0; i < 3; i++)
+	      {
+	      dx(i) = dxdxi(i,0);
+	      dy(i) = dxdxi(i,1);
+	      }
+	      n = Cross (dx, dy);
+	      n.Normalize();
+	      glNormal3d (n(0), n(1), n(2));
+	      glVertex3d (xg(0), xg(1), xg(2));
+	      }
+	      }
+  
+	      glEnd();
+
+
+	      } else // not high order
+	      {
+	      glBegin (GL_TRIANGLES);
+
+	      Point<3> lp0 = mesh->Point (el.PNum(1));
+	      Point<3> lp1 = mesh->Point (el.PNum(2));
+	      Point<3> lp2 = mesh->Point (el.PNum(3));
+                  
+	      Vec<3> n = Cross (lp1-lp0, lp2-lp0);
+	      n.Normalize();
+                  
+	      glNormal3d (n(0), n(1), n(2));
+	      glVertex3d (lp0(0), lp0(1), lp0(2));
+	      glVertex3d (lp1(0), lp1(1), lp1(2));
+	      glVertex3d (lp2(0), lp2(1), lp2(2));
+                  
+	      glEnd();
+	      }
+
+	      break;
+
+	      }
+
+	      case QUAD:
+	      {
+	      // cout << "BuildFilledList: QUAD" << endl;
+	      CurvedElements & curv = mesh->GetCurvedElements();
+	      if (curv.IsHighOrder() && curv.IsSurfaceElementCurved(sei))
+	      {
+	      const MeshTopology & top = mesh->GetTopology();
+
+	      int hoplotn = 1 << vispar.subdivisions; 
+	      // int hoplotn = curv.GetNVisualSubsecs();
+
+	      Point<2> xr[4];
+	      Point<3> xg;
+	      Vec<3> dx, dy, n;
+
+	      glBegin (GL_QUADS);
+
+	      for (int i = 0; i < hoplotn; i++)
+	      for (int j = 0; j < hoplotn; j++)
+	      {
+	      xr[0](0) = (double)    i/hoplotn; xr[0](1) = (double)    j/hoplotn;
+	      xr[1](0) = (double)(i+1)/hoplotn; xr[1](1) = (double)    j/hoplotn;
+	      xr[2](0) = (double)(i+1)/hoplotn; xr[2](1) = (double)(j+1)/hoplotn;
+	      xr[3](0) = (double)    i/hoplotn; xr[3](1) = (double)(j+1)/hoplotn;
+
+	      for (int l=0; l<4; l++)
+	      {
+	      Mat<3,2> dxdxi;
+			    
+	      curv.CalcSurfaceTransformation (xr[l], sei, xg, dxdxi);
+	      for (int i = 0; i < 3; i++)
+	      {
+	      dx(i) = dxdxi(i,0);
+	      dy(i) = dxdxi(i,1);
+	      }
+			    
+	      n = Cross (dx, dy);
+	      n.Normalize();
+	      glNormal3d (n(0), n(1), n(2));
+	      glVertex3d (xg(0), xg(1), xg(2));
+	      }
+
+	      }
+                    
+	      glEnd();
+
+
+	      } else // not high order
+	      {
+		    
+	      glBegin (GL_QUADS);
+
+	      const Point3d & lp1 = mesh->Point (el.PNum(1));
+	      const Point3d & lp2 = mesh->Point (el.PNum(2));
+	      const Point3d & lp3 = mesh->Point (el.PNum(4));
+	      const Point3d & lp4 = mesh->Point (el.PNum(3));
+	      Vec3d n = Cross (Vec3d (lp1, lp2),
+	      Vec3d (lp1, Center (lp3, lp4)));
+	      n /= (n.Length()+1e-12);
+	      glNormal3d (n.X(), n.Y(), n.Z());
+	      glVertex3d (lp1.X(), lp1.Y(), lp1.Z());
+	      glVertex3d (lp2.X(), lp2.Y(), lp2.Z());
+	      glVertex3d (lp4.X(), lp4.Y(), lp4.Z());
+	      glVertex3d (lp3.X(), lp3.Y(), lp3.Z());
+
+	      glEnd ();
+                
+	      }
+	      break;
+	      }
+	    */
+
+	  case TRIG:
+	    {
+	      CurvedElements & curv = mesh->GetCurvedElements();
+	      if (curv.IsHighOrder() && curv.IsSurfaceElementCurved(sei))
+		{
+		  Point<2> xr;
+		  Point<3> xg;
+		  Vec<3> n;
+                
+		  int hoplotn = 1 << vispar.subdivisions; 
+		  // int hoplotn = curv.GetNVisualSubsecs();
+
+		  glBegin (GL_LINE_STRIP);
+
+		  for (int side = 0; side < 3; side++)
+		    {
+		      for (int i = 0; i <= hoplotn; i++)
+			{
+			  switch (side)
+			    {
+			    case 0:
+			      xr(0) = (double) i/hoplotn;
+			      xr(1) = 0.;
+			      break;
+			    case 1:
+			      xr(0) = (double) (hoplotn-i)/hoplotn;
+			      xr(1) = (double)    i/hoplotn;
+			      break;
+			    case 2:
+			      xr(0) = 0.;
+			      xr(1) = (double) (hoplotn-i)/hoplotn;
+			      break;
+			    }
+
+			  Mat<3,2> dxdxi;
+                        
+			  curv.CalcSurfaceTransformation (xr, sei, xg, dxdxi);
+			  glVertex3d (xg(0), xg(1), xg(2));
+
+			}
+
+		    }                       
+		  glEnd();
+
+		} else {
+
+		  glBegin (GL_TRIANGLES);
+
+		  Point<3> lp0 = (*mesh) [el.PNum(1)];
+		  Point<3> lp1 = (*mesh) [el.PNum(2)];
+		  Point<3> lp2 = (*mesh) [el.PNum(3)];
+
+		  glVertex3dv (lp0);
+		  glVertex3d (lp1(0), lp1(1), lp1(2));
+		  glVertex3d (lp2(0), lp2(1), lp2(2));
+
+		  glEnd();
+
+		}
+
+	      break;
+
+	    }     
+ 
+	  case QUAD:
+	    {
+	      CurvedElements & curv = mesh->GetCurvedElements();
+	      if (curv.IsHighOrder() && curv.IsSurfaceElementCurved(sei))
+		{
+		  Point<2> xr;
+		  Point<3> xg;
+
+		  int hoplotn = 1 << vispar.subdivisions; 
+		  // int hoplotn = curv.GetNVisualSubsecs();
+
+		  glBegin (GL_LINE_STRIP);
+
+		  for (int side = 0; side < 4; side++)
+		    {
+		      for (int i = 0; i <= hoplotn; i++)
+			{
+			  switch (side)
+			    {
+			    case 0:
+			      xr(0) = (double) i/hoplotn;
+			      xr(1) = 0.;
+			      break;
+			    case 1:
+			      xr(0) = 1.;
+			      xr(1) = (double) i/hoplotn;
+			      break;
+			    case 2:
+			      xr(0) = (double) (hoplotn-i)/hoplotn;
+			      xr(1) = 1.;
+			      break;
+			    case 3:
+			      xr(0) = 0.;
+			      xr(1) = (double) (hoplotn-i)/hoplotn;
+			      break;
+			    }
+
+			  Mat<3,2> dxdxi;
+
+			  curv.CalcSurfaceTransformation (xr, sei, xg, dxdxi);
+			  glVertex3d (xg(0), xg(1), xg(2));
+
+			}
+
+		    }
+		  glEnd();
+
+		} else {
+
+		  glBegin (GL_QUADS);
+
+		  const Point3d & lp1 = mesh->Point (el.PNum(1));
+		  const Point3d & lp2 = mesh->Point (el.PNum(2));
+		  const Point3d & lp3 = mesh->Point (el.PNum(4));
+		  const Point3d & lp4 = mesh->Point (el.PNum(3));
+		  Vec3d n = Cross (Vec3d (lp1, lp2),
+				   Vec3d (lp1, Center (lp3, lp4)));
+		  n /= (n.Length() + 1e-12);
+		  glNormal3d (n.X(), n.Y(), n.Z());
+		  glVertex3d (lp1.X(), lp1.Y(), lp1.Z());
+		  glVertex3d (lp2.X(), lp2.Y(), lp2.Z());
+		  glVertex3d (lp4.X(), lp4.Y(), lp4.Z());
+		  glVertex3d (lp3.X(), lp3.Y(), lp3.Z());
+		  glEnd();
+
+		}
+	    
+	      break;
+	    
+	    }
+	    
+	  case TRIG6:
+	    {
+	      int lines[6][2] = {
+		{ 1, 6 }, { 2, 6 },
+		{ 1, 5 }, { 3, 5 },
+		{ 2, 4 }, { 3, 4 } };
+	    
+	      glBegin (GL_LINES);
+	      for (j = 0; j < 6; j++)
+		{
+		  const Point3d & lp1 = mesh->Point (el.PNum(lines[j][0]));
+		  const Point3d & lp2 = mesh->Point (el.PNum(lines[j][1]));
+		
+		  glVertex3d (lp1.X(), lp1.Y(), lp1.Z());
+		  glVertex3d (lp2.X(), lp2.Y(), lp2.Z());
+		}
+	    
+	      glEnd();
+	      break;
+	    }
+	  
+	  case QUAD6:
+	    {
+	      int lines[6][2] = {
+		{ 1, 5 }, { 2, 5 },
+		{ 3, 6 }, { 4, 6 },
+		{ 1, 4 }, { 2, 3 } };
+	    
+	      glBegin (GL_LINES);
+	    
+	      for (j = 0; j < 6; j++)
+		{
+		  const Point3d & lp1 = mesh->Point (el.PNum(lines[j][0]));
+		  const Point3d & lp2 = mesh->Point (el.PNum(lines[j][1]));
+		
+		  glVertex3d (lp1.X(), lp1.Y(), lp1.Z());
+		  glVertex3d (lp2.X(), lp2.Y(), lp2.Z());
+		}
+	      glEnd ();
+	      break;
+	    }
+
+	  default:
+	    PrintSysError ("Cannot draw (4) surface element of type ", 
+			     int(el.GetType()));
+	  }
+      }
+    
+    glEndList ();
+  }
+
+  void VisualSceneMesh :: BuildPointNumberList()
+  {
+    ;
+  }
+
+  void VisualSceneMesh :: BuildTetList()
+  {
+
+
+#ifdef FAST3DELEMENTS
+    
+
+    cout << "start fast test" << endl;
+
+    int i, j;
+    ARRAY<Element2d> faces;
+
+    if (tettimestamp > mesh->GetTimeStamp () &&
+	tettimestamp > vispar.clipplanetimestamp )
+      return;
+
+    if (!lock)
+      {
+	lock = new NgLock (mesh->Mutex());
+	lock -> Lock();
+      }
+
+    tettimestamp = NextTimeStamp();
+
+    if (tetlist)
+      glDeleteLists (tetlist, 1);
+
+
+    tetlist = glGenLists (1);
+    glNewList (tetlist, GL_COMPILE);
+
+  
+    BitArray shownode(mesh->GetNP());
+    if (vispar.clipenable)
+      {
+	shownode.Clear();
+	for (i = 1; i <= shownode.Size(); i++)
+	  {
+	    Point3d p = mesh->Point(i);
+	  
+	    double val =
+	      p.X() * clipplane[0] +
+	      p.Y() * clipplane[1] +
+	      p.Z() * clipplane[2] +
+	      clipplane[3];
+	  
+	    if (val > 0)
+	      shownode.Set (i);
+	  }
+      }
+    else
+      shownode.Set();
+
+
+    static float tetcols[][4] = 
+      {
+	{ 1.0f, 1.0f, 0.0f, 1.0f },
+	{ 1.0f, 0.0f, 0.0f, 1.0f },
+	{ 0.0f, 1.0f, 0.0f, 1.0f },
+	{ 0.0f, 0.0f, 1.0f, 1.0f }
+      };
+
+
+    ARRAY<int> elfaces;
+
+    const MeshTopology & top = mesh->GetTopology();
+    CurvedElements & curv = mesh->GetCurvedElements();
+
+    ARRAY<int> displayface(top.GetNFaces());
+    for (i = 0; i < top.GetNFaces(); i++)
+      displayface[i] = -1;
+    
+
+    for (i = 1; i <= mesh->GetNE(); i++)
+      {
+	if (vispar.drawtetsdomain > 0 &&
+	    vispar.drawtetsdomain != mesh->VolumeElement(i).GetIndex())
+	  continue;
+
+	Element el = (*mesh)[(ElementIndex) (i-1)];
+
+	if (el.GetType() == TET)
+	  {
+	    if (el.PNum(1))
+	      {
+		bool drawtet = 1;
+		for (j = 1; j <= el.GetNP(); j++)
+		  if (!shownode.Test(el.PNum(j)))
+		    drawtet = 0;
+		if (!drawtet) continue;
+		
+		{
+		  top.GetElementFaces (i, elfaces);
+		  
+		  for (j = 0; j < 4; j++)
+		    displayface[elfaces[j]-1] *= -1;
+		}
+	      }
+	  }
+      }
+
+    
+    for (i = 1; i <= mesh->GetNE(); i++)
+      {
+	if (vispar.drawtetsdomain > 0 &&
+	    vispar.drawtetsdomain != mesh->VolumeElement(i).GetIndex())
+	  continue;
+
+	if (mesh->VolumeElement(i).GetType() == TET)
+	  {
+	    // copy to be thread-safe
+	    Element el = mesh->VolumeElement (i);
+	    el.GetSurfaceTriangles (faces);
+
+	    if (el.PNum(1))
+	      {
+		bool drawtet = 1;
+		for (j = 1; j <= el.GetNP(); j++)
+		  if (!shownode.Test(el.PNum(j)))
+		    drawtet = 0;
+		if (!drawtet) continue;
+
+		int ind = el.GetIndex() % 4;
+		glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, tetcols[ind]);
+
+
+		top.GetElementFaces (i, elfaces);
+
+		glBegin (GL_TRIANGLES);
+
+		for (j = 0; j < faces.Size(); j++)
+		  {
+		    if (displayface[elfaces[j]-1] == -1) continue;
+
+		    Element2d & face = faces.Elem(j+1);
+
+		    if (curv.IsHighOrder() && curv.IsElementCurved(i-1))
+		  {
+		    int hoplotn = 1 << vispar.subdivisions; 
+		    // int hoplotn = curv.GetNVisualSubsecs();
+			    
+		    const Point3d * facepoint = MeshTopology :: GetVertices (TET);
+		    const ELEMENT_FACE * elface = MeshTopology :: GetFaces(TET);
+                    
+		    Vec<3> x0,x1,d0,d1;
+		    Point<3> xg;
+		    x0 = facepoint[face.PNum(3)-1] - facepoint[face.PNum(1)-1];
+		    x1 = facepoint[face.PNum(2)-1] - facepoint[face.PNum(1)-1];
+		    x0.Normalize();
+		    x1.Normalize();
+
+		    for (int m0 = 0; m0 < hoplotn; m0++)
+		      for (int m1 = 0; m1 < hoplotn-m0; m1++)
+			for (int k = 0; k < 2; k++)
+			  {
+			    Vec<3> dx, dy, dz, n;
+			    Point<4> la[3];
+			    int l;
+			    for (l = 0; l<3; l++) la[l] = Point<4>(0.,0.,0.,0.);
+
+			    if (k == 0)
+			      {
+				la[0](face.PNum(1)-1) = (m0  )/(double)hoplotn;
+				la[0](face.PNum(2)-1) = (m1  )/(double)hoplotn;
+				la[0](face.PNum(3)-1) = 1-la[0](face.PNum(1)-1)-la[0](face.PNum(2)-1);
+
+				la[1](face.PNum(1)-1) = (m0+1)/(double)hoplotn;
+				la[1](face.PNum(2)-1) = (m1  )/(double)hoplotn;
+				la[1](face.PNum(3)-1) = 1-la[1](face.PNum(1)-1)-la[1](face.PNum(2)-1);
+
+				la[2](face.PNum(1)-1) = (m0  )/(double)hoplotn;
+				la[2](face.PNum(2)-1) = (m1+1)/(double)hoplotn;
+				la[2](face.PNum(3)-1) = 1-la[2](face.PNum(1)-1)-la[2](face.PNum(2)-1);
+			      } else
+				{
+				  if (m1 == hoplotn-m0-1) continue;
+				  la[0](face.PNum(1)-1) = (m0+1)/(double)hoplotn;
+				  la[0](face.PNum(2)-1) = (m1+1)/(double)hoplotn;
+				  la[0](face.PNum(3)-1) = 1-la[0](face.PNum(1)-1)-la[0](face.PNum(2)-1);
+
+				  la[1](face.PNum(1)-1) = (m0  )/(double)hoplotn;
+				  la[1](face.PNum(2)-1) = (m1+1)/(double)hoplotn;
+				  la[1](face.PNum(3)-1) = 1-la[1](face.PNum(1)-1)-la[1](face.PNum(2)-1);
+
+				  la[2](face.PNum(1)-1) = (m0+1)/(double)hoplotn;
+				  la[2](face.PNum(2)-1) = (m1  )/(double)hoplotn;
+				  la[2](face.PNum(3)-1) = 1-la[2](face.PNum(1)-1)-la[2](face.PNum(2)-1);
+				}
+
+			    for (l = 0; l<3; l++)
+			      {
+				Mat<3,3> dxdxi;
+				Point<3> xr( la[l](0), la[l](1), la[l](2) );
+				curv.CalcElementTransformation (xr, i-1, xg, dxdxi);
+				for (int i = 0; i < 3; i++)
+				  {
+				    dx(i) = dxdxi(i,0);
+				    dy(i) = dxdxi(i,1);
+				    dz(i) = dxdxi(i,2);
+				  }
+
+				d0 = x0(0)*dx + x0(1)*dy + x0(2)*dz;
+				d1 = x1(0)*dx + x1(1)*dy + x1(2)*dz;
+				n = Cross (d0, d1);
+				glNormal3d ( n(0),  n(1),  n(2));
+				glVertex3d (xg(0), xg(1), xg(2));
+			      }
+			  }
+
+		  } else {
+		    const Point3d & lp1 = mesh->Point (el.PNum(face.PNum(1)));
+		    const Point3d & lp2 = mesh->Point (el.PNum(face.PNum(2)));
+		    const Point3d & lp3 = mesh->Point (el.PNum(face.PNum(3)));
+		    Vec3d n = Cross (Vec3d (lp1, lp3), Vec3d (lp1, lp2));
+		    n /= (n.Length()+1e-12);
+		    glNormal3d (n.X(), n.Y(), n.Z());
+		    glVertex3d (lp1.X(), lp1.Y(), lp1.Z());
+		    glVertex3d (lp2.X(), lp2.Y(), lp2.Z());
+		    glVertex3d (lp3.X(), lp3.Y(), lp3.Z());
+		  }
+	      }
+	     
+	    glEnd();
+	  }
+
+      }
+  }
+  glEndList ();
+
+
+
+
+#else
+
+
+  int i, j, k, l;
+  ARRAY<Element2d> faces;
+
+  if (tettimestamp > mesh->GetTimeStamp () &&
+      tettimestamp > vispar.clipplanetimestamp )
+    return;
+
+  if (!lock)
+  {
+    lock = new NgLock (mesh->Mutex());
+    lock -> Lock();
+  }
+
+  tettimestamp = NextTimeStamp();
+
+  if (tetlist)
+    glDeleteLists (tetlist, 1);
+
+
+  tetlist = glGenLists (1);
+  glNewList (tetlist, GL_COMPILE);
+
+  
+  BitArray shownode(mesh->GetNP());
+  if (vispar.clipenable)
+  {
+    shownode.Clear();
+    for (i = 1; i <= shownode.Size(); i++)
+      {
+	Point3d p = mesh->Point(i);
+	  
+	double val =
+	  p.X() * clipplane[0] +
+	  p.Y() * clipplane[1] +
+	  p.Z() * clipplane[2] +
+	  clipplane[3];
+	  
+	if (val > 0)
+	  shownode.Set (i);
+      }
+  }
+  else
+  shownode.Set();
+
+
+  static float tetcols[][4] = 
+    {
+      { 1.0f, 1.0f, 0.0f, 1.0f },
+      { 1.0f, 0.0f, 0.0f, 1.0f },
+      { 0.0f, 1.0f, 0.0f, 1.0f },
+      { 0.0f, 0.0f, 1.0f, 1.0f }
+    };
+
+
+  // ARRAY<int> elfaces;
+
+  // const MeshTopology & top = mesh->GetTopology();
+  CurvedElements & curv = mesh->GetCurvedElements();
+    
+
+  for (i = 1; i <= mesh->GetNE(); i++)
+  {
+    if (vispar.drawtetsdomain > 0 &&
+	vispar.drawtetsdomain != mesh->VolumeElement(i).GetIndex())
+      continue;
+
+    if (mesh->VolumeElement(i).GetType() == TET)
+      {
+	// copy to be thread-safe
+	Element el = mesh->VolumeElement (i);
+	el.GetSurfaceTriangles (faces);
+
+	if (el.PNum(1))
+	  {
+	    int drawtet = 1;
+	    for (j = 1; j <= el.GetNP(); j++)
+	      if (!shownode.Test(el.PNum(j)))
+		drawtet = 0;
+	    if (!drawtet) continue;
+
+	    Point3d c;
+	    if (vispar.shrink < 1)
+	      c = Center (Center (mesh->Point (el.PNum(1)),
+				  mesh->Point (el.PNum(2))),
+			  Center (mesh->Point (el.PNum(3)),
+				  mesh->Point (el.PNum(4))));
+
+
+
+	    int ind = el.GetIndex() % 4;
+	    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, tetcols[ind]);
+
+
+	    // top.GetElementFaces (i, elfaces);
+
+	    glBegin (GL_TRIANGLES);
+
+	    for (j = 0; j < faces.Size(); j++)
+	      {
+		Element2d & face = faces.Elem(j+1);
+
+		if (curv.IsHighOrder() && curv.IsElementCurved(i-1))
+		  {
+		    int hoplotn = 1 << vispar.subdivisions; 
+		    // int hoplotn = curv.GetNVisualSubsecs();
+			    
+		    const Point3d * facepoint = MeshTopology :: GetVertices (TET);
+		    const ELEMENT_FACE * elface = MeshTopology :: GetFaces(TET);
+                    
+		    Vec<3> x0,x1,d0,d1;
+		    Point<3> xg;
+		    x0 = facepoint[face.PNum(3)-1] - facepoint[face.PNum(1)-1];
+		    x1 = facepoint[face.PNum(2)-1] - facepoint[face.PNum(1)-1];
+		    x0.Normalize();
+		    x1.Normalize();
+
+		    for (int m0 = 0; m0 < hoplotn; m0++)
+		      for (int m1 = 0; m1 < hoplotn-m0; m1++)
+			for (k = 0; k < 2; k++)
+			  {
+			    Vec<3> dx, dy, dz, n;
+			    Point<4> la[3];
+					
+			    for (l = 0; l<3; l++) la[l] = Point<4>(0.,0.,0.,0.);
+
+			    if (k == 0)
+			      {
+				la[0](face.PNum(1)-1) = (m0  )/(double)hoplotn;
+				la[0](face.PNum(2)-1) = (m1  )/(double)hoplotn;
+				la[0](face.PNum(3)-1) = 1-la[0](face.PNum(1)-1)-la[0](face.PNum(2)-1);
+
+				la[1](face.PNum(1)-1) = (m0+1)/(double)hoplotn;
+				la[1](face.PNum(2)-1) = (m1  )/(double)hoplotn;
+				la[1](face.PNum(3)-1) = 1-la[1](face.PNum(1)-1)-la[1](face.PNum(2)-1);
+
+				la[2](face.PNum(1)-1) = (m0  )/(double)hoplotn;
+				la[2](face.PNum(2)-1) = (m1+1)/(double)hoplotn;
+				la[2](face.PNum(3)-1) = 1-la[2](face.PNum(1)-1)-la[2](face.PNum(2)-1);
+			      } else
+				{
+				  if (m1 == hoplotn-m0-1) continue;
+				  la[0](face.PNum(1)-1) = (m0+1)/(double)hoplotn;
+				  la[0](face.PNum(2)-1) = (m1+1)/(double)hoplotn;
+				  la[0](face.PNum(3)-1) = 1-la[0](face.PNum(1)-1)-la[0](face.PNum(2)-1);
+
+				  la[1](face.PNum(1)-1) = (m0  )/(double)hoplotn;
+				  la[1](face.PNum(2)-1) = (m1+1)/(double)hoplotn;
+				  la[1](face.PNum(3)-1) = 1-la[1](face.PNum(1)-1)-la[1](face.PNum(2)-1);
+
+				  la[2](face.PNum(1)-1) = (m0+1)/(double)hoplotn;
+				  la[2](face.PNum(2)-1) = (m1  )/(double)hoplotn;
+				  la[2](face.PNum(3)-1) = 1-la[2](face.PNum(1)-1)-la[2](face.PNum(2)-1);
+				}
+
+			    for (l = 0; l<3; l++)
+			      {
+				Mat<3,3> dxdxi;
+				Point<3> xr( la[l](0), la[l](1), la[l](2) );
+				curv.CalcElementTransformation (xr, i-1, xg, dxdxi);
+				for (int i = 0; i < 3; i++)
+				  {
+				    dx(i) = dxdxi(i,0);
+				    dy(i) = dxdxi(i,1);
+				    dz(i) = dxdxi(i,2);
+				  }
+
+				d0 = x0(0)*dx + x0(1)*dy + x0(2)*dz;
+				d1 = x1(0)*dx + x1(1)*dy + x1(2)*dz;
+				n = Cross (d0, d1);
+				glNormal3d ( n(0),  n(1),  n(2));
+				glVertex3d (xg(0), xg(1), xg(2));
+			      }
+			  }
+
+		  } else {
+		    Point3d lp1 = mesh->Point (el.PNum(face.PNum(1)));
+		    Point3d lp2 = mesh->Point (el.PNum(face.PNum(2)));
+		    Point3d lp3 = mesh->Point (el.PNum(face.PNum(3)));
+		    Vec3d n = Cross (Vec3d (lp1, lp3), Vec3d (lp1, lp2));
+		    n /= (n.Length()+1e-12);
+		    glNormal3d (n.X(), n.Y(), n.Z());
+
+		    if (vispar.shrink < 1)
+		      {
+			lp1 = c + vispar.shrink * (lp1 - c);
+			lp2 = c + vispar.shrink * (lp2 - c);
+			lp3 = c + vispar.shrink * (lp3 - c);
+		      }
+
+		    glVertex3d (lp1.X(), lp1.Y(), lp1.Z());
+		    glVertex3d (lp2.X(), lp2.Y(), lp2.Z());
+		    glVertex3d (lp3.X(), lp3.Y(), lp3.Z());
+		  }
+	      }
+	     
+	    glEnd();
+	  }
+      }
+  }
+  glEndList ();
+
+
+
+#endif
+}
+
+
+void VisualSceneMesh :: BuildPrismList()
+{
+  int i, j;
+
+  prismlist = glGenLists (1);
+  glNewList (prismlist, GL_COMPILE);
+
+  static float prismcol[] = { 0.0f, 1.0f, 1.0f, 1.0f };
+  glLineWidth (1.0f);  
+
+  ARRAY<Element2d> faces;
+
+  for (i = 1; i <= mesh->GetNE(); i++)
+    {
+      if (mesh->VolumeElement(i).GetType() == PRISM)
+	{
+	  // copy to be thread-safe
+	  Element el = mesh->VolumeElement (i);
+	  el.GetSurfaceTriangles (faces);
+
+	  glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, prismcol);
+	  if (el.PNum(1))
+	    {
+	      CurvedElements & curv = mesh->GetCurvedElements();
+	      if (curv.IsHighOrder() && curv.IsElementCurved(i-1))
+		{
+		  int hoplotn = 1 << vispar.subdivisions; 
+		  // int hoplotn = curv.GetNVisualSubsecs();
+
+		  const Point3d * facepoint = MeshTopology :: GetVertices (TRIG);
+		  const ELEMENT_FACE * elface = MeshTopology :: GetFaces(TRIG);
+
+		  glBegin (GL_TRIANGLES);
+
+		  for (int trig = 0; trig<2; trig++)
+		    {
+                    
+		      Vec<3> x0,x1,d0,d1;
+		      x0 = facepoint[1] - facepoint[2];
+		      x1 = facepoint[0] - facepoint[2];
+		      x0.Normalize();
+		      x1.Normalize();
+		      if (trig == 1) Swap (x0,x1);
+
+		      Point<3> xr[3];
+		      Point<3> xg;
+		      Vec<3> dx, dy, dz, n;
+
+		      for (int i1 = 0; i1 < hoplotn; i1++)
+			for (int j1 = 0; j1 < hoplotn-i1; j1++)
+			  for (int k = 0; k < 2; k++)
+			    {
+			      if (k == 0)
+				{
+				  xr[0](0) = (double)    i1/hoplotn; xr[0](1) = (double)    j1/hoplotn;
+				  xr[1](0) = (double)(i1+1)/hoplotn; xr[1](1) = (double)    j1/hoplotn;
+				  xr[2](0) = (double)    i1/hoplotn; xr[2](1) = (double)(j1+1)/hoplotn;
+				} else
+				  {
+				    if (j1 == hoplotn-i1-1) continue;
+				    xr[0](0) = (double)(i1+1)/hoplotn; xr[0](1) = (double)    j1/hoplotn;
+				    xr[1](0) = (double)(i1+1)/hoplotn; xr[1](1) = (double)(j1+1)/hoplotn;
+				    xr[2](0) = (double)    i1/hoplotn; xr[2](1) = (double)(j1+1)/hoplotn;
+				  };
+				    
+			      for (int l=0; l<3; l++)
+				{
+				  Mat<3,3> dxdxi;
+				  xr[l](2) = (double) trig;
+				  curv.CalcElementTransformation (xr[l], i-1, xg, dxdxi);
+				  for (int i = 0; i < 3; i++)
+				    {
+				      dx(i) = dxdxi(i,0);
+				      dy(i) = dxdxi(i,1);
+				      dz(i) = dxdxi(i,2);
+				    }
+
+				  Vec<3> d0 = x0(0)*dx + x0(1)*dy + x0(2)*dz;
+				  Vec<3> d1 = x1(0)*dx + x1(1)*dy + x1(2)*dz;
+				  n = Cross (d1, d0);
+				  glNormal3d (n(0), n(1), n(2));
+				  glVertex3d (xg(0), xg(1), xg(2));
+				}
+			    }
+			
+		    }
+
+		  glEnd ();
+
+		  glBegin (GL_QUADS);
+
+		  for (int quad = 0; quad<3; quad++)
+		    {   
+		      const Point3d * facepoint = MeshTopology :: GetVertices (PRISM);
+
+		      Vec<3> x0,x1;
+		      int xyz;
+
+		      switch (quad)
+			{
+			case 0:
+			  x0 = facepoint[5] - facepoint[2];
+			  x1 = facepoint[0] - facepoint[2];
+			  xyz = 0;
+			  break;
+			case 1:
+			  x0 = facepoint[4] - facepoint[0];
+			  x1 = facepoint[1] - facepoint[0];
+			  xyz = 0;
+			  break;
+			case 2:
+			  x0 = facepoint[1] - facepoint[2];
+			  x1 = facepoint[5] - facepoint[2];
+			  xyz = 1;
+			  break;
+			}
+
+		      x0.Normalize();
+		      x1.Normalize();
+
+		      Swap (x0,x1);
+
+		      Point<3> xr[4];
+		      Point<3> xg;
+		      Vec<3> dx, dy, dz, n;
+
+		      for (int i1 = 0; i1 < hoplotn; i1++)
+			for (int j1 = 0; j1 < hoplotn; j1++)
+			  {
+			    xr[0](xyz) = (double)    i1/hoplotn; xr[0](2) = (double)    j1/hoplotn;
+			    xr[1](xyz) = (double)(i1+1)/hoplotn; xr[1](2) = (double)    j1/hoplotn;
+			    xr[2](xyz) = (double)(i1+1)/hoplotn; xr[2](2) = (double)(j1+1)/hoplotn;
+			    xr[3](xyz) = (double)    i1/hoplotn; xr[3](2) = (double)(j1+1)/hoplotn;
+				    
+			    for (int l=0; l<4; l++)
+			      {
+				switch (quad)
+				  {
+				  case 0: xr[l](1) = 0; break;
+				  case 1: xr[l](1) = 1-xr[l](0); break;
+				  case 2: xr[l](0) = 0; break;
+				  }
+
+				Mat<3,3> dxdxi;
+				curv.CalcElementTransformation (xr[l], i-1, xg, dxdxi);
+				for (int i = 0; i < 3; i++)
+				  {
+				    dx(i) = dxdxi(i,0);
+				    dy(i) = dxdxi(i,1);
+				    dz(i) = dxdxi(i,2);
+				  }
+
+				Vec<3> d0 = x0(0)*dx + x0(1)*dy + x0(2)*dz;
+				Vec<3> d1 = x1(0)*dx + x1(1)*dy + x1(2)*dz;
+				n = Cross (d1, d0);
+				glNormal3d (n(0), n(1), n(2));
+				glVertex3d (xg(0), xg(1), xg(2));
+			      }
+			  }
+		    }
+		  glEnd ();
+		} else
+		  { 
+		    Point3d c(0,0,0);
+		    if (vispar.shrink < 1)
+		      {
+			for (j = 1; j <= 6; j++)
+			  {
+			    Point3d p = mesh->Point(el.PNum(j));
+			    c.X() += p.X() / 6;
+			    c.Y() += p.Y() / 6;
+			    c.Z() += p.Z() / 6;
+			  }
+		      }
+
+		    glBegin (GL_TRIANGLES);
+
+		    for (j = 1; j <= faces.Size(); j++)
+		      {
+			Element2d & face = faces.Elem(j);
+			Point3d lp1 = mesh->Point (el.PNum(face.PNum(1)));
+			Point3d lp2 = mesh->Point (el.PNum(face.PNum(2)));
+			Point3d lp3 = mesh->Point (el.PNum(face.PNum(3)));
+			Vec3d n = Cross (Vec3d (lp1, lp3), Vec3d (lp1, lp2));
+			n /= (n.Length()+1e-12);
+			glNormal3d (n.X(), n.Y(), n.Z());
+			if (vispar.shrink < 1)
+			  {
+			    lp1 = c + vispar.shrink * (lp1 - c);
+			    lp2 = c + vispar.shrink * (lp2 - c);
+			    lp3 = c + vispar.shrink * (lp3 - c);
+			  }
+			glVertex3d (lp1.X(), lp1.Y(), lp1.Z());
+			glVertex3d (lp2.X(), lp2.Y(), lp2.Z());
+			glVertex3d (lp3.X(), lp3.Y(), lp3.Z());
+		      }
+	      
+		    glEnd();
+		  }
+	    }
+	}
+    }
+  glEndList ();
+}
+ 
+
+
+
+
+
+
+void VisualSceneMesh :: BuildHexList()
+{
+  int i, j;
+
+  hexlist = glGenLists (1);
+  glNewList (hexlist, GL_COMPILE);
+
+  static float hexcol[] = { 1.0f, 1.0f, 0.0f, 1.0f };
+  glLineWidth (1.0f);  
+  glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, hexcol);
+
+  ARRAY<Element2d> faces;
+
+  for (i = 1; i <= mesh->GetNE(); i++)
+    {
+      Element el = mesh->VolumeElement (i);
+
+      if (el.GetType() == HEX &&
+	  el.PNum(1))
+	{
+	  el.GetSurfaceTriangles (faces);
+
+	  CurvedElements & curv = mesh->GetCurvedElements();
+	  if (curv.IsHighOrder() && curv.IsElementCurved(i-1))
+	    {
+	      cerr << "draw curved hex not implemented" << endl;
+	      int hoplotn = 1 << vispar.subdivisions; 
+	      // int hoplotn = curv.GetNVisualSubsecs();
+	      
+	      const Point3d * facepoint = MeshTopology :: GetVertices (TRIG);
+	      const ELEMENT_FACE * elface = MeshTopology :: GetFaces(TRIG);
+	      
+	      glBegin (GL_TRIANGLES);
+	      
+	      for (int trig = 0; trig<2; trig++)
+		{
+		  Vec<3> x0,x1,d0,d1;
+		  x0 = facepoint[1] - facepoint[2];
+		  x1 = facepoint[0] - facepoint[2];
+		      x0.Normalize();
+		      x1.Normalize();
+		      if (trig == 1) Swap (x0,x1);
+
+		      Point<3> xr[3];
+		      Point<3> xg;
+		      Vec<3> dx, dy, dz, n;
+
+		      for (int i1 = 0; i1 < hoplotn; i1++)
+			for (int j1 = 0; j1 < hoplotn-i1; j1++)
+			  for (int k = 0; k < 2; k++)
+			    {
+			      if (k == 0)
+				{
+				  xr[0](0) = (double)    i1/hoplotn; xr[0](1) = (double)    j1/hoplotn;
+				  xr[1](0) = (double)(i1+1)/hoplotn; xr[1](1) = (double)    j1/hoplotn;
+				  xr[2](0) = (double)    i1/hoplotn; xr[2](1) = (double)(j1+1)/hoplotn;
+				} else
+				  {
+				    if (j1 == hoplotn-i1-1) continue;
+				    xr[0](0) = (double)(i1+1)/hoplotn; xr[0](1) = (double)    j1/hoplotn;
+				    xr[1](0) = (double)(i1+1)/hoplotn; xr[1](1) = (double)(j1+1)/hoplotn;
+				    xr[2](0) = (double)    i1/hoplotn; xr[2](1) = (double)(j1+1)/hoplotn;
+				  };
+				    
+			      for (int l=0; l<3; l++)
+				{
+				  Mat<3,3> dxdxi;
+				  xr[l](2) = (double) trig;
+				  curv.CalcElementTransformation (xr[l], i-1, xg, dxdxi);
+				  for (int i = 0; i < 3; i++)
+				    {
+				      dx(i) = dxdxi(i,0);
+				      dy(i) = dxdxi(i,1);
+				      dz(i) = dxdxi(i,2);
+				    }
+
+				  Vec<3> d0 = x0(0)*dx + x0(1)*dy + x0(2)*dz;
+				  Vec<3> d1 = x1(0)*dx + x1(1)*dy + x1(2)*dz;
+				  n = Cross (d1, d0);
+				  glNormal3d (n(0), n(1), n(2));
+				  glVertex3d (xg(0), xg(1), xg(2));
+				}
+			    }
+			
+		    }
+
+		  glEnd ();
+
+		  glBegin (GL_QUADS);
+
+		  for (int quad = 0; quad<3; quad++)
+		    {   
+		      const Point3d * facepoint = MeshTopology :: GetVertices (PRISM);
+
+		      Vec<3> x0,x1;
+		      int xyz;
+
+		      switch (quad)
+			{
+			case 0:
+			  x0 = facepoint[5] - facepoint[2];
+			  x1 = facepoint[0] - facepoint[2];
+			  xyz = 0;
+			  break;
+			case 1:
+			  x0 = facepoint[4] - facepoint[0];
+			  x1 = facepoint[1] - facepoint[0];
+			  xyz = 0;
+			  break;
+			case 2:
+			  x0 = facepoint[1] - facepoint[2];
+			  x1 = facepoint[5] - facepoint[2];
+			  xyz = 1;
+			  break;
+			}
+
+		      x0.Normalize();
+		      x1.Normalize();
+
+		      Swap (x0,x1);
+
+		      Point<3> xr[4];
+		      Point<3> xg;
+		      Vec<3> dx, dy, dz, n;
+
+		      for (int i1 = 0; i1 < hoplotn; i1++)
+			for (int j1 = 0; j1 < hoplotn; j1++)
+			  {
+			    xr[0](xyz) = (double)    i1/hoplotn; xr[0](2) = (double)    j1/hoplotn;
+			    xr[1](xyz) = (double)(i1+1)/hoplotn; xr[1](2) = (double)    j1/hoplotn;
+			    xr[2](xyz) = (double)(i1+1)/hoplotn; xr[2](2) = (double)(j1+1)/hoplotn;
+			    xr[3](xyz) = (double)    i1/hoplotn; xr[3](2) = (double)(j1+1)/hoplotn;
+				    
+			    for (int l=0; l<4; l++)
+			      {
+				switch (quad)
+				  {
+				  case 0: xr[l](1) = 0; break;
+				  case 1: xr[l](1) = 1-xr[l](0); break;
+				  case 2: xr[l](0) = 0; break;
+				  }
+
+				Mat<3,3> dxdxi;
+				curv.CalcElementTransformation (xr[l], i-1, xg, dxdxi);
+				for (int i = 0; i < 3; i++)
+				  {
+				    dx(i) = dxdxi(i,0);
+				    dy(i) = dxdxi(i,1);
+				    dz(i) = dxdxi(i,2);
+				  }
+
+				Vec<3> d0 = x0(0)*dx + x0(1)*dy + x0(2)*dz;
+				Vec<3> d1 = x1(0)*dx + x1(1)*dy + x1(2)*dz;
+				n = Cross (d1, d0);
+				glNormal3d (n(0), n(1), n(2));
+				glVertex3d (xg(0), xg(1), xg(2));
+			      }
+			  }
+		    }
+		  glEnd ();
+	    } 
+	  else
+	    { 
+	      Point3d c(0,0,0);
+	      if (vispar.shrink < 1)
+		{
+		  for (j = 1; j <= 8; j++)
+		    {
+		      Point3d p = mesh->Point(el.PNum(j));
+		      c.X() += p.X();
+		      c.Y() += p.Y();
+		      c.Z() += p.Z();
+		    }
+		  c.X() /= 8;
+		  c.Y() /= 8;
+		  c.Z() /= 8;
+		}
+
+
+	      glBegin (GL_TRIANGLES);
+	      
+	      for (j = 1; j <= faces.Size(); j++)
+		{
+		  Element2d & face = faces.Elem(j);
+		  Point3d lp1 = mesh->Point (el.PNum(face.PNum(1)));
+		  Point3d lp2 = mesh->Point (el.PNum(face.PNum(2)));
+		  Point3d lp3 = mesh->Point (el.PNum(face.PNum(3)));
+		  Vec3d n = Cross (Vec3d (lp1, lp3), Vec3d (lp1, lp2));
+		  n /= (n.Length()+1e-12);
+		  glNormal3d (n.X(), n.Y(), n.Z());
+		  
+		  if (vispar.shrink < 1)
+		    {
+		      lp1 = c + vispar.shrink * (lp1 - c);
+		      lp2 = c + vispar.shrink * (lp2 - c);
+		      lp3 = c + vispar.shrink * (lp3 - c);
+		    }
+
+		  glVertex3d (lp1.X(), lp1.Y(), lp1.Z());
+		  glVertex3d (lp2.X(), lp2.Y(), lp2.Z());
+		  glVertex3d (lp3.X(), lp3.Y(), lp3.Z());
+		}
+	      glEnd();
+	    }
+	}
+    }
+  glEndList ();
+}
+
+
+
+
+
+
+
+
+ 
+void VisualSceneMesh :: BuildPyramidList()
+{
+  int i, j;
+
+  pyramidlist = glGenLists (1);
+  glNewList (pyramidlist, GL_COMPILE);
+  
+  static float pyramidcol[] = { 1.0f, 0.0f, 1.0f, 1.0f };
+  glLineWidth (1.0f);
+  ARRAY<Element2d> faces;
+
+  for (i = 1; i <= mesh->GetNE(); i++)
+    {
+      if (mesh->VolumeElement(i).GetType() == PYRAMID)
+	{
+	  // copy to be thread-safe
+	  Element el = mesh->VolumeElement (i);
+
+	  Point3d c(0,0,0);
+	  if (vispar.shrink < 1)
+	    {
+	      for (j = 1; j <= 5; j++)
+		{
+		  Point3d p = mesh->Point(el.PNum(j));
+		  c.X() += p.X() / 5;
+		  c.Y() += p.Y() / 5;
+		  c.Z() += p.Z() / 5;
+		}
+	    }
+
+
+	  el.GetSurfaceTriangles (faces);
+	  
+	  glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, pyramidcol);
+	  if (el.PNum(1))
+	    {
+	      glBegin (GL_TRIANGLES);
+	      
+	      for (j = 1; j <= faces.Size(); j++)
+		{
+		  Element2d & face = faces.Elem(j);
+		  Point3d lp1 = mesh->Point (el.PNum(face.PNum(1)));
+		  Point3d lp2 = mesh->Point (el.PNum(face.PNum(2)));
+		  Point3d lp3 = mesh->Point (el.PNum(face.PNum(3)));
+		  Vec3d n = Cross (Vec3d (lp1, lp2), Vec3d (lp1, lp3));
+		  n /= (n.Length()+1e-12);
+		  n *= -1;
+		  glNormal3d (n.X(), n.Y(), n.Z());
+
+		  if (vispar.shrink < 1)
+		    {
+		      lp1 = c + vispar.shrink * (lp1 - c);
+		      lp2 = c + vispar.shrink * (lp2 - c);
+		      lp3 = c + vispar.shrink * (lp3 - c);
+		    }
+
+		  glVertex3d (lp1.X(), lp1.Y(), lp1.Z());
+		  glVertex3d (lp2.X(), lp2.Y(), lp2.Z());
+		  glVertex3d (lp3.X(), lp3.Y(), lp3.Z());
+		}
+	      
+	      glEnd();
+	    }
+	}
+    }
+  glEndList ();
+}
+
+void VisualSceneMesh :: BuildBadelList()
+{
+  ;
+}
+
+void VisualSceneMesh :: BuildIdentifiedList()
+{
+  ;
+}
+  
+void VisualSceneMesh :: BuildDomainSurfList()
+{
+  if (domainsurflist)
+    glDeleteLists (domainsurflist, 1);
+
+  domainsurflist = glGenLists (1);
+  glNewList (domainsurflist, GL_COMPILE);
+
+  int i, j;
+  glLineWidth (1.0f);
+  
+  glDisable (GL_COLOR_MATERIAL);
+  
+  for (i = 1; i <= mesh->GetNSE(); i++)
+    {
+      Element2d el = mesh->SurfaceElement (i);
+      
+      int drawel = 1;
+      for (j = 1; j <= el.GetNP(); j++)
+	{
+	  if (!el.PNum(j))
+	    drawel = 0;
+	}
+      
+      if (!drawel)
+	continue;
+      
+      if (el.GetIndex() < 1 || el.GetIndex() > mesh->GetNFD())
+	continue;
+      int domin = mesh->GetFaceDescriptor(el.GetIndex()).DomainIn();
+      int domout = mesh->GetFaceDescriptor(el.GetIndex()).DomainOut();
+
+      int fac;
+      if (domin == vispar.drawdomainsurf)
+	fac = 1;
+      else if (domout == vispar.drawdomainsurf)
+	fac = -1;
+      else
+	continue;
+      
+      
+      GLfloat matcol[] = { 1, 0, 0, 1 };
+      glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, matcol);
+      
+      
+      if (el.GetNP() == 3)
+	{
+	  glBegin (GL_TRIANGLES);
+	      
+	  const Point3d & lp1 = mesh->Point (el.PNum(1));
+	  const Point3d & lp2 = mesh->Point (el.PNum(2));
+	  const Point3d & lp3 = mesh->Point (el.PNum(3));
+	  Vec3d n = Cross (Vec3d (lp1, lp2), Vec3d (lp1, lp3));
+	  n /= ( fac * (n.Length()+1e-12));
+	  glNormal3d (n.X(), n.Y(), n.Z());
+	  
+	  if (!vispar.colormeshsize)
+	    {
+	      glVertex3d (lp1.X(), lp1.Y(), lp1.Z());
+	      glVertex3d (lp2.X(), lp2.Y(), lp2.Z());
+	      glVertex3d (lp3.X(), lp3.Y(), lp3.Z());
+	    }
+	  glEnd();
+	}
+      else if (el.GetNP() == 4)
+	{
+	  glBegin (GL_QUADS);
+	  
+	  const Point3d & lp1 = mesh->Point (el.PNum(1));
+	  const Point3d & lp2 = mesh->Point (el.PNum(2));
+	  const Point3d & lp3 = mesh->Point (el.PNum(4));
+	  const Point3d & lp4 = mesh->Point (el.PNum(3));
+	  Vec3d n = Cross (Vec3d (lp1, lp2), 
+			   Vec3d (lp1, Center (lp3, lp4)));
+	  n /= (fac * (n.Length()+1e-12));
+	  glNormal3d (n.X(), n.Y(), n.Z()); 
+	  glVertex3d (lp1.X(), lp1.Y(), lp1.Z());
+	  glVertex3d (lp2.X(), lp2.Y(), lp2.Z());
+	  glVertex3d (lp4.X(), lp4.Y(), lp4.Z());
+	  glVertex3d (lp3.X(), lp3.Y(), lp3.Z());
+	  glEnd();
+	}
+      else if (el.GetNP() == 6)
+	{
+	  glBegin (GL_TRIANGLES);
+	  static int trigs[4][3] = {
+	    { 1, 6, 5 },
+	    { 2, 4, 6 },
+	    { 3, 5, 4 },
+	    { 4, 5, 6 } };
+	  
+	  for (j = 0; j < 4; j++)
+	    {
+	      const Point3d & lp1 = mesh->Point (el.PNum(trigs[j][0]));
+	      const Point3d & lp2 = mesh->Point (el.PNum(trigs[j][1]));
+	      const Point3d & lp3 = mesh->Point (el.PNum(trigs[j][2]));
+	      Vec3d n = Cross (Vec3d (lp1, lp2), Vec3d (lp1, lp3));
+	      n /= (fac * (n.Length() + 1e-12));
+	      glNormal3d (n.X(), n.Y(), n.Z());
+	      glVertex3d (lp1.X(), lp1.Y(), lp1.Z());
+	      glVertex3d (lp2.X(), lp2.Y(), lp2.Z());
+	      glVertex3d (lp3.X(), lp3.Y(), lp3.Z());
+	    }
+	  glEnd();
+	}
+    }
+  glEndList ();
+}
+
+
+
+
+
+
+
+
+
+
+
+
+void VisualSceneMesh :: MouseDblClick (int px, int py)
+{
+  int i, hits;
+
+  // select surface triangle by mouse click
+
+  GLuint selbuf[10000];
+  glSelectBuffer (10000, selbuf);
+
+
+  glRenderMode (GL_SELECT);
+
+  GLint viewport[4];
+  glGetIntegerv (GL_VIEWPORT, viewport);
+
+
+  glMatrixMode (GL_PROJECTION); 
+  glPushMatrix();
+
+  GLdouble projmat[16];
+  glGetDoublev (GL_PROJECTION_MATRIX, projmat);
+
+  glLoadIdentity(); 
+  gluPickMatrix (px, viewport[3] - py, 1, 1, viewport); 
+  glMultMatrixd (projmat);
+  
+
+
+  glClearColor(backcolor, backcolor, backcolor, 1.0);
+  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+  glMatrixMode (GL_MODELVIEW); 
+
+  glPushMatrix();
+  glMultMatrixf (transformationmat);
+
+
+  //  SetClippingPlane();
+
+  glInitNames();
+  glPushName (1);
+
+  glPolygonOffset (1, 1);
+  glEnable (GL_POLYGON_OFFSET_FILL);
+
+  glDisable(GL_CLIP_PLANE0);
+  
+  if (vispar.clipenable)
+    {
+      Vec<3> n(clipplane[0], clipplane[1], clipplane[2]);
+      double len = Abs(n);
+      double mu = -clipplane[3] / (len*len);
+      Point<3> p (mu * n);
+      n /= len;
+      Vec<3> t1 = n.GetNormal ();
+      Vec<3> t2 = Cross (n, t1);
+      
+      double xi1mid = (center - p) * t1;
+      double xi2mid = (center - p) * t2;
+      
+      glLoadName (0);  
+      glBegin (GL_QUADS);
+      glVertex3dv (p + (xi1mid-rad) * t1 + (xi2mid-rad) * t2);
+      glVertex3dv (p + (xi1mid+rad) * t1 + (xi2mid-rad) * t2);
+      glVertex3dv (p + (xi1mid+rad) * t1 + (xi2mid+rad) * t2);
+      glVertex3dv (p + (xi1mid-rad) * t1 + (xi2mid+rad) * t2);
+      glEnd ();
+    }
+
+  //  SetClippingPlane();
+
+  glCallList (filledlist);
+
+  glDisable (GL_POLYGON_OFFSET_FILL);
+  
+  glPopName();
+
+  glMatrixMode (GL_PROJECTION); 
+  glPopMatrix();
+
+  glMatrixMode (GL_MODELVIEW); 
+  glPopMatrix();
+
+  glFlush();  
+
+	
+  hits = glRenderMode (GL_RENDER);
+
+  //  cout << "hits = " << hits << endl;
+
+  int minname = 0;
+  GLuint mindepth = 0;
+
+  // find clippingplane
+  GLuint clipdepth = 0; // GLuint(-1);
+
+  for (i = 0; i < hits; i++)
+    {
+      int curname = selbuf[4*i+3];
+      if (!curname) clipdepth = selbuf[4*i+1];
+    }
+
+  for (i = 0; i < hits; i++)
+    {
+      int curname = selbuf[4*i+3];
+      GLuint curdepth = selbuf[4*i+1];
+      /*
+      cout << selbuf[4*i] << " " << selbuf[4*i+1] << " " 
+	   << selbuf[4*i+2] << " " << selbuf[4*i+3] << endl;
+      */
+      if (curname && (curdepth > clipdepth) &&
+	  (curdepth < mindepth || !minname))
+	{
+	  mindepth = curdepth;
+	  minname = curname;
+	}
+    }
+
+  seledge = -1;
+  if (minname)
+    {
+      const Element2d & sel = mesh->SurfaceElement(minname);
+
+
+      cout << "select element " << minname
+	   << " on face " << sel.GetIndex() << endl;
+      cout << "Nodes: ";
+      for (i = 1; i <= sel.GetNP(); i++)
+	cout << sel.PNum(i) << " ";
+      cout << endl;
+
+      selelement = minname;
+      selface = mesh->SurfaceElement(minname).GetIndex();
+
+      locpi = (locpi % sel.GetNP()) + 1;
+      selpoint2 = selpoint;
+      selpoint = sel.PNum(locpi);
+      cout << "selected point " << selpoint 
+	   << ", pos = " << mesh->Point (selpoint) 
+	   << endl;
+
+      for (i = 1; i <= mesh->GetNSeg(); i++)
+	{
+	  const Segment & seg = mesh->LineSegment(i);
+	  if (seg.p1 == selpoint && seg.p2 == selpoint2 || 
+	      seg.p2 == selpoint && seg.p1 == selpoint2)
+	    {
+	      seledge = seg.edgenr;
+	      cout << "seledge = " << seledge << endl;
+	    }
+	}
+      
+    }
+  else
+    {
+      selface = -1;
+      selelement = -1;
+      selpoint = -1;
+      selpoint2 = -1;
+    }
+
+  glDisable(GL_CLIP_PLANE0);
+
+  selecttimestamp = NextTimeStamp();
+}
+
+
+
+
+
+}
+
+
+
+
+
+
+
+
+
+  
diff --git a/Netgen/libsrc/visualization/vssolution.cpp b/Netgen/libsrc/visualization/vssolution.cpp
new file mode 100644
index 0000000000..8678fc900d
--- /dev/null
+++ b/Netgen/libsrc/visualization/vssolution.cpp
@@ -0,0 +1,2738 @@
+#include <mystdlib.h>
+#include "incvis.hpp"
+
+
+#include <myadt.hpp>
+#include <meshing.hpp>
+#include <csg.hpp>
+#include <stlgeom.hpp>
+
+#include <visual.hpp>
+
+
+namespace netgen
+{
+
+  extern AutoPtr<Mesh> mesh;
+
+  
+  VisualSceneSolution :: VisualSceneSolution ()
+    : VisualScene()
+  {
+    surfellist = 0;
+    linelist = 0;
+    clipplanelist = 0;
+    isolinelist = 0;
+    surface_vector_list = 0;
+    cone_list = 0;
+
+    surfeltimestamp = GetTimeStamp();
+    clipplanetimestamp = GetTimeStamp();
+    solutiontimestamp = GetTimeStamp();
+    fieldlinestimestamp = GetTimeStamp();
+    surface_vector_timestamp = GetTimeStamp();
+    AddVisualizationScene ("solution", &vssolution);
+  }
+  
+  VisualSceneSolution :: ~VisualSceneSolution ()
+  {
+    ;
+  }
+
+  void VisualSceneSolution :: AddSolutionData (SolData * sd)
+  {
+    int i, funcnr = -1;
+    
+    for (i = 0; i < soldata.Size(); i++)
+      {
+	if (strcmp (soldata[i]->name, sd->name) == 0)
+	  {
+	    soldata[i] = sd;
+	    funcnr = i;
+	    break;
+	  }
+      }
+    if (funcnr == -1)
+      {
+	soldata.Append (sd);
+	funcnr = soldata.Size()-1;
+      }
+    
+    SolData * nsd = soldata[funcnr];
+
+    nsd->size = 0;
+    if (mesh)
+      {
+	switch (nsd->soltype)
+	  {
+	  case SOL_NODAL: nsd->size = mesh->GetNV(); break;
+	  case SOL_ELEMENT: nsd->size = mesh->GetNE(); break;
+	  case SOL_SURFACE_ELEMENT: nsd->size = mesh->GetNSE(); break;
+	  case SOL_NONCONTINUOUS: 
+	    {
+	      switch (nsd->order)
+		{
+		case 0: nsd->size =      mesh->GetNE(); break;
+		case 1: nsd->size =  6 * mesh->GetNE(); break;
+		case 2: nsd->size = 18 * mesh->GetNE(); break;
+		}
+	      break;
+	    }
+	  case SOL_SURFACE_NONCONTINUOUS: 
+	    {
+	      switch (nsd->order)
+		{
+		case 0: nsd->size =     mesh->GetNSE(); break;
+		case 1: nsd->size = 4 * mesh->GetNSE(); break;
+		case 2: nsd->size = 9 * mesh->GetNSE(); break;
+		}
+	      break;
+	    }
+	  }
+	solutiontimestamp = NextTimeStamp();
+      }
+    
+    /*
+      (*testout) << "set sol-data " << nsd->name
+      << ", size = " << nsd->size << endl;
+      if (nsd->data)
+      for (i = 0; i < nsd->size; i++)
+      (*testout) << i << ": " << nsd->data[i] << endl;
+    */
+  }
+  
+  void VisualSceneSolution :: ClearSolutionData ()
+  {
+    soldata.SetSize (0);
+  }
+
+  void VisualSceneSolution :: UpdateSolutionTimeStamp ()
+  {
+    solutiontimestamp = NextTimeStamp();
+  }
+  
+
+    
+  VisualSceneSolution::SolData * VisualSceneSolution :: GetSolData (int i)
+  { 
+    if (i >= 0 && i < soldata.Size())
+      return soldata[i];
+    else 
+      return NULL;
+  }
+  
+
+
+
+  void VisualSceneSolution :: SaveSolutionData (const char * filename)
+  {
+    PrintMessage (1, "Write solution data to file ", filename);
+    int i, j, k;
+
+    ofstream ost(filename);
+    for (i = 0; i < soldata.Size(); i++)
+    {
+      const SolData & sol = *soldata[i];
+      
+      ost << "solution " 
+	  << sol.name
+	  << " -size=" << sol.size 
+	  << " -components=" << sol.components
+	  << " -order=" << sol.order;
+      if (sol.iscomplex)
+	ost << " -complex";
+      
+      switch (sol.soltype)
+	{
+	case SOL_NODAL:
+	  ost << " -type=nodal"; break;
+	case SOL_ELEMENT:
+	  ost << " -type=element"; break;
+	case SOL_SURFACE_ELEMENT:
+	  ost << " -type=surfaceelement"; break;
+	case SOL_NONCONTINUOUS:
+	  ost << " -type=noncontinuous"; break;
+	case SOL_SURFACE_NONCONTINUOUS:
+	  ost << " -type=surfacenoncontinuous"; break;
+	}
+      
+      ost << endl;
+      for (j = 0; j < sol.size; j++)
+	{
+	  for (k = 0; k < sol.components; k++)
+	    ost << sol.data[j*sol.dist+k] << " ";
+	  ost << "\n";
+	}
+    }
+  }
+  
+
+
+
+  void VisualSceneSolution :: DrawScene ()
+  {
+    /*
+    if (multithread.running) 
+      {
+	VisualScene::DrawScene();      
+	return;
+      }
+    */
+    int i, j, k;
+    
+    if (!mesh) 
+      {
+	VisualScene::DrawScene();      
+	return;
+      }
+
+    static NgLock mem_lock(mem_mutex);
+    mem_lock.Lock();
+
+    /*    
+    lock = NULL;
+    if (!lock)
+      {
+	lock = new NgLock (mesh->Mutex());
+	lock -> Lock();
+      }
+    */
+
+    BuildScene();
+
+    // either continuous, or discrete coloring
+    CreateTexture (numtexturecols, lineartexture);
+
+    glClearColor(backcolor, backcolor, backcolor, 1.0);
+    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+
+    SetLight();
+    
+    glPushMatrix();
+    glMultMatrixf (transformationmat);
+
+  
+
+    glMatrixMode (GL_MODELVIEW); 
+    
+    glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
+    
+    glPolygonOffset (1, 1);
+    glEnable (GL_POLYGON_OFFSET_FILL);
+
+    glEnable (GL_COLOR_MATERIAL);
+
+
+    if (usetexture)
+      glEnable (GL_TEXTURE_1D);
+
+
+    if (vispar.drawfilledtrigs)
+      {
+	SetClippingPlane ();
+	
+	glCallList (surfellist);
+	glCallList (surface_vector_list);
+      
+	glDisable(GL_CLIP_PLANE0);
+      }
+
+    if (showclipsolution)
+      glCallList (clipplanelist);
+  
+
+    if (draw_fieldlines)
+      {
+	BuildFieldLinesPlot ();
+
+	if (num_fieldlineslists <= 1)
+	  glCallList (fieldlineslist);
+	else
+	  {
+	    int start = int (time / 10 * num_fieldlineslists);
+	    for (int ln = 0; ln < 10; ln++)
+	      {
+		int nr = fieldlineslist + (start + ln) % num_fieldlineslists;
+		glCallList (nr);
+	      }
+	  }
+      }
+
+    if (usetexture)
+      glDisable (GL_TEXTURE_1D);
+
+
+
+    glDisable (GL_POLYGON_OFFSET_FILL);
+    
+    glDisable (GL_COLOR_MATERIAL);
+    
+    
+    GLfloat matcol0[] = { 0, 0, 0, 1 };
+    glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, matcol0);
+    glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, matcol0);
+    glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, matcol0);
+    
+    glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
+    glLineWidth (1.0f);
+    glColor3f (0.0f, 0.0f, 0.0f);
+    glDisable (GL_LINE_SMOOTH);
+    
+    if (vispar.drawoutline || numisolines)
+      {
+	SetClippingPlane ();
+	
+	if (numisolines)
+	  {
+	    glCallList (isolinelist);
+	  }
+	else
+	  {
+	    glCallList (linelist);
+	  }
+	
+	glDisable(GL_CLIP_PLANE0);
+      }
+    
+   
+
+    glPopMatrix();
+    
+    glDisable(GL_CLIP_PLANE0);
+    DrawColorBar (minval, maxval, logscale);
+    
+    if (vispar.drawcoordinatecross)
+      DrawCoordinateCross ();
+    DrawNetgenLogo ();
+    
+    glFinish();  
+    
+    /*
+    if (lock)
+      {
+	lock -> UnLock();
+	delete lock;
+      }
+    */
+    mem_lock.UnLock();
+  }
+  
+
+
+  static void RealVec3d (const double * values, Vec3d & v, 
+		  bool iscomplex, bool imag)
+  {
+    if (!iscomplex)
+      {
+	v.X() = values[0];
+	v.Y() = values[1];
+	v.Z() = values[2];
+      }
+    else
+      {
+	if (!imag)
+	  {
+	    v.X() = values[0];
+	    v.Y() = values[2];
+	    v.Z() = values[4];
+	  }
+	else
+	  {
+	    v.X() = values[1];
+	    v.Y() = values[3];
+	    v.Z() = values[5];
+	  }
+      }
+  }
+
+
+  static void RealVec3d (const double * values, Vec3d & v, 
+			 bool iscomplex, double phaser, double phasei)
+  {
+    if (!iscomplex)
+      {
+	v.X() = values[0];
+	v.Y() = values[1];
+	v.Z() = values[2];
+      }
+    else
+      {
+	for (int i = 0; i < 3; i++)
+	  v.X(i+1) = phaser * values[2*i] + phasei * values[2*i+1];
+      }
+  }
+
+
+  
+
+  void VisualSceneSolution :: BuildScene (int zoomall)
+  {
+    int i, j, k;
+ 
+    if (!mesh)
+      {
+	VisualScene::BuildScene (zoomall);
+	return;
+      }
+    
+    if (!cone_list)
+      {
+	cone_list = glGenLists (1);
+	glNewList (cone_list, GL_COMPILE);
+	DrawCone (Point<3> (0,0,0), Point<3> (0,0,1), 0.4);
+	glEndList();
+      }
+
+
+
+    
+    vispar.colormeshsize = 1;
+    
+    // recalc clipping plane
+    SetClippingPlane ();
+    glDisable(GL_CLIP_PLANE0);
+    
+    
+    const SolData * sol = NULL;
+    const SolData * vsol = NULL;
+  
+    if (scalfunction != -1) 
+      sol = soldata[scalfunction];
+    if (vecfunction != -1)
+      vsol = soldata[vecfunction];
+    
+  if (mesh->GetTimeStamp () > solutiontimestamp)
+    {
+      sol = NULL;
+      vsol = NULL;
+    }
+
+  if (!autoscale || scalfunction == -1)
+    {
+      minval = mminval;
+      maxval = mmaxval;
+    }
+  else
+    {
+      if (mesh->GetTimeStamp () > surfeltimestamp ||
+	  vispar.clipplanetimestamp > clipplanetimestamp ||
+	  solutiontimestamp > surfeltimestamp)
+	{
+	  GetMinMax (scalfunction, scalcomp, minval, maxval);
+	}
+    }
+ 
+
+  if (mesh->GetTimeStamp() > surfeltimestamp ||
+      solutiontimestamp > surfeltimestamp ||
+      zoomall)
+    {
+      if (mesh->GetTimeStamp() > surfeltimestamp ||
+	  zoomall)
+	{
+	  // mesh has changed
+	  
+	  Point3d pmin, pmax;
+	  static double oldrad = 0;
+	  
+	  mesh->GetBox (pmin, pmax, -1);
+	  center = Center (pmin, pmax);
+	  rad = 0.5 * Dist (pmin, pmax);
+	  
+	  glEnable (GL_NORMALIZE);
+	  
+	  if (rad > 1.5 * oldrad ||
+	      mesh->GetMajorTimeStamp() > surfeltimestamp ||
+	      zoomall)
+	    {
+	      CalcTransformationMatrices();
+	      oldrad = rad;
+	    }
+	}
+
+      
+      if (surfellist)
+	glDeleteLists (surfellist, 1);
+      
+      surfellist = glGenLists (1);
+      glNewList (surfellist, GL_COMPILE);
+      
+      DrawSurfaceElements();
+      
+      glEndList ();
+      
+      
+      if (linelist)
+	glDeleteLists (linelist, 1);
+      
+      linelist = glGenLists (1);
+      glNewList (linelist, GL_COMPILE);
+      
+      DrawSurfaceElementLines();
+      
+      glEndList ();
+
+      surfeltimestamp = max2 (solutiontimestamp, mesh->GetTimeStamp());
+
+      //      cout << "minval = " << minval << " maxval = " << maxval << endl;
+    }
+  
+
+
+  
+  if (mesh->GetTimeStamp() > surface_vector_timestamp ||
+      solutiontimestamp > surface_vector_timestamp ||
+      zoomall)
+    {
+      if (surface_vector_list)
+	glDeleteLists (surface_vector_list, 1);
+      
+      surface_vector_list = glGenLists (1);
+      glNewList (surface_vector_list, GL_COMPILE);
+
+      glEnable (GL_NORMALIZE);
+      DrawSurfaceVectors();
+
+      glEndList ();
+
+      surface_vector_timestamp = 
+	max2 (mesh->GetTimeStamp(), solutiontimestamp);
+    }
+
+
+  if (clipplanetimestamp < vispar.clipplanetimestamp ||
+      clipplanetimestamp < solutiontimestamp)
+    {
+
+      //      cout << "clipsolution = " << clipsolution << endl;
+      if (vispar.clipenable && clipsolution)      
+	{
+	  // lock->UnLock();
+	  mesh->BuildElementSearchTree();
+	  // lock->Lock();
+	}
+
+      if (clipplanelist)
+	glDeleteLists (clipplanelist, 1);
+      
+
+      clipplanelist = glGenLists (1);
+      glNewList (clipplanelist, GL_COMPILE);
+      
+      if (vispar.clipenable && clipsolution == 1 && sol)
+	{
+	  glDisable(GL_CLIP_PLANE0);
+	  
+	  ARRAY<ClipPlaneTrig> cpt;
+	  GetClippingPlaneTrigs (cpt);
+	  
+	  glNormal3d (-clipplane[0], -clipplane[1], -clipplane[2]);
+	  
+	  glBegin (GL_TRIANGLES);
+	  for (i = 0; i < cpt.Size(); i++)
+	    DrawClipPlaneTrig (sol, scalcomp, cpt[i], 2*subdivisions);
+	  glEnd();
+
+	  glEnable(GL_CLIP_PLANE0);
+	}
+      
+      
+      if (vispar.clipenable && clipsolution == 2 && vsol)
+	{
+	  if (autoscale)
+	    GetMinMax (vecfunction, 0, minval, maxval);
+
+
+	  ARRAY<ClipPlanePoint> cpp;
+	  GetClippingPlaneGrid (cpp);
+
+	  for (i = 0; i < cpp.Size(); i++)
+	    {
+	      const ClipPlanePoint & p = cpp[i];
+	      double values[6];
+	      Vec3d v;
+
+	      GetValues (vsol, p.elnr, p.lam1, p.lam2, p.lam3, values);
+	      RealVec3d (values, v, vsol->iscomplex, imag_part);
+
+	      double val = v.Length();
+
+	      if (val > 1e-10 * maxval)
+		{
+		  v *= (rad / val / gridsize * 0.5);
+		  
+		  SetOpenGlColor  (val, minval, maxval, logscale);
+		  DrawCone (p.p, p.p+v, rad / gridsize * 0.2);
+		}
+	    }
+	}
+
+      glEndList ();
+    }
+
+  
+  
+
+  if (
+      numisolines && 
+      (clipplanetimestamp < vispar.clipplanetimestamp ||
+       clipplanetimestamp < solutiontimestamp) 
+      )
+    {
+      if (isolinelist) glDeleteLists (isolinelist, 1);
+      
+      isolinelist = glGenLists (1);
+      glNewList (isolinelist, GL_COMPILE);
+
+      Point<3> points[1100];
+      double values[1100];
+      
+      SurfaceElementIndex sei;
+      glBegin (GL_LINES);
+      int nse = mesh->GetNSE();
+      if (sol)
+	for (sei = 0; sei <= nse; sei++)
+	  {
+	    const Element2d & el = (*mesh)[sei];
+	    
+	    if (el.GetType() == TRIG || el.GetType() == TRIG6)
+	      {
+		Point<3> lp1, lp2, lp3;
+		if (!mesh->GetCurvedElements().IsHighOrder())
+		  {
+		    GetPointDeformation (el[0]-1, lp1);
+		    GetPointDeformation (el[1]-1, lp2);
+		    GetPointDeformation (el[2]-1, lp3);
+		  }
+
+
+		
+		int n = 1 << subdivisions;
+		int ii = 0;
+		int ix, iy;
+		for (iy = 0; iy <= n; iy++)
+		  for (ix = 0; ix <= n-iy; ix++)
+		    {
+		      double x = double(ix) / n;
+		      double y = double(iy) / n;
+		  
+		      values[ii] = GetSurfValue (sol, sei, x, y, scalcomp);
+		      Point<2> xref(x,y);
+		      
+		      if (mesh->GetCurvedElements().IsHighOrder())
+			mesh->GetCurvedElements().
+			  CalcSurfaceTransformation (xref, sei, points[ii]);
+		      else
+			points[ii] = lp3 + x * (lp1-lp3) + y * (lp2-lp3);
+		  
+		      if (deform)
+			{
+			  Vec<3> def;
+			  GetSurfDeformation (sei, x, y, def);
+			  points[ii] += def;
+			}
+		      ii++;
+		    }
+
+		ii = 0;
+		for (iy = 0; iy < n; iy++)
+		  {
+		    for (ix = 0; ix < n-iy; ix++)
+		      {
+			double x = double(ix) / n;
+			double y = double(iy) / n;
+			
+			int index[] = { ii, ii+1, ii+n-iy+1,
+					ii+1, ii+n-iy+2, ii+n-iy+1 };
+			
+			int np = (ix == n-iy-1) ? 3 : 6;
+
+			DrawIsoLines (points[index[0]], points[index[1]], points[index[2]],
+				      values[index[0]], values[index[1]], values[index[2]],
+				      minval, maxval, numisolines);
+			if (np == 6)
+			  DrawIsoLines (points[index[3]], points[index[4]], points[index[5]],
+					values[index[3]], values[index[4]], values[index[5]],
+					minval, maxval, numisolines);
+			ii++;
+		      }	
+		    ii++;
+		  }    
+		/*
+		double val1, val2, val3;
+		val1 = GetSurfValue (sol, sei, 1, 0, scalcomp);
+		val2 = GetSurfValue (sol, sei, 0, 1, scalcomp);
+		val3 = GetSurfValue (sol, sei, 0, 0, scalcomp);
+		*/
+	      }
+	  }
+      
+      if (vispar.clipenable && clipsolution == 1 && sol)
+	{
+	  glDisable(GL_CLIP_PLANE0);
+	  
+	  ARRAY<ClipPlaneTrig> cpt;
+	  GetClippingPlaneTrigs (cpt);
+	  
+	  glNormal3d (-clipplane[0], -clipplane[1], -clipplane[2]);
+	  
+	  if (numisolines)
+	  for (i = 0; i < cpt.Size(); i++)
+	    {
+	      const ClipPlaneTrig & trig = cpt[i];
+	      double vali[3];
+	      for (j = 0; j < 3; j++)
+		vali[j] = GetValue (sol, trig.elnr, 
+				    trig.points[j].lami(0),
+				    trig.points[j].lami(1),
+				    trig.points[j].lami(2), scalcomp);
+	      
+	      DrawIsoLines (trig.points[0].p,
+			    trig.points[1].p,
+			    trig.points[2].p,
+			    vali[0], vali[1], vali[2], minval, maxval, numisolines);
+	    }
+	  glEnable(GL_CLIP_PLANE0);
+	}
+      glEnd();
+      
+      glEndList ();
+    }
+  
+  clipplanetimestamp = max2 (vispar.clipplanetimestamp, solutiontimestamp);
+  }
+  
+
+  void VisualSceneSolution :: BuildFieldLinesPlot ()
+  {
+    if (fieldlinestimestamp >= solutiontimestamp) 
+      return;
+    fieldlinestimestamp = solutiontimestamp;
+    
+
+    if (fieldlineslist)
+      glDeleteLists (fieldlineslist, num_fieldlineslists);
+
+    if (vecfunction == -1)
+      return;
+
+
+    const SolData * vsol = soldata[vecfunction];
+
+    num_fieldlineslists = (vsol -> iscomplex) ? 100 : 1;
+
+    Point3d pmin, pmax;
+    mesh->GetBox (pmin, pmax);
+    double lami[3];
+    int i;
+
+
+    fieldlineslist = glGenLists (num_fieldlineslists);
+
+    for (int ln = 0; ln < num_fieldlineslists; ln++)
+      {
+	glNewList (fieldlineslist + ln, GL_COMPILE);      
+
+	double phi = 2*M_PI*ln / num_fieldlineslists;
+	double phaser = cos(phi);
+	double phasei = sin(phi);
+
+	for (i = 1; i <= num_fieldlines / num_fieldlineslists+1; i++)
+	  {
+	    Point3d p (pmin.X() + double (rand()) / RAND_MAX * (pmax.X()-pmin.X()),
+		       pmin.Y() + double (rand()) / RAND_MAX * (pmax.Y()-pmin.Y()),
+		       pmin.Z() + double (rand()) / RAND_MAX * (pmax.Z()-pmin.Z()));
+	    
+	    ElementIndex elnr = mesh->GetElementOfPoint (p, lami)-1;
+	    (*testout) << "p = " << p << "; elnr = " << elnr << endl;
+	    if (elnr != -1)
+	      {
+		Vec3d v;
+		double values[6];
+		GetValues (vsol, elnr, lami[0], lami[1], lami[2], values);
+		RealVec3d (values, v, vsol->iscomplex, phaser, phasei);
+		
+		double val = v.Length();
+		
+		if (!fieldlines_randomstart ||
+		    (double (rand()) / RAND_MAX) < (val / maxval))
+		  {
+		    int i;
+		    Point3d p0 = p; 
+		    v *= (rad / val * 0.02);
+		    SetOpenGlColor  (val, minval, maxval, logscale);
+		    
+		    Point3d p2 = p + v; 
+		    cout << " p " << p << endl; 
+		    DrawCylinder (p, p2, rad * 0.003);
+		    p = p2;  		
+		    
+		    for(i=0;i<20;i++) 
+		      {
+			ElementIndex elnr = mesh->GetElementOfPoint (p, lami)-1;
+			
+			if (elnr != -1)
+			  {
+			    GetValues (vsol, elnr, lami[0], lami[1], lami[2], values);
+			    RealVec3d (values, v, vsol->iscomplex, phaser, phasei);
+			    val = v.Length();
+			    v *= (rad / val * 0.02);
+			    
+			    SetOpenGlColor  (val, minval, maxval, logscale);
+			    p2 = p +v; 
+			    DrawCylinder (p, p2, rad * 0.003);
+			    p = p2;  	
+			  }
+			else break; 
+		      } 
+		    p=p0; 
+		    for(i=0;i<20;i++) 
+		      {
+			ElementIndex elnr = mesh->GetElementOfPoint (p, lami)-1;
+
+			if (elnr != -1)
+			  {
+			    GetValues (vsol, elnr, lami[0], lami[1], lami[2], values);
+			    RealVec3d (values, v, vsol->iscomplex, phaser, phasei);
+			    
+			    val = v.Length();
+			    v *= (rad / val * 0.02);
+			    
+			    SetOpenGlColor  (val, minval, maxval, logscale);
+			    p2 = p - v; 
+			    DrawCylinder (p, p2, rad * 0.003);
+			    p = p2;  	
+			  }
+			else break; 
+		      } 
+		  }		  
+	      }
+	  }
+	glEndList ();
+      }
+  }
+  
+
+
+  void  VisualSceneSolution :: DrawSurfaceElements ()
+  {
+    int j, k;
+    SurfaceElementIndex sei;
+
+    const SolData * sol = NULL;
+    const SolData * vsol = NULL;
+    
+    if (scalfunction != -1)
+      sol = soldata[scalfunction];
+    if (vecfunction != -1)
+      vsol = soldata[vecfunction];
+    
+    if (mesh->GetTimeStamp () > solutiontimestamp)
+      {
+	sol = NULL;
+	vsol = NULL;
+      }
+    
+    glLineWidth (1.0f);
+
+    if (!sol || !sol->draw_surface)
+      glDisable (GL_TEXTURE_1D);
+
+    
+    Point<3> points[1100];
+    Vec<3> nvs[1100];
+    double values[1100];
+
+    glBegin (GL_TRIANGLES);
+    int nse = mesh->GetNSE();
+
+    glColor3f (0.4, 0.4, 0.4);
+
+    for (sei = 0; sei < nse; sei++)
+      {
+	Element2d & el = (*mesh)[sei];
+
+	if (el.GetType() == TRIG || el.GetType() == TRIG6)
+	  {
+	    Point<3> p1, p2, p3;
+	    if (!mesh->GetCurvedElements().IsHighOrder())
+	      {
+		GetPointDeformation (el[0]-1, p1, sei);
+		GetPointDeformation (el[1]-1, p2, sei);
+		GetPointDeformation (el[2]-1, p3, sei);
+	      }
+	    
+	    int n = 1 << subdivisions;
+	    int ii = 0;
+	    int ix, iy;
+	    for (iy = 0; iy <= n; iy++)
+	      for (ix = 0; ix <= n-iy; ix++)
+		{
+		  double x = double(ix) / n;
+		  double y = double(iy) / n;
+		  
+		  if (sol && sol->draw_surface) 
+		    values[ii] = GetSurfValue (sol, sei, x, y, scalcomp);
+
+		  Point<2> xref(x,y);
+		  Mat<3,2> dxdxi;
+
+		  if (mesh->GetCurvedElements().IsHighOrder())
+		    {
+		      mesh->GetCurvedElements().
+			CalcSurfaceTransformation (xref, sei, points[ii], dxdxi);
+		      nvs[ii] = Cross (dxdxi.Col(0), dxdxi.Col(1));
+		      nvs[ii].Normalize();
+		    }
+		  else
+		    {
+		      points[ii] = p3 + x * (p1-p3) + y * (p2-p3);
+		      nvs[ii] = Cross (p2-p1, p3-p1);
+		      nvs[ii].Normalize();
+		    }
+		  
+		  if (deform)
+		    {
+		      Vec<3> def;
+		      GetSurfDeformation (sei, x, y, def);
+		      points[ii] += def;
+		    }
+		  ii++;
+		}
+
+	    ii = 0;
+	    
+	    for (iy = 0; iy < n; iy++)
+	      {
+		for (ix = 0; ix < n-iy; ix++)
+		  {
+		    double x = double(ix) / n;
+		    double y = double(iy) / n;
+		    
+		    int index[] = { ii, ii+1, ii+n-iy+1,
+				    ii+1, ii+n-iy+2, ii+n-iy+1 };
+		    
+		    int np = (ix == n-iy-1) ? 3 : 6;
+		    for (int j = 0; j < np; j++)
+		      {
+			if (sol && sol->draw_surface)
+			  SetOpenGlColor  (values[index[j]], minval, maxval, logscale);
+			glNormal3dv (&nvs[index[j]](0));
+			glVertex3dv (points[index[j]]);
+		      }
+		    ii++;
+		  }	
+		ii++;
+	      }    
+	  }
+      }
+    glEnd ();
+    
+    
+  
+    
+  
+    
+    glBegin (GL_QUADS);
+    for (sei = 0; sei < nse; sei++)
+    {
+      const Element2d & el = (*mesh)[sei];
+      
+      if (el.GetType() == QUAD || el.GetType() == QUAD6)
+	{
+	  Point<3> lpi[4];
+	  for (k = 0; k < 4; k++)
+	    GetPointDeformation (el[k]-1, lpi[k]);
+	  Vec<3> vx = lpi[1]-lpi[0];
+	  Vec<3> vy = lpi[3]-lpi[0];
+	  Vec<3> vtwist = (lpi[0]-lpi[1]) + (lpi[2]-lpi[3]);
+	  Vec<3> nv = Cross (lpi[1]-lpi[0], Center (lpi[2],lpi[3]) - lpi[0]);
+	  nv.Normalize();
+	  glNormal3dv (nv);
+	  
+
+	  int n = 1 << subdivisions;
+	  int ii = 0;
+	  int ix, iy;
+	  for (iy = 0; iy <= n; iy++)
+	    for (ix = 0; ix <= n; ix++)
+	      {
+		double x = double(ix) / n;
+		double y = double(iy) / n;
+		
+		Point<2> xref(x,y);
+		Mat<3,2> dxdxi;
+
+		if (sol && sol->draw_surface) 
+		  values[ii] = GetSurfValue (sol, sei, x, y, scalcomp);
+
+
+		if (mesh->GetCurvedElements().IsHighOrder())
+		  {
+		    mesh->GetCurvedElements().
+		      CalcSurfaceTransformation (xref, sei, points[ii], dxdxi);
+		    nvs[ii] = Cross (dxdxi.Col(0), dxdxi.Col(1));
+		    nvs[ii].Normalize();
+		  }
+		else
+		  {
+		    points[ii] = lpi[0] + x * vx + y * vy + x*y * vtwist;
+		    nvs[ii] = Cross (vx, vy);
+		    nvs[ii].Normalize();
+		  }
+		  
+		if (deform)
+		  {
+		    Vec<3> def;
+		    GetSurfDeformation (sei, x, y, def);
+		    points[ii] += def;
+		  }
+
+		// points[ii] = lpi[0] + x * vx + y * vy;
+		ii++;
+	      }
+	  
+	  ii = 0;
+	  for (iy = 0; iy < n; iy++)
+	    {
+	      for (ix = 0; ix < n; ix++)
+		{
+		  double x = double(ix) / n;
+		  double y = double(iy) / n;
+		    
+		  int index[] = { ii, ii+1, ii+n+2, ii+n+1 };
+
+		  for (int j = 0; j < 4; j++)
+		    {
+		      if (sol && sol->draw_surface)
+			SetOpenGlColor  (values[index[j]], minval, maxval, logscale);
+		      glNormal3dv (&nvs[index[j]](0));
+		      glVertex3dv (points[index[j]]);
+		    }
+		  ii++;
+		}	
+	      ii++;
+	    }    
+	}
+    }
+  glEnd();
+
+  if (usetexture)
+    glEnable (GL_TEXTURE_1D);
+
+  }
+
+
+  // Bernstein Pol B_{n,i}(x) = n! / i! / (n-i)! (1-x)^{n-i} x^i
+  static  double Bernstein (int n, int i, double x)
+  {
+    int j;
+    double val = 1;
+    for (j = 1; j <= i; j++)
+      val *= x / j;
+    for (j = 1; j <= n-i; j++)
+      val *= (1-x) / j;
+    for (j = 1; j <= n; j++)
+      val *= j;
+    return val;
+  }
+
+  void  VisualSceneSolution :: DrawSurfaceElementLines ()
+  {
+    int i, j, k, l;
+    SurfaceElementIndex sei;
+
+    /*
+    int p = 4;
+    DenseMatrix mat(p+1,p+1), invmat(p+1,p+1);
+    for (i = 0; i <= p; i++)
+      for (j = 0; j <= p; j++)
+	mat.Elem(i+1,j+1) = Bernstein(p, i, double(j)/p);
+    CalcIo
+nverse (mat, invmat);
+    */
+
+    glLineWidth (1.0f);
+    glNormal3d (1, 0, 0);
+
+    int nse = mesh->GetNSE();
+
+    for (sei = 0; sei < nse; sei++)
+      {
+	Element2d & el = (*mesh)[sei];
+
+	int nv;
+	if (el.GetType() == TRIG || el.GetType() == TRIG6)
+	  nv = 3;
+	else 
+	  nv = 4;
+	
+	Point<3> p1, p2, p3, p4;
+	GetPointDeformation (el[0]-1, p1, sei);
+	GetPointDeformation (el[1]-1, p2, sei);
+	GetPointDeformation (el[2]-1, p3, sei);
+	if (nv == 4)
+	  GetPointDeformation (el[3]-1, p4, sei);
+
+
+	// glBegin (GL_LINE_LOOP);
+	int n = 1 << subdivisions;
+	// n = p;
+
+	int ii = 0;
+	int ix, iy;
+	Point<3> pnt;
+	
+	for (k = 0; k < nv; k++)
+	  {
+	    Point<2> p0;
+	    Vec<2> vtau;
+	    if (nv == 3)
+	      switch (k)
+		{
+		case 0:
+		  p0 = Point<2> (0,0);
+		  vtau = Vec<2> (1,0);
+		  break;
+		case 1:
+		  p0 = Point<2> (1,0);
+		  vtau = Vec<2> (-1,1);
+		  break;
+		case 2:
+		  p0 = Point<2> (0,1);
+		  vtau = Vec<2> (0,-1);
+		  break;
+		}
+	    else
+	      switch (k)
+		{
+		case 0:
+		  p0 = Point<2> (0,0);
+		  vtau = Vec<2> (1,0);
+		  break;
+		case 1:
+		  p0 = Point<2> (1,0);
+		  vtau = Vec<2> (0,1);
+		  break;
+		case 2:
+		  p0 = Point<2> (1,1);
+		  vtau = Vec<2> (-1,0);
+		  break;
+		case 3:
+		  p0 = Point<2> (0,1);
+		  vtau = Vec<2> (0,-1);
+		  break;
+		}
+
+	    
+	    glBegin (GL_LINE_STRIP);
+	    Point<3> pts[33], pts2[33];
+	    if (n > 32) cerr << "too many subdivisions, code 433425" << endl;
+
+	    for (ix = 0; ix <= n; ix++)
+	      {
+		Point<2> p = p0 + (double(ix) / n) * vtau;
+		double x = p(0);
+		double y = p(1);
+		Point<2> xref(x,y);
+
+		if (mesh->GetCurvedElements().IsHighOrder())
+		  mesh->GetCurvedElements().
+		    CalcSurfaceTransformation (xref, sei, pnt);
+		else
+		  {
+		    if (nv == 3)
+		      pnt = p3 + x * (p1-p3) + y * (p2-p3);
+		    else
+		      pnt = p1 + x * (p2-p1) + y * (p4-p1) + x*y * ( (p1-p2)+(p3-p4) );
+		  }
+		
+		if (deform)
+		  {
+		    Vec<3> def;
+		    GetSurfDeformation (sei, x, y, def);
+		    pnt += def;
+		  }
+		
+		glVertex3dv (pnt);
+
+		pts[ix] = pnt;
+	      }
+	    glEnd ();
+
+
+
+	    /*
+	    // convert from point-values to Bernstein basis
+	    for (i = 0; i < 3; i++)
+	      for (j = 0; j <= p; j++)
+		{
+		  pts2[j](i) = 0;
+		  for (l = 0; l <= p; l++)
+		    pts2[j](i) += invmat(l,j) * pts[l](i);
+		}
+
+
+	    glMap1d(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, n+1, &pts2[0](0));
+	    glEnable(GL_MAP1_VERTEX_3);
+
+	    int steps = 1 << subdivisions;
+
+// 	    glBegin (GL_LINE_STRIP);
+// 	    for (int hi = 0; hi <= 10; hi++)
+// 	      glEvalCoord1d (double(hi)/10.0);
+// 	    glEnd ();
+
+	    glMapGrid1d (steps, 0.0, 1.0);
+	    glEvalMesh1(GL_LINE, 0, steps);
+	    glDisable(GL_MAP1_VERTEX_3);
+	    */
+	  }
+	
+      }
+    
+  }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+void  VisualSceneSolution :: DrawSurfaceVectors ()
+{
+  int j, k;
+  int dir, dir1, dir2;
+  SurfaceElementIndex sei;
+
+  const SolData * vsol = NULL;
+
+  if (vecfunction != -1)
+    vsol = soldata[vecfunction];
+
+  if (mesh->GetTimeStamp () > solutiontimestamp)
+    {
+      vsol = NULL;
+    }
+
+  if (!vsol) return;
+
+
+  Point<3> pmin = center - Vec3d (rad, rad, rad);
+  Point<3> pmax = center - Vec3d (rad, rad, rad);
+
+  double s, t;
+
+  // draw surface cones
+  //  if (0)
+  /*
+  if (vsol->soltype==SOL_SURFACE_ELEMENT ||
+      vsol->soltype==SOL_SURFACE_NONCONTINUOUS ||
+      vsol->soltype==SOL_VIRTUALFUNCTION)
+  */
+  if (vsol->draw_surface && showsurfacesolution)
+    {
+      int nse = mesh->GetNSE();
+      for (sei = 0; sei < nse; sei++)
+	{
+	  const Element2d & el = (*mesh)[sei];
+	  
+	  if (el.GetType() != TRIG && el.GetType() != TRIG6) continue;
+	  
+	  Point<3> lp[3];
+	  Point<2> p2d[3];
+	  /*
+	  for (k = 0; k < 3; k++)
+	    lp[k] = mesh->Point (el[k]);
+	  */
+	  lp[0] = mesh->Point(el[2]);
+	  lp[1] = mesh->Point(el[0]);
+	  lp[2] = mesh->Point(el[1]);
+
+
+	  Vec<3> n = Cross (lp[1]-lp[0], lp[2]-lp[0]);
+	  Vec<3> na (fabs (n(0)), fabs(n(1)), fabs(n(2)));
+	  if (na(0) > na(1) && na(0) > na(2))
+	    dir = 1;
+	  else if (na(1) > na(2))
+	    dir = 2;
+	  else 
+	    dir = 3;
+
+	  dir1 = (dir % 3) + 1;
+	  dir2 = (dir1 % 3) + 1;
+	  
+	  for (k = 0; k < 3; k++)
+	    {
+	      p2d[k] = Point<2> ((lp[k](dir1-1) - pmin(dir1-1)) / (2*rad),
+				 (lp[k](dir2-1) - pmin(dir2-1)) / (2*rad));
+	    }
+	  
+	  double minx2d, maxx2d, miny2d, maxy2d;
+	  minx2d = maxx2d = p2d[0](0);
+	  miny2d = maxy2d = p2d[0](1);
+	  for (k = 1; k < 3; k++)
+	    {
+	      minx2d = min2 (minx2d, p2d[k](0));
+	      maxx2d = max2 (maxx2d, p2d[k](0));
+	      miny2d = min2 (miny2d, p2d[k](1));
+	      maxy2d = max2 (maxy2d, p2d[k](1));
+	    }
+
+	  double mat11 = p2d[1](0) - p2d[0](0);
+	  double mat21 = p2d[1](1) - p2d[0](1);
+	  double mat12 = p2d[2](0) - p2d[0](0);
+	  double mat22 = p2d[2](1) - p2d[0](1);
+
+	  double det = mat11*mat22-mat21*mat12;
+	  double inv11 = mat22/det;
+	  double inv21 = -mat21/det;
+	  double inv12 = -mat12/det;
+	  double inv22 = mat11/det;
+	  
+      
+	  
+	  for (s = 0; s <= 1; s += 1.0 / gridsize)
+	    if (s >= minx2d && s <= maxx2d)
+	      for (t = 0; t <= 1; t += 1.0 / gridsize)
+		if (t >= miny2d && t <= maxy2d)
+		  {
+		    double lam1 = inv11 * (s - p2d[0](0)) + inv12 * (t-p2d[0](1));
+		    double lam2 = inv21 * (s - p2d[0](0)) + inv22 * (t-p2d[0](1));
+		    
+		    if (lam1 >= 0 && lam2 >= 0 && lam1+lam2 <= 1)
+		      {
+			Point<3> cp;
+			for (k = 0; k < 3; k++)
+			  cp(k) = lp[0](k) + 
+			    lam1 * (lp[1](k)-lp[0](k)) + 
+			    lam2 * (lp[2](k)-lp[0](k));
+
+			Vec<3> v;
+			double values[6];
+			GetSurfValues (vsol, sei, lam1, lam2, values);
+
+			if (!vsol->iscomplex)
+			  for (k = 0; k < 3; k++)
+			    v(k) = values[k];
+			else
+			  {
+			    if (!imag_part)
+			      for (k = 0; k < 3; k++)
+				v(k) = values[2*k];
+			    else
+			      for (k = 0; k < 3; k++)
+				v(k) = values[2*k+1];
+			  }
+			
+			if (mesh->GetDimension() == 2)
+			  v(2) = 0;
+			
+			double val = v.Length();
+			SetOpenGlColor  (val, minval, maxval, logscale);
+
+			if (val > 1e-10 * maxval)
+			  v *= (rad / val / gridsize * 0.5);
+			DrawCone (cp, cp+4*v, 0.8*rad / gridsize);
+
+			/*
+			v /= val;
+			
+			glPushMatrix();
+			glTranslated (cp(0), cp(1), cp(2));
+
+			double l = 2*rad/gridsize;
+			double r = 0.8*rad/gridsize;
+			glScaled (l, l, l);
+			
+			double phi = acos (v(2));
+			glRotated (-180/M_PI*phi, v(1), -v(0), 0);
+
+			glCallList (cone_list);
+			glPopMatrix();
+			*/
+		      }
+		  }
+	}
+    }
+}
+
+
+
+
+void VisualSceneSolution :: 
+DrawIsoLines (const Point3d & p1, 
+	      const Point3d & p2, 
+	      const Point3d & p3,
+	      double val1, double val2, double val3,
+	      double minval, double maxval, int n)
+{
+  DrawIsoLines2 (p1, p2, p1, p3, val1, val2, val1, val3, minval, maxval, n);
+  DrawIsoLines2 (p2, p1, p2, p3, val2, val1, val2, val3, minval, maxval, n);
+  DrawIsoLines2 (p3, p1, p3, p2, val3, val1, val3, val2, minval, maxval, n);
+}
+
+void VisualSceneSolution :: 
+DrawIsoLines2 (const Point3d & p1, 
+	       const Point3d & p2, 
+	       const Point3d & p3,
+	       const Point3d & p4,
+	       double val1, double val2, double val3, double val4,
+	       double minval, double maxval, int n)
+{
+  if (val1 > val2) 
+    DrawIsoLines2 (p2, p1, p3, p4, val2, val1, val3, val4, minval, maxval, n);
+  if (val3 > val4) 
+    DrawIsoLines2 (p1, p2, p4, p3, val1, val2, val4, val3, minval, maxval, n);
+
+  val2 += 1e-10;
+  val4 += 1e-10;
+
+  double fac = (maxval-minval) / n;
+  double idelta1 = 1.0 / (val2 - val1);
+  double idelta2 = 1.0 / (val4 - val3);
+
+  int mini = int ((max2 (val1, val3) - minval) / fac);
+  int maxi = int ((min2 (val2, val4) - minval) / fac);
+  if (mini < 0) mini = 0;
+  if (maxi > n-1) maxi = n-1;
+
+  for (int i = mini; i <= maxi+1; i++)
+    {
+      double val = minval + i * fac;
+      double lam1 = (val - val1) * idelta1;
+      double lam2 = (val - val3) * idelta2;
+      if (lam1 >= 0 && lam1 <= 1 && lam2 >= 0 && lam2 <= 1)
+	{
+	  Point3d lp1 = p1 + lam1 * Vec3d (p1, p2);
+	  Point3d lp2 = p3 + lam2 * Vec3d (p3, p4);
+	  glVertex3d (lp1.X(), lp1.Y(), lp1.Z());
+	  glVertex3d (lp2.X(), lp2.Y(), lp2.Z());
+	  glVertex3d (lp2.X(), lp2.Y(), lp2.Z());
+	  glVertex3d (lp1.X(), lp1.Y(), lp1.Z());
+	}
+    }
+}
+
+
+
+
+
+
+
+void VisualSceneSolution :: 
+GetMinMax (int funcnr, int comp, double & minv, double & maxv) const
+{
+  int i, j;
+  const SolData * sol;
+  double val;
+
+  bool hasit = 0;
+  minv = 0; maxv = 1;
+  if (funcnr != -1)
+    {
+      sol = soldata[funcnr];
+      if (sol->draw_volume)
+	{
+	  int ne = mesh->GetNE();
+	  for (int i = 0; i < ne; i++)
+	    {
+	      double val = GetValue (sol, i, 0.333, 0.333, 0.333, comp);
+	      if (val > maxv || !hasit)
+		maxv = val;
+	      if (val < minv || !hasit)
+		minv = val;
+	      hasit = 1;
+	    }
+	}
+      if (sol->draw_surface)
+	{
+	  int nse = mesh->GetNSE();
+	  for (int i = 0; i < nse; i++)
+	    {
+	      double val = GetSurfValue (sol, i, 0.333, 0.333, comp);
+	      if (val > maxv || !hasit)
+		maxv = val;
+	      if (val < minv || !hasit)
+		minv = val;
+	      hasit = 1;
+	    }
+	}
+    }
+}
+
+
+
+
+
+void VisualSceneSolution :: 
+GetValues (const SolData * data, ElementIndex elnr, 
+	   double lam1, double lam2, double lam3,
+	   double * values) const
+{
+  switch (data->soltype)
+    {
+    case SOL_VIRTUALFUNCTION:
+      {
+	bool ok =
+	  data->solclass->GetValue (elnr, lam1, lam2, lam3, values);
+	break;
+      }
+    default:
+      {
+	for (int i = 0; i < data->components; i++)
+	  values[i] = GetValue (data, elnr, lam1, lam2, lam3, i+1);
+      }
+    }
+}
+
+
+double VisualSceneSolution :: 
+GetValue (const SolData * data, ElementIndex elnr, 
+	  double lam1, double lam2, double lam3,
+	  int comp) const
+{
+  if (comp == 0)
+    {
+      double val = 0;
+      ArrayMem<double,20> values(data->components);
+      GetValues (data, elnr, lam1, lam2, lam3, &values[0]);
+
+      switch (evalfunc)
+	{
+	case FUNC_ABS:
+	  {
+	    for (int ci = 0; ci < data->components; ci++)
+	      val += sqr (values[ci]);
+	    val = sqrt (val);
+	    break;
+	  }
+	case FUNC_ABS_TENSOR:
+	  {
+	    int d;
+	    switch (data->components)
+	      {
+	      case 1: d = 1; break;
+	      case 3: d = 2; break;
+	      case 6: d = 3; break;
+	      }
+	    int ci;
+	    for (ci = 0; ci < d; ci++)
+	      val += sqr (values[ci]);
+	    for (ci = d; ci < data->components; ci++)
+	      val += 2*sqr (values[ci]);
+	    val = sqrt (val);
+	    break;
+	  }
+
+	case FUNC_MISES:
+	{
+	    int d;
+	    switch(data->components)
+	      {
+	      case 1: d = 1; break;
+	      case 3: d = 2; break;
+	      case 6: d = 3; break;
+	      }
+	    int ci;
+	    double trace = 0.;
+	    for (ci = 0; ci < d; ci++)
+	      trace += 1./3.*(values[ci]);
+	    for (ci = 0; ci < d; ci++)
+	      val += sqr (values[ci]-trace);
+	    for (ci = d; ci < data->components; ci++)
+	      val += 2.*sqr (values[ci]);
+	    val = sqrt (val);
+	    break;
+	}
+	case FUNC_MAIN:
+	 {
+	    int d;
+	    switch(data->components)
+	      {
+	      case 1: d = 1; break;
+	      case 3: d = 2; break;
+	      case 6: d = 3; break;
+	      }
+	    Mat<3,3> m ;
+	    Vec<3> ev;
+	    int ci;
+            for (ci = 0; ci < d; ci++)
+	      m(ci,ci) = (values[ci]);
+	    m(0,1) = m(1,0) = values[3];
+	    m(0,2) = m(2,0) = values[4];
+	    m(1,2) = m(2,1) = values[5];
+
+	    EigenValues (m, ev);
+	    double help;
+            for (int i=0; i<d; i++)
+            {
+               for (int j=d-1; i<j; j--)
+               {
+                   if ( abs(ev(j)) > abs(ev(j-1)) )
+	           {
+	              help = ev(j);
+                      ev(j) = ev(j-1);
+	              ev(j-1) = help;
+	           }
+       		}
+  	    }
+            val = (ev(0));
+	    break;
+         }
+      }
+
+      return val;	
+    }
+
+
+  switch (data->soltype)
+    {
+    case SOL_VIRTUALFUNCTION:
+      {
+	double values[20];
+	bool ok = data->solclass->GetValue (elnr, lam1, lam2, lam3, values);
+
+	if (ok) 
+	  return values[comp-1];
+	else
+	  return 0;
+      }
+    case SOL_NODAL:
+      {
+	const Element & el = (*mesh)[elnr];
+
+	double lami[8];
+	int np, i;
+	double val = 0;
+	
+	switch (el.GetType())
+	  {
+	  case TET:
+	  case TET10:
+	    {
+	      lami[1] = lam1;
+	      lami[2] = lam2;
+	      lami[3] = lam3;
+	      lami[0] = 1-lam1-lam2-lam3;
+	      np = 4;
+	      break;
+	    }
+	  case PRISM:
+	  case PRISM12:
+	    {
+	      lami[0] = (1-lam3) * (1-lam1-lam2);
+	      lami[1] = (1-lam3) * lam1;
+	      lami[2] = (1-lam3) * lam2;
+	      lami[3] = (lam3) * (1-lam1-lam2);
+	      lami[4] = (lam3) * lam1;
+	      lami[5] = (lam3) * lam2;
+	      np = 6;
+	      break;
+	    }	    
+	  }
+
+	for (i = 0; i < np; i++)
+	  val += lami[i] * data->data[(el[i]-1) * data->dist + comp-1];
+
+	return val;
+      }
+
+    case SOL_ELEMENT:
+      {
+	return data->data[elnr * data->dist + comp-1];
+      }
+
+    case SOL_SURFACE_ELEMENT:
+      return 0;
+
+    case SOL_NONCONTINUOUS:
+      {
+	const Element & el = (*mesh)[elnr];
+
+	double lami[8];
+	int np, i;
+	double val = 0;
+
+	switch (el.GetType())
+	  {
+	  case TET:
+	  case TET10:
+	    {
+	      lami[1] = lam1;
+	      lami[2] = lam2;
+	      lami[3] = lam3;
+	      lami[0] = 1-lam1-lam2-lam3;
+	      np = 4;
+	      break;
+	    }
+	  case PRISM:
+	  case PRISM12:
+	    {
+	      lami[0] = (1-lam3) * (1-lam1-lam2);
+	      lami[1] = (1-lam3) * lam1;
+	      lami[2] = (1-lam3) * lam2;
+	      lami[3] = (lam3) * (1-lam1-lam2);
+	      lami[4] = (lam3) * lam1;
+	      lami[5] = (lam3) * lam2;
+	      np = 6;
+	      break;
+	    }
+	  case PYRAMID:
+	    {
+	      if (lam3 > 1-1e-5)
+		{
+		  lami[0] = lami[1] = lami[2] = lami[3] = 0;
+		  lami[4] = 1;
+		}
+	      else
+		{
+		  double x0 = lam1 / (1-lam3);
+		  double y0 = lam2 / (1-lam3);
+		  lami[0] = (1-x0) * (1-y0) * (1-lam3);
+		  lami[1] = (  x0) * (1-y0) * (1-lam3);
+		  lami[2] = (  x0) * (  y0) * (1-lam3);
+		  lami[3] = (1-x0) * (  y0) * (1-lam3);
+		  lami[4] = lam3;
+		  np = 5;
+		}
+	      break;
+	    }
+	  default:
+	    np = 0;
+	  }
+
+	int base;
+	if (data->order == 1)
+	  base = 6 * elnr;
+	else
+	  base = 10 * elnr;
+
+
+	for (i = 0; i < np; i++)
+	  val += lami[i] * data->data[(base+i) * data->dist + comp-1];
+
+	return val;
+      }
+
+    case SOL_MARKED_ELEMENTS:
+      return (*mesh)[elnr].TestRefinementFlag();
+      
+    case SOL_ELEMENT_ORDER:
+      return (*mesh)[elnr].GetOrder();
+    }
+  return 0;
+}
+
+
+
+
+void VisualSceneSolution :: 
+GetSurfValues (const SolData * data, SurfaceElementIndex selnr, 
+	       double lam1, double lam2, 
+	       double * values) const
+{
+  switch (data->soltype)
+    {
+    case SOL_VIRTUALFUNCTION:
+      {
+	bool ok =
+	  data->solclass->GetSurfValue (selnr, lam1, lam2, values);
+	break;
+      }
+    default:
+      {
+	for (int i = 0; i < data->components; i++)
+	  values[i] = GetSurfValue (data, selnr, lam1, lam2, i+1);
+      }
+    }
+}
+
+
+
+double VisualSceneSolution :: 
+GetSurfValue (const SolData * data, SurfaceElementIndex selnr, 
+	      double lam1, double lam2, 
+	      int comp) const
+{
+  if (comp == 0)
+    {
+      double val = 0;
+      ArrayMem<double,20> values(data->components);
+      GetSurfValues (data, selnr, lam1, lam2, &values[0]);
+
+      switch (evalfunc)
+	{
+	case FUNC_ABS:
+	  {
+	    for (int ci = 0; ci < data->components; ci++)
+	      val += sqr (values[ci]);
+	    val = sqrt (val);
+	    break;
+	  }
+	case FUNC_ABS_TENSOR:
+	  {
+	    int d;
+	    switch (data->components)
+	      {
+	      case 1: d = 1; break;
+	      case 3: d = 2; break;
+	      case 6: d = 3; break;
+	      }
+	    int ci;
+	    for (ci = 0; ci < d; ci++)
+	      val += sqr (values[ci]);
+	    for (ci = d; ci < data->components; ci++)
+	      val += 2*sqr (values[ci]);
+	    val = sqrt (val);
+	    break;
+	  }
+
+	case FUNC_MISES:
+	{
+	    int d;
+	    switch(data->components)
+	      {
+	      case 1: d = 1; break;
+	      case 3: d = 2; break;
+	      case 6: d = 3; break;
+	      }
+	    int ci;
+	    double trace = 0.;
+	    for (ci = 0; ci < d; ci++)
+	      trace += 1./3.*(values[ci]);
+	    for (ci = 0; ci < d; ci++)
+	      val += sqr (values[ci]-trace);
+	    for (ci = d; ci < data->components; ci++)
+	      val += 2.*sqr (values[ci]);
+	    val = sqrt (val);
+	    break;
+	}
+	case FUNC_MAIN:
+	 {
+	    int d;
+	    switch(data->components)
+	      {
+	      case 1: d = 1; break;
+	      case 3: d = 2; break;
+	      case 6: d = 3; break;
+	      }
+	    Mat<3,3> m ;
+	    Vec<3> ev;
+	    int ci;
+            for (ci = 0; ci < d; ci++)
+	      m(ci,ci) = (values[ci]);
+	    m(0,1) = m(1,0) = values[3];
+	    m(0,2) = m(2,0) = values[4];
+	    m(1,2) = m(2,1) = values[5];
+
+	    EigenValues (m, ev);
+	    double help;
+            for (int i=0; i<d; i++)
+            {
+               for (int j=d-1; i<j; j--)
+               {
+                   if ( abs(ev(j)) > abs(ev(j-1)) )
+	           {
+	              help = ev(j);
+                      ev(j) = ev(j-1);
+	              ev(j-1) = help;
+	           }
+       		}
+  	    }
+            val = (ev(0));
+	    break;
+         }
+      }
+
+      return val;	
+
+
+      /*
+      int ci;
+      double val = 0;
+      for (ci = 1; ci <= data->components; ci++)
+	val += sqr (GetSurfValue (data, selnr, lam1, lam2, ci));
+      return sqrt (val);
+      */
+    }
+
+
+  switch (data->soltype)
+    {
+   case SOL_VIRTUALFUNCTION:
+      {
+	double values[20];
+	bool ok =
+	  data->solclass->GetSurfValue (selnr, lam1, lam2, values);
+	if (ok)
+	  return values[comp-1];
+	else 
+	  return 0;
+      }
+
+
+    case SOL_NODAL:
+      {
+	const Element2d & el = (*mesh)[selnr];
+
+	double lami[8];
+	int np, i;
+	double val = 0;
+	double lam3 = 1-lam1-lam2;
+
+	switch (el.GetType())
+	  {
+	  case TRIG:
+	    /*
+	    lami[0] = lam3;
+	    lami[1] = lam1;
+	    lami[2] = lam2;
+	    */
+	    lami[0] = lam1;
+	    lami[1] = lam2;
+	    lami[2] = lam3;
+	    np = 3;
+	    break;
+
+	  case TRIG6:
+	    /*
+	    lami[0] = lam3*(2*lam3-1);
+	    lami[1] = lam1*(2*lam1-1);
+	    lami[2] = lam2*(2*lam2-1);
+	    */
+	    // hierarchical basis:
+	    lami[0] = lam3;
+	    lami[1] = lam1;
+	    lami[2] = lam2;
+	    lami[3] = 4*lam1*lam2;
+	    lami[4] = 4*lam2*lam3;
+	    lami[5] = 4*lam1*lam3;
+	    np = 6;
+	    break;
+
+	  case QUAD:
+	  case QUAD6:
+	    lami[0] = (1-lam1)*(1-lam2);
+	    lami[1] = lam1 * (1-lam2);
+	    lami[2] = lam1 * lam2;
+	    lami[3] = (1-lam1) * lam2;
+	    np = 4;
+	    break;
+
+	  default:
+	    np = 0;
+	  }
+
+	for (i = 0; i < np; i++)
+	  val += lami[i] * data->data[(el[i]-1) * data->dist + comp-1];
+
+	return val;
+      }
+
+    case SOL_ELEMENT:
+      {
+	int el1, el2;
+	mesh->GetTopology().GetSurface2VolumeElement (selnr+1, el1, el2);
+	el1--;
+
+	return data->data[el1 * data->dist+comp-1];
+      }
+
+    case SOL_NONCONTINUOUS:
+      {
+	return 0;
+      }
+
+    case SOL_SURFACE_ELEMENT:
+      {
+	return data->data[selnr * data->dist + comp-1];
+      }
+
+    case SOL_SURFACE_NONCONTINUOUS:
+      {
+	const Element2d & el = (*mesh)[selnr];
+
+	double lami[8];
+	int np, i;
+	double val = 0;
+	int order = data->order;
+
+	switch (order)
+	  {
+	  case 0:
+	    return data->data[selnr * data->dist + comp-1];
+	  case 1:
+	    {
+	      switch (el.GetType())
+		{
+		case TRIG:
+		case TRIG6:
+		  {
+		    lami[1] = lam1;
+		    lami[2] = lam2;
+		    lami[0] = 1-lam1-lam2;
+		    np = 3;
+		    break;
+		  }
+		}
+	      break;
+	    }
+	  case 2:
+	    {
+	      switch (el.GetType())
+		{
+		case TRIG:
+		  {
+		    lami[1] = lam1;
+		    lami[2] = lam2;
+		    lami[0] = 1-lam1-lam2;
+		    np = 3;
+		    break;
+		  }
+		case TRIG6:
+		  {
+		    double lam3 = 1-lam1-lam2;
+		    lami[1] = 2*lam1 * (lam1-0.5);
+		    lami[2] = 2*lam2 * (lam2-0.5);
+		    lami[0] = 2*lam3 * (lam3-0.5);
+		    lami[3] = 4*lam1*lam2;
+		    lami[4] = 4*lam2*lam3;
+		    lami[5] = 4*lam1*lam3;
+		    np = 6;
+		    break;
+		  }
+		}
+	      break;
+	    }
+	  }
+	
+	int base;
+	if (order == 1)
+	  base = 4 * selnr;
+	else 
+	  base = 9 * selnr;
+
+	for (i = 0; i < np; i++)
+	  {
+	    val += lami[i] * data->data[(base+i) * data->dist + comp-1];
+	  }
+	return val;
+      }
+
+    case SOL_MARKED_ELEMENTS:
+      return (*mesh)[selnr].TestRefinementFlag();
+      
+    case SOL_ELEMENT_ORDER:
+      return (*mesh)[selnr].GetOrder();
+
+    }
+  return 0;
+}
+
+
+void VisualSceneSolution :: 
+GetDeformation (ElementIndex elnr, double lam1, double lam2, double lam3,
+		Vec<3> & def) const
+{
+  if (deform && vecfunction != -1)
+    {
+      GetValues (soldata[vecfunction], elnr, lam1, lam2, lam3, &def(0));
+      def *= scaledeform;
+
+      if (soldata[vecfunction]->dist == 2) def(2) = 0;
+    }
+  else
+    def = 0;
+}
+
+
+void VisualSceneSolution :: 
+GetSurfDeformation (SurfaceElementIndex elnr, double lam1, double lam2, 
+		    Vec<3> & def) const
+{
+  if (deform && vecfunction != -1)
+    {
+      GetSurfValues (soldata[vecfunction], elnr, lam1, lam2,  &def(0));
+      def *= scaledeform;
+
+      if (soldata[vecfunction]->dist == 2) def(2) = 0;
+    }
+  else
+    def = 0;
+}
+
+void VisualSceneSolution :: GetPointDeformation (int pnum, Point<3> & p, 
+						 SurfaceElementIndex elnr) const
+{
+  p = mesh->Point (pnum+1);
+
+  if (deform && vecfunction != -1)
+    {
+      const SolData * vsol = soldata[vecfunction];
+      
+      Vec<3> v(0,0,0);
+      if (vsol->soltype == SOL_NODAL)
+	{
+	  v = Vec3d(vsol->data[pnum * vsol->dist],
+		    vsol->data[pnum * vsol->dist+1],
+		    vsol->data[pnum * vsol->dist+2]);
+	}
+      else if (vsol->soltype == SOL_SURFACE_NONCONTINUOUS)
+	{
+	  const Element2d & el = (*mesh)[elnr];
+	  for (int j = 0; j < el.GetNP(); j++)
+	    if (el[j] == pnum+1)
+	      {
+		int base = (4*elnr+j-1) * vsol->dist;
+		v = Vec3d(vsol->data[base],
+			  vsol->data[base+1],
+			  vsol->data[base+2]);
+	      }
+	}
+
+      if (vsol->dist == 2) v(2) = 0;
+      
+      v *= scaledeform;
+      p += v;
+    }
+}
+
+
+
+
+
+
+
+
+void VisualSceneSolution :: GetClippingPlaneTrigs (ARRAY<ClipPlaneTrig> & trigs)
+{
+  //  cout << "get clipplane trigs" << endl;
+
+  int ii, j, k, l;
+  ElementIndex ei;
+  // int np = mesh->GetNV();
+  int np = mesh->GetNP();
+  int ne = mesh->GetNE();
+
+  ARRAY<double> nodevals(np);
+  
+  for (int i = 0; i < np; i++)
+    {
+      Point<3> p;
+      GetPointDeformation(i, p);
+      nodevals[i] =
+	p(0) * clipplane[0] +
+	p(1) * clipplane[1] +
+	p(2) * clipplane[2] +
+	clipplane[3];
+    }
+
+  const int edgei[6][2] =
+  { 
+    { 0, 1 },
+    { 0, 2 },
+    { 0, 3 },
+    { 1, 2 },
+    { 1, 3 },
+    { 2, 3 }
+  };
+  double edgelam[6];
+  Point<3> edgep[6];
+  double nodevali[4];
+
+  int cntce;
+  int cpe1 = 0, cpe2 = 0, cpe3 = 0;
+
+  ARRAY<Element> loctets;
+  ARRAY<Element> loctetsloc;
+  ARRAY<Point3d> pointsloc;
+
+  for (ei = 0; ei < ne; ei++)
+    {
+      // const Element & el = mesh->VolumeElement(i);
+
+      (*mesh)[ei].GetTets (loctets);
+      (*mesh)[ei].GetTetsLocal (loctetsloc);
+      // (*mesh)[ei].GetNodesLocal (pointsloc);
+      (*mesh)[ei].GetNodesLocalNew (pointsloc);
+
+      for (ii = 0; ii < loctets.Size(); ii++)
+	{
+	  const Element & el = loctets[ii];
+	  
+	  for (j = 0; j < 4; j++)
+	    nodevali[j] = nodevals.Get(el[j]);
+	  
+	  cntce = 0;
+	  for (j = 0; j < 6; j++)
+	    {
+	      int lpi1 = edgei[j][0];
+	      int lpi2 = edgei[j][1];
+	      if ( (nodevali[lpi1] > 0) !=
+		   (nodevali[lpi2] > 0) )
+		{
+		  edgelam[j] = nodevali[lpi2] / (nodevali[lpi2] - nodevali[lpi1]);
+		  Point<3> p1, p2;
+		  GetPointDeformation (el[lpi1]-1, p1);
+		  GetPointDeformation (el[lpi2]-1, p2);
+		  
+		  edgep[j] = p1 + (1-edgelam[j]) * (p2-p1);
+		  
+		  cntce++;
+		  cpe3 = cpe2;
+		  cpe2 = cpe1;
+		  cpe1 = j;
+		  if (cntce >= 3)
+		    {
+		      ClipPlaneTrig cpt;
+		      cpt.elnr = ei;
+
+		      for (k = 0; k < 3; k++)
+			{
+			  int ednr;
+			  switch (k)
+			    {
+			    case 0: ednr = cpe1; break;
+			    case 1: ednr = cpe2; break;
+			    case 2: ednr = cpe3; break;
+			    }
+			  cpt.points[k].p = edgep[ednr];
+
+			  int pi1 = edgei[ednr][0];
+			  int pi2 = edgei[ednr][1];
+			  Point<3> p1 = pointsloc.Get (loctetsloc[ii][pi1]);
+			  Point<3> p2 = pointsloc.Get (loctetsloc[ii][pi2]);
+			  for (l = 0; l < 3; l++)
+			    cpt.points[k].lami(l) = 
+			      edgelam[ednr]     * p1(l) + 
+			      (1-edgelam[ednr]) * p2(l);
+			}
+
+		      trigs.Append (cpt);
+		    }
+		}
+	    }
+	}
+      
+    }
+}
+
+void VisualSceneSolution :: GetClippingPlaneGrid (ARRAY<ClipPlanePoint> & pts)
+{
+  int i, j, k;
+  int np = mesh->GetNV();
+  int ne = mesh->GetNE();
+  
+  Vec3d n(clipplane[0], clipplane[1], clipplane[2]);
+
+  double mu = -clipplane[3] / n.Length2();
+  Point3d p(mu*n.X(), mu * n.Y(), mu * n.Z());
+
+  n /= n.Length();
+  Vec3d t1, t2;
+  n.GetNormal (t1);
+  t2 = Cross (n, t1);
+
+  double xi1, xi2;
+
+  double xi1mid = (center - p) * t1;
+  double xi2mid = (center - p) * t2;
+
+  pts.SetSize(0);
+
+  int elnr;
+  double lami[3];
+
+  for (xi1 = xi1mid-rad; xi1 <= xi1mid+rad; xi1 += rad / gridsize)
+    for (xi2 = xi2mid-rad; xi2 <= xi2mid+rad; xi2 += rad / gridsize)
+      {
+	Point3d hp = p + xi1 * t1 + xi2 * t2;
+
+	elnr = mesh->GetElementOfPoint (hp, lami)-1;
+
+	if (elnr != -1)
+	  {
+	    ClipPlanePoint cpp;
+	    cpp.p = hp;
+	    cpp.elnr = elnr;
+	    cpp.lam1 = lami[0];
+	    cpp.lam2 = lami[1];
+	    cpp.lam3 = lami[2];
+	    pts.Append (cpp);
+	  }
+      }
+};
+
+
+
+void VisualSceneSolution ::
+SetOpenGlColor(double h, double hmin, double hmax, int logscale)
+{
+  double value;
+
+  if (!logscale)
+    value = (h - hmin) / (hmax - hmin);
+  else
+    {
+      if (hmax <= 0) hmax = 1;
+      if (hmin <= 0) hmin = 1e-4 * hmax;
+      value = (log(fabs(h)) - log(hmin)) / (log(hmax) - log(hmin));
+    }
+
+  if (!invcolor)
+    value = 1 - value;
+
+  if (usetexture)
+    {
+      glTexCoord1f ( 0.999 * value + 0.001);
+      return;
+    };
+
+  if (value > 1) value = 1;
+  if (value < 0) value = 0;
+
+  value *= 4;
+
+  const double colp[][3] =
+  {
+    { 1, 0, 0 },
+    { 1, 1, 0 },
+    { 0, 1, 0 },
+    { 0, 1, 1 },
+    { 0, 0, 1 },
+    { 1, 0, 1 },
+    { 1, 0, 0 },
+  };
+  
+  int i = int(value);
+  double r = value - i;
+
+  GLdouble col[3];
+  int j;
+  for (j = 0; j < 3; j++)
+    col[j] = (1-r) * colp[i][j] + r * colp[i+1][j];
+  
+  glColor3d (col[0], col[1], col[2]);
+}
+
+
+
+
+void VisualSceneSolution ::
+DrawCone (const Point<3> & p1, const Point<3> & p2, double r)
+{
+  int n = 10, i;
+  Vec<3> p1p2 = p2 - p1;
+
+  p1p2.Normalize();
+  Vec<3> p2p1 = -p1p2;
+
+  Vec<3> t1 = p1p2.GetNormal();
+  Vec<3> t2 = Cross (p1p2, t1);
+
+  Point<3> oldp = p1 + r * t1;
+  Vec<3> oldn = t1;
+
+  Point<3> p;
+  Vec<3> normal;
+
+  Mat<2> rotmat;
+  Vec<2> cs, newcs;
+  cs(0) = 1;
+  cs(1) = 0;
+  rotmat(0,0) = rotmat(1,1) = cos(2*M_PI/n);
+  rotmat(1,0) = sin(2*M_PI/n);
+  rotmat(0,1) = -rotmat(1,0);
+
+  glBegin (GL_TRIANGLES);
+  double phi;
+  for (i = 1; i <= n; i++)
+    {
+      /*
+      phi = 2 * M_PI * i / n;
+      normal = cos(phi) * t1 + sin(phi) * t2;
+      */
+      newcs = rotmat * cs;
+      cs = newcs;
+      normal = cs(0) * t1 + cs(1) * t2;
+
+      p = p1 + r * normal;
+
+      // cone
+      glNormal3dv (normal);
+      glVertex3dv (p);
+      glVertex3dv (p2);
+      glNormal3dv (oldn);
+      glVertex3dv (oldp);
+
+      // base-circle
+      glNormal3dv (p2p1);
+      glVertex3dv (p);
+      glVertex3dv (p1);
+      glVertex3dv (oldp);
+
+      oldp = p;
+      oldn = normal;
+    }
+  glEnd ();
+}
+
+
+
+void VisualSceneSolution ::
+DrawCylinder (const Point<3> & p1, const Point<3> & p2, double r)
+{
+  int n = 10, i;
+  Vec<3> p1p2 = p2 - p1;
+
+  p1p2.Normalize();
+  Vec<3> p2p1 = -p1p2;
+
+  Vec<3> t1 = p1p2.GetNormal();
+  Vec<3> t2 = Cross (p1p2, t1);
+
+  Point<3> oldhp1 = p1 + r * t1;
+  Point<3> oldhp2 = p2 + r * t1;
+  Vec<3> oldn = t1;
+
+  Point<3> hp1, hp2;
+  Vec<3> normal;
+
+  Mat<2> rotmat;
+  Vec<2> cs, newcs;
+  cs(0) = 1;
+  cs(1) = 0;
+  rotmat(0,0) = rotmat(1,1) = cos(2*M_PI/n);
+  rotmat(1,0) = sin(2*M_PI/n);
+  rotmat(0,1) = -rotmat(1,0);
+
+  glBegin (GL_QUADS);
+  double phi;
+  for (i = 1; i <= n; i++)
+    {
+      newcs = rotmat * cs;
+      cs = newcs;
+      normal = cs(0) * t1 + cs(1) * t2;
+
+      hp1 = p1 + r * normal;
+      hp2 = p2 + r * normal;
+
+      // cylinder
+      glNormal3dv (normal);
+
+      glVertex3dv (hp1);
+      glVertex3dv (hp2);
+      glVertex3dv (oldhp2);
+      glVertex3dv (oldhp1);
+
+      oldhp1 = hp1;
+      oldhp2 = hp2;
+      oldn = normal;
+    }
+  glEnd ();
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+void VisualSceneSolution :: MouseDblClick (int px, int py)
+{
+  ;
+}
+
+
+void VisualSceneSolution :: 
+DrawClipPlaneTrig (const SolData * sol, 
+		   int comp,
+		   const ClipPlaneTrig & trig, 
+		   int level)
+{
+  int j;
+  if (level <= 0)
+    for (j = 0; j < 3; j++)
+      {
+	Point<3> p;
+	if (mesh->GetCurvedElements().IsHighOrder())
+	  {
+	    mesh->GetCurvedElements().
+	      CalcElementTransformation (trig.points[j].lami, trig.elnr, p);
+	  }
+	else
+	  p = trig.points[j].p;
+	
+	if (deform)
+	  {
+	    Vec<3> def;
+	    GetDeformation (trig.elnr, 		    
+			    trig.points[j].lami(0),
+			    trig.points[j].lami(1),
+			    trig.points[j].lami(2), def);
+	    p += def;
+	  }
+
+	double val = 
+	  GetValue (sol, trig.elnr, 
+		    trig.points[j].lami(0),
+		    trig.points[j].lami(1),
+		    trig.points[j].lami(2), scalcomp);
+      
+	SetOpenGlColor  (val, minval, maxval, logscale);
+	glVertex3dv (p);
+      }
+  else
+    {
+      Point<3> newp = Center (trig.points[1].p, trig.points[2].p);
+      Point<3> newlami = Center (trig.points[1].lami, trig.points[2].lami);
+      ClipPlaneTrig t1, t2;
+      t1.elnr = t2.elnr = trig.elnr;
+      t1.points[0].p = newp;
+      t1.points[0].lami = newlami;
+      t1.points[1] = trig.points[2];
+      t1.points[2] = trig.points[0];
+      t2.points[0].p = newp;
+      t2.points[0].lami = newlami;
+      t2.points[1] = trig.points[0];
+      t2.points[2] = trig.points[1];
+      DrawClipPlaneTrig (sol, comp, t1, level-1);
+      DrawClipPlaneTrig (sol, comp, t2, level-1);
+    }
+}
+
+
+
+
+
+int Ng_Vis_Set (ClientData clientData,
+		Tcl_Interp * interp,
+		int argc, tcl_const char *argv[])
+
+{
+  int i;
+  if (argc >= 2)
+    {
+      if (strcmp (argv[1], "parameters") == 0)
+	{
+	  vssolution.imag_part = 
+	    atoi (Tcl_GetVar (interp, "visoptions.imaginary", 0));	  
+	  vssolution.usetexture = 
+	    atoi (Tcl_GetVar (interp, "visoptions.usetexture", 0));	  
+	  vssolution.invcolor = 
+	    atoi (Tcl_GetVar (interp, "visoptions.invcolor", 0));	  
+
+	  vssolution.clipsolution = 0;
+
+	  if (strcmp (Tcl_GetVar (interp, "visoptions.clipsolution", 0), 
+		      "scal") == 0)
+	    vssolution.clipsolution = 1;
+	  if (strcmp (Tcl_GetVar (interp, "visoptions.clipsolution", 0), 
+		      "vec") == 0)
+	    vssolution.clipsolution = 2;
+	    
+	  const char * scalname = 
+	    Tcl_GetVar (interp, "visoptions.scalfunction", 0);
+	  const char * vecname = 
+	    Tcl_GetVar (interp, "visoptions.vecfunction", 0);
+	  
+	  vssolution.scalfunction = -1;
+	  vssolution.vecfunction = -1;
+
+	  for (i = 0; i < vssolution.soldata.Size(); i++)
+	    {
+	      if (strlen (vssolution.soldata[i]->name) ==
+		  strlen (scalname)-2 &&
+		  strncmp (vssolution.soldata[i]->name, scalname,
+			   strlen (scalname)-2) == 0)
+		{
+		  vssolution.scalfunction = i;
+		  vssolution.scalcomp = atoi (scalname + strlen(scalname)-1);
+		}
+	      if (strcmp (vssolution.soldata[i]->name, vecname) == 0)
+		vssolution.vecfunction = i;
+	    }
+
+
+	  const char * evalname = 
+	    Tcl_GetVar (interp, "visoptions.evaluate", 0);
+	  
+	  if (strcmp(evalname, "abs") == 0) vssolution.evalfunc = VisualSceneSolution::FUNC_ABS;
+	  if (strcmp(evalname, "abstens") == 0) vssolution.evalfunc = VisualSceneSolution::FUNC_ABS_TENSOR;
+	  if (strcmp(evalname, "mises") == 0) vssolution.evalfunc = VisualSceneSolution::FUNC_MISES;
+	  if (strcmp(evalname, "main") == 0) vssolution.evalfunc = VisualSceneSolution::FUNC_MAIN;
+
+	  vssolution.gridsize = 
+	    atoi (Tcl_GetVar (interp, "visoptions.gridsize", 0));
+
+	  vssolution.autoscale = 
+	    atoi (Tcl_GetVar (interp, "visoptions.autoscale", 0));
+
+	  /*
+	  vssolution.linear_colors = 
+	    atoi (Tcl_GetVar (interp, "visoptions.lineartexture", 0));
+	  */
+	  vssolution.logscale = 
+	    atoi (Tcl_GetVar (interp, "visoptions.logscale", 0));
+
+	  vssolution.mminval = 
+	    atof (Tcl_GetVar (interp, "visoptions.mminval", 0));
+	  vssolution.mmaxval = 
+	    atof (Tcl_GetVar (interp, "visoptions.mmaxval", 0));
+
+	  vssolution.showclipsolution = 
+	    atoi (Tcl_GetVar (interp, "visoptions.showclipsolution", 0));
+	  vssolution.showsurfacesolution = 
+	    atoi (Tcl_GetVar (interp, "visoptions.showsurfacesolution", 0));
+	  vssolution.lineartexture = 
+	    atoi (Tcl_GetVar (interp, "visoptions.lineartexture", 0));
+	  vssolution.numtexturecols = 
+	    atoi (Tcl_GetVar (interp, "visoptions.numtexturecols", 0));
+
+	  vssolution.draw_fieldlines = 
+	    atoi (Tcl_GetVar (interp, "visoptions.drawfieldlines", 0));
+	  vssolution.num_fieldlines = 
+	    atoi (Tcl_GetVar (interp, "visoptions.numfieldlines", 0));
+	  vssolution.fieldlines_randomstart =
+	    atoi (Tcl_GetVar (interp, "visoptions.fieldlinesrandomstart", 0));
+	    
+	  
+	  vssolution.deform =
+	    atoi (Tcl_GetVar (interp, "visoptions.deformation", 0));
+	  vssolution.scaledeform =
+	    atof (Tcl_GetVar (interp, "visoptions.scaledeform1", 0)) *
+	    atof (Tcl_GetVar (interp, "visoptions.scaledeform2", 0));
+
+
+	  if (atoi (Tcl_GetVar (interp, "visoptions.isolines", 0)))
+	    vssolution.numisolines = atoi (Tcl_GetVar (interp, "visoptions.numiso", 0));
+	  else
+	    vssolution.numisolines = 0;
+
+	  vssolution.subdivisions = 
+	    atoi (Tcl_GetVar (interp, "visoptions.subdivisions", 0));
+	  vssolution.UpdateSolutionTimeStamp();
+	}
+      
+      if (argc >= 3 && strcmp (argv[1], "time") == 0)
+	{
+	  vssolution.time = double (atoi (argv[2])) / 1000;
+	  // cout << "time = " << vssolution.time << endl;
+	}
+
+    }
+  return TCL_OK;
+}
+
+int Ng_Vis_Field (ClientData clientData,
+		  Tcl_Interp * interp,
+		  int argc, tcl_const char *argv[])
+{
+  int i;
+  static char buf[1000];
+  buf[0] = 0;
+
+  if (argc >= 2)
+    {
+      if (strcmp (argv[1], "setfield") == 0)
+	{
+	  if (argc < 3)
+	    return TCL_ERROR;
+
+	  for (i = 0; i < vssolution.GetNSolData(); i++)
+	    if (strcmp (vssolution.GetSolData(i)->name, argv[2]) == 0)
+	      {
+		cout << "found soldata " << i << endl;
+	      }
+	}
+
+      if (strcmp (argv[1], "getnfieldnames") == 0)
+	{
+	  sprintf (buf, "%d", vssolution.GetNSolData());
+	}
+      
+      if (strcmp (argv[1], "getfieldname") == 0)
+	{
+	  sprintf (buf, "%s", vssolution.GetSolData(atoi(argv[2])-1)->name);
+	}
+
+      if (strcmp (argv[1], "iscomplex") == 0)
+	{
+	  sprintf (buf, "%d", vssolution.GetSolData(atoi(argv[2])-1)->iscomplex);
+	}
+
+      if (strcmp (argv[1], "getfieldcomponents") == 0)
+	{
+	  sprintf (buf, "%d", vssolution.GetSolData(atoi(argv[2])-1)->components);
+	}
+
+      
+      if (strcmp (argv[1], "getfieldnames") == 0)
+	{
+	  for (i = 0; i < vssolution.GetNSolData(); i++)
+	    {
+	      strcat (buf, vssolution.GetSolData(i)->name);
+	      strcat (buf, " ");
+	    }
+	  strcat (buf, "var1 var2 var3");
+	  Tcl_SetResult (interp, buf, TCL_STATIC);
+	}
+
+      if (strcmp (argv[1], "setcomponent") == 0)
+	{
+	  cout << "set component " << argv[2] << endl;
+	}
+
+      if (strcmp (argv[1], "getactivefield") == 0)
+	{
+	  sprintf (buf, "1");
+	}
+
+      if (strcmp (argv[1], "getdimension") == 0)
+	{
+	  sprintf (buf, "%d", mesh->GetDimension());
+	}
+    }
+
+  Tcl_SetResult (interp, buf, TCL_STATIC);
+  return TCL_OK;
+}
+
+
+extern "C" int Ng_Vis_Init (Tcl_Interp * interp);
+
+int Ng_Vis_Init (Tcl_Interp * interp)
+{
+  Tcl_CreateCommand (interp, "Ng_Vis_Set", Ng_Vis_Set,
+		     (ClientData)NULL,
+		     (Tcl_CmdDeleteProc*) NULL);
+
+  Tcl_CreateCommand (interp, "Ng_Vis_Field", Ng_Vis_Field,
+		     (ClientData)NULL,
+		     (Tcl_CmdDeleteProc*) NULL);
+
+
+  return TCL_OK;
+}
+}
diff --git a/Netgen/libsrc/visualization/vssolution.hpp b/Netgen/libsrc/visualization/vssolution.hpp
new file mode 100644
index 0000000000..8a63ffd6ba
--- /dev/null
+++ b/Netgen/libsrc/visualization/vssolution.hpp
@@ -0,0 +1,212 @@
+#ifndef FILE_VSSOLUTION
+#define FILE_VSSOLUTION
+
+
+
+
+
+extern int Ng_Vis_Set (ClientData clientData,
+		       Tcl_Interp * interp,
+		       int argc, tcl_const char *argv[]);
+
+class VisualSceneSolution : public VisualScene
+{
+  class ClipPlaneTrig
+  {
+  public:
+    struct ps 
+    {
+      Point<3> lami;
+      Point<3> p;
+    };
+    ps points[3];
+    ElementIndex elnr;
+  };
+
+  class ClipPlanePoint
+  {
+  public:
+    ElementIndex elnr;
+    double lam1, lam2, lam3;
+    Point<3> p;
+  };
+
+
+  int surfellist;
+  int linelist;
+  int clipplanelist;
+  int isolinelist;
+  int surface_vector_list;
+  int cone_list;
+
+  bool draw_fieldlines;
+  int num_fieldlines;
+  bool fieldlines_randomstart;
+  int fieldlineslist;
+  int num_fieldlineslists;
+
+  int surfeltimestamp, clipplanetimestamp, solutiontimestamp;
+  int fieldlinestimestamp, surface_vector_timestamp;
+  double minval, maxval;
+
+  
+
+  NgLock *lock;
+
+public:
+
+  enum EvalFunc { 
+    FUNC_ABS = 1, 
+    FUNC_ABS_TENSOR = 2,
+    FUNC_MISES = 3, 
+    FUNC_MAIN = 4
+  };
+  EvalFunc evalfunc;
+
+  enum SolType
+    { 
+      SOL_NODAL = 1, 
+      SOL_ELEMENT = 2, 
+      SOL_SURFACE_ELEMENT = 3, 
+      SOL_NONCONTINUOUS = 4, 
+      SOL_SURFACE_NONCONTINUOUS = 5,
+      SOL_VIRTUALFUNCTION = 6,
+      SOL_MARKED_ELEMENTS = 10,
+      SOL_ELEMENT_ORDER = 11,
+    };
+
+  class SolData
+  {
+  public:
+    char * name;
+    double * data;
+    int components;
+    int dist;
+    int order;
+    bool iscomplex;
+    bool draw_volume;
+    bool draw_surface;
+    SolType soltype;
+    SolutionData * solclass;
+
+    // internal variables:
+    int size;
+  };
+
+  ARRAY<SolData*> soldata;
+  
+
+
+  int usetexture;
+  int clipsolution;  // 0..no, 1..scal, 2..vec
+  int scalfunction, scalcomp, vecfunction;
+  int gridsize;
+
+  int autoscale, logscale;
+  double mminval, mmaxval;
+  int numisolines;
+  int subdivisions;
+
+  bool showclipsolution;
+  bool showsurfacesolution;
+  bool lineartexture;
+  int numtexturecols;
+
+  // bool fieldlineplot;
+  double time;
+
+  int deform;
+  double scaledeform;
+  bool imag_part;
+
+public:
+  VisualSceneSolution ();
+  virtual ~VisualSceneSolution ();
+
+  virtual void BuildScene (int zoomall = 0);
+  virtual void DrawScene ();
+  virtual void MouseDblClick (int px, int py);
+
+  void BuildFieldLinesPlot ();
+
+  void AddSolutionData (SolData * soldata);
+  void ClearSolutionData ();
+  void UpdateSolutionTimeStamp ();
+  SolData * GetSolData (int i);
+  int GetNSolData () { return soldata.Size(); }
+
+  void SaveSolutionData (const char * filename);
+private:
+  void GetMinMax (int funcnr, int comp, double & minv, double & maxv) const;
+
+  void GetClippingPlaneTrigs (ARRAY<ClipPlaneTrig> & trigs);
+  void GetClippingPlaneGrid (ARRAY<ClipPlanePoint> & pts);
+  void DrawCone (const Point<3> & p1, const Point<3> & p2, double r);
+  void DrawCylinder (const Point<3> & p1, const Point<3> & p2, double r);
+
+
+  // Get Function Value, local coordinates lam1, lam2, lam3, 
+  double GetValue (const SolData * data, ElementIndex elnr, 
+		   double lam1, double lam2, double lam3,
+		   int comp) const;
+  double GetSurfValue (const SolData * data, SurfaceElementIndex elnr,
+		       double lam1, double lam2, 
+		       int comp) const;
+  void GetValues (const SolData * data, ElementIndex elnr, 
+		  double lam1, double lam2, double lam3,
+		  double * values) const;
+  void GetSurfValues (const SolData * data, SurfaceElementIndex elnr,
+		      double lam1, double lam2, 
+		      double * values) const;
+
+  void GetDeformation (ElementIndex elnr, double lam1, double lam2, double lam3,
+		       Vec<3> & def) const;
+  void GetSurfDeformation (SurfaceElementIndex selnr, double lam1, double lam2,
+			   Vec<3> & def) const;
+
+  void GetPointDeformation (int pnum, Point<3> & p, SurfaceElementIndex elnr = -1) const;
+
+  /// draw elements (build lists)
+  void DrawSurfaceElements ();
+  void DrawSurfaceElementLines ();
+  void DrawSurfaceVectors ();
+  
+  void DrawIsoLines (const Point3d & p1, 
+		     const Point3d & p2, 
+		     const Point3d & p3,
+		     double val1, double val2, double val3,
+		     double minval, double maxval, int n);
+
+  // draw isolines between lines (p1,p2) and (p3,p4)
+  void DrawIsoLines2 (const Point3d & p1, 
+		      const Point3d & p2, 
+		      const Point3d & p3,
+		      const Point3d & p4,
+		      double val1, double val2, double val3, double val4,
+		      double minval, double maxval, int n);
+		     
+
+  void DrawClipPlaneTrig (const SolData * sol, 
+			  int comp,
+			  const ClipPlaneTrig & trig, 
+			  int level);
+			  
+  void SetOpenGlColor(double val, double valmin, double valmax, int logscale = 0);
+
+  
+  friend int Ng_Vis_Set (ClientData clientData,
+			 Tcl_Interp * interp,
+			 int argc, tcl_const char *argv[]);
+
+
+
+};
+
+
+extern VisualSceneSolution vssolution;
+
+
+
+
+#endif
+
diff --git a/configure b/configure
index f91e58457b..4187882b6c 100755
--- a/configure
+++ b/configure
@@ -852,6 +852,7 @@ Optional Features:
   --enable-system-menubar use the system menu bar on MacOS X (default=no)
   --enable-parallel       enable parallel version (default=no)
   --enable-triangle       compile Triangle if available (default=yes)
+  --enable-netgen         compile Netgen if available (default=yes)
   --enable-matheval       compile MathEval if available (default=yes)
   --enable-jpeg           enable JPEG support (default=yes)
   --enable-z              enable ZLIB support (default=yes)
@@ -1354,6 +1355,11 @@ fi;
 if test "${enable_triangle+set}" = set; then
   enableval="$enable_triangle"
 
+fi;
+# Check whether --enable-netgen or --disable-netgen was given.
+if test "${enable_netgen+set}" = set; then
+  enableval="$enable_netgen"
+
 fi;
 # Check whether --enable-matheval or --disable-matheval was given.
 if test "${enable_matheval+set}" = set; then
@@ -3539,6 +3545,58 @@ else
   fi
 fi
 
+
+echo "$as_me:$LINENO: checking for ./Netgen/libsrc/meshing/meshclass.cpp" >&5
+echo $ECHO_N "checking for ./Netgen/libsrc/meshing/meshclass.cpp... $ECHO_C" >&6
+if test "${ac_cv_file___Netgen_libsrc_meshing_meshclass_cpp+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  test "$cross_compiling" = yes &&
+  { { echo "$as_me:$LINENO: error: cannot check for file existence when cross compiling" >&5
+echo "$as_me: error: cannot check for file existence when cross compiling" >&2;}
+   { (exit 1); exit 1; }; }
+if test -r "./Netgen/libsrc/meshing/meshclass.cpp"; then
+  ac_cv_file___Netgen_libsrc_meshing_meshclass_cpp=yes
+else
+  ac_cv_file___Netgen_libsrc_meshing_meshclass_cpp=no
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_file___Netgen_libsrc_meshing_meshclass_cpp" >&5
+echo "${ECHO_T}$ac_cv_file___Netgen_libsrc_meshing_meshclass_cpp" >&6
+if test $ac_cv_file___Netgen_libsrc_meshing_meshclass_cpp = yes; then
+  NETGEN="yes"
+else
+  NETGEN="no"
+fi
+
+if test "x${NETGEN}" = "xyes"; then
+  if test "x$enable_netgen" != "xno"; then
+     GMSH_DIRS="${GMSH_DIRS} Netgen"
+     GMSH_LIBS="${GMSH_LIBS} -lGmshNetgen"
+     FLAGS="-DHAVE_NETGEN ${FLAGS}"
+     echo "********************************************************************"
+     echo "You are building a version of Gmsh that contains Joachim Schoberl's"
+     echo "Netgen as an alternative 3D mesh generator. Netgen is distributed"
+     echo "under the GNU LGPL: see ./Netgen/COPYING.LIB for more info."
+     echo "To disable Netgen, run configure again with the --disable-netgen"
+     echo "option."
+     echo "********************************************************************"
+  fi
+else
+  if test "x$enable_netgen" != "xno"; then
+     echo "********************************************************************"
+     echo "If you want to use Joachim Schoberl's Netgen as an alternative "
+     echo "3D mesh generator, please download Netgen from the project's"
+     echo "web site at http://www.hpfem.jku.at/netgen/, unpack the archive"
+     echo "and move the libsrc subdirectory in the ./Netgen subdirectory. Then"
+     echo "run ./configure again."
+     echo "Please note that by doing so, you agree with Netgen's licensing"
+     echo "requirements stated in ./Netgen/COPYING.LIB."
+     echo "********************************************************************"
+  fi
+fi
+
+
 echo "$as_me:$LINENO: checking for ./MathEval/matheval.cpp" >&5
 echo $ECHO_N "checking for ./MathEval/matheval.cpp... $ECHO_C" >&6
 if test "${ac_cv_file___MathEval_matheval_cpp+set}" = set; then
@@ -3570,6 +3628,7 @@ if test "x${MATHEVAL}" = "xyes"; then
   fi
 fi
 
+
 if test "x$enable_gsl" != "xno"; then
   if test "x${GSL_PREFIX}" != "x"; then
     LDFLAGS="-L${GSL_PREFIX}/lib ${LDFLAGS}"
diff --git a/configure.in b/configure.in
index ed200de6cd..ed2b49ff7b 100644
--- a/configure.in
+++ b/configure.in
@@ -1,4 +1,4 @@
-dnl $Id: configure.in,v 1.53 2004-06-12 18:34:31 geuzaine Exp $
+dnl $Id: configure.in,v 1.54 2004-06-26 17:58:14 geuzaine Exp $
 dnl
 dnl Copyright (C) 1997-2004 C. Geuzaine, J.-F. Remacle
 dnl
@@ -66,6 +66,9 @@ AC_ARG_ENABLE(parallel,
 AC_ARG_ENABLE(triangle,
               AC_HELP_STRING([--enable-triangle],
                              [compile Triangle if available (default=yes)]))
+AC_ARG_ENABLE(netgen,
+              AC_HELP_STRING([--enable-netgen],
+                             [compile Netgen if available (default=yes)]))
 AC_ARG_ENABLE(matheval,
               AC_HELP_STRING([--enable-matheval],
                              [compile MathEval if available (default=yes)]))
@@ -246,6 +249,37 @@ else
   fi
 fi
 
+
+dnl Check if Netgen is installed
+AC_CHECK_FILE(./Netgen/libsrc/meshing/meshclass.cpp, NETGEN="yes", NETGEN="no")
+if test "x${NETGEN}" = "xyes"; then
+  if test "x$enable_netgen" != "xno"; then
+     GMSH_DIRS="${GMSH_DIRS} Netgen"
+     GMSH_LIBS="${GMSH_LIBS} -lGmshNetgen"
+     FLAGS="-DHAVE_NETGEN ${FLAGS}"
+     echo "********************************************************************"
+     echo "You are building a version of Gmsh that contains Joachim Schoberl's"
+     echo "Netgen as an alternative 3D mesh generator. Netgen is distributed"
+     echo "under the GNU LGPL: see ./Netgen/COPYING.LIB for more info."
+     echo "To disable Netgen, run configure again with the --disable-netgen"
+     echo "option."
+     echo "********************************************************************"
+  fi
+else
+  if test "x$enable_netgen" != "xno"; then
+     echo "********************************************************************"
+     echo "If you want to use Joachim Schoberl's Netgen as an alternative "
+     echo "3D mesh generator, please download Netgen from the project's"
+     echo "web site at http://www.hpfem.jku.at/netgen/, unpack the archive"
+     echo "and move the libsrc subdirectory in the ./Netgen subdirectory. Then"
+     echo "run ./configure again."
+     echo "Please note that by doing so, you agree with Netgen's licensing"
+     echo "requirements stated in ./Netgen/COPYING.LIB."
+     echo "********************************************************************"
+  fi
+fi
+
+
 dnl Check for MathEval
 AC_CHECK_FILE(./MathEval/matheval.cpp, MATHEVAL="yes", MATHEVAL="no")
 if test "x${MATHEVAL}" = "xyes"; then
@@ -256,6 +290,7 @@ if test "x${MATHEVAL}" = "xyes"; then
   fi
 fi
 
+
 dnl Check for GSL
 if test "x$enable_gsl" != "xno"; then
   if test "x${GSL_PREFIX}" != "x"; then
diff --git a/tutorial/t2.geo b/tutorial/t2.geo
index 0ba1e40ed8..0de54c009e 100644
--- a/tutorial/t2.geo
+++ b/tutorial/t2.geo
@@ -71,10 +71,10 @@ Characteristic Length {tmp[0], 22, 2, 3, 16, 12} = lc * 4;
 // following volumes don't have holes and thus consist of single
 // surface loops:
 
-Surface Loop(145) = {121,11,131,135,139,144};
+Surface Loop(145) = {-121,11,-131,-135,-139,-144};
 Volume(146) = {145};
 
-Surface Loop(146) = {121,6,109,113,117,122};
+Surface Loop(146) = {121,-6,109,113,117,122};
 Volume(147) = {146};
 
 // To save all the tetrahedra discretizing the volumes 146 and 147
diff --git a/tutorial/t5.geo b/tutorial/t5.geo
index 9cadb74884..fb7db01277 100644
--- a/tutorial/t5.geo
+++ b/tutorial/t5.geo
@@ -48,14 +48,14 @@ Line(13) = {6,2};   Line(14) = {2,1};  Line(15) = {1,3};
 Line(16) = {3,7};   Line(17) = {7,2};  Line(18) = {3,4};
 Line(19) = {5,1};   Line(20) = {7,8};  Line(21) = {6,14};
 
-Line Loop(22) = {11,19,15,18};       Plane Surface(23) = {22};
+Line Loop(22) = {-11,-19,-15,-18};   Plane Surface(23) = {22};
 Line Loop(24) = {16,17,14,15};       Plane Surface(25) = {24};
 Line Loop(26) = {-17,20,1,5,-21,13}; Plane Surface(27) = {26};
-Line Loop(28) = {4,1,2,3};           Plane Surface(29) = {28};
-Line Loop(30) = {7,-2,5,6};          Plane Surface(31) = {30};
+Line Loop(28) = {-4,-1,-2,-3};       Plane Surface(29) = {28};
+Line Loop(30) = {-7,2,-5,-6};        Plane Surface(31) = {30};
 Line Loop(32) = {6,-9,10,11,12,21};  Plane Surface(33) = {32};
 Line Loop(34) = {7,3,8,9};           Plane Surface(35) = {34};
-Line Loop(36) = {10,-18,16,20,-4,8}; Plane Surface(37) = {36};
+Line Loop(36) = {-10,18,-16,-20,4,-8}; Plane Surface(37) = {36};
 Line Loop(38) = {-14,-13,-12,19};    Plane Surface(39) = {38};
 
 // Instead of using included files, let us now use a user-defined
@@ -98,11 +98,11 @@ Function CheeseHole
 
   l1 = newreg; Line Loop(l1) = {c5,c10,c4};   Ruled Surface(newreg) = {l1};
   l2 = newreg; Line Loop(l2) = {c9,-c5,c1};   Ruled Surface(newreg) = {l2};
-  l3 = newreg; Line Loop(l3) = {-c12,c8,c1};  Ruled Surface(newreg) = {l3};
+  l3 = newreg; Line Loop(l3) = {c12,-c8,-c1}; Ruled Surface(newreg) = {l3};
   l4 = newreg; Line Loop(l4) = {c8,-c4,c11};  Ruled Surface(newreg) = {l4};
   l5 = newreg; Line Loop(l5) = {-c10,c6,c3};  Ruled Surface(newreg) = {l5};
   l6 = newreg; Line Loop(l6) = {-c11,-c3,c7}; Ruled Surface(newreg) = {l6};
-  l7 = newreg; Line Loop(l7) = {c2,c7,c12};   Ruled Surface(newreg) = {l7};
+  l7 = newreg; Line Loop(l7) = {-c2,-c7,-c12};Ruled Surface(newreg) = {l7};
   l8 = newreg; Line Loop(l8) = {-c6,-c9,c2};  Ruled Surface(newreg) = {l8};
 
   // Please note that all surface meshes are generated by projecting a
-- 
GitLab